在方法结束时,我的所有测试printfs都会打印相同的结果。文件的最后一行。但是while循环中的当前printf工作正常。出于某种原因,我的节点具有相同的结果。我该如何解决? 这是我的结构单元:
struct unit
{
struct unit * next;
char *name;
};
这是我的链接列表逐行添加到链表的功能:
void readFile(char fileName[], struct unit * units)
{
FILE * fp;
char *line = NULL;
int length = 1000;
fp = fopen(fileName, "r");
int counter = 0;
int strLength = 0;
struct unit * current;
units = (struct units*)malloc(sizeof(struct unit));
current = units;
while ( getline(&line, &length, fp) != -1)
{
strLength = strlen(&line);
current->name = (char*)malloc(sizeof(char)* strLength);
current->next = (struct units*)malloc (sizeof(struct unit));
strcpy(¤t->name, &line);
printf("\nCurrent: %s",current->name);
current = current->next;
counter++;
}
printf("\nTest %s", units->name);
printf("\nTest %s", units->next->name);
printf("\nTest %s", units->next->next->name);
printf("\nTest %s", units->next->next->next->name);
}
答案 0 :(得分:1)
为什么要将&line
传入strlen
和strcpy
?如果我没记错的话,您应该将line
和current->name
传入这些功能。 (我不知道getline
;也许这样就好了。)
答案 1 :(得分:1)
这适用于我(使用包含多行的文件构建和运行。我必须更改编译器的getline函数:还更改了“unit”的几个“单位”,这是结构的名称。也是行缓冲是静态保留的,最大长度为255个字符):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct unit{
struct unit * next;
char *name;
};
void readFile(char fileName[], struct unit * units){
FILE * fp;
char line[255];
int length = 1000;
fp = fopen(fileName, "r");
int counter = 0;
int strLength = 0;
struct unit * current;
units = (struct unit*)malloc(sizeof(struct unit));
current = units;
while ( fgets ( line, sizeof line, fp ) != NULL ) /* read a line */
{
strLength = strlen(line);
current->name = (char*)malloc(sizeof(char)* strLength);
current->next = (struct unit*)malloc (sizeof(struct unit));
strcpy(current->name, line);
printf("\nCurrent: %s",current->name);
current = current->next;
counter++;
}
fclose ( fp );
printf("\nTest %s", units->name);
printf("\nTest %s", units->next->name);
printf("\nTest %s", units->next->next->name);
printf("\nTest %s", units->next->next->next->name);
}
int main(){
readFile("filename.txt", NULL);
}
答案 2 :(得分:0)
您的代码有几个不良做法和一些错误。在进入循环之前,您无需预先分配节点。您可以根据需要进行简单分配。有许多方法可以确保使用名为 forward-chaining 的技术将新分配的节点添加到列表末尾。我会在一分钟内完成。以下列表没有特别的顺序,但我至少尝试过自上而下的工作
专业:您的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()
行缓冲区,从而引入一次性内存泄漏。使用上述替代方案,您无需担心。
备用:最后,通过应用到目前为止讨论的所有内容,并向其添加称为前向链接的技术,可以使列表填充循环更加健壮。此技术使用指针指针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;
}