5

I just started learning C programming a few days back and I'm trying out some problems from the Kattis (open.kattis.com) website. I came up with this problem along the way where I don't really understand what it means.

//two stones

#include <stdio.h>

int main()
{ 
int n,x=2;

printf("The number of stones placed on the ground is ");
scanf("%d",&n);

if (n%x != 0)
{
    printf("The winner of the game is Alice! \n");
}
else
{
    printf("The winner of the game is Bob! \n");
}
return 0;
}

This appeared >>

warning: ignoring return value of scanf, declared with attribute warn_unused_result [-Wunused-result] regarding scanf("%d",&n);

Can anyone explain what's wrong with this and how to rectify this problem? Thanks.

spideringweb
  • 3,534
  • 2
  • 14
  • 17
jingsen
  • 59
  • 1
  • 2

5 Answers5

3

scanf has a return value that indicates success:

C Standard; §7.19.6.4.3:

The scanf function returns the value of the macro EOF if an input failure occurs before any conversion. Otherwise, the scanf function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure.

If you have a format string in your call to scanf that has one format specifier, then you can check that scanf succeeded in receiving an input of that type from the stdin by comparing its return value to 1.

Your compiler is warning you about this not specifically because scanf returns a value, but because it's important to inspect the result of scanf. A standard-compliant implementation of printf, for example, will also return a value (§7.19.6.3.3), but it's not critical to the soundness of your program that you inspect it.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
2

You are ignoring the return value of the scanf call.
That is what the compiler warns about and was told to treat as an error.
Please understand that there are many subtle mistakes possible to be done with scanf() and not caring about the success, which is indicated by the return value.

To hide the problem which the compiler kindly notifies you about, I recommend to first try the "obvious" straight forward approach

int IreallyWantToIgnoreTheImportantInfo;
/* ... */
IreallyWantToIgnoreTheImportantInfo = scanf("%d",&n);

This will however only move the problem somewhere else and the valid reason about ignoring the scanf() return value will then probably (or maybe "hopefully") turn into a "variable set but never used" warning.

The proper way to really solve the problem here is to USE the return value. You could e.g. make a loop, which attempts reading user input (giving an explanation and removing unscanned attempts) until the return value indicates success.

That would probably make much better code, at least much more robust.

If you really really want to ignore, without instead ignoring a variable which contains the info, then try

(void) scanf("%d",&n); /* I really really do not care ... */

But, please take that as completly helpfuly as I mean it, that is not a good idea.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
2

Can someone explain to me what's wrong with this and how to rectify this problem?

Many C functions return values to their callers. C does not require the caller to acknowledge or handle such return values, but usually, ignoring return values constitutes a program flaw. This is because ignoring the return value usually means one of these things is happening:

  • the function was called in order to obtain its return value, so failing to do anything with that value is an error in itself, or

  • the function was called primarily for its side effects, but its return value, which conveys information about the function's success in producing those side effects, was ignored. Occasionally the caller really doesn't care about the function's [degree of] success, but usually, ignoring the return value means the program is assuming complete success, such that it will malfunction if that was not actually achieved.

scanf() is ordinarily called for its side effects: reading formatted data from the standard input and recording it in the specified objects. Its return value indicates how many of the given input fields were successfully processed, and if the end of the stream or an I/O error was encountered before parsing any fields, then the return value indicates that, too, via a special return value.

If you do not verify that scanf read all the fields you expected it to do, then you do not know whether it gave you any data to work with, nor can you be confident about the state of the input. For example, suppose that when you run your program, you enter "x" instead of a number. What do you think it will do?

You appear to be using GCC and GLIBC. These are instrumented to produce warnings by default when the return values of certain functions, including scanf, are ignored. This catches many of the more common cases of such flaws. To avoid such warnings, check the return value (appropriately). For example,

if (scanf("%d",&n) != 1) {
    fputs("Invalid input -- aborting.\n", stderr);
    exit(1);
}
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

What happen is that your compiler is configured to warn you if you don't check the value returned by scanf.

You have many way to "fix" this :

  • you can configure your compiler to stop warning you. This is usually a bad idea, but since you're still learning C, it may be counterproductive to focus yourself on the error checking at this step.
  • You can put the result of scanf in a variable .... and do nothing with it. It will probably fool the compiler. Same as previous, not a good idea ...
  • You can actually do the error check of scanf. It will be probably confusing since you're learning C, but at last it will be a very good habit to have : each time you call a function that may fail, check if it succeed or failed. To do that, you will have to read the scanf manual : Don't try to read it all, you will probably have an headache before the end. Juste read the "Return Value" section, it's enougth.

Good luck !

Tom's
  • 2,448
  • 10
  • 22
  • 2
    "You can put the result of scanf in a variable .... and do nothing with it. It will probably fool the compiler": the compiler detects an unused variable. Use `(void)` prefix to tell it to shut up – Jean-François Fabre Sep 07 '18 at 14:38
0

What your compiler is warning you about is this:

You are reading input (which you don't control) with scanf(). You tell scanf() that you expect an integer "%d", and scanf() is supposed to place the result of the conversion into the variable you supplied with &n.

Now, what happens when your user does not input an integer, but says "evil message" instead? Well, scanf() cannot convert that into an integer. Accordingly, your variable n will not be initialized. And the only way for your program to realize that something went wrong, is to check what scanf() returns. If it returns that it has made 1 successful conversions, everything's ok. If it returns some other value, you know that some garbage was input into your program. (Usually you would want to bail out with a descriptive error message in case of an error, but details depend on the context)

Failures to handle input errors are among the easiest to exploit security vulnerabilities, and the developers of your compiler know this. Thus, they think that it's generally a really bad idea to ignore the return value of scanf() as it's the only way to catch input errors with scanf(). And they conveniently tell you about this. Try to follow their advise, and make sure that you actually handle the errors that may occur, or prove that they are safe to ignore.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106