C语言算术测验程序Addition模块首次计分错误求助
修复C语言算术测验程序的计分归属错误
问题现象
- 第一个玩家完成Addition测验时计分正常
- 后续玩家首次进行Addition测验时,所得分数错误计入第一个玩家账号,第二次及之后测验计分正常
- 仅Addition模块出现该问题,其他运算模块无异常
问题根源
程序使用指针currentUser跟踪当前登录用户,但saveUsers(保存数据时按用户名排序数组)和sortLeaderboard(显示排行榜时按对应分数排序数组)会修改users数组的元素顺序,导致currentUser指针指向的数组位置不再对应当前登录用户:
- 后续玩家注册后,
signUp函数会立即调用saveUsers排序数组,此时currentUser指针会错误指向其他用户,首次测验时分数就会加到错误账号 - 第二次登录时,
loadUsers重新读取文件并初始化数组,指针指向正确位置,因此测验恢复正常
修复方案
放弃使用指针跟踪当前用户,改用数组下标索引跟踪,这样无论数组元素如何排序,都能通过索引准确访问当前用户的数据。同时优化随机数初始化逻辑,避免短时间内生成重复随机数。
具体修改步骤
修改全局变量定义
将指针跟踪改为下标索引:// 原代码 User *currentUser = NULL; // 修改为 int currentUserIndex = -1;更新登录逻辑(
login函数)
记录当前用户的数组下标而非指针:// 原代码 currentUser = &users[i]; // 修改为 currentUserIndex = i;更新注册逻辑(
signUp函数)
注册时记录新用户的数组下标:// 原代码 currentUser = &users[userCount]; userCount++; // 修改为 currentUserIndex = userCount; userCount++;更新测验计分逻辑(
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
相关产品推荐
相关产品推荐

