程序设计基础C语言实验(黑龙江大学)

实验一:  C语言程序的运行环境和运行一个C语言程序的方法

A.实验要求

1.目的和要求

        1.了解所用的计算机系统的基本操作方法,学会使用该计算机系统。

        2.了解如何在该计算机系统上编辑、编译、连接和运行一个 C 语言程序。

        3.通过运行简单的 C 语言程序,初步了解 C 语言源程序的特点。

2.实验项目

        1.了解 WINDOWS 操作系统,学习如何进入正确的系统工作状态,掌握其操作命令和应用程序的使用,包括如何建立目录,查找文件,列目录,复制文件等。

        2.了解 Visual C++  集成开发环境。

        3.输入教材中第 2 章和第 3 章中的例子、实验题、习题,调试运行程序, 了解在 VC++环境下如何运行 C 程序。

3.实验指导

        首先进入 Visual C++环境,Visual C++环境界面如下。

                 程序设计基础C语言实验(黑龙江大学)_第1张图片

图 1-1 环境界面图

        在 Visual C++环境下设计并编写一个 C 语言程序后,要上机运行一般要进过一下几个步骤。

1.建立并编辑源程序

        在图 1-2 所示的界面中,选择“Files | new”命令,在打开的 New 对话框中(见图 1-3),选择“Files”选项卡中的“C++ Source File”选项,在 File 文本框中输入文件名,并选择保存路径(也可不选择路径。若不选择路径,建立的文件会放到缺省路径中),然后单击“OK ”按钮,建立一个扩展名为“.c”的 C 语言源文件。

        注意:若不以“.c”作为扩展名,系统将按扩展名“.cpp”保存。

        然后在“程序编辑”窗口按照 C 语言语法规则输入和编辑源程序,修改过程见图 1-4。编辑完成后保存源程序,具体操作方法见图 1-5。

                 程序设计基础C语言实验(黑龙江大学)_第2张图片

                                          图 1-2 新建文件界面图
                    程序设计基础C语言实验(黑龙江大学)_第3张图片

图 1-3 选择文件类型界面图

                    程序设计基础C语言实验(黑龙江大学)_第4张图片

图 1-4 编辑界面图

                        程序设计基础C语言实验(黑龙江大学)_第5张图片

图 1-5 保存文件界面图

2.编译

        计算机的 CPU 只能执行二进制的机器指令,因此需要经过编译将源程序转换为由机器指令组成的目标程序。具体编译过程见图 1-6。

                      程序设计基础C语言实验(黑龙江大学)_第6张图片

                                                      图 1-6 编译文件界面图

3.链接

        在源程序中,输入、输出以及常用函数运算通常不是由用户编写的,而是直接调用系统函数库中的库函数。因此,必须把库函数的处理过程链接到经过编译生成的目标程序中,以生成可执行程序。具体链接过程见图 1-7。

                           程序设计基础C语言实验(黑龙江大学)_第7张图片

图 1-6 链接文件界面图

4.运行程序

        运行过程见图 1-8。

        无论是出现编译错误、链接错误,还是运行错误,都需要修改源程序,并对它重新编译、链接和运行,直到将程序调试正确为止。

                          程序设计基础C语言实验(黑龙江大学)_第8张图片

图 1-8 运行文件界面图

B.代码实现

略,随便写

#include 

int main()
{
    int a, b, max;
    scanf("%d%d", &a, &b);
    if (a > b)
        max = a;
    else
        max = b;
    printf("%d", max);
    return 0;
}

实验二:  选择控制结构程序设计

A.实验要求

一、实验目的和要求

        1.掌握定义整型、字符型和实型变量的方法,以及对它们赋值的方法。

        2.学会使用 C 语言的有关算术运算符,以及包含这些运算符的表达式。

        3. 学会正确使用逻辑运算符和逻辑表达式。

        4.熟练掌握 if 语句和 switch 语句的格式及应用。

二、实验项目

        1.任意输入 3 个数,按从小到大输出。 (0.5 分)

        2.求一元二次方程ax2 + bx c = 0 的根,其中 a、b、c 均为实数,a≠0。其值由键盘输入。 (0.5 分)

        3.用拼音首字母查姓氏。如:输入字母’a’,输出“安、艾”等,要求至少能查 a 至 e 字母开头的 5 类姓氏,其余的可输出“其它”。 (1 分)

三、实验指导

        题目 1:对任意的输入 3 个数按从小到大输出,程序流程图如 2-1 所示。可通过 if 语句形成单分支结构实现。

                                  程序设计基础C语言实验(黑龙江大学)_第9张图片

                                     图 2-1 三个数排序的程序流程图

        题目 2:求一元二次方程 ax2 + bx c = 0 的根,程序流程图如 2-2 所示。可通过 if-else 语句形成多分支结构实现。

程序设计基础C语言实验(黑龙江大学)_第10张图片

                                         图 2-2 求一元二次方程根的程序流程图

        题目 3用拼音首字母查姓氏。如 输入字母’a’,输出安、艾等。程序流程 图如 2-3 所示。可通过 switch 语句形成多分支结构实现。

                     程序设计基础C语言实验(黑龙江大学)_第11张图片

图 2-3 用拼音首字母查姓氏的程序流程图

B.代码实现

test1.c

#include 

int main()
{
    int a, b, c;
    char ch;
    double d;

    printf("请输入三个整数:");
    scanf("%d%d%d", &a, &b, &c);

    if (a > b)
    {
        int temp = a;
        a = b;
        b = temp;
    }
    if (a > c)
    {
        int temp = a;
        a = c;
        c = temp;
    }
    if (b > c)
    {
        int temp = b;
        b = c;
        c = temp;
    }

    printf("从小到大排序后的结果为:%d %d %d", a, b, c);

    return 0;
}

test2.c

#include 
#include 

int main()
{
    double a, b, c, delta;

    printf("请输入一元二次方程的系数 a, b, c:");
    scanf("%lf %lf %lf", &a, &b, &c);

    delta = b * b - 4 * a * c;

    if (delta > 0)
    {
        double x1 = (-b + sqrt(delta)) / (2 * a);
        double x2 = (-b - sqrt(delta)) / (2 * a);
        printf("方程有两个不相等的实根:x1 = %.2lf, x2 = %.2lf", x1, x2);
    }
    else if (delta == 0)
    {
        double x = -b / (2 * a);
        printf("方程有一个实根:x = %.2lf", x);
    }
    else
    {
        double realPart = -b / (2 * a);
        double imaginaryPart = sqrt(-delta) / (2 * a);
        printf("方程有两个共轭虚根:x1 = %.2lf + %.2lfi, x2 = %.2lf - %.2lfi", realPart, imaginaryPart, realPart, imaginaryPart);
    }

    return 0;
}

test3.c

#include 
#include 

int main()
{
    char initial;
    printf("请输入拼音首字母:");
    scanf("%c", &initial);

    switch (initial)
    {
    case 'a':
            printf("安、艾");
            break;
        case 'b':
            printf("毕,白");
            break;
        case 'c':
            printf("陈,常");
            break;
        case 'd':
            printf("丁,党");
            break;
        case 'e':
            printf("鄂");
            break;
        default:
            printf("其他");
    }

    return 0;
}

