Why is printf not equivalent to scanf? - c

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.

Related

return value ignored: 'scanf' (closed)

I'm writing a program with C and this is one of my functions:
void group3()
{
char select[5];
printf("\nDetails etc.");
printf("\nPlease confirm Yes/No if you would like to subscribe:");
scanf("%s", select);
if (select == "Yes")
printf("Good.");
else
{
printf("Alright.");
main();
}
}
But when I try to compile and debug the program, a warning called "return value ignored: 'scanf'" appears. I noticed that the warning appears when I'm running scanf for integers too but the program still works for integers. However, when I try to scanf for strings, it doesn't work. I've tried using getchar() but the same warning occurs for getchar(). I've also tried using scanf_s but the same problem appears when I try to scanf_s for strings. I've also defined _CRT_SECURE_NO_WARNINGS in my program. Would really appreciate it if someone could explain to me how I can eliminate this warning from occurring/get the scanf or getchar to work with strings.
edit: thanks to some helpful users i found out that the problem isn't because the string wasn't read, but because i cannot compare strings using the if statement this way. the answer is in the comment section and i can't select it as the correct answer to this but this question is closed. thank you :)
The problem is that the return value of scanf() is ignored, so don't ignore that to eliminate the warning.
scanf() returns the number of data read on success and negative number on error, so it is useful to check if it successfully read required things.
Example:
if (scanf("%4s", select) != 1) {
fputs("read error\n", stderr);
exit(1);
}
Also it is good to read the length to read to avoid buffer overrun.
This is also done in the above example.
One more point is that select == "Yes" is not a correct way to compare strings in C.
This is comparing pointers and it won't be true because the array and the string literal are stored in differenct places in memory.
strcmp() function from string.h is useful to compare strings.

How does the following code works printf("%c")?

I wanted to know how the following program is working?
#include <stdio.h>
int main(void) {
while(1){
if(printf("%d",printf("%c")))
break;
else
continue;
}
return 0;
}
I did not know how the part printf("%c") is working and therefore the whole program.I am aware of writing something like printf("%c", 'a'); like that but how is it working without providing the character to be printed? My question is what does the following program prints and how does it prints so?
I have tried to run the program, sometimes it prints nothing, but sometimes it is printing some random character followed by 1. I am not able to get how it is working, can someone please explain what is going behind the code and how it is printing that random characters, and why there is one at the end?
Here are some output I am getting
Welcome to Undefined Behavior. You fail to have sufficient number of arguments for the format you specify, e.g.
C11 Standard - 7.21.6.1 The fprintf function(p2) "If there are insufficient arguments for the format, the behavior is undefined." 7.21.6.1(p9) "If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined."
A cool wrong program you have.
printf("%c") attempts to print a single character that is supposed to be the second parameter. However, since you have never passed the second parameter, the function prints whatever is in the register that was supposed to have the second parameter. In other words, some random character. However, it prints one character and returns 1: the number of characters printed.
That 1 is in turn printed by printf("%d",printf("%c")). Now you have a random character followed by 1, and since the outer printf also prints one character, it returns 1.
Finally, if(printf("%d",printf("%c"))) interprets that later 1 as true and breaks the loop.
This is about format bugs.
Look at this code, when execute printf("%d", 123), the program will push number 123 onto the stack, and then push string "%d", when printf meets "%d", it will read the value on the top of the stack, so printf find the number 123.
Now look at this code, printf("%c"), program will push string "%c" onto the stack, and try to read value on the top of the stack, you haven't push a value for printf, so printf will still find value, but the value is random, so you might get a random value.

