C: fgets 构建char*链表的用法
C: fgets usage for building a linked list of char*
我使用 fgets()
不正确吗?
我正在尝试构建一个字符串链表 (char *
),将每个新行添加到 LL 的末尾。我正在从一个文件中读取这些行,但由于某种原因,每一行都会被正在处理的当前行覆盖,只有在 while
循环中使用 fgets()
时,但添加函数似乎正在接收每个正确排列。
如果我在 main()
中单独添加行,则没有问题。
这是一个示例输入文件:
input.txt:
This life, which had been the
tomb of his virtue and of his
honour, is but a walking
shadow; a poor player, that
struts and frets his hour upon
the stage, and then is heard
no more: it is a tale told by an
idiot, full of sound and fury,
signifying nothing.
--William Shakespeare
代码:
#include <stdio.h> //printf, fopen
#include <stdlib.h> //exit, EXIT_FAILURE
#include <string.h> //strlen
struct node {
char *line;
struct node *next;
};
void print(struct node *node);
void add(struct node **head, char *newLine) {
//printf("%s", newLine);
struct node *new_node = (struct node *)malloc(sizeof(struct node));
struct node *curr = *head;
new_node->line = newLine;
new_node->next = NULL;
if (*head == NULL) {
*head = new_node;
} else {
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new_node;
}
print(*head);
}
void print(struct node *node) {
printf("\n");
while (node != NULL) {
printf("%s\n", node->line);
node = node->next;
}
}
int main(int argc, char *argv[16]) {
char newLine[81];
struct node *head = NULL;
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("ERROR: file open failed");
exit(EXIT_FAILURE);
}
while (fgets(newLine, 81, fp)) {
add(&head, newLine);
}
add(&head, "why");
add(&head, "does");
add(&head, "this");
add(&head, "work??");
fclose(fp);
print(head);
return 0;
}
有人可以向我解释一下发生了什么吗?我用头撞墙太久了。已经有一些我一直在尝试使用的注释打印语句,调试失败。
您有 一个 缓冲区用于存储输入。在添加节点时,您将指针传递给这个单个缓冲区的第一个元素。这意味着 all 节点中的字符串指针将指向同一个缓冲区。最后将包含您阅读的最后一个字符串。
最简单的解决办法就是把node-structure中的字符串做成一个数组,然后把字符串复制进去。
另一种解决方案是为字符串动态分配内存(记住终止空字符),然后再次将字符串复制到该内存中。
使用常量字符串文字的区别在于每个字符串都是不同的数组。
您的问题出在 add() 方法中。
它不断向列表中添加相同的缓冲区指针。
您需要将列表中的缓冲区复制到新分配的 space,即。
node->line 也需要分配,并将 newLine 复制到其中。
不要忘记 malloc (strlen (newLine) + 1).
您必须为每一行分配内存。按照目前的编码,所有节点都指向 main()
中的本地数组,每次调用 fgets()
.
时其内容都会被覆盖
另请注意,添加到列表中的每一行都包含一个终止换行符,您可能应该在调用之前将其删除。
这是更正后的版本:
#include <stdio.h> // printf, fopen
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h> // strlen, strdup
struct node {
char *line;
struct node *next;
};
void print(struct node *node);
void add(struct node **head, char *newLine) {
//printf("%s", newLine);
struct node *new_node = malloc(sizeof(struct node));
struct node *curr = *head;
new_node->line = strdup(newLine);
new_node->next = NULL;
if (*head == NULL) {
*head = new_node;
return;
}
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new_node;
print(*head);
}
void print(const struct node *node) {
printf("\n");
while (node != NULL) {
printf("%s\n", node->line);
node = node->next;
}
}
int main(int argc, char *argv[16]) {
char newLine[81];
struct node *head = NULL;
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("ERROR: file open failed");
exit(EXIT_FAILURE);
}
while (fgets(newLine, sizeof newLine, fp)) {
newLine[strcspn(newLine, "\n")] = '[=10=]'; // strip the newline if present
add(&head, newLine);
}
add(&head, "why");
add(&head, "does");
add(&head, "this");
add(&head, "work??");
fclose(fp);
print(head);
return 0;
}
我使用 fgets()
不正确吗?
我正在尝试构建一个字符串链表 (char *
),将每个新行添加到 LL 的末尾。我正在从一个文件中读取这些行,但由于某种原因,每一行都会被正在处理的当前行覆盖,只有在 while
循环中使用 fgets()
时,但添加函数似乎正在接收每个正确排列。
如果我在 main()
中单独添加行,则没有问题。
这是一个示例输入文件:
input.txt:
This life, which had been the
tomb of his virtue and of his
honour, is but a walking
shadow; a poor player, that
struts and frets his hour upon
the stage, and then is heard
no more: it is a tale told by an
idiot, full of sound and fury,
signifying nothing.
--William Shakespeare
代码:
#include <stdio.h> //printf, fopen
#include <stdlib.h> //exit, EXIT_FAILURE
#include <string.h> //strlen
struct node {
char *line;
struct node *next;
};
void print(struct node *node);
void add(struct node **head, char *newLine) {
//printf("%s", newLine);
struct node *new_node = (struct node *)malloc(sizeof(struct node));
struct node *curr = *head;
new_node->line = newLine;
new_node->next = NULL;
if (*head == NULL) {
*head = new_node;
} else {
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new_node;
}
print(*head);
}
void print(struct node *node) {
printf("\n");
while (node != NULL) {
printf("%s\n", node->line);
node = node->next;
}
}
int main(int argc, char *argv[16]) {
char newLine[81];
struct node *head = NULL;
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("ERROR: file open failed");
exit(EXIT_FAILURE);
}
while (fgets(newLine, 81, fp)) {
add(&head, newLine);
}
add(&head, "why");
add(&head, "does");
add(&head, "this");
add(&head, "work??");
fclose(fp);
print(head);
return 0;
}
有人可以向我解释一下发生了什么吗?我用头撞墙太久了。已经有一些我一直在尝试使用的注释打印语句,调试失败。
您有 一个 缓冲区用于存储输入。在添加节点时,您将指针传递给这个单个缓冲区的第一个元素。这意味着 all 节点中的字符串指针将指向同一个缓冲区。最后将包含您阅读的最后一个字符串。
最简单的解决办法就是把node-structure中的字符串做成一个数组,然后把字符串复制进去。
另一种解决方案是为字符串动态分配内存(记住终止空字符),然后再次将字符串复制到该内存中。
使用常量字符串文字的区别在于每个字符串都是不同的数组。
您的问题出在 add() 方法中。 它不断向列表中添加相同的缓冲区指针。 您需要将列表中的缓冲区复制到新分配的 space,即。 node->line 也需要分配,并将 newLine 复制到其中。 不要忘记 malloc (strlen (newLine) + 1).
您必须为每一行分配内存。按照目前的编码,所有节点都指向 main()
中的本地数组,每次调用 fgets()
.
另请注意,添加到列表中的每一行都包含一个终止换行符,您可能应该在调用之前将其删除。
这是更正后的版本:
#include <stdio.h> // printf, fopen
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h> // strlen, strdup
struct node {
char *line;
struct node *next;
};
void print(struct node *node);
void add(struct node **head, char *newLine) {
//printf("%s", newLine);
struct node *new_node = malloc(sizeof(struct node));
struct node *curr = *head;
new_node->line = strdup(newLine);
new_node->next = NULL;
if (*head == NULL) {
*head = new_node;
return;
}
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new_node;
print(*head);
}
void print(const struct node *node) {
printf("\n");
while (node != NULL) {
printf("%s\n", node->line);
node = node->next;
}
}
int main(int argc, char *argv[16]) {
char newLine[81];
struct node *head = NULL;
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("ERROR: file open failed");
exit(EXIT_FAILURE);
}
while (fgets(newLine, sizeof newLine, fp)) {
newLine[strcspn(newLine, "\n")] = '[=10=]'; // strip the newline if present
add(&head, newLine);
}
add(&head, "why");
add(&head, "does");
add(&head, "this");
add(&head, "work??");
fclose(fp);
print(head);
return 0;
}