storing an integer constant other than zero in a pointer variable - c++

int main()
{
int *d=0;
printf("%d\n",*d);
return 0;
}
this works fine.
>cc legal.c
> ./a.out
0
if i change the statement int *d=0; to int *d=1;
i see the error.
cc: "legal.c", line 6: error 1522: Cannot initialize a pointer with an integer constant other than zero.
so its obvious that it will allow only zero.i want to know what happens inside the memory when we do this int *d=0 which is making it valid syntax.
I am just asking this out of curiosity!

I'm surprised that you didn't get a SEGFAULT when you ran your code. The *d in the printf statement is dereferencing the pointer. To answer your question, though, C++ allows 0 to be given as a default initializer for any object, which is why it can be used to initialize the pointer to null (0 and null are identical). With the value of 1, you are asking the compiler to convert an integer to a pointer, which requires an explicit cast.

When initializing a pointer with 0, that 0 is implicitly converted to a null-pointer. How that null-pointer looks depends on your platform, the compiler will use the correct binary value.
When you try to initialize the pointer with 1 (or any other non-zero integer) the compiler doesn't know to convert this value to a valid pointer and issues a warning.

You are creating a pointer variable called d on the stack which is said to "point to an integer". You then assign that pointer variable to 0 which makes it point to memory address 0x0 which valid (and the same as NULL in C).
To make this clearer, int *d = 0 is the same as:
int *d;
d = 0; // set it to address 0
If you want to point to an integer 1 then you need this:
int x = 1;
int *d = &x; // "set it to 'address of x'"

Incase of *d = 0, your integer pointer d is getting initialized to 0 which is valid. Basically you are declaring an integer pointer so it makes sense to initialize a pointer.
But, you don't want to initialize the pointer, rather initialize memory pointed to by it, which is incorrect.
When you do *d = 1, the pointer values becomes 1, and when your printf statement gets executed, it will try to access the value at address 1 which will not be allowed.
Hope this helps.

In your "working" example you are dereferencing a null pointer and the language is putting whatever bits it finds as the argument to printf. That it works at all is a totally implementation dependent feature of your compiler and machine and will likely segfault in another implementation.
That the code works seems to be an indication that your compiler is doing something odd behind the scenes in attempt to "protect" coders from a very common error; that's a bad idea. I'd love to see what assembly is generated by your compiler with cc -s

In ISO-C99, there are two types of null pointer constants: integer constant expression of value 0 - eg 0, 1 - 1, (int)0.0 - and such expressions cast to void * - eg (void *)0, which is often used to define NULL.
Converting a null pointer constant to an arbitrary pointer type yields a null pointer of that type. This conversion is implicit, but may actually involve address translation as the standard doesn't require null pointers to have the bit-representation 0.
This conversion is also defined for function pointer types, even if it's normally illegal to convert object pointers to function pointers:
void (*foo)(void) = (void *)0; // valid
void *bar = 0; // valid
void (*baz)(void) = (void (*)(void))bar; // invalid even with explicit cast
This also means that you can use 0 to initialize any scalar type without casting, and it's the only value for which this is true: Converting 0 to pointer types will always yield a null pointer, whereas converting any other integral value is possible, but requires explicit casting, has an implementation-defined result and might fail due to alignment or address space restrictions.

Related

What happens we create a nullptr and use it in a IF condition in C++