实验三:  循环控制结构程序设计

A.实验要求

一、目的和要求

熟练掌握用 while 语句、do-while 语句和 for 语句实现循环的方法,并掌握用循环的方法实现各种算法。

二、实验项目

1.以四种形式输出九九乘法表。 (1 分)

        1X1= 1

        1X2= 2    2X2= 4                  
        1X3= 3    2X3= 6    3X3= 9            
        1X4= 4    2X4= 8    3X4=12    4X4=16        
        1X5= 5    2X5=10    3X5=15    4X5=20    5X5=25    
        1X6= 6    2X6=12    3X6=18    4X6=24    5X6=30    6X6=36        
        1X7= 7    2X7=14    3X7=21    4X7=28    5X7=35    6X7=42    7X7=49    
        1X8= 8    2X8=16    3X8=24    4X8=32    5X8=40    6X8=48    7X8=56    8X8=64
        1X9= 9    2X9=18    3X9=27    4X9=36    5X9=45    6X9=54    7X9=63    8X9=72    9X9=81


1X1= 1    1X2= 2    1X3= 3    1X4= 4    1X5= 5    1X6= 6    1X7= 7    1X8= 8    1X9= 9

                2X2= 4    2X3= 6    2X4= 8    2X5=10    2X6=12    2X7=14    2X8=16    2X9=18
                               3X3= 9    3X4=12    3X5=15    3X6=18    3X7=21    3X8=24    3X9=27
                                               4X4=16    4X5=20    4X6=24    4X7=28    4X8=32    4X9=36
                                                               5X5=25    5X6=30    5X7=35    5X8=40    5X9=45
                                                                                6X6=36    6X7=42    6X8=48    6X9=54
                                                                                                7X7=49    7X8=56    7X9=63
                                                                                                                 8X8=64    8X9=72
                                                                                                                                  9X9=81

1X1= 1

1X2= 2 2X2= 4

1X3= 3 2X3= 6 3X3= 9

1X4= 4 2X4= 8 3X4=12 4X4=16

1X5= 5 2X5=10 3X5=15 4X5=20 5X5=25

1X6= 6 2X6=12 3X6=18 4X6=24 5X6=30 6X6=36

1X7= 7 2X7=14 3X7=21 4X7=28 5X7=35 6X7=42 7X7=49

1X8= 8 2X8=16 3X8=24 4X8=32 5X8=40 6X8=48 7X8=56 8X8=64

                1X9= 9 2X9=18 3X9=27 4X9=36 5X9=45 6X9=54 7X9=63 8X9=72 9X9=81

9X9=81

8X8=64 8X9=72

7X7=49 7X8=56 7X9=63

6X6=36 6X7=42 6X8=48 6X9=54

5X5=25 5X6=30 5X7=35 5X8=40 5X9=45

4X4=16 4X5=20 4X6=24 4X7=28 4X8=32 4X9=36

3X3= 9 3X4=12 3X5=15 3X6=18 3X7=21 3X8=24 3X9=27

2X2= 4 2X3= 6 2X4= 8 2X5=10 2X6=12 2X7=14 2X8=16 2X9=18

1X1= 1 1X2= 2 1X3= 3 1X4= 4 1X5= 5 1X6= 6 1X7= 7 1X8= 8 1X9= 9

2. 输出 1-100 间的素数。要求:每行输出 5 个数,每个数占 6 位。 (1 分)

3.实现“小学生计算机辅助教学系统”。 (2 分)

        请编写一个程序来帮助小学生学习四则运算,参考本章介绍的猜数游戏程序,按下列任务要求以循序渐进的方式编程。

        任务 1:程序首先随机产生两个 1~10 之间的正整数,在屏幕上打印出问题,例如:6*7= ?

然后让学生输入答案。程序检查学生输入的答案是否正确。若正确,则打印“Right”,然后问下一个问题;否则打印“Wrong!  Please try again.”,然后提示学生重做,直到答对为止。

        任务 2:在上述功能实现的基础之上,当学生回答错误时,最多给三次重做的机会,三次仍未做对,则提示“Wrong! You have tried three times! Test over!”,程序结束。

        任务 3:在任务 1 的基础之上,连续做 10 道乘法运算题,不给机会重做, 若学生回答正确,则显示“Right!”,否 则 显示“Wrong!”。10 道题全部做完后,按每题 10 分统计并输出总分,同时为了记录学生能力提高的过程,再输出学生的回答正确率(即答对题数除以总题数的百分比)。

        任务 4:在任务 3 的基础上,通过计算机随机产生 10 道四则运算题,两个操作数为 1~10 之间的 机数,运算类型为随机产生的加、减、乘、整除中的任意一种,不给机会重做,如果学生回答正确,则显示“Right!”,否则显示“Wrong!”。10 道题全部做完后,按每题 10 分统计总得分,然后打印出总分和学生的回答正确率。

        任务 5:在任务 4 的基础上,为使学生通过反复练习熟练掌握所学内容,在学生完成 10 道运算题后,若学生回答正确率低于 75%,则重新做 10 道题,直到回答正确率高于 75%时才退出程序。

三、实验指导

        题目 1打印九九表的程序流程图如图 3-1 所示,可用两重循环实现。

                                         程序设计基础C语言实验(黑龙江大学)_第12张图片

图 3-1 打印九九表的程序流程图

        题目 2素数就是仅能被 1 和它自身整除的整数(只有 2 个约数的自然数是素数.)。判定一个整数 i 是否为素数就是要判定整数 i 能否被除 1 和它自身之外的任意整数整除,若都不能整除,则 i 为素数。

        程序设计时 j 可以从 2 开始,到 i-1 为止(或到该整数 i 的 1/2 为止),用 j 依次去除需要判定的整数,只要存在可以整除该数的情况,即可确定要判断的整数不是素数,否则是素数。输出 1-100 间的素数的程序流程图如图 3-2 所示,可用两重循环实现。输出 1-100 间的素数的程序流程图如图 3-2 所示,可用两重循环实现。

                                         程序设计基础C语言实验(黑龙江大学)_第13张图片

3-2  1-100 间的素数的程序流程图

B.代码实现

test1.c

#include 
#define N 9
// 第一种形式
void printMultiplicationTable1()
{
    for (int i = 1; i <= 9; i++)
    {
        for (int j = 1; j <= i; j++)
        {
            printf("%dX%d=%2d\t", j, i, i * j);
        }
        printf("\n");
    }
}

// 第二种形式
void printMultiplicationTable2()
{
    for (int i = 1; i <= 9; i++)
    {
        for (int k = 1; k < i; k++)
        {
            printf("\t\t");
        }

        for (int j = i; j <= 9; j++)
        {
            printf("%dX%d=%-4d\t", i, j, i * j);
        }
        printf("\n");
    }
}

// 第三种形式
void printMultiplicationTable3()
{
    int i, j, k, space;

    space = 9 - 1;

    for (i = 1; i <= 9; i++)
    {
        for (j = 1; j <= space; j++)
        {
            printf("\t");
        }

        space--;

        for (k = 1; k <= i; k++)
        {
            printf("%dX%d=%-10d", k, i, k * i);
        }

        printf("\n");
    }
}

