【C语言篇】C 语言总复习(下):点亮编程思维,穿越代码的浩瀚星河

在这里插入图片描述
在这里插入图片描述

我的个人主页
我的专栏C语言,希望能帮助到大家!!!点赞❤ 收藏❤
在这里插入图片描述

在C语言的世界里,结构体和联合体以及文件操作都是非常重要且实用的知识板块,掌握它们能帮助我们更高效地组织数据以及与外部文件进行交互。今天,就让我们一同深入探究这些内容吧。

一、结构体与联合体

(一)结构体的定义与使用

1. 结构体类型的声明与结构体变量的定义、初始化

结构体允许我们将不同类型的数据组合在一起,形成一个新的自定义数据类型。例如,我们要描述一个学生的信息,可能包含姓名(字符数组类型)、年龄(整型)和成绩(浮点型)等不同类型的数据,就可以这样声明结构体类型:

struct Student {char name[20];int age;float score;
};

声明好结构体类型后,我们可以定义结构体变量并进行初始化,像这样:

struct Student stu1 = {"Tom", 18, 85.5};
2. 结构体成员的访问与操作

一旦定义了结构体变量,我们就可以通过“.”操作符来访问其成员。例如,要获取stu1的姓名,可以使用stu1.name;要修改年龄,可以写成stu1.age = 19;,操作起来十分直观便捷,让我们能够灵活地处理结构体中各个成员的数据。

3. 结构体数组与结构体指针

有时候,我们需要处理多个同类型的结构体对象,这时候结构体数组就派上用场了。比如定义一个班级学生的结构体数组:

struct Student classStudents[30];

而结构体指针则可以更高效地操作结构体,特别是在函数传参等场景下,能够避免大量数据的复制。可以通过->操作符来访问结构体指针所指向结构体的成员,例如:

struct Student *pStu = &stu1;
pStu->age = 20;
4. 结构体作为函数参数与返回值

结构体可以作为函数的参数传递,不过要注意,如果结构体较大,直接传递可能会有性能损耗,这时候传递结构体指针会是更好的选择。同时,函数也可以返回结构体,方便我们从函数中获取多个相关的数据结果,例如:

struct Student createStudent(char *name, int age, float score) {struct Student newStu;strcpy(newStu.name, name);newStu.age = age;newStu.score = score;return newStu;
}

(二)联合体的概念与应用

1. 联合体的定义与特点(共享内存)

联合体和结构体有点类似,但它最大的特点是其所有成员共享同一块内存空间。也就是说,在某一时刻,联合体中只有一个成员的值是有效的,其定义形式如下:

union Data {int num;char ch;
};

例如,当我们给union Datanum成员赋值后,再去访问ch成员,其实就是从同一块内存按照不同的类型解读数据,这在一些内存空间有限且需要根据不同情况复用的场景很有用。

2. 联合体的使用场景

在嵌入式开发中,常常会遇到需要根据不同的配置或者状态来复用同一块内存区域存储不同类型数据的情况,联合体就能很好地满足需求。比如在通信协议解析中,接收到的数据可能根据不同的指令代表不同的数据类型,这时候可以利用联合体方便地进行处理。

二、文件操作

(一)文件的基本概念

1. 文件的类型(文本文件与二进制文件)

C语言中的文件主要分为文本文件和二进制文件。文本文件是以字符形式存储数据,便于人类阅读,每行以换行符等作为结束标志;而二进制文件则是按照数据在内存中的存储形式原样保存,更适合保存一些结构化的数据,比如结构体数组等,并且读写效率通常更高,不过可读性相对较差。

2. 文件指针与文件的打开与关闭(fopen、fclose函数)

文件指针是我们操作文件的关键,它指向了文件的相关信息结构体。通过fopen函数可以打开一个文件,例如:

FILE *fp = fopen("test.txt", "r");

这里"r"表示以只读方式打开文件。在使用完文件后,一定要记得用fclose函数关闭文件,释放相关资源,像这样:

fclose(fp);

(二)文件的读写操作

1. 字符读写函数(fgetc、fputc)

fgetc函数用于从文件中读取一个字符,而fputc则用于向文件中写入一个字符。例如,我们可以这样将一个字符写入文件:

fputc('A', fp);

再从文件中读取字符:

