2
votes

I'm having an issue with using getline/fgets. I'm trying to read from stdin while piping the input from a file and then processing it. While it works just fine with gcc 4.8.5 on opensuse, it does not work on Arch Linux with gcc 7 and on latest ubuntu with gcc 5. The latter will simply skip a few lines of input. (I am piping the same file). In the example, my program would skip the third and fourth line when piped but not when entered manually. Same thing with bigger files only that always the sames lines are skipped. Any thoughts? Greatly appreciated. Thank you.

The input is of the form (each line is followed by a linefeed):

0 1 2
2 3 4
3 4 5
2 4 5
1 2 3
1
2
3

My code looks like this:

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

int bytes;
size_t nbytes = 100;
char *str = (char *) malloc(nbytes+1); // 1 byte for \0
long i = 0;
node *itemArray = malloc(sizeof(itemArray));

while ((bytes = getline(&str, &nbytes, stdin) != -1)) {
    char* token;
    char *rest = str;
    int callNums = 0;
    long from = 0;
    long to =  0;
    long weight = 0;

    while((token = strtok_r(rest, " ", &rest))) {
        if(callNums == 0) {
            from = atol(token);
                    }
        if(callNums == 1) to = atol(token);
        if(callNums == 2) weight = atol(token);
        callNums++;
    }

    if(callNums == 3) {
        if(i == 0) {
            itemArray[i].from = from;
            itemArray[i].to = to;
            itemArray[i].weight = weight;
            printf("%li %li %li \n", itemArray[i].from, itemArray[i].to, itemArray[i].weight);
        }

        if(i > 0) {
            node *tmp = realloc(itemArray, (i * sizeof(itemArray)));
            if(tmp) {
                itemArray = tmp;
                itemArray[i].from = from;
                itemArray[i].to = to;
                itemArray[i].weight = weight;
                printf("%li %li %li \n", itemArray[i].from, itemArray[i].to, itemArray[i].weight);
            }
            else { printf("realloc failed");
                exit(-1); }
        }
        ++i;
    }
   }
  }
  free(str);
  free(itemArray);
  return(0);
 }
1
Are you sure this example is representative? I don't see any fgets(). - EOF
I changed the code from fgets() to getline, thinking I could solve the issue that way. My code skips those two lines regardless of which I use. I should have mentioned that. My apologies. - markus
And letting getline allocate memory for me will add random content where the actual read input should be. - markus
Also avoid casting the return of malloc - Badda
@markus you're freeing str inside the loop that uses it. - Chris Turner

1 Answers

1
votes

Give this a try. By setting itemArray to NULL the first call to realloc will act like malloc. Setting str to NULL and nbytes to 0 should work fine with getline.
sscanf should work to scan three longs from a string. If three are successfully scanned they will be added to itemarray.

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

    int bytes;
    size_t nbytes = 0;
    char *str = NULL;
    long i = 0;
    node *itemArray = NULL;

    while ( ( bytes = getline ( &str, &nbytes, stdin) != -1)) {
        int callNums = 0;
        long from = 0;
        long to =  0;
        long weight = 0;

        if ( 3 == sscanf ( str, "%ld%ld%ld", &from, &to, &weight)) {

            node *tmp = realloc ( itemArray, ( ( i + 1) * sizeof ( *tmp)));
            if(tmp) {
                itemArray = tmp;
                itemArray[i].from = from;
                itemArray[i].to = to;
                itemArray[i].weight = weight;
                printf ( "%li %li %li \n", itemArray[i].from, itemArray[i].to, itemArray[i].weight);
            }
            else { 
                printf("realloc failed");
                exit(-1); 
            }
            ++i;
        }
    }
    free(str);
    free(itemArray);
    return(0);
}