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?.
Local variables in C are not automatically initialized, only global variables are automatically initialized.
int x; // 0 by default
static int y; // 0 by default
void function()
{
static int z; // 0 by default
int w; // Not initialized! Could be anything!
}
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
or 0xeeeeeeee
.
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.
void function()
{
int *ptr = NULL;
...
}
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 pointer ptr
is initialized to NULL
and you are getting the correct output.
You can perhaps try this code to know what you want to know :
#include <stdio.h>
#include <stdlib.h>
typedef struct _appl{
//the pointer
int *ptr_int;
float *ptr_float;
double *ptr_double;
char *ptr_char;
//the basic data types
int a_int;
float a_float;
double a_double;
char a_char;
struct _appl *next;
} appl;
//the pointers
int *ptr_int_global;
float *ptr_float_global;
double *ptr_double_global;
char *ptr_char_global;
//the basic data types
int a_int_global;
float a_float_global;
double a_double_global;
char a_char_global;
//pointer to structure data type
appl *ptr_struct_global;
//struct data type;
appl a_struct_global;
int main()
{
//the pointers
int *ptr_int_local;
float *ptr_float_local;
double *ptr_double_local;
char *ptr_char_local;
//the basic data types
int a_int_local;
float a_float_local;
double a_double_local;
char a_char_local;
//pointer to structure data type
appl *ptr_struct_local;
//struct data type;
appl a_struct_local;
//test the basic data types (local variables)
puts("********");
puts("****first test : test the basic data types (local variables)");
puts("********");
printf("the value of a non-initialized int is : %d\n", a_int_local);
printf("the value of a non-initialized float is : %f\n", a_float_local);
printf("the value of a non-initialized double is : %f\n", a_double_local);
printf("the value of a non-initialized char is : %d\n\n", a_char_local);
//test the basic data types (global variables)
puts("second test : test the basic data types (global variables)");
printf("the value of a non-initialized int is : %d\n", a_int_global);
printf("the value of a non-initialized float is : %f\n", a_float_global);
printf("the value of a non-initialized double is : %f\n", a_double_global);
printf("the value of a non-initialized char is : %d\n\n", a_char_global);
//test the pointers (local variables)
puts("third test : test basic data type pointers (local variables)");
if(ptr_int_local == NULL) printf("a non-initialized int pointer is NULL\n");
else printf("a non-initialized int pointer is not NULL\n");
if(ptr_float_local == NULL) printf("a non-initialized float pointer is NULL\n");
else printf("a non-initialized float pointer is not NULL\n");
if(ptr_double_local == NULL) printf("a non-initialized double pointer is NULL\n");
else printf("a non-initialized double pointer is not NULL\n");
if(ptr_char_local == NULL) printf("a non-initialized char pointer is NULL\n\n");
else printf("a non-initialized char pointer is not NULL\n\n");
puts("attention ! sometimes a non-initialized char pointer (global variables) is NULL, while sometimes not !");
//test the pointers (global variables)
puts("fourth test : test basic data type pointers (global variables)");
if(ptr_int_global == NULL) printf("a non-initialized int pointer is NULL\n");
else printf("a non-initialized int pointer is not NULL\n");
if(ptr_float_global == NULL) printf("a non-initialized float pointer is NULL\n");
else printf("a non-initialized float pointer is not NULL\n");
if(ptr_double_global == NULL) printf("a non-initialized double pointer is NULL\n");
else printf("a non-initialized double pointer is not NULL\n");
if(ptr_char_global == NULL) printf("a non-initialized char pointer is NULL\n\n");
else printf("a non-initialized char pointer is not NULL\n\n");
//test data structure (local variable)
puts("fifth test : test data structure type (local variables)");
if(ptr_struct_local == NULL) printf("a non-initialized data structure pointer is NULL\n\n");
else printf("a non-initialized data structure pointer is not NULL\n\n");
//test data structure (global variable)
puts("sixth test : test data structure type (global variables)");
if(ptr_struct_global == NULL) printf("a non-initialized data structure pointer is NULL\n\n");
else printf("a non-initialized data structure pointer is not NULL\n\n");
ptr_struct_local = (struct _appl*)malloc(sizeof(struct _appl*));
if(ptr_struct_local == NULL) printf("failed to allocate memory\n\n");
else printf("success of allocating memory\n\n");
appl *a = ptr_struct_local;
//test the basic data types (in a local data structure variable)
puts("\nseventh test : test the basic data types (in a local data structure variable)");
printf("the value of a non-initialized int is : %d\n", a->a_int);
printf("the value of a non-initialized float is : %f\n", a->a_float);
printf("the value of a non-initialized double is : %f\n", a->a_double);
printf("the value of a non-initialized char is : %d\n\n", a->a_char);
//test the pointers (in a local data structure variable)
puts("eigth test : test the pointers (in a local data structure variable)");
if(a->ptr_int == NULL) printf("a non-initialized int pointer is NULL\n");
else printf("a non-initialized int pointer is not NULL\n");
if(a->ptr_float == NULL) printf("a non-initialized float pointer is NULL\n");
else printf("a non-initialized float pointer is not NULL\n");
if(a->ptr_double == NULL) printf("a non-initialized double pointer is NULL\n");
else printf("a non-initialized double pointer is not NULL\n");
if(a->ptr_char == NULL) printf("a non-initialized char pointer is NULL\n\n");
else printf("a non-initialized char pointer is not NULL\n\n");
ptr_struct_global = (struct _appl*)malloc(sizeof(struct _appl*));
if(ptr_struct_global == NULL) printf("failed to allocate memory\n\n");
else printf("success of allocating memory\n\n");
appl *b = ptr_struct_global;
//test the basic data types (in a global data structure)
puts("\nninth test : test the basic data types (in a global data structure)");
printf("the value of a non-initialized int is : %d\n", b->a_int);
printf("the value of a non-initialized float is : %f\n", b->a_float);
printf("the value of a non-initialized double is : %f\n", b->a_double);
printf("the value of a non-initialized char is : %d\n\n", b->a_char);
//test the pointers (in a global data structure)
puts("tenth test : test the pointers (in a global data structure)");
if(b->ptr_int == NULL) printf("a non-initialized int pointer is NULL\n");
else printf("a non-initialized int pointer is not NULL\n");
if(b->ptr_float == NULL) printf("a non-initialized float pointer is NULL\n");
else printf("a non-initialized float pointer is not NULL\n");
if(b->ptr_double == NULL) printf("a non-initialized double pointer is NULL\n");
else printf("a non-initialized double pointer is not NULL\n");
if(b->ptr_char == NULL) printf("a non-initialized char pointer is NULL\n\n");
else printf("a non-initialized char pointer is not NULL\n\n");
}