[C/C++]指针详讲-让你不在害怕指针

  •  个人主页:北·海
  •  🎐CSDN新晋作者
  •  🎉欢迎 👍点赞✍评论⭐收藏
  • ✨收录专栏:C/C++
  • 🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗

目录

前言

 一.&与*的作用与结合方向

二.指针和数组的关系

1.利用指针访问数组里的值

2.利用指针将数组作为实参传递给函数

 三.字符指针与字符数组

四.指针在内存分配中的应用

1.用C语言中的malloc在堆区分配动态内存

1.用C++中的new在堆区分配动态内存

五.使用指针为什么能提高程序的性能

六.指针与const搭配的四种情况

七.引用是实现原理

八.多级指针

九. 指针和函数的关系

1.通过指针使函数返回多个值

2.函数指针

3.函数的返回值类型为指针类型

十.指针和结构体的关系

 


前言

指针在编程语言中扮演着重要的角色,特别是在C语言中。指针提供了直接访问和操作内存地址的能力,使得编程更加灵活、高效,并且可以处理各种复杂的数据结构和算法。

以下是指针的几个重要方面和作用:

  1. 内存管理:指针允许程序直接与内存交互。通过使用指针,可以动态地分配和释放内存,避免了静态内存分配所带来的限制。这在处理动态数据结构(如链表、树、图等)和大规模数据中非常有用。

  2. 传递参数和引用:通过指针,可以在函数之间传递参数和引用。传递指针作为函数参数,可以避免在函数调用时产生副本,节省了内存和时间开销。此外,指针还可以用于函数返回多个值或修改调用者的变量。

  3. 动态数据结构:动态数据结构如链表、树、堆等通常需要使用指针进行内存分配和组织。指针可以在运行时创建、删除、连接和重新组织数据结构,使得数据结构的管理更加灵活和高效。

  4. 数组和字符串操作:在C语言中,数组实际上是通过指针来访问和操作的。指针使得数组可以直接访问和修改其元素,还可以进行指针算术操作,实现数组的遍历和操作。字符串在C语言中本质上是以空字符结尾的字符数组,指针的使用是对字符串进行处理的关键。

  5. 性能优化:指针的使用可以提高程序的性能。通过使用指针来访问和操作数据,可以减少副本的生成和数据的复制,提高程序的执行效率。


 一.&与*的作用与结合方向

作用: &在等号的右边为取地址符号,在等号的左边为引用符号

         *可以用做为乘号,也可用作为对指针变量解引的符号,取该地址存放的数据

结合方向:

“&”和“*”都是右结合的。假设有变量 x = 1,则*&x 的含义是,先获取变量 x 的地址,再获取地址中的内容。因为“&”和“*”互为逆运算,所以 x = *&x。

例如:输入 x、y 两个整数,然后将其中的值大的赋值给 x,小的赋值给 y。即:假设输入 x = 8,y = 9。就将 9 赋值给 x,8 赋值给 y。

void main(){//声明两个普通变量int x, y;//声明两个指针变量int *px, *py;//声明一个临时变量,用于交换int t;//输入两个值,赋值给 x、yscanf("%d", &x);scanf("%d", &y);//给指针变量 px、py 赋初值(关联变量 x、y)px = &x;py = &y;//利用指针来对比 x、y 的值,如果 x 的值比 y 的值小,就交换if(*px < *py){//交换步骤,其中*px == x、*py == yt = *px;*px = *py;*py = t;}printf("x =  %d, y = %d", *px, *py);
}

二.指针和数组的关系

1.利用指针访问数组里的值

	//利用指针访问数组里面的值int nums[] = {1,2,3,4};//方法一:下标法cout << "第一个数 :" << nums[0] << endl;//方法二:指针法cout << "第一个数 :" << *(nums + 0) << endl;//数组名就是数组元素的首地址

2.利用指针将数组作为实参传递给函数

void Test1(int nums[],int n) {for (int i = 0; i < n; i++) {cout << nums[i] << " ";}
}int main() {//利用指针访问数组里面的值int nums[] = {1,2,3,4};int* p = nums;//利用指针将数组作为实参传递给函数Test1(nums, 4);//数组名就是数组元素的首地址//方法二Test1(p, 4);//p指向数组,再将指向数组的指针传给被调函数
}

