Код использует один непрерывный блок памяти для хранения двумерного массива.
char *data = (char *)malloc(rows*cols*sizeof(char));
ОК - эта строка выделяет пространство для всего двумерного массива. 2-D массив - это rows
строк по cols
столбцам. Таким образом, общее количество элементов составляет rows * cols
. Затем вы должны умножить это на количество места, занимаемого каждым элементом, которое составляет sizeof(char)
, так как это двумерный массив char
. Таким образом, общий объем выделяемой памяти равен rows * cols * sizeof(char)
, что действительно является аргументом для malloc
.
Вызов malloc
возвращает указатель на выделенную память. Поскольку эта память будет использоваться для хранения char
, вы возвращаете возвращаемое значение к char *
.
char **array= (char **)malloc(rows*sizeof(char*));
array
объявляется как тип "указатель на указатель на символ", потому что это то, что он собирается делать. Это укажет на память, которая будет держать указатели на символ. Это будет один указатель для каждой строки. Таким образом, вы должны выделить rows * sizeof(char *)
памяти: количество указателей, умноженное на размер указателя правильного типа. И так как это было выделено, чтобы указывать на указатели на char, мы возвращаем значение возврата к char **
.
for (int i=0; i<rows; i++)
array[i] = &(data[cols*i]);
Это магия :). Это устанавливает каждый указатель в array
так, чтобы он указывал на в блоке фактических данных, выделенных ранее. Рассмотрим конкретный пример, где rows
равно 2, а cols
равно 3. Тогда в памяти есть блок из 6 символов:
[0][1][2][3][4][5]
И data[n]
(для n
от 0
до 5
) - это n-й элемент, а &data[n]
- это * адрес для n-го элемента.
Итак, что делает этот цикл в этом случае:
array[0] = &data[0];
array[1] = &data[3];
Таким образом, array[0]
указывает на подблок, начинающийся с [0]
, и array[1]
указывает на подблок, начинающийся с [3]
. Затем, когда вы добавляете второй индекс, вы индексируете с начала этого указателя. Таким образом, array[0][2]
означает «получить указатель, сохраненный в array[0]
. Найдите то, на что он указывает, а затем продвиньтесь на 2 элемента оттуда.»
array[0]
указывает на [0][1][2]
(ну, фактически указывает на [0]
). Затем вы продвигаете два элемента вперед и получаете [2]
.
Или, если вы начинаете с array[1][1]
, array[1]
указывает на [3][4][5]
(и фактически указывает на [3]
. Переместите один элемент вперед и получите [4]
.