Search code examples
cfindlinefgets

Reading line by line C


I have a txt file with some file names and their size. This is how I wrote the txt file:

banana //file name
3 //the size of file banana
programs
12
music
524

I have to find a keyboard entered file name and display it's size.

This is my code:

 FILE *text;
 text=fopen("text.txt","r");
 printf("Scan the number of letters of your file name");
 int n;
 scanf("%d",&n);
 char s[++n];
 printf("Scan the file name you are looking for: ");
 int i;
   for(i=0;i<=n;i++)
   {
       scanf("%c",&s[i]);
   }
 int l=0;
 char c[n];
 char g;
   while(!feof(text))
   {
       if(l%2==1) {fgetc(text); fgetc(text); l++;}
       if(l%2==0)
       {
         fgets(c,n,text);
         fgetc(text);
           for(i=0;i<n;i++)
           {
             printf("%c",c[i]);
           }
           l++;
       }
   }

Obviously, it's not correct. Can you help me? I'm a little bit confuse.


Solution

  • Ugh! Please learn more about basic input. Your program has various flaws:

    • fgetc reads single characters. This can be useful at times, but obviously you want to read whole lines. fgets does this. You use it once, but it is not advisable to mix these. Decide up front which input paradigm you want to use: char-wise (fgetc), line-wise (fgets) or token-wise (fscanf).
    • Please don't make the user enter the number of characters in the filename. Quick, how many characters are there in MySpiffyDocument.txt? That's work that the computer should do.
    • Don't use feof to control yopur input. All input functions have special return values toat indicate that either the end of the file was read or that an error occurred. For fgets, this return value is NULL, for fgetc, this return value is the special constant EOF. The functions feof and ferror are useful after you have encountered the special return values for a post mortem analysis of the two end conditions.
    • Your inner loop, which is responsible for the core program logic, doesn't make sense at all. For example, for an odd l, increment l and then test for an even l – which will be true, because you have just incrremented an odd l. Use else in such cases. And don't place things that happen anyway in conditional blocks: Increment l once after the if/else blocks.

    Here's an example implementation:

    #include <stdlib.h>
    #include <stdio.h>
    
    int process(const char *filename)
    {
        char line[80];
        char name[80];
        int size;
        int count = 0;
    
        FILE *f = fopen(filename, "r");
    
        if (f == NULL) return -1;
    
        while (fgets(line, sizeof(line), f)) {
            if (count % 2 == 0) {
                if (sscanf(line, "%s", name) < 1) continue;
            } else {
                if (sscanf(line, "%d", &size) < 1) continue;
                printf("%12d   %s\n", size, name);
            }
    
            count++;
        }
        fclose(f);
    
        return 0;    
    }
    
    int main()
    {
        char line[80];
        char name[80];
    
        puts("Please enter filename:");
    
        while (fgets(line, sizeof(line), stdin)) {
            if (sscanf(line, "%s", name) == 1) {
                process(name);
                break;
            }
        }
    
        return 0;
    }
    

    Things to note:

    • The program uses 80 characters a max. buffer size; that means your lines can be up to 78 characters long – line content plus new-line '\n' plus null terminator '\0'. That should be okay for many cases, but eventually the line may overflow. (So your file-name letter count has some merit, but the real solution here is to allocate memory dynamically. I won't open that can of worms now.)
    • The code uses a double strategy: Read lines first, then scan into these lines with sscanf, so that only the first word on each line is read.
    • Empty lines are skipped. Even lines that don't hold a valid number are skipped, too. This is sloppy error handling and may trip the odd/even count.
    • Reading stuff interactively from the keyboard isn't very easy in C. The awkward fgets/sscanf construct in main tries to handle the case when the user enters an empty line or evokes an end-of-file signal via Ctrl-D/Z. A better and easier way is to provide arguments to the command line via argc and argv.
    • I've moved the file reading into a separate function.