Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop reading when reading mutliple files (without goto)

Tags:

c

I have files with a single column full of numbers and I want to sum all the files. The problem is to be able to exit as soon as invalid data is found (as soon as fprintf fails).

A first attempt using goto (and inspired by this answer) is the following

while(1) {
    sum_a = 0;
    for(i=0 ; i<N ;i++){
        if(fscanf(infiles[i], "%d\n", &a) != 1){
            goto end; // yeah, I know...
        }
        sum_a += a;
    }
    printf("%d\n", sum_a); // Should NOT be read if anything failed before
}

end:
for(i=0 ; i<N ;i++)
    fclose(infiles[i]);

I would glad to see a nicer solution (ie not using goto and while(1)!). I don't want to mess up with many flags set and unset in a dirty way.

like image 662
styko Avatar asked Dec 11 '22 16:12

styko


2 Answers

Why?

It's a perfectly valid use case of goto. It's the most readable solution, and does the job. Why bother changing it?

like image 183
Leandros Avatar answered Jan 08 '23 20:01

Leandros


Assuming that you wish to avoid this perfectly legitimate use of goto as a learning exercise, here is how you can do it: make a flag variable that indicates loop termination, set it in the inner loop, and check it in all loops:

int stop = 0;
while(!stop) {
    sum_a = 0;
    for(i=0 ; i<N ;i++){
        if(fscanf(infiles[i], "%d\n", &a) != 1){
            stop = 1;
            break;
        }
        sum_a += a;
    }
    if (!stop) {
        printf("%d\n", sum_a);
    }
}
for(i=0 ; i<N ;i++)
    fclose(infiles[i]);

Note how your code instantly became less readable, because printf needs to be protected by a conditional.

Another trick would be rewriting with a single loop and using break to stop. The readability would not suffer as much:

int i = 0;
for (;;) { // This "forever" loop is idiomatic in C
    if(fscanf(infiles[i], "%d\n", &a) != 1) {
        break;
    }
    sum_a += a;
    if (++i == N) {
        printf("%d\n", sum_a);
        i = 0;
    }
}
for(i=0 ; i<N ;i++)
    fclose(infiles[i]);
like image 36
Sergey Kalinichenko Avatar answered Jan 08 '23 18:01

Sergey Kalinichenko