当前位置: 首页 > article >正文

C 语言奇幻之旅 - 第16篇:C 语言项目实战

目录

    • 引言
    • 1. 项目规划
      • 1.1 需求分析与设计
        • 1.1.1 项目目标
        • 1.1.2 功能需求
        • 1.1.3 技术实现方案
    • 2. 代码实现
      • 2.1 模块化编程
        • 2.1.1 学生信息模块
        • 2.1.2 成绩管理模块
      • 2.2 调试与测试
        • 2.2.1 调试
        • 2.2.2 测试
        • 2.2.4 测试结果
    • 3. 项目总结
      • 3.1 代码优化与重构
        • 3.1.1 代码优化
        • 3.1.2 代码重构
      • 3.2 项目反思
        • 3.2.1 存在的问题
        • 3.2.2 改进方式
    • 4. 模拟内存结构
      • 解释
    • 5. 案例执行结果
    • 结语

引言

欢迎来到 C 语言奇幻之旅的第16篇!在这一篇中,我们将一起踏上一段激动人心的项目实战之旅。无论你是初学者、中级开发者还是资深开发者,这篇文章都将为你提供宝贵的实战经验。我们将从项目规划、代码实现到项目总结,一步步带你领略 C 语言的魅力。准备好了吗?让我们开始吧!


1. 项目规划

1.1 需求分析与设计

在开始任何项目之前,需求分析和设计是至关重要的。我们需要明确项目的目标、功能需求以及技术实现方案。

1.1.1 项目目标

我们的项目目标是开发一个简单的学生成绩管理系统。该系统将允许用户添加学生信息、录入成绩、查询成绩以及计算平均成绩。通过这个项目,我们将学习如何将 C 语言的基础知识应用到实际开发中。

1.1.2 功能需求
  • 添加学生信息:用户可以输入学生的姓名、学号和成绩。
  • 录入成绩:用户可以录入学生的各科成绩。
  • 查询成绩:用户可以通过学号查询学生的成绩。
  • 计算平均成绩:系统可以计算并显示学生的平均成绩。
  • 删除学生信息:用户可以通过学号删除学生的信息。
  • 错误处理:系统能够处理无效输入(如重复学号、成绩超出范围等)。
1.1.3 技术实现方案

我们将采用模块化编程的方式来实现这个系统。每个功能模块将独立开发,最后通过主程序进行整合。为了提高代码的可维护性,我们将使用头文件源文件分离的方式组织代码。


2. 代码实现

2.1 模块化编程

模块化编程是将程序分解为多个独立模块的编程方法。每个模块负责一个特定的功能,这样可以提高代码的可读性、可维护性和可重用性。

2.1.1 学生信息模块
// student.h
#ifndef STUDENT_H
#define STUDENT_H

#define MAX_STUDENTS 100
#define NAME_LENGTH 50

typedef struct {
    char name[NAME_LENGTH];
    int id;
    float score;
} Student;

void addStudent(Student *students, int *count);
void deleteStudent(Student *students, int *count, int id);
void displayStudents(Student *students, int count);

#endif
// student.c
#include <stdio.h>
#include <string.h>
#include "student.h"

void addStudent(Student *students, int *count) {
    if (*count >= MAX_STUDENTS) {
        printf("错误:学生列表已满!\n");
        return;
    }

    Student newStudent;
    printf("请输入学生姓名:");
    scanf("%s", newStudent.name);
    printf("请输入学生学号:");
    scanf("%d", &newStudent.id);
    printf("请输入学生成绩:");
    scanf("%f", &newStudent.score);

    // 检查学号是否重复
    for (int i = 0; i < *count; i++) {
        if (students[i].id == newStudent.id) {
            printf("错误:学号已存在!\n");
            return;
        }
    }

    students[*count] = newStudent;
    (*count)++;
    printf("学生添加成功!\n");
}

void deleteStudent(Student *students, int *count, int id) {
    int found = 0;
    for (int i = 0; i < *count; i++) {
        if (students[i].id == id) {
            // 将最后一个学生信息移动到删除的位置
            students[i] = students[*count - 1];
            (*count)--;
            found = 1;
            printf("学生删除成功!\n");
            break;
        }
    }
    if (!found) {
        printf("错误:未找到该学号!\n");
    }
}

