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

C语言算术测验程序Addition模块首次计分错误求助

修复C语言算术测验程序的计分归属错误

问题现象

  • 第一个玩家完成Addition测验时计分正常
  • 后续玩家首次进行Addition测验时,所得分数错误计入第一个玩家账号,第二次及之后测验计分正常
  • 仅Addition模块出现该问题,其他运算模块无异常

问题根源

程序使用指针currentUser跟踪当前登录用户,但saveUsers(保存数据时按用户名排序数组)和sortLeaderboard(显示排行榜时按对应分数排序数组)会修改users数组的元素顺序,导致currentUser指针指向的数组位置不再对应当前登录用户:

  • 后续玩家注册后,signUp函数会立即调用saveUsers排序数组,此时currentUser指针会错误指向其他用户,首次测验时分数就会加到错误账号
  • 第二次登录时,loadUsers重新读取文件并初始化数组,指针指向正确位置,因此测验恢复正常

修复方案

放弃使用指针跟踪当前用户,改用数组下标索引跟踪,这样无论数组元素如何排序,都能通过索引准确访问当前用户的数据。同时优化随机数初始化逻辑,避免短时间内生成重复随机数。

具体修改步骤

  1. 修改全局变量定义
    将指针跟踪改为下标索引:

    // 原代码
    User *currentUser = NULL;
    // 修改为
    int currentUserIndex = -1;
    
  2. 更新登录逻辑(login函数)
    记录当前用户的数组下标而非指针:

    // 原代码
    currentUser = &users[i];
    // 修改为
    currentUserIndex = i;
    
  3. 更新注册逻辑(signUp函数)
    注册时记录新用户的数组下标:

    // 原代码
    currentUser = &users[userCount];
    userCount++;
    // 修改为
    currentUserIndex = userCount;
    userCount++;
    
  4. 更新测验计分逻辑(takeQuiz函数)
    通过下标访问当前用户的分数数组,同时调整随机数初始化位置:

    // 移除takeQuiz函数中的srand调用
    // srand(time(NULL));
    
    // 原计分代码
    currentUser->scores[operation - 1] += correct;
    // 修改为
    users[currentUserIndex].scores[operation - 1] += correct;
    

    将srand(time(NULL));移到main函数开头,仅执行一次:

    int main() {
        loadUsers();
        srand(time(NULL)); // 初始化随机数生成器
        int loggedIn = 0;
        // ... 后续代码
    }
    

修改后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define MAX_USERS 100
#define MAX_NAME_LEN 50
#define FILENAME "Players_Record.txt"

typedef struct {
    char username[MAX_NAME_LEN];
    char password[MAX_NAME_LEN];
    int scores[4]; // Scores for addition, subtraction, multiplication, and division
} User;

User users[MAX_USERS];
int userCount = 0;
int currentUserIndex = -1;

void loadUsers();
void saveUsers();
int login();
void signUp();
void sortLeaderboard(int operation);
void displayLeaderboardPerOperation(int operation);
void leaderboardMenu();
void takeQuiz(int operation);
int menu();
void sortLeaderboard(int operation);

int main() {
    loadUsers();
    srand(time(NULL)); // 只初始化一次随机数生成器
    int loggedIn = 0;

    while (!loggedIn) {
        int choice;
        printf("MAIN MENU\n1. Sign Up\n2. Log In\n3. Exit\n\nEnter choice: ");
        scanf("%d", &choice);
        getchar();

        switch (choice) {
            case 1: 
                system("cls");
                signUp(); 
                loggedIn = 1; 
                system("pause");
                system("cls");
                break;
            case 2: 
                system("cls");
                loggedIn = login(); 
                system("pause");
                system("cls");
                break;
            case 3: 
                printf("Exiting...\n"); 
                exit(0);
            default: 
                printf("Invalid input. Please try again.\n");
                system("pause");
                system("cls");
        }
    }

    while (1) {
        int choice = menu();
        if (choice == 6) {
            printf("Logging Out...\n");
            saveUsers();
            break;
        }
        if (choice == 5) {
            leaderboardMenu();
        } else {
            takeQuiz(choice);
        }
    }
    return 0;
}

int menu() {
    int choice;
    printf("CHOOSE YOUR OPERATION:\n1. Addition\n2. Subtraction\n3. Multiplication\n4. Division\n5. View Leaderboard\n6. Save and Log Out\n\nEnter choice: ");
    scanf("%d", &choice);
    system("cls");
    return choice;
}

void loadUsers() {
    FILE *file = fopen(FILENAME, "r");
    if (!file) return;

    char line[200];  // Buffer for reading lines

    // Skip first two lines (headers)
    fgets(line, sizeof(line), file);
    fgets(line, sizeof(line), file);

    userCount = 0;
    while (fscanf(file, "%s %s %d %d %d %d", users[userCount].username, 
        users[userCount].password, 
                  &users[userCount].scores[0], &users[userCount].scores[1], 
                  &users[userCount].scores[2], &users[userCount].scores[3]) == 6) {
        userCount++;
    }
    fclose(file);
}

