Is the value of an un-initialialized variable aways 'garbage'?

Viewed 63

Are there cases where it's ok to use a variable when it has not been initialized, or is it always assumed to be garbage? For example, one case would be:

// global example?
// static example?
// extern example?
// etc.
{
    int n=1, max_n;
    printf("%d %d\n", n, max_n);
}

In this case max_n has a garbage/undefined value. But are there ever cases where the value is known and can be used, such as doing something like bool item being auto-initialized to 0/false, or is that never the case in C?

6 Answers

By definition, if something is not initialized, it does not have a defined value. If it does have a defined value, it is initialized.

From cppreference:

The value in an uninitialized variable can be anything – it is unpredictable, and may be different every time the program is run. Reading the value of an uninitialized variable is undefined behaviour – which is always a bad idea. It has to be initialized with a value before you can use it.

Also from cppreference about implicit initialization:

If an initializer is not provided:

  • objects with automatic storage duration are initialized to indeterminate values (which may be trap representations)
  • objects with static and thread-local storage duration are zero-initialized

So for example, int a; will be zero-initialized if declared in e.g. global scope, as a static class variable, as a thread_local variable, etc. In other cases, it will be uninitialized.

In C, reading an uninitialized variable results in undefined behavior. It may be 0, but it may also be any random value that happens to be in that memory address. To make a long story short - don't rely on the values of uninitialized variables.

Not sure if you would consider this a "case", but in C, local variables are allocated on the stack, and are uninitialized.

However, global and static variables are allocated in one of the program data sections, so they are zeroed by the OS at load time.

See this question for more information on that including standard reference: Why are global and static variables initialized to their default values?

Global and static objects are initialized with the default value for their type (0 for integers, 0.0 for floats, NULL for pointers etc.)

No other uninitialized value can be relied upon.

Here is a quick explanation why: Most implementations have all local variables on a stack. This stack grows when you declare local variables or when you call a function, and shrinks when you do the reverse action - exit the scope of a variable or return from a function.

Now let's see a program:

void good()
{
    int p = 2;
    printf("%d", p);
}

void notgood()
{
    int p;
    printf("%d", p);
}

int main()
{
    good();
    notgood();
    notgood();
}

Here is the stack at the beginning of the program (stack grows downwards). The stack pointer always points to the top element (represented by an arrow):

|---------------------|
|main's return address| <-- stack pointer

Next is immediately after good() gets called:

|---------------------|
|main's return address|
|good's return address| <-- stack pointer

Next we declare p and initialize it with 2:

|---------------------|
|main's return address|
|good's return address|
|value 2 (variable p) | <-- stack pointer

After that, we have the call to printf:

|---------------------|
|main's return address|
|good's return address|
|value 2 (variable p) |
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     | <-- stack pointer

When printf returns, the return address and parameters are popped of the stack, but they are not erased from memory. That would be inefficient. We simply decrease the stack pointer.

|---------------------|
|main's return address|
|good's return address|
|value 2 (variable p) | <-- stack pointer
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     |

Next, our good() function returns to main:

|---------------------|
|main's return address| <-- stack pointer
|good's return address|
|value 2 (variable p) |
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     |

Call notgood. Whatever trash is on the stack gets overwritten:

|---------------------|
|main's return address|
|notgood's return addr| <-- stack pointer
|value 2 (variable p) |
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     |

Declare the variable (allocate the space), but we don't initialize. Hence, the old garbage value is still there:

|---------------------|
|main's return address|
|notgood's return addr|
|value 2 (variable p) | <-- stack pointer
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     |

Next, we call printf again. Please note that it's return address actually changes, so the old trash is overwritten on the stack:

|---------------------|
|main's return address|
|notgood's return addr|
|value 2 (variable p) |
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     | <-- stack pointer

So, as you can see, if you don't initialize variables, they take the value of whatever there was on the stack.

Be aware that the program may not work, as the compiler could optimize some function calls out.

The answer to your question is NO. That will depend on which scope that variable was declared. If it is a global or static variable it will be initialized to 0. In the other cases there is nothing you can be sure about.

Result of any operation using not initialized automatic storage variables is Undefined. What they hold initially is not determined.

C (2007 draft) Standard (6.7.8 p10):

If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.

Related