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;
}
Related
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
I am learning c++ and found POINTER is similar to an INTEGER, so I was curious if I could implement POINTER from LONG LONG, I know it's not a good idea though, but it will be fun to do so. Here my idea is to cast a pointer to int like data type (say xpointer), and then use xpointer to access and modify the content of address it contains if possible!
So in pursuit of doing it, I tried to store the POINTER in a LONG LONG type, but it overflowed, so rather got an error.
#include <iostream>
using namespace std;
int main()
{
int x = 1923;
long long xpointer;
xpointer = (int)&x;
cout << xpointer << endl;
return 0;
}
I know POINTER is too large to store in LONG LONG so got an error here, could you suggest me a way to achieve the goal?
Here is the error message for reference.
error: cast from pointer to smaller type 'int' loses information
xpointer = (int)&x;
^~~~~~~
1 error generated.
PS: Here I did a mistake in, casting x to int rather than long long so it overflowed, apart from it, how can I use xpointer to modify or retrieve data back, like what we do using a pointer variable if possible?
The essence of your problem is that your code is designed to shoot yourself in the foot, and you're misinterpreting the foot wound as a natural cause.
For example, in the environment you're compiling for, long long actually is large enough to store a pointer†, so there's no reason you couldn't write code like this:
int x = 1923;
long long xpointer;
xpointer = reinterpret_cast<long long>(&x); //Valid on a 64-bit x86 CPU compiled with GCC
cout << xpointer << endl;
return 0;
But your code is instead the equivalent of xpointer = reinterpret_cast<int>(&x);, which is not valid in your environment. int is not the same size as long long†, and if you're casting to the latter, you need an express cast to that type. Not to an intermediate type (int) that then gets implicitly expanded to the proper type (long long), which will instead cause a warning or error.
In the future, if you do intend to store a pointer as an integer, you should prefer std::intptr_t instead, as [iff that type is defined for your environment] it is guaranteed to be large enough to store a pointer as an integer.
int x = 1923;
intptr_t xpointer = reinterpret_cast<intptr_t>(&x); //Guaranteed to be valid if intptr_t is defined
cout << xpointer << endl;
return 0;
†Be aware that not all environments have the same sizes of integers (including int and long long) as GCC on a 64-bit x86 environment. In your case, that's 32-bits and 64-bits respectively, but those numbers, especially the former, may be different if you are instead compiling for a different environment.
If you then intend to actually use the pointer stored in xpointer to modify the data it points to, you need to then cast the pointer back. You cannot manipulate the data pointed to by xpointer without instructing the compiler to treat it as a pointer.
int x = 1923;
intptr_t xpointer = reinterpret_cast<intptr_t>(&x);
cout << xpointer << endl;
int* ptr = reinterpret_cast<int*>(xpointer); //Legal If-and-only-If xpointer has not been changed
*ptr = 2019;
cout << x << endl; //Should print "2019"
cout << *ptr << endl; //Should print "2019"
return 0;
Be warned though that if you attempt to perform any kind of arithmetic operation on the pointer itself, you'll quickly veer into Undefined Behavior territory, and the behavior of your program can no longer be guaranteed:
int x = 1923;
intptr_t xpointer = reinterpret_cast<intptr_t>(&x);
cout << xpointer << endl;
int* ptr = reinterpret_cast<int*>(xpointer); //Legal If-and-only-If xpointer has not been changed
*ptr = 2019;
cout << x << endl; //Should print "2019"
xpointer++;//Legal, but...
int* ptr2 = reinterpret_cast<int*>(xpointer);
*ptr2 = 2020; //This is now undefined behavior
cout << x << endl; //Legal on its own, but because of preceeding undefined behavior,
//this may not do what you expect.
return 0;
int is (in modern compilers) 32 bits. A pointer is 32 or 64 bits. Your compilation is probably with the 64 bit compiler, hence the error between int and int*.
Apart from that, C++ is a strongly typed language, or we could simply write it in assembly and forget about types.
int is not the same as a pointer, long long is not the same as a pointer. You would need ugly C style casts.
Suggestion, read a good book.
In standard C++, intptr_t is an integral type that is guaranteed to be large enough to hold a pointer. If you want to store an address in an integer, use that.
How is it possible that the value of *p and the value of DIM are different but the have the same address in memory?
const int DIM=9;
const int *p = &DIM;
* (int *) p = 18; //like const_cast
cout<< &DIM <<" "<< p << '\n';
cout << DIM << " " << *p << '\n';
You're changing the value of a const variable, which is undefined behavior. Literally anything could happen when you do this, including your program crashing, your computer exploding, ...
If a variable is supposed to change, don't make it const. The compiler is free to optimise away accesses to const variables, so even if you found a successful way to change the value in memory, your code might not even be accessing the original memory location.
It is a compiler optimization. Given that DIM is a constant, the compiler could have substituted its known value.
The code below does what you meant to do... as mentioned in other posts, if you mean to change the value of an variable, do not define it as const
#include <stdio.h>
int main()
{
int d= 9;
int *p_d=&d;
*p_d=18;
printf("d=%d\np_d=%d\n",d,*p_d);
return 0;
}
This code prints
d=18
p_d=18
I am busy learning about pointers and playing around a bit with different results.
While doing this I noticed that when I declare a variable and obtain its address, I get one value. But then when I declare a pointer that points to that variable, I get a different address for that same variable. And I also saw that this new address given to the variable was actually the address of the pointer itself(after checking). How can this be?
Just to be clear; I declared int a and then int *p to point to a. The address for a was 0x22ff2c (originally before declaring pointer), and the address for the pointer p was 0x22ff28. The new address for a after I declared the pointer was also 0x22ff28, the same as the address of the pointer itself.
I looked around on the net and here on SO to find some answers, but didn't really get what I needed. Here as some links which came close. This SO Link1 touches on the subject, but doesn't tell me what I don't already know. This other one SO Link2 seems similar to what I am asking, but it's way too advanced and makes my head spin.
A simple explanation would be appreciated as I am still very new to C++, thank you.
Code 1
int main()
{
int a = 1;
std::cout << "Address1: " << &a;
return 0;
}
output of code 1 ##
Address1: 0x22ff2c
code 2
int a = 1;
int *p;
p = &a;
std::cout << "Address1: " << p;
return 0;
output of code 2
Address1: 0x22ff28
code 3
int a = 1;
int *p;
p = &a;
std::cout << "Address1: " << p << "\n" << "Address2: " << &a;
return 0;
output of code 3
Address1: 0x22ff28
Address2: 0x22ff28
code 4
int a =1;
int *p;
p = &a;
std::cout << "Address1: " << &p;
output of code 4
Address1: 0x22ff28
Because &a == p. You are not printing the pointer's address. For that print &p instead of p. You will likely get a different address.
Try this :
#include <iostream>
int main() {
int a = 3 ;
int *p = &a ;
std::cout << &a << "\n" << p << "\n" << &p ;
return 0;
}
0x22ff28 is not address of the pointer but of the target the pointer is pointing to. Which is a. The address of the pointer is &p.
Here's part of what I think you're trying to ask: First a had address 0x22ff2c, then the program was changed to have variable p and after that a has a different address. Why?
The answer is, the compiler made different choices when building the second program than it did when build the first. After all, they're different programs.
The actual memory addresses used by two different programs (even if they are mostly similar) may be different for various reasons. They're not really comparable. (And when you get into more complex and less predictable situations, especially using dynamic allocation, then the memory addresses used by different invocations of the same program can be different.)
Now, for another part of your question:
The new address for "a" after I declared the pointer was also 0x22ff28, the same as the address of the pointer itself.
In the code you've shown, you're only ever examining the address that p contains, not the address that p itself lives at. If you try outputting &p then you'll see where it is and find that it is indeed different than &a.
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++;