// 第四种形式
void printMultiplicationTable4()
{
    
    int i, j;
    int a[N][N] = {0}; // 存储乘法表中每个位置的值

    // 计算每个位置的值
    for (i = 0; i < N; i++)
    {
        for (j = 0; j <= i; j++)
        {
            a[i][j] = (N - i + j) * (N - i);
        }
    }

    // 输出金字塔形
    for (i = 0; i < N; i++)
    {
        for (j = 0; j < N - i - 1; j++)
        {
            printf("    ");
        }

        for (j = 0; j <= i; j++)
        {
            printf("%2dX%-2d=%-3d    ", N - i,N - i + j,  a[i][j]);
        }

        printf("\n");
    }
}

int main()
{
    printf("第一种形式:\n");
    printMultiplicationTable1();

    printf("\n第二种形式:\n");
    printMultiplicationTable2();

    printf("\n第三种形式:\n");
    printMultiplicationTable3();

    printf("\n第四种形式:\n");
    printMultiplicationTable4();

    return 0;
}

test2.c

#include 

int main() {
    int count = 0; // 计数器,每行输出 5 个数
    for (int i = 2; i <= 100; i++) { // 从 2 开始遍历到 100
        int is_prime = 1; // 标记是否为素数
        for (int j = 2; j < i; j++) { // 遍历 2 到 i-1
            if (i % j == 0) { // 如果 i 能被 j 整除,则不是素数
                is_prime = 0;
                break;
            }
        }
        if (is_prime) { // 如果是素数
            printf("%6d", i); // 输出数字
            count++; // 计数器加 1
            if (count == 5) { // 如果已经输出了 5 个数
                printf("\n"); // 换行
                count = 0; // 计数器清零
            }
        }
    }
    return 0;
}

test3.c

#include 
#include 
#include 

int main() {
    int score = 0;
    int correctCount = 0;
    int totalCount = 0;
    int retryCount = 0;

    srand(time(NULL));

    while (1) {
   
        int num1 = rand() % 10 + 1;
        int num2 = rand() % 10 + 1;

        int operation = rand() % 4 + 1;
        char operatorChar;

        int correctAnswer;
        switch (operation) {
            case 1:
                operatorChar = '+';
                correctAnswer = num1 + num2;
                break;
            case 2:
                operatorChar = '-';
                correctAnswer = num1 - num2;
                break;
            case 3:
                operatorChar = '*';
                correctAnswer = num1 * num2;
                break;
            case 4:
                operatorChar = '/';
                correctAnswer = num1 / num2;
                break;
        }

      
        printf("%d %c %d = ?\n", num1, operatorChar, num2);
        int studentAnswer;
        scanf("%d", &studentAnswer);

        if (studentAnswer == correctAnswer) {
            printf("Right!\n");
            correctCount++;
            score += 10;
        } else {
            printf("Wrong! Please try again.\n");
            retryCount++;
            if (retryCount >= 3) {
                printf("Wrong! You have tried three times! Test over!\n");
                break;
            }
        }

        totalCount++;

        if (totalCount == 10) {
            printf("You have completed 10 questions.\n");
            printf("Your score: %d\n", score);
            printf("Correct rate: %.2f%%\n", (float)correctCount / totalCount * 100);

            if ((float)correctCount / totalCount < 0.75) {
                printf("Your correct rate is less than 75%. Retake the test.\n");
                retryCount = 0;
                correctCount = 0;
                totalCount = 0;
            } else {
                printf("Congratulations! You have passed the test.\n");
                break;
            }
        }
    }

    return 0;
}

实验四:函数

A.实验要求

一、目的和要求

        1.掌握函数定义、函数调用、函数声明的方法。

        2.熟悉模块化程序设计方法。

        3.掌握函数的嵌套调用方法。

        4.掌握函数递归调用方法。

        5.掌握调试程序和查帮助的基本方法。

二、实验内容

1. 用模块化程序设计方法重新编程实现“小学生计算机辅助教学系统”。要求:

① 在主函数中显示菜单,其格式如下:******************************************************************************

  • 1.  任务 1:随机产生 1-10 之间正整数,出乘法问题,直到学生答对为止。 
  • 2.  任务 2:在任务 1 基础上,当学生答错时,最多给三次机会。 
  • 3.  任务 3:在任务 1 基础上,连做 10 道乘法题,不给机会重做,统计总分、正确率。*
  • 4.  任务 4:在任务 3 基础上,随机产生 10 道四则运算题,不给机会重做,统计总分、正确率。 *
  • 5.  任务 5:在任务 4 基础上,若回答正确率低于 75%,则再做 10 道题,直到正确率高于 75%为止。
  • 6.  退出

**********************************************************************************

要求该菜单能反复使用,直到选择“退出”方可结束。

② 至少包括如下函数

  1. 每个任务封装成一个函数。
  2. 生成随机数函数。
  3. 成绩统计函数(具有统计总分与计算正确率的功能)。
  4. 判断答题是否正确函数。
  5. 对除法运算,判断产生的随机数是否合法。[选作]

2. 编写求一个数阶乘的递归的和非递归的函数,并在主函数中分别调用, 输出 10 以内的所有数的阶乘。

三、实验指导

题目 1. “小学生计算机辅助教学系统”的模块结构如图 4-1 所示。     

程序设计基础C语言实验(黑龙江大学)_第14张图片

                     图 4-1“小学生计算机辅助教学系统”模块结构图

题目 2.  编写求一个数阶乘的非递归的函数,并在主函数中分别调用,输出 10以内的所有数的阶乘。程序流程图如图 4-2 所示。

                                                   程序设计基础C语言实验(黑龙江大学)_第15张图片

图 4-2 求自然数 n 的阶乘的程序流程图

B.代码实现

test1.c

#include 
#include 
#include 

// 随机数生成函数,用于生成min-max之间的随机正整数
int random_int(int min, int max)
{
    srand(time(NULL));
    return rand() % (max - min + 1) + min;
}

// 判断输入的字符串是否代表一个合法的数字
int is_valid_input(char *str)
{
    char *p = str;
    while (*p != '\0')
    {
        if (*p < '0' || *p > '9')
            return 0;
        p++;
    }
    return 1;
}

// 判断乘法题目答案是否正确
int check_answer(int a, int b, int answer)
{
    return a * b == answer;
}

// 显示菜单
void show_menu()
{
    printf("请选择任务(输入数字序号):\n");
    printf("1.  任务 1:随机产生 1-10 之间正整数,出乘法问题,直到学生答对为止。\n");
    printf("2.  任务 2:在任务 1 基础上,当学生答错时,最多给三次机会。\n");
    printf("3.  任务 3:在任务 1 基础上,连做 10 道乘法题,不给机会重做,统计总分、正确率。\n");
    printf("4.  任务 4:在任务 3 基础上,随机产生 10 道四则运算题,不给机会重做,统计总分、正确率。\n");
    printf("5.  任务 5:在任务 4 基础上,若回答正确率低于 75%%,则再做 10 道题,直到正确率高于 75%% 为止。\n");
    printf("6.  退出\n");
}

// 任务1
void task1()
{
    int a = random_int(1, 10);
    int b = random_int(1, 10);
    printf("请回答%d x %d = ", a, b);
    int answer;
    scanf("%d", &answer);
    while (!check_answer(a, b, answer))
    {
        printf("回答错误,请重新回答:");
        scanf("%d", &answer);
    }
    printf("回答正确!\n");
}

