链接列表无法正确打印

时间:2012-06-27 01:16:14

标签: c linked-list

我一直在尝试创建一个简单的程序来接受用户输入,直到他们按下完成。当他们这样做时,程序将打印出他们输入的所有内容。我觉得我已经完成了大部分工作,并且程序编译得很好,但是当我输入输入然后按完成后,它将输出完成与我输入的输入一样多的行。我已经把它画出来了,觉得这段代码应该可行。我也很新C.所以如果有人能让我知道什么是错的,甚至给我建议。

#include <stdio.h>
#include <stdlib.h>

struct llist {          
struct llist* nxt; 
char* string;
};              

void add(struct llist **tail, char* str) { 
    struct llist* n_ptr = (struct llist*)malloc(sizeof(struct llist));
    (**tail).string = str; 
    (**tail).nxt = n_ptr;   
        (*tail) = n_ptr; 
    n_ptr->nxt = (struct llist*)0;
};

void print(struct llist *Head) {
    struct llist* ptr;
    ptr = Head;
    while(ptr->nxt){ 
        printf("%s\n", ptr->string);
        fflush(stdout);
        (ptr = (ptr->nxt)); }
}

int main() {
    char* line = NULL;
    size_t size = 100; 
    char* done = "done";

    struct llist head; 
    struct llist* tail = (struct llist*)malloc(sizeof(struct llist));

    tail = &head; 

    do { 
    getline(&line, &size, stdin); 
    add( &tail , line ) ;   
    } while ( strncmp(line, done, 4) != 0 );

    print(&head);

    return 0;
}

4 个答案:

答案 0 :(得分:3)

您的列表只包含数据的指针,而不包含数据本身。因此,如果添加到列表中的数据发生更改,则列表中的数据也会更改。对于add的每次通话,str都是相同的。所以你只是一遍又一遍地向列表添加相同的指针。

快速,丑陋的修复,改变:

(**tail).string = str;

为:

(**tail).string = strdup(str);

答案 1 :(得分:1)

给你一些笔记。

  • getline()获取指向缓​​冲区的指针。文本将存储在指针所指的任何位置。你的文字会在哪里?你应该这样做:

line = malloc(size);

或者

char line[100];

其中任何一个都可以解决问题。但是,如果getline()不够大,malloc()将动态增长缓冲区,可能getline()解决方案更可取。 (我不知道free()是否会在动态增长缓冲区时尝试调用malloc();如果是,那么getline()是非常可取的。)

编辑:你可以忽略上述观点!事实证明getline()足够聪明,如果你从一个空指针开始,它将为你分配一个缓冲区。所以你的代码写得正确。对于那个很抱歉;我不熟悉malloc()

  • 您的链接列表代码主要调用head来创建新节点。但由于某种原因,您静态地将单个节点声明为malloc()。这对于像这样的小程序来说没问题,但是如果你写了一个大程序就会让人感到困惑;当你去释放链表时,你需要注意不要释放第一个节点(因为它没有使用head分配)。我个人认为tailNULL都是指针,并将它们都设置为add()(对于长度为零的链表)。最简单的方法是让head函数为head指针设置一个参数,并在将第一个结构添加到链表时将其设置为tail。您还需要小心一点,因为当您将第一个结构添加到链接列表时,您的add()尚未设置,因此您不应尝试将新节点链接到上一个节点之前有一个节点。因此,您第一次调用head时应将tailnext设置为指向结构的全新实例,并且新实例应设置其add()指针为null;然后,对malloc()的其他调用应将新结构链接到现有链接列表。

  • 在实际程序中,您总是会检查函数的返回值。 strdup()可能会失败;你不应该只是假设它始终有效。但是,如果您正在为一个类执行此操作,并且您不必执行这些错误检查,我想您可以跳过它。不过,尽早学习细心的习惯绝对不会伤害。

  • 如@David Schwartz的回答所述,您应该致电{{1}}获取每个字符串的副本。

答案 2 :(得分:1)

struct llist head; 
struct llist* tail = (struct llist*)malloc(sizeof(struct llist));

tail = &head;

我还想指出这里的malloc是不必要的。无论如何,您正在丢弃它,第三行上的分配导致内存泄漏。

答案 3 :(得分:0)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum {FAILURE, SUCCESS} ReturnType;

typedef struct node_t Node;
struct node_t {
    Node* next;
    char* data;
};

Node* nodeCreate(char* str) {
    Node* res = (Node*) malloc(sizeof(Node));
    if (res == NULL) {
        return NULL;
    }

    res->data = (char*) malloc(strlen(str) + 1);
    if (res->data == NULL) {
        free(res);
        return NULL;
    }

    strcpy(res->data, str);
    res->next = NULL;

    return res;
}    

void nodeDestroy(Node* node) {
    free(node->data);
    free(node);
}    

typedef struct list_t {
    Node* head;
    Node* tail;
} List;

List* listCreate() {
    List* res = (List*) malloc(sizeof(List));
    if (res == NULL) {
        return NULL;
    }

    res->head = (Node*) malloc(sizeof(Node));
    if (res->head == NULL) {
        free(res);
        return NULL;
    }
    res->head->next = NULL;
    res->head->data = NULL;
    res->tail = res->head;

    return res;
}

void listDestroy(List* list) {
    if (list == NULL) {
        return;
    }

    Node* curr = list->head;
    Node* next = NULL;

    while (curr != NULL) {
        next = curr->next;
        nodeDestroy(curr);
        curr = next;
    }
    free(list);
}

ReturnType listAdd(List* list, char* str) {
    if (list == NULL) {
        return FAILURE;
    }

    Node* newNode = nodeCreate(str);
    if (newNode == NULL) {
        return FAILURE;
    }

    list->tail->next = newNode;
    list->tail = list->tail->next;

    return SUCCESS;
};

void listPrint(List* list) {
    if (list == NULL) {
        return;
    }

    Node* curr = list->head->next;
    while(curr != NULL){
        printf("%s\n", curr->data);
        curr = curr->next;
    }
}

#define MAX_LINE_SIZE 100

int main() {
    setvbuf(stdout, NULL, _IONBF, 0);
    char line[MAX_LINE_SIZE];
    char* done = "done";

    List* list = listCreate();
    if (list == NULL) {
        fprintf(stderr, "Failure!\n");
        return 0;
    }

    do {
        scanf("%s", line);
        if (listAdd(list , line) == FAILURE) {
            fprintf(stderr, "Failure!\n");
            listDestroy(list);
            return 0;
        }
    } while (strncmp(line, done, 4) != 0);

    listPrint(list);

    listDestroy(list);

    return 0;
}