小学数学练习

问题描述
编写一个帮助小学生练习数学的程序,帮助小学生练习 100 以内的四种数学运算:加、减、乘、除。

基本要求
a) 程序应先询问用户的 ID 号(ID 号包括两个大写字母和 4 位数字),例如:
请输入用户 ID 号:AB1234
程序应对输入的 ID 号验证,符合 ID 号要求的格式,然后程序提示三种选择:
(1)开始测试
(2)检查分数
(3)退出
b) 测试:该程序将给出 10 道数学题,例如:
12 * 3 =36
48 + 32 =80
56 / 28 =2
注意:
i)学生将依次回答每一个问题(在等于号后面给出答案),然后给出下一道题。
ii)试题应包含四种数学运算:加、减、乘、除,它们是随机产生的。相邻的问题应该是不同的操作,每个操作必须至少出现一次。
iii)为每道题随机生成数字,但必须确保参与运算的数字和结果都小于 100 且大于零的整数。
iv)十道题做完后,记录学生完成这十道题所用的时间。
v)给每个学生一个分数。将该学生的 ID、成绩和使用时间保存到一个名为 record.txt 的文件中。
vi)在屏幕上输出以下信息:
问题 | 正确答案 | 你的答案
c) 成绩检查:从文件“record.txt”中列出该学生的所有历史成绩。例如:
你以前的记录是:
AB1234 80 150 秒
AB1234 50 182 秒
AB1234 90 98 秒

水平有限,大神轻喷

/*  Program description: addition, subtraction, multiplication and division within 100
 *  Author: HelloW0r1d_1024
 *  Date: 2020/10/10
 *  P.S :
 *       ATTENTION! encoding with UTF-8
 *       The source code can be compiled and run in the following environment after testing
 *       win compiler ver: gcc 9.2.0(MinGW) please use c99 OR c11 standard
 *       linux compiler ver: gcc 9.3.0(wsl Ubuntu);
 *       please use c99 OR c11 standard,and add "-lm" at the end of the complie command // <math.h>
 */

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

#define True 1
#define False 0
#define DIGIT 7 // digit of id  6 + 1('\0')
#define NUM_OF_QUESTIONS 10

#if _WIN32
    #define FILE_PATH "D://record.txt"
#elif __linux__
    #define FILE_PATH "/tmp/record.txt"
#endif

const char op_list[4] = {'+', '-', '*', '/'};
char questions[NUM_OF_QUESTIONS][11] = {'\0'};
int usr_ans[NUM_OF_QUESTIONS];
int std_ans[NUM_OF_QUESTIONS];

typedef struct {
    char id[10];
    int score;
    int time;
} student;

int id_identify(student * stu);
/*  Ask user to enter a string, store it in stu->id[10],
 *  then check if the ID user entered is legal
 *  PARAM: stu - a pointer to type "student"
 *  RETURN: True for legal, False for illegal
 */

int list_factor(int num, int factor[]); 
/*  Put all the factors of the dividend into an array
 *  PARAM: num - Number to be decomposed
 *         factor - a array to store all the factors of num
 *  RETURN: False when num is prime, otherwise True
 */

void op_generator(int arr[]);   
/*  Generate 10 adjacent operators that do not repeat and each appear at least once,
 *  and store them in an array
 *  PARAM: arr - to store 10 operators
 */

void formula_generator(int arr[]);
/*  Randomly generate formulas,
 *  then store them in array "questions"
 *  PARAM: arr - including 10 operators
 */

int scorer(int a[], int b[]);
/*  Calculate user's score
 *  PARAM: usr - including user's answer of 10 questions
 *         std - including standard answer of 10 questions
 *  RETURN: user's score
 */
void print_ans(); 
/* Print question, correct answer, user answer
 */
void clbf(); 
/* Clear the buffer
 */

int main(void) {
    int current_op_list[NUM_OF_QUESTIONS]; // Store the currently randomly generated op
    int begin, end; // Timing
    int option; // 3 options
    char str[81]; // Store each line of the file
    FILE * fp;
    student stu1;
    // If the input is illegal, prompt the user to re-enter
    while (!id_identify(&stu1))
        printf("This id is invalid, please re-enter\n");

    while (True) {
        printf("options:\n");
        printf("(1)start testing\n");
        printf("(2)check score\n");
        printf("(3)exit\n");
        
        char ch1;
        while (scanf("%d", &option) == 0 || option < 1 || option > 3 || (ch1 = getchar()) != '\n') {
            printf("please enter an integer from 1 to 3!\n");
            clbf();
        }
  
        if (3 == option)
            break;

        switch (option) {
            // option1 -- start testing
            case 1:
                if ((fp = fopen(FILE_PATH, "a")) == NULL) {
                    printf("Error! opening file\n");
                    exit(1);
                }

                // question
                srand((unsigned int)time(NULL));
                op_generator(current_op_list);
                formula_generator(current_op_list);

                // answer
                char ch2;
                begin = time(NULL); // Timing begins
                for (int i = 0; i < NUM_OF_QUESTIONS; i++) {
                    printf("%s", questions[i]); // Print a question
                    
                    if (scanf("%d", &usr_ans[i]) == 0 || (ch2 = getchar()) != '\n') {
                        printf("Please enter an integer! Try again.\n");
                        i--; // Answer not finished yet, thus i--
                        clbf();
                    }
                }    
                end = time(NULL); // Timing ends

                stu1.score = scorer(usr_ans, std_ans);
                stu1.time = end - begin;
                // Write id, score, time to file
                fprintf(fp, "%s\t%d\t%ds\n", stu1.id, stu1.score, stu1.time);
                fclose(fp);
                // Print question, correct answer, user answer
                printf("Your score : %d\n", stu1.score);
                print_ans();
                break;

            // option2 -- check score
            case 2 :
                if ((fp = fopen(FILE_PATH, "r")) == NULL) {
                    printf("Error! opening file\n");
                    exit(1);
                }
                // Read records from file
                printf("Your previous records are:\n");
                while (!feof(fp)) {
                    fgets(str, 81, fp);
                    if (feof(fp)) // Prevent the last line of the file from being printed twice
                        break;
                    char tmp[7];
                    for (int i = 0; i < 6; i++)
                        tmp[i] = str[i];
                    if (!strcmp(tmp, stu1.id))
                        fputs(str, stdout);
                }
                fclose(fp);
                break;
        }   
    }
}

