George said:
George said:
On Tue, 18 Nov 2008 12:26:05 GMT, James Kuyper wrote:
George wrote:
assuming you mean the twenty lines at the beginning. Would fgets()
followed by
int line_num;
char data[32];
fscanf (line, "%d %32s", &line_num, data);
do the job?
Why fgets before scanf?
Key point to keep in mind here: I was thinking of sscanf(), not fscanf()
(or scanf()). The fgets()/sscanf() combo is the best way I know of to
read most text-format files.
I hadn't even disambiguated these. Am I correct that
scanf
sscanf
fscanf
are the only ones that look like another?
vfscanf
vscanf
vsscanf
swscanf
fwscanf
vfwscanf
vswscanf
vwscanf
wscanf
To decode those names: a prefix of 'f' means that it reads from a
specified file, 's' reads from a character string, and if neither is
present it reads from stdin. A prefix of 'v' means that takes a va_list
argument instead of a variable argument list, and a 'w' means that it
reads from a wchar_t source instead of a char source.
The list of printf() variants is even longer, since it includes things
like snprintf, for which there's no scanf() equivalent.
The math library has a similarly dizzying array of similar names, since
it uses a suffix of 'f' for functions that take float arguments and
produce float results, a suffix of 'l' indicates the use of 'long
double', and a prefix of 'c' indicates a function that works with
complex numbers.
In addition, there's a very confusing array of choices for rounding
numbers <math.h>, which are NOT all named with similar names.
Enjoy!
....
#include <stdio.h>
#include <stdlib.h>
#define PATH "george.txt"
#define NUMBER 100
#define BIN 1000
#define MAXFMTLEN 2000
int main(void)
{
FILE *fp;
char pattern[MAXFMTLEN];
char lnumber[NUMBER];
char lbin[BIN];
char line[MAXFMTLEN];
if ((fp = fopen(PATH, "r")) == NULL ) {
fprintf(stderr, "can't open file\n");
exit(1);
It's more portable to use EXIT_FAILURE. The standard defines what it
means when you use 0, EXIT_SUCCESS, or EXIT_FAILURE; it does not specify
say what an exit status of 1 means.
}
sprintf(pattern, "%%%ds %%%ds", BIN-1, NUMBER-1);
while ((fgets(line, MAXFMTLEN, fp)) != NULL ) {
sscanf(line, pattern , lnumber, lbin);
/*fscanf (fp, "%d %32s", &lnumber, lbin);*/
printf("%s\n", lbin);
}
I would add the following after the loop:
if(ferror(fp))
perror(PATH);
Q1) Does the while control satisfy your critism above?
I prefer
while(fgets(line, MAXFMTLEN, fp) == line)
If fgets() is functioning properly, !=NULL and ==line will produce the
exact same results. However, what if fgets() malfunctions and returns a
value that is neither equal to line nor a null pointer? Your version
treats a fgets() malfunction as a successful return; my version
terminates the loop. The chance that fgets() will malfunction should be
negligible, but so is the cost of using ==line rather than !=NULL.
I apply this logic to any function call that legally can produce only
two different values: I treat anything other than the value that
indicates success as a failure indicator.
Q2) Why doesn't the sprintf have to *follow* the while?
The pattern needs to be created only once, and it needs to be created
before it is used by sscanf(). Putting it inside the while loop would
pointlessly re-execute it during every pass through the loop.