补充对指针加一 : 例如p++,不会将地址的值加一,而是将数组下移一位

 三.字符指针与字符数组

C语言中,没有字符串类型的变量,通常用字符数组或者字符指针存放字符串

1.字符数组的声明

	char str[] = "C++";char str1[] = { 'C','+','+' ,'\0'};字符数组的声明方式,在使用第二种声明方式的时候,必须在最后加上\0,此符号代表在这个地方该数组就结束了,如果不加该符号,会访问出界的

  字符数组的访问

	char str[] = "C++";char str1[] = { 'C','+','+' ,'\0'};printf("%s\n", str1);//%s格式化,表示直接输出整个数组printf("%c\n", str[0]);//利用数组法取str第一个字符printf("%c\n", *(str1 + 1));//利用指针法取str1的第2个字符

由上面可以看出,可以通过%c一个字符一个字符的输出,那么也可也利用循环输出每个字符

	for (int i = 0; i < strlen(str); i++) {printf("%c", str[i]);}

还可以用过strlen(str)或者sizeof(str)/sizeof(char)来获取该数组的长度

2.字符指针的声明

char *word = "have a good night";

  字符指针的访问

	const char* word = "have a good night";printf("%s\n", word);printf("%c\n", word[0]);for (int i = 0; i < strlen(word); i++) {printf("%c", word[i]);}

    对字符指针地址的加减

	const char* word = "have a good night";word++;printf("%s\n", word);//此时就会将指针下移到第一个a的地方,从a的地方进行输出,输出为:ave a good nightword--;printf("%s\n", word);//输出为:have a good nightconst char str[] = "C++";str++;//报错,在字符数组中不能进行加减操作,表达式必须是可修改的左值printf("%s", str);

四.指针在内存分配中的应用

1.用C语言中的malloc在堆区分配动态内存

1.利用malloc创建一维数组

#include <iostream>
#include <stdlib.h>
using namespace std;
int main() {int n;int* p = nullptr;cout << "请输入要存放的数据个数:";cin >> n;//在堆区分配内存p = (int *)malloc(n * sizeof(int));//输入for (int i = 0; i < n; i++) {cin >> *(p+i);}//输出for (int i = 0; i < n; i++) {cout << *(p+i) << " ";}free(p);
}

用malloc进行分配,注意malloc的返回值类型位void*类型,需要进行强制类型转换,由于在堆区分配的动态内存,所以在使用完之后,为了防止内存泄漏,需要用free进行释放

2.利用malloc进行开辟二位数组,与释放二位数组

#include <iostream>
#include <stdlib.h>
using namespace std;
int main() {int row = 0 ,col = 0 ;int** p = nullptr;cout << "依此输入行和列:" << endl;cin >> row>>col;//在堆区分配内存p = (int **)malloc(row * sizeof(int*));for (int i = 0; i < row; i++) {*(p + i) = (int*)malloc(col * sizeof(int));}//输入for (int i = 0; i < row * col; i++) {cin >> p[i / col][i % col];}//输出for (int i = 0; i < row * col; i++) {cout << p[i / col][i % col] << " ";}//释放动态开辟的二维数组for (int i = 0; i < row; i++) {free(p[i]);}free(p);
}

原理是,先创建一个指针数组,然后在利用改一级指针去创建动态int类型数组,在输入时候,用到了一个小技巧,用一层循环给二维数组赋值,在使用二维数组时候,应该先将每一层一级指针指向的内存块释放掉,然后再去释放该释放二级指针本身指向的内存块

1.用C++中的new在堆区分配动态内存

用到C++中的new分配内存,用delete释放内存,这里的new和delete只适用于c++中,malloc与free适用于c/c++,直接上例子

1.使用new进行分配一个动态的一维数组

int main() {int n;cout << "输入数组的大小:";cin >> n;int* p = new int[n];//输入for (int i = 0; i < n; i++) {cin >> *(p + i);}//输出for (int i = 0; i < n; i++) {cout << *(p + i) << " ";}delete[]p;
}

2.创建二维数组

