0

I am trying to extract records from a text file named lib.txt. My program is a very simple library based management program where I will have to print all books by a given publisher or department. My code is:

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

struct Books
{
    char name[100];
    char author[100];
    char publisher[100];
    double price;
    char branch[100];
};

typedef struct Books Books;

void main()
{
    int a = 0,b=0,ch,i;
    char *pb = (char *)malloc(100*sizeof(char));
    Books *bk;
    FILE *fp;
    fp = fopen("lib.txt","r");
    if(fp == NULL)
    {
        fprintf(stderr,"\n Error to open the file \n");
        exit(1);
    }
    while(1)
    {
        if(feof(fp))
        {
            break;
        }
        char c;
        c = fgetc(fp);
        if(c=='\n')
        {
            a++;
        }
    }
    a++;
    bk = (Books *)malloc(a*sizeof(Books));
    while(fread(&bk[b],sizeof(Books),1,fp))  //Even tried individual character extraction but it is not working
    {
        b++;
        if(b==a)
        {
            break;
        }
    }
    for(i=0;i<a;i++)
    {
        printf("%s",bk[i].name);
    }
    printf("1. Display books supplied by a particular publisher \n");
    printf("2. Display books in a particular branch \n");
    printf("3. Exit");
    printf("\n");
    printf("Enter your choice : ");
    scanf("%d",&ch);
    switch(ch)
    {
        case 1:
        {
            printf("Enter the name of publisher \n");
            scanf(" %s",pb);
            printf("\nName\tAuthor\tPublisher\tPrice\tBranch\n");
            for(i=0;i<a;i++)
            {
                if(strcmp(bk[i].publisher,pb)==0)
                {
                    printf("%s\t%s\t%s\t%.2lf\t%s \n",bk[i].name,bk[i].author,bk[i].publisher,bk[i].price,bk[i].branch);
                }
            }
            fflush(pb);
            break;
        }
        case 2:
        {
            printf("Enter the name of branch \n");
            scanf(" %s",pb);
            printf("\nName\tAuthor\tPublisher\tPrice\tBranch\n");
            for(i=0;i<a;i++)
            {
                if(strcmp(bk[i].publisher,pb)==0)
                {
                    printf("%s\t%s\t%s\t%.2lf\t%s \n",bk[i].name,bk[i].author,bk[i].publisher,bk[i].price,bk[i].branch);
                }
            }
            fflush(pb);
            break;
        }
        case 3:
        {
            return;
        }
        default:
        {
            printf("Invalid choice");
        }
    }
    free(bk);
    free(pb);
    fclose(fp);

    getch();
}

The file lib.txt contains the following lines in same order as shown below:

Abc1    A1  P1  23.0    B1
Abc2    A2  P2  23.0    B2
Abc3    A3  P3  23.0    B3
Abc4    A4  P2  23.0    B4
Abc5    A5  P2  23.0    B5
Abc6    A6  P6  23.0    B6
Abc7    A7  P2  23.0    B7

Oh and they are seperated by tabs. Even tried with spaces but no change. The program is compiling fine but not generating desired output. Can anyone please please help? Edit: Even tried individual character extraction and then splitting into substrings but failed. Please help

1 Answers1

1

Here is how I would do it:

First, define some functions to help you read input (you can use them in other programs as well):

int readint(int *i)
{
    char buffer[255];
    if (!fgets(buffer, 255, stdin)) {
        fprintf(stderr, "stdin error\n");
        return 0; // failed
    }

    buffer[strcspn(buffer, "\n")] = '\0';
    
    if (sscanf(buffer, "%d", i) != 1)
        return 0; // failed
    
    return 1; // success
}

char *readstr(char *str, int size)
{
    if (!fgets(str, size, stdin)) {
        fprintf(stderr, "stdin error\n");
        return NULL;
    }
    
    str[strcspn(str, "\n")] = '\0';
    return str;
}

Then your main():

