至少有兩種方法可以在閱讀線條時構建表格。一個使用realloc()
的屬性,如果它的第一個參數是空指針,它的行爲將類似於malloc()
並分配請求的空間(因此代碼可以自啓動,單獨使用realloc()
)。該代碼可能看起來像:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { LEN = 1024*8 };
static void error(const char *fmt, ...);
static char *xstrdup(const char *str);
int main(void)
{
char line[LEN];
char **tab = NULL;
int tabsize = 0;
int lineno = 0;
while (fgets(line, sizeof(line), stdin) != 0)
{
if (lineno >= tabsize)
{
size_t newsize = (tabsize + 2) * 2;
char **newtab = realloc(tab, newsize * sizeof(*newtab));
if (newtab == 0)
error("Failed to allocate %zu bytes of memory\n", newsize * sizeof(*newtab));
tab = newtab;
tabsize = newsize;
}
tab[lineno++] = xstrdup(line);
}
/* Process the lines */
for (int i = 0; i < lineno; i++)
printf("%d: %s", i+1, tab[i]);
/* Release the lines */
for (int i = 0; i < lineno; i++)
free(tab[i]);
free(tab);
return(0);
}
static void error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(1);
}
static char *xstrdup(const char *str)
{
size_t len = strlen(str) + 1;
char *copy = malloc(len);
if (copy == 0)
error("Failed to allocate %zu bytes of memory\n", len);
memmove(copy, str, len);
return(copy);
}
替代使用malloc()
時明確表是空的,而最簡單的編碼爲:
int main(void)
{
char line[LEN];
int tabsize = 4;
int lineno = 0;
char **tab = malloc(tabsize * sizeof(*tab));
if (tab == 0)
error("Failed to allocate %zu bytes of memory\n", tabsize * sizeof(*tab));
...
事都可以保持不變。
注意,它可以方便的功能xmalloc()
和xrealloc()
這是從來沒有保證返回一個空指針,因爲他們的報告,而不是一個錯誤:
static void *xmalloc(size_t nbytes)
{
void *space = malloc(nbytes);
if (space == 0)
error("Failed to allocate %zu bytes of memory\n", nbytes);
return(space);
}
static void *xrealloc(void *buffer, size_t nbytes)
{
void *space = realloc(buffer, nbytes);
if (space == 0)
error("Failed to reallocate %zu bytes of memory\n", nbytes);
return(space);
}
在長期(大項目),這削減低於您寫出「內存不足」錯誤消息的總次數。另一方面,如果你必須從內存分配失敗中恢復(保存用戶的工作等),那麼這不是一個合適的策略。
上面的代碼創建了一個不齊整的數組; tab
中的不同條目具有不同的長度。如果您想要均勻長度(如原始代碼中那樣),則必須替換或修改xstrdup()
函數以分配最大長度。
您可能已經注意到xstrdup()
中的代碼使用了memmove()
而不是strcpy()
。這是因爲strlen()
已經測量了字符串的長度,因此不需要複製代碼來測試每個字節以查看是否需要複製。我使用了memmove()
,因爲它即使在字符串重疊的情況下也不會出錯,即使在這種情況下,很明顯字符串永遠不會重疊,因此如果字符串重疊,則不能保證正常工作 - 可能已被使用因爲字符串不能重疊。
分配(oldsize + 2) * 2
新條目的策略意味着內存重新分配代碼在測試過程中經常執行得足夠多,而不會不當地影響生產性能。參見Kernighan和Pike的The Practice of Programming討論爲什麼這是一個好主意。
我幾乎總是使用一組類似於error()
函數的函數,因爲它大大簡化了錯誤報告。我通常使用的功能是記錄和報告程序名稱(來自argv[0]
)的軟件包的一部分,並且具有相當廣泛的替代行爲。
count_lineMax爲零,因此您不分配任何東西。 –
看起來不錯;即使在設置count_lineMax時也適用於我。說了你可以分配一個塊。 – Keith
由於您正在分配0字節而不檢查(malloc將每次返回null),您正在收到seg錯誤。如果你真的想要一個二維數組,你可以在一行中一次分配整個塊。如果你想要一個可變長度的C字符串數組(這看起來像你想要的),你需要malloc第一個列表,使用lineMax> 0,然後在每個元素上分配足夠的空間來獲得可變長度在該位置的C字符串(不要忘記爲'\ 0'包含一個額外的字符) –