Unexpected output on using puts() and printf() function - c

I'm trying to run a basic code on my Dev C++ IDE, but it gives an expected output-
printf("%d", printf("stackoverflow1"));
printf("%d", puts("stackoverflow2"));
puts(printf("stackoverflow3"));
the expected output should be:
stackoverflow114stackoverflow2
14stackoverflow314
but the output I'm getting is:
stackoverflow114stackoverflow2
0stackoverflow3
Can someone explain the inconsistency in the output ? I know that puts return a non negative number but why I'm getting a '0' everytime. Also in the last statement why is puts not printing the no of characters printed by printf ?

puts(), as you mentioned, only has to return a non-negative number on success. This means the compiler you are using gets to decide what is returned, as long as it follows this. Your compiler appears to have chosen 0.
as 2501 mentioned, passing puts(const char * p ) an int is illegal, your compiler should have complained about it. puts() is supposed to print starting from p until it reaches a '\0' char, so the input has to be a pointer to a '\0' terminated string

You have undefined behavior. puts() takes a const char* argument yet you pass it an int.
puts(printf("stackoverflow3"));
Enable warnings on your compiler and your code won't even compile.

printf("%d", printf("stackoverflow1"));
Printf returns an int (how much chars are printed = 14). Because the arguments of the outer printf have to be evaluated before the outer one can be evaluated, the string printed will bee "stackoverflow114"
printf("%d", puts("stackoverflow2"));
puts returns a "nonnegative value" (this is the only guarantee, the standard gives to you). In your case the nonnegative value is the int 14. The string "stackoverflow2\n" is printed by puts and the 14 is printed by printf.
puts(printf("stackoverflow3"));
puts takes an const char* as an argument and printf returns the number of chars printed (which is 14, again). Since puts takes a pointer, it may interpret the memory at address 14 as a string and output it (it might cancel compilation, too - most compilers will be 'glad' and cast this for you, along with a warning). This string seems to be empty (this might be sort of random). This line thus only prints "stackoverflow3" (in your case) and the outer puts only prints a random string (in your case "").

Related

Why can a null character be embedded in a conversion specifier for scanf?

