I have a file with data something like this -
Name, Age, Occupation
John, 14, Student
George, 14, Student
William, 23, Programmer
Now, I want to read the data such that each value (e.g. Name, Age etc.) are read as a string.
This is my code snippet -
....
if (!(ferror(input_fp) || ferror(output_fp))) {
while(fscanf(input_fp, "%30[^ ,\n\t]%30[^ ,\n\t]%30[^ ,\n\t]",
name, age_array, occupation) != EOF){
fprintf(stdout, "%-30s%-30s%-30s\n", name, age_array, occupation);
}
fclose(input_fp);
fclose(output_fp);
}
....
However, this goes into an infinite loop giving some random output.
This is how I understand my input conversion specifiers.%30[^ ,\n\t] -> read a string that is at the maximum 30 characters long and that
DOES NOT include either a space, a comma, a newline or a tab character.
And I am reading 3 such strings.
Where am I going wrong?
OP's
fscanf(input_fp, "%30[^ ,\n\t]%30[^ ,\n\t]%30[^ ,\n\t]", ...
does not consume the ',' nor the '\n' in the text file. Subsequent fscanf() attempts also fail and return a value of 0, which not being EOF, causes an infinite loop.
Although OP requested a fscanf() solution, a fgets()/sscanf() better handles potential IO and parsing errors.
FILE *input_fp;
FILE *output_fp;
char buf[100];
while (fgets(buf, sizeof buf, input_fp) != NULL) {
char name[30]; // Insure this size is 1 more than the width in scanf format.
char age_array[30];
char occupation[30];
#define VFMT " %29[^ ,\n\t]"
int n; // Use to check for trailing junk
if (3 == sscanf(buf, VFMT "," VFMT "," VFMT " %n", name, age_array,
occupation, &n) && buf[n] == '\0') {
// Suspect OP really wants this width to be 1 more
if (fprintf(output_fp, "%-30s%-30s%-30s\n", name, age_array, occupation) < 0)
break;
} else
break; // format error
}
fclose(input_fp);
fclose(output_fp);
Rather than call ferror(), check return values of fgets(), fprintf().
Suspect OP's undeclared field buffers were [30] and adjusted scanf() accordingly.
[edit]
Details about if (3 == sscanf(buf, VFMT "," ...
The if (3 == sscanf(...) && buf[n] == '\0') { becomes true when:
1) exactly the 3 "%29[^ ,\n\t]" format specifiers each scanf in at least 1 char each.
2) buf[n] is the end of the string. n is set via the "%n" specifier. The preceding ' ' in " %n" causes any following white-space after the last "%29[^ ,\n\t]" to be consumed. scanf() sees "%n", which directs it to set the current offset from the beginning of scanning to be assign to the int pointed to by &n.
"VFMT "," VFMT "," VFMT " %n" is concatenated by the compiler to" %29[^ ,\n\t], %29[^ ,\n\t], %29[^ ,\n\t] %n".
I find the former easier to maintain than the latter.
The first space in " %29[^ ,\n\t]" directs sscanf() to scan over (consume and not save) 0 or more white-spaces (' ', '\t', '\n', etc.). The rest directs sscanf() to consume and save any 1 to 29 char except ',', '\n', '\t', then append a '\0'.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With