// 任务2
void task2()
{
    int a = random_int(1, 10);
    int b = random_int(1, 10);
    int chance = 3;
    int correct = 0;
    while (chance > 0)
    {
        printf("请回答%d x %d = ", a, b);
        int answer;
        scanf("%d", &answer);
        if (check_answer(a, b, answer))
        {
            printf("回答正确!\n");
            correct = 1;
            break;
        }
        else
        {
            chance--;
            if (chance > 0)
                printf("回答错误,还有%d次机会,请重新回答:", chance);
            else
                printf("回答错误!正确答案是%d。\n", a * b);
        }
    }
    if (correct)
    {
        printf("恭喜你通过任务2!\n");
    }
    else
    {
        printf("任务2失败!\n");
    }
}

// 任务3
void task3()
{
    int score = 0;
    int correct_count = 0;
    for (int i = 1; i <= 10; i++)
    {
        int a = random_int(1, 10);
        int b = random_int(1, 10);
        printf("第%d道题:请回答%d x %d = ", i, a, b);
        int answer;
        scanf("%d", &answer);
        if (check_answer(a, b, answer))
        {
            printf("回答正确!\n");
            score += 10;
            correct_count++;
        }
        else
        {
            printf("回答错误!正确答案是%d。\n", a * b);
        }
    }
    printf("任务3完成,总分:%d,正确率:%.2f%%。\n", score, 100.0 * correct_count / 10);
}

// 任务4
void task4()
{
    int score = 0;
    int correct_count = 0;
    for (int i = 1; i <= 10; i++)
    {
        int a = random_int(1, 100);
        int b = random_int(1, 100);
        int op = random_int(1, 4); // 随机选择运算符(1-加法,2-减法,3-乘法,4-除法)
        char op_char;
        int result;
        switch (op)
        {
        case 1:
            op_char = '+';
            result = a + b;
            break;
        case 2:
            op_char = '-';
            result = a - b;
            break;
        case 3:
            op_char = 'x';
            result = a * b;
            break;
        case 4:
            op_char = '/';
            while (b == 0 || a % b != 0 || a / b > 100)
            { // 避免产生不合法的除法题目
                a = random_int(1, 100);
                b = random_int(1, 100);
            }
            result = a / b;
            break;
        }
        printf("第%d道题:请回答%d %c %d = ", i, a, op_char, b);
        char answer_str[20];
        scanf("%s", answer_str); // 使用字符串读入用户的答案,方便后续判断
        if (is_valid_input(answer_str) && check_answer(a, b, atoi(answer_str)))
        {
            printf("回答正确!\n");
            score += 10;
            correct_count++;
        }
        else
        {
            printf("回答错误!正确答案是%d。\n", result);
        }
    }
    printf("任务4完成,总分:%d,正确率:%.2f%%。\n", score, 100.0 * correct_count / 10);
}

// 任务5
void task5()
{
    int score = 0;
    int correct_count = 0;
    int restart_count = 0;
    while (1)
    {
        for (int i = 1; i <= 10; i++)
        {
            int a = random_int(1, 100);
            int b = random_int(1, 100);
            int op = random_int(1, 4); // 随机选择运算符(1-加法,2-减法,3-乘法,4-除法)
            char op_char;
            int result;
            switch (op)
            {
            case 1:
                op_char = '+';
                result = a + b;
                break;
            case 2:
                op_char = '-';
                result = a - b;
                break;
            case 3:
                op_char = 'x';
                result = a * b;
                break;
            case 4:
                op_char = '/';
                while (b == 0 || a % b != 0 || a / b > 100)
                { // 避免产生不合法的除法题目
                    a = random_int(1, 100);
                    b = random_int(1, 100);
                }
                result = a / b;
                break;
            }
            printf("第%d道题:请回答%d %c %d = ", i, a, op_char, b);
            char answer_str[20];
            scanf("%s", answer_str); // 使用字符串读入用户的答案,方便后续判断
            if (is_valid_input(answer_str) && check_answer(a, b, atoi(answer_str)))
            {
                printf("回答正确!\n");
                score += 10;
                correct_count++;
            }
            else
            {
                printf("回答错误!正确答案是%d。\n", result);
            }
        }
        double correct_rate = 1.0 * correct_count / 10;
        printf("正确率:%.2f%%。\n", 100.0 * correct_rate);
        if (correct_rate >= 0.75)
        {
            printf("任务5完成,总分:%d,正确率:%.2f%%。\n", score, 100.0 * correct_count / 10);
            break;
        }
        else
        {
            printf("正确率未达标(低于75%%),重新开始任务5!\n");
            score = 0;
            correct_count = 0;
            restart_count++;
            if (restart_count > 5)
            { // 最多重做5次
                printf("由于连续多次未达标,任务失败!\n");
                break;
            }
        }
    }
}

// 主函数
int main()
{
    while (1)
    {
        show_menu();
        int choice;
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
            task1();
            break;
        case 2:
            task2();
            break;
        case 3:
            task3();
            break;
        case 4:
            task4();
            break;
        case 5:
            task5();
            break;
        case 6:
            printf("感谢使用本程序!\n");
            exit(0);
        default:
            printf("无效的选择!请重新选择。\n");
            break;
        }
    }
    return 0;
}

test2.c

#include 

// 递归函数
int factorial_recursive(int n)
{
    if (n == 0)
    {
        return 1;
    }
    else
    {
        return n * factorial_recursive(n - 1);
    }
}

// 非递归函数
int factorial_non_recursive(int n)
{
    int result = 1;
    for (int i = 1; i <= n; i++)
    {
        result *= i;
    }
    return result;
}

int main()
{
    int n = 10;
    printf("递归计算10的阶乘结果:%d", factorial_recursive(n));
    printf("\n");
    printf("非递归计算10的阶乘结果:%d", factorial_non_recursive(n));
    return 0;
}

实验五:数组

A.实验要求

一、目的和要求

        1.掌握数组的定义、赋值和输入/输出方法。

        2.掌握与数组有关的算法(例如:各种排序算法)。

二、实验内容

        1.用选择排序法对 10 个整数进行排序。要求在主函数中分别调用输入、排序、输出三个函数实现。【必做】

        2.求 3*3 矩阵中最大元素所在的行列位置。要求在主函数中分别调用输入函数、求最大元素值的函数、输出函数实现。【必做】

三、实验指导

        题目 1:用选择排序法对 n 个整数进行排序,程序流程图如图 5-1 所示。                   程序设计基础C语言实验(黑龙江大学)_第16张图片

                                图 5-1 选择排序程序流程图

B.代码实现

test1.c

#include 

// 函数声明
void inputArray(int arr[], int size);
void selectionSort(int arr[], int size);
void printArray(int arr[], int size);

int main() {
    int arr[10];

    printf("Enter 10 integers:\n");
    inputArray(arr, 10);

    printf("Original array: ");
    printArray(arr, 10);

    selectionSort(arr, 10);

    printf("Sorted array: ");
    printArray(arr, 10);

    return 0;
}

// 输入函数
void inputArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        scanf("%d", &arr[i]);
    }
}

