I've checked myself, I wrote a program like this
int main() {
int i;
cout << i;
return 0;
}
I ran the program a few times and the result was same all the time, zero.
I've tried it in C and the result was the same.
But my textbook says
If you don’t initialize an variable that’s defined
inside a function, the variable value remain undefined.That means the element takes on
whatever value previously resided at that location in memory.
How's this possible when the program always assign a free memory location to a variable? How could it be something other than zero(I assume that default free memory value is zero)?
How's this possible when the program always assign a free memory
location to a variable? How could it be something rather than zero?
Let's take a look at an example practical implementation.
Let's say it utilizes stack to keep local variables.
void
foo(void)
{
int foo_var = 42;
}
void
bar(void)
{
int bar_var;
printf("%d\n", bar_var);
}
int
main(void)
{
bar();
foo();
bar();
}
Totally broken code above illustrates the point. After we call foo, certain location on the stack where foo_var was placed is set to 42. When we call bar, bar_var occupies that exact location. And indeed, executing the code results in printing 0 and 42, showing that bar_var value cannot be relied upon unless initialized.
Now it should be clear that local variable initialisation is required. But could main be an exception? Is there anything which could play with the stack and in result give us a non-zero value?
Yes. main is not the first function executed in your program. In fact there is tons of work required to set everything up. Any of this work could have used the stack and leave some non-zeros on it. Not only you can't expect the same value on different operating systems, it may very well suddenly change on the very system you are using right now. Interested parties can google for "dynamic linker".
Finally, the C language standard does not even have the term stack. Having a "place" for local variables is left to the compiler. It could even get random crap from whatever happened to be in a given register. It really can be totally anything. In fact, if an undefined behaviour is triggered, the compiler has the freedom to do whatever it feels like.
If you don’t initialize an variable that’s defined inside a function, the variable value remain undefined.
This bit is true.
That means the element takes on whatever value previously resided at that location in memory.
This bit is not.
Sometimes in practice this will occur, and you should realise that getting zero or not getting zero perfectly fits this theory, for any given run of your program.
In theory your compiler could actually assign a random initial value to that integer if it wanted, so trying to rationalise about this is entirely pointless. But let's continue as if we assumed that "the element takes on whatever value previously resided at that location in memory"…
How could it be something rather than zero(I assume that default free memory value is zero)?
Well, this is what happens when you assume. :)
This code invokes Undefined Behavior (UB), since the variable is used uninitialized.
The compiler should emit a warning, when a warning flag is used, like -Wall for example:
warning: 'i' is used uninitialized in this function [-Wuninitialized]
cout << i;
^
It just happens, that at this run, on your system, it had the value of 0. That means that the garbage value the variable was assigned to, happened to be 0, because the memory leftovers there suggested so.
However, notice that, kernel zeroes appear relatively often. That means that it is quite common that I can get zero as an output of my system, but it is not guaranteed and should not be taken into a promise.
Static variables and global variables are initialized to zero:
Global:
int a; //a is initialized as 0
void myfunc(){
static int x; // x is also initialized as 0
printf("%d", x);}
Where as non-static variables or auto variables i.e. the local variables are indeterminate (indeterminate usually means it can do anything. It can be zero, it can be the value that was in there, it can crash the program). Reading them prior to assigning a value results in undefined behavior.
void myfunc2(){
int x; // value of x is assigned by compiler it can even be 0
printf("%d", x);}
It mostly depends on compiler but in general most cases the value is pre assumed as 0 by the compliers
Related
int main()
{
{int x = 532;}
int xc;
int x = *(&xc+1);
cout << x << endl; // prints 532
}
I create an int variable with a value of 532 and then it immediately goes out of scope.
I then create another int variable right after so that it has an address of 1 word before x.
I then assign that value of whatever was one word past xc to x and print it, and it has the value of 532.
Is this guaranteed to happen? Why/why not?
No, the arrangement and padding (and even the existence) of variables on the stack is implementation-dependent, and what you have here is Undefined Behavior. The language specifies that you must not use a pointer to access the memory of any object other than the one it points to.
In this case, &xc + 1 points to memory that lies outside the allocation of xc. You cannot read or write to this location and expect any kind of predictable result. Note that it is actually a valid pointer -- you are allowed to point "one-past-the-end" of an allocation, provided you never dereference that address.
To explain what's actually happening in your case: your variables are being pushed onto the stack, and the stack memory extends in the direction of lower addresses. It appears your compiler didn't bother to unwind the stack after the original x went out of scope. Alternatively, multiple values of 532 might have been initialized in memory, or in a register, and the value you're reading might not be the one that was stored at x. All this said, even this program on your computer with your compiler does not guarantee this behavior.
The original variable x could be optimized away by the compiler completely because it is not used.
The value of xc is uninitialized. Its location (if any) on the stack is not guaranteed. Even though x had additional scope, the compiler is not required to push and pop stack locations if it doesn't want to.
The compiler is not required to understand that you're aliasing x via xc because, as already mentioned such behavior is not defined.
#include<iostream>
using namespace std;
void fun(int a) {
int x;
cout << x << endl;
x = a;
}
int main() {
fun(12);
fun(1);
return 0;
}
The output of this code is as follows:
178293 //garbage value
12
why are we getting 12 and not garbage value instead??
why are we getting 12 and not garbage value instead??
In theory, the value of x could be anything. However, what's happening in practice is that two calls to fun one after the other is responsible for the previous value of x to be still on the stack frame.
Let's say the stack frame is structured as below:
arguments
return value
local variables
In your case,
Memory used for arguments is equal to sizeof(int).
The compiler may omit using any memory for the return value since the return type is void.
Memory used for local variables is equal to sizeof(int).
When the function call is made the first time, the value in the arguments part is set to 12. The value in the local variables is garbage, as you noticed. However, before you return from the function, you set the value of the local variable to 12.
The second time the function is made, the the value of the argument is set to 1. The value in the local variable is still left over from the previous call. Hence, it is still 12. If you call the function a third time, you are likely to see the value 1 in the local variable.
Anyway, that's one plausible explanation. Once again, remember that this is undefined behavior. Don't count on any specific behavior. The compiler could decide to scrub the stack frame before using it. The compiler could decide to scrub the stack frame immediately after it is used. The compiler could do whatever it wants to do with the stack frame after it is used. If there is another call between the calls to fun, you will most likely get completely different values.
You have not initialized the value x when printing it. Reading from uninitialized memory is UB, i.e., there are no guarantees as to what will happen. It could output a random number, or invoke an unlikely combination of bits that will do something unexpected.
Reading an uninitialized integer is UNDEFINED BEHAVIOR, that means that it can do literally anything, can print anything. It can format your hard drive or collapse the observable universe! Basically I dont know compiler implementations that do so but theoretically they can!
I have encountered a problem in my learning of C++, where a local variable in a function is being passed to the local variable with the same name in another function, both of these functions run in main().
When this is run,
#include <iostream>
using namespace std;
void next();
void again();
int main()
{
int a = 2;
cout << a << endl;
next();
again();
return 0;
}
void next()
{
int a = 5;
cout << a << endl;
}
void again()
{
int a;
cout << a << endl;
}
it outputs:
2
5
5
I expected that again() would say null or 0 since 'a' is declared again there, and yet it seems to use the value that 'a' was assigned in next().
Why does next() pass the value of local variable 'a' to again() if 'a' is declared another time in again()?
http://en.cppreference.com/w/cpp/language/ub
You're correct, an uninitialized variable is a no-no. However, you are allowed to declare a variable and not initialize it until later. Memory is set aside to hold the integer, but what value happens to be in that memory until you do so can be anything at all. Some compilers will auto-initialize variables to junk values (to help you catch bugs), some will auto-initialize to default values, and some do nothing at all. C++ itself promises nothing, hence it's undefined behavior. In your case, with your simple program, it's easy enough to imagine how the compiler created assembly code that reused that exact same piece of memory without altering it. However, that's blind luck, and even in your simple program isn't guaranteed to happen. These types of bugs can actually be fairly insidious, so make it a rule: Be vigilant about uninitialized variables.
An uninitialized non-static local variable of *built-in type (phew! that was a mouthful) has an indeterminate value. Except for the char types, using that value yields formally Undefined Behavior, a.k.a. UB. Anything can happen, including the behavior that you see.
Apparently with your compiler and options, the stack area that was used for a in the call of next, was not used for something else until the call of again, where it was reused for the a in again, now with the same value as before.
But you cannot rely on that. With UB anything, or nothing, can happen.
* Or more generally of POD type, Plain Old Data. The standard's specification of this is somewhat complicated. In C++11 it starts with §8.5/11, “If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value.”. Where “automatic … storage duration” includes the case of local non-static variable. And where the “no initialization” can occur in two ways via §8.5/6 that defines default initialization, namely either via a do-nothing default constructor, or via the object not being of class or array type.
This is completely coincidental and undefined behavior.
What's happened is that you have two functions called immediately after one another. Both will have more or less identical function prologs and both reserve a variable of exactly the same size on the stack.
Since there are no other variables in play and the stack is not modified between the calls, you just happen to end up with the local variable in the second function "landing" in the same place as the previous function's local variable.
Clearly, this is not good to rely upon. In fact, it's a perfect example of why you should always initialize variables!
I am getting different values for the a variable which is an int.
Although I know I am not initializing it, the value changes from 32767 32766 32765 and 32764 for variable a (with code version 1) and its always 0 with code version 2.
I know I don't have to leave variables uninitialized, just asked this question to see if anybody knew what is happening behind the scenes at runtime, I am using gcc .
whith code version 1
#include <iostream>
int main()
{
int a;
int *b = new int; // <----- this line
std::cout<<a<<std::endl;
std::cout<<*b<<std::endl;
return 0;
}
whith code version 2
#include <iostream>
int main()
{
int a;
std::cout<<a<<std::endl;
int *b = new int; // <----- same line moved here
std::cout<<*b<<std::endl;
return 0;
}
You read uninitialized memory. This is undefined behavior. That means the C++ language rules give literally no guarantee what happens when you run this code, at all. You may see the values you observed, nothing at all, crash your PC or set your house on fire. All equally legal outcomes of running this code.
In practice this will only print unpredictable garbage values in the range of int of course, dependent on what just happens to be left over in your memory and do nothing interesting.
Proof from the standard (N4140) for the non-believers:
When storage for an object
with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if
no initialization is performed for the object, that object retains an indeterminate value until that value is
replaced (5.17). [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. —
end note ] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the
following cases:
[8.5 (12)], emphasize mine, the exceptions following this don't apply.
It's an unchecked coincidence in a highly complex system.
That may be the best answer you'll get regarding why uninitialized memory in your computer is showing you the pattern you see.
See also...
The c++ statement new int allocates memory from the heap but it doesn't initialize it. So whatever was on the heap or memory from before is being read. You have to do int *b = new int(0) to initialize what b is pointing to with 0.
The following code shows different output with gcc and g++ on using const variable i.
The addresses of i and value of ptr is same, but on accessing that address by printing value of i and derefrencing value of ptr I got value of i as 5 with g++ and 10 with gcc.
How g++ holds const variable in memory?
#include <stdio.h>
int main()
{
const int i =5;
int *ptr =(int*)&i;
*ptr = 10;
printf("\n %u and %u and %d and %d \n",&i,ptr,i,*ptr);
return 0;
}
You are modifying a const qualified object. This is not allowed in C ("undefined behavior"). Anything can happen.
Examples:
The compiler could put i into read-only memory. Writing to *ptr would crash your program.
It could put it into writable memory and you would just see the 10.
It could put it into writable memory but replace all read accesses to i by the number 5 (You promised it is const, didn't you?).
I guess the C compiler chose 2 while the C++ compiler went for 3.
Other have commented on the "undefined" nature of what the code is doing. But to explain how this happens is that it is entirely possible that the compiler applied an optimisation and the runtime value of i is never passed to the printf but instead replaces the i with the constant 5. You did declare it to be const so it is not supposed to change.
It may be in memory or it may be hard-coded into your executable. It is const; the compiler may perform aggressive optimisations on it.
This is why you must not modify it.
You can dereference/cast const as non-cost and overwrite but the behavior is undefined.
As the behaviour is undefined, you may get anything in result, and you should not question why, how etc.
Once the compiler learns your variable is const, it is very well allowed to keep this variable in RO memory and/or replace occurances of this variable with the hardcoded value. A C++ compiler may choose not to assign memory to a const variable unless you ask its address in your code.
Rule of thumb is, decide whether you want to change a variable or not and make it const accordingly.