3

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

4 回答 4

3

您的列表仅包含指向数据的指针,而不包含数据本身。因此,如果添加到列表中的数据发生变化,则列表中的数据也会发生变化。每次调用add,str都是一样的。因此,您只是一遍又一遍地将相同的指针添加到列表中。

为了快速而丑陋的修复,请更改:

(**tail).string = str;

到:

(**tail).string = strdup(str);
于 2012-06-27T01:24:42.297 回答
1

一些笔记给你。

  • getline()接受一个指向缓冲区的指针。文本将存储在指针所说的任何位置。你的文字会去哪里?你应该这样做:

line = malloc(size);

也许

char line[100];

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

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

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

  • 在实际程序中,您总是会检查函数的返回值。有可能malloc()失败;你不应该只是假设它总是有效的。但如果你是为一堂课做这个,而且你不必做那些错误检查,我想你可以跳过它。不过,尽早学习谨慎的习惯永远不会有坏处。

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

于 2012-06-27T01:33:46.783 回答
1
struct llist head; 
struct llist* tail = (struct llist*)malloc(sizeof(struct llist));

tail = &head;

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

于 2012-06-27T01:38:22.673 回答
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;
}
于 2012-06-27T02:40:36.943 回答