Что такое "-1 [p]", когда p указывает на индекс массива (из int)?

Сегодня я наткнулся на загадку С, которая принесла мне новый сюрприз.

Я не думал, что -1 [p] в приведенном ниже примере скомпилируется, но это произошло. На самом деле, х в конечном итоге будет -3.

    int x;
    int array[] = {1, 2, 3};
    int *p = &array[1];
    x = -1[p]

Я искал в интернете что-то вроде -1 [указатель], но ничего не смог найти. Ладно, мне трудно ввести правильный поисковый запрос. Кто знает, почему -1 [p] компилируется, а X становится -3?

+20
источник поделиться
5 ответов

Я человек, который сделал эту "загадку" (см. мой пост в Twitter)

Так! Что случилось с -1 [p]?

ISO C фактически определяет [] как симметричный, то есть x[y] совпадает с y[x], где x и y оба являются выражениями.

Наивно, мы можем прийти к выводу, что -1[p], следовательно, p[-1], и поэтому x = 1, Однако -1 на самом деле является оператором унарного минуса, примененного к константе 1, и унарный минус имеет более низкий приоритет, чем []

Итак, -1[p] - это -(p[1]), что приводит к -3.

Это также может привести к появлению в стиле фанк фрагментов, подобных этому:

sizeof(char)["abc"] /* yields 'b' */

+27
источник

Первое, что нужно выяснить, это приоритет. А именно [] имеет более высокий приоритет, чем унарные операторы, поэтому -1[p] равен -(1[p]), а не (-1)[p]. Итак, мы берем результат 1[p] и отрицаем его.

x[y] равен *(x+y), поэтому 1[p] равен *(1+p), что равно *(p+1), что равно p[1].

Итак, мы берем элемент один после того, где указывает p, то есть третий элемент в array, то есть 3, и затем отрицаем его, что дает нам -3.

+12
источник

В соответствии со стандартом C (6.5.2 операторы Postfix) оператор нижнего индекса определяется следующим образом:

postfix-expression [ expression ]

Поэтому перед квадратными скобками должно быть выражение с постфиксом.

В этом выражении высказывание

x = -1[p];

здесь используется постфиксное выражение 1 (то есть одновременно первичное выражение), постфиксное выражение 1[p] (то есть оператор индекса) и унарный оператор -. Учтите, что при Компилятор разбивает программу на токены, а целочисленные константы считаются токенами без минуса. минус - это отдельный токен.

Таким образом, утверждение может быть переписано как

x = -( 1[p] );

потому что выражение постфикса имеет более высокий приоритет, чем унарное выражение.

Давайте сначала рассмотрим подфиксное выражение postfix 1[p]

Согласно стандарту C (6.5.2.1 Массив подписки)

2 Постфиксное выражение, за которым следует выражение в квадратных скобках [] является подписанным обозначением элемента объекта массива. Определение индекса оператора [] заключается в том, что E1 [E2] идентичен (* ((E1) + (E2))). Из-за правил преобразования, которые применяются к бинарный оператор +, если E1 является объектом массива (эквивалентно указателю к начальному элементу объекта массива) и E2 является целым числом, E1 [E2] обозначает E2-й элемент E1 (считая с нуля).

Таким образом, это подвыражение оценивается как *( ( 1 ) + ( p ) ) и совпадает с *( ( p ) + ( 1 ) ).

Таким образом, приведенное выше утверждение

x = -1[p];

эквивалентно

x = -p[1];

и выдаст -3, потому что указатель p указывает на второй элемент массива из-за оператора

int *p = &array[1];

а затем выражение p[1] возвращает значение элемента после второго элемента массива. Затем применяется унарный оператор -.

+10
источник

Это

int array[] = {1, 2, 3};

выглядит как

array[0]   array[1]  array[2]
 --------------------------
|     1   |    2    |   3  | 
 --------------------------
 0x100     0x104     0x108   <-- lets assume 0x100 is base address of array
array

Дальше, когда тебе нравится

int *p = &array[1];

целочисленный указатель p указывает на адрес array[1], т.е. 0x104. Похоже,

array[0]   array[1]  array[2]
 --------------------------
|     1   |    2    |   3  | 
 --------------------------
 0x100     0x104     0x108   <-- lets assume 0x100 is base address of array
             |
            p holds 0x104

А когда тебе нравится

x = -1[p]

-1[p] эквивалентно -(1[p]), т.е. -(p[1]). это выглядит как

-(p[1]) ==> -(*(p + 1*4)) /* p holds points to array[1] i.e 0x104 */
        ==> -(*(0x104 + 4))
        ==> -(*(0x108)) ==> value at 0x108 is 3
        ==> prints -3
+6
источник

То, что здесь происходит, действительно интересно.

p [n] означает *(p+n). Вот почему вы видите 3, потому что "p" указывает на массив [1], который равен 2, а -p [1] интерпретируется как -(*(p+1)), который является -3.

+2
источник

Посмотрите другие вопросы по меткам или Задайте вопрос