Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: Why do unassigned pointers point to unpredictable memory and NOT point to NULL?

Tags:

c

pointers

A long time ago I used to program in C for school. I remember something that I really hated about C: unassigned pointers do not point to NULL.

I asked many people including teachers why in the world would they make the default behavior of an unassigned pointer not point to NULL as it seems far more dangerous for it to be unpredictable.

The answer was supposedly performance but I never bought that. I think many many bugs in the history of programming could have been avoided had C defaulted to NULL.

Here some C code to point out (pun intended) what I am talking about:

#include <stdio.h>  void main() {    int * randomA;   int * randomB;   int * nullA = NULL;   int * nullB = NULL;     printf("randomA: %p, randomB: %p, nullA: %p, nullB: %p\n\n",       randomA, randomB, nullA, nullB); } 

Which compiles with warnings (Its nice to see the C compilers are much nicer than when I was in school) and outputs:

randomA: 0xb779eff4, randomB: 0x804844b, nullA: (nil), nullB: (nil)

like image 816
Adam Gent Avatar asked Jun 23 '10 13:06

Adam Gent


People also ask

Is an unassigned pointer null?

NULL vs Uninitialized pointer – An uninitialized pointer stores an undefined value. A null pointer stores a defined value, but one that is defined by the environment to not be a valid address for any member or object.

Why do we set pointers to null?

A null pointer has a reserved value that is called a null pointer constant for indicating that the pointer does not point to any valid object or function. You can use null pointers in the following cases: Initialize pointers. Represent conditions such as the end of a list of unknown length.

Should you always initialize pointers to null?

No, you don't have to set it to NULL , but some consider it good practice as it gives a new pointer a value that makes it explicit it's not pointing at anything (yet). If you are creating a pointer and then immediately assigning another value to it, then there's really not much value in setting it to NULL .

What does uninitialized pointer point to?

The pointer p is uninitialized and points to a random location in memory when you declare it. It could be pointing into the system stack, or the global variables, or into the program's code space, or into the operating system.


2 Answers

Actually, it depends on the storage of the pointer. Pointers with static storage are initizalized with null pointers. Pointers with automatic storage duration are not initialized. See ISO C 99 6.7.8.10:

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

  • if it has pointer type, it is initialized to a null pointer;
  • if it has arithmetic type, it is initialized to (positive or unsigned) zero;
  • if it is an aggregate, every member is initialized (recursively) according to these rules;
  • if it is a union, the first named member is initialized (recursively) according to these rules.

And yes, objects with automatic storage duration are not initialized for performance reasons. Just imagine initializing a 4K array on every call to a logging function (something I saw on a project I worked on, thankfully C let me avoid the initialization, resulting in a nice performance boost).

like image 87
ninjalj Avatar answered Nov 04 '22 15:11

ninjalj


Because in C, declaration and initialisation are deliberately different steps. They are deliberately different because that is how C is designed.

When you say this inside a function:

void demo(void) {     int *param;     ... } 

You are saying, "my dear C compiler, when you create the stack frame for this function, please remember to reserve sizeof(int*) bytes for storing a pointer." The compiler does not ask what's going there - it assumes you're going to tell it soon. If you don't, maybe there's a better language for you ;)

Maybe it wouldn't be diabolically hard to generate some safe stack clearing code. But it'd have to be called on every function invocation, and I doubt that many C developers would appreciate the hit when they're just going to fill it themselves anyway. Incidentally, there's a lot you can do for performance if you're allowed to be flexible with the stack. For example, the compiler can make the optimisation where...

If your function1 calls another function2 and stores its return value, or maybe there are some parameters passed in to function2 that aren't changed inside function2... we don't have to create extra space, do we? Just use the same part of the stack for both! Note that this is in direct conflict with the concept of initialising the stack before every use.

But in a wider sense, (and to my mind, more importantly) it's aligned with C's philosophy of not doing very much more than is absolutely necessary. And this applies whether you're working on a PDP11, a PIC32MX (what I use it for) or a Cray XT3. It's exactly why people might choose to use C instead of other languages.

  • If I want to write a program with no trace of malloc and free, I don't have to! No memory management is forced upon me!
  • If I want to bit-pack and type-pun a data union, I can! (As long as I read my implementation's notes on standard adherence, of course.)
  • If I know exactly what I'm doing with my stack frame, the compiler doesn't have to do anything else for me!

In short, when you ask the C compiler to jump, it doesn't ask how high. The resulting code probably won't even come back down again.

Since most people who choose to develop in C like it that way, it has enough inertia not to change. Your way might not be an inherently bad idea, it's just not really asked for by many other C developers.

like image 22
detly Avatar answered Nov 04 '22 15:11

detly