Why does the following snippet cause random numbers to print to the screen with printf, but putchar always outputs 1?
#include <stdio.h>
int main() {
char c;
printf("%d\n", c );
putchar(c);
}
According to C99 standard, this is undefined behavior. Let's see why:
Section 6.7.8.9 says that
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.
This applies to your variable c, because it has automatic storage duration, and it is not initialized explicitly.
Section J.2 says that
The behavior is undefined in the following circumstances:
...
The value of an object with automatic storage duration is used while it is
indeterminate
This applies to your code as well, because you read c when you pass it as a parameter to both printf and putchar, and the value of c is still indeterminate, because it has not been assigned.
1) The c variable first has a random value(default/garbage value) to itself as you declared-but-did-not-initialize your char c to any defined letter or value of ur interest(character).
2) Next you tried to printf the %d(digit/decimal/numerical value) of the char c, so now it is giving you a converted value of the garbage which was earlier assigned to c when you declared the char c in the first place.
3) Finally you tried to use putchar(c), which again behaves similarly because your char c is uninitialized and is still being read thereby re-trying to manage with an undetermined value to be printed onto the screen. (since the same un-initialized character variable c is being passed to both kind of printing as a parameter).
Yes these 3 statements are a bit clumsy to understand but they are as layman as it can get to help speed-up some understanding regarding this query of yours.
Pay attention to the 1st comment response to your question by #bluemoon. Those 3 words alone litterally have a huge amount of sensibility and meaningfull-ness to them, to a point that it also tells you what you have done erroneous in your own code(your actions)."UNDEFINED"(try relating the same with UNINITIALIZED).
Related
This question already has answers here:
Is un-initialized integer always default to 0 in c?
(4 answers)
Closed 1 year ago.
In C, we know that without initializing a variable, it holds a garbage value. Yet in online compilers and also, in an IDE, when I tried this program it got compiled and there was a perfect output. When I tried to print the same without the while loop, it returned a garbage value. So, is not initializing fine?
#include <stdio.h>
int main() {
int j;
while(j<=10){
printf("\n %d",j);
j=j+1;
}
}
Try disassembling your code, for example "gcc -S test.c", so you can see that there is no instruction dedicated to initializing the integer "j" with or without loop. Greetings.
… it holds a garbage value.
When anybody says an object has a garbage value, they are being imprecise with language.
There is no value that is a garbage value. For 32-bit two’s complement integers, there are the values −2,147,483,648 to +2,147,483,647. Each of them is a valid value. None of them is a garbage value.
What it actually means to say something has a garbage value, if the speaker understands C semantics, is that the value of the object is uncontrolled. It has not been set to any specific value, and therefore whatever value you get from using it is a happenstance of circumstances. It may be some value that was in the memory of the object before it was reserved to be the memory for that object.
However, it might be other things. When an object is uninitialized, the C standard not only has no requirement that the memory of the object have any particular value, it has no requirement that the object behave as if it had any fixed value at all. This frees the compiler for purposes that are useful for optimization in other situations. But it means that, if you have int x; printf("%d\n", x); int y = x+3; printf("%d\n", y);, the compiler does not have to load x from memory each time it is used. Because x is uninitialized, the compiler is not required to do any work to load it from memory. For the printf("%d\n", x);, the compiler might let x be whatever value is in the register that would be used to pass the second argument to printf. For the int y = x+3;, the compiler might let x be whatever is in some other register that it would use to hold the value of x if x were defined. This could be a different register. So printf("%d\n", x); might print “47” while int y = x+3; printf("%d\n", y); prints “−372”, not “50”.
Sometimes an uninitialized object might behave as if it started with the value zero. This is not uncommon in short programs such as the one in the question, where nothing has used the stack much yet, so the part of it reserved for j is still in the initial state the program loader put it in, filled with zeros. But that is happenstance. When you change the program, the compiler might use a different part of the stack for j, and that part might not have zeros in it, because it was used by some of the initial program start-up code that runs before main starts.
Always avoid use a uninitialized variables, because it cause undefined behavior.
Uninitialized variables
Unlike some programming languages, C/C++ does not initialize most variables to a given value (such as zero) automatically. Thus when a variable is assigned a memory location by the compiler, the default value of that variable is whatever (garbage) value happens to already be in that memory location! A variable that has not been given a known value (usually through initialization or assignment) is called an uninitialized variable.
For your reference:
https://wiki.sei.cmu.edu/confluence/display/c/EXP33-C.+Do+not+read+uninitialized+memory
https://www.learncpp.com/cpp-tutorial/uninitialized-variables-and-undefined-behavior/
This question already has answers here:
(Why) is using an uninitialized variable undefined behavior?
(7 answers)
Closed 3 years ago.
if i run this program:
#include <stdio.h>
int main()
{
int a=32,b=2,c,i;
for(i=0;i<3;i++){
printf("%d\n",c);
c=a/b;
a=c;
}
return 0;
}
the output is:
32765
16
8
In there, I dont define the value of C, Where from came this output 32765.?
even again i run this code more time,it show different values like 32764,32767. Why this different output showing on?
Because c has automatic storage duration (i.e. is a non-static local variable) and is uninitialized, its value is indeterminate. Attempting to print an uninitialized variable that never had its address taken (i.e. was not the subject of the address-of operator &) invokes undefined behavior.
Even if you did take the address of c you could still have undefined behavior if it contains a trap representation. If it does not contain a trap representation (and most implementations don't have them), the the value is unspecified which simply means the printed value can't be predicted.
Automatic variables (a local variables which are allocated and deallocated automatically when program flow enters and leaves the variables's scope) for which there is no explicit initializer have undefined (i.e. garbage) values.
This question already has answers here:
What happens to a declared, uninitialized variable in C? Does it have a value?
(9 answers)
Closed 5 years ago.
I just made this short program. Can someone please explain why I am getting 2 as a result here?
Here is the code
#include <stdio.h>
#include <stdlib.h>
int main()
{
int variable;
int a;
a=variable;
a=200;
printf("%d",variable);
return 0;
}
Because you print the value of an uninitialized variable. It will have an indeterminate (and seemingly random) value.
The assignment you make to a just copies the value of variable and then of 200 into a. The value of variable remains unmodified and indeterminate.
I recommend you find a good beginners book or two to read.
At the beginning, you define two variables, a and variable. Note, that those variables at this point are not initialized. Right now, the compiler only knows that there are two variables of type int and their names, nothing more.
You then try to initialize variable a with the not initialized variable variable, the result should be clear: The two variables remain uninitialized.
Then you proceed and initialize a with 200, variable is still only defined, not initialized.
After that, you print the still uninitialized variable variable, which hasn't recieved any "real" value as of yet, only what already was "lying around" in memory when the compiler assigned that memory location to the variable. In your case, that was "2" (or at least, that's what printf could extract from there).
Further reading: C Variables. This explains how variables are defined, declared and initialized.
Assigment operator (a = variable;) does not link the two variables, just assignes whatever value there is in the righthandside expression to the left handside.
You can visualize local variables as boxes where you can put values into.
In c if you don't assign a value to the variable then it stores the garbage value which can be anything.In your code you did not assign the value to variable so it print 2 (which can be anything)
strlen returns the number of characters that precede the terminating null character. An implementation of strlen might look like this:
size_t strlen(const char * str)
{
const char *s;
for (s = str; *s; ++s) {}
return(s - str);
}
This particular implementation dereferences s, where s may contain indeterminate values. It's equivalent to this:
int a;
int* p = &a;
*p;
So for example if one were to do this (which causes strlen to give an incorrect output):
char buffer[10];
buffer[9] = '\0';
strlen(buffer);
Is it undefined behavior?
Calling the standard function strlen causes undefined behaviour. DR 451 clarifies this:
library functions will exhibit undefined behavior when used on indeterminate values
For a more in-depth discussion see this thread.
The behavior of the variant that you are showing is well defined under these circumstances.
The bytes of the uninitialized array have all indeterminate values, with exception of the 10th element that you set to 0.
Accessing an indeterminate value would only be UB if the address of the underlying object would be never taken or if the value is a trap for the corresponding type.
Since this is an array and access to array elements is through pointer arithmetic, the first case is not relevant, here.
Any char value can be accessed without UB, the clauses about trap representations in the standard explicitly exclude all character types from that.
Thus the values that you are dealing with are simply "unspecified".
Reading unspecified values may according to some members of the C standards committee give different results each time, what some call a "whobly" state or so. This property is not relevant, here, since your function reads any such value at most once.
So your access to the array elements gives you any arbitrary but valid char value.
You are sure that your for loop stops at latest at position 9, so you will not overrun your array.
So no "bad" things beyond the visible may happen if you use your specific version of the function. But having a function call that produces unspecified results is certainly nothing you want to see in real code. Something like this here leads to very subtle bugs, and you should avoid it by all means.
No, it's not undefined behavior. Your strlen function will stop before the end of the buffer. If your strlen function referenced buffer[10], then, yes that is undefined.
It certainly will be unexpected behavior, since most of buffer contains random data. "Undefined" is special word for people writing language standards. It means that anything could happen, including memory faults or exiting the program. By unexpected, I mean that it sure not what the programmer wanted to happen. On some runs, the result of strlen could be 3 or it could be 10.
Yes, it's undefined behaviour. From the draft C11 standard, §J.2 "Undefined behavior":
The behavior is undefined in the following circumstances:
...
The value of an object with automatic storage duration is used while it is
indeterminate.
int main(void)
{
char name1[5];
int count;
printf("Please enter names\n");
count = scanf("%s",name1);
printf("You entered name1 %s\n",name1);
return 0;
}
When I entered more than 5 characters, it printed the characters as I entered, it was more than 5, but the char array is declared as:
char name1[5];
Why did this happened
Because the characters are stored on the addresses after the 'storage space'. This is very dangerous and can lead to crashes.
E.g. suppose you enter name: Michael and the name1 variable starts at 0x1000.
name1: M i c h a e l \0
0x1000 0x1001 0x1002 0x1003 0x1004 0x1005 0x1006 0x1007
[................................]
The allocated space is shown with [...]
This means from 0x1005 memory is overwritten.
Solution:
Copy only 5 characters (including the \0 at the end) or check the length of the entered string before you copy it.
This is undefined behavior, you are writing beyond the bounds of allocated memory. Anything can happen, including a program that appears to work correctly.
The C99 draft standard section J.2 Undefined Behavior says:
The behavior is undefined in the following circumstances:
and contains the following bullet:
An array subscript is out of range, even if an object is apparently accessible with the
given subscript (as in the lvalue expression a[1][7] given the declaration int a[4][5]) (6.5.6).
This applies to the more general case since E1[E2] is identical to (*((E1)+(E2))).
This is undefined behavior, you can't count on it. It just happens to work, it may not work on another machine.
To avoid buffer overflow, use
fgets(name1, sizeof(name1) - 1, stdin);
or in C11
gets_s(name1, sizeof(name1) - 1);
another example to make things clearer :
#include <stdio.h>
int array[5] ;
int main ( void )
{
array[-1] = array[-1] ; // sound strange ??
printf ( "%d" , array[-1] ) ; // but work !!
return 0 ;
}
array in this case in an address, and you get number
before or after that address, but this is undefined behavior
unless you know what you do. Pointer works with ++ or -- !
It's very clear from other answers that this constitutes some kind of vulnerability to your program.
What can be learned from this? Lets assume:
int func(void)
{
char buffer[1];
...
In almost every implementation of the C compiler, the code generated here will create a local stack area and enables you to access this stack by the address given in buffer. On this stack reside other important data too, for example: the address of the next code line to be executed after the function returns to it's caller.
You could, therefore, theoretically:
Enter a lot of code into your input function,
Create a code that defines (in binary code) a new function that does something ugly,
Overwrite the correct return address (on the stack) with the address that the new function would have if you write it beyond the buffers bounds.
This is called buffer overflow exploit, you can read up here (and on many other places).
Yes it is allowed in C, as there is no bound checking.