int val{ 100 };
int* ptr1 = (int*)val;
int* ptr2 = ptr1 + 5;
std::cout << ptr2 << '\n' << (int)ptr2 << std::endl;
In this code example the result of (int*)val is 00000064, but I don't understand why. I also don't understand why (int)ptr2 is 120.
Analyzing line per line:
int* ptr1 = (int*)val;
Assign the decimal value 100 to the pointer ptr1;
int* ptr2 = ptr1 + 5;
This instuction invokes undefined behaviour, the algebric operation over pointer is allowed only in array context.
std::cout << ptr2 << '\n' << (int)ptr2 << std::endl;
This instruction can print everything due to the previous undefined behaviour.
The the result of (int*)val is 00000064 because is the representation of decimal value 100 in hexadecimal notation
Step by step:
int* ptr1 = (int*)val;
After executing this instruction ptr1 has decimal value 100 (00000064 in hexadecimal).
int* ptr2 = ptr1 + 5;
Now ptr2 has the same memory adress of ptr1, shifted by 5 units. It is shifted by 5 * (4 bytes) = 20 bytes. The memory address represented by ptr2 is (00000078)
This is the reason why (int)ptr2 is 120 (100 + 20).
Can this reasoning make sense?
Related
So I read online that if you have an array like
int arr[3] = {1,2,3}
I read that if you take (arr+n) any number n it will just add sizeof(n) to the address so if n is an integer(takes up 4 bytes) it will just add 4 right? But then I also experimented on my own and read some more stuff and found that
arr[i] = *(arr+i) for any i, which means it's not just adding the sizeof(i) so how exactly is this working?
Because obviously arr[0] == *(arr+0) and arr[1] == *(arr+1) so it's not just adding sizeof(the number) what is it doing?
I read that if you take (arr+n) any number n it will just add sizeof(n) to the address
This is wrong. When n is an int (or an integer literal of type int) then sizeof(n) is the same as sizeof(int) and that is a compile time constant. What actually happens is that first arr decays to a pointer to the first element of the array. Then sizeof(int) * n is added to the pointers value (because elements type is int):
1 2 3
^ ^
| |
arr arr+2
This is because each element in the array occupies sizeof(int) bytes and to get to memory address of the next element you have to add sizeof(int).
[...] and read some more stuff and found that arr[i] = *(arr+i)
This is correct. For c-ararys arr[i] is just shorthand way of writing *(arr+i).
When you write some_pointer + x then how much the pointer value is incremented depends on the type of the pointer. Consider this example:
#include <iostream>
int main(void) {
int * x = 0;
double * y = 0;
std::cout << x + 2 << "\n";
std::cout << y + 2 << "\n";
}
Possible output is
0x8
0x10
because x is incremented by 2* sizeof(int) while y is incremented by 2 * sizeof(double). Thats also the reason why you get different results here:
#include <iostream>
int main(void) {
int x[] = {1,2,3};
std::cout << &x + 1 <<"\n";
std::cout << &x[0] + 1;
}
However, note that you get different output with int* x = new int[3]{1,2,3}; because then x is just a int* that points to an array, it is not an array. This distinction between arrays and pointers to arrays causes much confusion. It is important to understand that arrays are not pointers, but they often do decay to pointers to their first element.
I am a c++ novice
After I calculated the pointer of the Player structure, the result was beyond my surprise
struct Player
{
const char* Name = "ab";
uintptr_t Health = 6;
uintptr_t Coins = 3;
} player;
std::cout << &player << std::endl; // 0100C000
uintptr_t* playerBaseAddress = (uintptr_t*)&player;
std::cout << playerBaseAddress << std::endl; // 0100C000
std::cout << (playerBaseAddress + 4) << std::endl; // 0100C010
0100C000+4 How do I get 0100C004 instead of 0100C010
Can someone explain that, please?
Like this
uintptr_t playerBaseAddress = (uintptr_t)&player;
In your version you have a pointer, so when you added 4 to your pointer the result was multiplied by the size of the object being pointed at. Clearly on your platform uintptr_t has size 4, so you got 0100C000 + 4*4 which is 0100C010.
This would also work
char* playerBaseAddress = (char*)&player;
because here the size of char is 1. so you get 0100C000 + 1*4 which equals 0100C004.
In pointer arithmetics, the sizes of the operations are multiplied by the pointed type's size.
This way it's easy to reference data right next to each other in memory.
For example:
int* ptr = new int[5];
ptr[3] = 4;
std::cout << *(ptr+3) << endl; // 4
delete[] ptr;
You could add four bytes to it by converting it to a pointer type which has the size of one byte, for example char*.
playerBaseAddress is of type uintptr_t* which is a pointer. Presumably uintptr_t takes 4 bytes in your environment. Now this piece
playerBaseAddress + 4
involves the pointer arithmetic: you move the pointer 4*sizeof(uintptr_t)=4*4=16 bytes forward. 16 in hex is 10. Hence your result.
Note that uintptr_t* playerBaseAddress = (uintptr_t*)&player; is UB anyway. I assume you meant uintptr_t playerBaseAddress = (uintptr_t)&player; instead.
Calculating the offset into a struct can be done by using offsetof, e.g.
#include <cstddef>
#include <iostream>
struct Player {
const char *name = "ab";
uintptr_t health = 6;
uintptr_t coins = 3;
};
int main()
{
size_t off = offsetof(Player, health);
std::cout << "off=" << off << '\n';
}
Will show 4 or 8, depending on the architecture and size of the structure's elements.
int firstvalue = 5, secondvalue = 15;
int * p1, * p2;
p1 = &firstvalue;
p2 = &secondvalue;
*p1 = 10; //line 1
*p2 = *p1; //line 2
p1 = p2; //line 3
*p1 = 20;
cout << "firstvalue is " << firstvalue << '\n';
cout << "secondvalue is " << secondvalue << '\n';
return 0;
My Analysis of this code:
p1 points to the first value and p2 points to the second value. Now, p1 points to value 10. My first question is :
Does this means that first value now stores 10. (line 1)
According to me, line 2 means that p2 and p1 point to the value stored at the address of the second value. AM I correct or wrong?
Lastly, I have no clue of line 3. So, need some help over there too.
Answer 1: p1 still points to firstValue, but the value of firstValue is now changed to 10
Answer 2: in line 2, secondValue is assigned the value of firstValue.
Answer 3: line 3 is assigning the pointer of secondValue to the p1, so any changes in *p1 will reflect in the changed value of secondValue.
Hope this helps.
Does this means that first value now stores 10. (line 1)
Yes.
line 2 means that p2 and p1 point to the value stored at the address of the second value.
No. It means that the value p2 points to gets a copy of the value that p1 points to. It is the equivalent of saying secondvalue = firstvalue; because p2 points to secondvalue and p1 points to firatvalue and the * in *p1 or *p2 in this context accesses the value the pointer points to.
I have no clue of line 3.
This says that p1 will now point at the same place that p2 points to. So both p1 and p2 point to secondvalue.
Forget syntax for a second and think about what those objects are.
A memory location has exactly two properties, location and content.
int firstvalue; reserves a memory location (its size does not matter here).
firstvalue = 5; stores a value there.
firstvalue is a label associated with the memory address, &firstvalue is that address.
A pointer is a variable containing an address, dereferencing with '*' gives you the content at that address.
So now
p1 = &firstvalue; //address of firstvalue stored in pointer p1
p2 = &secondvalue; // same thing for p2 and secondvalue
*p1 = 10; //line 1: value 10 to variable pointed to by p1 i.e. firstvalue
*p2 = *p1; //line 2: copy firstvalue to secondvalue
p1 = p2; //line 3: now both point to secondvalue
Ok?
Lets understand what is a pointer - Pointer is storage of address it does not store value itself in light of it lets analyze the code line by line
1) Line 1 - Defined two variables (space to hold value)
2) Line 2 - Defined two pointers (space to hold address)
3) Line 4 & 5 - assigned address of the variables to pointers p1 & p2 now p1 points to location where value 5 is stored and p2 points to a location where 15 is stored
4) Line 6 - Value 10 is stored at the location p1 is pointing this means value of the variable firstvalue is changed from 5 to 10
5) Line 7 - Value of the location pointed by p1 is copied to location pointed by p2. Now both firstvalue and secondvalue is same which is 10
6) Line 8 - Value of the p2 pointer (which is address of secondvalue variable) is assigned to p1. now p1 and p2 both points to secondvalue variable
7) Line 9 - Assigned value 20 to the location pointed by pointer p1 which is now secondvalue variable
Result - both output will show value 20 as both pointers are now pointing to secondvalue variable and it is update to 20 at Line number 9
There you go...
#include <iostream>
using namespace std;
int main()
{
int firstvalue = 5, secondvalue = 15;
int * p1, *p2;
p1 = &firstvalue;
p2 = &secondvalue;
cout << "firstvalue address: ," << &firstvalue << "p1 address: ," << p1 << "p1 Value " << *p1 << endl;
*p1 = 10; //line 1
*p2 = *p1; //line 2
cout << "p1 Value " << *p1 << "p2 Value " << *p2 << endl;
p1 = p2; //line 3
cout << "p1 address: ," << p1 << "p2 address: ," << p2 << endl;
*p1 = 20;
cout << "p1 value: " << *p1 << endl;
return 0;
}
output:
firstvalue address: 0115FA74,p1 address: 0115FA74,p1 Value 5
p1 Value 10, p2 Value 10
p1 address: 0115FA68,p2 address: 0115FA68
p1 value: 20
Sorry, but your analysis is incorrect.
Starting with the first part of your code
int firstvalue = 5, secondvalue = 15;
int * p1, * p2;
p1 = &firstvalue;
p2 = &secondvalue;
and your analysis of it
p1 points to the first value and p2 points to the second value.
Your analysis is roughly correct. I'll give a slightly more complete description.
p1 is a variable of type int * (i.r. a pointer to an int). The assignment p1 = &firstvalue assigns the value of p1 to be the address of the variable firstvalue. This is sometimes said to mean that the pointer p1 is assigned to point at firstvalue.
The same description applies to p2 and secondvalue.
Now, for the next statement
*p1 = 10; //line 1
and your analysis of it
Now, p1 points to value 10.
This is incorrect. p1 does not point to the value 10.
The statement, *p1 = 10 assigns the value 10 to the result of *p1. *p1 is a reference to whatever p1 points at, which (as per above) is firstvalue. Accordingly, the assignment *p1 = 10 has the effect of assigning firstvalue to the value 10.
This brings us to your first question (albeit one you wrote without a question mark).
Does this means that first value now stores 10. (line 1)
If by "first value" you mean "the variable named firstvalue", the answer here is "yes".
Now, we come to the next code statement
*p2 = *p1; //line 2
and your analysis
According to me, line 2 means that p2 and p1 point to the value stored at the address of the second value. AM I correct or wrong?
You are completely and utterly wrong here.
To better understand, let's break the statement into parts. *p1 obtains a reference to the variable pointed to by p1 - which is firstvalue (which has a value 10). *p2 obtains a reference to the variable pointed to by p2 - which is secondvalue. The assignment *p2 = *p1 therefore has the same effect as secondvalue = firstvalue.
p1 still points at (contains the address of) firstvalue. Similarly, p2 still points at secondvalue. Both variables firstvalue and secondvalue have the value 10.
Now we come to line 3
p1 = p2; //line 3
And your observation about it it
Lastly, I have no clue of line 3. So, need some help over there too.
Uh hu.
p2 is a pointer, and its value is &secondvalue - the address of secondvalue. The assignment p1 = p2 assign the value of p1 to equal the value of p2. This means that p1 and p2 both contain the value &secondvalue. (Or that both the pointers p1 and p2 point to secondvalue).
A consequence is that
*p1 = 20;
has the effect of assigning secondvalue to have the value 20. firstvalue is unaffected, and still contains the value 10.
In my book, it says Pointers are addresses and have a numerical value. You can print out the value of a pointer as cout << (unsigned long)(p)
Write code to compare p,p+1,q, and q+1. Explain the results, Im not sure what the book wants me to so here's what I have. Does anyone Know if I am doing this right
int num = 20;
double dbl = 20.0;
int *p = #
double *q = &dbl;
cout << (unsigned long)(q) << endl;
q = q + 1;
cout << (unsigned long)(q) << endl;
cout << (unsigned long)(p) << endl;
p = p + 1 ;
cout << (unsigned long)(p) << endl;
Assuming it's the pointer arithmetic you have problems with, let my try to to show how it's done in a more "graphical" way:
Lets say we have a pointer variable ptr which points to an array of integers, something like
int array[4] = { 1234, 5678, 9012, 3456 };
int* ptr = array; // Makes `ptr` point to the first element of `array`
In memory it looks something like
+------+------+------+------+
| 1234 | 5678 | 9012 | 3456 |
+------+------+------+------+
^ ^ ^ ^
| | | |
ptr ptr+1 ptr+2 ptr+3
The first is technically ptr+0
When adding one to a pointer, you go to the next element in the "array".
Perhaps now you start to see some similarities between pointer arithmetic and array indexing. And that is because there is a common thread here: For any pointer or array p and valid index i, the expression p[i] is exactly the same as *(p + i).
Using the knowledge that p[i] is equal to *(p + i) makes it easier to understand how an array can be used as a pointer to its first element. We start with a pointer to the first element of array (as defined above): &array[0]. This is equal to the expression &*(array + 0). The address-of (&) and dereference (*) operators cancel out each, leaving us with (array + 0). Adding zero to anything can be removed as well, so now we have (array). And finally we can remove the parentheses, leaving us with array. That means that &array[0] is equal to array.
You do it right, if you want to print the decimal representation of the addresses your pointers point to.
If you wonder, why the results are such, you need to learn pointer arithmetic. If you add 1 to any pointer, it's address will be increased by sizeof(<type>), where type is the type of the variable your pointer points to.
So that, if you have a pointer to int and increment it, the address will be increased by sizeof(int), which is, most likely, four.
This is probably a stupid question, but I don't understand why this works:
int** test = new int*[7];
int x = 7;
*(test+1) = &x;
cout << (**(test+1));
test is a pointer to a pointer right? The second pointer points to the array, right?
In my understand I would need to dereference the "test" pointer first to get to the pointer that has the array.
(*test) // Now I have int*
*((*test) + 1) // to access the first element.
Where is my faulty thinking?
int** test = new int*[7];
+------++------++------++------++------++------++------+
| int* || int* || int* || int* || int* || int* || int* |
+------++------++------++------++------++------++------+
is the equivalent of an array with int pointers:
int* test[0]
int* test[1]
...
int* test[6]
this
int x = 7;
*(test+1) = &x;
+------++------++------++------++------++------++------+
| int* || &x || int* || int* || int* || int* || int* |
+------++------++------++------++------++------++------+
is the same as
int x = 7;
test[1] = &x
so now one of the pointers in your original array is pointing the memory location of x
cout << (**(test+1));
is the same as
cout << *test[1]
which is the value of x (==7) and which both test[1] and &x point to.
Is your misunderstanding that you think you have created a pointer to an array of 7 int? You haven't. You actually have created an array of 7 pointers to int. So there is no "second pointer" here that would point to an array. There is just one pointer that points to the first of the 7 pointers (test).
And with *test you get that first pointer which you haven't initialized yet, though. If you would add 1 to that, you would add 1 to some random address. But if you add 1 to test you get a pointer that points to the second pointer of the array. And dererencing that you get that second pointer, which you did initialize.
What you describe would be achieved by a different syntax
typedef int array[7];
array* test = new int[1][7];
// Note: "test" is a pointer to an array of int.
// There are already 7 integers! You cannot make it
// point to an int somehow.
*(*test + 1) = 7;
int *p1 = *test
int i1 = *(p1 + 1); // i1 is 7, second element of the int[7]
delete[] test;
Without using the typedef, this looks like the following
int(*test)[7] = new int[1][7];
That is, you have created a one-element array, where the element-type of that is a 7-element array of int. new gives you a pointer back to that array. Note that the parenthesis is important: The * has less precedence than the [7], so otherwise this would be taken as an array of 7 pointer to integers.
Suppose that
test[0] = 0x12345678; // some pointer value
test[1] = 0x23456789; // some pointer value
*test = 0x12345678;
*test + 1 is now 0x12345678 + 1 = 0x12345679;
* or dereference operator has higher precedence than binary +). So the expression is evaluated in that order.
However what you wanted for is to get to test[0] = 0x23456789;
So the correct expression to get to test[1] = (*(test + 1))
In general arr[i] is *(arr + i)
EDIT 2:
given
int buf[10] = {0, 1, 2};
int *p = buf;
buf[0] == p[0] == *(p + 0) equal to 0.
Note that it is perfectly fine to use array access syntax with the lvalue expression p even if it is not an array type. In fact the expression buf[0] is internally translated by the compiler to *(buf + 0) as well.
The expression *(test + 1) is equivalent to test[1], so your code could be rewritten thus:
int** test = new int*[7];
int x = 7;
test[1] = &x;
cout << *test[1];
Since test[1] obviously points to x, *test[1] is 7.
Just to be clear, the expression **(test + 1) is simply equivalent to *(*(test + 1)), which is in turn equivalent to *test[1].