You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言嵌套链表插入球员数据异常:仅存最后一条的解决方法

解决嵌套链表存储球员数据仅保留最后一条的问题

问题根源

你的代码核心问题是链表头指针被错误覆盖,同时文件读取逻辑存在漏洞:

  • 每个球队的PLAYERS链表初始是一个哨兵空节点(由makePlayer创建),这是链表的真正头节点。但在readFile中,每次插入球员后执行temp->player = temp->player->next,导致temp->player最终指向最后一个球员节点,原来的哨兵头指针被丢失,后续遍历只能看到最后一个节点。
  • while(!feof(f))的写法会导致最后一次读取失败后仍进入循环,可能产生无效数据。

解决方案

  1. 保留哨兵头节点:用临时尾指针跟踪插入位置,绝不修改temp->player的指向(它始终指向哨兵头)。
  2. 尾插法存储球员:按文件顺序把前11名球员插入链表尾部,保证顺序正确且链表完整。
  3. 修正文件读取逻辑:用fscanf的返回值判断读取是否成功,避免feof的逻辑漏洞。

修改后的关键代码

1. 修正readFile函数

void readFile(teamList* team){
    teamList* temp = team;
    FILE *f = fopen("teamsinfo.txt","r");
    if (f == NULL) {
        printf("Failed to open file!\n");
        return;
    }
    int i, counter = 1;
    char playerName[50];
    char teamCode[50];

    // 读取第一个球队
    if(fscanf(f,"*%s",teamCode) == 1){
        printf("*%s\n", teamCode);
        strcpy(temp->code,teamCode);
        PLAYERS* playerTail = temp->player; // 尾指针指向哨兵头

        while(1){
            // 尝试读取新球队标识
            if(fscanf(f,"*%s",teamCode) == 1){
                counter = 1;
                temp->next = MakeEmptyList(temp->next);
                temp = temp->next;
                strcpy(temp->code,teamCode);
                playerTail = temp->player; // 重置当前球队的尾指针
            } else {
                // 回退指针,读取球员数据
                ungetc(fgetc(f), f); // 修正读取位置,避免跳过字符
                if(counter < 12){
                    if(fscanf(f,"%d-%s",&i,playerName) == 2){
                        // 尾插法创建新球员节点
                        PLAYERS* newPlayer = (PLAYERS*)malloc(sizeof(PLAYERS));
                        strcpy(newPlayer->name, playerName);
                        newPlayer->num = i;
                        newPlayer->next = NULL;
                        playerTail->next = newPlayer;
                        playerTail = newPlayer; // 更新尾指针
                        counter++;
                    } else {
                        break; // 读取失败,退出循环
                    }
                } else {
                    if(fscanf(f,"%d-%s",&i,playerName) == 2){
                        enQueue(temp->playerQueue,playerName,i);
                    } else {
                        break;
                    }
                }
            }
        }
    }
    fclose(f);
}

2. 正确的遍历打印函数

打印时要跳过哨兵节点,从temp->player->next开始遍历:

void printTeamPlayers(teamList* team){
    teamList* currTeam = team;
    while(currTeam != NULL){
        printf("=== Team: %s ===\n", currTeam->code);
        PLAYERS* currPlayer = currTeam->player->next; // 跳过哨兵空节点
        printf("Players:\n");
        while(currPlayer != NULL){
            printf("%d-%s\n", currPlayer->num, currPlayer->name);
            currPlayer = currPlayer->next;
        }
        currTeam = currTeam->next;
    }
}

额外注意事项

  • 记得为enQueue函数实现正确的队列逻辑,避免内存泄漏或指针错误。
  • 所有malloc操作后都要检查是否分配成功,避免空指针异常。

内容的提问来源于stack exchange,提问作者AverageStackOverFlowUser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 09:01:14