Страницы

Поиск по вопросам

среда, 10 июля 2019 г.

Имена массивов в си и арифметика указателей

В этой статье автор пытается рассказать о том, чем являются имена массивов в Си. Он показывает, что a и &a имеют одно и то же числовое значение, то разные типы. Имя a является указателем на первый элемент массива и имеет тип int *, а &a - то же самое, что &a[0], и является указателем на массив из трех чисел.
Пример в конце статьи:
preserve do :escaped (gdb) print a + 1 $10 = (int *) 0x7fff5fbff570 (gdb) print &a + 1 $11 = (int (*)[3]) 0x7fff5fbff578
И цитата автора: Note that adding 1 to a adds four to a’s address, whereas adding 1 to &a adds twelve!
Почему здесь написано, что к &a прибавляется 12, когда по логу видно, что прибавляется 8? Почему прибавление единицы к &a инкрементирует значение гораздо больше, чем прибавление единицы к a? Что это за игра с типами такая?


Ответ

По поводу первого вопроса
Почему здесь написано, что к &a прибавляется 12, когда по логу видно, что прибавляется 8?
Стоит обратить внимание, что в логе отображены результаты сложения, и между ними разница действительно 8 и это вводит в заблуждение. Но, чтобы узнать сколько прибавилось, нужно смотреть на начальный адрес
= preserve do :escaped (gdb) x/4xb a 0x7fff5fbff56c: 0x01 0x00 0x00 0x00 (gdb) x/4xb &a 0x7fff5fbff56c: 0x01 0x00 0x00 0x00
И если смотреть разницу относительно него, то можно увидеть, что в первом случае она равно 4, а во втором - 12 как и написано в статье.
Что касается второго вопроса
Почему прибавление единицы к &a инкрементирует значение гораздо больше, чем прибавление единицы к a? Что это за игра с типами такая?
то возможно поможет перевод аналогичного вопроса на английском
Имя массива обычно вычисляется как адрес первого элемента, так что array и &array имеют одинаковое значение (но разные типы, array+1 и &array+1 не будут равны, если длина массива больше одного элемента).
Есть два исключения из этого правила: когда имя массива является операндом sizeof или унарного & (address-of) имя указывает на сам массив, поэтому sizeof возвращает размер всего массива, а не размер указателя.
Для массива определенного как T array[size], array будет иметь тип T *. При инкрементировании его вы получите следующий элемент в массиве.
&array возвращает тот же адрес, но при этом тип указателя будет уже T(*)[size] - т.е. это указатель на весь массив, а не отдельный элемента. И когда вы увеличиваете этот указатель он добавляет размер всего массива, а не размер отдельного элемента.

Комментариев нет:

Отправить комментарий