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 50typedef 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_Hvoid 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.mzph.cn/diannao/66383.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云安全博客阅读(二)

2024-05-30 Cloudflare acquires BastionZero to extend Zero Trust access to IT infrastructure IT 基础设施的零信任 不同于应用安全&#xff0c;基础设置的安全的防护紧急程度更高&#xff0c;基础设施的安全防护没有统一的方案IT基础设施安全的场景多样&#xff0c;如se…

06-RabbitMQ基础

目录 1.初识MQ 1.1.同步调用 1.2.异步调用 1.3.技术选型 2.RabbitMQ 2.1.安装 2.2.收发消息 2.2.1.交换机 2.2.2.队列 2.2.3.绑定关系 2.2.4.发送消息 2.3.数据隔离 2.3.1.用户管理 2.3.2.virtual host 3.SpringAMQP 3.1.导入Demo工程 3.2.快速入门 3.2.1.消…

【Linux系列】并发与顺序执行:在 Linux 脚本中的应用与选择

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【机器学习篇】 科技异次元的超强 “魔杖”,开启奇幻新程

一起开启这场旅行吧&#xff0c;关注博主&#xff0c;点赞支持不迷路&#xff0c;下面一同欣赏本篇的美妙吧&#xff01;&#xff01; &#xff01; 博主主页&#xff1a; 羑悻的小杀马特.-CSDN博客 在当今科技飞速发展的时代&#xff0c;机器学习宛如一把来自科技异次元的超强…

联发科MTK6771/MT6771安卓核心板规格参数介绍

MT6771&#xff0c;也被称为Helio P60&#xff0c;是联发科技(MediaTek)推出的一款中央处理器(CPU)芯片&#xff0c;可运行 android9.0 操作系统的 4G AI 安卓智能模块。MT6771芯片采用了12纳米工艺制造&#xff0c;拥有八个ARM Cortex-A73和Cortex-A53核心&#xff0c;主频分别…

ros2笔记-2.5.3 多线程与回调函数

本节体验下多线程。 python示例 在src/demo_python_pkg/demo_python_pkg/下新建文件&#xff0c;learn_thread.py import threading import requestsclass Download:def download(self,url,callback):print(f线程&#xff1a;{threading.get_ident()} 开始下载&#xff1a;{…

人工智能的发展领域之GPU加速计算的应用概述、架构介绍与教学过程

文章目录 一、架构介绍GPU算力平台概述优势与特点 二、注册与登录账号注册流程GPU服务器类型配置选择指南内存和存储容量网络带宽CPU配置 三、创建实例实例创建步骤镜像选择与设置 四、连接实例SSH连接方法远程桌面配置 一、架构介绍 GPU算力平台概述 一个专注于GPU加速计算的…

Unity【Colliders碰撞器】和【Rigibody刚体】的应用——小球反弹效果

目录 Collider 2D 定义&#xff1a; 类型&#xff1a; Rigidbody 2D 定义&#xff1a; 属性和行为&#xff1a; 运动控制&#xff1a; 碰撞检测&#xff1a; 结合使用 实用检测 延伸拓展 1、在Unity中优化Collider 2D和Rigidbody 2D的性能 2、Unity中Collider 2D…

[微服务]redis主从集群搭建与优化

搭建主从集群 单节点Redis的并发能力是有上限的&#xff0c;要进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写分离。 1. 主从集群结构 下图就是一个简单的Redis主从集群结构&#xff1a; 如图所示&#xff0c;集群中有一个master节点、两个s…

自动化立体仓库堆垛机SRM控制系统自动控制功能块开发

1、堆垛机SRM控制系统硬件组态如下图 2、堆垛机SRM控制系统HMI屏幕页面如下图 驱动状态显示、堆垛机状态 3、堆垛机SRM控制系统中相关变量定义如下图 其中包含系统控制相关变量:系统急停、系统手动、复位、货叉左极限、货叉左居中 货叉右极限 货叉右居中 货叉编码器位置反…

【数据结构】栈与队列(FIFO)

