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

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! 🚀

相关文章:

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.…...

项目实战——使用python脚本完成指定OTA或者其他功能的自动化断电上电测试

前言 在嵌入式设备的OTA场景测试和其他断电上电测试过程中&#xff0c;有的场景发生在夜晚或者随时可能发生&#xff0c;这个时候不可能24h人工盯着&#xff0c;需要自动化抓取串口日志处罚断电上电操作。 下面的python脚本可以实现自动抓取串口指定关键词&#xff0c;然后触发…...

04、Redis深入数据结构

一、简单动态字符串SDS 无论是Redis中的key还是value&#xff0c;其基础数据类型都是字符串。如&#xff0c;Hash型value的field与value的类型&#xff0c;List型&#xff0c;Set型&#xff0c;ZSet型value的元素的类型等都是字符串。redis没有使用传统C中的字符串而是自定义了…...

【MySQL学习笔记】MySQL的索引

MySQL索引 1、索引概述2、 索引的数据结构2.1 BTree索引结构2.2 Hash索引结构2.3 InnoDB选择BTree的原因 3、索引分类4、索引的语法5、SQL性能分析5.1 SQL执行频率5.2 慢查询日志5.3 profile详情5.4 explain执行计划 6、索引使用规则6.1 最左前缀法则6.2 范围查询6.3索引失效情…...

利用ArcGIS快速准确地统计出地块的现状容积率

研究目的 根据建筑.dwg、建筑.dwg Annotation、建筑.dwg Polygon&#xff0c;地籍边界.shp等数据&#xff0c;利用GIS快速准确地统计出地块的现状容积率。 研究思路 加载数据图层&#xff1a;建筑.dwg Polygon、建筑.dwg Annotation&#xff0c;使用空间连接功能把建筑层数数…...

C++类的引入

C中类的前身 1> 面向对象三大特征&#xff1a;封装、继承、多态 2> 封装&#xff1a;将能够实现某一事物的所有万事万物都封装到一起&#xff0c;包括成员属性&#xff08;成员变量&#xff09;&#xff0c;行为&#xff08;功能函数&#xff09;都封装在一起&#xff…...

【跨域问题】

跨域问题 官方概念&#xff1a; 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域本质来说&#xff0c;是前端请求给到后端时候&#xff0c;请求头里面&#xff0c;有一个 Origin &#xff0c;会带上 协议域名端口号等&#xff1b;后端接受到请求&…...

“深入浅出”系列之FFmpeg:(1)音视频开发基础

我的音视频开发大部分内容是跟着雷霄骅大佬学习的&#xff0c;所以笔记也是跟雷老师的博客写的。 一、音视频相关的基础知识 首先播放一个视频文件的流程如下所示&#xff1a; FFmpeg的作用就是将H.264格式的数据转换成YUV格式的数据&#xff0c;然后SDL将YUV显示到电脑屏幕上…...

Springboot3.4整合jsp

文章目录 环境 springboot3.4 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency> <!--用于编译jsp--> <!-- Tomcat Embed Jasper --> <dependency>…...

CSS:背景样式、盒子模型与文本样式

背景样式 背景样式用于设置网页元素的背景&#xff0c;包括颜色、图片等。 背景颜色 使用 background-color 属性设置背景颜色&#xff0c;支持多种格式&#xff08;颜色英文、十六进制、RGB等&#xff09;。 div {background-color: lightblue; }格式示例十六进制#ff5733R…...

算法:线性查找

线性查找算法是一种简单的查找算法,用于在一个数组或列表中查找一个特定的元素。它从数组的第一个元素开始,逐个检查每个元素,直到找到所需的元素或搜索完整个数组。线性查找的时间复杂度为O(n),其中n是数组中的元素数量。 实现原理 从列表的第一个元素开始,逐个检查每个…...

【计算机网络】什么是网关(Gateway)?

网上冲浪多了&#xff0c;你可以听到过网关&#xff08;Gateway&#xff09;这个词&#xff0c;但是却不太清楚网关&#xff08;Gateway&#xff09;到底是干什么的、负责网络当中的什么任务&#xff0c;本篇文字将会为你介绍网关&#xff08;Gateway&#xff09;的作用&#x…...

20250106面试

rabbitmq如何保证消息不丢失 my&#xff1a; 持久化&#xff0c;包括消息持久化和队列持久化&#xff0c;重启不丢失。持久化到磁盘中的。 消息确认 死信队列&#xff1a;消费失败&#xff08;业务异常/未确认&#xff0c;重试后&#xff0c;会放死信队列&#xff09;&…...

Java 分布式锁:Redisson、Zookeeper、Spring 提供的 Redis 分布式锁封装详解

&#x1f4da; Java 分布式锁&#xff1a;Redisson、Zookeeper、Spring 提供的 Redis 分布式锁封装详解 在分布式系统中&#xff0c;分布式锁 用于解决多个服务实例同时访问共享资源时的 数据一致性 问题。Java 生态中&#xff0c;有多种成熟的框架可以实现分布式锁&#xff0…...

智能汽车的数字钥匙安全

数字钥匙作为汽车智能化变革下的一项创新技术&#xff0c;利用蓝牙定位、NFC等近场通信技术进行钥匙与汽车的匹配继而开锁&#xff0c;可以让车主通过智能手机、可穿戴设备等解锁汽车&#xff0c;并对汽车实施相关的操作&#xff0c;提升用车便利性&#xff0c;受到越来越多车企…...

YangQG 面试题汇总

一、交叉链表 问题&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 解题思想&#xff1a; 双指针 备注&#xff1a;不是快慢指针&#xff0c;如果两个长度相…...

急速了解什么是GPU服务器

GPU服务器是一种专门配置了高性能图形处理器&#xff08;GPU&#xff09;的服务器&#xff0c;旨在提供高性能计算、深度学习、科学计算等多种场景的计算服务。与传统的CPU服务器相比&#xff0c;GPU服务器在处理并行密集型计算任务时具有显著优势。本文将详细介绍GPU服务器的定…...

用 Python 绘制可爱的招财猫

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​​​ ​​​​​​​​​ ​​​​ 招财猫&#xff0c;也被称为“幸运猫”&#xff0c;是一种象征财富和好运的吉祥物&#xff0c;经常…...

Linux 获取文本部分内容

Linux获取文本部分内容 前言场景获取前几行内容获取末尾几行内容获取中间内容head 命令 tail 命令 结合sed 命令awk 命令 前言 test.log 文本内容如下&#xff1a; &#xff08;注意&#xff1a;内容 a1004和a1005之间有一空行&#xff09; [rootgaussdb002 tmp]# cat test.…...

01-51单片机LED与独立按键

一、单片机概述 注意&#xff1a;个人学习笔记&#xff0c;里面涉及到的C语言和进程转换相关的知识在C语言部分已经写了&#xff0c;这里是默认都会的状态学习单片机。 1.什么是单片机 单片机&#xff0c;英文Micro Controller Unit&#xff0c;简称MCU。其内部集成了CPU、R…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...