LED Fantom
LED Fantom

Reputation: 1373

When to use NULL and when to use '\0' in linked list in C?

I learned that in C: null char == '\0' == NULL, and I wrote a loop below to read from the start to the end of a char[] in C.

// case #1
char buf[32];
while (buf[i] != NULL){
    //do something...
}  

However, my gcc compiler gave me a warning: comparison between pointer and integer. Someone mentioned that I was confusing two separate concepts: NULL is for pointers, whereas '\0' is for characters. So to get rid of the warning, I should use '\0' since my loop tests a char.

Now I am writing a linked list, and testing if a head pointer points to a node or not. Since it's struct, it's reasonable to use if (h1 == NULL) but apparently the compiler also compiles when I use if (h1 == '\0') even though the node is a struct but not a char. Can someone give some help why both '\0' and NULL can be used in this case while they can't be both use on the first case?

// case #2
struct ListNode {
    int val;
    struct ListNode *next;
};

Upvotes: 5

Views: 2043

Answers (3)

zwol
zwol

Reputation: 140886

This is a very common confusion. A "null character" (often spelled NUL, with only one L, for historical reasons) is a character that compares equal to zero. A "null pointer" is a pointer that compares equal to zero. The difference is only the type -- but that is an important difference. The compiler is allowed, but not required, to object to your program, because you are comparing a character value to a null pointer constant.

C has a fairly loose type system, especially when it comes to integer constants, so you can get away with using constants with a formally incorrect type a lot of the time. This is especially true when it comes to zero: the integer literal 0 can be used everywhere it is safe to use the macro NULL or the character literal '\0'. In fact, the implementation is specifically allowed to use #define NULL 0 in all editions of the C standard. Because of this, there are a small handful of contexts where one absolutely must use (T*)0 for some concrete type T, instead of either bare 0 or NULL, such as when passing null pointers to a function that takes a variable number of arguments (e.g. execl).

As further icing on the confusion cake, in C character literals have type int, not char, and '\0' is a legitimate null pointer constant. (In C++ neither of those things is true.)

Best practice in C, IMNSHO, is to use '\0' for the null character, and 0not NULL — for the null pointer.

Upvotes: 10

Remy Lebeau
Remy Lebeau

Reputation: 598448

Depending on the compiler, NULL may be defined may different ways:

#define NULL ((char *)0)

#define NULL ((void *)0)

#define NULL 0L

#define NULL 0

NULL is meant for pointer comparisons. However, integer 0 is a special case that is allowed for pointer comparisons, which is why you can compare a ListNode* pointer against 0 directly (otherwise the above NULL defines where a pointer type-cast is not present would not work):

if (h1 == 0)

Or simpler:

if (!h1)

A '\0' character literal is an int in C, and is implicitly convertible to an int in C++. So '\0' can be used in pointer comparisons as well.

You should use '\0' (or just 0) for character comparisons, do not use NULL:

while (buf[i] != '\0') // or 0

Or simpler:

while (buf[i])

Upvotes: 3

Will Richardson
Will Richardson

Reputation: 7980

NULL is effectively used as null terminator for linked lists or arrays of pointers. '\0' is used as a null terminator for strings (i.e. char arrays)

If you had an array of structs, you might want to loop over them until you reach the end:

MyStruct** things = ...
for(int i = 0; things[i] != NULL; i++) {
    // Do something with things[i]
}

This loop will end when the pointer to the last struct is NULL.

Upvotes: 1

Related Questions