Hi i am trying to see what happens when i create a nullptr in C++ and use it in a if statement. For example, my code is as following:
int *p=nullptr; if(p){cout<<"Inside IF";}
My questions are as follows:
What happens when we create a nullptr? I mean does a new pointer object is created that holds the value 0(as address) or something else? And if the address it holds is 0 then is that pointer pointing to a possibly valid address in the memory?
What is happening when we use it in the IF statement ? I mean is the IF statement checking whether the value that the pointer object holds is 0 or something else?
What happens when we create a nullptr?
You can create a null pointer, but not a nullptr. The keyword nullptr denotes a literal value, not something that can be created.
Based on your code, you meant to ask what happens when a pointer variable is assigned nullptr. The answer to that is that your variable becomes a null pointer, a pointer that points to nothing and that evaluates to false when used in a boolean context.
I mean does a new pointer object is created that holds the value 0(as address) or something else?
We usually think of the value of a null pointer as being zero, but technically an implementation could use a bit pattern that has some non-zero bits. As long as you do not look too closely at the compiled code, go ahead and think of null pointers as holding the address 0.
And if the address it holds is 0 then is that pointer pointing to a possibly valid address in the memory?
The value of a null pointer must be distinct from all potentially valid memory addresses. If 0 is possibly a valid memory address in an implementation, then that implementation must use a different bit pattern to represent null pointers. (I am not aware of any implementations that fall into this category.)
What is happening when we use it in the IF statement ?
The condition of an if statement is contextually converted to bool. When converting to bool from a pointer, the null pointer value converts to false and all other values convert to true.
I mean is the IF statement checking whether the value that the pointer object holds is 0 or something else?
Something else (but only by a fine shade of meaning). It checks whether the value is the null pointer value (which is almost certainly represented by zero bits on your computer, but technically not guaranteed to be so).
What you said is right nullptr allocates location and gives value 0 and 0 is false in c++
#include <iostream>
using namespace std;
int main() {
int *p=nullptr;
if(p){cout<<"Inside IF";}
cout<<&p<<endl;
cout<<p;
}
Output
0x7ffc92b66710
0
For reference:
nullptr, the null pointer literal
std::nullptr_t, the type of nullptr
implicit conversions, particularly pointer to bool conversions.
The line
int *p=nullptr;
Creates an int* pointer-to-int with automatic storage duration. Then nullptr is assigned to it, and is automatically converted to the null pointer value for the int* pointer. It's not actually necessarily the case that this value is stored internally as 0, although there's an implicit conversion from the integer literal 0 to the null pointer value for every pointer type.
Then, in the comparison
if(p){cout<<"Inside IF";}
There's an implicit conversion from every pointer type to bool, which is applied in this if statement. Specifically:
Boolean conversions
The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true.
So p has the value of the null int* pointer, and therefore becomes false.

Can I use NULL as substitution for the value of 0?

