0

I'm writing a C program that reads an undefined amount of integers from the keyboard. No limits. The program has a loop that reads integers with scanf and stores the lowest and highest value to display. If the user enters a negative number or non integer, the loop ends and displays info (lowest and highest value).

NOTE: I DO NOT WANT USE BUILT IN FUNCTIONS LIKE "ISDIGIT" OR "FGET". No idea what they are and I don't want to "cheat".

I found out that my EOF value is -1. I tried putting "while(scanf("%d", &num) > -1)" in my loop. This just does nothing if you enter a char(keeps reading and never ends loop). It sometimes breaks the loop if you enter a double negative such a "--2". It doesn't work, anyways.

My problem is with my programs confusing behavior with my current code. Sometimes it does not keep or read a zero. Sometimes it only stores and displays the second highest value. Sometimes it display the second to highest or lowest value after I enter an character or symbol to trigger an end to the loop. Other times it works just fine. I tried some more logical statements to force the min to be zero if it's not equal to 1 and less than 1, but that didn't work either.

An example of the weird behavior...

Enter some integer values, EOF to quit...

0

1

2

3

4

e

not an int

The minimum value is 0

and the maximum value is 3

Can anyone explain why this is happening and offer a solution and/or hint? I've been searching and googling for hours now.

Thank You!

Here is my code...

int min;

int max;

int num;

printf(" Enter some integer values, EOF to quit...\n");
scanf("%d\n", &num);

min = max = num;

 while(scanf("%d", &num) == 1)
  {
    if(num > max)
     {
      max = num;
     }

    else if(num < min)
     {
      min = num;
     }
   scanf("%d\n", &num);

 }//while(scanf("%d", &num) == 1);


    printf(" not an int \n");


    printf(" The minimum value is %d\n", min);
    printf(" and the maximum value is %d\n", max);
Suraj Jain
  • 4,463
  • 28
  • 39
  • 1
    You are calling `scanf` *twice* for each loop. Is that really what you want? – kaylum Feb 06 '17 at 01:16
  • 1
    When you enter something that can't be an integer, `scanf()` returns 0, not EOF. – Jonathan Leffler Feb 06 '17 at 01:33
  • "... an undefined amount of integers from the keyboard. No limits." Which one is it: undefined or unlimited? The two terms are technically orthogonal; you can't *define* the *undefined* as *unlimited*. – autistic Feb 06 '17 at 01:50
  • Also, you *really* should do more research. This is a common problem, and already has answers! :( – autistic Feb 06 '17 at 01:52
  • Maybe you should read the documentation for scanf. That's not cheating – M.M Feb 06 '17 at 02:00
  • @kaylum Oops, I forgot to take that out when I changed it from a do while to a while loop. Works great now. Thank you! –  Feb 06 '17 at 02:17
  • I saw the thing @Seb posted earlier. Didn't really help. I want to keep zeros. I also meant that I'm not limiting how many integers as user can enter. They can type until they die. I'm new to this and my book didn't mention documentation. Not sure what that means, but I will look into it. I'm guessing it's details and definitions, which would help obviously. –  Feb 06 '17 at 02:22
  • @JonathanLeffler Duplicate Question Consider scanf("%d" , &number) == 0 , also this question has pretty nice asnwer. – Suraj Jain Feb 06 '17 at 05:26

1 Answers1

1

You can make this "work" with scanf, but it won't really work. scanf is ill advised for a large number of reasons.

For example, let's say we did this:

printf("Enter some integers, or ctrl-D to quit.\n");
while(scanf("%d", &input) != EOF) {
    if(input > max) {
        max = input;
    }
    else if(input < min) {
        min = input;
    }
}

Seems sensible, scanf returns EOF if it doesn't have any input. And it seems to work.

$ ./test
Enter some integers, or ctrl-D to quit.
230
-238 
5
max: 230, min: -238

But what if we give it something that isn't a number?

$ ./test
Enter some integers, or ctrl-D to quit.
230
-238
5
ldsfkj
^D
^D
^D
^C

Why won't it stop? If it fails to read what's required, it leaves it on the stdin buffer. It tries to read ldsfkj, fails because it's not an integer, returns 0 (not EOF) because it didn't match anything. But ldsfkj is still in the buffer, so when it loops again it reads it again and fails again. This is the big flaw in scanf.

Ok, what if we check that it scanned something?

while(scanf("%d", &input) == 1) {
    ...
}

Again, seems to work great... until we enter something that isn't an integer. Then it just stops because scanf failed. This isn't the behavior we want.

$ ./test
Enter some integers, or ctrl-D to quit.
2039
-203
23.4
max: 2039, min: -203

The safe thing to do is to read input line by line and process it with sscanf. This separates reading the line from parsing the line. We don't have to worry about things getting stuck in the buffer, and we can do more with the parsing, like giving the user an error message.

printf("Enter some integers, or ctrl-D to quit.\n");
char line[256];
while(fgets(line, 256, stdin) != NULL) {
    if( sscanf(line, "%d", &input) != 1 ) {
        puts("Sorry, I don't understand that");
        continue;
    }

    if(input > max) {
        max = input;
    }

    if(input < min) {
        min = input;
    }
}

Note that we always check both min and max because it's now possible for the input to be both.

Note that we're using fgets instead of gets because gets will not limit its input to the size of the string, it can easily overflow its buffer.


The second part is making min/max code simpler. Instead of making the first number a special case that's both min and max, assign the largest possible integer to min, and the smallest possible integer to max. Then the first input is guaranteed to be both the min and max. These limits can be found in limits.h.

Here it is all together.

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

int main() {
    int min = INT_MAX;
    int max = INT_MIN;
    int input;

    printf("Enter some integers, or ctrl-D to quit.\n");
    char line[256];
    while(fgets(line, 256, stdin) != NULL) {
        if( sscanf(line, "%d", &input) != 1 ) {
            puts("Sorry, I don't understand that");
            continue;
        }

        if(input > max) {
            max = input;
        }

        if(input < min) {
            min = input;
        }
    }

    printf("max: %d, min: %d\n", max, min);
}

There is a small glitch in that program. I leave it as an exercise for you to find it and fix it.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • what happens when while( scanf("%d" ,&input ) == 0) , can you add that case too ? – Suraj Jain Feb 06 '17 at 05:27
  • @SurajJain `scanf` returns the number of items matched. 0 means it didn't match anything, so the loop would go *until* it's given a number. Unless the very first input is a match, the first non-match will remain in the buffer and the loop it will loop over that non-match infinitely. You can try it yourself. – Schwern Feb 06 '17 at 21:32