int main() {int rows = 3;int cols = 4;// 创建动态二维数组int** array = new int*[rows];  // 创建一级指针数组for (int i = 0; i < rows; i++) {array[i] = new int[cols];  // 创建二级指针数组}// 使用动态二维数组for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {array[i][j] = i * cols + j;  // 给数组元素赋值}}// 打印动态二维数组for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {std::cout << array[i][j] << " ";}std::cout << std::endl;}// 释放动态二维数组的内存for (int i = 0; i < rows; i++) {delete[] array[i];  // 释放二级指针数组}delete[] array;  // 释放一级指针数组return 0;
}

和malloc的原理都是一样的,起始可以将一维数组创建的长一点,利用p[i / col][i % col];完全可以将一位数组当二维数组用,二维数组的存储方式也是按行存储的,地址都是连续的

在使用delete时候,数组的释放格式为 delete []p;,单个变量的释放格式为 delete p;

五.使用指针为什么能提高程序的性能

  • 直接访问内存:指针允许直接访问和操作内存中的数据。相比于通过变量的拷贝进行操作,直接访问内存可以减少数据的复制和移动,从而提高程序的执行效率。

#include <iostream>
using namespace std;
void Test1(int *p) {(*p)++;
}
void Test2(int m) {m++;
}
int main() {int num1 = 10,num2=10;Test1(&num1);cout << "Test1 :" << num1 << endl;//输出结果11Test2(num2);cout << "Test2 :" << num2 << endl;//输出结果10
}

Test1通过直接访问内存,避免了数据的拷贝和移动,提高了程序的执行效率。

Test2函数通过传递值的拷贝来操作变量。当我们调用该函数后,原始变量的值保持不变

  • 减少内存和时间开销:通过传递指针作为函数参数,可以避免在函数调用时产生变量的副本,从而减少内存的使用和传输的时间开销。特别是在处理大型数据结构或大量数据时,使用指针可以显著减少内存和时间的消耗。

  • 动态内存分配:指针使得动态内存分配成为可能,即在程序运行时根据需要分配和释放内存。相比于静态内存分配,动态内存分配可以更灵活地管理内存,避免内存浪费和限制,并且减少了程序启动时的内存占用。

六.指针与const搭配的四种情况

  • const 写在int之前,则限定不能通过*指针去改变该指针指向的值,但是可以指向别的指针
  • const 写在int之后,则限定可以通过*指针去改变该指针指向的值,但是不能指向别的指针
  • 两个const一个写在int前,一个写在变量名前,限制指针不能指向别的指针,并且不允许修改指针指向的值
  • 总结 : 看const离类型(int)近,还是理变量名近,离谁近,就修饰谁,谁就不能变
#include<iostream>
using namespace std;int main() {int wife = 30;int girl = 18;//第一种 : 渣男型,普通指针可以随意更改指向与指向地址的值int* zha_nan = &wife;cout << *zha_nan << endl;zha_nan = &girl;cout << *zha_nan << endl;//第二种 : 直男型,以自我为中心,可以改变指向,但是不可以改变指向的地址的值const int* zhi_nan = &wife;//*zhi_nan = 25;//报错,不能改变值zhi_nan = &girl;cout << *zhi_nan << endl;//第三种 : 暖男型,专一,不可以改变指向,但是可以改变指向的地址的值int* const nuan_nan = &wife;//nuan_nan = &girl;//报错,不能改变指向*nuan_nan = 25;cout << *nuan_nan << endl;//第四种 : 超级暖男型,超级专一,不能改变指向,也不能改变指向地址的值const int* const _super_nuan_nan = &wife;//*_super_nuan_nan = 25;//报错,不能改变指向地址的值//super_nuan_nan = &girl;//报错,不能改变指向//总结 : const理谁近就修饰谁,理(int)近,则修饰该指针的值不能改变,修饰变量,//	    则该指针不能在指向别的变量了
}

七.引用是实现原理

引用的底层也是用指针进行实现的

	int a = 0;int b = 2;int& c = a;c = b;//c是a的别名,将b的值赋值给c,就相当于将b的值也赋值给了acout << c << endl;//2cout << a << endl;//2//引用变量只能初始化一次,很像 int* const c = a;//该指针也只能进行一次初始化,就可以猜测引用的底层也是用该类型指针实现的

在使用引用的时候,编辑器会将引用类型转换为int * const 类型

例子:

