C语言——自定义类型:结构体

前言

本篇博客位大家介绍C语言中一块儿重要的内容,那就是结构体,关于结构体的内容,大家需要深入掌握,在后面的学习中依然会用到,如果你对本文感兴趣,麻烦点进来的老铁一键三连。多多支持,下面我们进入正文部分。

1. 结构体类型的声明

1.1 什么是结构体

C语言已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类 型还是不够的,假设我想描述学生,描述⼀本书,这时单⼀的内置类型是不行的。

描述⼀个学生需要名字、年龄、学号、身高、体重等;

描述一本书需要作者、出版社、定价等。C语言为了解决这个问 题,增加了结构体这种自定义的数据类型,让程序员可以自己创造适合的类型。

结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如: 标量、数组、指针,甚至是其他结构体。

上面为大家介绍了结构体的概念,大家需要进行理解;结构体就是用于一些比较复杂的对象,这也给了程序员一定的自由发挥的空间;

1.2 结构体的声明方法

关于结构体的声明方法其实挺简单的,大家来看下面的代码;

struct Stu
{
	char name[20];//名字 
	int age;//年龄 
	char sex[5];//性别 
	char id[20];//学号 
}; //分号不能丢 

这里大家可以看到,上面就是结构体的声明方法,这里要提醒大家一下,结尾的分号一定不能丢,否则程序将报错;

1.3 结构体的特殊声明 

上面说了结构体的一般声明方法,然而还存在一类特殊的声明方法,大家请看下面的代码;

struct
{
	int a;
	char b;
	double c;

}s = { 10,'a',3.14 };
int main()
{
	printf("%d %c %lf", s.a, s.b, s.c);
	return 0;
}

这里大家可以发现,我将结构体的名字省略掉了,这种声明方法声明的结构体叫做匿名结构体;这种声明方法声明的结构体在创建变量的时候,必须和声明同时进行,不能单独拿出来进行创建;

这里建议大家不要去使用匿名结构体类型,这种写法是容易出现问题的;

2. 结构体变量的创建和初始化

2.1 结构体变量的定义/创建

//代码1:变量的定义 
struct Point
{
 int x;
 int y;
}p1; //声明类型的同时定义变量p1 
struct Point p2; //定义结构体变量p2

大家可以看到,上面给出了两种创建方式,一种是在声明类型的同时进行定义;还有一种是单独进行定义;这两种方法都是正确的,大家根据自己的习惯进行选择。

2.2 结构体变量的初始化

//代码2:初始化。 
struct Point p3 = {10, 20};
struct Stu //类型声明
{
 char name[15];//名字 
 int age; //年龄 
};
struct Stu s1 = {"zhangsan", 20};//初始化 
struct Stu s2 = {.age=20, .name="lisi"};//指定顺序初始化
//代码3
#include<stdio.h>
struct s 
{
	int a;
	char b;
}; 
struct b
{
	struct s a;
	int* p;
	char arr[10];
	float sc;
};
int main()
{
	struct b c = { {10,'w'},NULL,"hehe",85.5f };
}

这里大家仔细观察上面的代码,在代码2中,展示了两种初始化的方法,一种是常规的初始化方法,按照声明时的顺序进行初始化;第二种初始化方法是按照指定顺序进行初始化,这里大家需要注意其写法,用到了“.”操作符,这是结构体成员访问操作符,这个后面还会为大家介绍;

下面来说说代码3,前面说过,结构体的成员可以是不同类型的变量,这里当然就包括结构体了;那么大家来看代码3,这里大家可以看到,我声明了两个不同的结构体,并且用第一个结构体定义了一个变量将其放到第二个结构体中,当我对第二个变量进行初始化的时候,大家注意嵌套结构体初始化的方法,对于嵌套的结构体,我们需要使用{}进行初始化,这里希望大家可以根据上面的代码理解嵌套结构体初始化的方法。

3. 结构体成员访问操作符

3.1 结构体成员的直接访问

结构体成员的直接访问是通过点操作符(.)访问的;点操作符接受两个操作数;如下所示:

#include <stdio.h>
struct Point
{
 int x;
 int y;
}p = {1,2};
int main()
{
 printf("x: %d y: %d\n", p.x, p.y);
 return 0;
}

 

上面大家看到,使同方式:结构体变量.成员名,这就是对结构体成员直接访问的方法;

那么这里就有一个问题,如果是嵌套结构体呢?我们应该如何进行访问,大家来看下面的代码;

#include<stdio.h>
struct s 
{
	int a;
	char b;
}; 
struct b
{
	struct s a;
	int* p;
	char arr[10];
	float sc;
};
int main()
{
	struct b c = { {10,'w'},NULL,"hehe",85.5f };
	printf("%c\n", c.a.b);
}

 

