Pointer Maths
-
Folks, Quick question in relation to the Pointer Maths in this program below, The Output is as follows: 1, 2, 3 . . . . . . . . . 245026, 245027, 245028 246017, 246018, 246019 247010, 247011, 247012 248005, 248006, 248007 249002, 249003, 249004 The Last Record is : 245028 Using the MoveBack function I expected the output to be 248007, the record before the current record, however it seems we move back 12 blocks of memory to 245028 and not the 12bytes I expected. Can someone explain to me whats going on here and how I can modify the code to get 248007 from the function? Thanks In Advance
#include "stdafx.h"
#include <conio.h>typedef struct MyStruct{
int i;
int j;
int k;
} TheStruct;int MoveBack(int *iPos);
int main(int argc, char* argv[])
{
TheStruct ts[500];
int i = 0;for(i = 0; i < 500; i++) { ts\[i\].i = i \* i + 1; ts\[i\].j = i \* i + 2; ts\[i\].k = i \* i + 3; } for(i = 0; i < 500; i++) { printf("%ld, %ld, %ld \\r\\n" ,ts\[i\].i ,ts\[i\].j, ts\[i\].k); if(i == 499) { //Pointer - Move back to last record printf("The Last Record is : %ld" , MoveBack(&ts\[i\].k)); } } while(!getch()); return 0;
}
int MoveBack(int *iPos)
{
int *i = iPos - sizeof(TheStruct);
return *i;
} -
Folks, Quick question in relation to the Pointer Maths in this program below, The Output is as follows: 1, 2, 3 . . . . . . . . . 245026, 245027, 245028 246017, 246018, 246019 247010, 247011, 247012 248005, 248006, 248007 249002, 249003, 249004 The Last Record is : 245028 Using the MoveBack function I expected the output to be 248007, the record before the current record, however it seems we move back 12 blocks of memory to 245028 and not the 12bytes I expected. Can someone explain to me whats going on here and how I can modify the code to get 248007 from the function? Thanks In Advance
#include "stdafx.h"
#include <conio.h>typedef struct MyStruct{
int i;
int j;
int k;
} TheStruct;int MoveBack(int *iPos);
int main(int argc, char* argv[])
{
TheStruct ts[500];
int i = 0;for(i = 0; i < 500; i++) { ts\[i\].i = i \* i + 1; ts\[i\].j = i \* i + 2; ts\[i\].k = i \* i + 3; } for(i = 0; i < 500; i++) { printf("%ld, %ld, %ld \\r\\n" ,ts\[i\].i ,ts\[i\].j, ts\[i\].k); if(i == 499) { //Pointer - Move back to last record printf("The Last Record is : %ld" , MoveBack(&ts\[i\].k)); } } while(!getch()); return 0;
}
int MoveBack(int *iPos)
{
int *i = iPos - sizeof(TheStruct);
return *i;
}Adding or subtracting from a pointer will always be done in multiples of the size of the type pointed to. In this case, MoveBack subtracts 12 times the size of an int from the address, since i points to an int (or at least that's how you declared it). If you don't want that, you have to use
void*
rather thanint*
. That said, it's a horrible idea to cast a pointer into an array of some struct toint*
! Why don't you just pass a pointer to MyStruct instead? Also, it's an even worse idea to dereference an int pointer that in truth points to a struct. This may or may not work, depending on the compiler. And if you ever choose to modify your struct later, the code will likely break (provided it did actually work before).MyStruct* MoveBack(const MyStruct* p)
{
return p-1; // moves pointer to previous struct in array
}// to use it do this:
printf("The Last Record is : %ld" , MoveBack(&ts[i])->k);P.S.: Note that this solution a) makes the function independent of the definition of MyStruct b) gets rid of error prone type casts c) removes the need to use sizeof d) is actually shorter, to the point that you could inline it, or simply forgo the function alltogether (e. g., above you could write
(&ts[i]-1)->k
) P.P.S.: you could of course just usets[i-1].k
That would be technically equivalent to the code I suggested under d) abovemodified on Tuesday, July 12, 2011 9:59 AM
-
Folks, Quick question in relation to the Pointer Maths in this program below, The Output is as follows: 1, 2, 3 . . . . . . . . . 245026, 245027, 245028 246017, 246018, 246019 247010, 247011, 247012 248005, 248006, 248007 249002, 249003, 249004 The Last Record is : 245028 Using the MoveBack function I expected the output to be 248007, the record before the current record, however it seems we move back 12 blocks of memory to 245028 and not the 12bytes I expected. Can someone explain to me whats going on here and how I can modify the code to get 248007 from the function? Thanks In Advance
#include "stdafx.h"
#include <conio.h>typedef struct MyStruct{
int i;
int j;
int k;
} TheStruct;int MoveBack(int *iPos);
int main(int argc, char* argv[])
{
TheStruct ts[500];
int i = 0;for(i = 0; i < 500; i++) { ts\[i\].i = i \* i + 1; ts\[i\].j = i \* i + 2; ts\[i\].k = i \* i + 3; } for(i = 0; i < 500; i++) { printf("%ld, %ld, %ld \\r\\n" ,ts\[i\].i ,ts\[i\].j, ts\[i\].k); if(i == 499) { //Pointer - Move back to last record printf("The Last Record is : %ld" , MoveBack(&ts\[i\].k)); } } while(!getch()); return 0;
}
int MoveBack(int *iPos)
{
int *i = iPos - sizeof(TheStruct);
return *i;
}When using sizeof with a structure it is not guaranteed that you get the sum of the single components due to Structure padding (wiki for it). Just printf the sizeof() of your struct and you will see that its not 12 Bytes. Anyway it is very unclear to me why are you even trying to do it this way. Dont mess with addresses and pointers in such an unsafe way. Who even tells you that you could just decrease the given int pointer and it would still point to a valid adress. E.g. just use the indices of the array to get the last element.
-
Adding or subtracting from a pointer will always be done in multiples of the size of the type pointed to. In this case, MoveBack subtracts 12 times the size of an int from the address, since i points to an int (or at least that's how you declared it). If you don't want that, you have to use
void*
rather thanint*
. That said, it's a horrible idea to cast a pointer into an array of some struct toint*
! Why don't you just pass a pointer to MyStruct instead? Also, it's an even worse idea to dereference an int pointer that in truth points to a struct. This may or may not work, depending on the compiler. And if you ever choose to modify your struct later, the code will likely break (provided it did actually work before).MyStruct* MoveBack(const MyStruct* p)
{
return p-1; // moves pointer to previous struct in array
}// to use it do this:
printf("The Last Record is : %ld" , MoveBack(&ts[i])->k);P.S.: Note that this solution a) makes the function independent of the definition of MyStruct b) gets rid of error prone type casts c) removes the need to use sizeof d) is actually shorter, to the point that you could inline it, or simply forgo the function alltogether (e. g., above you could write
(&ts[i]-1)->k
) P.P.S.: you could of course just usets[i-1].k
That would be technically equivalent to the code I suggested under d) abovemodified on Tuesday, July 12, 2011 9:59 AM
-
You can't. Not inside
MoveBack()
anyway. Which is yet another good argument not to meddle with pointers recklessly. The only way to ensure a pointer is inside the scope of an array is to compare it to the start address, and only the function that defined the array knows it. So if you really wanted a 'safe' MoveBack function, you'd have to add a parameter, like this:MyStruct* MoveBack_s(const MyStruct* p, const MyStruct* parray)
{
MyStruct* result = 0;
if (p > parray)
result = p-1;
return result;
}Of course, even this function is not safe if you pass it a pointer to the start of a different array... The only way to be truly safe is not to use pointers, but iterators, such as those used for the STL class vector. They contain references to the container they refer to and therefore can check their boundaries themselves.
-
When using sizeof with a structure it is not guaranteed that you get the sum of the single components due to Structure padding (wiki for it). Just printf the sizeof() of your struct and you will see that its not 12 Bytes. Anyway it is very unclear to me why are you even trying to do it this way. Dont mess with addresses and pointers in such an unsafe way. Who even tells you that you could just decrease the given int pointer and it would still point to a valid adress. E.g. just use the indices of the array to get the last element.
-
When using sizeof with a structure it is not guaranteed that you get the sum of the single components due to Structure padding (wiki for it). Just printf the sizeof() of your struct and you will see that its not 12 Bytes. Anyway it is very unclear to me why are you even trying to do it this way. Dont mess with addresses and pointers in such an unsafe way. Who even tells you that you could just decrease the given int pointer and it would still point to a valid adress. E.g. just use the indices of the array to get the last element.
-
When using sizeof with a structure it is not guaranteed that you get the sum of the single components due to Structure padding (wiki for it). Just printf the sizeof() of your struct and you will see that its not 12 Bytes. Anyway it is very unclear to me why are you even trying to do it this way. Dont mess with addresses and pointers in such an unsafe way. Who even tells you that you could just decrease the given int pointer and it would still point to a valid adress. E.g. just use the indices of the array to get the last element.
Legor wrote:
When using sizeof with a structure it is not guaranteed that you get the sum of the single components due to Structure padding
But it doesn't matter since you will always get the size of the actual structure as created by the compiler, so you can still use
sizeof
to increment avoid
pointer. However, as you rightly point out, that is a stupid way to do it since normal increment/decrement or indexing is the correct way.The best things in life are not things.