Strings Became Symbols When They Output in C

563 views Asked by At

I have a problem when i output some strings in my codes. When i input 1 string and then output it, there is no problem at all. But, when i input at least 2 strings, it went fail. The strings became symbols, except the last one. Here is the screenshot:

enter image description here

I've been using fflush(stdin) and fflush(stdout), but the problem is still exist. So, what should i do? I need your advice.

Here is my complete codes:

#include <stdio.h>
#include <stdlib.h>

void menu();
void entry();
void search();
void PrintSingle();
void PrintComplete();
float TotalUsed(int i);
float RegularCost(int i);
float tax(int i);
float discount(int i);
float TotalPayment(int i);

#define NMaks 101

typedef enum {false=0,true=1} boolean;
typedef struct {int BillNumber,BillClass;float LastMeter,CurrentMeter;char name[];} BillDatabase;
BillDatabase bill[NMaks];

int DataAmount=0;

int main() {

    menu();
    return 0;
}

void menu() {

    int i;

    repeat:
    system("cls");
    printf("\t\t.: Electric Billing System :.\n\n");
    printf("[1] Entries customer information\n");
    printf("[2] Search customer\n");
    printf("[3] Print single bill\n");
    printf("[4] Print complete billing report\n");
    printf("[5] Exit\n\n");
    printf("Select the menu[1..5]: ");scanf("%d",&i);

    switch (i) {
        case 1  :   entry();break;
        case 2  :   search();break;
        case 3  :   PrintSingle();break;
        case 4  :   PrintComplete();break;
        case 5  :   {
                    printf("\n\nGoodbye!");
                    getch();
                    break;
        }
        default :   {
                    printf("\n\nWrong menu!");
                    goto repeat;
        }
    }
}

void entry() {

    char repeat;

    do {
        system("cls");
        printf("\t\t.: Electric Billing System :.\n\n");
        printf("[1] Entries customer information\n\n");
        DataAmount++;
        printf("Bill number: ");scanf("%d",&bill[DataAmount].BillNumber);
        printf("Customer name: ");fflush(stdin);fflush(stdout);gets(bill[DataAmount].name);
        printf("Class[1..3]: ");scanf("%d",&bill[DataAmount].BillClass);
        printf("Last meter: ");scanf("%f",&bill[DataAmount].LastMeter);
        printf("Current meter: ");scanf("%f",&bill[DataAmount].CurrentMeter);
        printf("\nEntry again[y/n]: ");repeat=getche();
    } while (tolower(repeat)=='y');
    menu();
}

void search() {

    int i,BN;
    boolean found;
    char repeat;

    do {
        system("cls");
        printf("\t\t.: Electric Billing System :.\n\n");
        printf("[2] Search customer\n\n");
        printf("Enter the bill number: ");scanf("%d",&BN);
        found=false;
        for (i=1;i<=DataAmount;i++)
            if (BN==bill[i].BillNumber) {
                found=true;
                break;
            }
        if (found) {
            printf("\nCustomer found!\n\n");
            printf("Bill number\tN   a    m    e Class\t\tLast meter\tCurrent meter\n");
            fflush(stdin);fflush(stdout);
            printf("%d\t\t%15.15s\t%d\t\t%.2f kWh\t%.2f kWh\n",bill[i].BillNumber,bill[i].name,bill[i].BillClass,bill[i].LastMeter,bill[i].CurrentMeter);
        }
        else
            printf("\nCustomer not found!\n");
        printf("\nSearch again[y/n]: ");repeat=getche();
    } while (tolower(repeat)=='y');
    menu();
}

void PrintSingle() {

    int i,BN;
    boolean found;
    char repeat;

    do {
        system("cls");
        printf("\t\t.: Electric Billing System :.\n\n");
        printf("[3] Print single bill\n\n");
        printf("Enter the bill number: ");scanf("%d",&BN);
        found=false;
        for (i=1;i<=DataAmount;i++)
            if (BN==bill[i].BillNumber) {
                found=true;
                break;
            }
        if (found) {
            printf("\nCustomer found!\n\n");
            printf("Bill number\tN   a    m    e Class\t\tLast meter\tCurrent meter\n");
            fflush(stdin);fflush(stdout);
            printf("%d\t\t%15.15s\t%d\t\t%.2f kWh\t%.2f kWh\n",bill[i].BillNumber,bill[i].name,bill[i].BillClass,bill[i].LastMeter,bill[i].CurrentMeter);
            printf("Total used\tRegular cost\tTax\t\tDiscount\tTotal Payment\n");
            printf("%.2f kWh\t$%7.2f\t$%7.2f\t$%7.2f\t$%7.2f\n",TotalUsed(i),RegularCost(i),tax(i),discount(i),TotalPayment(i));
        }
        else
            printf("\nCustomer not found!\n");
        printf("\nPrint again[y/n]: ");repeat=getche();
    } while (tolower(repeat)=='y');
    menu();
}