char ch = fgetc(fp);
2. 字符串读写函数(fgets、fputs)

fgets能够从文件中读取一行字符串,它会自动在读取到换行符或者达到指定长度时停止,使用起来很方便。fputs则可以将一个字符串写入文件,比如:

char str[] = "Hello World";
fputs(str, fp);
3. 格式化读写函数(fscanf、fprintf)

这两个函数类似于scanfprintf,不过它们是针对文件进行操作的。可以按照指定的格式从文件中读取数据或者向文件中写入数据,例如:

int num;
fscanf(fp, "%d", &num);
fprintf(fp, "%d", num);
4. 数据块读写函数(fread、fwrite)

如果要读写一块连续的数据,比如结构体数组等,freadfwrite就很实用了。它们可以按照指定的字节数来读写数据,像这样:

struct Student students[10];
fwrite(students, sizeof(struct Student), 10, fp);

(三)文件的定位与状态检测

1. 文件定位函数(fseek、ftell)

fseek函数可以用来改变文件指针的位置,实现随机读写的功能。例如,我们想将文件指针移动到文件开头,可以这样操作:

fseek(fp, 0, SEEK_SET);

ftell函数则能返回当前文件指针相对于文件开头的偏移量,方便我们知晓文件读取或写入的进度位置。

2. 文件状态检测函数(feof、ferror)

feof函数用于判断是否已经读到文件末尾了,而ferror函数则是用来检测在文件操作过程中是否出现了错误,便于我们及时处理异常情况,确保文件操作的正确性。

三、预处理指令

1. 宏定义

无参宏的定义与使用

无参宏是一种简单的文本替换机制,通过#define指令来定义。例如,定义一个表示圆周率PI的无参宏:

#define PI 3.14159

在编译预处理阶段,代码中所有出现PI的地方都会被替换为3.14159。它的优点是方便代码的修改和维护,如果需要改变PI的值,只需修改宏定义处即可,而不用在整个代码中逐一查找修改。

带参宏的展开规则与应用

带参宏可以像函数一样接受参数,但它本质上还是文本替换。例如,定义一个计算平方的带参宏:

#define SQUARE(x) ((x) * (x))

当使用SQUARE(5)时,在预处理阶段会展开为((5) * (5))。需要注意的是,参数在宏定义中要加上括号,以避免在复杂表达式中出现错误的运算顺序。例如,如果写成#define SQUARE(x) x * x,那么SQUARE(2 + 3)会展开为2 + 3 * 2 + 3,结果就不是预期的25了。带参宏常用于一些简单的、对性能要求较高且代码量较小的计算场景,因为它避免了函数调用的开销。

2. 文件包含指令

#include 的作用与用法

#include指令用于将指定的文件内容插入到当前源文件中。通常有两种形式:#include <文件名>#include "文件名"。尖括号形式用于包含标准库头文件,编译器会在系统指定的标准库路径中查找文件;双引号形式用于包含自定义头文件,编译器会先在当前源文件所在目录查找,如果找不到再去标准库路径查找。例如,要使用标准输入输出函数,就需要包含<stdio.h>头文件:

#include <stdio.h>

如果我们自己编写了一个头文件myheader.h,其中包含了一些自定义函数的声明,在使用这些函数的源文件中就可以使用#include "myheader.h"将其包含进来。

头文件的编写与组织

头文件一般包含函数声明、宏定义、结构体和联合体的声明等内容,但通常不包含函数的定义(除非是内联函数)。这样可以避免在多个源文件包含同一个头文件时出现重复定义的错误。例如,一个简单的头文件math_functions.h可以这样编写:

#ifndef MATH_FUNCTIONS_H
#define MATH_FUNCTIONS_H// 函数声明
int add(int a, int b);
float multiply(float a, float b);// 宏定义
#define MAX_NUM 100#endif

这里使用了条件编译指令#ifndef#define来防止头文件的重复包含。

3. 条件编译指令

#ifdef、#ifndef、#else、#endif 的使用场景

#ifdef指令用于判断某个宏是否已经被定义,如果定义了则编译其后的代码块。例如:

#ifdef DEBUGprintf("Debug mode is on.\n");
#endif

如果在之前定义了DEBUG宏,那么就会打印调试信息。

