Разрешены ли отрицательные индексы массива в C? - PullRequest
99 голосов
/ 13 августа 2010

Я просто читал какой-то код и обнаружил, что человек использовал arr[-2] для доступа ко 2-му элементу перед arr, например:

|a|b|c|d|e|f|g|
       ^------------ arr[0]
         ^---------- arr[1]
   ^---------------- arr[-2]

Это разрешено?1007 * Я знаю, что arr[x] совпадает с *(arr + x).Так что arr[-2] - это *(arr - 2), что кажется нормальным.Что ты думаешь?

Ответы [ 7 ]

156 голосов
/ 13 августа 2010

Это правильно. От C99 §6.5.2.1 / 2:

Определение индекса оператор [] в том, что E1 [E2] идентично (* ((E1) + (E2))).

Там нет магии. Это эквивалентность 1-1. Как всегда при разыменовании указателя (*), вы должны быть уверены, что он указывает на действительный адрес.

62 голосов
/ 13 августа 2010

Это допустимо, только если arr - указатель, указывающий на второй элемент в массиве или более поздний элемент В противном случае это недопустимо, потому что вы будете обращаться к памяти за пределами массива. Так, например, это было бы неправильно:

int arr[10];

int x = arr[-2]; // invalid; out of range

Но это было бы хорошо:

int arr[10];
int* p = &arr[2];

int x = p[-2]; // valid:  accesses arr[0]

Однако необычно использовать отрицательный индекс.

10 голосов
/ 13 августа 2010

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

7 голосов
/ 11 октября 2010

Я не уверен, насколько это надежно, но я только что прочитал следующее предупреждение об отрицательных индексах массива в 64-битных системах (предположительно, LP64): http://www.devx.com/tips/Tip/41349

Автор, кажется, говорит, что32-битные индексы массива int с 64-битной адресацией могут привести к ошибочным вычислениям адресов, если только индекс массива явно не увеличен до 64 бит (например, с помощью преобразования ptrdiff_t).Я действительно видел ошибку такого рода с версией PowerPC gcc 4.1.0, но я не знаю, является ли это ошибкой компилятора (то есть должна работать в соответствии со стандартом C99) или правильным поведением (то есть для индекса необходимо преобразование до 64биты для правильного поведения)?

7 голосов
/ 13 августа 2010

Что, вероятно, было arr, указывающим на середину массива, поэтому arr[-2] указывает на что-то в исходном массиве, не выходя за пределы.

1 голос
/ 26 января 2017

О том, почему кто-то хочет использовать отрицательные индексы, я использовал их в двух контекстах:

  1. Имея таблицу комбинаторных чисел, которая говорит вам гребень [1] [- 1]= 0;вы всегда можете проверить индексы перед доступом к таблице, но таким образом код выглядит чище и выполняется быстрее.

  2. Помещение центинеля в начало таблицы.Например, вы хотите использовать что-то вроде

     while (x < a[i]) i--;
    

, но тогда вам также следует проверить, что i положительно.
Решение: сделайте так, чтобы a[-1] было-DBLE_MAX, так что x&lt;a[-1] всегда будет ложным.

1 голос
/ 05 мая 2016

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

Я помню Принципы разработки компилятора. Предположим, что a является массивом int, а размер int равен 2, & Base addressдля a это 1000.

Как будет работать a[5] ->

Base Address of your Array a + (index of array *size of(data type for array a))
Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010

Это объяснение также является причиной, по которой отрицательные индексы в массивах работают в C.

, т.е.если я получу доступ к a[-5], это даст мне

Base Address of your Array a + (index of array *size of(data type for array a))
Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990

Это вернет мне объект в местоположении 990. По этой логике мы можем получить доступ к отрицательным индексам в массиве в C.

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