[英]Initialize 2-D array of unknown size
我有一個二維字符數組,例如char aList[numStrings][maxLength]
。 理想情況下,在程序執行期間,我希望能夠修改aList的內容,即添加,修改或刪除條目。 由於aList可能會發生變化,因此我不想在每次更改后都重新編譯程序來修改aList。 因此,我想在程序結束時將aList寫入文本文件,然后在下一個程序運行開始時將其讀回到aList中。
但是,我不知道程序啟動時numStrings的值是什么。 (我沒有使用C99,所以我不能使用VLA,並且不能從外部文件中提取一些以前的字符串。)當然,我可以將numStrings設置為人為的高值,但這會很麻煩!
有沒有一種方法不知道numStrings的值來填充aList? 我不認為有(我已經看過相關問題),但是還有另一種方式來實現我所需要的嗎?
如果您確實希望能夠從網格的中間刪除項目(您的問題尚不清楚),則需要某種多重鏈接結構。 這些通常用於實現稀疏數組,因此您可能會發現一個預制數組。
我說的是這樣的:
+---+
| A |
+-|\+
| \
| \
| \
| \
| +----+----+----+
| | C0 | C1 | C2 | ...
| +--|-+----+--|-+
| | |
| | |
+-V--+ +--V-+ | +----+
| R0 |->|a0,0|-------+>|a0,3|--> ...
+----+ +--|-+ +--V-+----+
| R1 |-----+----->|a1,2|--> ...
+----+ | +--|-+
... V |
... V
...
其中A是對象的根節點,C是列指針的數組,R是行指針的數組,每個單元格沿其行和列指向它的下一個鄰居。 假定所有未明確表示的單元格都具有一些默認值(通常為NULL或0)。
這是一個簡單的主意,但實現起來比較挑剔,有很多機會搞砸,因此,如果可以,請使用調試的庫。
您可以動態分配數組:
char **aList;
int i;
aList = malloc(sizeof(char *) * numStrings);
for (i = 0; i < numStrings; i++)
{
aList[i] = malloc(maxLength);
}
如果有機會可以使用C ++代替C,則可以始終使用C ++向量:
std::vector<std::vector<char> > aList;
您所描述的情況恰好是malloc
的用途-分配可變長度的內存塊。
如果計划在讀取文件時填充數據,則可以執行以下兩項操作之一。
要么將字符串數存儲為文件中的第一個元素,然后jgottula的建議就可以很好地工作。
還是必須使用數組? 您可以將它們直接讀到鏈接列表中,然后在閱讀完畢后將它們移到數組中,然后釋放鏈接列表。
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 ++會自動進行清除(例如,內存不足異常)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.