Error: expected declaration specifiers or '...' before string constant [puts() and gets() statement errors

After compiling my program of Dice Roll, I got this error. What is wrong with the code?
Also before I was using gets() instead of scanf() command, but because of that I got this error - passing argument 1 of 'gets' makes pointer from integer without a cast
So I removed the gets() command and used scanf and then there was no error regarding scanf().
What is the reason for getting these two errors?
Ok, so as per the answer I got to know how I should have used the gets() command and why I shouldn't use it instead should use scanf(). So, I made the changes.
Though I have encountered two new errors, this time it's related to the delay() command that I used.
Errors: undefined reference to delay
|error: ld returned 1 exit status|
OK so I solved my last errors by using Sleep() command from windows.h library instead of Delay() command. The programs was compiled.
But still there is a runtime error in the program, it works well till getting the roll1 but then it just print the next two statement and terminated the programs without taking a input for the guess.
It skips all the code after printf("Will it be Higher/Lower or the same? (press H/L/S)\n"); and directly terminates the program.
Ok So I solved above problem adding a whitespace before the "%c" in scanf(" %c", &nextGuess); statement. (Little things xD)
Now only problem is that my toupper() command is not working.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <windows.h>
int main()
{
int i, roll1=0, roll2=0, NumberOfRolls, RandomNUM1[50], RandomNUM2[50];
char nextGuess;
puts("Welcome to the Dice Roll Game");
puts("How many times do you want to roll a dice?");
scanf("%d", &NumberOfRolls);
for( i=1; i<=NumberOfRolls; i++ ) {
RandomNUM1[i] = ( rand()%6 ) + 1;
roll1 += RandomNUM1[i];
}
printf("\nYou Got %d in your first roll!\n", roll1);
Sleep(3000);
printf("\nLet's see if you can guess the value of next roll.\n");
printf("Will it be Higher/Lower or the same? (press H/L/S)\n");
scanf(" %c", &nextGuess);
toupper(nextGuess);
for( i=1; i<=NumberOfRolls; i++ ) {
RandomNUM2[i] = ( rand()%6 ) + 1;
roll2 += RandomNUM2[i];
}
if(nextGuess=='H'){
if(roll1<roll2){
printf("You are such a player, you guessed it right! It's %d", roll2);
}
else if(roll1>roll2){
printf("Uh-Oh! Bad Luck! First roll was higher, It's %d", roll2);
}
else if(roll1==roll2){
printf("Uh-Oh! Bad Luck! Both the rolls are same, It's %d", roll2);
}
}
if(nextGuess=='L'){
if(roll1>roll2){
printf("You are such a player, you guessed it right! It's %d", roll2);
}
else if(roll1<roll2){
printf("Uh-Oh! Bad Luck! First roll was lower, It's %d", roll2);
}
else if(roll1==roll2){
printf("Uh-Oh! Bad Luck! Both the rolls are same, It's %d", roll2);
}
}
if(nextGuess=='S'){
if(roll1==roll2){
printf("You are such a player, you guessed it right! It's %d", roll2);
}
else if(roll1>roll2){
printf("Uh-Oh! Bad Luck! First roll was higher, It's %d", roll2);
}
else if(roll1<roll2){
printf("Uh-Oh! Bad Luck! Second roll is higher, It's %d", roll2);
}
}
return 0;
}
You have a stray ,
At the 2nd line of your main, you declare char nextGuess, instead of char nextGuess;
The compiler tells you it expects specifiers or ... after , so either you add these, or you end the line properly with;.
And for the other problem you mention:
passing argument 1 of 'gets' makes pointer from integer without a cast
Since gets argument should be char *str and you didn't provide it.
You can fix that by, for example:
char tmp_NumberOfRolls[10];
gets(tmp_NumberOfRolls);
NumberOfRolls = atoi(tmp_NumberOfRolls);
but I prefer the scanf solution
PS: (in a now edited version of the code) ***//Error Line*** is not a comment (at least, not all of it) since the *** is still counted as part of the code and will cause an error. Either move the // a bit to the left or enclose that whole part with /* ... */
The gets function reads a string (till the next newline character) from stdin, therefore it asks for a char pointer (char*) to an area of memory where it can put all the characters read including string terminator. The mistake you made is to pass to that function a pointer to int, therefore not only you get a compiler error because you tried to pass an int pointer to gets (for which there are none implicit conversions), but even if it compiled, it would not have worked as you expected because it would put all the characters (which have a size of one byte - most of the times) in that area of memory encoded as chars. That means that when you try to dereference one using a pointer to int, the characters are "read like they were an int"!
There is an example (supposing 1-byte chars, 4-bytes int and a little endian machine and that there is an implicit cast from int* to char* which does not exist and hopefully will never exist):
int num
gets(&num);
if I input 123 in stdin, the memory area pointer by num is large enough to contain the string, but it would contain (exadecimal representation):
0x31|0x32|0x33|0x00
because the string is 3 characters long, ASCII code for '1' is 0x31, for '2' is 0x32, and for '3' is 0x33 and terminates with '\0'!!
Then, when you try to dereference it you get this int (binary representation - supposing a little endian machine):
00000000|00110001|00110010|00110011
which is not the int value 123 but instead ‭3224115‬. Which is not what you wanted to get.
When you use the scanf function, you pass to that function a format string which tells it how to interpret the next arguments passed to it and performs the appropriate conversions between the string read to the right type you specified. That means that you should still pay attention to what you tell to the scanf function while you write the format string (if you tell it to read a string and pass to it a pointer to int, the program will probably crash), but it performs the appropriate conversions for you, if you write the format string correctly.
That's why with scanf everything works perfectly (you're reading an int and you specified "%d" as format string), whereas with gets it does not compile to avoid serious mistakes.
I also would like to remark some points of this answer:
The example is just for didactic purposes and the code provided does not work indeeed. The fact that I supposed that it compiles is for didactic purposes; obviously, the code provided in that example does not compile
If, in that example, we input a string larger than 3 characters (which are four if we include the null terminator) or the int (char) type contains less (more) than 4 (1) byte, the program would have crashed because we corrupted other areas of memory
The reference is more expert than me in techincal stuff, so here are the links to the gets function and the scanf function: gets, scanf (and the ASCII Table is useful too)
You could use the gets function together with the atoi function to parse the string read from gets (using a char pointer to a free area of memory large enough to contain the string, which is pretty hard to allocate (*)) to an int, but scanf is the best approach.
(*) Remember: if you allocate an area of memory that contains 20 chars, the user will input 21 chars. The atoi function fails, but the worst thing is that you have a buffer overflow (and can be a high security issue if your program runs under root permissions).