// 选择排序算法
void selectionSort(int arr[], int size) {
    for (int i = 0; i < size - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < size; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        // 交换元素
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}

// 输出函数
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

test2.c

#include 

// 函数声明
void inputMatrix(int mat[][3]);
void findMaxElement(int mat[][3], int *row, int *col);
void printMatrix(int mat[][3]);

int main() {
    int matrix[3][3];
    int maxRow, maxCol;

    printf("Enter a 3x3 matrix:\n");
    inputMatrix(matrix);

    printf("Matrix:\n");
    printMatrix(matrix);

    findMaxElement(matrix, &maxRow, &maxCol);

    printf("Maximum element is %d at row %d and column %d\n", matrix[maxRow][maxCol], maxRow + 1, maxCol + 1);

    return 0;
}

// 输入函数
void inputMatrix(int mat[][3]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            scanf("%d", &mat[i][j]);
        }
    }
}

// 查找最大元素的函数
void findMaxElement(int mat[][3], int *row, int *col) {
    int max = mat[0][0];
    *row = 0;
    *col = 0;

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (mat[i][j] > max) {
                max = mat[i][j];
                *row = i;
                *col = j;
            }
        }
    }
}

// 输出函数
void printMatrix(int mat[][3]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
}

实验六:  指针

A.实验要求

一、目的和要求

1.掌握指针的概念,掌握定义和使用指针变量的方法。

2.熟悉指针作函数参数。

3.掌握使用数组的指针和指向数组的指针变量。

二、实验内容

1.通过指针型参数实现互换两个变量的值的函数。【必做】

2.输入 10 个整数,将其中最小的数与第一个数互换,把最大的数与最后一个数互换。写三个函数分别实现:(1)输入 10 个数;(2)实现具体互换处理,并通过指针型参数的间接运算返回最大值和最小值;(3)输出 10 个数。【必做】

B.代码实现

test1.c

#include 

// 函数用于交换两个整数的值
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int num1 = 10;
    int num2 = 20;

    printf("交换前:\n");
    printf("num1 = %d\n", num1);
    printf("num2 = %d\n", num2);

    // 调用 swap 函数来交换 num1 和 num2 的值
    swap(&num1, &num2);

    printf("交换后:\n");
    printf("num1 = %d\n", num1);
    printf("num2 = %d\n", num2);

    return 0;
}

test2.c

#include 

