一般来说,二维 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++ 会自动进行清理(例如内存不足异常)。