0
votes

I'm having a harsh time achieving this. I read a string of integer, extract them from that chain and put them in an array. I wanted to try something new because a used to read character by character with getChar in the past, but now I find sscanf which handle the job.

From Doc (sscanf) : On success, the function returns the number of items in the argument list successfully filled. This count can match the expected number of items or be less (even zero) in the case of a matching failure. In the case of an input failure before any data could be successfully interpreted, EOF is returned.

line : char line[] = "100 185 20 11 1000"; // number of int is unknown, it can differ

Problem: How to make diffrence between end of line and a whatever error

Eg: char line[] = "100 185 abc(not int) 11 1000";

Code :

int main(int argc, char** argv) {

    char line[] = "100 185 20 11 1000";    
    int  arrOfInt[10];
    char *data = line;
    int  track, number, index = 0;

    while ((sscanf(data, " %d%n", &number, &track)) == 1)
    {
        arrOfInt[index] = number;
        data += track;
        index++;
    }
    return 0;
}
3
while....== 1...emm..why? - Sourav Ghosh
1 means success - David Edgar
is it? Din't you write "On success, the function returns the number of items in the argument list successfully filled." ? - Sourav Ghosh
@SouravGhosh %n is not counted as read elements. - BLUEPIXY
save return value of sscanf. E.g (status=sscanf(data, " %d%n", &number, &track)) == 1... end of line : status == EOF, read error : status == 0 - BLUEPIXY

3 Answers

2
votes

@BLUEPIXY mentioned the correct answer. Just formalizing it here.

If the return value of scanf is EOF that means an EOF is seen. If it is 0 that means some other error has occurred and the value set via %n is undefined(eg. the input does not match the format specified).

The following approach works as long as there are no tokens with mixed alphabets and letter like "hey45hey2".

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {

    char line[] = "100 185 20 11 1000 sdf 342 hey45hey2";    
    int  arrOfInt[10];
    char *data = line;
    int  track, status = 0, number, index = 0;

    // read until an EOF is found
    while ((status = sscanf(data, " %d%n", &number, &track)) != EOF)
    {
        // store only if status is non-zero i.e. sscanf has read according to the format specified
        if(status != 0){
            arrOfInt[index] = number;
            index++;
        }
        else
            track=1;
        data += track;
    }
    // print the array back to check if we read correctly
    int i;
    for(i=0;i<index;i++)
    printf("%d ", arrOfInt[i]);
    return 0;
}

The output of this code is:

100 185 20 11 1000 342 45 2

If you want to exclude strings like "hey45hey2" from the output, then use the following.

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {

    char line[] = " egsdfgfd rgege 100 185 20 11  hey45hey2 0d0  00 sddbrsdtbrtsdbrsf 342";    
    int  arrOfInt[10];
    char *data = line;
    int  track, status = 0, index = 0;
    char str[100]; // will fail for tokens of length more than 100

    // read until an EOF is found
    while ((status = sscanf(data, "%s%n", str, &track)) != EOF)
    {
        // store only if status is non-zero
        if(status != 0){
            // check if str is all zeros
            int num=(int)strtol(str,0,10); 
            char *i = str;
            if(num == 0){
                while(*i){
                    if(*i != '0') break;
                    i++;
                }
            }
            if(*i == 0 || num != 0){
                // if *i is zero, then num is also zero
                arrOfInt[index] = num;
                index++;
            }
        }
        else
            track = 1;
        data += track;
    }
    // print the array back to check if we read correctly
    int i;
    for(i=0;i<index;i++)
    printf("%d ", arrOfInt[i]);
    return 0;
}

Output is 100 185 20 11 0 342

1
votes

How to make diffrence between end of line and a whatever error

Sorry to say this, but the answer is: Drop sscanf, and do the parsing yourself.


If, for what ever reasons, you need/want to stick to sscanf you could always do a test on the "string" after sscanf is done, to see if there is more after the last token read, as you know the number of tokens parsed. You would do this for example by tokenizing the string beforehand using strtok on whitespaces, if you scanned in few, then you'd advance the string pointer behind the last+1 token and continue using sscanf. But is this sane? ;-)

1
votes

I achieved what I really wanted to do by using your advice. Just to mention that when I find undesired character I have to leave my loop and show error.

Code(can be useful for others)

int main(int argc, char** argv) {

    char line[] = "100 185 20 11 1000"; // or "100 185 abc 11 1000"     
    int  arrOfInt[10];
    char *data = line;
    int  track, number, index = 0;

    int statutLine;


    while ((statutLine = sscanf(data, " %d%n", &number, &track)) == 1)
    {
        arrOfInt[index] = number;
        data += track;
        index++;
    }

    if(statutLine == 0){
        printf("Line invalide");
    }

    if(statutLine == EOF){
        printf("Line valide");
    }

    return 0;
}