一,结构体的定义
聚合数据类型:能够同时存储超过一个的单独数据(例如C语言中的数组和结构体)
结构体是一些值的集合,这些值成为它的成员,既是一种自定义类型,也是一种聚合数据类型。
二,结构体的声明及具体使用
1,声明
在声明结构体时,必须列出它包含的所有成员。
struct A
{
int a;
char c;
};
A仅仅为一个标签,单独的A并不是结构体的类型,struct A才是。a,c为它的成员列表,一定注意后面的分号千万不能丢,没有就出错了。
struct A
{
int a;
char c;
}sa1,sa2;
又如这种形式,sa1和sa2是结构体的变量列表,如果没有标签的话,记得一定要有,否则还是错的。
那么,想要在外部定义一个结构体类型的变量又该怎么做呢?
struct A s;
好像依旧很麻烦,因为struct还是不能省略,于是,我们又想到了另一个办
typedef struct S
{
int a;
char name[10];
char c;
}S;
这样,我们就可以省略struct了,巧妙地运用类型重命名typedef解决了此问题,有木有很棒呢。
S s;
S *ps;
声明完成之后,该怎样对它进行赋值呢?
2.初始化
s.a=10;s.name="zhangsan";s.c='w';
是这样吗,看似好像没什么问题,然而是no,给你说什么来着,数组名代表数组首元素的地址,看看你又忘了,没好好复习吧,该罚,嘻嘻。当然,你怎么能将一个常量字符串赋给一个地址呢,这样做当然是不对滴。那到底怎样才算对呢,听我细细给你道来.
strcpy(s.name,"zhangsan");
又比如
ps=&s;
这样一来,我们就可以通过两种方式来访问其内部成员
strcpy(ps-->name,"zhangsan");
strcpy((*ps).name,"zhangsan");
当然,两种方式的效果是一样一样的!
整体初始化:
S s={10,"zhangsan",'w'};
3.嵌套
typedef struct S
{
int a;
char c;
}S;
typedef struct Stu
{
char name[10];
int age;
S s;
char tele[20];
}Stu;
可通过S.s.a访问S中的成员a,由此可见,结构体内部的多层嵌套可通过‘.’来访问。
初始化则为:
Stu s={"liming",16,{15,'q'},"7417147474741"};
4.结构体的自引用
typedef struct Node
{
int data;
struct Node *next;
}Node;
注意成员列表中的struct不能省略
5.不完整的声明
struct B;
struct A
{
struct B *pb;
};
struct B
{
struct A* pa;
};
因为B中用到了A,A中又用到了B,所以当中必须有一个委曲求全一下,例如B,做了一个不完整的声明
三,结构体的存储分配----->内存对齐
typedef struct A
{
char c;
int i;
}A;
你觉得会输出几呢?如果你想的是5,那就错了,因为你没考虑到他的内存对齐,正确结果是8.再看一下下面一段代码:
typedef struct A
{
char c;
char d;
int i;
}A;
你可能说,上次忘了考虑内存对齐,这次不会了,于是你信誓旦旦的说答案是12,结果是你又错了,答案仍然是8,让我来给你讲讲为什么吧!
首先,我们从两个角度考虑进行分析。
(1)为什么要内存对齐?
(2)内存对齐后,如何求取结构体大小?
在这里,我们需要提到几个新概念
默认对齐数:每个环境下均不相同chengyuan
VC------>8 VS------->8 LINUX-------->4
对齐数:成员自身大小和默认对齐数的较小值
偏移数:成员变量在内存中偏移的字节数
规定每个成员必须放到其对齐数的倍数位置处
结构体的大小必须是最大对齐数的倍数
此结构体的大小为8
此结构体的大小仍为8
下面介绍一下结构体中嵌套结构体的内存对齐
此结构体的大小为32。
此结构体大小为40,因为结构体的大小必须为整体最大对齐数的倍数