void displayStudents(Student *students, int count) {
    if (count == 0) {
        printf("没有找到学生信息。\n");
        return;
    }
    for (int i = 0; i < count; i++) {
        printf("姓名:%s,学号:%d,成绩:%.2f\n", students[i].name, students[i].id, students[i].score);
    }
}
2.1.2 成绩管理模块
// grade.h
#ifndef GRADE_H
#define GRADE_H

void enterGrades(Student *students, int count);
void queryGrade(Student *students, int count);
float calculateAverage(Student *students, int count);

#endif
// grade.c
#include <stdio.h>
#include "grade.h"
#include "student.h"

void enterGrades(Student *students, int count) {
    int id;
    printf("请输入学生学号:");
    scanf("%d", &id);
    for (int i = 0; i < count; i++) {
        if (students[i].id == id) {
            printf("请输入新的成绩:");
            scanf("%f", &students[i].score);
            printf("成绩更新成功!\n");
            return;
        }
    }
    printf("错误:未找到该学号!\n");
}

void queryGrade(Student *students, int count) {
    int id;
    printf("请输入学生学号:");
    scanf("%d", &id);
    for (int i = 0; i < count; i++) {
        if (students[i].id == id) {
            printf("姓名:%s,成绩:%.2f\n", students[i].name, students[i].score);
            return;
        }
    }
    printf("错误:未找到该学号!\n");
}

float calculateAverage(Student *students, int count) {
    if (count == 0) {
        printf("没有找到学生信息。\n");
        return 0.0;
    }
    float sum = 0;
    for (int i = 0; i < count; i++) {
        sum += students[i].score;
    }
    return sum / count;
}

2.2 调试与测试

在编写完代码后,我们需要进行调试和测试,以确保程序的正确性和稳定性。

2.2.1 调试

调试是发现和修复代码中错误的过程。我们可以使用调试工具(如 gdb)来逐步执行代码,检查变量的值和程序的执行流程。

2.2.2 测试

测试是验证程序是否按预期工作的过程。我们可以编写测试用例,覆盖所有功能模块,确保每个功能都能正常工作。

// main.c
#include <stdio.h>
#include "student.h"
#include "grade.h"

int main() {
    Student students[MAX_STUDENTS];
    int count = 0;
    int choice;

    while (1) {
        printf("\n--- 学生成绩管理系统 ---\n");
        printf("1. 添加学生\n");
        printf("2. 删除学生\n");
        printf("3. 录入成绩\n");
        printf("4. 查询成绩\n");
        printf("5. 计算平均成绩\n");
        printf("6. 显示所有学生\n");
        printf("7. 退出\n");
        printf("请输入您的选择:");
        scanf("%d", &choice);

        switch (choice) {
            case 1:
                addStudent(students, &count);
                break;
            case 2:
                if (count == 0) {
                    printf("没有学生可删除。\n");
                } else {
                    int id;
                    printf("请输入要删除的学生学号:");
                    scanf("%d", &id);
                    deleteStudent(students, &count, id);
                }
                break;
            case 3:
                enterGrades(students, count);
                break;
            case 4:
                queryGrade(students, count);
                break;
            case 5:
                printf("平均成绩:%.2f\n", calculateAverage(students, count));
                break;
            case 6:
                displayStudents(students, count);
                break;
            case 7:
                printf("正在退出...\n");
                return 0;
            default:
                printf("无效的选择,请重试。\n");
        }
    }

    return 0;
}
2.2.4 测试结果

该实战程序测试结果如下,测试程序的在下一同级标题,测试结果使用 GIF 演示,该 GIF 生成程序由本人制作,现已开源,希望更多小伙伴一同加入开发。

在这里插入图片描述

完整源码,复制到任意支持 C 语言开发的环境下即可。

#include <stdio.h>
#include <string.h>
#include "student.h"

void addStudent(Student *students, int *count) {
	if (*count >= MAX_STUDENTS) {
		printf("错误:学生列表已满!\n");
		return;
	}
	
	Student newStudent;
	printf("请输入学生姓名:");
	scanf("%s", newStudent.name);
	printf("请输入学生学号:");
	scanf("%d", &newStudent.id);
	printf("请输入学生成绩:");
	scanf("%f", &newStudent.score);
	
	// 检查学号是否重复
	for (int i = 0; i < *count; i++) {
		if (students[i].id == newStudent.id) {
			printf("错误:学号已存在!\n");
			return;
		}
	}
	
	students[*count] = newStudent;
	(*count)++;
	printf("学生添加成功!\n");
}