大家注意在访问嵌套结构体的时候,我们是按照顺序依次访问的,大家可以通过上面的代码进行理解,相信大家可以掌握。

3.2 结构体成员的间接访问 

有时候我们得到的不是⼀个结构体变量,而是得到了⼀个指向结构体的指针。如下所示:

#include <stdio.h>
struct Point
{
 int x;
 int y;
};
int main()
{
 struct Point p = {3, 4};
 struct Point *ptr = &p;
 ptr->x = 10;
 ptr->y = 20;
 printf("x = %d y = %d\n", ptr->x, ptr->y);
 return 0;
}

这里大家注意,间接访问的方法:使用方式:结构体指针->成员名;

这里创建了一个结构体指针接受了我们创建了结构体变量p,我们将p的地址传给结构体指针,通过结构体指针来间接访问结构体的内容;这种访问方法大家也需要理解并且掌握。

4. 结构体的内存对齐

前面我们了解了结构体的基本内容,下面我们要讨论一个问题:计算结构体的大小;这就是我们接下来要说到的内容——结构体的内存对齐

4.1 对齐规则

首先为大家展示结构体的内存对齐规则,下面用一个例子来为大家解释;

struct S1
{
	char c1;
	int i;
	char c2;
};
int main()
{
	struct S1 s;
	printf("%zd\n", sizeof(s));
}

大家来看这段代码,这里我想要求出代码中的结构体的大小,那么就需要遵循上面说的对齐规则;

 

大家仔细来看上面的图,右边的数字就是偏移量。根据第一条规则,第一个成员对齐到结构体变量起始位置偏移量为0的地址处,如上图所示;

下面轮到第二个成员,这里大家要理解对齐数的概念,在VS里默认对齐数为8,而最终的对齐数是在默认对齐数和成员变量大小中取较小的那一个,比如这里的第二个成员,是int类型。大小为4字节,而VS默认值为8,所以结果就是4,也就是说第二个成员要对齐到4的整数倍的地址处,那么最近的就是从偏移量为4的地方开始存储,向后存4个字节;

第三个成员,和第二个同理,char类型的大小是1字节,VS默认值是8,所以对于第三个成员来说,对齐数就为1,那么第三个成员就需要对齐到1的整数倍的地址处,看一下图,就是偏移量为8的位置,在这里存储第三个成员,占1字节;

综上,可能有的同学就认为这个结构体的大小是9字节了,那么这里大家要注意第三条规则,结构体的总大小为最大对齐数的整数倍,那么在这个结构体中,第一个成员的对齐数为1,第二个成员的对齐数为4,第三个成员的对齐数为1,那么最大对齐数就为4了,所以整个结构体的大小就必须为4的整数倍,那么我们看图,占内存最小的就是12,那么这个结构体的大小就为12字节;

大家可以看到,上面是在VS2022环境下算出的结构体的大小,与我们上面的推理结果一致;希望大家可以通过这个例子理解对齐规则;

为了让大家更好地掌握对齐规则,下面有几道例题,大家一起来看一下;

​//例题1
#include<stdio.h>
struct S2
{
	char c1;
	char c2;
	int i;
};
int main()
{
	struct S2 s;
	printf("%zd\n", sizeof(s));
}

​

大家来看一下这道题,和前面的分析方法一样,首先来对齐第一个成员,第一个成员是char类型,占1字节;

第二个成员,依然是char类型,VS默认值为8,char为1字节,所以其对齐数就是1,那么第二个成员将对齐到偏移量为1的地址处;

第三个成员,为int类型,大小4字节,VS默认值是8,所以其对齐数为4,那么第三个成员就需要对齐到4的整数倍的地址处,那么最近的就是偏移量为4的地址处,从那里往后占4字节;

综上,我们将三个成员都存进去了,下面我们要确定整个结构体的大小,很容易知道,最大对齐数为4,那么整个结构体的大小就必须为4的倍数,我们可以发现,前面我们刚好占用了8个字节,8又刚好是4的整数倍,所以整个结构体的大小就是8字节。

//例题2
#include<stdio.h>
struct S3
{
	double d;
	char c;
	int i;
};
int main()
{
	struct S3 s;
	printf("%zd\n", sizeof(s));
}

这道题还是同样的分析方法;

首先来看第一个成员,double类型,我们知道它占8字节;

第二个成员,char类型,大小为1字节,默认值是8,那么其对齐数就是1,那么第二个成员就要对齐在1的整数倍的地址处,前面已经存过了第一个成员,那么第二个成员就可以放在偏移量为8的地址处;

