Any local variable that isn't initialized contains an indeterminate value. Regardless of type. There's no obvious difference here between for example an uninitialized int
, int*
or int**
.
However, there is a rule in C saying that if you don't access the address of such an uninitialized local variable, but use its value, you invoke undefined behavior - meaning a bug, possibly a crash etc. The rationale is likely that such variables may be allocated in registers and not have an addressable memory location. See https://stackoverflow.com/a/40674888/584518 for details.
So these examples below are all bad and wrong, since the address of the local variables themselves are never used:
{
int i;
int* ip;
int** ipp;
printf("%d\n, i); // undefined behavior
printf("%p\n, (void*)ip); // undefined behavior
printf("%p\n, (void*)ipp); // undefined behavior
}
However, if you take the address of a variable somewhere, C is less strict. In such a case you end up with the variable getting an indeterminate value, which means that it could contain anything and the value might not be consistent if you access it multiple times. This could be a "random address" in case of pointers, but not necessarily so.
An indeterminate value may be what's known as a "trap representation", a forbidden binary sequence for that type. In such cases, accessing the variable (read or write) invokes undefined behavior. This isn't likely to happen for plain int
unless you have a very exotic system that is not using 2's complement - because in standard 2's complement systems, all value combinations of an int
are valid and there are no padding bits, negative zero etc.
Example (assuming 2's complement):
{
int i;
int* ip = &i;
printf("%d\n", *ip); // unspecified behavior, might print anything
}
Unspecified behavior meaning that the compiler need not document the behavior. You can get any kind of output and it need not be consistent. But at least the program won't crash & burn as might happen in the case of undefined behavior.
But trap representations is more likely to be a thing for pointer variables. A specific CPU could have a restricted address space or at the low level initialization, the MMU could be set to have certain regions as virtual, some regions to only contain data or some regions to only contain code etc. It might be possible that such a CPU generates a hardware exception even when you read an invalid address value into an index register. It is certainly very likely that it does so if you attempt to access memory through an invalid address.
For example, the MMU might block runaway code which tries to execute code from the data segment of the memory, or to access the contents of the code memory as if it was data.