С указатель математика со структурами - PullRequest
1 голос
/ 09 апреля 2011

Пытаясь лучше изучить математику указателя, я написал этот код.Намерение состояло в том, чтобы увеличить указатель бросить структуру и распечатать ее членов.Я знаю, как печатать его элементы проще, но очень хотел бы знать, как испортилась моя математика указателя.Спасибо.

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;
}

Ответы [ 3 ]

5 голосов
/ 09 апреля 2011

Арифметика указателя увеличивает указатель на количество байтов, на которое указывает.Например,

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

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

Следовательно, ваша строка

address = address + sizeof(int);

фактически изменит address на address + sizeof(int) * sizeof(astruct) (используя обычную арифметику без указателей).

Тамне гарантированный способ сделать то, что вы пытаетесь, потому что компилятору разрешено вводить заполнение в структуре.Рассмотрим структуру

struct A {
    char a;
    int b;
};

Компилятор, скорее всего, даст этой структуре следующий макет:

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

Таким образом, вы не можете добраться до b, взяв адрес экземпляра структуры идобавление 1.

В вашем конкретном случае компилятор , вероятно, не вводит заполнение, поэтому вы можете использовать эти строки для обновления address:

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

Опять же, это полностью зависит от того, как компилятор выложит структуру так, как вы думаете, и любое небольшое изменение, вероятно, сломает ее, так что вы действительно не должны полагаться на этот типповедение.

3 голосов
/ 09 апреля 2011

Когда вы добавляете к указателю, вы фактически добавляете n * sizeof(*ptr) байтов.

Следовательно, на 32-битной машине, где ваша структура будет занимать 12 байтов, добавление sizeof(int) байтов фактически добавит 48 байтовуказатель.

Чтобы указать на num2, вам сначала нужно привести адрес к указателю на целое число:

int *iaddress = (int *)address;

, а затем добавить один к этому кдостичь значения 4567.

0 голосов
/ 09 апреля 2011

Конструкции разработаны таким образом, чтобы избежать таких расчетов.Вместо перебора памяти вы можете использовать mystruct.num, mystruct.num2 и mystruct.string.И все же это будет ошибка, поскольку вы не выделяете память для «aaaaaaa».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...