Не могу точно понять указатели в 2d массиве - PullRequest
0 голосов
/ 20 февраля 2020

Я что-то сделал, посмотрев на inte rnet, но здесь чего-то не хватает, это мой код

void draw_way(int *arr,int lenght_row,int lenght_column) {
int s1 = 0, s2 = 0;
for (s1 = 0; s1 < lenght_row; s1++)
{
    for (s2 = 0; s2 < lenght_column; s2++) {
        if (*((arr + s1 * lenght_row) + s2) == 1)
        {
            printf("S");
        }
        else if (*((arr + s1 * lenght_row) + s2) == 2)
        {
            printf("G");
        }
        else if(*((arr + s1 * lenght_row) + s2) == 3)
        {
            printf("#");
        }
        else if (*((arr + s1 * lenght_row) + s2) == 4)
        {
            printf(".");
        }
    }
    printf("\n");
}

Это на самом деле печать лабиринта, но это не важно. Я хочу понять, почему я должен использовать *((arr + s1 * lenght_row) + s2), почему это не работает, если я использую *(*(arr+s1)+s2), что 'lenght_row' делает.

Ответы [ 4 ]

1 голос
/ 20 февраля 2020

Для любого массива или указателя arr и индекса i выражение *(arr + i) точно равно arr[i].

Если мы сделаем этот перевод для *(*(arr+s1)+s2), это будет (arr[s1])[s2] (или arr[s1][s2]). Поскольку arr не является указателем на указатель (или массив массивов), то arr[s1][s2] не имеет смысла.

Вместо этого вы как бы эмулируете двумерный массив (массив массивов), используя массив (на первый элемент которого указывает arr) и используйте arithmeti c для вычисления одного индекса в этом массиве.

Это очень распространено для динамически выделяемой памяти, где вместо использования неровный массив (с помощью указателей на указатели) вы используете одну смежную область или память.


Это может быть легче понять с помощью иллюстрации ...

Допустим, мы хочу 2d массив из 2 на 3 элемента. Мы можем создать его, используя динамическое выделение c в виде зубчатого массива:

int **arr;
arr = malloc(2 * sizeof *arr);  // First dimension
for (size_t i = 0; i < 2; ++i)
    arr[i] = malloc(3 * sizeof *arr[i]);  // Second dimension

Поскольку у нас есть несколько распределений, в массиве нет местоположения, за arr[0][2] может не следовать arr[1][0]. Локальность и наличие смежного 2d-массива может быть полезно для некоторых алгоритмов и вариантов использования.

Непрерывный 2d-массив будет массивом массивов, таких как

int arr[2][3];

, но это сложнее обрабатывать динамически, поэтому вместо этого мы выделяем одну непрерывную область памяти из 2 * 3 элементов:

int *arr;
arr = malloc(2 * 3 * sizeof *arr);

К сожалению, это не может быть проиндексировано таким же интуитивно понятным способом, как зубчатый массив или массив массивов (т.е. arr[0][1] не возможно). Но с некоторой умной арифметикой c это возможно: arr[row_index * row_length + column_index] будет похоже на arr[row_index][column_index] (для зубчатого массива или массива массивов).

1 голос
/ 20 февраля 2020

arr - это плоский массив, а не многомерный массив. Он эмулирует многомерный массив путем передачи размера сетки. Таким образом, если бы это было 5x2, то arr как плоский массив был бы длиной 10 целых, а не массивом из 5 строк другого массива из 2 столбцов.

Следовательно, для эмуляции он использует простую арифметику указателей c размеры r, c путем расчета индекса плоского массива

((arr + s1 * lenght_row) + s2)

0 голосов
/ 20 февраля 2020

если вы уменьшите количество паразитов, это будет легче понять: if (*(arr + s1 * lenght_row + s2) == 2)

2D-массив содержит c столбцов и r строк. Они хранятся в памяти непрерывно row0, затем row 1 them row2 ...

Таким образом, чтобы получить доступ к определенному элементу (строка, столбец), вам нужно умножить строку на 'r' (в каком количестве элементов мы имеем строка и добавить столбец.

0 голосов
/ 20 февраля 2020

Для начала выражение в выражениях if-else, подобных этому

if (*((arr + s1 * lenght_row) + s2) == 1)

, неверно. Должно быть

if (*((arr + s1 * lenght_column) + s2) == 1)

Параметр arr, объявленный как

int *arr

, имеет тип int *. Поэтому разыменовывая указатель, например *arr, вы получите объект типа int, для которого вы не можете применять оператор разыменования.

Так что это выражение

*(*(arr+s1)+s2)

неверно. Подвыражение *(arr+s1) имеет тип int. Таким образом, второе использование оператора * приводит к ошибке компиляции.

В показанной функции эмулируется двумерный массив с использованием указателя на одномерный массив. То есть одномерный массив логически разбивается на куски элементами length_column.

Вот демонстрационная программа.

#include <stdio.h>

#define ROW_LENGTH      2
#define COLUMN_LENGTH   3

void display( const int *arr, size_t row_length, size_t column_length )
{
    for ( size_t i = 0; i < row_length; i++ )
    {
        for ( size_t j = 0; j < column_length; j++ )
        {
            printf( "%d ", *( arr + i * column_length + j ) );
        }
        putchar( '\n' );
    }
}

int main(void) 
{
    int arr[ROW_LENGTH * COLUMN_LENGTH] = { 1, 2, 3, 4, 5, 6 };

    display( arr, ROW_LENGTH, COLUMN_LENGTH );

    return 0;
}

Его вывод

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