tags:

views:

408

answers:

6

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

+7  A: 

Use strtol instead.

Marcelo Cantos
what if i have no idea how long the first int could be? i need to declare the string array before hand to pass to fscanf. presumably i could make one of these ints enormous, which would require the initialization of an enormous array.
hatorade
@hatorade - No, the `int` type will overflow long before the biggest number you could store in `char[80]`.
Chris Lutz
`char[80]` can handle 256 bit integers...
R Samuel Klatchko
A: 

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

Anders K.
+5  A: 

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.

Chris Lutz
+1  A: 

What about

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

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

mcabral
+5  A: 

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;
}
Jerry Coffin
A: 

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