void swap1(int& a, int& b) {int temp = a;a = b;b = temp;
}
void swap2(int* const a,int* const b) {int temp = *a;*a = *b;*b = temp;
}
int main() {int a = 1;int b = 2;swap1(a, b);//引用实现cout << "a = " << a << " b = " << b << endl;//a = 2,b =1swap2(&a, &b);cout << "a = " << a << " b = " << b << endl;//a = 2,b =1
}

对照swap1和swap2,在形参方面,引用变量会被改为int * const类型,在实参方面会将传入整数改为传入地址

八.多级指针

举例二级指针,懂了引用变量的话,那么对二级指针就可以有个优化了,提出指针引用,代码如下:

void home(int * p) {int b = 12;p = &b;
}
int main() {int a = 10;int* p = &a;//让p存放b的地址home(p);cout << *p << endl;//10
}

可以看出以上代码是无法改变p的指向的,改变值需要用一级指针,改变一级指针的指向需要用到二级指针,一次类推,这里直接就不写二级指针了,直接用一级指针的引用代替二级指针

void home(int *& p) {int b = 12;p = &b;
}
int main() {int a = 10;int* p = &a;//让p存放b的地址home(p);cout << *p << endl;//12
}

由此可以看出,利用指针引用可以将p的指向改变,这也的引用可以增强代码的可读性,与简洁性

九. 指针和函数的关系

1.通过指针使函数返回多个值

比如给你了一个已经初始化的数组,需要定义一个函数,用于返回这个数组的最大值与次大值,这个时候,为了增强代码的可读性,尽量返回一个数组,因为当返回的数据多了,也只能用返回数组实现了,代码如下:

void _max(int *nums,int n,int* exterm) {exterm[0] = nums[0];exterm[1] = nums[0];for (int i = 0; i < n; i++) {//大于次大的if (nums[i] > exterm[1]) {if (nums[i] > exterm[0]) {//大于最大的exterm[1] = exterm[0];exterm[0] = nums[i];}if (nums[i] < exterm[0]) {//小于最大的exterm[1] = nums[i];}}}
}int main() {//求该数组中的最大值与次大值int nums[] = { 2,6,4,9,5 };int exterm[2] = { 0 };_max(nums, 5, exterm);cout << exterm[0] << " " << exterm[1] << endl;//9,6
}

2.函数指针

函数指针是指向函数的指针变量。它可以存储函数的地址,并允许我们通过该指针调用相应的函数。函数指针在C和C++中都有广泛的应用,可以用于回调函数、函数参数以及实现函数的动态调用等场景。

要理解函数指针,首先需要了解函数的定义和函数指针的声明以及函数指针的使用方式。

1.函数定义:
返回类型 函数名(参数列表) {// 函数体
}2.函数指针的声明:
返回类型 (*指针变量名)(参数列表);指针变量名:函数指针的名称。
*:用于指明该变量是一个指针。
返回类型:函数指针指向的函数的返回类型。
参数列表:函数指针指向的函数的参数列表。3.将函数指针指向函数
指针变量名 = 函数名;4.通过函数指针调用函数:
(*指针变量名)(参数列表);//方法一
(指针变量名)(参数列表);//方法二

举例:

#include <iostream>int add(int a, int b) {return a + b;
}int subtract(int a, int b) {return a - b;
}int main() {// 声明函数指针int (*p)(int, int);// 将函数指针指向add函数p = add;// 通过函数指针调用add函数int result = (*p)(10, 5);std::cout << "Add: " << result << std::endl;// 将函数指针指向subtract函数p = subtract;// 通过函数指针调用subtract函数result = (*p)(10, 5);std::cout << "Subtract: " << result << std::endl;return 0;
}

3.函数的返回值类型为指针类型

int* creat() {return new int(1);//创建一个int类型的变量初始化为1,动态分配的数组不能进行初始化	
}int main() {//函数的返回值类型为指针变量类型,例子,//在creat函数里面动态的分配内存,将指向该段内存的指针返回int* p = creat();cout << "*p :" << *p << endl;//*p : 1delete p;
}

十.指针和结构体的关系

利用指针访问结构体里面的值