void swap(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
// Function to input 10 integers
void inputArray(int arr[], int size) {
    printf("Enter 10 integers:\n");
    for (int i = 0; i < size; i++) {
        scanf("%d", &arr[i]);
    }
}

// Function to find and swap the minimum and maximum elements
void swapMinMax(int arr[], int size) {
    int minIndex = 0, maxIndex = 0;
    for (int i = 1; i < size; i++) {
        if (arr[i] < arr[minIndex]) {
            minIndex = i;
        }
        if (arr[i] > arr[maxIndex]) {
            maxIndex = i;
        }
    }

    // Swap minimum with the first element
    swap(&arr[0], &arr[minIndex]);
    // If the maximum index was 0, it is now at minIndex after the previous swap
    // So, update maxIndex
    if (maxIndex == 0) {
        maxIndex = minIndex;
    }
    // Swap maximum with the last element
    swap(&arr[size - 1], &arr[maxIndex]);
}

// Function to print 10 integers
void printArray(int arr[], int size) {
    printf("Modified array: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int arr[10];
    inputArray(arr, 10);
    swapMinMax(arr, 10);
    printArray(arr, 10);

    return 0;
}

实验七:字符串

A.实验要求

一、目的和要求

  1. 掌握字符数组的定义、字符串的存储、输入、输出方法。
  2. 学会使用字符串函数。
  3. 学会设计与实现字符串函数。

二、实验内容

1.用一个函数实现两个字符串的比较,即自己编写一个 Mystrcmp 函数,函数原型为 int Mystrcmp (char *p1,char *p2);设 P1 指向字符串 S1,P2 指向字符串

S2。要求:当 S1=S2 时,返回值为 0;若 S1>S2,返回值为正数;若 S1

2. 设计一个函数 Mystrcat()将两个字符串连起来(本题不可直接调用库函数 strcat())。

三、实验指导

        题目 1从第 1 个字符开始将两个字符串的对应字符进行比较,若对应字符相同,则继续比较下一对对应的字符,直到对应字符不相等或至少有一个串扫完为止。当两串同时扫完,意味着两串相等,此时返回 0,否则返回它们两者第一个不同字符的 ASCII 码差值。如果 S1>S2,则输出正值,如果 S1

B.代码实现

test1.c

#include 

int Mystrcmp(const char *p1, const char *p2) {
    while (*p1 == *p2) {
        if (*p1 == '\0') {
            return 0; // 字符串相等
        }
        p1++;
        p2++;
    }
    return *p1 - *p2; // 返回差值
}

int main() {
    char str1[] = "hello";
    char str2[] = "world";
    
    int result = Mystrcmp(str1, str2);
    
    if (result == 0) {
        printf("str1 等于 str2\n");
    } else if (result > 0) {
        printf("str1 大于 str2\n");
    } else {
        printf("str1 小于 str2\n");
    }
    
    return 0;
}

test2.c

#include 

void Mystrcat(char *dest, const char *src)
{
    while (*dest != '\0')
    {
        dest++;
    }

    while (*src != '\0')
    {
        *dest = *src;
        dest++;
        src++;
    }

    *dest = '\0'; // 添加字符串结束标志
}

int main()
{
    char str1[50] = "Hello, ";
    char str2[] = "world!";

    Mystrcat(str1, str2);

    printf("拼接后的字符串: %s\n", str1);

    return 0;
}

实验八:  指针和数组

A.实验要求

一、目的和要求

  1. 熟悉二维数组作函数参数时函数定义、函数调用方法。
  2. 模块化程序设计及增量测试法。
  3. 掌握指针与二维数组的关系,并学会通过指针对二维数组进行操作。
  4. 掌握指针数组的使用方法。

二、实验内容

        1.有一个班 5 个学生,3 门课。用二维数组作函数参数编程实现如下菜单驱动的学生成绩管理系统:(2 分)

****************************************************************

  1. 录入每个学生的学号和成绩;
  2. 求第一门课的平均分;
  3. 找出有 2 门以上课程不及格的学生,输出他们的学号、全部课程成绩、平均成绩;
  4. 找出平均成绩 90 分以上或全部课成绩在 85 分以上的学生。
  5. 退出

****************************************************************

要求:

  1. 分别编 4 个函数,通过指针运算实现以上 4 个功能。
  2. 菜单可以反复使用,直到选择退出。

B.代码实现

test.c

#include 

#define NUM_STUDENTS 5
#define NUM_COURSES 3

struct Student
{
    int id;
    int grades[NUM_COURSES];
};

void inputGrades(struct Student students[])
{
    printf("请输入每个学生的学号和成绩:\n");
    for (int i = 0; i < NUM_STUDENTS; i++)
    {
        printf("学生%d的学号: ", i + 1);
        scanf("%d", &students[i].id);
        printf("学生%d的成绩(%d门课,用空格分隔): ", i + 1, NUM_COURSES);
        for (int j = 0; j < NUM_COURSES; j++)
        {
            scanf("%d", &students[i].grades[j]);
        }
    }
}

float calculateFirstCourseAverage(struct Student students[])
{
    float total = 0.0;
    for (int i = 0; i < NUM_STUDENTS; i++)
    {
        total += students[i].grades[0];
    }
    return total / NUM_STUDENTS;
}

void studentsWithTwoFailures(struct Student students[])
{
    printf("以下学生有2门以上课程不及格:\n");
    for (int i = 0; i < NUM_STUDENTS; i++)
    {
        int failCount = 0;
        for (int j = 0; j < NUM_COURSES; j++)
        {
            if (students[i].grades[j] < 60)
            {
                failCount++;
            }
        }
        if (failCount >= 2)
        {
            float average = 0.0;
            for (int j = 0; j < NUM_COURSES; j++)
            {
                average += students[i].grades[j];
            }
            average /= NUM_COURSES;
            printf("学号:%d,成绩:", students[i].id);
            for (int j = 0; j < NUM_COURSES; j++)
            {
                printf("%d ", students[i].grades[j]);
            }
            printf("平均成绩:%f\n", average);
        }
    }
}

void highAchievers(struct Student students[])
{
    printf("以下学生平均成绩90分以上或全部课程成绩85分以上:\n");
    for (int i = 0; i < NUM_STUDENTS; i++)
    {
        float average = 0.0;
        int allCoursesAbove85 = 1;
        for (int j = 0; j < NUM_COURSES; j++)
        {
            average += students[i].grades[j];
            if (students[i].grades[j] < 85)
            {
                allCoursesAbove85 = 0;
            }
        }
        average /= NUM_COURSES;
        if (average >= 90 || allCoursesAbove85)
        {
            printf("学号:%d,成绩:", students[i].id);
            for (int j = 0; j < NUM_COURSES; j++)
            {
                printf("%d ", students[i].grades[j]);
            }
            printf("平均成绩:%f\n", average);
        }
    }
}

int main()
{
    struct Student students[NUM_STUDENTS];

    int choice;
    do
    {
        printf("****************************************************\n");
        printf("(1)录入每个学生的学号和成绩:\n");
        printf("(2)求第一门课的平均分:\n");
        printf("(3)找出有2门以上课程不及格的学生,输出他们的学号、全部课程成绩、平均成绩;\n");
        printf("(4)找出平均成绩90分以上或全部课成绩在85分以上的学生。\n");
        printf("(5)退出\n");
        printf("****************************************************\n");
        printf("请选择操作(1-5): ");
        scanf("%d", &choice);

        switch (choice)
        {
        case 1:
            inputGrades(students);
            break;
        case 2:
            printf("第一门课的平均分为:%f\n", calculateFirstCourseAverage(students));
            break;
        case 3:
            studentsWithTwoFailures(students);
            break;
        case 4:
            highAchievers(students);
            break;
        case 5:
            printf("退出程序\n");
            break;
        default:
            printf("无效的选项,请重新选择(1-5)\n");
        }
    } while (choice != 5);

    return 0;
}

实验九:结构体和共用体

A.实验要求

一、目的和要求

        1.掌握结构体类型变量的定义和使用方法。

        2.掌握结构体类型数组的概念和使用方法。

        3.掌握共用体的概念和使用方法。

二、实验内容

        1.10 名学生的数据信息,包括学号,姓名,性别,出生年,月,日,C 语言成绩,高等数学成绩,线性代数学成绩,平均成绩和名次等。(一个小 MIS 的实现)【必做】

        按照如下步骤编写程序:

        (1)要求定义一个结构体数据类型来描述学生的信息。

        (2)输入学生的基本信息以及三门课程的成绩。

        (3)求出每个学和三门课程的平均分。

        (4)对 10 名学和按照平均分进行排队。

        (5)输出每门课程成绩最高的同学的基本信息。

三、实验指导

题目 1

描述学生信息的结构体类型定义应该在所有函数定义之前。

分别设计 5 个函数,通过指针运算实现以上 5 个功能。

设计一个菜单,可以选择上述 5 个功能,菜单应该能反复使用,直到选择退出。

B.代码实现

test.c

#include 
#include 

struct Student
{
    char studentID[10];
    char name[50];
    char gender;
    int birthYear;
    int birthMonth;
    int birthDay;
    double cLanguageScore;
    double higherMathScore;
    double linearAlgebraScore;
    double averageScore;
    int rank;
};

struct Student students[10];

int main()
{

    for (int i = 0; i < 10; i++)
    {
        printf("请输入第%d名学生的信息:\n", i + 1);
        printf("学号:");
        scanf("%s", students[i].studentID);
        printf("姓名:");
        scanf("%s", students[i].name);
        printf("性别:");
        scanf(" %c", &students[i].gender);
        printf("出生年月日:");
        scanf("%d %d %d", &students[i].birthYear, &students[i].birthMonth, &students[i].birthDay);
        printf("C语言成绩:");
        scanf("%lf", &students[i].cLanguageScore);
        printf("高等数学成绩:");
        scanf("%lf", &students[i].higherMathScore);
        printf("线性代数成绩:");
        scanf("%lf", &students[i].linearAlgebraScore);

        // 计算平均分
        students[i].averageScore = (students[i].cLanguageScore + students[i].higherMathScore + students[i].linearAlgebraScore) / 3;
    }

    // 冒泡排序
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 9 - i; j++)
        {
            if (students[j].averageScore < students[j + 1].averageScore)
            {
                struct Student temp = students[j];
                students[j] = students[j + 1];
                students[j + 1] = temp;
            }
        }
    }

    printf("每门课程成绩最高的学生信息:\n");

    // 找到每门课程成绩最高的学生
    struct Student topCLanguageStudent = students[0];
    struct Student topMathStudent = students[0];
    struct Student topLinearAlgebraStudent = students[0];

    for (int i = 0; i < 10; i++)
    {
        if (students[i].cLanguageScore > topCLanguageStudent.cLanguageScore)
        {
            topCLanguageStudent = students[i];
        }
        if (students[i].higherMathScore > topMathStudent.higherMathScore)
        {
            topMathStudent = students[i];
        }
        if (students[i].linearAlgebraScore > topLinearAlgebraStudent.linearAlgebraScore)
        {
            topLinearAlgebraStudent = students[i];
        }
    }

    printf("C语言成绩最高的学生信息:\n");
    printf("学号: %s\n姓名: %s\n", topCLanguageStudent.studentID, topCLanguageStudent.name);

    printf("高等数学成绩最高的学生信息:\n");
    printf("学号: %s\n姓名: %s\n", topMathStudent.studentID, topMathStudent.name);

    printf("线性代数成绩最高的学生信息:\n");
    printf("学号: %s\n姓名: %s\n", topLinearAlgebraStudent.studentID, topLinearAlgebraStudent.name);
}

实验十:  链表

A.实验要求

一、目的和要求

        1.掌握指向结构体的指针变量的定义和使用方法。

        2. 掌握链表的建立及使用方法。

二、实验内容

        1. 对学生的基本信息用链表进行处理,基本信息包括:学号、姓名、性别、年龄、C 语言的成绩。要求:

        (1)建立链表,输入一个学生的基本信息,插入链表,插入要求为链表必须按照学号从小到大的顺序进行排列。

        (2)可以在链表中删除某一学生的信息即输入一个学生的学号,查找到该节点信息作删除。

