C pointer math with structures

2019-01-27 04:20发布

问题:

Trying to learn pointer math better I wrote this code. The intention was to increment the pointer threw the structure and print it's members. I know how to print it's member easier ways but would really like to know how my pointer math is messed up. Thank you.

typedef struct{ 
  int num;
  int num2;
  char *string;
} astruct ;

int main (int argc, const char * argv[])
{
  astruct mystruct = { 1234, 4567,"aaaaaaa"};

  astruct *address;
  address = &mystruct;

  // this does print 1234
  printf("address 0x%x has value of:%i\n",address, *address); 
  address = address + sizeof(int);

  //this does NOT print 4567
  printf("address 0x%x has value of:%i\n",address, *address); 
  address = address + sizeof(int);

  //this crashes the program, I wanted to print aaaaaaaa
  printf("address 0x%x has value of:%s\n",address, **address); 

  return 0;
}

回答1:

Pointer arithmetic increments a pointer by the number of bytes pointed to. For example,

int a[2];
int *p = a;

assert( &a[0] == p )
assert( &a[1] == p + 1 )

Therefore, your line

address = address + sizeof(int);

actually changes address to address + sizeof(int) * sizeof(astruct) (using normal, not pointer arithmetic).

There is no guaranteed way to do what you are trying, because the compiler is allowed to introduce padding in a struct. Consider the struct

struct A {
    char a;
    int b;
};

The compiler will most likely give this struct the following layout:

+------------+-------------------+-------------+
| a (1 byte) | (3 bytes padding) | b (4 bytes) |
+------------+-------------------+-------------+

So you cannot get to b by taking the address of a struct instance and adding 1.

In your specific case, the compiler probably doesn't introduce padding, so you may be able to use these lines to update address:

address = (char *) address + sizeof(int); // OR...
address = (int *) address + 1;

Again, though, this depends entirely on the compiler laying out the struct the way you think it will, and any small change will probably break it, so you really shouldn't rely on this type of behavior.



回答2:

When you add to a pointer, you actually add n * sizeof(*ptr) bytes.

Hence on a 32 bit machine where your structure would take 12 bytes, adding sizeof(int) bytes would actually add 48 bytes to the pointer.

To point at num2 you would first have to cast address to a pointer to an integer:

int *iaddress = (int *)address;

and then add one to that to reach your 4567 value.



回答3:

The structures are designed to avoid such types of caluculation. Instead of iterating through memory, you can use mystruct.num, mystruct.num2 and mystruct.string. And still this will be a segfault since you do not allocate memory for 'aaaaaaa'.