1

I'm trying to get some ideas how to check for errors or mistypes in my data file. The errors are made by me, intentionally.

My file looks like this

Name HouseNr City Country number(how many sports) Sport1 Sport2 SportN

Carl Lincoln42 Houston USA 2 Basketball Football

while(fscanf(fData, "%s %s %s %s %d", (person + i)->name,
    (person + i)->adr.houseNr, (person + i)->adr.city, (huvi + i)->adr.country,
    &(sport + i)->sportCount) == 5)
{
    for (j = 0; j < (person + i)->sportCount; j++)
    {
        fscanf(fData, "%s", (person + i)->sportName[j]);
    }
    i++;
}

Now what I don't grasp is, how should I check for errors in that file.

Let's assume that number's value is higher than that of the SportN.

This would mean that it scans other person's details as SportName

How should I tackle this? Change some code (please, some suggestions) or change the way I store my data?

Community
  • 1
  • 1
Karl
  • 89
  • 5
  • Your conditions must take care of number and new line, for example – LPs Feb 15 '17 at 15:46
  • By errors I mean, if I type 5 in Number, but I only have 2 SportNames. – Karl Feb 15 '17 at 15:48
  • 3
    Is the data in the file *line based*? Then a good start is to read line by line, and parsing each line separately. – Some programmer dude Feb 15 '17 at 15:48
  • @LPs How to check for new line in fscanf? Is it even possible? @ Some programmer dude And if I should go the line by line way, how can I use sscanf to read the strings I want? I don't have fixed amount of strings – Karl Feb 15 '17 at 15:53
  • 4
    If you want the validation to be based on lines of data, then using `fscanf()` directly is wrong — it doesn't care about where newlines occur. It is simply the wrong tool for line-based processing where there may be errors. You need to read lines with [`fgets()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fgets.html) (or perhaps POSIX's [`getline()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html)) and then perhaps parse the result with [`sscanf()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sscanf.html). – Jonathan Leffler Feb 15 '17 at 15:54
  • @KarlJoonasVolke You can have a look at the `%[` format specifier to read lines. Something like: `char line[1000]; if(fscanf(fData, "%[^\n]%*c", line) != 1) { /* fscanf failed or EOF */ }` and then `sscanf` the line – Spikatrix Feb 15 '17 at 15:59
  • @JonathanLeffler Any idea how should I use sscanf when I dont know how many strings it should read? *Name HouseNr City Country* is always there, but after *number*, it depends on the *number* how many strings it reads – Karl Feb 15 '17 at 16:08
  • 2
    See [How to use `sscanf()` in loops?](http://stackoverflow.com/questions/3975236/how-to-use-sscanf-in-loops) Use `%n` to identify where the number of sports ends, then use the technique in that question to read the sports in turn. – Jonathan Leffler Feb 15 '17 at 16:18

1 Answers1

2

As @SomeProgrammerDude mentioned in the comments, it is much better to read the file line by line and parse each line accordingly.

You can use the %[ format specifier to read lines from the file. This can be achieved by using %[^\n] which tells *scanf to scan everything until a \n (or EOF, whichever comes first). Of course, it doesn't scan in the \n and as %[^\n] will fail if the first character to be read is a \n, you'll have to get rid of the newline after each line. This can be achieved by using a %*c right after the %[^\n]. It tells *scanf to read and discard a character.

Now that you've read the line, its time to parse it. The sscanf function along with the help of the %n format specifier can be used for this.

char line[1000];
int i = 0;
while(fscanf(fData, "%[^\n]%*c", line) == 1)
{
    int offset;
    if(sscanf(line, "%s %s %s %s %d%n", (person + i)->name,
    (person + i)->adr.houseNr, (person + i)->adr.city, (huvi + i)->adr.country,
    &(sport + i)->sportCount, &offset) != 5)
    {
        fprintf(stderr, "Invalid line '%s'\n", line);
        i++;
        continue; /* Move on to next line */
    }
    bool valid = true;
    for(int j = 0; j < (sport + i)->sportCount; j++)
        if(sscanf(line + offset, "%s%n", (person + i)->sportName[j], &offset) != 1)
        {
            valid = false;
            break;
        }
    char dummy[100];
    if(sscanf(line + offset, "%s", dummy) == 1)
        valid = false;

    if(valid)
        printf("Good input for line '%s'\n", line);
    else
        fprintf(stderr, "Invalid number of items in '%s'\n", line);
    i++;
}

Untested Code ↑

Community
  • 1
  • 1
Spikatrix
  • 20,225
  • 7
  • 37
  • 83