在阅读该篇文章之前&#xff0c;可以先了解一下堆栈寄存器和栈帧的运作原理&#xff1a;<【操作系统】堆栈寄存器sp详解以及栈帧>。 栈(FILO) 特性: 栈区的存储遵循着先进后出的原则。 例子: 枪的弹夹&#xff0c;最先装进去的子弹最后射出来&#xff0c;最后装入的子弹…

黑马JavaWeb开发跟学(十五).Maven高级

黑马JavaWeb开发跟学.十五.Maven高级 Maven高级1. 分模块设计与开发1.1 介绍1.2 实践1.2.1 分析1.2.2 实现 1.3 总结 2. 继承与聚合2.1 继承2.1.1 继承关系2.1.1.1 思路分析2.1.1.2 实现 2.1.2 版本锁定2.1.2.1 场景2.1.2.2 介绍2.1.2.3 实现2.1.2.4 属性配置 2.2 聚合2.2.1 介…

入门级容器技术解析:Docker和K8s的区别与关系

目录 &#x1f3af;学习小目标&#xff1a; 关于容器 传统物理机&#x1f5a5;️ 虚拟机&#x1f4bb; 为什么使用容器技术呢&#xff1f;&#x1f914; 容器技术&#x1f943; Docker—容器化平台 K8s(Kubernetes)—容器编排系统​ Docker和K8s有什么关系和区别&#…

凌鸥电机开发学习记录

文章目录 9、凌鸥库函数软件过流点设定值BUG8、系统初始化7、ADC触发周期设定6、电机参数测量5、有感HALL相序问题4、电机参数问题3、PWM频率设置2、IO口对应问题1、供电问题 9、凌鸥库函数软件过流点设定值BUG 在软件过流点的判断中&#xff0c;是以当前三相电流和经过了内部…

怎样修改el-table主题样式

起因&#xff1a;el-table有主题样式&#xff0c;部分需要单独设置 环境&#xff1a;ideanodejs插件谷歌浏览器 第一步&#xff1a;找到scss文件&#xff1a; 谷歌浏览器打开表格页面&#xff0c;ctrlshifti打开开发者工具&#xff0c;点击后鼠标移动到表格单元格上单击一下…

Flink operator实现自动扩缩容

官网文档位置&#xff1a; 1.Autoscaler | Apache Flink Kubernetes Operator 2.Configuration | Apache Flink Kubernetes Operator 1.部署K8S集群 可参照我之前的文章k8s集群搭建 2.Helm安装Flink-Operator helm repo add flink-operator-repo https://downloads.apach…

从入门到精通:Ansible Shell 模块的应用与最佳实践

Ansible是一款强大的自动化运维工具&#xff0c;通过其模块化的设计&#xff0c;可以方便地管理和配置远程主机。作为Ansible的一个常用模块&#xff0c;shell 模块使得我们可以在目标主机上执行复杂的命令或脚本。无论是单一的命令&#xff0c;还是复杂的Shell脚本&#xff0c…

Linux应用软件编程--网络通信(传输层:udp协议,tcp协议,应用层:http协议)

网络通信&#xff1a;不同主机&#xff0c;进程间通信&#xff0c;分为广域网和局域网 OSI 七层模型&#xff1a;是一种理论模型 应用层&#xff1a;通信传输的数据内容 http、FTP、TFTP、MQTT 表述层&#xff1a;数据加密&#xff0c;解密操作&#xff0c;压缩&#xff…

鸿蒙的APP真机调试以及发布

目录&#xff1a; 1、创建好鸿蒙项目2、创建AGC项目3、实现自动签名3.1、手动方式创建签名文件和密码 4、运行项目5、无线真机调试 1、创建好鸿蒙项目 2、创建AGC项目 &#xff08;1&#xff09;在File->Project Structure->Project->Signing Configs中进行登录。(未…

n8n - AI自动化工作流

文章目录 一、关于 n8n关键能力n8n 是什么意思 二、快速上手 一、关于 n8n n8n是一个具有原生AI功能的工作流自动化平台&#xff0c;它为技术团队提供了代码的灵活性和无代码的速度。凭借400多种集成、原生人工智能功能和公平代码许可证&#xff0c;n8n可让您构建强大的自动化…