C语言 链表未正确打印



我一直在尝试制作一个简单的程序来接受用户输入,直到他们按完成。当他们这样做时,程序将打印出他们键入的所有内容。我觉得我已经完成了大部分工作,程序编译得很好,但是当我输入输入然后按完成时,它将输出与我输入输入的行一样多的行。我把它画出来,觉得这段代码应该可以工作。我也对 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("%sn", 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;
}

列表仅包含指向数据的指针,而不包含数据本身。因此,如果添加到列表中的数据发生更改,列表中的数据也会更改。对于每个调用addstr都是相同的。因此,您只是一遍又一遍地将相同的指针添加到列表中。

为了快速、丑陋地修复,请更改:

(**tail).string = str;

自:

(**tail).string = strdup(str);
struct llist head; 
struct llist* tail = (struct llist*)malloc(sizeof(struct llist));
tail = &head;

我还想指出,这里的malloc是不必要的。无论如何,您都会丢弃它,第三行的赋值会导致内存泄漏。

给你一些注意事项。

  • getline()采用指向缓冲区的指针。 文本将存储在指针所说的任何位置。 你的文字会去哪里? 您应该执行以下操作:

line = malloc(size);

或者也许

char line[100];

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

编辑:您可以忽略上述要点! 事实证明,getline()足够聪明,如果你从一个空指针开始,它会为你分配一个缓冲区。 所以你的代码是正确的。 对此感到抱歉;我不熟悉getline().

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

  • 在实际程序中,您将始终检查函数的返回值。 malloc()有可能失败;你不应该只是假设它总是有效。 但是,如果您为一个类执行此操作,并且您不必进行这些错误检查,我想您可以跳过它。 不过,尽早学习谨慎的习惯并没有什么坏处。

  • 如 @David Schwartz 的回答中所述,您应该调用 strdup() 以获取每个字符串的副本。

#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("%sn", 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;
}

相关内容

  • 没有找到相关文章

最新更新