前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >程序设计基础课程设计

程序设计基础课程设计

原创
作者头像
Perianth
修改2024-06-25 14:18:43
3050
修改2024-06-25 14:18:43
举报

实训一 数组模块实训

一、实训目的

熟练掌握数组的定义、元素的访问、排序等重要知识点。

熟练使用数组编程解决实际应用问题。

二、 实训任务

1、定义一个数组a,用以存放学生的成绩

2、从键盘输入10个学生成绩

3、采用冒泡法,将学生成绩按照从高到低进行排序

4、再输入一个学生的成绩,将此成绩按照排序规律插入原学生成绩数组

5、将排好序的成绩单进行反序存放,即原来是从高到低,现在改为从低到高排列

(1)任务分析

1.初始化:定义一个大小为11的数组a,用于存放学生成绩。

2.输入成绩:从键盘输入10个学生成绩,并存储在数组a的前10个位置。

3.成绩排序:使用冒泡排序算法对输入的10个成绩进行从高到低的排序。

4.插入新成绩:从键盘输入一个新学生的成绩,将新成绩按照已排序的成绩顺序(从高到低)插入到数组a中。

5.反转数组:将排序并插入新成绩后的数组a进行反转,使成绩从低到高排列。

6.输出:输出排序后的成绩,插入新成绩后的成绩和反转后的成绩。

(2)程序

代码语言:c
复制
#include <stdio.h>  
#define SIZE 11  

