Different types of pointer in C

Thread Starter

Dadu@

Joined Feb 4, 2022
155
Pointer is the most important and difficult topic in C programming language. I understand that pointer can point to memory location of another variable. There are many types of pointers such as null pointer, dangling pointer.

I don't understand the difference between NULL pointer and dangling pointer.

If I understand NULL pointer correctly, does it mean that NULL pointer does not point to any memory location and dangling pointer point to the invalid memory location.

What do you think is the difference between a null pointer and a dangling pointer?
 

MrChips

Joined Oct 2, 2009
30,720
A pointer is a program variable whose value is a memory address.

All variables have a value whether initialized or not.
If a pointer has not been initialized then it is dangling.
A NULL pointer could have been initialized to address 0.

In both cases, the pointer is invalid because it does not point to a proper memory address.
 

Papabravo

Joined Feb 24, 2006
21,159
A NULL pointer usually points to memory location 0. In most machine architectures, address 0 is, by convention, NOT a useful place for data to reside, and typically is used for some other purpose. Thus, a NULL pointer does point to an address, but that address is never used for data. Instead, it is used to represent a pointer that has not been initialized. NOTE: the token NULL is defined using a preprocessor macro and CAN be assigned a value other than zero. For example, you could have:
C:
#define NULL (-1)
A dangling pointer would point to a block of memory that has been "freeed". So although it points to a valid address, the data at that address is no longer valid or what you expect to be there.
 

MrChips

Joined Oct 2, 2009
30,720
To expand on this, using a NULL or dangling pointer will likely cause a program to crash.

The advantage of a NULL pointer is the program can detect that it is invalid. For example, it can be used to indicate the end of a list.

A dangling pointer still points to an address which you do not realize is no longer valid.
 

Thread Starter

Dadu@

Joined Feb 4, 2022
155
A dangling pointer would point to a block of memory that has been "freeed". So although it points to a valid address, the data at that address is no longer valid or what you expect to be there.
I don't understand dangling pointer. Let's say I am allocating dynamic memory using malloc. Now X hold the memory location. At this memory location I am storing value 2.

free (X )

What happens when i write above line code?
 

BobTPH

Joined Jun 5, 2013
8,816
When you call free, the memory pointed to is released and becomes available to allocate again.

So later, you might do:

Y = malloc(4);
*Y = 3;

now, if Y was allocated the same memory, *X is changed to 3 without any apparent assignment to it. This can cause disatrous behavior in a large, complex program. And it is very difficult to debug.

Bob
 

MrChips

Joined Oct 2, 2009
30,720
Here is response from another forum.
Setting unused pointers to NULL is a defensive style, protecting against dangling pointer bugs. If a dangling pointer is accessed after it is freed, you may read or overwrite random memory. If a null pointer is accessed, you get an immediate crash on most systems, telling you right away what the error is.

For local variables, it may be a little bit pointless if it is "obvious" that the pointer isn't accessed anymore after being freed, so this style is more appropriate for member data and global variables. Even for local variables, it may be a good approach if the function continues after the memory is released.

To complete the style, you should also initialize pointers to NULL before they get assigned a true pointer value.
 

ApacheKid

Joined Jan 12, 2015
1,533
I don't understand dangling pointer. Let's say I am allocating dynamic memory using malloc. Now X hold the memory location. At this memory location I am storing value 2.

free (X )

What happens when i write above line code?
I guess the term "dangling" isn't a specific language term!

I'd understand it to mean a pointer that contains an address that is no longer meant to be accessed. So in that code above you can see that X is not set to NULL, even though it was passed to "free" and the free API has done its work (merging free blocks, and so on) the pointer X continues to hold the address and could - if one was not careful - get used somehow later on.

It always amazed me that the signature for "free" was not:

Code:
void free(void **ptr)
So that the free function would forcibly set the supplied pointer to NULL before it returned.
 

nsaspook

Joined Aug 27, 2009
13,086
Most computer architectures have a hardware zero value flag for registers. Testing flags is easy and can be done quickly to check for a NULL pointer value vs software based testing an N-bit register for zero or not-zero.
 

nsaspook

Joined Aug 27, 2009
13,086
...
It always amazed me that the signature for "free" was not:

Code:
void free(void **ptr)
So that the free function would forcibly set the supplied pointer to NULL before it returned.
Because it's an unnecessary inefficiency in the vast majority of cases. C doesn't hold your hand, it's up to the programmer to get it right.
 

MrChips

