2

Can a null pointer be reused? If yes, under what conditions?

More specifically, can anyone tell what happens with this piece of code?

int *p = 0;
p = (int*)malloc(sizeof(int));

If it's problematic - why? And what is the correct way to do it?

EDIT: I know it's not necessary to do it like that. I'm asking what happens in order to understand the way pointers work in C.

  • It's OK and quite common. Except that allocating a single `int` is normally never needed. – prapin Feb 01 '22 at 10:45
  • 1
    About casting the result of `malloc()`, see https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – nielsen Feb 01 '22 at 11:02
  • It is a code smell ("double write") if you assign a value to a variable and reassign it without reading it before. I'd like to extend this to initialized variables, too. – the busybee Feb 01 '22 at 11:08
  • @thebusybee You are correct when addressing veteran programmers. However, beginners should simply be taught to always initialize their variables. There will be a time when they can skip out such initializations, when they are experienced enough to always consider what's the first point when a variable is used in the source. But that's some 5+ years down the road for most. – Lundin Feb 01 '22 at 11:30
  • better `p = malloc(sizeof(*p))` – 0___________ Feb 01 '22 at 18:38

4 Answers4

5

Can a null pointer be re-used?

Yes

if yes, under what conditions?

Always

Your question is actually equivalent to ask when it's ok to reuse an int that has been set to zero, or any other value for that matter. What you need to know is that you cannot undo an assignment, so whatever value the pointer contains will be lost. This is the only direct consequence of reassigning a pointer, null or not null. Any problems will be a consequence of no longer having access the previous value. The reassignment itself is always fine, provided it's done properly. See below.

There are basically two common problems related to this when it comes to pointers.

  1. Dangling pointers. This will happen after you call free on a pointer. It will also happen if the object the pointer is pointing at goes out of scope. A dangling pointer contains garbage, and it's undefined behavior to dereference it.

  2. Memory leaks. If you have allocated memory with malloc or similar to a pointer p and then reassign the pointer, you may lose the ability to free the allocated memory.

But it is always legal to reassign a pointer. What value it contains does not affect that. Consider this code:

...
int *p;
...
p = x;

If this is ok or not will entirely depend on x. Both it's type and value and if it is initialized or not.

More specifically, can anyone tell what happens with this piece of code?

It does work. But I have a few remarks.

  1. It's not necessary to initialize the pointer to null before assigning. Some say it's a good habit. Others say it's bad. There are pros and cons and depends on the situation. I personally think it's bad1 to always2 use it.
    1 In short, my argument is that if null initialization solves a problem, then you might have a much bigger problem in your design that the initialization will not solve, but only hide.
    2 There are valid use cases. Use it in those cases, but make sure you understand why you're doing it.

  2. There's no need to cast the result from malloc. Again, some say it's good. Some say it's bad. I think it's bad, unless you want to compile the C code with a C++ compiler.

  3. Don't use sizeof(int). Use sizeof *p instead.

See Do I cast the result of malloc? to read about 2 and 3.

I'd write your code as

int *p = malloc(sizeof *p);
if(!p) {
    // Handle error
}
klutt
  • 30,332
  • 17
  • 55
  • 95
1

This declaration

int *p = 0;

declares the variable p that is initialized by a null pointer constant.

As any other variable that is not qualified the variable p can be reassigned with a new value as for example

p = (int*)malloc(sizeof(int));

Note: in C you can also just write

p = malloc( sizeof( int ) );

You could not reassigned the variable if it was declared with the qualifier const like

int * const p = 0;

Here is a simple demonstration program

#include <stdio.h>
#include <stdlib.h>

int main( void )
{
    int *p = 0;

    p = malloc( sizeof( int ) );

    if ( p != NULL )
    {
        *p = 10;
        printf( "*p = %d\n", *p );
    }

    free( p );

    int x = 20;

    p = &x;

    printf( "*p = %d\n", *p );
}

Pay attention to that you may call the function free for a null pointer.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

Pointers behave exactly the same as any other object.

If you have an integer variable:

int x = 0;

would you ask if you can "reuse" it and assign another value?

0___________
  • 60,014
  • 4
  • 34
  • 74
1

Any normal (read/write) pointer can be assigned a new value at any time without problems. A null pointer is simply a pointer pointing at a somewhat well-defined "nowhere". It is generally considered good practice to initialize all pointers to null for that reason. Your code isn't problematic but good practice.

Take your specific example: since you initialize p to null, it will now be possible to write a clean-up code such as

free(p);
p=NULL;

This clean-up code can be called regardless of if malloc was called or not, since passing a null pointer to free is well-defined as "no operation".

This in turn enables the possibility to write an initializing function which can be called multiple times, regardless of if p points at valid memory or not. It would simply clean up the previous use before calling malloc.

What you can't do is to re-assign a pointer pointing at the result of malloc, or you lose the reference to that allocated memory and can't free() it. That creates a memory leak.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Initializing pointers to null is good in some situations but bad in others. I would not say it's good practice to do it in the general case. – klutt Feb 01 '22 at 12:25