2D-массивы в стиле C в общем, простите, выглядят странно ... они выглядят простыми и полезными на бумаге, но реализация динамического управления памятью - обработка ошибок выделения и очистки / изменения размеров - часто довольно сложна в деталях.
Что вы можете сделать, это что-то вроде:
/*
* Start with an array that can hold INITIAL_NUM elements of (char*).
*/
char **aList = (char**)malloc(INITIAL_NUM, sizeof(*aList));
int curIdx = 0, curListSz = INITIAL_NUM;
while (more_stuff_to_append) {
/*
* Still space in the existing list ? If not - resize
*/
if (curIdx >= INITIAL_NUM) {
curListSz += ALLOC_INCREMENT_FOR_ALIST;
if ((aList = realloc(aList, curListSz * sizeof(*aList))) == NULL)
error_and_yucky_cleanup("can't resize list, out of memory");
}
/*
* Allocate a new element.
* Note that if it's _known_ in advance that all elements
* are the same size, then malloc'ing a big block and slicing
* that into pieces is more efficient.
*/
if ((aList[curIdx] = malloc(new_elem_size, sizeof(char)) == NULL)
error_and_yucky_cleanup("out of memory");
/*
* put the contents into the new buffer, however that's done.
*/
populate_new_entry(aList[curIdx]);
curIdx++;
}
Большая проблема с этими подходами обычно состоит в том, что очистка грязная. Нужно пройти через массив и вызвать free () для каждого элемента, плюс дополнительный финальный элемент для очистки aList
.
Если вы заранее знаете все размеры, можно выделить один блок памяти, который содержит как aList
, так и все элементы. Это работает через что-то вроде:
#define LISTSZ(lst) (NUMSTRINGS_MAX * sizeof(*(lst)))
#define ELEMSZ(lst) (STRINGSIZE_MAX * sizeof(**(lst)))
char **aList = malloc(LISTSZ(aList) + NUMSTRINGS * ELEMSZ(aList));
char *curElem = ((char*)aList) + LISTSZ(aList));
int i;
for (i = 0; i < NUMSTRINGS_MAX; i++) {
aList[i] = curElem;
curElem += ELEMSZ(aList);
}
Преимущество этого в том, что очистка тривиальна - просто позвоните free((char*)aList);
, и все закончится. Но вы больше не можете realloc()
, так как это не вставит новый пробел в начале блока памяти (где хранится aList[]
).
Эти вещи являются действительно вескими причинами для использования векторов C ++; по крайней мере C ++ выполняет очистку (например, при исключениях нехватки памяти) автоматически.