1

So right now, I'm majoring in CS and we've been learning about C. I've been doing pretty good with the exercises except for this problem with the while loops.

The problem asks us to read in an input from the user until they enter the integer -1. If that is their first input, then the program should print "NO INPUT". Otherwise, it prints the integer with the max value.

I just can't seem to wrap my head around this and although it seems simple, I've spent hours scouring the Internet for answers yet I'm unable to complete the code. This is what I've gotten so far:

    int main(int argc, char** argv)
{
    //Problem 1
    int input, max;
    max = 0;
    
    do
    {
        scanf("%d", &input);
        if (input != -1)
        {
            if (input >= max)
            {
                max = input;
            }
        }
        else
        {
            printf("%d\n", max);
            break;
        }
    } while (1);


    return (EXIT_SUCCESS);
}

I tried putting the "NO INPUT" line first in the body but it will print it even after I've entered other numbers and I need to get the program to output the negative numbers as well. For example, if I've entered -10000 multiple times until I enter -1 to end the loop, then it should say -10000 but the code will output 0.

3
  • Instead of initializing max to 0, you want ideally negative infinity, or, practically speaking, something like -99999999. That way the max can be less than zero. Commented Mar 14, 2021 at 4:40
  • 2
    Create another flag variable max_set = 0; then start reading input. if (input == -1 && !max_set) { /* show NO INPUT */ } otherwise max_set = 1; and use your general comparison against max. Note: you must check the return of scanf() EVERY time... Commented Mar 14, 2021 at 4:40
  • To me, the -1 being treated special only at first is a suprising user interface that I still don't understand. It's very specific; I'd love to hear the use-case for this input. Commented Mar 14, 2021 at 5:30

2 Answers 2

1

In order to print "NO INPUT", you could have a variable which keeps track of whether input has been entered. I suggest creating a variable (Something like has_input) and set its value to 0 before entering the do..while loop. When you receive input other than -1, set it to 1. Then when you exit the program, check if has_input is equal to 0. If it is, that means you never recieved an input other than -1, so you should print "NO INPUT", if it's not, print the value of max.

As to why it outputs 0 even when you feed it negative numbers, think about what happens when you input -10000: it compares that value to the current value of max, which is set to 0 by default. The max of -10,000 and 0 is 0, and so max will never drop below its default value. To fix this, you could initialize it to the lowest possible int value, which is usually -2,147,483,648.

Alternatively, you could ask the user for input once before entering the do..while loop and initialize max with that value, exiting with a "NO INPUT" if the input is -1, solving both problems.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your suggestion and explaining the problem to the output. It makes sense now!
0

To begin, you must validate the return of every input function used -- every time. Otherwise, you invite undefined behavior be using a variable without knowing whether the input succeeded or failed. Always check the return (especially when using scanf())

Moreover, you must handle a matching-failure (user slips and presses 'r' instead of 4) and clear all characters from stdin before you attempt the next input in your loop. If you fail to do so, you will spin off into an infinite loop. Try entering 'r' in your code and see what happens?

