С указатель математика со структурами
Пытаясь лучше изучить математику указателей, я написал этот код. Намерение состояло в том, чтобы увеличить указатель бросить структуру и распечатать ее членов. Я знаю, как печатать его элементы проще, но очень хотел бы знать, как испортилась моя математика указателя. Спасибо.
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 ответа
Арифметика указателя увеличивает указатель на количество байтов, на которое указывает. Например,
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;
Опять же, однако, это полностью зависит от того, как компилятор выложит структуру так, как вы думаете, и любые небольшие изменения, вероятно, сломают ее, так что вы действительно не должны полагаться на этот тип поведения.
Когда вы добавляете к указателю, вы фактически добавляете n * sizeof(*ptr)
байт.
Следовательно, на 32-битной машине, где ваша структура будет занимать 12 байтов, добавляя sizeof(int)
байты фактически добавили бы 48 байтов к указателю.
Указать на num2
сначала вы должны привести адрес к указателю на целое число:
int *iaddress = (int *)address;
и затем добавьте один к этому, чтобы достигнуть своего значения 4567.
Конструкции разработаны таким образом, чтобы избежать таких расчетов. Вместо того, чтобы перебирать память, вы можете использовать mystruct.num
, mystruct.num2
а также mystruct.string
, И все же это будет ошибка, так как вы не выделяете память для "aaaaaaa".