Am I allowed to use the NULL pointer as replacement for the value of 0?
Or is there anything wrong about that doing?
Like, for example:
int i = NULL;
as replacement for:
int i = 0;
As experiment I compiled the following code:
#include <stdio.h>
int main(void)
{
int i = NULL;
printf("%d",i);
return 0;
}
Output:
0
Indeed it gives me this warning, which is completely correct on its own:
warning: initialization makes integer from pointer without a cast [-Wint-conversion]
but the result is still equivalent.
Am I crossing into "Undefined Behavior" with this?
Is it permissible to utilize NULL in this way?
Is there anything wrong with using NULL as a numerical value in arithmetical expressions?
And what is the result and behavior in C++ for this case?
I have read the answers of What is the difference between NULL, '\0' and 0 about what the difference between NULL, \0 and 0 is, but I did not get the concise information from there, if it is quite permissible and also right to use NULL as value to operate with in assignments and other arithmetical operations.
Am I allowed to use the NULL pointer as replacement for the value of 0?
No, it is not safe to do so. NULL is a null-pointer constant, which could have type int, but which more typically has type void * (in C), or otherwise is not directly assignable to an int (in C++ >= 11). Both languages allow pointers to be converted to integers, but they do not provide for such conversions to be performed implicitly (though some compilers provide that as an extension). Moreover, although it is common for converting a null pointer to an integer to yield the value 0, the standard does not guarantee that. If you want a constant with type int and value 0 then spell it 0.
Am I might crossing into Undefined Behavior with this?
Yes, on any implementation where NULL expands to a value with type void * or any other not directly assignable to int. The standard does not define the behavior of your assignment on such an implementation, ergo its behavior is undefined.
is it permissible to operate with the NULL in that way?
It is poor style, and it will break on some systems and under some circumstances. Inasmuch as you appear to be using GCC, it would break in your own example if you compiled with the -Werror option.
Is there anything wrong about to use NULL as numerical value in arithmetical expressions?
Yes. It is not guaranteed to have a numerical value at all. If you mean 0 then write 0, which is not only well defined, but shorter and clearer.
And how is the result in C++ to that case?
The C++ language is stricter about conversions than is C and has different rules for NULL, but there, too, implementations may provide extensions. Again, if you mean 0 then that's what you should write.
NULL is some null pointer constant. In C it could be an integer constant expression with value 0 or such an expression cast to void*, with the latter more likely. Which means you can't assume to use NULL interchangeably with zero. For instance, in this code sample
char const* foo = "bar";
foo + 0;
Replacing 0 with NULL is not guaranteed to be a valid C program, because addition between two pointers (let alone of different pointer types) is not defined. It will cause a diagnostic to be issued due to a constraint violation. The operands for addition will not be valid.
As for C++, things are somewhat different. Lack of an implicit conversion from void* to other object types meant that NULL was historically defined as 0 in C++ code. In C++03, you could probably get away with it. But since C++11 it can legally be defined as the nullptr keyword. Now again producing an error, since std::nullptr_t may not be added to pointer types.
If NULL is defined as nullptr then even your experiment becomes invalid. There is no conversion from std::nullptr_t to an integer. That is why it is considered a safer null pointer constant.
Am I allowed to use the NULL pointer as a replacement for the value of 0?
int i = NULL;
The rules vary between languages and their versions. In some cases you can and in others, you can't. Regardless, you shouldn't. If you're lucky, your compiler will warn when you attempt it or even better, fail to compile.
In C++, prior to C++11 (quote from C++03):
[lib.support.types]
NULL is an implementation-defined C++ null pointer constant in this International Standard.
It makes little sense to use a null pointer constant as an integer. However...
[conv.ptr]
A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.
So, it would technically work even if it's nonsensical. Due to this technicality, you may encounter poorly written programs that abuse NULL.
Since C++11 (quote from latest draft):
[conv.ptr]
A null pointer constant is an integer literal ([lex.icon]) with value zero or a prvalue of type std​::​nullptr_­t.
A std​::​nullptr_­t is not convertible to an integer, so using NULL as integer would work only conditionally, depending on choices made by the language implementation.
P.S. nullptr is a prvalue of type std​::​nullptr_­t. Unless you need your program to compile in pre-C++11, you should always use nullptr instead of NULL.
C is a bit different (quotes from C11 draft N1548):
6.3.2.3 Language / Conversions / Other operands / Pointers
3 An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. ...
So, the case is similar to post C++11 i.e. the abuse of NULL works conditionally depending on choices made by the language implementation.
Yes, though depending on the implementation you may need a cast. But yes, it is 100% legitimate, otherwise.
Although it is really, really, really bad style (needless to say?).
NULL is, or was, actually not C++, it is C. The standard does however, like for many C legacies, have two clauses ([diff.null] and [support.types.nullptr]) which technically make NULL C++. It is an implementation-defined null-pointer constant. Therefore, even if it's bad style, it's technically as C++ as it can be.
As pointed out in the footnote, possible implementations could be 0 or 0L, but not (void*)0.
NULL could, of course (the standard doesn't explicitly say so, but it's pretty much the only choice remaining after 0 or 0L) be nullptr. That's almost never the case, but it is a legal possibility.
The warning that the compiler showed to you demonstrates that the compiler is in fact not compliant (unless you compiled in C mode). Because, well, according to the warning, it did convert a null pointer (not nullptr which would be of nullptr_t, which would be distinct), so apparently the definition of NULL is indeed (void*)0, which it may not be.
Either way, you have two possible legitimate (i.e. compiler not broken) cases. Either (the realistic case), NULL is something like 0 or 0L, then you have "zero or one" conversions to integer, and you are good to go.
Or NULL is indeed nullptr. In that case you have a distinct value that has guarantees about comparison as well as clearly-defined conversions from integers, but unluckily not to integers. It does, however, have a clearly-defined conversion to bool (resulting in false), and bool has a clearly-defined conversion to integer (resulting in 0).
Unluckily, that's two conversions, so it's not within "zero or one" as pointed out in [conv]. Thus, if your implementation defines NULL as nullptr, then you will have to add an explicit cast for your code to be correct.
From the C faq:
Q: If NULL and 0 are equivalent as null pointer constants, which should I use?
A: It is only in pointer contexts that NULL and 0 are equivalent. NULL should not be used when another kind of 0 is required, even though it might work, because doing so sends the wrong stylistic message. (Furthermore, ANSI allows the definition of NULL to be ((void *)0), which will not work at all in non-pointer contexts.) In particular, do not use NULL when the ASCII null character (NUL) is desired. Provide your own definition
http://c-faq.com/null/nullor0.html
Disclaimer: I don't know C++. My answer is not meant to be applied in the context of C++
'\0' is an int with value zero, just 100% exactly like 0.
for (int k = 10; k > '\0'; k--) /* void */;
for (int k = 10; k > 0; k--) /* void */;
In the context of pointers, 0 and NULL are 100% equivalent:
if (ptr) /* ... */;
if (ptr != NULL) /* ... */;
if (ptr != '\0') /* ... */;
if (ptr != 0) /* ... */;
are all 100% equivalent.
Note about ptr + NULL
The context of ptr + NULL is not that of pointers. There is no definition for the addition of pointers in the C language; pointers and integers can be added (or subtracted). In ptr + NULL if either ptr or NULL is a pointer, the other must be an integer, so ptr + NULL is effectively (int)ptr + NULL or ptr + (int)NULL and depending on the definitions of ptr and NULL several behaviours can be expected: it all working, warning for conversion between pointer and integer, failure to compile, ...
No, not anymore preferred to use NULL(old way of pointer initilization).
Since C++11:
The keyword nullptr denotes the pointer literal. It is a prvalue of type std::nullptr_t. There exist implicit conversions from nullptr to null pointer value of any pointer type and any pointer to member type. Similar conversions exist for any null pointer constant, which includes values of type std::nullptr_t as well as the macro NULL.
https://en.cppreference.com/w/cpp/language/nullptr
Actually, std::nullptr_t is the type of the null pointer literal, nullptr. It is a distinct type that is not itself a pointer type or a pointer to member type.
#include <cstddef>
#include <iostream>
void f(int* pi)
{
std::cout << "Pointer to integer overload\n";
}
void f(double* pd)
{
std::cout << "Pointer to double overload\n";
}
void f(std::nullptr_t nullp)
{
std::cout << "null pointer overload\n";
}
int main()
{
int* pi; double* pd;
f(pi);
f(pd);
f(nullptr); // would be ambiguous without void f(nullptr_t)
// f(0); // ambiguous call: all three functions are candidates
// f(NULL); // ambiguous if NULL is an integral null pointer constant
// (as is the case in most implementations)
}
Output:
Pointer to integer overload
Pointer to double overload
null pointer overload