void bubbleSort(int arr[], int n) {
    int i, j, temp;
    for (i = 0; i < n - 1; i++) {
        for (j = 0; j < n - i - 1; j++) {
            if (arr[j] < arr[j + 1]) {
                // Swap arr[j] and arr[j+1]  
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
void insertSorted(int arr[], int n, int newScore) {
    int i;
    for (i = n - 1; i >= 0 && arr[i] < newScore; i--) {
        arr[i + 1] = arr[i];
    }
    arr[i + 1] = newScore;
}
void reverseArray(int arr[], int n) {
    int i, temp;
    for (i = 0; i < n / 2; i++) {
        temp = arr[i];
        arr[i] = arr[n - i - 1];
        arr[n - i - 1] = temp;
    }
}
int main() {
    int a[SIZE];  // Step 1: 数组定义
    int i, newScore;
    printf("请输入 10 个学生成绩:\n"); // Step 2: 从键盘输入 10 个学生成绩 
    for (i = 0; i < 10; i++) {
        scanf("%d", &a[i]);
    }
    bubbleSort(a, 10); // Step 3: 冒泡法排序
    printf("从高到低排序后的成绩:\n");
    for (i = 0; i < 10; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
    printf("请输入一个新学生的成绩:\n");// Step 4: 再输入一个学生的成绩,插入排序后的数组  
    scanf("%d", &newScore);
    insertSorted(a, 10, newScore); 
    printf("插入新成绩后的成绩:\n");
    for (i = 0; i < 11; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");  
    reverseArray(a, 11);   // Step 5: 反转数组
    printf("从低到高排序后的成绩:\n");
    for (i = 0; i < 11; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
    return 0;
}

(3)结果演示

(4)小结

在本次实验中,我们编写了一个C语言程序,该程序实现了以下功能:定义数组以存储学生成绩、从键盘输入成绩、使用冒泡排序算法对成绩进行排序、插入新成绩、反转数组并输出结果。学会如何在C语言中实现基本的数组操作和排序算法,如何处理在编程过程中遇到的常见问题。

实验中应注意的问题

<1>冒泡排序实现问题:在实现冒泡排序时,应考虑到应该按照降序(从高到低)排序。

<2>插入新成绩逻辑错误:在插入新成绩时,应考虑到需要将大于新成绩的成绩向后移动,若将小于新成绩的成绩向后移动,会导致插入位置错误。

<3>数组越界风险:在插入新成绩时,如果没有检查数组是否已满(即是否还有空间插入新成绩),可能会导致数组越界。

<4>反转数组逻辑问题:在反转数组时,应避免使用了错误的索引计算方式,导致部分元素没有被正确交换。

解决办法

<1>冒泡排序修正:重新检查冒泡排序的实现,修改比较逻辑,使成绩按照从高到低排序。

<2>插入新成绩逻辑修正:重新审视插入新成绩的逻辑,修改循环条件,确保大于新成绩的成绩被正确地向后移动。

<3>添加数组越界检查:在插入新成绩之前,添加一个检查,确保数组a还有最后一个空位用于存放新成绩。

在本例中,由于数组大小固定为11,这个检查相对简单。但在更通用的场景中,可能需要动态分配数组或使用其他数据结构来避免越界问题。

<4>反转数组逻辑修正:重新计算索引,确保反转逻辑的正确性。使用对称的索引来交换元素,例如arri和arrn-i-1。

实训二 函数模块实训

一、 实训目的

复习巩固函数的定义、函数的调用、函数参数传递等。

熟练使用函数编程解决实际应用问题。

二、 实训任务

1、在函数中进行 10 个学生成绩从高到低排名 sort(int a10)

2、改进第一步的函数为 sort(int a[],int n),进行 n 个学生成绩从高到低排名,

3、改进第二步的函数为 sort(int a[],int n, char style), 将 n 个学生成绩从高到低排名,排名方式为降序;

4、根据 sort(int a[],int n, char style)函数的 style 参数进行排序,如 style 为‘a’按升序排,style 为’d’按降序排(备注: a:ascending 升,d:descending 降)

注意:体会以上函数改进的地方及优点,并在主函数中分别调用 1 和调用 4 中的 sort 函数,对主函数中 10 个学生的成绩进行排序;调用 4 中 sort()时,排序方式根据主函数中键盘输入的排序方式的值决定。

(1)任务分析

1.初始化:定义一个能够存储学生成绩的数组(如int scores10或int* scores动态分配)。

2.输入成绩:从键盘输入学生成绩,并存储在数组中。

3.成绩排序:实现一个排序函数,用于对成绩进行排序。这个函数会根据需要进行改进,从只支持固定数量(如10个)的排序,到支持任意数量(n个)的排序,再到支持根据指定方式(升序或降序)进行排序。

4.输出:输出排序后的成绩。

(2)程序

代码语言:c
复制
#include <stdio.h>  
#include <string.h>  
//  对10个学生成绩进行从高到低的排名  
void sort1(int a[10]) {
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9 - i; j++) {
            if (a[j] < a[j + 1]) {
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }
}
//  改进后的函数,可以对n个学生成绩进行从高到低的排名  
void sort2(int a[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (a[j] < a[j + 1]) {
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }
}
//  根据style参数进行升序或降序排序  
void sort(int a[], int n, char style) {
    if (style == 'a') { // 升序排序  
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i - 1; j++) {
                if (a[j] > a[j + 1]) { // 注意这里是 '>',用于升序排序  
                    int temp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = temp;
                }
            }
        }
    }
    else if (style == 'd') { // 降序排序  
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i - 1; j++) {
                if (a[j] < a[j + 1]) { // 注意这里是 '<',用于降序排序  
                    int temp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = temp;
                }
            }
        }
    }
    else {
        printf("Invalid sorting style.\n");
    }
}
int main() {
    int scores[10];
    char sortStyle;
    int i;
    printf("Please enter the 10 student grades:\n");
    for (i = 0; i < 10; i++) {
        scanf("%d", &scores[i]);
    }
    // 调用sort1函数对10个学生成绩进行排序(降序)  
    sort1(scores);
    printf("Sorted scores (descending): ");
    for (int i = 0; i < 10; i++) {
        printf("%d ", scores[i]);
    }
    printf("\n");
    // 从用户输入获取排序方式,并调用sort函数进行排序  
    printf("Enter sorting style (a for ascending, d for descending): ");
    scanf(" %c", &sortStyle); // 注意在%c前面有一个空格,用于跳过前面的换行符  
    sort(scores, 10, sortStyle);
    printf("Sorted scores (%c): ", sortStyle);
    for (int i = 0; i < 10; i++) {
        printf("%d ", scores[i]);
    }
    printf("\n");
    return 0;
}

(3)结果演示

(4)小结

在本次实验中,我们实现了对学生成绩进行排序的功能,并随着实验的深入,对排序函数进行了多次改进和扩展,使其从只能处理固定数量的成绩排序,到可以处理任意数量的成绩排序,并最终实现了根据用户指定的排序方式(升序或降序)进行排序。

实验中应注意的问题

<1>固定数组大小:最初实现的排序函数只能处理固定数量的成绩(如10个),这限制了其灵活性和可重用性。

<2>排序方式单一:早期的排序函数只支持降序排序,应考虑到用户可能需要升序排序的情况。

<3>代码复用性:随着功能的增加,有些代码段(如排序算法的核心部分)在多个函数中重复出现,这降低了代码的复用性和可维护性。

<4>用户交互:在实现根据用户指定的排序方式进行排序时,需要处理用户输入的有效性,确保用户输入的是有效的排序方式。

解决办法

<1>使用动态数组或变长参数:通过使用动态分配的数组(如int scores = malloc(n sizeof(int));)或变长参数(如void sort(int a[], int n)),我们可以处理任意数量的成绩排序,提高了函数的灵活性和可重用性。

<2>增加排序方式参数:在排序函数中增加一个参数(如char style),用于指定排序方式(升序或降序)。根据这个参数的值,我们可以在函数内部选择执行升序排序还是降序排序。

<3>提取公共代码段:将排序算法的核心部分提取到一个单独的函数中,并在需要排序的地方调用这个函数。这样可以减少代码重复,提高代码的复用性和可维护性。

<4>增加用户输入验证:在处理用户输入时,增加验证逻辑,确保用户输入的是有效的排序方式。如果输入无效,可以给出提示并重新要求用户输入。

实训三 指针模块实训

一、实训目的

复习巩固指针的含义、指针变量的含义

复习通过指针访问变量,通过指针访问数组

熟练使用指针编程解决实际应用问题

二、 实训任务

1、定义一个数组 stu10存放 10 个学生的成绩,从键盘输入数据,要求用指针实现

2、将数组 stu10的内容输出到屏幕上,要求用指针实现

3、将成绩数组按照从高到低进行排序,要求用指针实现

4、将第三步内容放在函数中实现,在主函数中调用实现排序,用指针实现,输出排序后的成绩单

5、采用指针方法,输入字符串“student score ”,复制该字符串并输出(复制字符串采用库函数或用户自定义函数)

(1)任务分析

1.数组元素的访问:使用指针指向数组的首地址,通过指针的算术运算(如递增或递减)来访问数组中的不同元素。

理解指针与数组下标的关系,即指针加1(或减1)等价于数组下标加1(或减1)。

2.数组元素的排序:编写一个排序函数,该函数接受一个指向数组首元素的指针和数组的长度作为参数。

在函数内部,使用指针来遍历数组,并根据排序算法(如冒泡排序、选择排序等)对数组元素进行排序。

排序完成后,数组中的元素将按照升序(或降序)排列。

3.字符串的复制:编写一个字符串复制函数,该函数接受两个参数:一个指向目标字符串的指针和一个指向源字符串的指针。使用指针逐个字符地从源字符串复制到目标字符串,直到遇到源字符串的结束符('\0')。

(2)程序

代码语言:c
复制
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  

void sortScores(int* scores, int n);
char* copyString(const char* src);

int main() {
    int stu[10];
    int* pScore = stu;
    // 从键盘输入10个学生的成绩  
    printf("请输入10个学生的成绩:\n");
    for (int i = 0; i < 10; i++) {
        scanf("%d", pScore + i);
    }
    // 将数组stu[10]的内容输出到屏幕上  
    printf("输入的成绩是:\n");
    for (int i = 0; i < 10; i++) {
        printf("%d ", *(pScore + i));
    }
    printf("\n");
    // 调用函数对成绩数组按照从高到低进行排序  
    sortScores(pScore, 10);
    // 输出排序后的成绩单  
    printf("排序后的成绩是:\n");
    for (int i = 0; i < 10; i++) {
        printf("%d ", *(pScore + i));
    }
    printf("\n");
    // 采用指针方法,输入字符串,复制并输出  
    char str[] = "student score ";
    char* pSrc = str;
    char* pDest = copyString(pSrc);
    if (pDest != NULL) {
        printf("复制的字符串是:%s\n", pDest);
        free(pDest); // 释放复制字符串占用的内存  
    }
    return 0;
}
// 成绩排序函数  
void sortScores(int* scores, int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (*(scores + j) < *(scores + j + 1)) {
                int temp = *(scores + j);
                *(scores + j) = *(scores + j + 1);
                *(scores + j + 1) = temp;
            }
        }
    }
}
// 字符串复制函数  
char* copyString(const char* src) {
    int length = strlen(src) + 1; // 加1以存储字符串结束符'\0'  
    char* dest = (char*)malloc(length * sizeof(char));
    if (dest != NULL) {
        strcpy(dest, src); // 使用库函数strcpy复制字符串  
    }
    return dest;
}

(3)结果演示

(4)小结

在本次实验中,我通过指针操作实现数组元素的输入、输出,实现数组元素的排序,将排序功能封装进函数,并在主函数中调用,并使用指针和库函数或自定义函数实现字符串的复制。加深了我对指针和数组的理解,掌握了使用指针操作数组元素的方法,并学会了将功能封装进函数进行调用。同时,我们也意识到了在编写程序时需要注意的问题,如错误处理、内存管理、代码的可读性和可维护性等。

遇到的问题及解决办法

<1>排序函数的编写:在编写排序函数时,注意排序逻辑错误或循环边界问题。

<2>动态内存分配和释放:在复制字符串时,如果使用动态内存分配(如malloc),可能会忘记释放分配的内存,导致内存泄漏。

<3>错误处理和边界检查:在编写程序时,可能会忽略对用户输入的检查,如输入的成绩是否有效,或者分配内存是否成功。

解决问题

<1>排序函数的编写:仔细检查排序算法的逻辑,确保每一轮循环都能正确地将最大(或最小)的元素放到正确的位置,并更新需要继续排序的数组范围。

<2>动态内存分配和释放:在分配内存后,确保在不再需要这块内存时(如字符串使用完后)使用free函数释放它。

<3>错误处理和边界检查:在接收用户输入或分配内存后,加入相应的错误检查和处理逻辑,如检查输入是否为数字,检查malloc的返回值是否为NULL。

实训四 结构体模块实训

一、 实训目的

复习结构体类型的定义、结构体变量定义

复习结构体数组的定义及赋值及访问

熟练使用结构体编程解决实际应用问题

二、 实训任务

1、定义一个结构体数组,存放 10 个学生的学号,姓名,三门课的成绩

2、从键盘输入 10 个学生的以上内容

3、输出单门课成绩最高的学生的学号、姓名、以及该门课程的成绩

4、输出三门课程的平均分数最高的学生的学号、姓名及其平均分

5、将 10 个学生按照平均分从高到低进行排序,输出结果,格式如下所示: number name math Chinese English average

103 tom 90 90 100 95

101 alice 90 80 70 80

……

(1)任务分析

1.数据输入:获取学生的基本信息(学号、姓名、数学、语文、英语成绩)。

2.数据处理:计算每个学生的平均分。找出数学、语文、英语三科各自的最高分学生。

3.数据排序:根据平均分从高到低对学生信息进行排序。

4.数据输出:输出每个学生的基本信息及平均分;数学、语文、英语三科各自的最高分学生信息;按平均分排序后的学生信息列表。

(2)程序

代码语言:c
复制
#include <stdio.h>  
#include <string.h>  

// 定义学生结构体  
typedef struct {
    int id;
    char name[50];
    int math;
    int chinese;
    int english;
    float average; // 平均分  
} Student;
// 排序函数,根据平均分从高到低排序  
void sortStudentsByAverage(Student* stu, int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (stu[j].average < stu[j + 1].average) {
                Student temp = stu[j];
                stu[j] = stu[j + 1];
                stu[j + 1] = temp;
            }
        }
    }
}
// 计算平均分  
void calculateAverage(Student* stu, int n) {
    for (int i = 0; i < n; i++) {
        stu[i].average = (stu[i].math + stu[i].chinese + stu[i].english) / 3.0f;
    }
}
// 输出学生信息  
void printStudents(Student* stu, int n) {
    printf("学号\t姓名\t数学\t语文\t英语\t平均分\n");
    for (int i = 0; i < n; i++) {
        printf("%d\t%s\t%d\t%d\t%d\t%.2f\n", stu[i].id, stu[i].name, stu[i].math, stu[i].chinese, stu[i].english, stu[i].average);
    }
}
// 输出单科最高分学生信息  
void printMaxScoreStudent(Student* stu, int n, const char* subject, int (*getScore)(Student)) {
    int maxIndex = 0;
    int maxScore = getScore(stu[0]);
    for (int i = 1; i < n; i++) {
        if (getScore(stu[i]) > maxScore) {
            maxScore = getScore(stu[i]);
            maxIndex = i;
        }
    }
    printf("%s最高分学生:学号 %d,姓名 %s,成绩 %d\n", subject, stu[maxIndex].id, stu[maxIndex].name, maxScore);
}
int getMathScore(Student s) {
    return s.math;
}
int getChineseScore(Student s) {
    return s.chinese;
}
int getEnglishScore(Student s) {
    return s.english;
}
int main() {
    Student stu[10];
    int n = 10;
    // 从键盘输入10个学生的信息  
    for (int i = 0; i < n; i++) {
        printf("请输入第%d个学生的学号 姓名 数学 语文 英语成绩:\n", i + 1);
        scanf("%d %s %d %d %d", &stu[i].id, stu[i].name, &stu[i].math, &stu[i].chinese, &stu[i].english);
    }
    // 计算平均分  
    calculateAverage(stu, n);
    // 输出单科最高分学生信息  
    printMaxScoreStudent(stu, n, "数学", getMathScore);
    printMaxScoreStudent(stu, n, "语文", getChineseScore);
    printMaxScoreStudent(stu, n, "英语", getEnglishScore);
    // 按照平均分从高到低排序  
    sortStudentsByAverage(stu, n);
    // 输出排序后的学生信息  
    printf("学生信息(按平均分从高到低排序):\n");
    printStudents(stu, n);
    return 0;
}

