Reputation: 1373
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
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 0
— not NULL
— for the null pointer.
Upvotes: 10
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
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