Joined Oct 2, 2009
30,720
I would have expected the free( ) function to set the pointer to NULL, but it doesn't.
The other warning I just read is don't free( ) a pointer that already has been freed!
 

nsaspook

Joined Aug 27, 2009
13,086
I would have expected the free( ) function to set the pointer to NULL, but it doesn't.
The other warning I just read is don't free( ) a pointer that already has been freed!
The problem is usually not the original pointer used in the free() function. The usually programming error is from another another pointer to it (memory location) somewhere else that continues to be used after the fact. Setting the free'd pointer to NULL won't fix the most common of pointer errors. C is a sharp pointed instrument, act accordingly.
 

xox

Joined Sep 8, 2017
838
I would have expected the free( ) function to set the pointer to NULL, but it doesn't.

The other warning I just read is don't free( ) a pointer that already has been freed!
Only problem is, in C the pointer argument of the 'free' function is passed BY VALUE. In other words any changes to the pointer itself (where it points that is) will ONLY have a local effect inside that function.

A simple workaround might look something like this:

Code:
/*
 A safe `free` function alternative
*/

#include <stdbool.h>
#include <stdlib.h>

bool cede_(void** address) {
  free(*address);
  if (*address == NULL)
    return false;
  *address = NULL;
  return true;
}

#define cede(memory) cede_((void*)&memory)

// Sample usage:

#include <stdio.h>

void attempt(const char* what, bool succeeded) {
  printf("%s: %s\n", what, succeeded ? "success" : "FAIL");
}

int main() {
  int* dat = malloc(1024);
  attempt("Allocating data", dat != NULL);
  attempt("Freeing data", cede(dat));
  attempt("Freeing data", cede(dat));
}
Output:

Allocating data: success
Freeing data: success
Freeing data: FAIL
And yes in C it is perfectly fine to "free" a NULL pointer. (However that does not hold true for "fclose"!)
 

nsaspook

Joined Aug 27, 2009
13,086
IMO it's better to have a use-after-free crash that can be found in a core-dump than a hard to find operational bug hidden by 'safe' functions auto-nulling pointers in C.
 

xox

Joined Sep 8, 2017
838
IMO it's better to have a use-after-free crash that can be found in a core-dump than a hard to find operational bug hidden by 'safe' functions auto-nulling pointers in C.
That may seem so from the outset but actually use-after-free errors are notoriously difficult to pinpoint. Sometimes they lead to an instant crash, other times you just notice some weird data corruption somewhere else. Setting a pointer to NULL on the other hand is very useful, as you get an immediate core dump that is easily traced.

In any case, freeing a pointer then setting to NULL is so common that it really does warrant a single function call (or macro). Also, if you look at my implementation you will see that the return value can always be checked for diagnostic purposes (eg. "assert(cede(ptr));").
 

ApacheKid

Joined Jan 12, 2015
1,533
The problem is usually not the original pointer used in the free() function. The usually programming error is from another another pointer to it (memory location) somewhere else that continues to be used after the fact. Setting the free'd pointer to NULL won't fix the most common of pointer errors. C is a sharp pointed instrument, act accordingly.
This is true but c
That may seem so from the outset but actually use-after-free errors are notoriously difficult to pinpoint. Sometimes they lead to an instant crash, other times you just notice some weird data corruption somewhere else. Setting a pointer to NULL on the other hand is very useful, as you get an immediate core dump that is easily traced.

In any case, freeing a pointer then setting to NULL is so common that it really does warrant a single function call (or macro). Also, if you look at my implementation you will see that the return value can always be checked for diagnostic purposes (eg. "assert(cede(ptr));").
I fine example - IMHO - is a use after free error in a language parser I developed years ago.

A locally declared pointer was not initialized and so when the function was called several times there were times when - by pure fluke - the pointer contained a genuine true address of something that had been previously used, so it was scanning a tree that although the nodes were all valid, some of the nodes were not actually part of the tree.

Here's the fix - an init and here's the comment explaining it, one could argue that a freed pointer that retains the old address is more or less an uninitialized pointer.
 

click_here

Joined Sep 22, 2020
548
NOTE: the token NULL is defined using a preprocessor macro and CAN be assigned a value other than zero
NULL is always 0

C99 Standards, 6.3.2.3 Pointers, section 3:
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function

The normal definition that you'll see is...
Code:
#define NULL (void *)0
That is why you see code like this...
Code:
int Banana(int *apple)
{
    if(!apple)
        return NULL_ARGUMENT_EX;

    ....
 
Top