void deleteStudent(Student *students, int *count, int id) {
	int found = 0;
	for (int i = 0; i < *count; i++) {
		if (students[i].id == id) {
			// 将最后一个学生信息移动到删除的位置
			students[i] = students[*count - 1];
			(*count)--;
			found = 1;
			printf("学生删除成功!\n");
			break;
		}
	}
	if (!found) {
		printf("错误:未找到该学号!\n");
	}
}

void displayStudents(Student *students, int count) {
	if (count == 0) {
		printf("没有找到学生信息。\n");
		return;
	}
	for (int i = 0; i < count; i++) {
		printf("姓名:%s,学号:%d,成绩:%.2f\n", students[i].name, students[i].id, students[i].score);
	}
}


void enterGrades(Student *students, int count) {
	int id;
	printf("请输入学生学号:");
	scanf("%d", &id);
	for (int i = 0; i < count; i++) {
		if (students[i].id == id) {
			printf("请输入新的成绩:");
			scanf("%f", &students[i].score);
			printf("成绩更新成功!\n");
			return;
		}
	}
	printf("错误:未找到该学号!\n");
}

void queryGrade(Student *students, int count) {
	int id;
	printf("请输入学生学号:");
	scanf("%d", &id);
	for (int i = 0; i < count; i++) {
		if (students[i].id == id) {
			printf("姓名:%s,成绩:%.2f\n", students[i].name, students[i].score);
			return;
		}
	}
	printf("错误:未找到该学号!\n");
}

float calculateAverage(Student *students, int count) {
	if (count == 0) {
		printf("没有找到学生信息。\n");
		return 0.0;
	}
	float sum = 0;
	for (int i = 0; i < count; i++) {
		sum += students[i].score;
	}
	return sum / count;
}

int main() {
	Student students[MAX_STUDENTS];
	int count = 0;
	int choice;
	
	while (1) {
		printf("\n--- 学生成绩管理系统 ---\n");
		printf("1. 添加学生\n");
		printf("2. 删除学生\n");
		printf("3. 录入成绩\n");
		printf("4. 查询成绩\n");
		printf("5. 计算平均成绩\n");
		printf("6. 显示所有学生\n");
		printf("7. 退出\n");
		printf("请输入您的选择:");
		scanf("%d", &choice);
		
		switch (choice) {
		case 1:
			addStudent(students, &count);
			break;
		case 2:
			if (count == 0) {
				printf("没有学生可删除。\n");
			} else {
				int id;
				printf("请输入要删除的学生学号:");
				scanf("%d", &id);
				deleteStudent(students, &count, id);
			}
			break;
		case 3:
			enterGrades(students, count);
			break;
		case 4:
			queryGrade(students, count);
			break;
		case 5:
			printf("平均成绩:%.2f\n", calculateAverage(students, count));
			break;
		case 6:
			displayStudents(students, count);
			break;
		case 7:
			printf("正在退出...\n");
			return 0;
		default:
			printf("无效的选择,请重试。\n");
		}
	}
	
	return 0;
}



3. 项目总结

3.1 代码优化与重构

在项目完成后,我们可以对代码进行优化和重构,以提高代码的质量和性能。

3.1.1 代码优化
  • 减少重复代码:将重复的代码提取到函数中,减少代码冗余。
  • 提高算法效率:优化算法,减少时间和空间复杂度。
3.1.2 代码重构
  • 模块化重构:将功能相似的代码合并到一个模块中,提高代码的可读性和可维护性。
  • 命名规范:使用有意义的变量名和函数名,提高代码的可读性。

3.2 项目反思

在完成项目后,我们需要反思项目的开发过程,思考可能存在的问题和改进方式。

3.2.1 存在的问题
  • 代码耦合度高:部分模块之间的耦合度较高,影响了代码的可维护性。
  • 错误处理不足:程序中没有足够的错误处理机制,可能导致程序崩溃。
3.2.2 改进方式
  • 降低耦合度:通过接口和抽象类降低模块之间的耦合度。
  • 增强错误处理:增加错误处理机制,提高程序的健壮性。

4. 模拟内存结构

为了更好地理解程序的运行机制,我们可以模拟程序在内存中的结构。以下是 students 数组在内存中的布局示例:

假设我们添加了以下学生信息:

  1. 学生1:姓名 = "张三", 学号 = 101, 成绩 = 85.5
  2. 学生2:姓名 = "李四", 学号 = 102, 成绩 = 90.0
  3. 学生3:姓名 = "王五", 学号 = 103, 成绩 = 78.5

