Ignoring return value of scanf - c

I have this issue where gcc using the Werror argument, comes up with the error 'ignoring return value of scanf'. Now, I checked the forums and I did do stuff such as putting it in an if statement which seemed to work fine, but the thing is, I do not get the error if I were to compile it at my University.
#include <stdio.h>
#include <stdlib.h>
#define EXAMPLE1 5
int main (int argc, char* argv[]) {
int example;
scanf ("%d", &example);
if (example <= EXAMPLE1) {
printf ("Woohoo\n");
} else {
printf ("Oohoow\n");
}
return EXIT_SUCCESS;
}
So this code for example would compile fine using gcc -Wall -Werror -O -o namehere namehere.c at my uni, but if I were to use it at home, the aforementioned error comes up. My uni is using gcc 4.9.2. I tried it at home on gcc 4.8.4, 4.8.5, 4.9.3.

Ignoring the return value of scanf() is not good because it means you are not checking for possible errors in input. Though some compilers or settings don't give warnings for that, you shouldn't ignore return values of scanf().
Try this:
#include <stdio.h>
#include <stdlib.h>
#define EXAMPLE1 5
int main (int argc, char* argv[]) {
int example;
if (scanf ("%d", &example) != 1) {
printf ("Read error\n");
}
else if (example <= EXAMPLE1) {
printf ("Woohoo\n");
} else {
printf ("Oohoow\n");
}
return 0;
}

You are not getting an error, the compiler is so friendly to give you a warning. And correctly! Upon erroneous input example will have a random value.
Always check that the return value of scanf matches the number of arguments you want to read.

scanf ("%d", &example);
This tells scanf to read a sequence of decimal digit characters (possibly with a prefixed negative sign) up to the first non-decimal character, and convert that sequence into an int value that gets stored into example.
What if the user enters something that is entirely non-decimal, or if stdin is closed? The scanf call would fail, indicating such a failure using a corresponding return value... but what would the value of example be in such a situation?
You need to check the return value to avoid using example when it contains garbage. If you try to use that variable, the behaviour of your program may be erratic. This might include segfaults.
Your compiler is within its rights to refuse to compile this code, because using an uninitialised (or otherwise indeterminate) variable is undefined behaviour.
In summary, it's well within your best interests to always check the return value because:
Some compilers might refuse to compile code that doesn't have such checks, as you've noticed.
Those that do compile your code will allow your program to behave erratically, using garbage when the user enters garbage or in some cases, possibly segfaulting due to use of a trap representation.

Related

Runtime error when using char as int to scanf and printf