Perhaps I'm misinterpreting my results, but:
#include <stdio.h>
int
main(void)
{
char buf[32] = "";
int x;
x = scanf("%31[^\0]", buf);
printf("x = %d, buf=%s", x, buf);
}
$ printf 'foo\n\0bar' | ./a.out
x = 1, buf=foo
Since the string literal "%31[^\0]" contains an embedded null, it seems that it should be treated the same as "%31[^", and the compiler should complain that the [ is unmatched. Indeed, if you replace the string literal, clang gives:
warning: no closing ']' for '%[' in scanf format string [-Wformat]
Why does it work to embed a null character in the string literal passed to scanf?
-- EDIT --
The above is undefined behavior and merely happens to "work".
First of all, Clang totally fails to output any meaningful diagnostics here, whereas GCC knows exactly what is happening - so yet again GCC 1 - 0 Clang.
And as for the format string - well, it doesn't work. The format argument to scanf is a string. The string ends at terminating null, i.e. the format string you're giving to scanf is
scanf("%31[^", buf);
On my computer, compiling the program gives
% gcc scanf.c
scanf.c: In function ‘main’:
scanf.c:8:20: warning: no closing ‘]’ for ‘%[’ format [-Wformat=]
8 | x = scanf("%31[^\0]", buf);
| ^
scanf.c:8:21: warning: embedded ‘\0’ in format [-Wformat-contains-nul]
8 | x = scanf("%31[^\0]", buf);
| ^~
The scanset must have the closing right bracket ], otherwise the conversion specifier is invalid. If conversion specifier is invalid, the behaviour is undefined.
And, on my computer running it,
% printf 'foo\n\0bar' | ./a.out
x = 0, buf=
Q.E.D.
This is a rather strange situation. I think there are a couple of things going on.
First of all, a string in C ends by definition at the first \0. You can always scoff at this rule, for example by writing a string literal with an explicit \0 in the middle of it. When you do, though, the characters after the \0 are mostly invisible. Very few standard library functions are able to see them, because of course just about everything that interprets a C string will stop at the first \0 it finds.
However: the string you pass as the first argument to scanf is typically parsed twice -- and by "parsed" I mean actually interpreted as a scanf format string possibly containing special % sequences. It's always going to be parsed at run time, by the actual copy of scanf in your C run-time library. But it's typically also parsed by the compiler, at compile time, so that the compiler can warn you if the % sequences don't match the actual arguments you call it with. (The run-time library code for scanf, of course, is unable to perform this checking.)
Now, of course, there's a pretty significant potential problem here: what if the parsing performed by the compiler is in some way different than the parsing performed by the actual scanf code in the run-time library? That might lead to confusing results.
And, to my considerable surprise, it looks like the scanf format parsing code in compilers can (and in some cases does) do something special and unexpected. clang doesn't (it doesn't complain about the malformed string at all), but gcc says both "no closing ‘]’ for ‘%[’ format" and "embedded ‘\0’ in format". So it's noticing.
This is possible (though still surprising) because the compiler, at least, can see the whole string literal, and is in a position to notice that the null character is an explicit one inserted by the programmer, not the more usual implicit one appended by the compiler. And indeed the warning "embedded ‘\0’ in format" emitted by gcc proves that gcc, at least, is quite definitely written to accommodate this possibility. (See the footnote below for a bit more on the compiler's ability to "see" the whole string literal.)
But the second question is, why does it (seem to) work at runtime? What is the actual scanf code in the C library doing?
That code, at least, has no way of knowing that the \0 was explicit and that there are "real" characters following it. That code simply must stop at the first \0 that it finds. So it's operating as if the format string was
"%31[^"
That's a malformed format string, of course. The run-time library code isn't required to do anything reasonable. But my copy, like yours, is able to read the full string "foo". What's up with that?
My guess is that after seeing the % and the [ and the ^, and deciding that it's going to scan characters not matching some set, it's perfectly willing to, in effect, infer the missing ], and sail on matching characters from the scanset, which ends up having no excluded characters.
I tested this by trying the variant
x = scanf("%31[^\0o]", buf);
This also matched and printed "foo", not "f".
Obviously things are nothing like guaranteed to work like this, of course. #AnttiHaapala has already posted an answer showing that his C RTL declines to scan "foo" with the malformed scan string at all.
Footnote:
Most of the time, an embedded in \0 in a string truly, prematurely ends it. Most of the time, everything following the \0 is effectively invisible, because at run time, every piece of string interpreting code will stop at the first \0 it finds, with no way to know whether it was one explicitly inserted by the programmer or implicitly appended by the compiler. But as we've seen, the compiler can tell the difference, because the compiler (obviously) can see the entire string literal, exactly as entered by the programmer. Here's proof:
char str1[] = "Hello, world!";
char str2[] = "Hello\0world!";
printf("sizeof(str1) = %zu, strlen(str1) = %zu\n", sizeof(str1), strlen(str1));
printf("sizeof(str2) = %zu, strlen(str2) = %zu\n", sizeof(str2), strlen(str2));
Normally, sizeof on a string literal gives you a number one bigger than strlen. But this code prints:
sizeof(str1) = 14, strlen(str1) = 13
sizeof(str2) = 13, strlen(str2) = 5
Just for fun I also tried:
char str3[5] = "Hello";
This time, though, strlen gave a larger number:
sizeof(str3) = 5, strlen(str3) = 10
I was mildly lucky. str3 has no trailing \0, neither one inserted by me nor appended by the compiler, so strlen sails off the end, and could easily have counted hundreds or thousands of characters before finding a random \0 somewhere in memory, or crashing.
Why can a null character be embedded in a conversion specifier for scanf?
A null character cannot directly be specified as part of a scanset as in "%31[^\0]" as the parsing of the string ends with the first null character.
"%31[^\0]" is parsed by scanf() as if it was "%31[^". As it is an invalid scanf()
specifier, UB will likely follow. A compiler may provide diagnostics on more than what scanf() sees.
A null character can be part of a scanset as in "%31[^\n]". This will read in all characters, including the null character, other than '\n'.
In the unusual case of reading null chracters, to determine the number of characters read scanned, use "%n".
int n = 0;
scanf("%31[^\n]%n", buf, &n);
scanf("%*1[\n]"); // Consume any 1 trailing \n
if (n) {
printf("First part of buf=%s, %d characters read ", buf, n);
}

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).