confused with address of function in c

i am confused! are all of the following printf's the correct way to print the addresses of functions?
Let me tell you my confusion as well. Everytime i run all of these printf's (that is, 1st printf, 2nd printf and 3rd printf), in output i get
02D4
02D4
02D4
but if i remove or comment of 1st and 2nd printf, i get folowing as output
02BA
when i remove third printf statement, i am getting following output
02D0
Again when i uncomment all of these three, i get:
02D4
02D4
02D4
Why is one statement affecting the output of other printf line?
Is this not really the address of function?
I have heard that s and &s give the same value that is address (just like arrays). but here i am confused why s and &s are affected when i try to print b also, where b=s or &s.
#include<stdio.h>
#include<conio.h>
int s(int);
void main()
{
int a=10,*b;
clrscr();
b=s(a++);
b=&s;
printf("%p\n",s); // 1st printf
printf("%p\n",&s); //2nd printf
printf("%p\n",b); //3rd printf
getch();
}
int s(int x)
{
return x;
}
The address of a variable or a function is not something you can depend on, as both the compiler and the operating system can influence where it ends up.
But supposing that the operating system always loads your executable code at the same address, if you change the length of code in the main() function, that may very well influence the starting address of the s() function. Consequently, you get a different result.

C programming: how do I terminate the program after the user enters a sentinel value?

so I first #define SENTINEL -1
and in a certain function, I set up an if statement
void blahblah(blah)
{
printf("Enter an integer (-1 to quit)");
scanf("%d", &value);
if (value == SENTINEL)
return;
}
but for some reason it's not terminating the program like I want it to?
return doesn't mean quit, it just means return from the function.... in your code there, the if statement is useless, because the function will return anyways if the if statement is false.
You probablly want to return a value from blahbalh to say to quit.
If you wish your entire program to terminate, please replace return with a exit(0);. Also, please ensure that the data type of value is int and not unsigned int.
There is no reason for program to terminate, you are only leaving (return) a function when value == SENTINEL.
You function also has three problems; if value != SENTINEL then you don't return a function which is undefined behaviour; parameter blah is missing a type (int blah) ; and value should be global for that function to work.
The normal way would be to set a flag to cause a return; in main() - but you can use exit() to immediately abort a program from any part of the code.
Be aware that if you use exit() the program will just end there and you wont get any termination/clean up code you might want to run.
edit again, was thinking in the wrong language! exit() expects an int parameter signifying the status of the return, either EXIT_SUCCESS or EXIT_FAILURE
my bad!

Resources