I am messing around with C pointers. When I compile and run the following code.
Example 1:
#include <stdio.h>
int main()
{
int k;
int *ptr;
k = 555;
if (ptr == NULL) {
printf("ptr is NULL\n");
} else {
printf("ptr is not NULL\n");
printf("ptr value is %d\n", *ptr);
}
printf("ptr address is %p\n", ptr);
}
I get the output:
ptr is not NULL
ptr value is 1
ptr address is 0x7fff801ace30
If I don't assign a value to k:
Example 2:
#include <stdio.h>
int main()
{
int k;
int *ptr;
if (ptr == NULL) {
printf("ptr is NULL\n");
} else {
printf("ptr is not NULL\n");
printf("ptr value is %d\n", *ptr);
}
printf("ptr address is %p\n", ptr);
}
Then the output is as I expect:
ptr is NULL
ptr address is (nil)
Similarly if I define the variables outside the function:
Example 3:
#include <stdio.h>
int k;
int *ptr;
int main()
{
k = 555;
if (ptr == NULL) {
printf("ptr is NULL\n");
} else {
printf("ptr is not NULL\n");
printf("ptr value is %d\n", *ptr);
}
printf("ptr address is %p\n", ptr);
}
Output:
ptr is NULL
ptr address is (nil)
In the first example, where ptr has an address and value, is this expected behaviour? If so then:
- Why does ptr have an address and value?
- Where do these come from, what sets them?
- How do I correctly define null pointers in the local scope and keep them null until I'm ready to use?
I am compiling with gcc on Ubuntu 12.04.04 on x64:
root@dev:~# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
EDIT
I have numbered my examples above for clarity.
Based on Dietrich's answer I did a bit of searching and found this question: Why are global variables always initialized to '0', but not local variables?.
You can perhaps try this code to know what you want to know :
Local variables in C are not automatically initialized, only global variables are automatically initialized.
The value of an uninitialized variable is unspecified. In practice, this can mean different things.
It may be zero, if your compiler or runtime zeroes memory before it is used.
It may be filled with a sentinel like
0xdeadbeef
or0xeeeeeeee
.It may contain garbage from whatever was last in that particular memory location. (This approach is the most common.)
You are using GCC, which uses the third approach, so you are seeing garbage from the last function to use that memory location. You can run the program with Valgrind (highly recommended), and it will probably spit out error messages for using the uninitialized memory, although it is not guaranteed to catch all errors.
The correct way to do things
One option is to explicitly initialize local variables if you are going to use them.
I prefer to leave variables uninitialized if the value is not used, since the compiler and Valgrind can give me diagnostic messages letting me know that my understanding of the code is incorrect, if it turns out that the uninitialized memory is used.
Never apply the indirection operator to an uninitialized pointer variable. If it is not initialized then attempting to use it invokes undefined behavior.
The above two codes are invoking undefined behavior. In this case the result may be either expected or unexpected.
The last code is working fine because the global variables are initialized to
0
implicitly. Hence the pointerptr
is initialized toNULL
and you are getting the correct output.