第三个成员,int类型,大小4字节,默认值为8,其对齐数就为4,那么就应该对齐在偏移量为12的地址处,占4字节;

那么最终大家可以发现,我们一共占用了16个字节,我们知道最大对齐数为8,那么16是8的整数倍,所以这个结构体的大小就为16字节。

//例题3
#include<stdio.h>
struct S3
{
	double d;
	char c;
	int i;
};
struct S4
{
	char c1;
	struct S3 s3;
	double d;
};
int main()
{
	struct S4 s;
	printf("%zd\n", sizeof(s));
}

这道题大家要注意它和前两道是不一样的,它出现了嵌套结构体的情况,那么这个时候大家就要注意上面对齐规则中的第四条规则了;

第一个成员,char类型。大小1字节,直接存到起始位置;

第二个成员,这是一个结构体,那么第四条规则告诉我们:结构体成员对齐到自己的成员中最大对齐数的整数倍处,那么从例题2我们知道,S3结构体中最大对齐数是8,所以S3必须对齐到8的整数倍的地址处,在这里就需要对齐到偏移量为8的地址处,占16字节;

第三个成员,double类型,大小8字节,VS默认值为8,所以其对齐数为8,那么成员三就需要对齐到8的整数倍的地址处,大家自己画图会发现,就是偏移量为24的地址处,占8字节;

综上,我们一共占用了32个字节,那么整个结构体的大小是多少呢?再来看一下第四条规则,整个结构体的大小必须为所有最大对齐数的整数倍,那么我们知道,在S4结构体中,最大的对齐数为8,所以整个S4结构体的大小就要为8的整数倍,刚才说一共占用了32字节,32刚好是8的整数倍,那么S4结构体的大小就是32字节。

 

OK,上面我们讨论了几道关于结构体内存对齐的例题,希望大家通过这些例题能够更好地掌握内存对齐的规则;

不知道大家是否注意到,在内存对齐的过程中,其实造成了空间的浪费,那么我们为什么还要遵循内存对齐规则呢?下面我们继续来讨论为什么会有内存对齐?

4.2 为什么存在内存对齐 

4.2.1 平台原因(移植原因)

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

4.2.2 性能原因

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用⼀个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。

总体来说:结构体的内存对齐是拿空间来换取时间的做法

那么,我们有没有一种方式,既满足对齐,又能节省空间呢?
大家来看下面的代码;

struct S1
{
 char c1;
 int i;
 char c2;
};
struct S2
{
 char c1;
 char c2;
 int i;
};

大家观察这段代码,并且取计算一下这两个结构体的大小;

这里大家发现,两个结构体虽然成员一样,但是最终大小却不一样;这里大家就要注意一点,在创建结构体的过程中我们要让占有空间小的成员尽量集中在一起,这样我们就可以在满足对齐的情况下尽量节省空间。

4.3 修改默认对齐数

#pragma 这个预处理指令,可以改变编译器的默认对齐数。

结构体在对齐方式不合适的时候,我们可以自己更改默认对齐数。

5. 结构体传参 

#include<stdio.h>
struct S
{
	int data[1000];
	int num;
};
struct S s = { {1,2,3,4}, 1000 };
//结构体传参 
void print1(struct S s)
{
	printf("%d\n", s.num);

}
//结构体地址传参 
void print2(struct S* ps)
{
	printf("%d\n", ps->num);
}
int main()
{
	print1(s); //传结构体 
	print2(&s); //传地址 
	return 0;
}

大家看看上面的代码,一个是传结构体本身;还有一个是传结构体的地址;那么哪种方式更好呢?答案是print2;

为什么呢?

结论: 结构体传参的时候,要传结构体的地址。 

6.结构体实现位段

6.1 位段的概念

位段的声明和结构是类似的,有两个不同:

1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以选择其他类型。

2. 位段的成员名后边有⼀个冒号和⼀个数字。

struct A
{
 int _a:2;
 int _b:5;
 int _c:10;
 int _d:30;
};

大家可以发现,位段是专门用来节省内存的;

这里还有一个问题,位段A的大小的多少呢? 

大家可以自己去测试一下,相信很多同学的第一反应是6(因为有一共47个bit);

大家发现,这个结果并不是6,那这是什么原因呢?咱们继续看下面的内容;

6.2 位段的内存分配 

1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型

 2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。

 3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段

这里给大家举个例子,咱们来看下面的代码;

#include<stdio.h>
struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	printf("%zd", sizeof(s));
	return 0;
}

 这里大家可以思考一下结果;​​​​​​​

 大家仔细看上面这张图,它描述了位段申请空间的过程;这里大家注意,每一个小格子代表一个bit;

