Как типы переменных влияют на арифметику указателей c, работающую в C? - PullRequest
2 голосов
/ 25 февраля 2020

У меня проблемы с пониманием арифметики указателя c.

Let int B=0, *p=&B, **V=&p и sizeof(int)=4, sizeof(*int)=8

Что делает инструкция (*V)[1]? Для меня то, что я вижу, это то, что (*V)[1] эквивалентно *(*V+1), поэтому, что должно произойти, мы разыменовываем V (который является указателем на указатель на int) и суммируем 1 к содержимому этой переменной, которая является адресом. Эта переменная является указателем, и мы предполагаем sizeof(*int)=8, поэтому теоретически мы должны суммировать 1 * sizeof(*int) (что равно 8) с любым адресом, хранящимся в указателе p, на который указывает указатель V.

Однако решение говорит о сумме 4 (1 + sizeof(int)). Это неправильно или я не так думаю?

Ответы [ 2 ]

2 голосов
/ 25 февраля 2020

Правильное решение, на которое вы ссылаетесь.

Выражение *V имеет тип int *, поэтому оно указывает на массив 1 или более int. Поэтому, поскольку он указывает на int, когда арифметика указателя c происходит, размер типа данных, на который он указывает (sizeof(int), т.е. 4), умножается на данное значение (1). Поэтому, если бы вы напечатали значения *V и *V + 1, вы бы увидели, что они отличаются на 4.

Однако существует проблема с (*V)[1], что эквивалентно *(*V + 1). Поскольку *V указывает на B, *V + 1 указывает на один элемент за B. Это допустимо, поскольку указатель может указывать на один элемент за концом массива (или, что то же самое, на один объект, который обрабатывается как массив размером 1). Однако не законно - разыменовать этот указатель. Это вызывает неопределенное поведение .

2 голосов
/ 25 февраля 2020

(*V)[1] действительно эквивалентно *(*V+1).

Поскольку V равно &p (при инициализации), *V равно p. Итак, у нас есть *(p+1).

Обратите внимание, что и *V, и p имеют тип int *. Они указывают на int, поэтому p+1 указывает на «следующий» int.

Так как p указывает на B (при инициализации), а B является единственным int, p+1 точек сразу после конца B (где было бы «следующее целое», если бы у нас был массив int вместо одного int).

This «Только после конца B» разрешено указатель, и это место, к которому ваш источник относится для решения, (*V)[1] эффективно добавляет четыре байта к местоположению, на которое указывает *V.

Однако, хотя разрешено ссылаться на один конец после B, стандарт C не определяет поведение попытки доступа к объекту там. (*V+1) является определенным указателем, но *(*V+1) не является определенным выражением для объекта в этом месте. Его поведение не определяется стандартом C.

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