Поддерживают ли указатели "индексацию стиля массива"?
(Ответы на свои вопросы - этот вопрос постоянно всплывает)
Я предполагаю, что читатель знает, как работает арифметика указателей.
int arr[3] = {1,2,3};
int* ptr = arr;
...
*(ptr + i) = value;
Книги Учителя / С продолжают говорить мне, что я не должен использовать *(ptr + i)
как в приведенном выше примере, потому что "указатели поддерживают индексирование стиля массива", и я должен использовать ptr[i] = value;
вместо. Там нет аргументов - гораздо легче читать.
Но, просматривая стандарт C, я не нахожу ничего, что называется "индексация в стиле массива". На самом деле, оператор []
не ожидает, что любой операнд будет массивом, но вместо этого указатель или целое число!
6.5.2.1 Массив подписки
Ограничения
Одно из выражений должно иметь тип "указатель на полный тип объекта", другое выражение должно иметь целочисленный тип, а результат имеет тип "тип".
Почему оператор подписки массива не ожидает массив? Стандарт не так? Моя книга учителя /C перепутана?
1 ответ
Вы действительно должны использовать ptr[i]
над *(ptr + i)
для удобства чтения. Но кроме этого, []
Оператор, строго говоря, фактически никогда не используется с операндом массива.
Массивы при использовании в выражении всегда "затухают" в указатель на первый элемент (за некоторыми исключениями). C17 6.3.2.1/3, упорная шахта:
За исключением случаев, когда это операнд оператора sizeof или унарный оператор &, или строковый литерал, используемый для инициализации массива, выражение с типом '' массив типа '' преобразуется в выражение с указателем типа '' набрать '', который указывает на начальный элемент объекта массива и не является lvalue.
Это означает, что всякий раз, когда вы печатаете arr[i]
операнд arr
заменяется указателем на первый элемент в этом массиве. Это неофициально называется "распадом массива". Больше информации здесь: Что такое распадающийся массив?
Поэтому всякий раз, когда вы используете []
оператор, вы используете его по указателю. Всегда.
Стандарт C говорит, что этот оператор гарантированно эквивалентен арифметике указателя (C17 6.5.2.1/2):
Определение подстрочного оператора
[]
в том, чтоE1[E2]
идентично(*((E1)+(E2)))
,
Поэтому всякий раз, когда мы печатаем arr[i]
, это на самом деле молча заменяется *(arr+i)
, куда arr
по-прежнему указатель на первый элемент.
И именно поэтому в приведенном вами описании говорится, что один из операндов может быть указателем, а другой - целым числом. Потому что, очевидно, не имеет значения, если мы введем *(arr+i)
или же *(i+arr)
- это эквивалентный код.
Что в свою очередь позволяет нам писать запутанный код "шутка", как i[arr]
, который на самом деле является действительным C и полностью эквивалентен arr[i]
, Но не пишите такой код в реальных приложениях.