0

I am making a simple library to store, edit, search books and add new books. I have the following structure:

struct books {
    char bname[150];
    char bauthor[100];
    unsigned bpages,
             price,
             numavail;
} info[MAX];   //array of structures

I have this function to calculate the number of books in the txt file and it works fine:

int numofbooks(FILE *ptr) {
    char ch;
    int num = 0, keep;
    ch = fgetc(ptr);
    while (ch != EOF) {
        if (ch == ':') {
            num++;
        }
        ch = fgetc(ptr);
    }
    return num / 5;
}

and I am using this function to add new books and store then in a txt file and also to the array info. Here the variable p is always 0 even there are books in the file:

void add() {
    int ans = 1;
    static int p;
    char bname[30], bauthor[30];
    unsigned price, bpages, numavail;
    FILE *ptr = fopen("books info.txt", "a");

    system("cls");
    if (ptr == NULL) {
        printf("Couldn't open the file....");
        exit(1);
    }
    p = numofbooks(ptr);  //calling numofbooks to store the number of books in the file in static variable p
    printf("%d", p);  //it always prints 0
    while (ans == 1) {
        printf("\nEnter The name of the book: ");
        fflush(stdin);
        gets(info[p].bname);
        fprintf(ptr, "Book name: %s\n", info[p].bname);
        fflush(stdin);
        printf("Enter The author of this book: ");
        gets(info[p].bauthor);
        fprintf(ptr, "Book author: %s\n", info[p].bauthor);
        fflush(stdin);
        printf("Enter The number of pages of this book: ");
        scanf("%u", &info[p].bpages);
        fprintf(ptr, "Number of pages: %u\n", info[p].bpages);
        fflush(stdin);
        printf("What is the price of the book (in EGP)? ");
        scanf("%u", &info[p].price);
        fprintf(ptr, "Price (in EGP): %u\n", info[p].price);
        printf("Number of books available: ");
        scanf("%u", &info[p].numavail);
        fprintf(ptr, "Number of books available: %u", info[p].numavail);
        fprintf(ptr, "\n---------------------------------------------------------\n");
        printf("\nBook information saved successfully....\n");
        fflush(stdin);
        printf("\nEnter (1) to add another book, (0) to exit or (2) for main menu. ");
        scanf("%d", &ans);
        if (ans == 2) {
            fclose(ptr);
            system("cls");
            main();
        }
    }
}

here is the function I used to search in the file using the name of the author:

void searchauthor(FILE *ptr) {
    char in_name[30];
    int flag = 1;
    ptr = fopen("books info", "r");
    fflush(stdin);
    printf("Enter the name of the author: ");
    gets(in_name);
    int num = numofbooks(ptr);      //num to hold number of books
    for (int i = 0; i < num; i++) {
        if (strcmpi(in_name, info[i].bauthor) == 0) {
            printf("%s %u %u %u", info[i].bname, info[i].price, info[i].numavail, info[i].bpages);
            flag = 0;
        }
    }
    if (flag == 1) {
        printf("Not found.");
    }
}

here is the code that reads data from the file:

        ptr = fopen("books info.txt", "r");
        printf("Total (%d) books are available:-\n\n", numofbooks(ptr));
        ptr = freopen("books info.txt", "r", ptr);
        ch = fgetc(ptr);
        while (ch != EOF) {
            printf("%c", ch);
            ch = fgetc(ptr);
        }

The problem is that this function always prints Not found although the name of the author is already in the txt file. how can I solve this?

A sample of the contents of the file

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Ok. I fixed and it worked, but on exiting the program and trying to search the same name again it prints not found – Ali Elneklawy Aug 26 '21 at 13:15
  • I edited the code in the question.... ptr = fopen("books info.txt", "r"); printf("\n\n Here are all the books we have in the library.....\n\n\n"); printf("Total (%d) books are available:-\n\n", numofbooks(ptr)); ptr = freopen("books info.txt", "r", ptr); ch = fgetc(ptr); while (ch != EOF){ printf("%c", ch); ch = fgetc(ptr); } here it is – Ali Elneklawy Aug 26 '21 at 13:36
  • `char ch;` should be `int ch;` , – wildplasser Aug 26 '21 at 13:45
  • `Couldn't open the file....` is the canonical example of a useless error message. Try: `const char *path = "books info.txt"; if( (ptr = fopen(path, "a")) == NULL) { perror(path); ...` Better still, use `argv[1]` instead of `path`. The main point is that the error message should be written to stderr and be informative. `perror` gives you both of those. – William Pursell Aug 26 '21 at 13:45
  • Don't flush stdin: https://stackoverflow.com/questions/2979209/using-fflushstdin – William Pursell Aug 26 '21 at 13:48
  • @Ali Elneklawy - Sample content of `books info.txt` would help. – Armali Aug 26 '21 at 14:40
  • @Armali ok I updated the question with an image of the file – Ali Elneklawy Aug 26 '21 at 16:01
  • 1
    @user3121023 yes exactly it prints nothing – Ali Elneklawy Aug 26 '21 at 16:05
  • @WilliamPursell Ok now I know that fflush() is dangerous but what should I use instead? – Ali Elneklawy Aug 26 '21 at 16:12
  • It depends on what you are trying to accomplish with the `fflush(stdin)`. – William Pursell Aug 26 '21 at 16:18
  • @WilliamPursell If I don't use it I get this: Enter the author of the book: Enter the number of pages: And I cannot enter the name of the author! – Ali Elneklawy Aug 26 '21 at 16:20

