C语言读取歌曲文件至elenco链表时出现乱码问题求助
问题原因分析
乱码出现主要源于三个核心问题:
- 错误使用
feof()作为循环条件:feof()仅在尝试读取文件末尾后才会返回真,这会导致循环多执行一次,最后一次分配的结构体无有效数据,输出时读取到内存垃圾值。 fscanf("%d:%d")遗留换行符:读取完时长的minuti和secondi后,该行末尾的换行符会留在输入缓冲区,下一次调用fscanf("%29[^\n]")会读取空字符串,且目标数组未被正确初始化(缺少字符串终止符\0),printf输出时越界读取内存导致乱码。- 未处理
fscanf读取失败场景:若某次fscanf读取失败,结构体的字符数组会保留malloc后的垃圾值,输出时同样触发乱码。
修复方案
以下是修正后的完整代码,改用更可靠的fgets读取每行内容,彻底解决缓冲区和初始化问题:
#include <stdio.h> #include <stdlib.h> #include <string.h> struct elenco{ char titolo[30]; char autore[30]; int durata_in_sec; int rips; struct elenco *prossima; }; // 辅助函数:去除字符串末尾的换行符 void trim_newline(char *str) { size_t len = strlen(str); if (len > 0 && str[len-1] == '\n') { str[len-1] = '\0'; } } int main() { FILE *fp = fopen("musica.txt", "r"); if (!fp) { // 检查文件是否成功打开 perror("无法打开文件"); return 1; } int i = 0; int minuti, secondi; char durata_str[10]; struct elenco *start = NULL; struct elenco *elenco = NULL; struct elenco *prec = NULL; // 循环读取:每次读取标题、作者、时长三行 while (1) { elenco = malloc(sizeof(struct elenco)); if (!elenco) { // 检查内存分配是否成功 perror("内存分配失败"); return 1; } // 读取标题 if (!fgets(elenco->titolo, sizeof(elenco->titolo), fp)) { free(elenco); // 读取失败,释放刚分配的内存 break; } trim_newline(elenco->titolo); // 读取作者 if (!fgets(elenco->autore, sizeof(elenco->autore), fp)) { free(elenco); break; } trim_newline(elenco->autore); // 读取时长字符串并解析 if (!fgets(durata_str, sizeof(durata_str), fp)) { free(elenco); break; } trim_newline(durata_str); if (sscanf(durata_str, "%d:%d", &minuti, &secondi) != 2) { free(elenco); break; } // 填充结构体字段 elenco->durata_in_sec = minuti * 60 + secondi; elenco->rips = 1; elenco->prossima = NULL; // 更新链表 if (i == 0) { start = elenco; } else { prec->prossima = elenco; } prec = elenco; i++; } // 输出链表内容 elenco = start; while (elenco != NULL) { printf("%s\n", elenco->titolo); printf("%s\n", elenco->autore); printf("%d\n", elenco->durata_in_sec); printf("%d\n", elenco->rips); elenco = elenco->prossima; } fclose(fp); // 释放链表内存 elenco = start; while (elenco != NULL) { struct elenco* temp = elenco; elenco = elenco->prossima; free(temp); } return 0; }
关键修复点说明
- 替换循环逻辑:不再依赖
feof(),通过fgets的返回值判断读取状态,避免循环多执行一次导致的垃圾值输出。 - 改用
fgets读取每行:fgets会读取整行内容(含换行符),配合trim_newline函数去除末尾换行,确保字符数组始终以\0结尾,杜绝printf越界读取。 - 添加全面错误检查:对文件打开、内存分配、内容读取、时长解析的所有步骤都做了错误检查,避免意外错误引发内存泄漏或乱码。
- 分离时长读取与解析:先读取时长字符串再用
sscanf解析,彻底解决fscanf遗留的缓冲区换行符问题。
内容的提问来源于stack exchange,提问作者ShishRobot
相关产品推荐
相关产品推荐