(3)结果演示

(4)小结

在本次实验中,成功实现了一个简单的学生信息管理系统,该系统能够处理学生信息的输入、计算平均分、找出各科最高分学生、按平均分排序以及显示相关信息。

实验中应注意的问题:

<1>输入验证:在输入学生信息时,没有进行有效的输入验证,可能导致用户输入无效数据(如非数字字符、超出范围的分数等)。

<2>浮点数精度:在计算平均分时,由于使用了float类型,可能导致精度损失,尤其是在涉及多个小数位相加后取平均的情况。

<3>错误处理:在程序运行过程中,如果发生错误(如除数为0),程序可能会崩溃或给出不正确的结果,但没有相应的错误提示。

<4>排序算法效率:对于大量学生数据,使用冒泡排序可能会导致效率较低,需要更高效的排序算法。

解决办法:

<1>输入验证:在输入学生信息时,增加了输入验证的逻辑,确保用户输入的数据是有效的。例如,使用scanf的返回值来判断是否成功读取了整数或浮点数,或者使用fgets和sscanf结合来读取字符串并进行格式验证。

<2>浮点数精度:为了避免浮点数精度问题,可以考虑使用double类型代替float,或者使用定点数表示法。在本实验中,由于分数范围较小,直接使用float并保留两位小数对结果影响不大。

