簡體   English   中英

初始化大小未知的二維數組

[英]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)。

這是一個簡單的主意,但實現起來比較挑剔,有很多機會搞砸,因此,如果可以,請使用調試的庫。

您可以使用動態分配的數組。 使用malloc()制作一個, realloc()更改一個的大小,完成后使用free() 但這已經被另一個答案所覆蓋。

另一種選擇是使用鏈表 這樣,你就不必realloc()你想擴展您的陣列每一次- realloc()可能相當昂貴,如果它有整個數組復制到新的位置。

您可以動態分配數組:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM