1

I am observing this strange behavior with uninitialized pointers.

As you can see from the following examples, sometimes it prints a NULL value while others it prints a valid address, in an alternating fashion.

Why is this happening?

Code:

int *i;
printf("%p\n", i);

Output:
(nil)


Code:

int *i;
printf("%p\n", i);

int *j;
printf("%p\n", j);

Output:
0x7fff2d0c1b50
(nil)


Code:

int *i;
printf("%p\n", i);

int *j;
printf("%p\n", j);

int *k;
printf("%p\n", k);

Output:
(nil)
0x7fffda5284b0
(nil)


Code:

int *i;
printf("%p\n", i);

int *j;
printf("%p\n", j);

int *k;
printf("%p\n", k);

int *l;
printf("%p\n", l);

Output:
0x400510
(nil)
0x7fff6d7089c0
(nil)


Code:

int *i;
printf("%p\n", i);

int *j;
printf("%p\n", j);

int *k;
printf("%p\n", k);

int *l;
printf("%p\n", l);

int *m;
printf("%p\n", m);

Output:
0x357521cbc0
0x400520
(nil)
0x7fff715849e0
(nil)


System: x86_64 x86_64 x86_64 GNU/Linux (x86_64-redhat-linux)
Compiler: gcc version 4.1.2 20080704 (Red Hat 4.1.2-52)

mrucci
  • 4,342
  • 3
  • 33
  • 35
