Dereferencing a double-level pointer results in different behaviour from dereferencing a single-level pointer

StackOverflow https://stackoverflow.com/questions/16256158

Domanda

Version 1:

int* work(int** pointer, int offset)
{
    return *pointer + (offset/sizeof(int));
}

int main()
{
    int** pointer = (int**) 0x4df73c;
    int offset = 0xf4;

    int* healthLowestPointer = work(pointer, offset);

    while(true) {
        *healthLowestPointer = 1000;
        Sleep(250);
    }
}

Version 2:

int* work(int* pointer, int offset)
{
    return (int*) (*pointer + (offset/sizeof(int)));
}

int main()
{    
    int* pointer = (int*) 0x4df73c;
    int offset = 0xf4;

    int* healthLowestPointer = work(pointer, offset);

    while(true) {
        *healthLowestPointer = 1000;
        Sleep(250);
    }
}

Version 1 works correctly, but version 2 doesn't seem to. I don't understand why version 2 is broken. Isn't dereferencing a a double-level pointer the same thing as dereferencing a single-level pointer i.e. it grabs the value at the memory address the pointer contains?

How would I write a function that takes a n-level pointer as input, and returns a 1-level pointer by dereferencing the n-level pointer n-1 times?

È stato utile?

Soluzione

They are very different things. An int** is a pointer to a pointer to an int. If you dereference it, you get an int*. An int* is a pointer to an int. If you dereference it, you get an int.

In the first example, you pass an int** with value 0x4df73c as the first argument to work. You then dereference this, which should give you an int*. That is, 0x4df73c is the address of an address and doing *pointer has gotten you the second addess. You then do pointer arithmetic with this int* by adding (offset/sizeof(int)), which works out how many ints there are with offset bytes. So when you add this value, your int* will move along to point at the int at that offset. You then return this int* and all is well.

In the second example, you pass 0x4df73c as an int*. You then dereference it, which gives you an int. Now the + doesn't do pointer arithmetic - it does integer arithmetic. (offset/sizeof(int)) will still give you the number of ints in offset bytes, but the arithmetic won't do what you want. It won't increase the value of the int by the appropriate amount.

Let's say an int is 4 bytes on your machine. When you have an int* called p and you do p + 5, this doesn't just add 5 to the address in p. It adds 5 times the size of an int (20 bytes), so that it's now pointing at the 5th int. However, if you have an int called i and you do i + 5, this really does just add 5.

So that's your problem. When you add to the int, you're not doing the appropriate arithmetic. I imagine it would work if you change it to, assuming an int* and an int are the same size on your system (as you say they are):

return (int*) (*pointer + offset);

but I do not recommend this. Don't use an int as though it were a pointer. The cast to the (int*) involves a reinterpret_cast and is horrible. Stick to your first code.

Altri suggerimenti

Pointer arithmetic and integer arithmetic are not the same thing.

Ignoring the issue of whether writing to the locations you are using is valid, consider the result of these:

int i=5;
int j=i+1; // now j==6
int* pi = &i; // let's say pi is 0x1000
int* pj = &i+1 // now pj is 0x1000 + (sizeof int)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top