Today I’ve looked over some C code that was parsing data from a text file
and I’ve stumbled upon these lines
fgets(line,MAX,fp);
if(line[strlen(line)-1]=='\n'){
line[strlen(line)-1]='\0');
}else{
printf("Error on line length\n");
exit(1);
}
sscanf((line,"%s",records->bday));
with record being a structure
typedef struct {
char bday[11];
}record;
So my question here regards the fgets-sscanf combination to create a type/length safe stream reader:
-
Is there any other way to work this out beside having to combine these two readers?
-
What about the
\nchecking-removing sequence?
The combination of
fgets()withsscanf()is usually good. However, you should probably be using:This checks for I/O errors and EOF. It also assumes that the definition of the array is visible (otherwise
sizeofgives you the size of a pointer, not of the array). If the array is not in scope, you should probably pass the size of the array to the function containing this code. All that said, there are worse sins than usingMAXin place ofsizeof(line).You have not checked for a zero-length birthday string; you will probably end up doing quite a lot of validation on the string that is entered, though (dates are fickle and hard to process).
Given that MAX is 60, but
sizeof(records->bday) == 11, you need to protect yourself from buffer overflows in thesscanf(). One way to do that is:Note that the
10issizeof(records->bday) - 1, but you can’t provide the length as an argument tosscanf(); it has to appear in the format string literally. Here, you can probably live with the odd sizing, but if you were dealing with more generic code, you’d probably think about:The first
%%maps to%; the%zuformats the size (zis C99 forsize_t); thesis for the string conversion when the format is used.Or you could consider using
strcpy()ormemcpy()ormemmove()to copy the right subsection of the input string to the structure – but note that%10sskips leading blanks whichstrcpy()et al will not. You have to know how long the string is before you do the copying, of course, and make sure the string is null terminated.