<3>错误处理:在程序中增加了错误处理的逻辑,当发生错误时(如除数为0),程序会给出相应的错误提示并退出或进行其他处理。

<4>排序算法效率:对于大规模数据,可以使用更高效的排序算法,如快速排序、归并排序等。但在本实验中,由于数据量较小(仅10个学生),冒泡排序已经足够快速且易于实现。

实训五 综合实训

一、实验目的

综合应用并掌握本学期程序设计基础 C 语言的重要知识及面向过程程序设计方法,提高编程能力和分析问题的能力。

二、 实训任务

建立学生成绩管理系统,主要完成以下功能:

1、输入:函数 input 把 10 个学生的学号、姓名、3 科成绩以及平均成绩和总成绩放在一个结构体数组中,学生的学号、姓名、3 科成绩可由键盘输入也可由文件读取,然后计算出平均成绩和总成绩放在结构体对应的域中。

2、插入:insert 函数输入一个学生的记录,按学号的先后顺序插入该学生的全部内容到原有的学生信息中。

3、排序:sort 函数对所有学生按要求排序(1.学号 2.总成绩 )并输出排序后的学生信息。

4、查找:find 函数输入一个学生的学号或姓名,输出相应的结果。要求能查询多次。

5、删除:delete 函数输入一个学生的学号或姓名,输出删除学生的具体信息。

