Что означает двойной указатель и malloc размера указателя типа даты - PullRequest
0 голосов
/ 07 января 2019
int **matrix, i, j;
matrix = malloc(5 * sizeof(int*));
*matrix = malloc(20 * sizeof(int));

Я просто не понимаю концепции двойных указателей и того, как это переводится в двумерный массив (если это правда) Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 07 января 2019

Здесь создается технически не двумерный массив, а массив указателей, каждый из которых будет содержать начальный адрес массива. Затем его можно проиндексировать, как если бы это был «настоящий» 2D-массив.

Эта строка создает массив из 5 указателей на int:

matrix = malloc(5 * sizeof(int*));

Следующая строка создает один массив 20 int:

*matrix = malloc(20 * sizeof(int));

Это, однако, не является полным с точки зрения двумерного массива, потому что была выделена только одна строка. Вам нужно перебрать все элементы, на которые указывает matrix, чтобы создать каждую строку:

int **matrix, i;

matrix = malloc(5 * sizeof(int*));
for (i=0; i<5; i++) {
    matrix[i] = malloc(20 * sizeof(int));
}

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

for (i=0; i<5; i++) {
    free(matrix[i]);
}
free(matrix);

Это несколько отличается от реального 2D-массива. Во-первых, в истинном двумерном массиве все элементы непрерывны в памяти, тогда как в этом случае массив указателей и каждый массив строк не совпадают.

Другое отличие состоит в том, что при передаче в функцию вы не можете передать ее так же, как при передаче реального 2D-массива.

Для простого одномерного массива, выделенного во время компиляции или динамически:

int a1[5];
int *a2 = malloc(5 * sizeof(int));

И то, и другое может быть передано такой функции:

void f(int *a);

Но в случае двумерного массива:

int a[5][20];

Это должно быть передано функции, подобной этой:

void f(int a[5][20]);

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

void f(int (*a)[20]);

Принимая во внимание, что динамический 2D-массив должен быть передан функции, подобной этой:

void f(int **a);
0 голосов
/ 07 января 2019

Некоторые картинки могут помочь.

Давайте начнем с matrix, который является указателем на указатель на int:

  int **
+--------+
| matrix |---???
+--------+

После первого звонка на malloc у вас есть следующее:

  int **        int *
+--------+    +-----------+
| matrix |--->| matrix[0] |
+--------+    +-----------+
              | matrix[1] |
              +-----------+
              | matrix[2] |
              +-----------+
              | matrix[3] |
              +-----------+
              | matrix[4] |
              +-----------+

Вы динамически распределяете пространство для 5 int * объектов, а matrix указывает на первый. После второго вызова malloc у вас есть это (выражение *matrix эквивалентно matrix[0] - подробнее об этом ниже):

  int **        int *            int
+--------+    +-----------+    +---------------+
| matrix |--->| matrix[0] |--->| matrix[0][0]  | 
+--------+    +-----------+    +---------------+
              | matrix[1] |    | matrix[0][1]  |
              +-----------+    +---------------+
              | matrix[2] |    | matrix[0][2]  |
              +-----------+    +---------------+
              | matrix[3] |           ...
              +-----------+    +---------------+
              | matrix[4] |    | matrix[0][19] |
              +-----------+    +---------------+

Вы динамически распределяете пространство для 20 int объектов, и matrix[0] указывает на первый.

Итак, вкратце - каждый matrix[i][j] является int. Каждый matrix[i] указывает на matrix[i][0], поэтому каждый matrix[i] должен быть указателем на int или int *. matrix указывает matrix[0], что означает matrix должен быть указатель на int * или int **.

Помните, что выражение индекса массива a[i] определено как *(a + i) - с учетом адреса a, смещение i элементов (не байтов!) Из этого адрес и почтение результат. Таким образом, *matrix эквивалентно *(matrix + 0), что эквивалентно matrix[0].

Теперь у вас есть , а не истинный 2D-массив - у вас есть последовательность указателей, каждый из которых может указывать на первую из последовательности int объектов (или ничего на все). «Строки» массива (скорее всего) не будут смежными в памяти. В истинном 2D-массиве все элементы массива будут смежными. Учитывая

int matrix[5][20];

элементы будут выглядеть так:

+---------------+
| matrix[0][0]  |
+---------------+
| matrix[0][1]  |
+---------------+
      ...
+---------------+
| matrix[0][19] |
+---------------+
| matrix[1][0]  |
+---------------+
| matrix[1][1]  |
+---------------+
       ...
+---------------+
| matrix[4][19] |
+---------------+

EDIT

Некоторые другие ключевые различия между указателем на указатель и двумерным массивом. Сначала предположим следующие определения:

int **ptr;
int matrix[ROWS][COLS];
  1. Выражение ptr имеет тип int **. Выражение matrix будет «затухать» от типа int [ROWS][COLS] до типа int (*)[COLS] (указатель на COLS -элементный массив int);

  2. sizeof ptr дает размер самого указателя (4, 8 или некоторое другое количество байтов). sizeof matrix дает размер всего массива в байтах (ROW * COLS * sizeof (int)).

  3. Выражения &matrix, matrix, &matrix[0] и &matrix[0][0] будут давать одно и то же значение (адрес первого элемента массива), хотя типы выражений будут разными - int (*)[ROWS][COLS], int (*)[COLS], int (*)[COLS] и int * соответственно. Выражения &ptr, ptr, &ptr[0] и &ptr[0][0] не будут все давать одинаковые значения - &ptr и &ptr[0][0] будут отличаться от ptr и &ptr[0], а типы выражения будут int ***, int **, int ** и int *.

0 голосов
/ 07 января 2019

Я думаю, вы хотите следующее:

int **matrix, i, j;
matrix = malloc(5 * sizeof(int*));
for (int i=0; i<5; i++)
    matrix[i] = malloc(20 * sizeof(int));

Здесь вы сначала выделяете массив указателей на строки. Затем вы выделяете память для каждой строки.

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