Thread: Difference between NULL, (void *)0 and (char *)0

  1. #1
    Registered User
    Join Date
    Mar 2024
    Posts
    6

    Difference between NULL, (void *)0 and (char *)0

    I'm not sure I really get the difference between NULL, (void *)0 and (char *)0.

    According to the C standard:
    An integer constant expression with the value 0, or such an expression cast to type
    void *, is called a null pointer constant.
    The macros are
    NULL
    which expands to an implementation-defined null pointer constant; and
    So does that mean that those values can be used on pointers of any type? For example, are these valid null pointers?:
    Code:
    #include <stdio.h>
    
    struct book {
        char title[25];
        char author[25];
    };
    
    int main(void) {
        int *ptr1 = 0;
        int *ptr2 = (void *)0;
        char *name = 0LL;
        struct book book1 = 0;
        struct book book2 = NULL;
        return 0;
    }
    And it also means that the NULL macro may be either (void *)0, or just plain 0 or even 0L.

    Furthermore, the standard also says:
    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.
    So this means those constants casted to a specific type are valid null pointers for that type, but not for another one? For example:
    Code:
    #include <stdio.h>
    
    struct book {
        char title[25];
        char author[25];
    };
    
    int main(void) {
        int *ptr1 = (int *)0; // Correct, int null pointer
    
        int *ptr2 = (void *)0; // Correct, null pointer constant
    
        struct book book1 = (struct book *)0; // Correct, struct book null pointer
    
        struct book book2 = NULL; // Correct, null pointer constant
    
        int *ptr3 = 0LL; // Correct, null pointer constant, despite the constant being of type long long
    
        float *ptr4 = (int *)0; // Incorrect, assignment of an int null pointer to a float pointer
    
        return 0;
    }
    Did I understand it correctly??

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Sabidos
    So does that mean that those values can be used on pointers of any type? For example, are these valid null pointers?
    They look fine to me. Instead of being too concerned with such details, just use NULL and compile at a high warning level to help to detect issues.

    Quote Originally Posted by Sabidos
    And it also means that the NULL macro may be either (void *)0, or just plain 0 or even 0L.
    Yes.

    Quote Originally Posted by Sabidos
    So this means those constants casted to a specific type are valid null pointers for that type, but not for another one?
    What that part of the standard actually means is that null pointers are guaranteed to compare unequal to pointers that actually point to something, be it an object or a function. It's not concerned about null pointers of different types.

    Having said that, it would be confusing to use a null pointer of type int* when you want to initialise a pointer to float. Don't do that, even if your compiler allows it.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Sep 2022
    Posts
    55
    Maybe it will be better understood if you ignore both the semantics of pointers and what the standard says for a moment. The value of a pointer variable is a memory address in all implementations that I can think of. So imagine a pointer as the number of a house in a street. The type of the pointer tells about how many bytes it points to, like how many people are living in a house. In case of a pointer to void it's unclear to how many bytes it points to (void is an "incomplete type") which is the reason why a void* can't be de-referenced to access the memory it points to. NULL is a special case. Usually it holds address 0. Just like the counting of houses in a street begins with 1, where address 0 is not valid. So NULL points to "nowhere" and thus, NULL represents a well-defined error state.

    Back to the standard: NULL can be used to initialize/assign pointer variables of any type, NULL can be passed to any pointer parameter (which doesn't mean that the function implementation handles it), and pointers of any type can be compared against NULL for equality. This is the reason why you don't need type casts. Compilers don't complain because they would violate the rules of the standard otherwise. Moreover, the standard tells nothing about the result of a type cast of 0 to any other pointer type than void* What I said above about pointers holding memory addresses and value 0 being the address of a null pointer is how it is implemented on many (if not all) platforms. In theory, though, NULL can be anything implementation-defined, where the compiler is required to do the right things if it sees (void*)0 but not in case of (struct book *)0.

  4. #4
    Registered User
    Join Date
    Apr 2021
    Posts
    140
    When C was first implemented, they used 0 to mean a pointer that had no value.

    This was because a 0 pointer had no meaning on their systems.

    However, when they started spreading C to other machine types, they came across a class of computers that had flag bits in their pointers -- the pointers contained an address, but there were more bits in the pointer than there were bits in the address space, and the computer vendor chose to put protection bits and other strangeness in the pointer. (Like, imagine if you had a number that could store up to 100,000. But there were only 1000 valid addresses, so the top digits weren't being used until some clever idiot said, "hey! we can put apartment numbers up there" or something. So "#705 main street, apartment 99" becomes 99705.

    As a result, it was possible that a "null pointer" was actually something like 0x6000. Why? Because some idiot wanted to use all the bits, that's why. But the reality was, every OTHER programmer compared their pointers with 0. So what's a compiler writer to do? What's the standards committee to do?

    They made a rule: if you're comparing a pointer against "zero", then you're checking for a null pointer. And if "null pointer" on your system isn't zero, then substitute that value. But the source code is still gonna say "0" someplace.

    If it helps, think of "0" as being the null-pointer-operator and also the "zero number operator", much like how "-" can be the "negative number prefix" and also the "subtraction" operator. It all depends on the context where they are used.

    Finally, see here: Question 5.17

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. What is the difference between these 2 void
    By sash_007 in forum C Programming
    Replies: 4
    Last Post: 06-26-2019, 03:59 PM
  2. void and null pointers
    By cooljaini in forum C Programming
    Replies: 1
    Last Post: 05-23-2012, 06:24 AM
  3. difference between void and static void function
    By mahaju in forum C++ Programming
    Replies: 7
    Last Post: 12-27-2011, 04:02 AM
  4. difference between 0 and null
    By anomaly in forum C++ Programming
    Replies: 23
    Last Post: 12-13-2003, 04:29 PM
  5. Read File To Char Array with Null char init
    By MicroFiend in forum Windows Programming
    Replies: 1
    Last Post: 10-28-2003, 06:18 PM

Tags for this Thread