I want to know necessity of null check.
Sample code is following
#include <iostream>
bool twice( int* a )
{
if( a == nullptr )
{
std::cout << "null" << std::endl;
return true;
}
std::cout << *a << std::endl;
*a *= 2;
std::cout << *a << std::endl;
return false;
}
int main()
{
twice( nullptr );
int v = 16;
std::cout << v << std::endl;
twice( &v );
std::cout << v << std::endl;
}
This is output
null
16
16
32
32
I recognize that 'nullptr' is "the pointer that point out address zero of memory" or "Flag when reference of pointer variable is invalid".
Q1. address zero of memory is only one per real memory?
Q2. Can you reproduce "reference of pointer variable is invalid" on this code?
Q3. What kind of function does the pointer variable reference become invalid?
Sorry, my poor English.
I would recommend thinking about this in a different way. Rather thinking of a null pointer as "memory address zero," think of it as "this pointer does not actually point at anything."
With that mental model, there's a clearer reason why you need the null check. If you have a pointer that doesn't actually point at anything, then writing
*a *= 2;
is a meaningless operation - there is no thing being pointed at by a, so dereferencing a to get an integer and then doubling that integer isn't a well-defined operation.
Internally, on most systems, yes nullptr is implemented as "a pointer to memory address zero, which is considered invalid on most operating systems," but I don't think that sheds much light on why this code needs the null check.
Pointer is just the unsigned integer that points to memory address. ln some system having virtual memory, the first page of the memory will not be mapped to physical memory.so, when we are trying to read/write at null pointer address it causes segmentation fault/ page fault. However in some embedded devices we will not observe the segmentation fault issue as we could access the zero memory space
Irrespective of the os,To avoid application crash, adding null pointer check is good practice
Related
I am messing around a little with pointers. Please take a look at the following results (addresses).
1st code:
#include <iostream>
int main(){
int a = 5;
void* pointer = &a;
std::cout << a << std::endl << &a << std::endl;
std::cout << pointer << std::endl ;
std::cin.get();
}
Result:
2nd code:
#include <iostream>
int main(){
int a = 5;
void* pointer = &a;
std::cout << a << std::endl << &a << std::endl;
std::cout << &pointer << std::endl ;
std::cin.get();
}
Result:
Why does the address of the variable a change between the two codes?
In the first case, you never take the address of pointer, so pointer can be stored in a register, or even not at all. (Modern compilers are very clever, and modern machines have many registers.)
For instance, gcc 11 keeps the value in a register without optimization, and with -O2 it just inserts the address of a directly. (Assembly here, for the curious.)
In the second case, you do take the address of pointer, so it must be stored somewhere in memory.
This means that a might be stored in a different place in order to make room for it.
Also, some platforms randomize storage locations in order to make programs less hackable, so it's usually not a good idea to assume that things will have the same address in different "runs".
In the first code poiner stores the address of variable a, and by command.
std::cout<<pointer<<std::endl;
You print the address of a. That's it.
In the second code pointer also stores the address of variable a, but &pointer is the address of variable pointer. Try the following
#include <iostream>
int main(){
int a = 5;
void* pointer = &a;
void** pointer_to_pointer = &pointer;
std::cout << a << std::endl << &a << std::endl << pointer << std::endl;
std::cout << &pointer << std::endl << pointer_to_pointer;
std::cin.get();
}
The output for me is
5
0x7aba1bd92e94
0x7aba1bd92e94
0x7aba1bd92e98
0x7aba1bd92e98
It is very simple.
int a and void* pointer are two distinct variables or I better say memory locations on the stack. a holds a value like 5 in its location. pointer holds the address to a's memory location. pointer itself is stored in a different location and when you write std::cout << &pointer << std::endl; it will print the address of the pointer variable, not the contents of it which is a's address.
As a simplified example:
Consider 0x4 as the address of pointer itself and the value inside it is 0xC. This value points to a's location. In order to read the value of a(which is 5), you first have to go to 0x4 to read its content. Its content is 0xC and now you have successfully found out that a's location is 0xC. Then you have to go to 0xC and at that address, you will find the value 5.
You look at -> 0x4( content == 0xC ) -> 0xC( content == 5 ) -> done!
When you initialize a pointer with nothing(NULL), that element still has a memory address big enough for the initialising type of that pointer(4 bytes for int, 1 for char etc.) but why,since it's tehnically nothing, not even the value zero? I mean, NULL can't be a fixed value like 0 because zero still is considered a value, so it is something more than that?
Example:
#include <iostream>
int *a=NULL;
int main()
{
std::cout <<&a; //it will show the address in hexadecimal system;
return 0;
}
Your program does not answer the question you were asking. This program shows that, yes the pointer has an address, it needs one to store the value (the address it is pointing to). When you print the value you see that it is indeed nullptr (since this is C++ not C).
#include <iostream>
int *a= nullptr;
int main()
{
std::cout << &a << '\n'; // Will show the address OF THE POINTER in hexadecimal system;
std::cout << a << '\n'; // Will show the address at a is pointing to.
return 0;
}
Output:
0x601180
0
I'm pretty sure there's a duplicate, but I don't see any now. You confuse the meaning of operators * and & in different contexts.
Here, &p means "address of p". And what is p? p is a global variable of pointer type. It is perfectly valid to take address of any global variable.
So, to clear things up:
#include <iostream>
int *a=NULL;
int main()
{
std::cout << &a; //perfectly valid, address of p, type int** (pointer-to-pointer-to-int)
std::cout << a; //still valid, it gives address to where p is pointing, i.e. 0 (NULL)
std::cout << *a; //wrong, dereferencing an invalid address, there's no memory allocated
return 0;
}
You also seem to have few misconceptions about pointers:
"that element still has a memory address big enough for the initialising type of that pointer(4 bytes for int, 1 for char etc.)"
Not at all. Pointer is just a pointer. It doesn't care where does it point to. In fact, on lower levels it's just plain int. It can point to an array, to an element, to nothing at all or to some wild place where nothing was ever stored.
"NULL can't be a fixed value like 0 because zero still is considered a value, so it is something more than that?"
Again, pointer is just a pointer. Pointer doesn't know anything at all about value. Value may or may not exist, and the memory where pointer points to may or may not be valid. And in fact, NULL is defined to be exactly 0 (or nullptr in newer standards): https://en.cppreference.com/w/cpp/types/NULL
I have an assignment that were supposed to evaluate some pointer manipulation expressions and memory leak situations in C/C++. There's one I'm stuck with:
unsigned int* pInt = (unsigned int*) 0x403004;
Right off the bat this is suspicious to me, but in the assignment this line is theoretically working, however running the program I'm get segfault right at this line.
The question is: Is this right or even is possible or the professor is just fooling us telling this is right? I've seen some examples and questions with string "hex" to int, but nothing regarding "pure hex" to int or int*
unsigned int* pInt = (unsigned int*) 0x403004;
Two things are suspicious here:
Unless, you are writing some specialized Software like device drivers or OS, or you are in some embedded or special system where memory is fixed, seeing memory address hardcoded is certainly suspicious. Your program will (at best) fail if it tries to access memory it doesn't have the access rights to.
On the right hand side, the compiler first deduces the value 0x403004 as in int and will correctly convert it to a pointer. Thus, your Segfault is probably as a result of the first point.
unsigned int* pInt = (unsigned int*) 0x403004;
Possible?: yes (compiles, builds just fine)
Is it right?: depends on what for. Evidently it is useful for illustration in a classroom assignment.
Is it recommended? no. It will invoke undefined behavior. You are creating a variable that points to a location in memory that you may or may not have rights to. If you never use it, fine. But if you do use it, the results are indeterminate.
it works fine only if that number represents an already allocated memory
eg:
#include <iostream>
int main()
{
int i = 7;
std::cout << "i: " << i << std::endl; // 7
std::cout << "&i: " << &i << std::endl; // in my case: 0018FF44
unsigned int* ptr = (unsigned int*)0x0018FF44; // it's ok
/*
this is just for explaining because the address of i may differ at anytime the program
launches thus 0018FF44 will no longer be assigned to i and consequently segfault.
the right thing is to make pointer points always to whatever i may take as an address.
to do so:
*/
//int* ptr = (unsigned int*)&i; // not i but the address of i
(*ptr)++;
std::cout << i << std::endl; // 8
// above we changed i through pointer ptr
int* pRandom = (int*)0xAB2FC0DE0; // this causes me segfault
*pRandom = 5; // segfault
std::cout << "*pRandom: " << *pRandom << std::endl; // segfault
std::cout << std::endl;
return 0;
}
Wouldn't the highest pointer be the one which can't be incremented through pointer arithmetic?
#include <iostream>
int main()
{
// Find the largest pointer
int x = 0;
int* px = &x;
while ((px+1) != px)
++px;
std::cout << "The largest pointer is: " << px;
return 0;
}
yields
Timeout
As already mentioned, you've got an infinite loop because the condition can never be false.
That being said, what you're doing is undefined behaviour, illegal C++. Pointer arithmetic is only legal with pointers pointing to the same array (and a single object is treated as an array of one element) and right past the end of it. You can't expect a reasonable outcome of your program even if you fix the loop.
I suspect the value of std::numeric_limits<uintptr_t>::max() is the theoretical maximum value of pointer (converted to integer), but it might not be avaliable to your program. There are things such as virtual address space and segmented memory model to consider. Anyway, exact values of pointers (except for nullptr) is not something you should be concerned with. You get pointers by taking addresses of existing objects or by calling allocation functions and that's that.
N.B. I think you have a misconception that attempting to increment an integer type beyond its maximum value will just do nothing. That's incorrect - unsigned integers will wrap around to 0 and with signed integers you get undefined behaviour again (see signed integer overflow).
Hope that helps.
This will never be false and thus never quit
while ((px+1) != px)
Look at this program:
#include <iostream>
int main()
{
int *px = (int *) (~0);
std::cout << "Value: " << px;
++px;
std::cout << " Value: " << px << std::endl;
}
whose output is:
Value: 0xffffffffffffffff Value: 0x3
As you can see, when you increment a pointer that is at its maximum, it values is reseted and begins again
You might want to look for the largest pointer value that occurs before wrap-around, i.e.:
while (px+1 > px)
px++;
...which will not work, of course, without the proper casts:
while ((unsigned long long)(px + 1) > (unsigned long long)px)
px++;
#include <iostream>
int main()
{
int anything[] = {5};
int *something = new int;
*something = 5;
std::cout << &anything << "==" << &anything[0] << "==" << anything << std::endl;
std::cout << &something << "!=" << &something[0] << "==" << something << std::endl;
}
Why is the memory address in &something different from &something[0] and something? Although it is a dynamic allocation, I don't understand why the memory address is different. I tried it with more than one value; it's the same thing. Here I used one value for both for simplicity.
&something is the memory address of the pointer itself (hey, it needs to store that value somewhere!), while &something[0] is the address of the actual memory that is storing your stuff.
something is a pointer. &something is the address of that pointer. &something[0] is the address of the first element pointed to by the pointer, which is completely different from the address of the pointer. something is the value of the pointer, which is also the address of the element that is pointed to.
I'm sure this topic has been covered many times before, I hope I did it justice.