int id_identify(student * stu) {
    printf("Please enter your id:");

    // safer than gets()
    if (fgets(stu->id, 10, stdin) && stu->id[0] != '\n') {
        int j = 0;
        while (stu->id[j] != '\n' && stu->id[j] != '\0')
            j++;
        if (stu->id[j] == '\n')
            stu->id[j] = '\0';
        else
            while (getchar() != '\n')
                continue;        
    }

    int flag = True;
    if (strlen(stu->id) != 6)
        flag = False;

    for (int i = 0; i < DIGIT - 1; i++) {
        if (i < 2) {
            if (stu->id[i] < 65 || stu->id[i] > 90)
                flag = False;
        } 
        else {
            if (stu->id[i] < 48 || stu->id[i] > 57)
                flag = False;
        }
    }

    return flag;
}

int list_factor(int num, int factor[]) {
    int tmp = (int)sqrt(num); // Round down
    int cnt = 0;

    for (int i = 2, j = 0; i <= tmp; i++) {
        if (num % i == 0) {
            factor[j] = i;
            cnt++;
            j++; // Index j will only increase if there is a deposit in the array
            if (i != num / i) {
                factor[j] = num / i;
                j++;
            }
        }
    }

    return 0 == cnt ? False : True;
}

void op_generator(int op[]) {
    int op_index; // Temporarily store the random number in [0, 3], compare with the last generated
    int flag[4] = {False};

    // Once each operator does not appear at least once, then regenerate
    while (!(flag[0] && flag[1] && flag[2] && flag[3])) {
        op[0] = rand() % 4;
        for (int i = 1; i < NUM_OF_QUESTIONS; i++) {
            // If the randomly generated operator is the same as the last time,
            // then regenerate until it is different
            do {
                op_index = rand() % 4;
            } while (op_index == op[i - 1]);

            // Once an operator appears randomly, its corresponding flag is changed to True
			flag[op_index] = True;
            op[i] = op_index;
        }
    }
}

void formula_generator(int op[]) {
    int a, b;
    int factor[20] = {0}; // Store all factors of the dividend
    for(int i = 0; i < NUM_OF_QUESTIONS; i++) {
        a = rand() % 99 + 1; // a∈[1, 99]

        switch (op_list[op[i]]) {
            case '+':
                b = rand() % (99 - a) + 1; // b∈[1, 99 - a]
                std_ans[i] = a + b;
                break;

            case '-':
                b = rand() % (a - 1) + 1; // b∈[1, a - 1]
                std_ans[i] = a - b;
                break;

            case '*':
                a = rand() % 48 + 2; // a∈[2, 49]
                b = rand() % ((99 / a) - 1) + 2; // b∈[2, 99 / a]
                std_ans[i] = a * b;
                break;

            case '/':
                // Put all the factors of the dividend in factor[], and regenerate if a is prime
                while (!list_factor(a, factor)) {
                    // factor[] is cleared after each loop
                    for (int i = 0; i < 20; i++)
                        factor[i] = 0;
                    a = rand() % 96 + 4; // a∈[4, 99]
                }
            
                int length = 0;
                for (int j = 0; factor[j]; j++)
                    length++;         
                b = factor[rand() % length]; // Randomly take from the non-1 and non-self factors of a
                for (int i = 0; i < 20; i++)
                        factor[i] = 0;

                std_ans[i] = a / b;
                break;
        }
        snprintf(questions[i], 11, "%2d %c %-2d = ", a, op_list[op[i]], b);
    }
}

int scorer(int usr_ans[], int std_ans[]) {
    int score = 0;

    for (int i = 0; i < NUM_OF_QUESTIONS; i++) {
        if (usr_ans[i] == std_ans[i])
            score += 10;
    }

    return score;
}

void print_ans() {
    printf("questions\tcorrect answer\tyour answer\n");
    for (int i = 0; i < NUM_OF_QUESTIONS; i++)
        printf("%s\t%d\t\t%d\t\n", questions[i], std_ans[i], usr_ans[i]);
}

void clbf() {
    while (getchar() != '\n')
        continue;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值