Why output length is coming 6?

I have written a simple program to calculate length of string in this way.
I know that there are other ways too. But I just want to know why this program is giving this output.
#include <stdio.h>
int main()
{
char str[1];
printf( "%d", printf("%s", gets(str)));
return 0;
}
OUTPUT :
(null)6
Unless you always pass empty strings from the standard input, you are invoking undefined behavior, so the output could be pretty much anything, and it could crash as well. str cannot be a well-formed C string of more than zero characters.
char str[1] allocates storage room for one single character, but that character needs to be the NUL character to satisfy C string constraints. You need to create a character array large enough to hold the string that you're writing with gets.
"(null)6" as the output could mean that gets returned NULL because it failed for some reason or that the stack was corrupted in such a way that the return value was overwritten with zeroes (per the undefined behavior explanation). 6 following "(null)" is expected, as the return value of printf is the number of characters that were printed, and "(null)" is six characters long.
There's several issues with your program.
First off, you're defining a char buffer way too short, a 1 char buffer for a string can only hold one string, the empty one. This is because you need a null at the end of the string to terminate it.
Next, you're using the gets function which is very unsafe, (as your compiler almost certainly warned you about), as it just blindly takes input and copies it into a buffer. As your buffer is 0+terminator characters long, you're going to be automatically overwriting the end of your string into other areas of memory which could and probably does contain important information, such as your rsp (your return pointer). This is the classic method of smashing the stack.
Third, you're passing the output of a printf function to another printf. printf isn't designed for formating strings and returning strings, there are other functions for that. Generally the one you will want to use is sprintf and pass it in a string.
Please read the documentation on this sort of thing, and if you're unsure about any specific thing read up on it before just trying to program it in. You seem confused on the basic usage of many important C functions.
It invokes undefined behavior. In this case you may get any thing. At least str should be of 2 bytes if you are not passing a empty string.
When you declare a variable some space is reserved to store the value.
The reserved space can be a space that was previously used by some other
code and has values. When the variable goes out of scope or is freed
the value is not erased (or it may be, anything goes.) only the programs access
to that variable is revoked.
When you read from an unitialised location you can get anything.
This is undefined behaviour and you are doing that,
Output on gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 is 0
For above program your input is "(null)", So you are getting "(null)6". Here "6" is the output from printf (number of characters successfully printed).

Strange output of this C program

#include<stdio.h>
main()
{
int i;
char c;
for (i=0;i<5;i++){
scanf("%d",&c);
printf("%d",i);
}
printf("\n");
}
I thought it will print 0 1 2 3 4 but it didn't.
What's the reason of the strange output?
Undefined Behaviour.
You're attempting to read an int (the "%d" in the scanf call) into an object of type char (the c). Don't do that!
This program exhibits undefined behavior: The type of &c (char *) does not correspond to the type of the scanf arg (%d wants a signed int *).
What is probably happening is that the scanf is writing 4 bytes to the memory location starting at the address of c. Which is only 1 byte long, so the other 3 bytes overwrite the first 3 bytes of i's value. On a little-endian system, that would effectively set i to whatever integer value you enter shifted right by 8 bits.
But, of course, the behavior is undefined. Next time you compile this code, it could do something completely different. A different compiler, or the same compiler with different options, could keep i in a register (where scanf cannot overwrite it) (but it might instead smash the return address on the stack, causing a crash when the program ends), or it could put the values on the stack in the opposite order (same deal), or it could leave 4 bytes on the stack for c (causing no unexpected behavior), or it could detect the situation and abort with an error, or it could even make demons fly out of your nose.
You are reading into c but printing i, so you will see 01234. You probably mean to print c. But that's not enough. c should be declared int because you are reading with format "%d", which expects an int. Either use format hhd or change c to type int
scanf("%d",&c);
should be
scanf("%c",&c);
btw. It will ask you to input value for c in every iteration and then it will print one value of i. What are you getting?
What's the reason of the strange output?
It's because you havn't used scanf properly. When you use "%d", you have to give scanf a pointer to an int, but you gave it a pointer to a char.
Change your char c to int c
(You should also check functions for errors. e.g. scanf will return EOF on end of input. It will also return the count of assigned values. Since you have given it 1 value, &c , you should check that scanf returns 1. If it does not, something bad might have happened)

Resources