#ifndef#ifdef相反,它判断某个宏是否未被定义。常用于头文件防止重复包含,如前面提到的math_functions.h中的用法。

#else可以与#ifdef#ifndef配合使用,提供另一种编译选择。例如:

#ifdef DEBUGprintf("Debugging information.\n");
#elseprintf("Release version.\n");
#endif
条件编译在程序调试与跨平台开发中的应用

在程序调试时,可以通过条件编译来选择性地编译调试代码。例如,在开发过程中定义DEBUG宏,将一些调试信息输出的代码包含在#ifdef DEBUG块中,在发布版本时去掉DEBUG宏的定义,这些调试代码就不会被编译进最终的可执行文件,从而减小文件大小并提高运行效率。

在跨平台开发中,不同的操作系统或硬件平台可能需要不同的代码实现。可以利用条件编译来针对不同平台编写特定的代码块。例如:

#ifdef WIN32// Windows 平台相关代码
#elif defined(__LINUX__)// Linux 平台相关代码
#else// 其他平台代码
#endif

四、内存管理

1. 动态内存分配函数

malloc、calloc、realloc 函数的使用

malloc函数用于从堆内存中分配指定字节数的连续空间,并返回指向该空间的指针。例如:

int *p = (int *)malloc(5 * sizeof(int));

这里分配了能存储 5 个int类型数据的空间,并将返回的指针强制转换为int *类型后赋值给p

calloc函数与malloc类似,但它会在分配内存后将内存空间初始化为 0。例如:

int *p = (int *)calloc(5, sizeof(int));

这会分配 5 个int类型大小的空间,并将其初始化为 0。

realloc函数用于重新调整已分配内存块的大小。例如:

int *p = (int *)malloc(5 * sizeof(int));
// 假设之后需要更多空间
p = (int *)realloc(p, 10 * sizeof(int));

它会尝试将p指向的内存块大小调整为能存储 10 个int类型数据的空间,如果原内存块后面有足够连续的空闲空间,会直接扩展;否则会重新分配一块足够大的内存空间,并将原内存块中的数据复制过去,然后释放原内存块。

动态内存分配的注意事项与错误处理

在使用动态内存分配函数时,必须检查返回值是否为NULL。如果返回NULL,表示内存分配失败,例如:

int *p = (int *)malloc(100000000 * sizeof(int));
if (p == NULL) {printf("Memory allocation failed!\n");// 可以进行一些错误处理,如退出程序或尝试释放其他资源exit(1);
}

另外,使用完动态分配的内存后,一定要使用free函数释放,以避免内存泄漏。例如:

int *p = (int *)malloc(5 * sizeof(int));
// 使用 p 指向的内存
free(p);
p = NULL; // 建议将指针赋值为 NULL,防止悬空指针

2. 内存泄漏与悬空指针

内存泄漏的原因与检测方法

内存泄漏是指程序中动态分配的内存空间在不再使用后没有被释放。常见的原因包括忘记调用free函数、错误的指针操作导致无法正确释放内存等。例如:

while (1) {int *p = (int *)malloc(100 * sizeof(int));// 这里如果没有合适的释放机制,每次循环都会分配新内存而不释放,导致内存泄漏
}

检测内存泄漏可以使用一些工具,如 Valgrind(在 Linux 系统下)。它可以监控程序的内存使用情况,检测出内存泄漏的位置和原因。

悬空指针的产生与危害

悬空指针是指指针所指向的内存已经被释放,但指针仍然存在。例如:

int *p = (int *)malloc(5 * sizeof(int));
free(p);
// 此时 p 就是悬空指针,如果继续使用 p,会导致未定义行为,可能会崩溃或产生错误的结果

悬空指针可能会导致程序崩溃、数据损坏或产生难以调试的错误,因此在释放内存后,应将指针赋值为NULL或者将指针的作用域限制在合理范围内,避免其成为悬空指针。

五、C 语言综合应用与调试技巧

1. 综合项目案例分析

小型 C 语言项目的架构与实现思路

以一个简单的学生成绩管理系统为例,其架构可以包括数据存储模块(用于存储学生信息和成绩,可能使用结构体数组或链表)、数据输入输出模块(负责从用户获取数据和显示数据)、数据处理模块(如计算平均成绩、排序等)。

实现思路上,首先定义结构体来表示学生信息:

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

