Reputation: 25538
Imagine I have a csv with and each value is an integer. so the first value is the INTEGER 100
.
I want fscanf() to read this line, and either tell me it's an integer ONLY, or not. So, it would pass 100
but fail on 100t
. What i've been trying to get work is "%d," where the comma is the delimiter of my CSV. so the whole function is
fscanf(fp, "%d,", &count)
Unfortunately, this fails to fail on '100t,' works on '100' and works on 't'. so it just isn't distinguishing between 100
and 100t
(all of these numbers are followed by commas, of course
Upvotes: 1
Views: 1900
Reputation: 123448
The scanf()
family of functions aren't very good at detecting this kind of error. It's not impossible (see Jerry Coffin's answer, which works but is IMO difficult to generalize), but IMO it's not that robust. The better option is to use fgets()
to read input as text, tokenize with strtok()
or similar, and then use strtol()
or strtod()
to convert tokens to numerical values:
char buffer[LINE_SIZE];
while (fgets(buffer, sizeof buffer, inFile))
{
char *token;
char *newline = strchr(buffer, '\n');
if (newline)
*newline = 0;
token = strtok(buffer, ",");
while (token)
{
char *chk;
int value = (int) strtol(token, &chk, 10);
if (!isspace(*chk) && *chk != 0)
{
printf("%s is not a valid integer\n", token);
}
else
{
printf("successfully read integer value %d\n", val);
}
token = strtok(NULL, ",");
}
}
if (feof(inFile))
{
printf("Hit end-of-file\n");
}
else
{
printf("Error during read\n");
}
Upvotes: 0
Reputation: 490108
fscanf is actually much more usable than some of the other answers would imply -- but most people don't know it very well, and don't know how to exercise its full capabilities.
Useful points: first of all, use the return value from fscanf -- it tells you how many items were converted. Second, the "scan set" conversion can be extremely useful. Consider the following (I've used sscanf
to avoid requiring an external file, but fscanf
differs only in the source from which it reads):
#include <stdio.h>
int main() {
int i;
char *test[] = {
"100,", // should succeed.
"100t,", // should fail.
"t" // should also fail.
};
for (i=0; i<3; i++) {
int count;
char ch[2];
if (2 == sscanf(test[i], "%d%[,]", &count, &ch))
fprintf(stderr, "Conversion of \"%s\" succeeded.\n", test[i]);
else
fprintf(stderr, "Conversion of \"%s\" failed.\n", test[i]);
}
return 0;
}
Upvotes: 5
Reputation: 3558
What about
fscanf(fp, "%d%c", &count, &aChar)
if aChar != ',' && != '\n' then you don't have only an integer
Upvotes: 1
Reputation: 75389
You don't.
The problem is that fscanf()
isn't very useful. The best way to handle it is to read in an entire line (or significant chunk of the line) and then analyze the string. Here's an example:
int value;
char *extra;
char buffer[100];
// read in some data from the buffer
fgets(buffer, sizeof buffer, stdin);
// parse out a digit, if we can
i = strtol(buffer, &extra, 0);
At this point, you can check extra
to see if there are any extra characters, meaning the line wasn't purely a number, or if extra
points to the beginning of buffer
, meaning there was no number to parse.
Upvotes: 5
Reputation: 36082
scanf-functions on input that is not 100% controlled can be a pain to get error free, it is better to read the line using fgets() then use strtok() to split up the line in tokens which then can be converted.
using atoi on one token like "100t" would then yield 0 whereas "100" would yield 100
Upvotes: 0