B.代码实现

test.c

#include 
#include 
#include 

// 定义学生结构体
struct Student
{
    char studentID[10];
    char name[50];
    char gender;
    int age;
    double cLanguageScore;
    struct Student *next;
};

// 初始化链表头
struct Student *head = NULL;

// 插入学生信息到链表中,按学号排序
void insertStudent(struct Student *newStudent)
{
    if (head == NULL || strcmp(newStudent->studentID, head->studentID) < 0)
    {
        newStudent->next = head;
        head = newStudent;
    }
    else
    {
        struct Student *current = head;
        while (current->next != NULL && strcmp(newStudent->studentID, current->next->studentID) > 0)
        {
            current = current->next;
        }
        newStudent->next = current->next;
        current->next = newStudent;
    }
}

// 根据学号删除学生信息
void deleteStudent(char studentIDToDelete[10])
{
    struct Student *current = head;
    struct Student *previous = NULL;

    while (current != NULL)
    {
        if (strcmp(current->studentID, studentIDToDelete) == 0)
        {
            if (previous == NULL)
            {
                head = current->next;
            }
            else
            {
                previous->next = current->next;
            }
            free(current);
            printf("学生信息已删除。\n");
            return;
        }

        previous = current;
        current = current->next;
    }

    printf("未找到指定学号的学生信息。\n");
}

int main()
{
    int choice;
    struct Student *newStudent;
    char studentIDToDelete[10];

    do
    {
        printf("\n学生信息管理系统\n");
        printf("1. 插入学生信息\n");
        printf("2. 删除学生信息\n");
        printf("3. 退出\n");
        printf("请选择操作: ");
        scanf("%d", &choice);

        switch (choice)
        {
        case 1:
            newStudent = (struct Student *)malloc(sizeof(struct Student));
            if (newStudent == NULL)
            {
                printf("内存分配失败。\n");
                return 1;
            }
            printf("学号:");
            scanf("%s", newStudent->studentID);
            printf("姓名:");
            scanf("%s", newStudent->name);
            printf("性别:");
            scanf(" %c", &(newStudent->gender));
            printf("年龄:");
            scanf("%d", &(newStudent->age));
            printf("C语言成绩:");
            scanf("%lf", &(newStudent->cLanguageScore));
            newStudent->next = NULL;
            insertStudent(newStudent);
            break;
        case 2:
            printf("请输入要删除学生的学号: ");
            scanf("%s", studentIDToDelete);
            deleteStudent(studentIDToDelete);
            break;
        case 3:
            printf("程序已退出。\n");
            break;
        default:
            printf("无效的选项,请重新选择。\n");
        }
    } while (choice != 3);

    // 释放链表内存
    while (head != NULL)
    {
        struct Student *temp = head;
        head = head->next;
        free(temp);
    }

    return 0;
}

实验十一 :   文件

A.实验要求

一、目的和要求

        1.掌握文件和文件指针的概念。

        2.学会使用文件打开、关闭、读、写等文件操作函数。

        3.掌握二进制文件、文本文件的概念及操作。

二、实验内容

        按照要求进行如下基本文件操作:

        1.从键盘上输入一串字行,以$结束,将输入的字符串存入到文件 char.dat 中;

        2.从文件 char.dat 中将存放在字符串读出,将其中的小写字母变成大写输出到屏幕上。

        3.有 5 个学生。每个学生有 3 门课程的成绩,从键盘上输入学生号,姓名, 三门课的成绩,计算出平均成绩,将原有数据和计算出的平均分数存放在磁盘文件 STUD 中。

        4.从上一题目文件 STUD 中,输入学生的学号,读出该学生的数据信息。

B.代码实现

#include 
#include 
#include 

// 1:从键盘输入字符串并写入文件
void inputAndWriteToFile()
{
    FILE *file;
    char inputString[1000];

    printf("请输入一串字符,以$结束:\n");

    // 打开文件 char.dat 以写入模式
    file = fopen("char.dat", "w");
    if (file == NULL)
    {
        perror("无法打开文件");
        return;
    }

    // 从键盘输入字符串,以$结束
    fgets(inputString, sizeof(inputString), stdin);

    // 将字符串写入文件
    fputs(inputString, file);

    // 关闭文件
    fclose(file);

    printf("已将输入的字符串写入文件 char.dat。\n");
}

// 2:从文件中读取字符串并将小写字母转换为大写
void readFromFileAndConvertToUpper()
{
    FILE *file;
    char ch;

    printf("从文件 char.dat 中读取字符串并将小写字母转换为大写:\n");

    // 打开文件 char.dat 以读取模式
    file = fopen("char.dat", "r");
    if (file == NULL)
    {
        perror("无法打开文件");
        return;
    }

    // 读取文件中的字符并将小写字母转换为大写
    while ((ch = fgetc(file)) != EOF)
    {
        if (islower(ch))
        {
            ch = toupper(ch);
        }
        putchar(ch);
    }

    // 关闭文件
    fclose(file);

    printf("\n");
}

// 学生结构体
struct Student
{
    char studentID[10];
    char name[50];
    double grades[3];
    double averageGrade;
};

// 3:输入学生信息并计算平均成绩,将数据写入文件 STUD
void inputStudentDataAndWriteToFile()
{
    FILE *file;
    struct Student students[5];

    printf("请输入5个学生的信息和成绩:\n");

    for (int i = 0; i < 5; i++)
    {
        printf("学生%d的学号:", i + 1);
        scanf("%s", students[i].studentID);
        printf("学生%d的姓名:", i + 1);
        scanf("%s", students[i].name);
        printf("学生%d的三门课成绩(用空格分隔):", i + 1);
        scanf("%lf %lf %lf", &students[i].grades[0], &students[i].grades[1], &students[i].grades[2]);

        // 计算平均成绩
        students[i].averageGrade = (students[i].grades[0] + students[i].grades[1] + students[i].grades[2]) / 3.0;
    }

    // 打开文件 STUD 以写入模式
    file = fopen("STUD", "wb");
    if (file == NULL)
    {
        perror("无法打开文件");
        return;
    }

    // 将学生信息写入文件
    fwrite(students, sizeof(struct Student), 5, file);

    // 关闭文件
    fclose(file);

    printf("学生信息已写入文件 STUD。\n");
}

// 4:从文件 STUD 中读取学生信息并输出
void readStudentDataFromFile()
{
    FILE *file;
    struct Student students[5];

    // 打开文件 STUD 以读取模式
    file = fopen("STUD", "rb");
    if (file == NULL)
    {
        perror("无法打开文件");
        return;
    }

    // 从文件中读取学生信息
    fread(students, sizeof(struct Student), 5, file);

    // 输出学生信息
    printf("从文件 STUD 中读取的学生信息:\n");
    for (int i = 0; i < 5; i++)
    {
        printf("学号:%s\n", students[i].studentID);
        printf("姓名:%s\n", students[i].name);
        printf("三门课成绩:%lf %lf %lf\n", students[i].grades[0], students[i].grades[1], students[i].grades[2]);
        printf("平均成绩:%lf\n", students[i].averageGrade);
        printf("\n");
    }

    // 关闭文件
    fclose(file);
}