1 Answers1

0

Here is one way things could be arranged.
This addresses the issue of avoiding fflush(stdin) by using fgets for input and sscanf to parse as needed.
Generally it is a bad idea to call main from a function. Return to main and use a loop to repeat menu choices.

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

#define MAX 100

struct books{
    char bname[150];
    char bauthor[100];
    unsigned bpages;
    unsigned price;
    unsigned numavail;
} info[MAX];

int readbooks ( void) {
    FILE *ptr = fopen("books info.txt", "r");
    if ( ! ptr) {
        perror ( "books info.txt");
        return 0;
    }
    int book = 0;
    int field = -1;
    int each = 0;
    int parse = 0;
    int ch = 0;

    info[0].bname[0] = 0;
    info[0].bauthor[0] = 0;
    info[0].bpages = 0;
    info[0].price = 0;
    info[0].numavail = 0;

    while ( EOF != ( ch = fgetc ( ptr))) {
        printf("%c", ch);

        if ( '\n' == ch) {
            parse = 0;//end of line. no parsing
        }
        if ( parse) {
            if ( ! each && ( ' ' == ch || '\t' == ch)) {
                continue;//skip leading spaces
            }
            if ( 0 == field) {
                if ( each + 1 < 150) {
                    info[book].bname[each] = ch;
                    ++each;
                    info[book].bname[each] = 0;
                }
                printf ( "name %s  ", info[book].bname);
            }
            if ( 1 == field) {
                if ( each + 1 < 100) {
                    info[book].bauthor[each] = ch;
                    ++each;
                    info[book].bauthor[each] = 0;
                }
                printf ( "author %s  ", info[book].bauthor);
            }
            if ( 2 == field) {
                info[book].bpages *= 10;
                info[book].bpages += ch - '0';
            }
            if ( 3 == field) {
                info[book].price *= 10;
                info[book].price += ch - '0';
            }
            if ( 4 == field) {
                info[book].numavail *= 10;
                info[book].numavail += ch - '0';
            }
        }
        if ( ':' == ch) {
            ++field;
            if ( 5 == field) {
                field = 0;
                if ( book + 1 < MAX) {
                    ++book;
                    info[book].bname[0] = 0;
                    info[book].bauthor[0] = 0;
                    info[book].bpages = 0;
                    info[book].price = 0;
                    info[book].numavail = 0;
                }
            }
            each = 0;
            parse = 1;//resume parsing
        }
    }
    fclose ( ptr);
    if (4 == field) {
        ++book;
    }
    return book;
}

int add ( void) {
    int ans = 1;
    char line[100] = "";
    int p;

    p = readbooks();
    printf("%d", p);
    FILE *ptr = fopen("books info.txt", "a");
    if ( ! ptr) {
        perror ( "books info.txt");
        return 0;
    }
    while(ans == 1){

        printf("\nEnter The name of the book: ");
        fgets(info[p].bname, 150, stdin);
        info[p].bname[strcspn ( info[p].bname, "\n")] = 0;
        fprintf(ptr, "Book name: %s\n", info[p].bname);

        printf("Enter The author of this book: ");
        fgets(info[p].bauthor, 100, stdin);
        info[p].bauthor[strcspn ( info[p].bauthor, "\n")] = 0;
        fprintf(ptr, "Book author: %s\n", info[p].bauthor);

        printf("Enter The number of pages of this book: ");
        fgets ( line, 100, stdin);
        sscanf(line, "%u", &info[p].bpages);
        fprintf(ptr, "Number of pages: %u\n", info[p].bpages);

        printf("What is the price of the book (in EGP)? ");
        fgets ( line, 100, stdin);
        sscanf( line, "%u", &info[p].price);
        fprintf(ptr, "Price (in EGP): %u\n", info[p].price);

        printf("Number of books available: ");
        fgets ( line, 100, stdin);
        sscanf( line, "%u", &info[p].numavail);
        fprintf(ptr, "Number of books available: %u", info[p].numavail);
        fprintf(ptr, "\n---------------------------------------------------------\n");
        printf("\nBook information saved successfully....\n");
        ++p;
        printf("\nEnter    (1) to add another book\nor       (2) for main menu. ");

        fgets ( line, 100, stdin);
        sscanf( line, "%d", &ans);
        if (ans == 2)       {
            fclose(ptr);
        }
    }
    return p;

}

int main ( void) {
    int totalbooks = 0;

    totalbooks = add ( );
    for ( int each = 0; each < totalbooks; ++each) {
        printf ( "name %s\n", info[each].bname);
        printf ( "author %s\n", info[each].bauthor);
        printf ( "pages %u\n", info[each].bpages);
        printf ( "price %u\n", info[each].price);
        printf ( "number %u\n", info[each].numavail);
    }

    return 0;
}
user3121023
  • 8,181
  • 5
  • 18
  • 16