Why can pointers be NULL

In C or C++, isn't NULL just the constant integer 0? Why are we allowed to assign some pointer to the value NULL if it a constant integer? Wouldn't a compiler say that the two types don't match?
The interpretation of the constant 0 depends on the context. If it's being used in a context where a number is required, it's the number zero. If it's being used in a context where a pointer is required, it's treated as a null pointer. So if you have the code:
int n = 0; // assigns zero
int *p = 0; // assigns null pointer
somefunc((char *)0); // passes null pointer to the function
In C, the macro NULL is permitted to expand into either an integer constant 0 or such a constant cast to void *. In C++ pre-11, it can expand into either an integer constant that evaluates to 0. In C++-11 it can expand into an integer literal with value 0 or a prvalue of type std::nullptr_t (e.g. nullptr).
See http://en.cppreference.com/w/cpp/types/NULL for the C++ description, http://en.cppreference.com/w/c/types/NULL for the C description.
There are two issues:
A type can have a "special", out-of-band, exceptional value. For example, floating-point numbers have the value NaN. And pointers have a special, not-a-valid-pointer value, the null pointer.
What's the name of the null pointer? In C, for better or worse, its name is 0. (It would avoid all kinds of confusion if its name were a separate keyword like null or nil, but that's not the way the language definition came out.)
But yes, you're right, the ability to assign the constant 0 to a pointer variable is a special case, enshrined in the language definition.
6.3.2.3 Pointers
...
3 An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.66) 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.
66) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.
C 2011 online draft
A literal 0 in a pointer context is treated specially by the compiler, and is understood to be the null pointer constant. In the context of your source code, it behaves like any other zero-valued expression.
However, once your code is translated to machine code, all occurrences of the null pointer constant will be replaced with whatever value the underlying platform uses to represent a well-defined invalid pointer value, whether that’s 0 or 0xFFFFFFFF or 0xDEADBEEF.

Assign integer literal to pointer?

