If int x=printf("test"); executes safely, without error in c because printf returns an int value (the length of data it has printed.) But what about if we are not storing that integer value:
printf("text");
Why don't we get an error from this?
Many functions in C return something. Whether the programmer decides to do anything with that value is up to them - and often ignoring the return code leads to bugs... But in the case of printf(), the return value is seldom useful. It is provided for to allow the following code:
int width;
width = printf("%d", value); // Find out how wide it was
while (width++<15) printf(" ");
width = printf("%s", name);
while (width++<30) printf(" ");
I'm not saying that's good code (there are other ways to do this too!), but it describes why a function could return a value that isn't used very often.
If the programmer does decide to ignore the return value, there isn't a compiler error - the value is merely forgotten. It's a bit like buying something, getting the receipt, and dropping it on the floor - ignore the returned value.
The latest compilers can be instructed to flag code where returned values are ignored. But even these compilers can be taught which functions' returns are significant and which aren't. printf() would be in the second category.
You are not obliged to store the returned value, you can safely ignore it (as long as you're sure you really don't need it of course).
In most cases the value is simply stored in a CPU register. If you choose to ignore it, it will simply be lost once that register is overwritten.
Related
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)) {};
It seems like there is problem in scanf_s
Here is my code.
#include <stdio.h>
#include "stack.h"
int main(){
int disk;
int hanoi[3][9];
char input[3] = { 0,0,0 };
int moveDisk;
for (int i = 0; i < 9; i++) {
hanoi[0][i] = i + 1;
hanoi[1][i] = 0;
hanoi[2][i] = 0;
}
printf("Insert the number of disks(1~9): ");
scanf_s("%d", &disk);
while (input[0] != 'q') {
printf("%3c %3c %3c\n", 'A', 'B', 'C');
for (int i = 0; i < disk; i++) {
printf("%3d %3d %3d\n", hanoi[0][i], hanoi[1][i], hanoi[2][i]);
}
scanf_s("%s", &input); //getting moving disk -- LOCATION OF ERROR
}
}
I have no idea how to solve this
No doubt you tried to use scanf() in the normal way and Visual Studio reported an error instructing you to use scanf_s()? It is not a direct replacement. For all %c, %s and %[ format specifiers you must provide two arguments - the target receiving the input, and the size of target (or strictly the number of elements).
In VS2019 even at /W1 warning level, it issues a clear explanation of the problem in this case:
warning C4473: 'scanf_s' : not enough arguments passed for format string
message : placeholders and their parameters expect 2 variadic arguments, but 1 were provided
message : the missing variadic argument 2 is required by format string '%s'
message : this argument is used as a buffer size
Don't ignore the warnings, and certainly don't disable them globally (/W0).
So in this case:
scanf_s("%s", input, sizeof(input) ) ;
again more strictly:
scanf_s("%s", input, sizeof(input)/sizeof(*input) ) ;
but the latter is really only necessary for wscanf_s (wide characters). In both cases you could use the _countof() macro, but it is Microsoft specific.
scanf_s("%s", input, _countof(input) ) ;
Note also the lack of an & before input. You don't need it for an argument that is already array or pointer. That is true of scanf() too.
Whilst there are arguments for using scanf_s() over scanf() (which is intrinsically more dangerous), it can just make life difficult if you are learning from standard examples or using a different toolchain. The simpler solution is just to disable the warning, and understand that it is unsafe:
You cited the line
scanf_s("%s", &input);
There are several things wrong with this line:
You are reading a string into a character array. This is an exception to the normal pattern for scanf, in that you do not need the &.
You are using the semistandard scanf_s, instead of the normal scanf. scanf_s is supposed to be "safer", but in order for it to provide its safetiness guarantees you have to call it differently than normal scanf, too. You have to tell it the size of the array you're reading the string into. Combined with #1 above, I believe a more correct call would be scanf_s("%s", input, 3);.
For most purposes, a string of size 3 would be far too small for reading a line of input from the user. Since in this case I guess you're only reading a "line" to give yourself an opportunity to hit RETURN before the program makes another trip through its loop, I guess it's okay.
As I mentioned, scanf_s is not quite Standard, so using it is a mixed bag. Pros: 1. It's allegedly safer. 2. Some people (including perhaps your instructor) will recommend always using it for that reason. Cons: 3. It's nut fully standard (it's an optional part of the standard) meaning that not all C compilers and libraries will support it. 4. Its calling patterns are necessarily quite different than normal scanf; it is not a drop-in replacement, so confusion is likely. (I'm not saying "don't use scanf_s", but you should be aware of its somewhat dubious status.)
If you want to read a line of input from the user before continuing, and if the line might be a "q" or something else, scanf (of any variety) might not be the best choice. In particular, %s wants to read a non-whitespace string, so if you just hit the Return key, it's going to keep waiting. This might or might not be a problem for you. (Or it might not be something you need to worry about right now; you may have bigger fish to fry.)
How can I solve this problem during debugging?
Run your program step by step using the debugger. Then when you get the exception, you've found the line causing it.
Restart your program and go up to the line where the exception will occur. That is stop on that line without execution it.
Then with the debugger, you can look at all variables and try to understand if their value is what you expect.
Does this answered your question?
BTW: The compiler should at least emitted some warnings. You really should first fix those warnings. If you have no warning, make sure you have turned on all warnings in the compiler options.
I started learning programming only few days ago, so basically I have no knowledge.
I'm starting with C, and I wrote a very simple code which is:
int main (int argc, const char * argv[])
{
printf("%d + %d", 1 + 3);
return 0;
}
with the code above, I got the value of 4 + 1606416608 and later found that the return value is wrong because I put more %d than necessary. Then my question is, how did that strange value actually come out? If anyone knows, please help me. Thank you!!
You know what you did wrong already, so to explain what your particular implementation of C probably did:
When you call printf, a new stack frame is pushed to the call stack. The call stack is a last in first out structure with one 'frame' per called function. So if main called logStuff which called printf then three consecutive frames would be for main, then logStuff, then printf. When printf returns, it's frame is removed from the structure and execution continues with logStuff.
So a frame usually contains at least the parameters passed to the function and storage for local variables. Those things may be one and the same, it's implementation dependant.
With a variadic function like printf there's a stream of unnamed parameters. The bit patterns will be put into an appropriate place in the frame. But C is not a reflective language. Each bit patten doesn't inherently have a meaning: any one could be an integer, a float, or anything else. It also isn't a language that invests in bounds checking. You're trusted to write code that acts correctly.
printf determines the types and number of unnamed parameters from the string. So if you've given it false information, it will interpret the bit patterns with something other than their correct meaning and it may think there are fewer or more than are really there.
You told it there were more. So what probably happened was that the parameters were in the equivalent of an array and it read a value from beyond the end of the array. As it's all implementation dependent, that value may have been meant to represent anything. It could be the address of the caller. It could be uninitialised storage for another local variable. It could be bookkeeping. It could be the format string, incorrectly interpreted as an integer.
What it isn't is any reliable value. It may not even always be safe to read.
You are in undefined behavior land... you are telling a variadic function that you have 2 int sized params, then you only supply one, you are leaking something from the stack.
1) %d is a format specifier, it tells the compiler how you want to access the value stored at a particular location.(here as an integer)
2) For every format specifier you need to provide a corresponding variable or a value, otherwise at runtime you will get "garbage" i.e. some random value.
Example :
int main()
{
int a = 65;
printf("\na = %d", a); // here the value stored in a is accessed as an integer.
printf("\na = %c", a); // the value inside a is accessed as a character.
return 0;
}
In the above example '%d' in the first printf statement tells the compiler that the value stored in the variable a is to be accessed as an integer. (o/p - 65)
In the second printf statement '%c' is used to access the same variable as a character.(o/p - A)
Your code expects two numerical parameters to be printed, and you're giving it one.
Expected:
printf("%d + %d", <some_num>, <another_num>);
You're giving it:
printf("%d + %d", <some_num>);
Where <some_num> is what 1+3 evaluates to. The function expects another argument, but receives garbage instead.
What you should do is
printf("%d + %d = %d", 1, 3, 1+3);
If I have a program that is using scanf to get user inputted data:
scanf("%d",&val);
When I run it through lint I get warnings saying that scanf returns a int and it is not being assigned anywhere. What is the c practice to solve this problem? Do I type cast it as void?
(void)scanf("%d",&val);
The C best practice to solve this warnings is simple: Check the resultcode. The scanf function returns in the int if the operation has gone ok or not, and stores the error usually in errno.
The lack of resultcode checks usually results in big errors in certain situations.
The proper answer, of course, is to not ignore the return value. For a robust program, you should always (EDIT: usually) check that the return value indicates success, and fail gracefully when it does not.
Ideally you would do something like
int scanVal = scanf("%d", &val);
if (scanVal != 1) {
// wait a minute, scanf couldn't match input to a "%d"!
}
and then act on the output in a sensible manner.
Instead of silencing the lint message, just check the return value to make sure nothing has gone wrong. From the man page:
RETURN VALUE
These functions return the number of input items
successfully matched and assigned, which can be
fewer than provided for, or even zero in the event of an early
matching failure.
The value EOF is returned if the end of input is reached before
either the first successful conversion or a matching failure occurs. EOF is also >returned if a read error occurs, in which case the
error indicator for the stream (see ferror(3)) is set, and
errno is set indicate the error.
scanf returns the number of input items successfully matched and assigned. Compare its return value to the number you expect in order to detect errors.
while (scanf("%d",&val) != 1)
printf("Try again.\n");
Use
#pragma warning(disable:<warning number>)
scanf("%d",&val);
#pragma warning(default:<warning number>)
And your compiler will suppress that warning.
The best practice is to assign the return value of scanf to see if all (or how many) items were read. In this particular case, if it returns anything but 1, something went wrong (e. g. you wanted a number but the user is giving you unprintable characters) and you should handle it appropriately.
If you want your code to be robust in the presence of bad input, don't use scanf("%d", ...).
For most errors, scanf("%d", &val) will return 0 to indicate that it wasn't able to read an int value (for example, if the input is "foo" rather than "123").
But if the input is syntactically valid but out of range (for example 9999999999999999999), the behavior is undefined.
Most implementations will probably behave sanely, but I don't know how much consistency there is.
To read an int value safely, use fgets() (not gets()) followed by strtol(). (fgets() can have problems with very long input lines, but there are ways to deal with that.)
In the simplest way possible, how can I check if an integer initialized from function scanf is a number?
http://www.cplusplus.com/reference/clibrary/cstdio/scanf/
On success, [scanf] returns the
number of items succesfully read. This
count can match the expected number of
readings or fewer, even zero, if a
matching failure happens. In the case
of an input failure before any data
could be successfully read, EOF is
returned.
So you could do something like this:
#include <stdio.h>
int main()
{
int v;
if (scanf("%d", &v) == 1) {
printf("OK\n");
} else {
printf("Not an integer.\n");
}
return 0;
}
But it is suggest that you use fgets and strtol instead.
Your question is weirdly worded. An initialized integer is always a number (aside from exotic cases of trap representations), which means that there's no need to check anything.
I would guess that you need to check whether the given string is a valid representation of a number. For that, you first need to define what the valid representation should look like. Do you allow sign? Is a redundant + allowed (as a sign)? What about 0x prefix for hexadecimals? And so on.
C language offers its own set of rules that define the language's idea of a valid string representation of an integer. If that's what you need, then in order to verify whether the given string satisfies these rules, the best way is to use string-to-integer conversion function like strtol (and other functions from strto... group) and then check for the error condition.
Beware of the answers that suggest writing your own function that would verify these rules. This just doesn't make any sense, since the standard function exists already. Also, strictly speaking, in real-life programming there's rarely a need to perform verification without the actual conversion. strto... will do both.
Also, stay away from functions from scanf group to perfrom string-to-integer conversion. These functions produce undefined behavior on overflow (i.e. if the input string representation is too long). In general case, the only proper way to do such a conversion in C is functions from strto... group.