这里一次开辟一个字节(8bit),在VS 中,在一个字节内部空间是从右向左进行使用的;那么剩余的空间是继续使用,还是浪费掉呢?在VS中,答案是浪费掉。最终我们可以发现,一共申请了3个字节的空间。

每个方块儿中存放的是对应数据的二进制,由于空间有限,所以数据并不能完整地存放到空间中,就会发生截断的现象;所以最终我们通过调试就可以看见位段s中的数据;

大家注意这里是十六进制的形式进行表示的;OK,到这里,关于位段内存分配的内容就为大家介绍完了;

6.3 位段的跨平台问题

1. int位段被当成有符号数还是无符号数是不确定的。

2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。

3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

4. 当⼀个结构包含两个位段,第⼆个位段成员⽐较大,无法容纳于第⼀个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

总结: 跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

6.4 位段的应用

这里的内容大家作了解即可,在这里不需要深入研究,后面在学习网络的相关知识的时候,

6.5 位段使用的注意事项

位段的几个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位 置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的。

所以不能对位段的成员使⽤&操作符,这样就不能使用scanf直接给位段的成员输入值,只能是先输入放在⼀个变量中,然后赋值给位段的成员。

int main()
{
 struct A sa = {0};
 scanf("%d", &sa._b);//这是错误的 
 
 //正确的⽰范 
 int b = 0;
 scanf("%d", &b);
 sa._b = b;
 return 0;
}

大家看一下上面的一段代码,我们是不能对位段的成员进行取地址操作的。

7. 总结 

本篇文章为大家介绍了结构体的相关内容,结构体在C语言中也是一种重要的自定义类型,在后面的学习中大家会经常使用,所以本篇内容,建议大家认真阅读,注意其中的细节,掌握结构体的使用方法以及关于结构体的对齐规则;最后,希望本篇博客可以为大家带来帮助,谢谢!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

食家巷助力“甘肃乡村振兴,百强主播·打call 甘味”活动

2024年&#xff0c;甘肃省“商务乡村振兴”促消费暨“百强主播打call 甘味”活动在天水市龙城广场盛大启动。 活动现场&#xff0c;来自甘肃省 14 个市州的农特产品展台琳琅满目&#xff0c;让人目不暇接。此次活动中&#xff0c;各企业带来了多款深受消费者喜爱的产品&a…

【C++提高编程-06】----C++之STL-函数对象、谓词、仿函数

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

这 10 种架构师,不合格!

大家好&#xff0c;我是君哥。 架构师这个岗位是好多程序员努力的方向&#xff0c;尤其是刚毕业的时候&#xff0c;对架构师有一种崇拜感。毕竟从初级到架构要经历好几次级别飞跃。 工作时间久了&#xff0c;发现架构师这个岗位&#xff0c;其实定义非常广泛&#xff0c;根据工…

linux 部署瑞数6实战(维普,药监局)sign第二部分

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx …

如何通过在线封装APP快速上线?小猪APP分发帮你解决难题

你是否曾经为了上线一款APP而头疼不已&#xff1f;开发完成后&#xff0c;封装、测试、分发&#xff0c;这些繁琐的步骤让人望而却步。别担心&#xff0c;小猪APP分发来了&#xff01;这篇文章将带你了解如何通过在线封装APP快速上线&#xff0c;并且告诉你为什么选择小猪APP分…

[Linux] TCP协议介绍(3): TCP协议的“四次挥手“过程、状态分析...

TCP协议是面向连接的 上一篇文章简单分析了TCP通信非常重要的建立连接的"三次握手"的过程 本篇文章来分析TCP通信中同样非常重要的断开连接的"四次挥手"的过程 TCP的"四次挥手" TCP协议建立连接 需要"三次握手". "三次挥手&q…

Postman下发流表至Opendaylight

目录 任务目的 任务内容 实验原理 实验环境 实验过程 1、打开ODL控制器 2、网页端打开ODL控制页面 3、创建拓扑 4、Postman中查看交换机的信息 5、L2层流表下发 6、L3层流表下发 7、L4层流表下发 任务目的 1、掌握OpenFlow流表相关知识&#xff0c;理解SDN网络中L…

飞书API 2-1:如何通过 API 创建文件夹?

本文探讨如何通过飞书的 API 来创建文件夹。通过 API 创建的文件夹&#xff0c;一般是放在共享空间&#xff0c;如果要放在个人空间&#xff0c;建议手动创建。 查看 API 文档 API 路径&#xff0c;可在飞书开放平台的服务端 API&#xff0c;依次查找云文档>云空间>文件…