数据存储模块可以定义一个结构体数组来存储多个学生的信息:

struct Student students[100];

数据输入输出模块可以使用scanfprintf函数来实现与用户的交互,例如:

printf("Enter student name: ");
scanf("%s", students[i].name);

数据处理模块可以编写函数来计算平均成绩:

float averageScore(struct Student *students, int numStudents) {float sum = 0;for (int i = 0; i < numStudents; i++) {sum += students[i].score;}return sum / numStudents;
}
不同模块之间的协作与数据传递

在学生成绩管理系统中,数据输入输出模块获取用户输入的数据后,将其传递给数据存储模块进行存储。数据处理模块则从数据存储模块获取数据进行处理,并将处理结果返回给数据输出模块进行显示。例如,在计算平均成绩时,数据处理模块的averageScore函数接收数据存储模块中的students数组和学生数量作为参数,计算出平均成绩后,数据输出模块将其打印出来:

float avg = averageScore(students, numStudents);
printf("Average score: %.2f\n", avg);

2. 程序调试方法与工具

使用调试器(如 gdb)进行程序调试

使用gdb调试器,首先要在编译程序时加上-g选项,以便生成调试信息。例如:

gcc -g -o myprogram myprogram.c

然后启动gdb并加载可执行文件:

gdb myprogram

gdb中,可以设置断点,例如在某一行代码处设置断点:

break 10

然后运行程序:

run

当程序运行到断点处时,会暂停,可以查看变量的值:

print variable_name

还可以单步执行程序(逐行执行):

next

或者进入函数内部单步执行:

step
常见错误类型(语法错误、逻辑错误、运行时错误)及排查方法
  • 语法错误:通常是由于违反了 C 语言的语法规则,如缺少分号、括号不匹配、变量未定义等。编译器在编译时会报告语法错误的位置和错误信息。排查方法是仔细查看编译器提示的错误信息,根据错误位置检查代码是否符合语法规范。例如,如果编译器提示“error: expected ‘;’ before ‘}’”,就需要检查对应的代码块,看是否遗漏了分号。
  • 逻辑错误:程序能正常编译运行,但结果不正确。这可能是由于算法错误、条件判断错误等原因。排查方法可以通过添加调试输出语句,打印关键变量的值,逐步分析程序的执行流程,找出逻辑错误的地方。例如,如果一个计算结果总是错误,可以在计算过程中的关键步骤打印中间变量的值,检查是否符合预期。
  • 运行时错误:如内存访问错误(越界访问、使用悬空指针等)、除以 0 等。这些错误通常在程序运行时才会出现,可能导致程序崩溃。排查方法可以使用调试器,如gdb,在程序崩溃时查看堆栈信息,确定错误发生的位置和原因。例如,如果程序因为访问非法内存地址而崩溃,gdb会显示相关的堆栈调用信息,帮助定位是哪一行代码导致了非法访问。

3. 代码优化与规范

C 语言代码优化的原则与策略
  • 减少不必要的计算:例如,避免在循环中进行重复的计算,如果某个表达式的值在循环过程中不变,可以将其提到循环外面计算一次。
  • 选择合适的数据结构和算法:根据问题的特点选择高效的数据结构和算法。例如,如果需要频繁地进行插入和删除操作,链表可能比数组更合适;如果需要快速查找元素,哈希表或二叉搜索树可能更高效。
  • 优化内存使用:合理使用动态内存分配,避免不必要的内存浪费。例如,如果知道一个数组的最大可能大小,可以预先分配足够的内存,而不是频繁地进行重新分配。
  • 编译器优化选项:使用编译器的优化选项,如gcc中的-O系列选项(如-O2-O3),让编译器自动对代码进行一些优化,但要注意可能会影响调试。
代码规范与风格的重要性及遵循的标准

良好的代码规范和风格可以提高代码的可读性、可维护性和可扩展性。例如,统一的命名规则(变量名、函数名采用有意义的名称,遵循驼峰命名法或下划线命名法)、合理的代码缩进(通常使用 4 个空格或一个制表符缩进)、适当的注释(对复杂的代码逻辑、函数功能等进行注释)。遵循一些行业标准,如 GNU 编码标准或公司内部的代码规范,可以使代码更易于团队协作开发和后续的维护升级。例如:

