我一直在尝试创建一个简单的程序来接受用户输入,直到他们按下完成。当他们这样做时,程序将打印出他们输入的所有内容。我觉得我已经完成了大部分工作,并且程序编译得很好,但是当我输入输入然后按完成后,它将输出完成与我输入的输入一样多的行。我已经把它画出来了,觉得这段代码应该可行。我也很新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;
}
答案 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
分配)。我个人认为tail
和NULL
都是指针,并将它们都设置为add()
(对于长度为零的链表)。最简单的方法是让head
函数为head
指针设置一个参数,并在将第一个结构添加到链表时将其设置为tail
。您还需要小心一点,因为当您将第一个结构添加到链接列表时,您的add()
尚未设置,因此您不应尝试将新节点链接到上一个节点之前有一个节点。因此,您第一次调用head
时应将tail
和next
设置为指向结构的全新实例,并且新实例应设置其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;
}