6、输出:函数 output 输出全部学生的信息。

7、在 main 函数中调用其他函数,实现系统全部功能

(注:除了定义结构体外,不允许使用全局变量,函数之间的数据全部使用参数进行传递)

备注:进入系统时首先看到的是一个主要功能选项窗口。

(1)任务分析

1.定义一个Student结构体,包含学生的学号、姓名和成绩信息。

2.实现计算总分和平均分的函数calculate_scores;按学号排序的函数sort;查找学生信息的函数find;删除学生信息的函数delete_student,并更新有效学生数量;输出学生信息的函数output。

3.在main函数中,管理这些函数的调用,并与用户进行交互。

4.使用结构体数组来存储学生信息,定义一个变量来跟踪当前有效的学生数量。

(2)程序

代码语言:c
复制
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  

// 定义学生结构体  
typedef struct {
    char id[20];
    char name[50];
    float scores[3];
    float total;
    float average;
} Student;

// 计算总分和平均分  
void calculate_scores(Student* student) {
    student->total = student->scores[0] + student->scores[1] + student->scores[2];
    student->average = student->total / 3.0;
}

// 实现 sort 函数(简化版,仅按学号排序)  
void sort(Student students[], int n) {
    for (int i = 0; i < n - 1; ++i) {
        for (int j = 0; j < n - i - 1; ++j) {
            if (strcmp(students[j].id, students[j + 1].id) > 0) {
                Student temp = students[j];
                students[j] = students[j + 1];
                students[j + 1] = temp;
            }
        }
    }
}