// 这是一个计算两个数之和的函数
int addNumbers(int num1, int num2) {// 计算和int sum = num1 + num2;return sum;
}

这里函数名采用了有意义的名称,代码有适当的缩进,并且对函数功能进行了注释,符合基本的代码规范要求。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/63959.shtml

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

相关文章

CNCF云原生生态版图-项目和产品综合分析

CNCF云原生生态版图-项目和产品综合分析 CNCF云原生生态版图-项目和产品综合分析整体统计分析中国研发人员贡献项目和产品其中&#xff0c;纳入 CNCF 管理的开源项目 链接 CNCF云原生生态版图-项目和产品综合分析 整体统计分析 在对云原生技术选型时&#xff0c;优先选择经过 …

VScode、Windsurf、Cursor 中 R 语言相关快捷键设置

前言 在生物信息学数据分析中&#xff0c;R语言是一个不可或缺的工具。为了提高R语言编程效率&#xff0c;合理设置快捷键显得尤为重要。本文介绍在VSCode Windsurf Cursor 中一些实用的R语言快捷键设置&#xff0c;让非 Rstudio 的 IDE 用起来得心应手&#x1f611; 操作种…

分布式任务调度平台xxl-job源码学习

XXL-JOB是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线&#xff0c;开箱即用。 官网&#xff1a;https://www.xuxueli.com/xxl-job/ github&#xff1a;https://github.com/xuxueli/xxl-…

Macbookpro M1 IDEA中安装mysql

一&#xff1a;安装与连接数据库 1. 首先在mysql中创建一个初始数据库&#xff1a;idea_db&#xff0c;如示&#xff1a; 2.打开IDEA,如果最右侧没有database窗口&#xff0c;则在插件那里下载“Database navigator”,稍后重启一下即可&#xff1b; 点击最右侧Database---->…

Linux内核结构及源码概述

参考&#xff1a;深入分析LINUX内核源码 深入分析Linux内核源码 (kerneltravel.net) Linux 是一个庞大、高效而复杂的操作系统&#xff0c;虽然它的开发起始于 Linus Torvalds 一个人&#xff0c;但随着时间的推移&#xff0c;越来越多的人加入了 Linux 的开发和对它的不断完善…

[Unity] Text文本首行缩进两个字符

Text文本首行缩进两个字符的方法比较简单。通过代码把"\u3000\u3000"加到文本字符串前面即可。 比如&#xff1a; 效果&#xff1a; 代码&#xff1a; TMPtext1.text "\u3000\u3000" "选择动作类型&#xff1a;";

容器内部时间和Node时间不同步问题

之前在《 Docker及Kubernetes使用过程中出现的问题&#xff08;FAQ&#xff09;》中的“FAQ30 容器内部时间和Node时间不同”分享过容器内部和容器服务器之间时间不一致的问题&#xff1b;这通常会导致各种问题&#xff0c;比如日志记录、定时任务等。 问题原因&#xff1a;问…

AI开源南京分享会回顾录

AI 开源南京分享会&#xff0c;已于2024年11月30日下午在国浩律师&#xff08;南京&#xff09;事务所5楼会议厅成功举办。此次活动由 KCC南京、PowerData、RISC-Verse 联合主办&#xff0c;国浩律师&#xff08;南京&#xff09;事务所协办。 活动以“开源视角的 AI 对话”为主…

OpenCV 图像变换与处理实战

OpenCV快速通关 第一章&#xff1a;OpenCV 简介与环境搭建 第二章&#xff1a;OpenCV 图像基本操作 第三章&#xff1a;OpenCV 图像变换与处理实战 OpenCV 图像变换与处理实战 OpenCV快速通关OpenCV 图像变换与处理实战一、OpenCV 基础与图像处理概览二、图像变换理论精析三、…

Ubuntu22.04安装docker desktop遇到的bug

1. 确认已启用 KVM 虚拟化 如果加载了模块&#xff0c;输出应该如下图。说明 Intel CPU 的 KVM 模块已开启。 否则在VMware开启宿主机虚拟化功能&#xff1a; 2. 下一步操作&#xff1a; Ubuntu | Docker Docs 3. 启动Docker桌面后发现账户登陆不上去&#xff1a; Sign in | …

【深度学习入门】深度学习介绍

