Использование указателя с массивом

avatar
Ashwin Karki
8 августа 2021 в 16:06
110
3
0

Я изучаю указатели в программировании на C. Фрагмент кода:

#include <stdio.h>
    int main()
    {
        int ary[4] = {1, 2, 3, 4};
        int *p = ary + 3;
        printf("%d\n", p[-2]);
    }

ary — это массив, и как *p указывает на ary+3, а на выходе получается 2. Как указатель обрабатывает значения массива? Я просмотрел https://www.geeksforgeeks.org/pointer-array-array-pointer/, но не нашел, как там указатель влияет на массив?

Источник
Weather Vane
8 августа 2021 в 16:11
3

Арифметика указателя работает аналогично индексации массива. Массив распадается на указатель, поэтому ary + 3 имеет то же значение, что и &ary[3].

Ashwin Karki
8 августа 2021 в 16:17
0

я попытался увидеть другой результат, изменив index. p[0] дает «4», а p[1],p[2] дает «0», как это видно?

Weather Vane
8 августа 2021 в 16:19
2

p[1] и p[2] индексируются за пределами последнего элемента исходного массива, что является неопределенным поведением, и найденные значения не имеют значения.

Andrew Henle
8 августа 2021 в 16:24
1

https://www.geeksforgeeks.org/pointer-array-array-pointer/ размещен очень плохой код. sizeof(p) = %lu имеет неопределенное поведение и абсолютно неправильно в 64-разрядных системах Windows, где size_t — 64-битное, а <longs> — 64-битное.

Ответы (3)

avatar
Shreekesh Murkar
8 августа 2021 в 16:17
4

Это очень легко понять.

Мы знаем, что arr — это массив, но ссылка arr всегда будет указывать на адрес начального элемента массива.

Итак, для приведенного выше примера. arr указывает на адрес arr[0] (значение 1). arr + 3 будет указывать на arr[3] (значение 4).

Это означает, что указатель p указывает на arr[3]. Теперь p[-2] переместит адрес указателя 2 назад и укажет на arr[1] (значение 2).

Следовательно, вывод 2 !

avatar
John Bode
8 августа 2021 в 18:11
1

The subscript expression a[i] is defined as *(a + i) - given an address a1, offset i elements (not bytes! - more on that below ) с этого адреса и разыменовать результат. ary[0] эквивалентно выражению *(ary + 0), которое эквивалентно *ary, ary[1] эквивалентно *(ary + 1) и т. д.

Выражение p[-2] эквивалентно *(p - 2); начиная с p == ary + 3, затем p - 2 == ary + 3 - 2 == ary + 1, который является адресом второго элемента ary. Таким образом, p[-2] == ary[1] == 2.

Арифметика указателя основана на размере типа, на который указывает указатель. Если p содержит адрес объекта типа T, то p + 1 дает адрес следующего объекта того типа. Например, задано

char  *cp = (char *)  0x1000;
short *sp = (short *) 0x1000;
long  *lp = (long *)  0x1000;

тогда имеем следующее:

Address    char            short          long
-------    +---+           +---+          +---+         
0x1000     |   | cp        |   | sp       |   | lp
           +---+           + - +          + - +
0x1001     |   | cp + 1    |   |          |   |
           +---+           +---+          + - +
0x1002     |   | cp + 2    |   | sp + 1   |   |
           +---+           + - +          + - +
0x1003     |   | cp + 3    |   |          |   |
           +---+           +---+          +---+
0x1004     |   | cp + 4    |   | sp + 2   |   | lp + 1
           +---+           + - +          + - +
            ...             ...            ...

  1. Массивы не являются указателями, однако если они не являются операндами операторов sizeof или унарных & или строковым литералом, используемым для инициализации массива символов в объявлении, выражение типа "N-элементный массив из T" будет преобразовано или "затухать" в выражение типа "указатель на T", а значением выражения будет адрес первый элемент массива.
avatar
alex01011
8 августа 2021 в 16:19
2

Синтаксис массива p[-2] эквивалентен *(p - 2), поскольку p указывает на ary + 3, который является четвертым элементом в вашем массиве, при уменьшении указателя на 2 будет напечатано 2.

p[0] напечатает значение, на которое указывает p, поскольку *(p + 0), любой другой положительный индекс приведет к доступу к массиву за пределами границ, которые не определены.