In your case, you need to know if you are on your first trip though the loop or not. Just declare another int to use as a flag to indicate if your are in the first iteration or not. You can just use int first_loop = 1; to indicate your first trip through the loop, and set it to 0 during your loop. (don't worry that you set it to 0 every iteration, that is negligible)

Putting it altogether, your main could look like:

int main (void) {
    
    int max = INT_MIN,                  /* initialize max to minimum possible value */
        first_loop = 1;                 /* flag for 1st iteration, set true */ 
    
    while (1) {                         /* loop continually */
        int rtn, tmp;                   /* variable for scanf() return, temp value */
        
        fputs ("enter value, -1 to exit: ", stdout);    /* prompt user */
        
        if ((rtn = scanf ("%d", &tmp)) == EOF) {        /* read input saving return */
            puts ("(user canceled input)");             /* manul EOF, user canceled */
            return 0;
        }
        else if (rtn == 0) {            /* return 0, matching failure occurred */
            fputs ("  error: invalid integer input.\n", stderr);
            empty_stdin();              /* empty offending characters from stdin */
            continue;                   /* get next input */
        }
        
        if (tmp == -1) {                /* if input was -1 */
            if (first_loop) {           /* if first_loop set, 1st iteration */ 
                puts ("NO INPUT");      /* output NO INPUT and exit */
                return 0;
            }
            break;                      /* otherwise, break read-loop */
        }
        
        if (tmp > max)                  /* set max as necessary */
            max = tmp;
        
        first_loop = 0;                 /* set first loop flag false */
    }
    
    printf ("\nmax: %d\n", max);        /* output result */
}

Note: setting of max to the minimum possible value in the range of int, INT_MIN. This is necessary whenever you are testing for max (and the converse for min). What if all the user enters are large negative values? There will be a maximum in the input, but you will never see it with max initialized to 0;

Also note the empty_stdin() function used to remove the characters that remain in stdin after a matching-failure occurs with scanf(). You simply loop until you find the '\n' generated by the user pressing Enter or you reach EOF for stdin. It can be nothing more than:

/* simple function to empty stdin */
void empty_stdin (void)
{
    int c = getchar();
    
    while (c != '\n' && c != EOF)
        c = getchar();
}

Lastly note, you will need to include limits.h for INT_MIN, so with that, the full program could be:

#include <stdio.h>
#include <limits.h>

/* simple function to empty stdin */
void empty_stdin (void)
{
    int c = getchar();
    
    while (c != '\n' && c != EOF)
        c = getchar();
}

int main (void) {
    
    int max = INT_MIN,                  /* initialize max to minimum possible value */
        first_loop = 1;                 /* flag for 1st iteration, set true */ 
    
    while (1) {                         /* loop continually */
        int rtn, tmp;                   /* variable for scanf() return, temp value */
        
        fputs ("enter value, -1 to exit: ", stdout);    /* prompt user */
        
        if ((rtn = scanf ("%d", &tmp)) == EOF) {        /* read input saving return */
            puts ("(user canceled input)");             /* manul EOF, user canceled */
            return 0;
        }
        else if (rtn == 0) {            /* return 0, matching failure occurred */
            fputs ("  error: invalid integer input.\n", stderr);
            empty_stdin();              /* empty offending characters from stdin */
            continue;                   /* get next input */
        }
        
        if (tmp == -1) {                /* if input was -1 */
            if (first_loop) {           /* if first_loop set, 1st iteration */ 
                puts ("NO INPUT");      /* output NO INPUT and exit */
                return 0;
            }
            break;                      /* otherwise, break read-loop */
        }
        
        if (tmp > max)                  /* set max as necessary */
            max = tmp;
        
        first_loop = 0;                 /* set first loop flag false */
    }
    
    printf ("\nmax: %d\n", max);        /* output result */
}

Example Use/Output

No Input case:

$ ./bin/no_input
enter value, -1 to exit: -1
NO INPUT

Normal case, with intentional invalid input:

$ ./bin/no_input
enter value, -1 to exit: 1
enter value, -1 to exit: 9
enter value, -1 to exit: 4
enter value, -1 to exit: bananas
  error: invalid integer input.
enter value, -1 to exit: 5
enter value, -1 to exit: 11
enter value, -1 to exit: -1

max: 11

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

2 Comments

Thank you very much for your reply. I learned something new about the matching-failure and was wondering why my output kept going into an infinite loop when I accidentally entered characters. I also wasn't sure how to use the limits.h but was able to incorporate it in my code with your explanation and it worked!
You are very welcome. Another option is reading each line of input with fgets() (using a buffer large enough to hold any input) and then using sscanf() to convert values from the buffer. That way, you do not have to worry about emptying stdin because it is completely read each time. A character array of 1024 bytes makes a great buffer. Good luck with your coding!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.