Вы уже приняли ответ (и это правильно, поскольку он подробно объясняет, что было не так). Я знаю это, потому что внес в это свой вклад: -)
Однако я также хотел бы предложить другой способ размещения ваших 2D-массивов. Выполнение этого как серии выделений означает, что вы несете ответственность за очистку отдельных выделений, когда вы закончите работу с массивом.
Хотя это можно сделать с помощью другой функции, в нее необходимо передать число строк, чтобы можно было правильно освободить каждое выделение строк перед освобождением выделения массива указателей.
Метод, который я использовал в прошлом, состоит в том, чтобы выделить один блок памяти, достаточно большой для обоих массивов указателей и для всех массивов строк, а затем помассировать его так, чтобы он выглядит как обычный 2D-массив (так что такие вещи, как array[row][col] = 7
все еще работают).
Код ниже делает это, и единственным требованием является то, что требования к выравниванию для int16_t
не являются более строгими, чем int16_t*
(это было бы редко, и вы могли бы обойти это, но, вероятно, в этом нет необходимости Подавляющее большинство сред):
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
void *create_2d_array(uint8_t num_rows, uint16_t num_cols, int clear_data) {
// Create a single block big enough for both level-1 pointer array
// and level-2 value array.
size_t totalMemSz =
(num_rows * sizeof(uint16_t*)) + // pointers.
(num_rows * num_cols * sizeof(uint16_t)); // values.
void *memBlock = clear_data ? calloc(totalMemSz, 1) : malloc(totalMemSz);
if (memBlock == NULL) return NULL;
// Populate the level-1 pointers to point at the level-2 rows.
for (size_t i = 0; i < num_rows; ++i) {
((int16_t**)memBlock)[i] = (int16_t*)(&(((char*)memBlock)[
num_rows * sizeof(uint16_t*) + // skip pointers.
i * num_cols * sizeof(uint16_t) // select row.
]));
}
return memBlock;
}
#include <stdio.h>
#include <stdbool.h>
void dumpArr(int16_t **addr, size_t num_rows, size_t num_cols) {
for (size_t i = 0; i < num_rows; ++i) {
printf("Pointer[%zd] = %p, data =", i, addr[i]);
for (size_t j = 0; j < num_cols; ++j) {
printf(" %2d", addr[i][j]);
}
putchar('\n');
}
}
int main() {
puts("Running ...");
int16_t **arr = create_2d_array(4, 7, true);
arr[0][0] = 1;
arr[1][2] = 42;
arr[3][6] = 77;
dumpArr(arr, 4, 7);
free(arr);
}
Этот код является полной тестовой программой для функции create_2d_array
, поэтому вы можете проверить ее, как пожелаете. Важно то, что когда вы закончите работу с 2D-массивом, вы просто отпускаете его с free(arr)
, а не выполняете какую-либо специальную обработку, зависящую от размера.
Пример выполнения кода в его текущем виде:
Running ...
Pointer[0] = 0x675440, data = 1 0 0 0 0 0 0
Pointer[1] = 0x67544e, data = 0 0 42 0 0 0 0
Pointer[2] = 0x67545c, data = 0 0 0 0 0 0 0
Pointer[3] = 0x67546a, data = 0 0 0 0 0 0 77