内存结构如下:

地址字段名
0x1000姓名"张三"
0x1000+50学号101
0x1000+54成绩85.5
0x1050姓名"李四"
0x1050+50学号102
0x1050+54成绩90.0
0x10A0姓名"王五"
0x10A0+50学号103
0x10A0+54成绩78.5

解释

  • 姓名 字段:每个学生的 姓名 字段占用 50 字节(NAME_LENGTH 定义的大小)。
  • 学号 字段学号 是一个 int 类型,占用 4 字节。
  • 成绩 字段成绩 是一个 float 类型,占用 4 字节。

通过这种内存布局,我们可以清晰地看到每个学生的信息是如何在内存中存储的。


5. 案例执行结果

以下是程序的运行示例:

--- 学生成绩管理系统 ---
1. 添加学生
2. 删除学生
3. 录入成绩
4. 查询成绩
5. 计算平均成绩
6. 显示所有学生
7. 退出
请输入您的选择:1
请输入学生姓名:张三
请输入学生学号:101
请输入学生成绩:85.5
学生添加成功!

--- 学生成绩管理系统 ---
1. 添加学生
2. 删除学生
3. 录入成绩
4. 查询成绩
5. 计算平均成绩
6. 显示所有学生
7. 退出
请输入您的选择:1
请输入学生姓名:李四
请输入学生学号:102
请输入学生成绩:90.0
学生添加成功!

--- 学生成绩管理系统 ---
1. 添加学生
2. 删除学生
3. 录入成绩
4. 查询成绩
5. 计算平均成绩
6. 显示所有学生
7. 退出
请输入您的选择:6
姓名:张三,学号:101,成绩:85.50
姓名:李四,学号:102,成绩:90.00

--- 学生成绩管理系统 ---
1. 添加学生
2. 删除学生
3. 录入成绩
4. 查询成绩
5. 计算平均成绩
6. 显示所有学生
7. 退出
请输入您的选择:5
平均成绩:87.75

--- 学生成绩管理系统 ---
1. 添加学生
2. 删除学生
3. 录入成绩
4. 查询成绩
5. 计算平均成绩
6. 显示所有学生
7. 退出
请输入您的选择:7
正在退出...

结语

通过这个项目实战,我们不仅掌握了 C 语言的基本语法和编程技巧,还学会了如何进行模块化编程、调试与测试以及代码优化与重构。希望这篇文章能激发你对 C 语言的学习兴趣,并提升你的开发技能。继续努力,未来的编程大师就是你!


希望这篇博客能够激发你对 C 语言预处理器与宏的兴趣,并帮助你在编程之路上走得更远。Happy coding! 🚀


http://www.kler.cn/a/472711.html

相关文章:

  • 接口测试-postman(使用postman测试接口笔记)
  • uniapp实现后端数据i18n国际化
  • 《HeadFirst设计模式》笔记(上)
  • 加速物联网HMI革命,基于TouchGFX的高效GUI显示方案
  • 部署:上传项目代码 配置数据库
  • C#—Task异步的常用方法及TaskFactory工厂类详解
  • 安装 华三云实验室 H3C Cloud Lab
  • Android Studio 安装配置(个人笔记)
  • 【杂记】机器视觉 #opencv #numpy #matplotlib
  • 自闭症家庭:建立支持系统与平衡生活
  • QML学习(九) Qt Quick - Control2中的主要组件:Label组件和Button组件的属性和使用方法
  • 机器学习模型评估指标
  • 页面转 PDF 功能的实现思路与使用方法
  • 【算法】八大排序算法
  • PostgreSQL 插件的事务回调机制
  • 怎么把word试题转成excel?
  • 在windows系统上安装docker并自定义安装和数据存储位置
  • No Homebrew ruby 2.6.3_2 available for arm64 processors!
  • 微软Office存在的意义是什么?
  • 【深度学习量化交易12】基于miniQMT的量化交易框架总体构建思路——回测、模拟、实盘通吃的系统架构
  • 显示器太薄怎么用屏幕挂灯?2025最新屏幕挂灯什么牌子好
  • 如何在 LobeChat 中使用 Ollama
  • 《网络安全里的Linux基础:构建安全网络的关键基石》
  • Python爬虫基础——数据清洗
  • python虚拟环境的使用
  • 【2024华为OD-E卷-200分-会议接待】(题目+思路+JavaC++Python解析)