Parsing a comma separated file using C using fscanf()
c, file-io, scanf
Solution
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'`.
Problem
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?