C语言链表歌曲播放列表:PLAY命令无法触发print_list打印问题求助
问题分析与修复:链表播放列表PLAY命令无法打印内容
问题根源
main函数的循环逻辑存在错误:当输入PLAY命令时,程序直接打印总时长后就执行break终止循环,完全跳过了调用execute_cmd的步骤,导致PLAY分支里的print_list函数从未被触发。
修复方案
调整main函数中PLAY命令的处理顺序,先执行命令逻辑再处理其他操作,同时根据需求决定是否终止程序:
- 如果希望打印播放列表后程序继续运行,移除
break语句; - 如果需要打印后退出,确保先调用
execute_cmd再执行break。
另外补充一个潜在问题的修复:REMOVE命令处理时,未检查歌曲是否存在就直接减去时长,会导致总时长计算错误,需要增加存在性判断。
修复后的完整代码
#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef enum commands { ADDBEG, ADDEND, PLAY, REMOVE, INVALID } command_t; typedef struct song_s { char name[99]; char time[20]; struct song_s *next; } song_t; void insert_end(song_t **p, song_t *entry); void insert_begin(song_t **p, song_t *entry); void remove_song(song_t **p, song_t *entry); void execute_cmd(command_t command, song_t **head, song_t *entry); bool already_present(song_t **p, song_t *new_song); void print_list(song_t *p); command_t split_input(char *input, song_t *song) { command_t command = INVALID; int len = strlen(input); // Remove the newline character, if present if (input[len - 1] == '\n') { input[len - 1] = '\0'; } // Check if the input command is "PLAY" if (strcmp(input, "PLAY") == 0) { return PLAY; } char *token = strtok(input, ","); char *data[3]; int i = 0; // Check if the input command starts with "REMOVE," if (input[0] == 'R') { while (token != NULL && i < 2) { data[i] = token; token = strtok(NULL, ","); i++; } strcpy(song->name, data[1]); return REMOVE; } // Check if the input command starts with "ADDBEG" or "ADDEND" if (input[0] == 'A') { while (token != NULL && i < 3) { data[i] = token; token = strtok(NULL, ","); i++; } } // Set the command based on the input data if (strcmp(data[0], "ADDBEG") == 0) { command = ADDBEG; } else if (strcmp(data[0], "ADDEND") == 0) { command = ADDEND; } // Copy song data if available if (data[1] != NULL) strcpy(song->name, data[1]); if (data[2] != NULL) strcpy(song->time, data[2]); return command; } int main(void) { char input[100]; song_t song; song_t *head = NULL; int total_time = 0; command_t command; while (1) { printf("input: "); fgets(input, 100, stdin); command = split_input(input, &song); // 先执行所有命令逻辑,包括PLAY execute_cmd(command, &head, &song); // 总时长计算放在命令执行后,确保操作有效 if (command == ADDBEG || command == ADDEND) { if (!already_present(&head, &song)){ total_time += atoi(song.time); } } if (command == REMOVE) { // 移除前检查歌曲是否存在,避免错误扣减时长 if (already_present(&head, &song)) { total_time -= atoi(song.time); } } // PLAY命令处理:打印总时长,不终止程序(如需终止可添加break) if (command == PLAY) { printf("total time: %d\n", total_time); // 如果需要输入PLAY后退出,取消下面的注释 // break; } } return 0; } void insert_end(song_t **p, song_t *entry) { song_t *q = (song_t *)malloc(sizeof(song_t)); memcpy(q, entry, sizeof(song_t)); q->next = NULL; song_t *aux; if (*p == NULL) *p = q; else { aux = *p; while (aux->next != NULL) aux = aux->next; aux->next = q; } } void insert_begin(song_t **p, song_t *entry) { song_t *q = (song_t *)malloc(sizeof(song_t)); memcpy(q, entry, sizeof(song_t)); q->next = *p; *p = q; } void remove_song(song_t **p, song_t *entry) { song_t *q = *p; if (q == NULL) return; // empty list if (strcmp(q->name, entry->name) == 0) { *p = q->next; free(q); return; } while (q->next != NULL) { if (strcmp(q->next->name, entry->name) == 0) break; q = q->next; } if (q->next == NULL) return; // value not found song_t *tmp = q->next; q->next = tmp->next; free(tmp); } void print_list(song_t *p) { while (p != NULL) { printf("Song Name: %s, Time: %s\n", p->name, p->time); p = p->next; } } void execute_cmd(command_t command, song_t **head, song_t *new_song) { // Call the appropriate function based on the command if (command == ADDBEG) { insert_begin(head, new_song); } else if (command == ADDEND) { insert_end(head, new_song); } else if (command == REMOVE) { remove_song(head, new_song); } else if (command == PLAY) { print_list(*head); } else { printf("Invalid command\n"); } } // Check if the song is already in the playlist bool already_present(song_t **p, song_t *new_song) { song_t *q = *p; while (q != NULL) { if (strcmp(q->name, new_song->name) == 0) { return true; } q = q->next; } return false; }
额外说明
- 调整了命令执行顺序,确保所有命令(包括PLAY)都能触发
execute_cmd中的逻辑; - 修复了REMOVE命令的时长计算bug,只有歌曲存在时才扣减时长;
- 移除了原split_input中多余的printf调试语句,避免干扰正常输出;
- 保留了PLAY后是否终止程序的可选逻辑,可根据需求调整。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