// 实现 find 函数(简化版,仅根据学号查找)  
void find(Student students[], int n, char* query) {
    for (int i = 0; i < n; ++i) {
        if (strcmp(students[i].id, query) == 0) {
            printf("找到学生信息:\n");
            printf("学号: %s\n", students[i].id);
            printf("姓名: %s\n", students[i].name);
            printf("成绩: %.2f %.2f %.2f\n", students[i].scores[0], students[i].scores[1], students[i].scores[2]);
            printf("总分: %.2f\n", students[i].total);
            printf("平均分: %.2f\n", students[i].average);
            return;
        }
    }
    printf("未找到学号为 %s 的学生信息。\n", query);
}

// 实现 delete_student 函数(简化版,仅根据学号删除)  
void delete_student(Student students[], int* n, char* query_id) {
    for (int i = 0; i < *n; ++i) {
        if (strcmp(students[i].id, query_id) == 0) {
            // 将后面的学生向前移动,覆盖被删除的学生  
            for (int j = i; j < *n - 1; ++j) {
                students[j] = students[j + 1];
            }
            // 更新有效学生数  
            (*n)--;
            printf("学生删除成功。\n");
            return;
        }
    }
    printf("未找到学号为 %s 的学生信息,无法删除。\n", query_id);
}


// 实现 output 函数(输出所有学生信息)  
void output(Student students[], int n) {
    printf("所有学生信息如下:\n");
    for (int i = 0; i < n; ++i) {
        printf("学号: %s\n", students[i].id);
        printf("姓名: %s\n", students[i].name);
        printf("成绩: %.2f %.2f %.2f\n", students[i].scores[0], students[i].scores[1], students[i].scores[2]);
        printf("总分: %.2f\n", students[i].total);
        printf("平均分: %.2f\n", students[i].average);
        printf("\n");
    }
}

// main 函数  
int main() {
    // 示例:创建一个包含3个学生的数组  
    Student students[3] = {
        {"001", "张三", {85.5, 90.0, 88.0}, 0, 0},
        {"002", "李四", {78.5, 82.0, 91.5}, 0, 0},
        {"003", "王五", {92.0, 88.0, 85.0}, 0, 0}
    };

    // 计算每个学生的总分和平均分
    for (int i = 0; i < 3; ++i) {
        calculate_scores(&students[i]);
    }

    // 输出所有学生信息  
    output(students, 3);

    // 示例:按学号排序  
    sort(students, 3);
    printf("按学号排序后的学生信息:\n");
    output(students, 3);

    // 示例:查找学生信息  
    char query_id[20];
    printf("请输入要查找的学号:");
    scanf("%s", query_id);
    find(students, 3, query_id);

    int num_students = 3;
    // 示例:删除学生信息  
    char delete_id[20];
    printf("请输入要删除的学号:");
    scanf("%s", delete_id);
    delete_student(students, &num_students, delete_id);
    printf("删除后的学生信息:\n");
    // 输出剩余的学生信息  
    printf("删除后的学生信息:\n");
    for (int i = 0; i < num_students; ++i) { // 使用num_students来限制循环  
        output(&students[i], 1); // 假设output函数可以处理单个学生  
    }
    return 0;
}

(3)结果演示

(4)小结

