您的代碼具有若干不良做法,和幾個錯誤。進入循環之前,您不需要預先分配節點。您可以簡單地按需分配。有許多方法可以確保使用稱爲正向鏈接的技術將新分配的節點添加到列表的末尾。我會在一分鐘內達成。下面的列表是沒有特定的順序,不過我至少嘗試去解決它自上而下
主要:您readFile()
函數應該回它分配列表的頭部。如果你想以後加入這個其他一些列表,隨意,但功能應該與此開始:
struct unit* readFile(const char fileName[])
小:還要注意我們沒有修改文件名,所以沒有理由把它作爲可變的,因此它是非常量的。
主要:使用它檢查您的文件打開操作成功前:
fp = fopen(fileName, "r");
if (fp == NULL)
{
perror("Failed to open file.");
return NULL;
}
主要:對API使用正確類型的變量調用你的決策。功能getline()
,一個非標準擴展,是原型爲:
ssize_t getline(char ** , size_t * , FILE *)
它返回一個ssize_t
(一個「簽名」大小型),並採取了size_t*
用於第二參數。作爲第二個參數,您要傳遞一個int
變量的地址,即length
。這不能保證兩者是兼容的類型。通過聲明length
作爲正確的類型來解決這個問題。 size_t
size_t length = 0;
小:同樣的問題發生與返回值的類型的strlen()
,這也是size_t
,但將在一剎那間變得不重要的,你很快就會看到。
主要:您使用的getline()
除了第二個參數之前提到的幾乎正確。第一個循環的初始輸入是一個NULL
指針的地址和一個0值的length
。如果在前一個循環中已經分配的緩衝區足夠大,每次迭代都會被重用。不幸的是,讀取更短的行,然後更長,然後然後更短,並且然後更長將引入不需要的額外分配。事實上,您可以完全放棄您的malloc()
邏輯,只是使用getline()
來分配緩衝區,因爲它被記錄爲使用malloc()
兼容分配。因此,使用現有的邏輯(我們將在最後走了過來):
while (getline(&line, &length, fp) != -1)
{
// note: added to throw out empty lines
if (length > 0)
{
// note: added to null out trailing newline. see the
// documentation of getline() for more info.
if (line[length-1] == '\n')
line[length-1] = 0;
}
if (line[0] != 0)
{
// other code here
current->name = line;
}
else
{ // not using this. release it.
free(line);
}
// reset line and length for next iteration
line = NULL;
length = 0;
}
主要:您原來的算法從未free()
d行緩衝,一旦你用它做,從而引入一次性內存泄漏。使用上述替代方法,您無需擔心。
備用:最後,列表循環人口可以進行應用到目前爲止所討論的一切,並添加到其名爲前向鏈接技術更穩健。該技術使用指針指針pp
,該指針始終保存將接收下一個節點分配的指針地址。如果列表最初是空的(它是),它保存着head
指針的地址。每添加一個新節點pp
都會分配最後一個節點的next
成員的地址。當循環完成時(即使我沒有添加任何節點),我們通過設置*pp = NULL
來結束列表。
這是readFile
的最終代碼庫。我希望你覺得它很有用:
struct unit* readFile(char fileName[])
{
FILE * fp;
char *line = NULL;
size_t length = 0;
// used for populating the list
struct unit *head = NULL;
struct unit **pp = &head;
// open file
fp = fopen(fileName, "r");
if (fp == NULL)
{
perror("Failed to open file");
return NULL;
}
while (getline(&line, &length, fp) != -1)
{
// note: added to throw out empty lines
if (length > 0)
{
// note: added to null out trailing newline. see the
// documentation of getline() for more info.
if (line[length-1] == '\n')
line[length-1] = 0;
}
if (line[0] != 0)
{
// allocate new node
*pp = malloc(sizeof(**pp));
if (*pp != NULL)
{
(*pp)->name = line;
pp = &(*pp)->next;
}
else
{ // could not allocate a new node. uh oh.
perror("Failed to allocate new node");
free(line);
break;
}
}
else
{ // not using this. release it.
free(line);
}
// reset line and length for next iteration
line = NULL;
length = 0;
}
*pp = NULL;
return head;
}
我建議讓一個白板或一張紙,並繪製出來遵循你的邏輯。這會幫助你找到錯誤。 – jia103
[請不要在C中輸入malloc的結果](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) –
getline在哪裏定義? – Shmoopy