This question might be too bad but I can take risk to post this question here to address my confusion.
Actually my question is that we can only assign address to pointer like :-
int *p,a;
p = &a; // OK
p = 1; // Error because you cannot assign integer literal to p*
But we can assign NULL to p like :
p = NULL;
Indeed, NULL is a macro which is value is 0 and before compiling this code by compiler it get replaced with 0 by prepocessor. So after replacement its look like
p = 0;
I know it means p is point to nothing but according to rule we can only assign address to pointer but 0 is an integer.
So this isn't break the rule ?
Thanks.
barak manos already pointed it out in his comment:
If you want to set a pointer to a literal value, you need to cast the literal value to the corresponding pointer type first.
NULL could just as well be defined as (void *) 0... which is implicitly convertible to any pointer type.
In either case, you end up with a pointer pointing to a literal address.
In no case, however, does your pointer point to memory containing a literal 4, though. This is, to my knowledge, not possible without assigning that literal value to an int first:
int i = 4;
int * p = &i;
No it does not break the rule. The integer constant 0 (and generally any constant expression evaluating to 0) is treated specially and it is allowed to assign such value to a pointer. It does not mean that you can assign any integer - just zero.
The current version of C++ introduces the new nullptr keyword which should be used instead.
you can directly set the address of a pointer in c:
char * p = reinterpret_cast<char *>( 0x0000ffff ) ;
Note that is not generally considered safe use of pointers for obvious reasons (can point anywhere in memory).
for more info see here and related question here
The reason for this is different in C from C++ IIRC. In C++ 0 is special literal that, by definition, can be interpreted as a null pointer of any pointer type; so in this case there is no cast from integer to pointer. To test this you can try doing this:
int i = 0;
int* p = i;
Which you will discover gives an error (See here for IDEOne example)
In fact literal 0 or any constant value that is zero is an exception. It could assign to a pointer and it means a NULL or nullptr. In reverse, any null pointer evaluates to 0.
Null does not point to any memory address location, its compiler's responsibility to handle it. It is null and null is nowhere in the memory. It points to nothing.

Null pointer in C++

When in C++ I declare a null pointer to be int* p=0, does that mean the zero is some special constant of integer pointer type, or does it mean that p is pointing to address 0x0?
Of course for that 0x0 would have to be an special address to which C++ never touches during allocation of variables/arrays.
The C++ standard defines that the integer constant 0 converts to a null pointer. This does not mean that null pointers point to address 0x0. It just means that the text '0' turns into a null pointer when converted to a pointer.
Of course, making null pointers have a representation other than 0x0 is rather complicated, so most compilers just let 0x0 be the null pointer address and make sure nothing is ever allocated at zero.
Note that using this zero-conversion is considered bad style. Use NULL (which is a preprocessor macro defined as 0, 0L, or some other zero integral constant), or, if your compiler is new enough to support it, nullptr.
It means that an integral constant expression with value zero has a special meaning in C++; it is called a null pointer constant. when you use such an expression to initialize a pointer with, or to assign to a pointer, the implementation ensures that the pointer contains the appropriately typed null pointer value. This is guaranteed to be a different value to any pointer pointing at a genuine object. It may or may not have a representation that is "zero".
ISO/IEC 14882:2011 4.10 [conv.ptr] / 1:
A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type.
It's a special value, which by the standard is guaranteed to never be equal to a pointer that is pointing to an object or a function. The address-of operator & will never yield the null pointer, nor will any successful dynamic memory allocations. You should not think of it as address 0, but rather as special value that indicates that the pointer is pointing nowhere. There is a macro NULL for this purpose, and the new idiom is nullptr.
It means that it's not pointing to anything.
The value of the pointer is just 0. It doesn't necessarily mean it points to address 0x0. The NULL macro, is just a 0 constant.
the pointer points to address 0. On most platforms that is very special, but you should use NULL, because it is not always 0 (but very often).
Yes. Zero is a special constant. In fact, it's the only integral constant which can be used, without using explicit cast, in such statements:
int *pi = 0; //ok
char *pc = 0; //ok
void *pv = 0; //ok
A *pa = 0; //ok
All would compile fine.
However, if you use this instead:
int *pi = 1; //error
char *pc = 2; //error
void *pv = 3; //error
A *pa = 4; //error
All would give compilation error.
In C++11, you should use nullptr, instead of 0, when you mean null pointer.
In your example 'p' is the address of an int. By setting p to 0 you're saying there is an int at address 0. The convention is that 0 is the "not a valid address address", but its just a convention.
In pratice address 0 is generally "unmapped" (that is there is no memory backing that address), so you will get a fault at that address. That's not true in some embedded systems, though.
You could just as well pick any random address (e.g. 0xffff7777 or any other value) as the "null" address, but you would be bucking convention and confusing a lot of folks that read your code. Zero is generally used because most languages have support for testing is-zero is-not-zero efficiently.
See this related question: Why is address zero used for the null pointer?