1

I have a program that asks for the temperature and returns a response depending on what the temperature is.

int main(void) 
{
    while(1)
    {
        int temp;
        printf("What is the temperature?\nTemp: "); // fetch temperature
        scanf("%d", &temp);
        if (temp == -858993460) // for some reason parsing "q" returns this value
        {
            break;
        }

in

// Att trycka q först funkar, men om man först skriver in en tempratur så funkar det inte att i senare iterations skriva q, då tar programet bara den senaste inlagda tempraturen

#include <stdio.h>
#include <stdlib.h>
#pragma warning (disable: 4996)

int main(void) 
{
    while(1)
    {
        int temp;
        printf("What is the temperature?\nTemp: "); // fetch temperature
        scanf("%d", &temp);
        if (temp == -858993460) // for some reason parsing "q" returns this value
        {
            break;
        }

        // check the temperature against diffrent values
        if (temp > 32 && temp < 40)
        {
            printf("%d is too hot!", temp);
        }

        else if (temp > 18 && temp < 33)
        {
            printf("%d is a good temperature", temp);
        }

        else if (temp > 39)
        {
            printf("It's %d degrees, turn on your AC!", temp);
        }

        else if (temp < 19)
        {
            printf("%d is too cold!", temp);
        }
        else
        {
            printf("Something has went very wrong...")
        }
        printf("\n\n----------\n\n");
    }

    return 0;
}

if you input "q" during the first iteration it works as expected:

temperatur.exe (process 26592) exited with code 0.                                                                                                                  Press any key to close this window . . .

but inputting a number during the first iteration, the "q" during iteration n>1 returns (assume first input is "12" second input is "q")

What is the temperature?
Temp: 12
12 is too cold!

----------

What is the temperature?
Temp: q
12 is too cold!

----------

What is the temperature?
Temp: 12 is too cold!

----------

What is the temperature?
Temp: 12 is too cold!

----------
...

I can't find anything on any forums of anyone having a similar issue

Oskar
  • 119
  • 8
  • 5
    `if (temp == -858993460) // for some reason parsing "q" returns this value`. This is bad you're assuming this. – Fiddling Bits Aug 25 '22 at 13:52
  • 3
    Entering `q` puts `scanf` in an error state. You should use a real sentinel value like Absolute Zero - 1. – Fiddling Bits Aug 25 '22 at 13:53
  • 3
    Check if `scanf("%d", &temp)` returns `1` instead. That means it succeeded. – Ted Lyngmo Aug 25 '22 at 13:54
  • 3
    I'm guessing it's `-858993460` because it's the garbage that was on the stack, since you don't initialize it. – Fiddling Bits Aug 25 '22 at 13:54
  • 5
    Giving and input of `q` for a call like `scanf("%d", &temp);` will cause the read to fail and no value will be assigned to `temp`. So, whatever was there before will still be there. On your first run through the loop, it appears that the peculiar value you have indicated is in that variable. On other iterations, who knows what will be there ... maybe the value given in the last loop, but that's not guaranteed, because it's *formally* a new variable on each loop. – Adrian Mole Aug 25 '22 at 13:54
  • @AdrianMole I think I understand what you mean, so what would be the best way fix this? – Oskar Aug 25 '22 at 13:55
  • `yes I know about "else if" and "else" but this improves readbility and has the same result. In this case this is better` That may be true for you but I think most professional programmers would disagree. Also, you check every case even if you've found one that's true. It's a waste of time. – Fiddling Bits Aug 25 '22 at 13:56
  • @FiddlingBits `This is bad you're assuming this.` I am aware that it as awful, but I learned 4 days ago, so it's the best I could manage, what would be a better way? – Oskar Aug 25 '22 at 13:56
  • 3
    "what would be a better way?" -- The best solution would probably be not to use `scanf` for user input. See [this link](http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html) for further information. However, if you do want to use `scanf`, then `if ( scanf( "%d", &temp ) != 1 ) { break; }` would probably be best. Note that I cannot write newline characters into this comment, so you must add them yourself. – Andreas Wenzel Aug 25 '22 at 13:59
  • @AndreasWenzel Would you mind posting this as a question so I can mark it as an answer so others can see the solution to the issue? – Oskar Aug 25 '22 at 14:06
  • 1
    @Oskar: Ok, I have now posted my solution as an answer. – Andreas Wenzel Aug 25 '22 at 14:25
  • `scanf` is what everyone uses for dirt-simple input in the first few C programs they write, but it turns out that `scanf` is *not* so simple: it has lots of quirks and foibles, which unfortunately no one ever tells you about. See [here](https://stackoverflow.com/questions/72178518#72178652) for one list of things to watch out for. (Your problem is #8 on that list.) – Steve Summit Aug 25 '22 at 15:27

2 Answers2

2

In order to determine whether scanf was successful, you should check the return value of scanf. It will return an int which specifies the number of arguments that were successfully converted (which should be 1 in your case). If something went wrong, it will return a number less than the number of arguments that you asked for (i.e. 0 in your case). When no arguments were converted, it may also return the special value EOF instead of 0 in some situations.

Therefore, if scanf does not return 1, you should ignore the value of temp, as it is not guaranteed to contain a meaningful value.

For this reason, it would probably be best to change the lines

scanf("%d", &temp);
if (temp == -858993460) // for some reason parsing "q" returns this value
{
    break;
}

to:

if ( scanf( "%d", &temp ) != 1 )
{
   break;
}

However, I generally do not recommend using scanf for user input, as that is not what the function is designed for. That function does not behave in an intuitive manner when dealing with user input. For example, it does not always read an entire line of input at once.

You may want to read this guide for further information:

A beginners' guide away from scanf()

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
0

Taking a look at https://www.geeksforgeeks.org/scanf-in-c/ which tells us that the return value of scanf tells us

>0: The number of values converted and assigned successfully.

0: No value was assigned.

<0: Read error encountered or end-of-file(EOF) reached before any assignment was made.

The problem is that when scanf encounters the q, it doesn't jump over the q, it stays at the q and you get the same every iteration.

To solve this, you can simply get characters from the input stream until you encounter a new line like this:

if(scanf("%d", &temp) != 1)
    ; // handle invalid input
while(fgetc(stdin) != '\n'); // or getchar() if you prefer
Lost
  • 23
  • 1
  • 6
  • In your answer, you wrote: "The problem is that when scanf encounters the q, it doesn't jump over the q, it stays at the q and you get the same every iteration." -- That is not the actual problem in this case. You are correct that `scanf` never consumes the `q`, so that OP's program is getting stuck in an infinite loop. However, since OP's program is supposed to quit when the user enters 'q', the fact that the `q` is not consumed is not a problem. The actual problem is that OP is not detecting that `q` was entered by the user. – Andreas Wenzel Aug 25 '22 at 14:41
  • For the reason stated in my previous comment, the line `while(fgetc(stdin) != '\n');` is not necessary in this case. It would only be necessary if the program read more input afterwards. – Andreas Wenzel Aug 25 '22 at 14:52
  • @AndreasWenzel The OP never stated that q is supposed to mean quit, I thought it was abritrary chosen and the `if (temp == -858993460)` was the result of it not working, for debugging purposes. The checking for new line is necessary since the program reads more input afterwards, the OP, presumably, chose the "while" to repeatedly take in input. – Lost Aug 25 '22 at 15:18
  • In your previous comment, you wrote: "The OP never stated that q is supposed to mean quit" -- I disagree with this statement. In the question, OP wrote the following: "if you input "q" during the first iteration it works as expected: temperatur.exe (process 26592) exited with code 0." Also, the comments in the code make it clear that OP intends to break out of the infinite loop when the user enters "q". – Andreas Wenzel Aug 25 '22 at 15:27
  • It probably is a good habit to write `while( ( c = getchar() != '\n' ) && c != EOF );` after every `scanf`, so I don't want to discourage you from doing that. All I am saying is that it will not help OP in this case. – Andreas Wenzel Aug 25 '22 at 16:01
  • Note that `while(fgetc(stdin) != '\n');` will cause an infinite loop if `fgetc` returns `EOF`. Therefore, `while( ( c = fgetc( stdin ) != '\n' ) && c != EOF );` would probably be better. – Andreas Wenzel Aug 25 '22 at 16:44