drowsell
drowsell

Reputation: 1

Stopping a While Loop Via EOF in C

I'm just learning C and I'm running into a problem with my basic understanding. What I am attempting to do is print X the same number of times as the input. The input is all on the same line, and I have that working well right now.

The problem I am running into is with ending the program. What I am trying to do is have the program end after the line is read.

example: input 1 2 3

Output:

X
XX
XXX

PROGRAM ENDS

Right now I am just on a loop forever...

Can anyone try to explain the concept that I am missing here? I'm sure it may be a syntax thing, but I'm really trying to get an understanding of where my logic is wrong.

How does EOF work in this case?

    int main(void)

{

int i;

int n = 0;

while ( n  != EOF ) {

scanf( "%d",&n );

    if (n == EOF){

    break;

    }

        for ( i=0; i<n; i++){

        printf("X");
    }

    printf("\n");

}

}

Upvotes: 0

Views: 2482

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84521

You can do what you are trying to do, just not the way you are doing it...

For starters, you must always validate the return of scanf. You must protect against three cases:

  1. EOF returned - meaning the end of input was reached before any input was encountered (this can be manually generated by the user by pressing Ctrl+d (or Ctrl+z on windows1));

  2. less than then number of conversion specifiers is returned indicating a matching or input failure (when this occurs, extracting characters from the stream stops and you are responsible for removing any extraneous characters before your next attempted read); or

  3. the return equals the number of conversion specifiers -- indicating that data was converted and stored in each variable you provided;

Further, you must validate the input received is within an acceptable range. (you probably do not want negative values input.

For your code, you can simply validate (3) above and exit on EOF, or a matching or input failure -- because you are only reading 1-type of data (integers) and can exit on any failure.

But that doesn't solve your problem. The correct way to approach this problem is reading a line of data at a time (with fgets or POSIX getline) and then parsing each integer value from the line of data by repeated calls to strtol and making use of its endptr parameter to work your way down the entire line. (there are many examples on SO about its proper use)

However, you can also do what you want to do by simply checking the next character after you read each int with getchar() and if it is '\n', then your read is done, otherwise you need to put the character back in stdin using ungetc and validating the put-back succeeded by what? (hint: checking the return -- the return of every C-library function is clearly described in it associated man page -- use them :)

Putting it altogether, you could do something like:

#include <stdio.h>

int main (void) {

    int i, n;

    printf ("input: ");

    while (scanf ("%d", &n) == 1) { /* validate the 'return' of scanf */
        if (n < 0) {    /* validate n not negative */
            fprintf (stderr, "error, input cannot be negative.\n");
            return 1;
        }
        for (i = 0; i < n; i++)     /* then loop that number of times   */
            putchar ('X');          /* don't printf 1-char, use putchar */
        putchar ('\n');             /* tidy up with newline */

        i = getchar();      /* read next char in stdin */
        if (i == '\n')      /* if end of line - break (done) */
            break;
        else if (ungetc (i, stdin) != i) {  /* validate putting it back */
            fprintf (stderr, "error: putting char back in stdin.\n");
            return 1;
        }
    }

    return 0;
}

Example Use/Output

$ ./bin/output_x
input: 1 2 3
X
XX
XXX

or

$ ./bin/output_x
input: 7 1 1 5 1 1 1
XXXXXXX
X
X
XXXXX
X
X
X

Look things over and let me know if you have further questions.

Footnotes

  1. But see: CTRL+Z does not generate EOF in Windows 10

Upvotes: 1

Related Questions