int main()
{
    // 1. Attempt to open file
    // ------------------------------------------------------------------------
    FILE *fp = fopen("lib.txt", "r");
    if(!fp) {
        fprintf(stderr, "Error to open the file\n");
        return 1;
    }
    
    
    // 2. Read file text
    // ------------------------------------------------------------------------
    int lines_count = 7; // Depends on how many lines you have
    Books *bk = malloc(lines_count * sizeof(*bk));
    if (!bk) {
        fclose(fp);
        return 0;
    }
    
    char line[255];
    int i = 0;
    
    while(fgets(line, sizeof line, fp)) {
        line[strcspn(line, "\n")] = '\0'; // Remove \n read by fgets()
        
        char name[100];
        char author[100];
        char publisher[100];
        double price;
        char branch[100];
        
        int ret = sscanf(line, "%99[^\t]\t%99[^\t]\t%99[^\t]\t%lf\t%99[^\t]", name, author, publisher, &price, branch);
        if (ret != 5) {
            printf("Line %d is problematic.\n", i+1);
        }

        strcpy(bk[i].name, name);
        strcpy(bk[i].author, author);
        strcpy(bk[i].publisher, publisher);
        bk[i].price = price;
        strcpy(bk[i].branch, branch);
        
        i++;
    }
    
    fclose(fp);
    
    // 3. User input
    // ------------------------------------------------------------------------
    
    printf("1. Display books supplied by a particular publisher\n");
    printf("2. Display books in a particular branch\n");
    printf("3. Exit");
    printf("\n");
    
    printf("Enter your choice: ");
    int ch;
    readint(&ch); // Ignored error checking for the sake of simplicity
    
    char pb[100];
    
    switch(ch)
    {
    case 1:
        printf("Enter the name of publisher: ");
        readstr(pb, sizeof(pb));
        
        printf("\nName\tAuthor\tPublisher\tPrice\tBranch\n");
        for(i = 0; i < lines_count; i++)
            if(!strcmp(bk[i].publisher, pb))
                printf("%s\t%s\t%s\t%.2lf\t%s \n", bk[i].name, bk[i].author, bk[i].publisher, bk[i].price, bk[i].branch);

        break;

    case 2:
        printf("Enter the name of branch: ");
        readstr(pb, sizeof(pb));
        
        printf("\nName\tAuthor\tPublisher\tPrice\tBranch\n");
        
        for(i = 0; i < lines_count; i++)
            if(!strcmp(bk[i].branch, pb))
                printf("%s\t%s\t%s\t%.2lf\t%s \n",bk[i].name, bk[i].author, bk[i].publisher ,bk[i].price, bk[i].branch);
        
        break;
    
    case 3:
        return 0;
    
    default:
        printf("Invalid choice\n");
    }
    
    free(bk);
}

Make sure lib.txt contains tabs, not spaces. You should verify if your editor is replacing tabs with spaces.


Few things to consider:

  1. main() should always return int, not void.
  2. Use fgets() to read input from the user, and sscanf() to parse it. You should avoid using scanf() as much as you can.
Zakk
  • 1,935
  • 1
  • 6
  • 17
  • thank you very much. You don't know how much this helped me. And thanks for giving those advises as well. They really helped. Thank you. – Surya Majumder Sep 16 '21 at 04:07
  • can you please explain to me what is the use of sscanf() in buffer for integer? – Surya Majumder Sep 16 '21 at 05:05
  • Ok sorry to disturb you I got it @Zakk. Thank you very much. – Surya Majumder Sep 16 '21 at 05:54
  • Umm sorry to disturb you @Zakk but readstr is giving error conflicting types – Surya Majumder Sep 16 '21 at 07:02
  • This is much closer to what you want: the input is read by `fgets` line by line into a buffer and then `sscanf` is used to parse that. To be robust, I'd also warn if the line doesn't fit in the line buffer. The trouble with `[f]scanf` is it doesn't delineate between whitespace, which you need here. – Neil May 16 '22 at 15:57