C语言链表二次遍历打印符号而非单词的问题求助
链表二次遍历单词显示异常问题
我是C语言初学者,代码可能不够规范。我想实现一个链表,节点结构体包含char数组(存储单词)和int类型的frequency(频率)。程序从测试文件读取内容并打印,第一次读取文件和遍历链表均正常,但第二次遍历链表时,行数和整数频率正确,单词却被符号替代。附上代码寻求帮助。我有一定编程基础,学C是为了深入理解程序运行底层逻辑,助力后续开发。
#include <stdio.h> #include <stdlib.h> #define Word_MAX_LENGTH 255 struct WordFreq { char word[Word_MAX_LENGTH]; int frequency; struct WordFreq *next; } WordFreq; struct WordFreq *head = NULL; void insert(struct WordFreq *newNode) { if (head == NULL) { head = newNode; newNode->next = NULL; return; } struct WordFreq *current = head; while (current->next != NULL) { current = current->next; } current->next = newNode; newNode->next = NULL; } void main(int argc, char *argv[]) { if (argc != 2) { printf("Please run as %s [filename]\n", argv[0]); return; } FILE *f; f = fopen(argv[1], "r"); if (f == NULL) { printf("File (%s) does not exist\n", argv[1]); return; } struct WordFreq *line = malloc(sizeof(struct WordFreq)); if (line == NULL) { printf("Cannot do dynamic memory managment\n"); return; } printf("File content in %s:\n", argv[1]); while (fscanf(f, "%s %d", line->word, &(line->frequency)) != EOF) { printf("%s %d\n", line->word, line->frequency); insert(line); line = malloc(sizeof(struct WordFreq)); if (line == NULL) { printf("Cannot do dynamic memory management"); return; } } fclose(f); // To keep head intact for sorting portion struct WordFreq *current = head; printf("\nContent of linked list:\n"); while (current != NULL) { printf("%s %d\n", current->word, current->frequency); struct WordFreq *temp = current; current = current->next; free(temp); } printf("\n\n"); current = head; while (current != NULL) { printf("%s %d\n", current->word, current->frequency); current = current->next; } free(current); free(line); }
问题根源
你在第一次遍历链表时,已经通过free(temp)把所有节点的内存都释放了,此时head指向的是已经被系统回收的内存区域,属于野指针。第二次遍历访问的是已释放的内存,word数组的内容被系统覆盖所以显示乱码;frequency数值正确只是巧合,属于未定义行为。
修复方案
- 移除第一次遍历的free操作:如果后续还要使用链表,不能提前释放节点。
- 调整内存释放时机:在最后一次遍历完成后,再逐个释放所有链表节点,避免内存泄漏。
- 修正main函数返回类型:C标准中
main返回类型应为int,而非void。 - 清理多余的free调用:
free(current)是多余的(最后current为NULL),最后一次malloc的空节点line需要在循环结束后释放。
修复后的代码示例
#include <stdio.h> #include <stdlib.h> #define Word_MAX_LENGTH 255 struct WordFreq { char word[Word_MAX_LENGTH]; int frequency; struct WordFreq *next; }; struct WordFreq *head = NULL; void insert(struct WordFreq *newNode) { if (head == NULL) { head = newNode; newNode->next = NULL; return; } struct WordFreq *current = head; while (current->next != NULL) { current = current->next; } current->next = newNode; newNode->next = NULL; } int main(int argc, char *argv[]) { if (argc != 2) { printf("Please run as %s [filename]\n", argv[0]); return 1; } FILE *f = fopen(argv[1], "r"); if (f == NULL) { printf("File (%s) does not exist\n", argv[1]); return 1; } struct WordFreq *line = malloc(sizeof(struct WordFreq)); if (line == NULL) { printf("Cannot do dynamic memory management\n"); fclose(f); return 1; } printf("File content in %s:\n", argv[1]); while (fscanf(f, "%s %d", line->word, &(line->frequency)) != EOF) { printf("%s %d\n", line->word, line->frequency); insert(line); line = malloc(sizeof(struct WordFreq)); if (line == NULL) { printf("Cannot do dynamic memory management\n"); fclose(f); // 此处可添加已插入节点的释放逻辑,避免内存泄漏 return 1; } } fclose(f); free(line); // 释放最后一次malloc的空节点 // 第一次遍历链表 struct WordFreq *current = head; printf("\nContent of linked list:\n"); while (current != NULL) { printf("%s %d\n", current->word, current->frequency); current = current->next; } // 第二次遍历链表 printf("\n\nSecond traversal of linked list:\n"); current = head; while (current != NULL) { printf("%s %d\n", current->word, current->frequency); current = current->next; } // 最后释放所有链表节点 current = head; while (current != NULL) { struct WordFreq *temp = current; current = current->next; free(temp); } head = NULL; // 清空头指针,避免野指针 return 0; }
额外注意事项
- 野指针是C语言常见错误,访问已释放内存属于未定义行为,结果不可预测,必须避免。
- 内存管理要配对:每个
malloc对应一个free,既不能泄漏也不能重复释放。 - 原结构体定义后的
WordFreq是多余的全局变量,建议移除。
内容的提问来源于stack exchange,提问作者dirthogger
相关产品推荐
相关产品推荐