int main()
{
char ch = 0;
int c = 0;
scanf("%d", &ch);
printf("%c", ch);
}
I can input the ASCII number and output the correct character. But the program crashes at the end of the code, the } sign.
Using Visual Studio 2019
Run-Time Check Failure #2 - Stack around the variable 'ch' was corrupted.
Since scanf has non-existent type safety, it can't know the type of parameters passed (one reason why the format string is there in the first place).
The stack corruption is caused by you lying to the compiler here: scanf("%d", &ch);. You tell it "trust me, ch is an int". But it isn't. So scanf tries to store 4 bytes in an area where only 1 byte is allocated and you get a crash.
Decent compilers can warn for incorrect format specifiers.
There are multiple problems in your code:
missing #include <stdio.h> ;
unused variable c ;
type mismatch passing a char variable address when scanf() expects an int * for the %d conversion specifier ;
missing test on scanf() return value ;
missing newline at the end of the output ;
missing return 0; (implied as of c99, but sloppy).
Here is a modified version:
#include <stdio.h>
int main() {
int ch;
if (scanf("%d", &ch) == 1) {
printf("%c\n", ch);
}
return 0;
}
I guess your question was not, "What did I do wrong?", or "Why didn't it work?".
I guess your question is, "Why did it work?", or, "Why did it print an error message after seeming to work correctly?"
There are lots of mistakes you can make which will corrupt the stack. This is one of them. Much of the time, these errors are rather inscrutable: If the memory corruption is severe enough that the memory management hardware can detect it, you may get a generic message like "Segmentation violation" at the instant the bad access occurs, but if not, if the damage isn't bad enough to cause any overt problems, your program may seem to work as you expected, despite the error.
It would be prohibitively expensive to perform explicit tests (in software) to check the stack for damage during every operation. Therefore, no attempt is made to do so, and the primary responsibility is placed on you, the programmer, not to do obviously wrong things like telling scanf to store an int in a char-sized box.
In this case, your system did make a check for stack damage, but as some kind of a one-time operation, only after the main function had returned. That's why the scanf and the printf seemed to work correctly, and the error message seemed to coincide with the closing } at the end of main.
Echoing an analogy I made in a comment, this is sort of like having a policeman write you a ticket for having done something dangerous that did not cause an accident. Why not write the ticket as you are doing the dangerous thing? Why write the ticket after the fact at all, since your dangerous behavior didn't cause an accident? Well, because sometimes that's just the way the world works.
I think you are trying to input an integer and print its char value so in my opinion this is what you are trying to do:
#include <iostream>
using namespace std;
int main()
{
int c = 0;
scanf("%d", &c);
printf("%c", c);
return 0;
}
Note: This is a C++ code but the syntax inside main function will work for C language as well

Return value ignored [scanf]