javaWeb项目-springboot+vue人事管理系统功能介绍

本项目源码&#xff1a;java-springbootvue人事管理系统源码说明文档资料资源-CSDN文库 项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot…

高级人工智能复习 题目整理 中科大

题目整理 填空 1.准确性&#xff0c;复杂性&#xff0c;验证集 2. 3 2 n 3^{2^n} 32n 3 C 2 n m 3^{C^m_{2n}} 3C2nm​ 3 m 3^m 3m n 1 n1 n1 3. 状态 从状态s采取行动a后继续采用策略 π \pi π的收益 环境 4. 语法 语义 推理规则 5. 参与者&#xff0c;策略集&#xff…

算法排序之冒泡排序及优化

public class Bubbling {public static void main(String[] args) {// 定义需要排序的数组int[] arr {0,1,21,2,31,12,5,8};// 冒泡排序方法bubbleSort(arr);bubbleOptSort(arr);}/*** 冒泡排序* param arr 数组*/public static void bubbleSort(int[] arr){// i0&#xff0c;…

【C语言】解决C语言报错:Format String Vulnerability

文章目录 简介什么是Format String VulnerabilityFormat String Vulnerability的常见原因如何检测和调试Format String Vulnerability解决Format String Vulnerability的最佳实践详细实例解析示例1&#xff1a;直接使用不受信任的输入作为格式化字符串示例2&#xff1a;未验证格…

英伟达开源最强通用模型Nemotron-4 340B:开启AI合成数据新纪元

【震撼发布】 英伟达最新力作——Nemotron-4 340B,一个拥有3400亿参数的超级通用模型,震撼登场!这不仅是技术的一大飞跃,更是AI领域的一次革命性突破! 【性能卓越】 Nemotron-4 340B以其卓越的性能超越了Llama-3,专为合成数据而生。它将为医疗健康、金融、制造、零售等行…

基于WPF技术的换热站智能监控系统09--封装水泵对象

1、添加用户控件 2、编写水泵UI 控件中用到了Viewbox控件&#xff0c;Viewbox控件是WPF中一个简单的缩放工具&#xff0c;它可以帮助你放大或缩小单个元素&#xff0c;同时保持其宽高比。通过样式和属性设置&#xff0c;你可以创建出既美观又功能丰富的用户界面。在实际开发中…

RabbitMQ揭秘:轻量级消息队列的优缺点全解析

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 亲爱的读者朋友们,大家好!我是小米,一个热爱技术、喜欢分享的大哥哥。今天我们来聊聊一个在消息队列领域非常重要的工具——RabbitMQ。作为一个在通信…

EasyExcel文件导出,出现有文件但没有数据的问题

一开始由于JDK版本过高&#xff0c;我用的17&#xff0c;一直excel没有数据&#xff0c;表头也没有&#xff0c;后来摸索了好久&#xff0c;找了资料也没有&#xff0c;后来改了代码后报了一个错误&#xff08;com.alibaba.excel.exception.ExcelGenerateException: java.lang.…

如何让视频有高级感 高级感视频制作方法 高级感视频怎么剪 会声会影视频剪辑制作教程 会声会影中文免费下载

高质量视频通常具有清晰的画面、优质的音频和令人印象深刻的视觉效果。这篇文章来了解如何让视频有高级感&#xff0c;高级感视频制作方法。 一、如何让视频有高级感 要让视频有高级感&#xff0c;要注意以下几个要点&#xff1a; 1、剧本和故事性&#xff1a;一个好的剧本和…

Vue主要使用-03

组件通讯 组件通讯也是我们需要了解的,在我们的实际开发中,我们使用的非常多,比如父组件内的数据传入到子组件,子组件的数据传入到父组件,什么是父组件什么是子组件&#xff1f;父组件内包含着我们的子组件,我们的父组件可以有多个子组件,父组件就是我们使用子组件拼接的。 …

001 Spring介绍

文章目录 特点1.方便解耦&#xff0c;简化开发2.AOP编程的支持3.声明式事务的支持4.方便程序的测试5.方便集成各种优秀框架6.降低Java EE API的使用难度7.Java源码是经典学习范例 好处什么是耦合和内聚耦合性&#xff0c;也叫耦合度&#xff0c;是对模块间关联程度的度量内聚标…

如何学习VBA_3.3.3:VBA对于工作簿、工作表的一般操作

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的劳动效率&#xff0c;而且可以提高数据处理的准确度。我推出的VBA系列教程共九套和一部VBA汉英手册&#xff0c;现在已经全部完成&#xff0c;希望大家利用、学习。 如果…