C语言双向链表实现音乐播放器选择播放曲目时程序崩溃排查
基于双向链表实现的音乐播放器运行崩溃排查
我做学校课程项目的小型音乐播放器,要求必须用链表存储数据,目前代码编译无警告但运行时会触发崩溃,其中用于遍历展示链表的View_List(原函数名Afficher_Liste)运行正常。
相关代码片段
音轨结构体定义
typedef struct Piste{ char *pTitle; char *pArtist; char *pPath; struct Piste *pNext; struct Piste *pPrev; }Piste;
存在问题的播放功能函数
void Play_Music(Piste **pHead){ int choice; int ctr = 1; char * path_music; path_music= (char*)malloc(200 * sizeof(char)); View_List(&ppDL); Piste *pCur = *pHead; printf("What music you want to play ?"); scanf("%d",&choice); while(choix!=cptr){ pCur = pCur->pNext; ctr++; if(choice==cptr){ path_music= pCur->pPath; } } printf("your choice is %s",path_music); scanf("%d",choice); }
调用播放函数的用户菜单代码
void User_Mode(){ int choice; char *search= NULL; while(choice!= 4) { system("cls"); printf("---------- User Menu----------\n\n"); printf("1 - Search\n"); printf("2 - Play a music\n"); printf("3 - Back to menu\n"); printf("your choice?\n"); scanf("%d", &choice); switch(choice){ case 1: fflush(stdin); search = (char*)malloc(200 * sizeof(char)); printf( "what do you want to listen ? : \n" ); scanf( "%[^\n]", seach); fgetc( stdin ); if(search!=NULL){ search_music(search,&ppDL); } break; case 2: play_music(); break; case 3: main_menu(); break; default: system("cls"); printf("your choice isnt good\n\n"); user_mode(); } } }
崩溃原因汇总
全是代码笔误+边界判断缺失导致的,逐个对应修改即可:
- 变量名拼写错误直接导致逻辑跑飞:循环条件写的是
while(choix!=cptr),实际定义的计数器是ctr、存储用户输入的变量是choice,两个变量名全拼错。编译没报错是因为旧C标准会对未声明的变量默认按int类型处理,运行时直接读取随机野值,循环要么不执行要么无限死循环。 - 链表遍历完全没做空指针判断:循环里直接执行
pCur = pCur->pNext,如果用户输入的序号超过链表总长度,pCur走到链表尾部的NULL之后,下一次访问pCur->pNext就是直接访问空指针,必然触发崩溃。另外初始计数器ctr设为1,用户输入1的时候循环根本不会进入,拿不到第一个节点的路径数据。 - 内存泄漏+野指针问题:一开始给
path_music申请了200字节的堆内存,找到对应节点后又直接把path_music指针指向节点内的pPath地址,之前申请的内存没有释放也没有指针指向,直接造成内存泄漏。 - 函数调用和定义完全不匹配:定义的
Play_Music需要传入双向链表头指针的二级指针,结果菜单case2里调用的时候直接写play_music(),既没传参数,函数名大小写也不对(C语言大小写敏感),等于直接跳转到未知内存地址执行。 - 末尾的scanf写法错误:最后一行
scanf("%d",choice);没有传入变量地址,直接把用户输入的整数值当内存地址写入,触发非法内存访问崩溃。 - 菜单逻辑存在多处笔误:搜索功能里
scanf( "%[^\n]", seach);把search拼成了seach,属于写入野指针;choice变量定义后没有初始化就进入while(choice!=4)的判断,初始值是随机垃圾值,逻辑完全不可控。 - 函数参数传了没用:
View_List(&ppDL);直接写死了全局变量,根本没用到传入的pHead参数,参数定义完全多余。
顺带提一句,fflush(stdin)属于C标准未定义行为,不要用来清空输入缓冲区,用循环读取剩余字符的方式更稳妥。
修复参考
修复后的播放函数
void Play_Music(Piste **pHead){ // 先判断链表是否为空 if (pHead == NULL || *pHead == NULL) { printf("当前播放列表为空!\n"); getchar();getchar(); return; } int choice; int ctr = 1; int list_len = 0; Piste *pCur = *pHead; // 先统计链表总长度,校验用户输入范围 while(pCur != NULL) { list_len++; pCur = pCur->pNext; } pCur = *pHead; View_List(pHead); printf("请输入要播放的音乐序号(1-%d):", list_len); scanf("%d",&choice); if (choice <1 || choice > list_len) { printf("输入的序号无效!\n"); getchar();getchar(); return; } // 遍历定位到目标节点 while(ctr != choice){ pCur = pCur->pNext; ctr++; } printf("你选择的音乐路径为:%s\n", pCur->pPath); // 这里补充实际调用系统API播放音频的逻辑即可 printf("按回车键返回菜单..."); getchar();getchar(); }
菜单部分对应修改
- 定义
choice时直接初始化为0,避免初始野值 - 搜索功能里的
seach笔误改为search - case2的调用改为
Play_Music(&ppDL); - 删掉播放函数末尾多余的错误scanf代码
内容的提问来源于stack exchange,提问作者julien1h
相关产品推荐
相关产品推荐