I'm using C language.
I know that every function has return value(except void function).
But C6031 warning message appears only in scanf function.
It doesn't appear in other functions like printf or hello (look below).
Why this Phenomenon happens?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int hello(void) {
printf("Hello World!");
return 10;
}
int main(void) {
int i;
scanf("%d", &i);
hello();
return 0;
}
As #SteveSummit indicates in a comment, most C implementations have a mechanism to identify functions whose return value should not be ignored.
C itself (as defined by the C standard) has always allowed a caller to ignore the return value of a function. It even allows a function declared with a return value type to not return any value as long as all callers ignore the return value.
However, that permissiveness does not generally lead to good programming practice. In some cases, it is very likely that ignoring the return value of a function will lead to a bug. scanf is considered to be such a function, so the authors of standard libraries tend to mark scanf as requiring that the return value be used.
There is no standard way to mark a function as requiring use of their return values. In GCC and Clang, this is done using the attribute warn_unused_result:
int fn (int a) __attribute__ ((warn_unused_result));
(See the GCC documentation for the warn_unused_result function attribute and how to turn off the warning (not recommended): the `-Wno-unused-result.)
In MSVC, it's done with the _Check_return_ macro, found in sal.h:
#include <sal.h>
_Check_return_ int fn (int a);
(See the Visual Studio docs for error C6031 and this documenation on the Source Annotation Library (sal).)
There are good reasons not to ignore the return value of any library function which uses the return value to indicate failure, including many standard library functions which do input or output. Ignoring input or output failure can lead to problems, but the problems are more evident when ignoring input failure because that can lead to the use of uninitialised values, which in turn can lead to Undefined Behaviour. That is certainly the case for scanf: ignoring its return value means that your program will not respond correctly to malformed input, which is almost certainly a bug.
Ignoring the failure of output functions will sometimes mean that the user is not warned about failure to save persistent data. That can be serious, and it may well be that some action needs to be taken to save that data. But in other cases, the error simply means that the user didn't see some logging message and most likely will not see future logging messages either. This might not be considered important.
put scanf inside an if.
scanf returns the number of successfully input parameter.
if(scanf("%d", &i)) {};

How to check if the argument passed is a string in c?

I have the following code :
void test(int N)
{
printf("%d", N);
}
int main(int ac, char **av)
{
test("");
return 0;
}
I have a function test that expects an integer argument, but in the main when I call the function I give a string argument and c converts it to a integer and prints it for me. But what I want is that if someone passes a string than I give an error. How to check whether the argument is a string though ?
Thanks !
void test(int N) { /* ... */ }
...
test("");
That function call is simply invalid. test requires an argument of type int, or of something that's implicitly convertible to int (any arithmetic type will do). "" is a string literal; in this context, it's converted to a char* value which points to the '\0' character which is the first (and last, and only) character of the array.
There is no implicit conversion from char* to int. A conforming compiler must issue a diagnostic for the invalid call, and it may (and IMHO should) reject it outright. It's exactly as invalid as trying to take the square root of a string literal, or add 42 to a structure.
Older versions of C (before the 1989 ANSI standard) were more lax about this kind of thing, and that laxity survives into some modern compilers. It's likely that, if your compiler doesn't reject the call, it will take the address of the string literal and convert it to an int. The result of this conversion is largely meaningless; such a compiler really isn't doing you any favors by permitting it.
If your compiler doesn't reject, or at the very least warn about, the call, you should enable whatever options are necessary to make it do so. For gcc, for example, you might try something like:
gcc -std=c99 -pedantic -Wall -Wextra filename.c
You can drop the -pedantic if you want to use gcc-specific extensions. There are several possible arguments for the -std= option. See the gcc documentation for more information -- or the documentation for whatever compiler you're using.
If you're asking about validating user input (i.e., input from someone running your program rather than writing C code), user input is not generally in the form of numbers. It's in the form of text, sequences of characters. For example, you might use the fgets() function to read a line of text from standard input. You can then, if you like, check whether that line has the form of an integer literal. One way to do that is to use the sscanf function. A quick example:
#include <stdio.h>
int main(void) {
char line[200];
int n;
printf("Enter an integer: ");
fflush(stdout);
fgets(line, sizeof line, stdin);
if (sscanf(line, "%d", &n) == 1) {
printf("You entered %d (0x%x)\n", n, (unsigned)n);
}
else {
printf("You did not enter an integer\n");
}
}
But if your question is about someone writing C code that calls a function you provide, the compiler will check that any arguments are of a valid type.
what I want is that if someone passes a string than I give an error
That's not really your problem. Most compilers will give a warning for this, I think -- presuming warnings are enabled.
The issue is that C always passes by value, but a string argument is an array, and its value is the address of the first character in the array -- a pointer, but pointer values can be treated as integers. Again, most compilers are smart enough to catch this ambiguity, if you use them properly.
You can't completely bulletproof your code against people who use it improperly. You write an API, you document it, but you don't have to cover cases for those who cannot use basic tools properly.
The core standard C library does not include checks of the sort you are looking for here, so it seems pointless to incorporate them into your API -- there are oodles of built-in standard commands with int args to which an array can be passed in the same way. Saving someone from doing something stupid with your library won't save them from doing the exact same thing with the base C lib -- i.e., you can't stop them from passing pointers in place of ints. Period.
The naive approach is something like this:
int is_integer( const char *s )
{
if( *s == '-' || *s == '+' ) s++;
while( isdigit(*s) ) s++;
return *s == 0;
}
That will tell you if all characters are digits, with an optional sign. It's not particularly robust, however. It can't handle whitespace, and it doesn't check the integer is in the valid range.
However, it might be enough for your needs.
Example:
int main( int argc, char **argv )
{
int val;
if( argc <= 1 || !is_integer(argv[1]) ) {
fprintf( stderr, "Syntax: %s val\n\nWhere val is an integer\n", argv[0] );
return 1;
}
val = strtol( argv[1], NULL, 10 );
test(val);
return 0;
}
Compile with -Wall and -Werror and your problem will magically go away.
gcc -Wall -Werror file.c

Why is printf not equivalent to scanf?

I have a program which displays "hi", but I do not understand why.
I understand both scanf and printf return the number of characters they read/write but how does it work in this case?
void main()
{
if(printf==scanf)
printf("hello");
else
printf("hi");
}
You aren't calling the functions and comparing the results, you are comparing the functions themselves, which boils down to comparing the addresses of the functions (function names will convert to function pointers in many contexts, this is one). What you wrote is equal to this:
/* this is the correct signature for main by the way, not `void main()` */
int main(int argc, char **argv) {
/* compare the address of printf to that of scanf */
if (&printf == &scanf) {
printf("hello");
} else {
printf("hi");
}
}
Since scanf and printf are not the same function they live at a different address so the comparison fails and hi is printed.
Here you compare the adreses of the functions and as the functions are not the same, the equality does not hold. I do not see what confuses you.
You are not calling printf or scanf in the if statement. Rather, you are comparing the location of scanf and printf function in the memory, which are different (otherwise, they will run the same code, and have the same functionality).
You only get back the return value if you invoke the function. An invocation will look like <function_name> ( <arguments separated by commas> ).
As others have already mentioned you are comparing the address of two functions (printf and scanf in this case) and since these functions cannot have the same address, the comparison fails making the program print "hi".
You can try the below code to understand it better
int main(void)
{
printf("printf = %x\n", printf);
printf("scanf = %x\n", scanf);
return 0;
}
Because the address of the function printf is not the same as the function scanf.
Just to add another angle on this matter. Others have already pointed out how you can compare the addresses to the functions. But this code make (well, it's a far stretch) sense:
int main()
{
if(printf("")==scanf(""))
printf("hello");
else
printf("hi");
}
This code is guaranteed to print "hello". Why? Well, lets first look at return values. printf will return the number of characters printed, which is zero for an empty string. scanf will return the number of successful assignments (not the number of characters read), which for an empty string is also zero. Well, if some error occurs, it can also return EOF, which I find highly unlikely even if I cannot guarantee that it will not happen. Well, printf can fail too, and will in that case return an unspecified negative number.
So, it will print "hello", unless both printf and scanf both encounters a problem, AND that printf returns EOF, in which it will print "hi" instead.
However, it could be the case that this is UB. I'm not sure if the order of evaluation is well defined, or even if that matters.

Why do I get a segmentation fault with isdigit()?

Scenario 1:
Code:
int main(){
int a = 12345678;
if(isdigit(a)){
printf("ok: foo\n");
}
else{
printf("false: bar\n");
}
printf("test\n");
return EXIT_SUCCESS;
}
Output:
Segmentation fault
Scenario 2:
Code:
...
if(isdigit(a)){
//printf("ok: foo\n");
}
else{
//printf("false: bar\n");
}
printf("test\n");
...
Output:
test
and now the last, Code:
...
int a = 1234567;
...
Output:
ok: foo
test
What's wrong with isdigit()? I do not understand!
Probably because the compiler optimizes the isdigit function call from the code. That is it doesn't run it.
Also note that isdigit expects a character, not a number. http://www.cplusplus.com/reference/clibrary/cctype/isdigit/
This is because isdigit can be defined as macro like this
#define isdigit(c) ((map[c] & FLAG_DIGIT)==FLAG_DIGIT)
You call isdigit with integer value, but map array size is 256 elements. In this case you try to read value outside of array bounds -> segmentation fault. This segmentation fault can occurs randomly. Depending on your program or data size.
This was probably optimized by the compiler. As neither the if or the else does something, it was removed and the isdigit ends up not called. Be sure to
#include <ctype.h>
The segmentation fault is coming probably from the fact that you're passing a (not so small) number, when a character was expected. When you remove the printf statements and the compiler optimizes it, the call won't happen thus not failing.
Note that the headers can be in fact omitted since the program will be linked with the standard C library by default, so it works. But it's not a good idea, and you should see a warning at least.
First of all, isdigit(3) checks whether a character is a digit.
The segmentation fault probably (I'm positive) happens because you haven't included stdio.h.
Then you're calling printf which uses variable arguments without knowing its prototype (undefined behavior).

Resources