1.1 深度学习介绍 学习目标 目标 知道深度学习与机器学习的区别了解神经网络的结构组成知道深度学习效果特点 应用 无 区别 特征提取方面 机器学习的特征工程步骤是要靠手动完成的&#xff0c;而且需要大量领域专业知识深度学习通常由多个层组成&#xff0c;它们通常将更简…

实现按键按下(低电平)检测到下降沿

按照流程进行编程 步骤1&#xff1a; 初始化函数 包括时基工作参数配置 输入通道配置 更新中断使能 使能捕获、捕获中断及计数器 HAL_TIM_IC_Init(&ic_handle) //时基参数配置 HAL_TIM_IC_ConfigChannel(&ic_handle,&ic_config,TIM_CHANNEL_2) //输…

汽车车牌标记支持YOLO,COCO,VOC三种格式标记,4000张图片的数据集

本数据集支持YOLO&#xff0c;COCO&#xff0c;VOC三种格式标记汽车车牌&#xff0c;无论是新能源汽车还是油车都能识别标记&#xff0c;该数据集一共包含4000张图片 数据集分割 4000总图像数 训练组 70&#xff05; 2800图片 有效集 20&#xff05; 800图片 测…

游秦岭山感

巍乎高哉&#xff01; 悠悠大秦岭 佑吾华夏之根脉 八水润之 泽万物而赋予生机 于万山之山中 享自然之美于万物 西有昆仑祖龙脉 东有秦岭护关中 绿水青山国之本 万山长青谋发展 旭日东升耀中华 固我山河永泰安 你我同行共保护 关中龙脉更兴旺

阿里云-通义灵码:测试与实例展示

目录 一.引子 二.例子 三.优点 四.其他优点 五.总结 一.引子 在软件开发的广袤天地中&#xff0c;阿里云通义灵码宛如一座蕴藏无尽智慧的宝库&#xff0c;等待着开发者们去深入挖掘和探索。当我们跨越了入门的门槛&#xff0c;真正开始使用通义灵码进行代码生成和开发工作…

微信小程序中使用miniprogram-sm-crypto实现SM4加密攻略

在微信小程序开发过程中&#xff0c;数据安全至关重要。本文将为大家介绍如何在微信小程序中使用miniprogram-sm-crypto插件进行SM4加密&#xff0c;确保数据传输的安全性。 一、SM4加密简介 SM4是一种对称加密算法&#xff0c;由国家密码管理局发布&#xff0c;适用于商密领…

使用 Ansys Fluent 对气体泄漏检测进行建模

了解使用 Ansys Fluent 仿真气体泄漏和确保安全的前沿技术。 挑战 气体泄漏对人类安全和环境构成重大风险。及早检测气体泄漏可以防止潜在的灾难&#xff0c;包括爆炸、火灾和有毒物质暴露。有效的气体泄漏检测系统对于石油和天然气、化学加工和住宅基础设施等行业至关重要。…

QT图形/视图架构详解(一)

场景、视图与图形项 图形/视图架构主要由 3 个部分组成&#xff0c;即场景、视图和图形项&#xff0c;三者的关系如图所示&#xff1a; 场景、视图和图形项的关系 场景&#xff08;QGraphicsScene 类&#xff09; 场景不是界面组件&#xff0c;它是不可见的。场景是一个抽象的…

LLM之RAG实战(五十)| FastAPI:构建基于LLM的WEB接口界面

FastAPI是WEB UI接口&#xff0c;随着LLM的蓬勃发展&#xff0c;FastAPI的生态也迎来了新的机遇。本文将围绕FastAPI、OpenAI的API以及FastCRUD&#xff0c;来创建一个个性化的电子邮件写作助手&#xff0c;以展示如何结合这些技术来构建强大的应用程序。 下面我们开始分步骤操…

Maven学习(Maven项目模块化。模块间“继承“机制。父(工程),子项目(模块)间聚合)

目录 一、Maven项目模块化&#xff1f; &#xff08;1&#xff09;基本介绍。 &#xff08;2&#xff09;汽车模块化生产再聚合组装。 &#xff08;3&#xff09;Maven项目模块化图解。 1、maven_parent。 2、maven_pojo。 3、maven_dao。 4、maven_service。 5、maven_web。 6…