Nikhil Vidhani
  • 709
  • 5
  • 11
  • undefined or unspecified behavior. A good reason to initialize variables to a known good value. – crashmstr Sep 11 '14 at 15:20
  • 2
    uninitialized pointers? uninitialised is just that! don't assume the contents will EVER be valid! – Mitch Wheat Sep 11 '14 at 15:20
  • 2
    Undefined behavior I suppose. Not sure if there's anything else to add. – Marco A. Sep 11 '14 at 15:20
  • 2
    the pointer will be some random location in memory. You get whatever was in that bit of memory from previous programs. sometimes it's null, sometimes it's garbage, sometimes it's someone's credit card number, etc... Basically you're playing "pin the tail on the donkey". – Marc B Sep 11 '14 at 15:21
  • @crashmstr yes i know uninitialized local vars have undefined values. But why I am getting such a pattern of valid addresses and NULL. And oddly enough this behavior is repeatable all the time. – Nikhil Vidhani Sep 11 '14 at 15:21
  • 2
    @NikhilVidhani ["undefined behavior"](http://en.wikipedia.org/wiki/Undefined_behavior) means that anything could happen and different compilers may do something different. Avoid undefined behavior. – crashmstr Sep 11 '14 at 15:24
  • 3
    What are all the down-votes for? The title implies that OP is aware of the uninitialized values. The question implies that OP is trying to understand the "partially consistent" behavior, where each time a different variable stores a `NULL` value. On the "formal" side of it, it is the result of undefined behavior according the C-language standard. On the "practical" side of it, it is most likely the result of the random contents of the stack at the point in time when the code is executed. OP appears to be trying to grasp the "not entirely" random behavior of the program. What's wrong with that? – barak manos Sep 11 '14 at 15:31
  • 1
    The OP know that doing this is undefined behavior and then asks why doing this prints strange numbers. Undefined behavior is just that: undefined. Anything can happen! The printf can print (nul) or a valid address or his computer could reformat its disk. No, they're not equally likely to happen but as far as the C standard is concerned, they're all possible. – DoxyLover Sep 11 '14 at 17:42

4 Answers4

6

In general, just don't use uninitialized variables at all. If you want to know more, read on.

All your examples are straight Undefined Behavior (UB), due to this standard passage:

6.3.2.1 Lvalues, arrays, and function designators

[...]
2 [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.

Now, let's pretend in some omitted line the address was taken.

&i; // Like this

6.2.4 Storage durations of objects

5 An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration, as do some compound literals. [...]
6 [...] The initial value of the object is indeterminate.

Alternative quote:

6.7.9 Initialization

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

3.19.2

1 indeterminate value
either an unspecified value or a trap representation

3.19.3

1 unspecified value
valid value of the relevant type where this International Standard imposes no requirements on which value is chosen in any instance
2 NOTE An unspecified value cannot be a trap representation.

3.19.4

1 trap representation
an object representation that need not represent a value of the object type

6.2.6.1 General

5 Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined. If such a representation is produced by a side effect that modifies all or any part of the object by an lvalue expression that does not have character type, the behavior is undefined.50) Such a representation is called a trap representation.

Thus, if your implementation supports trap-representations for the type you read (Yours don't for int*), you have UB.

Because you don't, unspecified value applies, which means every read returns some arbitrary value, and not neccessarily the same.


All quotes are from draft n1570, C99+Ammendments aka C11.

Community
  • 1
  • 1
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • Very nice detailed explanation. +1 – ani627 Sep 11 '14 at 17:53
  • The description of **6.3.2.1/2** is totally different in N1256. Strange. – R Sahu Sep 11 '14 at 17:59
  • @RSahu Used draft n1570, C99+ammendments (aka C11). (The info I quoted from 6.2.4 is duplicated in 6.7.8, which I did not quote. Yet.) – Deduplicator Sep 11 '14 at 18:36
  • @Deduplicator yes you are right. We can't expect a consistent behavior with uninitialized variables. I ran the above on a different machine and there I get completely different answers. But there also the addresses I get are repeatable which can be attributed to the fact that the execution stack always fetches the same local variables. – Nikhil Vidhani Sep 12 '14 at 07:43
  • @NikhilVidhani: You might like to make your program ASLR-compatible and enable that. Voilá, different values every run. – Deduplicator Sep 17 '14 at 21:18
2

From the C99 Standard (n1256):

6.7.8 Initialization

...

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

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • +1 for specifying automatic storage class. – ani627 Sep 11 '14 at 15:33
  • Would be worthy of an upvote. If you mentioned the result too. – Deduplicator Sep 11 '14 at 16:16
  • @Deduplicator, do you mean, "the result of using a pointer whose value is indeterminate"? – R Sahu Sep 11 '14 at 16:41
  • Actually, the result of reading an indeterminate automatic variable which could have register-storage-class. Respectively, if it could not have register storage-class, what indeterminate would allow (any odd value, and a different one each time, or a trap if the implementation allowed for trap-representation in pointers (no for these ones)) – Deduplicator Sep 11 '14 at 16:46
  • @Deduplicator, I don't fully understand what you are talking about. I would be uncomfortable saying anything that is potentially inaccurate. – R Sahu Sep 11 '14 at 16:49
  • @Deduplicator, if you would point me to a place where I could read more about it, that will be helpful. Thanks. – R Sahu Sep 11 '14 at 16:51
  • @RSahu: Put all the details in my answer. – Deduplicator Sep 11 '14 at 17:21
1

Variables with automatic duration (i.e. local variables without the static storage class) start out containing garbage, unless they are explicitly initialized.

Source: http://c-faq.com/decl/initval.html

braindf
  • 734
  • 4
  • 14
0

Try this, instead:

int *i = 0;
printf("%p\n", i);

int *j = 0;
printf("%p\n", j);

You can write = NULL instead of = 0 if you prefer, but either way, the difference is that the pointers are initialized.

Why does this matter? Answer: because i and j are variables. That is, i and j are small, reserved blocks of storage in an area of your computer's memory called the stack. The purpose of such a block of storage, in light of a pointer definition like int *i, is to hold an address. However, in your case, you have written no address to the block of storage; so, when your printf tries to read the address, it just gets whatever, random bits of information happened already to be in the block of storage from before the definition int *i. The behavior is thus undefined.

thb
  • 13,796
  • 3
  • 40
  • 68
  • "It gets whatever random bits of information already happened to be ...": That's not the same as undefined behavior. There are situations in which a guarantee to that effect would make the program well-behaved. – Deduplicator Sep 11 '14 at 16:15
  • @Deduplicator: I did not know that. (I have been programming C++ for ten years, and have even taught a beginning college course on the subject, so it is good to know that there remain things for me to learn!) If you have some time, would you edit my answer so that (a) it is right and (b) it teaches me my mistake? My education is in electrical engineering, so I tend to think of C++ from a hardware perspective: maybe this is my problem. – thb Sep 11 '14 at 16:39
  • 1
    You hit that nail on the head in your comment: Your analogy is too physical, concrete and thus leaky. Simply said, look at the rules for initialization, indeterminate values and lvalue designators, and than lawyer. – Deduplicator Sep 11 '14 at 16:48
  • @Deduplicator: I should have said "C," not "C++." (I have been programming C for twenty years, if it matters.) – thb Sep 11 '14 at 16:49
  • 1
    As this goes into the dark and dangerous underbelly of the language, it actually matters. Quite a bit. Unless you prudently decide to just abstain from riding the edge (Which should be the advice extolled before diving into the details anyway). – Deduplicator Sep 11 '14 at 16:53
  • 1
    Added an answer exploring all those nooks and crannies. – Deduplicator Sep 11 '14 at 17:20