简体   繁体   中英

C - how to get fscanf() to determine whether what it read is only digits, and no characters

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

请改用strtol

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.

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;
}

What about

fscanf(fp, "%d%c", &count, &aChar)

if aChar != ',' && != '\\n' then you don't have only an integer

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

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");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM