C while loop feof

Barry Percy picture Barry Percy · Mar 7, 2013 · Viewed 10.6k times · Source

This is part of a much bigger program to make a filmgenie and for some reason the program crashes as it reaches this while loop and i don't understand what my problem is.

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

FILE *fp, *fopen();
char *arrayoffilms[45];
int main()
{
    char line[100],junk[100];
    fp=fopen("filmtitles.txt","r");
    int i=0;
    while(!feof(fp)) {
        fscanf(fp,"%[^\n]s",line);
        strcpy(arrayoffilms[i],line);
        fscanf(fp,"%[\n]s",junk);
        i++;
    }
    fclose(fp);
    printf("%s\n\n\n",arrayoffilms[i]);
    return 0;
}

Answer

autistic picture autistic · Mar 8, 2013

feof will never return true until an actual read attempt is made, and EOF has been reached. The read attempts usually have return values that indicate failure. Why not use those, instead?

Don't confuse the %[ and %s format specifiers; %[ doesn't provide a scanset for %s; %[^\n]s tells scanf to read "one or more non-'\n' characters, followed by a 's' character". Does that make sense? Think about it, carefully. What is the purpose of this format specifier? What happens if the user merely presses enter, and scanf doesn't get it's "one or more non-'\n' characters"? Before we look for non-'\n' characters, it's important to get rid of any '\n' characters. Any whitespace bytes in the format string will cause scanf to consume as much whitespace as possible, up until the first non-whitespace character. I'm going to presume you wanted %[^\n], or perhaps even %99[^\n], which would prevent overflows of line.

Perhaps you'd also want to count the number of bytes processed by scanf, so you can malloc the correct length and copy into arrayoffilms, for some reason I can't imagine. You can use the %n format specifier, which will tell you how many bytes scanf processed.

I noticed that you want to read and discard the remainder of a line. In my example, the remainder of a line will only ever be discarded if 99 characters are read before a newline is encountered. I'll use the assignment suppression '*': %*[^\n].

Combining these format specifiers results in a format string of " %99[^\n]%n%*[^\n]", two arguments (a char * for %[ and an int * for %n), and an expected return value of 1 (because 1 input is being assigned). The loop will end when the return value isn't 1, which will likely be caused by an error such as "reading beyond eof".

int length;
while (fscanf(fp, " %99[^\n]%n%*[^\n]", line, &length) == 1) {
    arrayoffilms[i] = malloc(length + 1);
    strcpy(arrayoffilms[i], line);
    i++;
}