void saveUsers() {
    // Sort users alphabetically by username before saving
    for (int i = 0; i < userCount - 1; i++) {
        for (int j = i + 1; j < userCount; j++) {
            if (strcmp(users[i].username, users[j].username) > 0) {
                User temp = users[i];
                users[i] = users[j];
                users[j] = temp;
            }
        }
    }

    FILE *file = fopen(FILENAME, "w");
    if (!file) return;

    // Write header only once at the top
    fprintf(file, "%-15s %-10s %-10s %-10s %-10s %-10s\n", 
            "Username", "Password", "Addition", "Subtraction", 
        "Multiplication", "Division");
    fprintf(file, "-----------------------------------------------------------\n");

    for (int i = 0; i < userCount; i++) {
        fprintf(file, "%-15s %-10s %-10d %-10d %-10d %-10d\n", 
                users[i].username, users[i].password, 
                users[i].scores[0], users[i].scores[1], users[i].scores[2], 
        users[i].scores[3]);
    }
    fclose(file);
}

int login() {
    char username[MAX_NAME_LEN], password[MAX_NAME_LEN];
    printf("Enter username: ");
    scanf("%s", username);
    printf("Enter password: ");
    scanf("%s", password);

    for (int i = 0; i < userCount; i++) {
        if (strcmp(users[i].username, username) == 0 && strcmp(users[i].password, password) == 0) {
            currentUserIndex = i;
            printf("\nLogin successful!\n");
            return 1;
        }
    }
    printf("\nInvalid username or password. Please try again. \n");
    return 0;
}

void signUp() {
    if (userCount >= MAX_USERS) {
        printf("\nUser limit reached!\n");
        return;
    }

    char newUsername[MAX_NAME_LEN], newPassword[MAX_NAME_LEN];

    while (1) {
        int exists = 0;
        printf("Enter new username: ");
        scanf("%s", newUsername);

        // Check if username already exists
        for (int i = 0; i < userCount; i++) {
            if (strcmp(users[i].username, newUsername) == 0) {
                printf("\nUsername already exists! Please choose another.\n\n");
                exists = 1;
                break;
            }
        }
        if (!exists) break;
    }

    printf("Enter new password: ");
    scanf("%s", newPassword);

    // Store the new user
    strcpy(users[userCount].username, newUsername);
    strcpy(users[userCount].password, newPassword);
    for (int i = 0; i < 4; i++) {
        users[userCount].scores[i] = 0;
    }

    currentUserIndex = userCount;
    userCount++;
    saveUsers();
    
    printf("\nSign up SUCCESSFUL!\n\n");
}
void leaderboardMenu() {
    int operation;
    while (1) {
        printf("VIEW LEADERBOARD FOR:\n1. Addition\n2. Subtraction\n3. Multiplication\n4. Division\n5. Back to Main Menu\n\nEnter choice: ");
        scanf("%d", &operation);
        system("cls");
        if (operation >= 1 && operation <= 4) {
            displayLeaderboardPerOperation(operation);
            system("pause"); // Pause so the user can view the leaderboard
            system("cls");
        } else if (operation == 5) {
            system("cls");
            return; // Go back to the main menu
        } else {
            printf("Invalid choice. Try again.\n");
            system("pause");
            system("cls");
        }
    }
}

void sortLeaderboard(int operation) {
    for (int i = 0; i < userCount - 1; i++) {
        for (int j = i + 1; j < userCount; j++) {
            if (users[i].scores[operation - 1] < users[j].scores[operation - 1]) {
                // Swap users[i] and users[j]
                User temp = users[i];
                users[i] = users[j];
                users[j] = temp;
            }
        }
    }
}

void displayLeaderboardPerOperation(int operation) {
    char *operations[] = {"Addition", "Subtraction", "Multiplication", "Division"};
    
    // Sort leaderboard before displaying
    sortLeaderboard(operation);
    
    printf("LEADERBOARD - %s\n\n", operations[operation - 1]);
    printf("%-15s %-10s\n", "USERNAME", "SCORE");
    printf("--------------------------\n");

    for (int i = 0; i < userCount; i++) {
        printf("%-15s %-10d\n", users[i].username, users[i].scores[operation - 1]);
    }
}

void takeQuiz(int operation) {
    int correct = 0;
    for (int i = 0; i < 10; i++) {
        int a, b, userAns, correctAns;
        char op;
        do {
            a = rand() % 50 + 1;
            b = rand() % 50 + 1;
        } while (operation == 4 && a % b != 0);

        correctAns = (operation == 1) ? a + b : (operation == 2) ? a - b : (operation == 3) ? a * b : a / b;
        op = "+-*/"[operation - 1];

        printf("\n%d %c %d = ", a, op, b);
        scanf("%d", &userAns);

        if (userAns == correctAns) {
            printf("BYUTIPUL!\n");
            correct++;
        } else {
            printf("INCORRECT! The correct answer is %d.\n", correctAns);
        }
    }
    printf("\nYOU GOT %d/10 CORRECT ANSWERS!\n\n\n", correct);
    users[currentUserIndex].scores[operation - 1] += correct;
    system("pause");
    system("cls");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 14:27:32