int main()
{
    inputAndWriteToFile();            // 1
    readFromFileAndConvertToUpper();  // 2
    inputStudentDataAndWriteToFile(); // 3
    readStudentDataFromFile();        // 4

    return 0;
}

附录一  VC 环境下 C 程序调试方法

        在程序设计的过程中,不可避免地会存在一些错误。因此,通过调试(Debug) 查错、改错的技术显得特别重要。与调试相关的一些手段:

(1)断点(Breakpoint)

        断点可以让程序的执行中断在需要的地方,方便检查分析程序。一个程序可以设置多个断点,这丝毫不影响程序的正常执行。但当以调试状态运行程序时, 每次运行到断点所在的代码行时,程序就暂停,这时可以用后面介绍的控制和查看程序的状态,程序语句是否存在错误。设置断点过程见图1。

程序设计基础C语言实验(黑龙江大学)_第17张图片 

                                             图 1 调试程序设置断点图

(2)单步跟踪(Tracker)

        当程序在断点处暂停时,就进入了单步跟踪状态。通过单步跟踪,可以逐条语句或逐个函数地执行程序,每执行完一条语句或一个函数,程序就暂停,因此可可以逐条语句或逐个函数地检查它们的执行结果。调试程序显示过程见图 2。

 
       程序设计基础C语言实验(黑龙江大学)_第18张图片

图 2 调试程序显示过程图

        断点所在行的代码是下一行要被执行的代码,叫做当前代码行。此时对程序的单步跟踪有 6 个选择。

        ① 单步执行(Step Over):执行一行代码,然后再暂停,如果存在函数调用语句,则把整个函数视为单步依次执行(即不会在该函数中的任何语句处暂停)。该方法常用在模块(通常程序由一个或多个函数构成)调试时期,可以通过观察变量在模块执行前后的变化情况来确定该模块中是否存在错误,也可用来跳过已测试完毕的模块。

        ② 单步进入(Step Into):执行一行代码,如果此行中有函数调用语句,则进入当前代码行所调用的函数内部,在该函数的第一行代码处暂停,也就是跟踪到函数内部;如果此行中没有函数调用,其作用与单步执行等价。单步进入一般只能进入有源代码的函数,如用户自己编写的函数,如果库函数没有源代码,就不能跟踪进入。该方法可以跟踪程序的每步执行过程,优点是容易直接定位错误, 缺点是调试速度较慢。

        所以,一般首先采用模块调试法,尽量缩小错误范围,然后使用单步执行和 断点来快速跳过没有出现错误的部分,最后才使用该方法来逐步跟踪以找出错误。

        ③ 运行出函数(Step Out):继续运行程序,当遇到断点或返回函数调用者时暂停。当只想调试函数中的一部分代码,并在调试完后快速跳出该函数时,可以使用这个命令。

        ④ 运行到光标所在行(Run to Cursor):将光标定位在某行代码上,并调用这个命令,程序会执行到断点或光标定位的那行代码暂停。如果想重点观察某一行(或多行)代码,而且不想从第一行启动,也不想设置断点时,可以采用这种方式。这种方式比较灵活,可以一次执行一行,也可以一次执行多行,可以直接跳出函数,也可以进入函数内部。

 

        ⑤ 继续运行(Continue):继续运行程序,当遇到断点时暂停。如果已经单步执行了感兴趣的代码行,则可以使用该方式,使程序继续执行,直到遇到下一个断点暂停。

        ⑥ 停止调试(Stop):程序运行终止,回到编辑状态。

(3)监视窗

        当程序暂停时,除了可以控制它的执行,还可以通过监视窗(Watch)来查看和修改各个变量的值。综合使用监视窗和单步跟踪功能,是找出程序中隐蔽错误的最简单的方法,因为每运行一行,就可以查看程序究竟做了什么,变量的值发生了怎样的变化,它们是否按预期的变化。若程序是按照要求正常工作的,则这一行就算调试通过了,否则也就找到了错误所在。当程序的运行结果不正确时, 采用这种方法显示出可能出错的局部和全局变量的值,可以有效地帮助用户检查究竟哪里的程序计算有误。调试程序监视窗见图 4-7。

                      程序设计基础C语言实验(黑龙江大学)_第19张图片

                                                           图 3 调试程序监视窗图

        在 VC++环境下,调试 C 程序的命令:

        VC 常用的调试命令如表 5-1 所示。每行中的菜单命令、图标、快捷键所实现的操作完全等价,采用其中任意一种即可。

 

 1 VC 基本调试命令

菜单命令

图标

快捷键

说明

Go

F5

开始或继续在调试状态下运行程序

Run to Cursor

Ctrl +F10

运行到光标所在行

Insert / Remove Breakpoint

F9

插入或删除断点

Step Into

F11

单步进入,遇到函数

Step Over

F10

单步执行

Step Out

Shift+F11

跳出当前函数

Stop Debugging

Shift+F5

停止调试程序

 

附录二  CodeBlocks 环境下 C 程序调试方法

        在 CodeBlocks 中进行程序调试基本步骤与 VC 类似,但是需要先创建工程, 具体方法如下:

  1. 创建一个 C 语言工程。

  (1)  选择 File->New->Projects,打开创建工程向导,  如图 1 所示。

程序设计基础C语言实验(黑龙江大学)_第20张图片                                              

                                                     图 1 打开创建工程向导

(2)选择 Console application,并点击“go”,见图 2。

程序设计基础C语言实验(黑龙江大学)_第21张图片

                                   图 2 选择 Console application 选项

(3)选择“C”,点击“Next”建立一个 C 语言的源程序,见图 3。

 
程序设计基础C语言实验(黑龙江大学)_第22张图片

图 3 选择源程序类型

(4)填写工程的信息,点击“Next”,见图 4。

程序设计基础C语言实验(黑龙江大学)_第23张图片

图 4 填写工程基本信息

(5)选择编译器,并点击“Finish”创建工程,见图 5。

程序设计基础C语言实验(黑龙江大学)_第24张图片

                                                                图 5 编译器选择

(6)打开工程中的 C 语言源文件,并编写程序,见图 6。

程序设计基础C语言实验(黑龙江大学)_第25张图片

                                                        图 6 编写源程序

        2. 程序的单步调试

        (1)点击“Debugging windows”按钮打开“Watches”监视窗口,常用的调试功能在 Debug 菜单中,灰色的部分会在“条件”具备时变得可用,见图 7。

程序设计基础C语言实验(黑龙江大学)_第26张图片

                                                             图 7 打开监视窗口

        (2)直接在行号后单击鼠标可以“添加断点“或“移除断点”,或按快捷键 F5

在光标所在行添加或移除断点,见图 8。

程序设计基础C语言实验(黑龙江大学)_第27张图片

                                                                图 8 添加断点

(3)常用的调试命令

                                                 表 1 CodeBlocks 基本调试命令

菜单命令

快捷键

功能说明

Start

F8

开始调试

Run to cursor

F4

运行到光标所在行

Next line

F7

单步执行

Step into

Shift+F7

进入函数

Step out

Ctrl+F7

跳出函数

Stop debugger

Shift+F8

停止调试

你可能感兴趣的:(c语言,开发语言)