Разыменование указателя на 2d массив

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

int array[2][2] = {{0,1},{0,1}}; 
int (*p)[2];
p = array;

p = address of a[0][0], p+1 = address of a[1][0], 
*p = address of a[0][0], (*p)+1 = the address of a[0][1];

Я понимаю, что p - это указатель на массив из двух целых чисел, а не указатель на целое число. Но если мы выведем значение p, это все равно будет адрес целого числа. Я хочу знать, что происходит под капотом? Является ли p указателем на массив указателей? Итак, мы должны разыменовать его дважды, чтобы получить значение целого числа, на которое он указывает?

Указатель на int,

int* p;

это переменная, хранящаяся в ячейке, которая содержит адрес другой переменной (int).

Когда мы разыменовываем его, мы получаем значение этой переменной. Как этот процесс работает именно с указателем на массив?

Что говорят ваши предупреждения о присваивании несовместимых типов указателей с p = array;? int (*p)[2]; будет правильно.

David C. Rankin 17.12.2020 04:49

хорошо, я только что исправил это

Heng Wei 17.12.2020 04:54

Есть две вещи, которые вам нужно помнить, когда речь заходит о массивах и их связи с указателями. Во-первых, массив сам по себе распадается на указатель на его первый элемент. Это означает, что array точно такое же, как &array[0]. Во-вторых, для любого массива или указателя array и индекса i выражение array[i] в точности равно *(array + i).

Some programmer dude 17.12.2020 04:56

2D-массив представляет собой массив 1D-массивов. p указывает на первый одномерный массив в array. Итак, p указывает на array[0], а p+1 указывает на array[1]. Напомним, что при доступе массив преобразуется в указатель на его первый элемент. Таким образом, *p будет указывать на первый элемент первой строки (это то же самое, что *(p+0), то же самое, что и p[0])

David C. Rankin 17.12.2020 04:59

А когда имеешь дело с массивами и указателями, я очень рекомендую рисовать их на бумаге. Используйте квадраты для одиночных переменных, прямоугольники для массивов (разделите, чтобы показать элементы) и стрелки для указателей. Обычно это помогает получить общее представление о вещах.

Some programmer dude 17.12.2020 05:00
p = address of a[0][0] Вместо этого должен быть адрес a[0] (да, адрес тот же, но тип другой). p+1 = address of a[1][0] Вместо этого должен быть адрес a[1]. *(p+1) = the address of a[0][1] Нет, это противоречит тому, что вы написали выше.
dxiv 17.12.2020 05:05

@dxiv Извините, опечатка

Heng Wei 17.12.2020 05:10
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
1
7
1 917
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

  1. Доступ к значению в массиве можно получить с помощью
    array[i] = *(array+i) (расширение [i]).

  2. Аналогично, (*p)[i] = *(*(p+i)). Итак, нам нужно дважды разыменовать значение, чтобы получить доступ к нему.

  3. Если вы хотите получить доступ, array[0][0], вы должны использовать *(*(p+0)+0) = **p;, Точно так же array[0][1] можно получить с помощью *(*(p+0)+1) = *((*p)+1);

  4. Обратите внимание, *p указывает на первую строку (хранит адрес array[0][0]), а *(p+1) указывает на вторую строку (хранит адрес array[1][0]).

Пожалуйста, проверьте приведенный ниже код:

#include <stdio.h>
int main()
{
    int array[2][2] = {{1, 2}, {3, 4}};
    int(*p)[2];
    p = array;


    printf("The address of array[0][0] is %p \n",&array[0][0]);
    printf("The address of *p is %p \n",*p);

    printf("The address of array[1][0] is %p \n",&array[1][0]);
    printf("The address of *(p+1) is %p \n",*(p+1));

    printf("The value of array[0][0] is %d \n",array[0][0]);
    printf("The value of **p is %d \n",**p);

    printf("The value of array[0][1] is %d \n",array[0][1]);
    printf("The value of *((*p)+1) is %d \n",*((*p)+1));


    return 0;
}

Результат:

The address of array[0][0] is 0x7fff6e8781a0 
The address of *p is 0x7fff6e8781a0 
The address of array[1][0] is 0x7fff6e8781a8 
The address of *(p+1) is 0x7fff6e8781a8 
The value of array[0][0] is 1 
The value of **p is 1 
The value of array[0][1] is 2 
The value of *((*p)+1) is 2 
Ответ принят как подходящий

Адрес массива совпадает с адресом его первого элемента.

Учитывая определение int array[2][2] = {{0,1},{0,1}};, компилятор упорядочивает некоторое место в памяти, чтобы оно содержало значения int 0, 1, 0 и 1. Предположим, что это место имеет адрес 1000, а значение int 0 хранится в байтах 1000-1003, 1 хранится в диапазоне от 1004 до 1007, 0 сохраняется в диапазоне от 1008 до 1011, а 1 сохраняется в диапазоне от 1012 до 1015.

Где в памяти начинается элемент array[0][0]? На месте 1000.

Где в памяти начинается массив array? На месте 1000.

Где в памяти начинается массив array[0]? На месте 1000.

Массив начинается в памяти в том же месте, где его первый элемент начинается в памяти. Кроме того, array[0], который сам по себе является массивом, начинается с позиции 1000.

Итак, после p = array;, p указывает на позицию 1000. И элемент array[0][0] также начинается с позиции 1000. Таким образом, когда вы печатаете p, как и в случае с printf("%p\n", (void *) p);, неудивительно, что вы получаете тот же результат, что и при печати адреса array[0][0], как с printf("%p\n", (void *) &array[0][0]);.

Массив автоматически преобразуется в адрес его первого элемента.

Далее рассмотрим *p. Тип p — это int (*)[2], указатель на массив из 2 int. Следовательно, *p — это массив из 2 int.

В частности, *p — это массив. Предположим, мы пытаемся напечатать его, передав его в качестве аргумента printf. Что происходит?

В C, когда массив используется в выражении, он автоматически преобразуется в адрес своего первого элемента (за исключением случаев, когда массив является операндом sizeof или унарным & или строковым литералом, используемым для инициализации массива). Итак, если вы используете *p в качестве аргумента для printf, изначально это означает array[0], но этот массив преобразуется в адрес своего первого аргумента. Таким образом, передача *p в качестве аргумента фактически передает &array[0][0] (или, что то же самое, &(*p)[0]).

Таким образом, printf("%p\n", (void *) *p); напечатает тот же адрес, что и printf("%p\n", (void *) &a[0][0]);.

Другие вопросы по теме