链接列表给出相同的结果C.

时间:2014-02-13 23:27:10

标签: c linked-list

在方法结束时,我的所有测试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(&current->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);
}

3 个答案:

答案 0 :(得分:1)

为什么要将&line传入strlenstrcpy?如果我没记错的话,您应该将linecurrent->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;
}