-4

I was referring to NULL Pointer in What's the difference between a null pointer and a void pointer? According to the post reply by @AnT, "Formally, each specific pointer type (int *, char * etc.) has its own dedicated null-pointer value"

I wrote simple program. But the pointer value is not fixed for integer or character. It changes sometimes. So how can we conclude that NULL pointer to int has a fixed value? Also the value of pointer is never 0.

 #include <stdio.h>

int main()
{
    int a;
    char *ptr; // Declaring a pointer without initializing it
    int *ptrToInt;

    if(ptr)
    {
        printf("Pointer is not NULL\n");
        printf("Value of pointer = %x\n",ptr);
        printf("Value of pointer = %x\n",ptrToInt);
    }
    else
    {
        printf("Pointer is NULL\n"); 
        printf("Value of pointer = %x",ptr);
        printf("Value of pointer = %x\n",ptrToInt);
    }
    return 0;
}
Community
  • 1
  • 1
Jon Wheelock
  • 263
  • 3
  • 16
  • 3
    Your `if(ptr)` is undefined behavior, since `ptr` is an uninitialized automatic variable. See C11 draft standard `6.2.4 Storage durations of objects, Section 6` and `Annex J.2 Undefined behavior`. – EOF Oct 03 '15 at 17:13
  • I do not see any null-pointer, but just two uninitialised pointers. – alk Oct 03 '15 at 17:15
  • should be `char *ptr = NULL;` – nafsaka Oct 03 '15 at 17:17
  • Also to print a pointer value use the `%p` conversion specifier and cast the pointer to `void*`: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html – alk Oct 03 '15 at 17:17
  • 3
    An uninitialised pointer is not a null-pointer. – alk Oct 03 '15 at 17:18
  • `NULL` is a macro with a **a** _null pointer constant. It is not **the** _null pointer_, as that is any pointer which contains **a** _null pointer constant_. There is no "NULL pointer` and not a single constant (this is not related to type, but generally). So, there might be a bit which makes a pointer a _null pointer_ with the rest being ignored. Anyway, your code does not even contain a _null pointer constant_m but undefined behaviour. Please read a tutorial or book! – too honest for this site Oct 03 '15 at 17:23
  • 1
    And do not print pointer values with integer format string type specifier, but use the correct one `"%p"`! – too honest for this site Oct 03 '15 at 17:27
  • a `void*` is a type similar to `int*`, `char*`, etc. a pointer can contain a NULL (thereby called a NULL pointer) – user3629249 Oct 03 '15 at 17:28
  • this line: `if(ptr)` is testing the contents of the ptr variable, however that variable has not been set/initialized to any specific value. Therefore, it contains trash. (for a 32 bit architecture) that ptr variable has a 1/4gig chance of containing 0 I.E. a 4gig -1 chance of the code entering the first `if` statement. Similar statements can be said for the `ptrToint` variable – user3629249 Oct 03 '15 at 17:33
  • @user3629249: The standard does not require a single value _null pointer constant_. There is a clear distinction between the NULL` macro and a _null pointer_: Please read the standard. – too honest for this site Oct 03 '15 at 17:43
  • By standard _null pointer constant_ and _null pointer_ have definition. And NULL is macro implementation of _null pointer constant_. _null pointer constant_ is not constant of _null pointer_, which mean a compiler can't define _null pointer_ = 123 as a constant. Look here for clarity: http://stackoverflow.com/questions/2599207/can-a-conforming-c-implementation-define-null-to-be-something-wacky – nafsaka Oct 03 '15 at 18:23

1 Answers1

1

NULL is a value that means a pointer of any type is not valid, and void* is a type. In C or C++, the constant 0 can be assigned to a pointer of any type, and will set it to a null pointer of that type. The constant NULL might be declared as 0, ((void*)0), or something else on an unusual system.

A NULL pointer is a pointer, of any type, that’s been set to the invalid value NULL. You have to set it to this value yourself; simply leaving a pointer with no initializer means it might contain garbage. (There are technically a few exceptions, but always initialize your variables.)

A void* is a type that can store any other type of pointer (except a pointer to a function). It can’t be dereferenced, and you can’t index it like an array or do pointer arithmetic on it. It’s typically used as syntactic sugar to let you call a function such as memset(), which just treats the address you give it as an array of bytes to be filled, or assign p = malloc(…), without an explicit cast. In other words, when you just treat a pointer as an untyped block of memory that will be turned into some type of object later, but you don’t care which.

If you want to test the bit values of null pointers of different types, I suggest a cast to uintptr_t and the printf() format specifier in <inttypes.h>. On most but not all implementations, these will all be zero.

Davislor
  • 14,674
  • 2
  • 34
  • 49
  • Unfortunately the C standard does not require a null pointer constant to have type `void *`. There is no "`NULL` pointer", but a _null pointer_. `NULL` is just a macro. The actual value use for _null pointer constant_ is not defined by the standard. It just has to compare unequel to any valid pointer value. – too honest for this site Oct 03 '15 at 18:22
  • And you **always** have to initialize an `auto` variable; there are no exceptions. The only difference is _how_ to. You do not ned an _initializer_, but can use an assignment as well. `void *` is not "syntactical sugar", but a required type, as it is the only one which can be converted to/from any other _object pointer_. – too honest for this site Oct 03 '15 at 18:26
  • The addition of C++ is a very bad idea, as C++11 introduced a true `nullptr` which is clearly different from missusing the integer `0` as done before in both languages. Using `0` in C++ has fianlly been deprecated (so they learned finally from older languages like Pascal). Hopefully, C will follow , but I'm not optimistic. – too honest for this site Oct 03 '15 at 18:31
  • @Olaf: Whoops, corrected the sentence about the type of `NULL`: it is often, but not guaranteed, to be `(void*)0`. – Davislor Oct 03 '15 at 18:31
  • Well, it should be and I do enforce it if I can define the coding standard. This missuse of `0` is one of the worse legacies of C. – too honest for this site Oct 03 '15 at 18:32
  • 3.2.2.3 Pointers An integral 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 assigned to or compared for equality to a pointer, the constant is converted to a pointer of that type. Such a pointer, called a _null pointer_, is guaranteed to compare unequal to a pointer to any object or function. – nafsaka Oct 03 '15 at 18:32
  • Nonetheless, using `0` works and is historically how it’s been done. It’s tagged as a C question. – Davislor Oct 03 '15 at 18:33
  • @Olaf " It just has to compare unequel to any valid pointer value" Then i can just use 0xB00000000000 in the compiler as a constant, then the compiler will make this constant not applicable to any pointer. – nafsaka Oct 03 '15 at 18:36
  • No, most compilers `#define NULL ((void *)0)` actually. See gcc `stddef.h`: they even differentiate between C and C++ (and modern gcc). Problem `(void *)` is not used in C++ is it had to be cast to the actual type. In C, this is not required. Reason you might see `0` in C code is either it was compiled by a C++ compiler (which is a **very** bad idea - C != C++) or people coming from C++ and ignoring/not knowing they are different languages. – too honest for this site Oct 03 '15 at 18:37
  • @olaf, yes by the standard it, actually said _integral constant expression_ with the value 0, or such an expression cast to type void*. Not just only "has to compare unequal to any valid pointer value" – nafsaka Oct 03 '15 at 18:38
  • The exceptions to always having to initialize your variables include static variables . That time, I *was* being pedantically correct. And I did say to always initialize your variables. I’m not sure what the objection is. – Davislor Oct 03 '15 at 18:39
  • @nafsaka: Where do you read the opposite? There are/have been architectures `(void *)0` is/has been a valid address. The compiler is not enforced to use the value `0` for a _null pointer constant_`! It just has to ensure the correct behaviour (a such constants compare equal, etc.). Admittedly, using the _integer constant_ `0` makes it complicated to cast this value to a pointer, but actually this is _undefined behaviour_ anyway. – too honest for this site Oct 03 '15 at 18:40
  • @nafsaka: The standard does not have a section "3.2.2.3". Please provide a link! And [3.2](http://port70.net/~nsz/c/c11/n1570.html#3.2) is a definition of the term "alignment" – too honest for this site Oct 03 '15 at 18:41
  • @Olaf. I read from here http://stackoverflow.com/questions/2599207/can-a-conforming-c-implementation-define-null-to-be-something-wacky and here:http://stackoverflow.com/questions/2599207/can-a-conforming-c-implementation-define-null-to-be-something-wacky The CDC Cyber 180 Series has 48-bit pointers consisting of a ring, segment, and offset. Most users (in ring 11) have null pointers of 0xB00000000000 – nafsaka Oct 03 '15 at 18:41
  • 1
    @nafsaka: There is a difference between the definition of the macro `NULL`, resp. a _null pointer constant_ marker (which unfortunately is the integer constant `0`) and the actual value used internally! This is the reason better designed languages use a reserved word for this special value. Note that C++ has also introduces such a reserved word with `nullptr`. – too honest for this site Oct 03 '15 at 18:43
  • @nafsaka: What do you mean? – too honest for this site Oct 03 '15 at 18:46
  • A common example of casting the value 0 to a pointer as the literal value zero is the trick to define `offsetof(t,m)` as `((size_t)&((t*)0)->m)` or similar. This invokes undefined behavior, but (from memory) many real implementations have used a cast such as that. – Davislor Oct 03 '15 at 18:47
  • @Olaf I don't understand with "difference between the definition of the macro NULL" "and the actual value used internally"? For example i've read from stddef.h from my linux, it should used this #define NULL ((void *)0). Does it mean that gcc will use a different value internally (in gasm maybe?) – nafsaka Oct 03 '15 at 18:47
  • @Lorehead: Please think about the implications of the term "underfined". This is a borderline case; 1) as this is not assigned to a pointer, `0` is - strictly speaking - not a pointer, but only after the cast, 2) this pointer is never dereferenced. Note that the standard ony says that the _integer constant_ `0` or that cast to `void *` are actually _null pointer constants_, not `0` cast to a different pointer type! – too honest for this site Oct 03 '15 at 18:53
  • @nafsaka: That is actually implementation defined, and likely it **will** use the absolute value `0` as _null pointer constant_. However, it is free to use any other value internally. That depends on the implementation, it migh use a bit for that or anything else. Just consider an architecture which includes type-information in a pointer value (one reason castiong pointer types is also UB). – too honest for this site Oct 03 '15 at 18:56
  • @Olaf I don't understand, so gcc definition shows us ((void *)0) but in the assembly or machine code it could be different constant (0xB00000000000 for example). It's that what you mean? – nafsaka Oct 03 '15 at 19:01
  • Although I’m feeling like I stepped into someone’s holy war, one final point before I go. In the examples I gave, `void*` is syntactic sugar because any function needs to cast any `void*` value to another type anyway in order to dereference it. You could just do this before calling or after returning. Historically, `void*` simply replaced `char*` in the prototypes of some stdlib functions. The `void*` type saves us from writing an explicit cast; but `malloc()` and `memset()` need to manipulate blocks anyway, so there has to be a type they can use for that internally, which is not `void*`. – Davislor Oct 03 '15 at 19:04
  • @nafsaka: Doese gcc type your source code? This has already gone too far OT. Please read (and understand) the standard. There is a reason they talk only about an "abstract machine" and not actual implementation. And gcc is not the only compiler (for instance: it only uses 2s complement for signed integers, so it cannot be used for targets with other representation). Btw: do you think the CPU works with integers as a string? `123` is a string in the first place, so the compiler has to convert this, too. – too honest for this site Oct 03 '15 at 19:07
  • @Olaf I mean it as integer, i usually use "123" to identify it as a string. – nafsaka Oct 03 '15 at 19:15
  • @Olaf Yes i think you're right, it doesn't said about anything in the machine representation. So to comment my own question, whether the machine code could be different(for example 0xB00000000000), then Yes, i think it could. But the implementation of the compiler still either 0 (integral constant expression, could be 1-1 or 3-2-1, can't be 0xB00000000000) or cast of it with (void *). – nafsaka Oct 03 '15 at 20:31
  • The practical implication of that feature is that you can’t portably count on memory cleared with `memset()` or obtained from `calloc()` to contain initialized null pointers. They’ll contain pointers with all bits zero. And a compiler with that property might provide a constant like `zero_ptr` or a function like `void* make_pointer(uintptr_t)`. In practice, though, the assumption that a `0x0` pointer is invalid is so commonplace that most compilers will probably try to work around it rather than break that much code. – Davislor Oct 04 '15 at 02:23