void PrintComplete() {

    int i;

    system("cls");
    printf("\t\t.: Electric Billing System :.\n\n");
    printf("[4] Print complete billing report\n\n");
    printf("Bill number\tN   a    m    e\t\tClass\tTotal Payment\n");
    for (i=1;i<=DataAmount;i++) {
        fflush(stdin);fflush(stdout);
        printf("%d\t\t%15.15s\t\t%d\t$%.2f\n",bill[i].BillNumber,bill[i].name,bill[i].BillClass,TotalPayment(i));
    }
    printf("\nPress any key to the main menu");
    getch();
    menu();
}

float TotalUsed(int i) {

    return bill[i].CurrentMeter-bill[i].LastMeter;
}

float RegularCost(int i) {

    float price;

    switch (bill[i].BillClass) {
        case 1  :   price=10.0;break;
        case 2  :   price=7.5;break;
        default :   price=13.75;
    }
    return TotalUsed(i)*price;
}

float tax(int i) {

    float TaxPercentage;

    switch (bill[i].BillClass) {
        case 1  :   TaxPercentage=1.5/100;break;
        case 2  :   TaxPercentage=0.25/100;break;
        default :   TaxPercentage=3.5/100;
    }
    return RegularCost(i)-(RegularCost(i)*TaxPercentage);
}

float discount(int i) {

    float DiscountPercentage;

    switch (bill[i].BillClass) {
        case 1  :   DiscountPercentage=3.0/100;break;
        case 2  :   DiscountPercentage=2.0/100;break;
        default :   DiscountPercentage=5.5/100;break;
    }
    if (RegularCost(i)>100.0)
        return RegularCost(i)-(RegularCost(i)*DiscountPercentage);
    else
        return 0.0;
}

float TotalPayment(int i) {

    return RegularCost(i)+tax(i)-discount(i);
}

Note: I use Code Blocks for the IDE.

2

There are 2 answers

0
Sami Kuhmonen On

You are not allocating any memory for your names, so you're just writing into random places in memory. This is undefined behaviour.

2
John M On

I see a number of problems here.

First of all, your over-use of global variables is troubling. The array bill and the int DataAmount should definitely not be global. This is not good c programming practice and I would not trust someone whose code looks like this. Please give your "menu", "entry", "printcomplete", and "search" functions arguments so that you can make these variables local, not global.

Second, there are very few cases where it is acceptable to have many statements on the same line as in

 printf("Customer name: ");fflush(stdin);fflush(stdout);gets(bill[DataAmount].name);

I'm getting a headache just looking at it!!! pleeease don't!

Third, You are not using array bounds correctly in this for loop, which is the cause of the bug you are asking about in the first place.

 for (i=1;i<=DataAmount;i++) {
    fflush(stdin);fflush(stdout);
    printf("%d\t\t%15.15s\t\t%d\t$%.2f\n",bill[i].BillNumber,bill[i].name,bill[i].BillClass,TotalPayment(i));
}

Remember, in the C language, array indices start at 0 and end at "n - 1". Your loop is starting at 1 and ending at "n".

The reason for the bogus character is that you are accessing a BillDataBase that is outside the boundaries of the array bill.

Fourth, as Sami Kuhmonen said, you are not allocating any memory for your name array. Although this is probably not causing the bug you are seeing, it will almost certainly cause your program to crash with a segmentation fault at some point in the future. In order to fix this looming problem, you have 2 options

  1. The easy way out: change your BillDatabase struct to the following

    typedef struct
    {
        int BillNumber, BillClass;
        float LastMeter, CurrentMeter;
        char name[128];
    } BillDatabase;
    

    This is easy, but not good, because the name can never be more than 128 chars. Also, please don't EVER put the entire struct on one line. I almost started hitting myself over the head with my saxophone.

  2. The harder way out: learn to use malloc(), and manually allocate the name arrays.