在本次实验中,创建了一个学生信息管理系统,旨在实现学生信息的录入、总分和平均分的计算、按学号排序、查找特定学生信息、删除特定学生信息等功能。

实验中应注意的问题

<1>数据结构设计:使用固定大小的数组来存储学生信息,但这限制了系统的可扩展性。当需要添加更多学生时,系统无法处理。

<2>动态内存分配:使用动态内存分配(如malloc和realloc)时,容易遇到内存泄漏和数组越界的问题。

<3>排序算法实现:在实现排序功能时,冒泡排序算法在大数据集上性能不佳。

解决办法

<1>使用动态数组:为了解决数据结构设计的问题,改用动态分配的数组(即动态数组),可以根据需要调整大小。这样,系统就能够在需要时添加或删除学生信息。

<2>内存管理:为了防止内存泄漏和数组越界,每次使用malloc或realloc分配内存后,确保在适当的时候使用free释放内存。

<3>优化排序算法:为了提高排序性能,使用快速排序或归并排序。

实训小结

在本次实训中,构建了一个功能完备的学生信息管理系统,涉及了数据结构设计、动态内存分配、排序算法实现、错误处理以及用户交互等多个方面。

一、数据结构设计

在第一个实验中,面临数据结构设计的问题,使用固定大小的数组来存储学生信息,限制了系统的可扩展性。为了解决这个问题,使用动态分配的数组(即动态数组),使得系统可以根据需要动态地添加或删除学生信息。这大大提高了系统的灵活性和可扩展性。

二、动态内存分配

在第二个实验中,深入学习了动态内存分配的概念,并实践了malloc和realloc等函数的使用。然而,在这个过程中,容易遇到内存泄漏和数组越界的问题。通过不断调试和修改代码,学会了如何正确地分配和释放内存,以及如何避免数组越界。

三、排序算法实现

在第三个实验中,实现了按学号排序的功能。冒泡排序算法在大数据集上性能不佳。为了提高性能,考虑了更高效的排序算法,如快速排序或归并排序。然而,为了保持实验的简单性,最终选择了优化冒泡排序算法的性能。通过添加标志来检测数组是否已排序,我们显著提高了排序的效率。

四、错误处理

在第四个实验中,专注于提高系统的错误处理能力。在删除和查找操作时,如果输入了不存在的学号,程序可能会崩溃或给出不正确的反馈。为了解决这个问题,在代码中添加了更多的条件判断,以检测用户输入的有效性和学生信息的存在性。如果输入了不存在的学号,程序会给出清晰的错误提示,而不是崩溃或给出不正确的反馈。这大大提高了系统的稳定性和用户体验。

五、用户交互

在最后一个实验中,改善了系统的用户交互界面。通过增加清晰的提示和反馈,使系统更加易于使用和理解。例如,在输入学号时,给出了明确的格式要求;在删除或查找学生时,给出了操作成功或失败的提示。这些改进使得用户能够更轻松地与系统交互,并提高了系统的整体可用性。

通过这五个实验,不仅掌握了C语言编程的基本技能,还学会了如何设计和实现一个完整的系统。在解决问题的过程中,提高了自己的编程能力、分析问题的能力以及解决问题的能力。同时,也对数据结构、动态内存分配、排序算法、错误处理以及用户交互等方面有了更深入的了解。这些经验和知识将对未来的学习和工作产生积极的影响。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实训一 数组模块实训
    • 一、实训目的
      • 二、 实训任务
        • (1)任务分析
          • (2)程序
            • (3)结果演示
              • (4)小结
              • 实训二 函数模块实训
                • 一、 实训目的
                  • 二、 实训任务
                    • (1)任务分析
                      • (2)程序
                        • (3)结果演示
                          • (4)小结
                          • 实训三 指针模块实训
                            • 一、实训目的
                              • 二、 实训任务
                                • (1)任务分析
                                  • (2)程序
                                    • (3)结果演示
                                      • (4)小结
                                      • 实训四 结构体模块实训
                                        • 一、 实训目的
                                          • 二、 实训任务
                                            • (1)任务分析
                                              • (2)程序
                                                • (3)结果演示
                                                  • (4)小结
                                                  • 实训五 综合实训
                                                    • 一、实验目的
                                                      • 二、 实训任务
                                                        • (1)任务分析
                                                          • (2)程序
                                                            • (3)结果演示
                                                              • (4)小结
                                                              • 实训小结
                                                              领券
                                                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档