struct Test{int a;int b;int c;};struct Test ss = { 2,3,4 };//声明了结构对象ss,并把ss 的成员初始化为2,3 和4。struct Test* ptr = &ss;//声明了一个指向结构对象ss 的指针。它的类型是//Test *,它指向的类型是Test 。printf("%d", ptr->a);printf("%d", ptr->b);printf("%d", ptr->c);

 

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

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

相关文章

无涯教程-JavaScript - NEGBINOMDIST函数

NEGBINOMDIST函数取代了Excel 2010中的NEGBINOM.DIST函数。 描述 该函数返回负二项式分布。 NEGBINOMDIST返回在第number_s次成功之前出现number_f次失败的概率,而成功的恒定概率是概率_s。 该函数与二项式分布相似,不同之处在于成功次数是固定的,而试验次数是可变的。像二项…

基于51单片机的SHT11温湿度上下限LCD12864显示报警仿真设计( proteus仿真+程序+原理图+报告+讲解视频)

51单片机SHT11温湿度上下限LCD12864显示报警仿真设计( proteus仿真程序原理图报告讲解视频&#xff09; 讲解视频1.主要功能&#xff1a;2.仿真3. 程序代码4. 原理图5. 设计报告6. 设计资料内容清单&下载链接 51单片机SHT11温湿度上下限LCD12864显示报警仿真设计( proteus仿…

JVM 垃圾收集

垃圾收集 分代理论Java 堆的内存分区不同分代收集垃圾收集算法 分代理论 弱分代假说&#xff1a;绝大多数对象都是朝生夕灭&#xff0c;即绝大多数对象都是用完很快需要销毁的。强分代假说&#xff1a;熬过多次垃圾收集过程的对象就越难以消亡&#xff0c;即如果对象经过多次垃…

浏览器连不上 Flink WebUI 8081 端口

安装 flink-1.17.0 后&#xff0c;start-cluster.sh 启动&#xff0c;发现浏览器连不上 Flink WebUI 的8081端口。 问题排查&#xff1a; command R&#xff0c;输入cmd&#xff0c;检查宿主机能否ping通虚拟机&#xff0c;发现能ping通。 检查是否有flink以外的任务占用8081…

Linux网络编程 网络基础知识

目录 1.网络的历史和协议的分成 2.网络互联促成了TCP/IP协议的产生 3.网络的体系结构 4.TCP/IP协议族体系 5.网络各层的协议解释 6.网络的封包和拆包 7.网络预备知识 1.网络的历史和协议的分成 Internet-"冷战"的产物 1957年十月和十一月&#xff0c;前苏…

MusicBrainz Picard for Mac :音乐文件ID3编辑器

MusicBrainz Picard for Mac是一款macOS平台的音乐文件ID3编辑器&#xff0c;能够帮助我们在Mac电脑上编辑音乐文件的ID3标签信息&#xff0c;包括艺人、专辑等信息&#xff0c;非常快速和简单方便。Picard是下一代MusicBrainz标记应用程序。 这个新的标签概念是面向专辑的&…

美客多(mercadolibre)测评下单技术(养号环境搭建详解)

MercadoLibre&#xff08;美客多&#xff09;是拉丁美洲的一个网购平台。该公司为其客户提供电子商务交易的购买&#xff0c;出售&#xff0c;支付和收集机制。目前全球第十大电商市场——巴西是MercadoLibre的主要市场&#xff0c;占据近60%的平台营收&#xff0c;接着是阿根廷…

4.(Python数模)0-1规划

Python解决0-1规划问题 参考下面文章 源代码 import pulp # 导入 pulp 库# 主程序 def main():# 投资决策问题&#xff1a;# 公司现有 5个拟投资项目&#xff0c;根据投资额、投资收益和限制条件&#xff0c;问如何决策使收益最大。"""问题建模&#x…

PyTorch 模型性能分析和优化 - 第 3 部分

这[1]是关于使用 PyTorch Profiler 和 TensorBoard 分析和优化 PyTorch 模型主题的系列文章的第三部分。我们的目的是强调基于 GPU 的训练工作负载的性能分析和优化的好处及其对训练速度和成本的潜在影响。特别是&#xff0c;我们希望向所有机器学习开发人员展示 PyTorch Profi…

PHP8的数组-PHP8知识详解

今天开始学习数组&#xff0c; 本文主要讲了三点&#xff1a;什么是数组、php8中数组的改进、数组函数。 一、什么是数组 在PHP8中&#xff0c;数组是非常重要的数据类型。相对于其他的数据类型&#xff0c;数组更像一种结构&#xff0c;而这种结构可以储存一系列数值。 数组…

设计模式之桥接模式

文章目录 手机操作问题传统方案解决手机操作问题传统方案解决手机操作问题分析桥接模式(Bridge)-基本介绍桥接模式(Bridge)-原理类图桥接模式解决手机操作问题桥接模式的注意事项和细节桥接模式其它应用场景常见的应用场景: 手机操作问题 现在对不同手机类型的不同品牌实现操作…

国标视频融合云平台EasyCVR视频汇聚平台关于远程控制的详细介绍

EasyCVR国标视频融合云平台是一个能在复杂网络环境下统一汇聚、整合和集中管理各类分散视频资源的平台。该平台提供了多种视频能力和服务&#xff0c;包括视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、集群、电子地图、H.265视频自动转码和智能分析等…

安圭拉变成AI领域的数字金矿?

这个小小的岛国今年的域名销售额可能达到其GDP的10%&#xff01; 安圭拉a小小的英国岛屿领土在加勒比海地区&#xff0c;由于其“可再生能源”&#xff0c;今年可能带来高达3000万美元的收入。ai”域名&#xff0c;报告彭博在周四发表的一篇文章中说。在过去的一年里&#xff0…

手写Mybatis:第6章-数据源池化技术实现

文章目录 一、目标&#xff1a;数据源池化技术实现二、设计&#xff1a;数据源池化技术实现三、实现:数据源池化技术实现3.1 工程结构3.2 数据源池化技术关系图3.3 无池化链接实现3.4 有池化链接实现3.4.1 有连接的数据源3.4.2 池化链接的代理3.4.3 池状态定义3.4.4 pushConnec…

Linux系统下建立Socket聊天服务器

目录 1.服务器结构 2.各模块函数 2.1 socket函数 2.2 bind函数 2.3 Listen函数 2.4 accept函数 2.5 接收发送函数 2.6 close函数 2.7 connect函数 3 代码段 3.1 服务器代码 1.服务器结构 使用socket的API函数编写服务端和客户端程序的步骤图示: 2.各模块函数 服务…

Lliux管理员一些小技巧

1、查看bash日志 history命令显示日期和时间 2、打印时候对行列转换 xargs命令是改变已存在的文件的输出格式。“cat 文件名”是根据文件的行分隔符输出显示在屏幕上。如想改变一下&#xff0c;想把所有行合并为一行&#xff0c;就可以使用管道及xargs命令。 cat 文件名 |…

【原创】H3C三层交换机VLAN路由

网络拓扑图 VLAN 配置 VLAN 100 VLAN 200 [H3C]int vlan 100 ip address 1.1.1.1 255.255.255.0[H3C-Vlan-interface100]int vlan 200 ip address 2.2.2.1 255.255.255.0[H3C]int GigabitEthernet 1/0/1port access vlan 100[H3C]int GigabitEthernet 1/0/2port access vlan 2…

sql:SQL优化知识点记录(六)

&#xff08;1&#xff09;索引优化1 查看一下有没有建立索引&#xff1a; 用到索引中的一个&#xff1a;type中的ref决定访问性能 用到索引中的两个&#xff1a;通过key_len的长度可以看出来&#xff0c;比第一个大一点。或者通过ref&#xff1a;中用到了两个常量const 用到了…

黑马 大事件项目 笔记

学习视频&#xff1a;黑马 Vue23 课程 后台数据管理系统 - 项目架构设计 在线演示&#xff1a;https://fe-bigevent-web.itheima.net/login 接口文档: https://apifox.com/apidoc/shared-26c67aee-0233-4d23-aab7-08448fdf95ff/api-93850835 接口根路径&#xff1a; http:/…

Spring 系统架构

Spring总共大约有 20个模块&#xff0c;由1300多个不同的文件构成。而这些组件被分别整合在核心容器&#xff08;CoreContainer&#xff09;、AOP&#xff08;Aspect Oriented Programming&#xff09;和设备支持&#xff08;Instrmentation&#xff09;、数据访问及集成&#…