自定义类型:结构体-1

简介: 自定义类型:结构体

前言:

类型

1、内置类型

char

short

int

long

long long

double

2、自定义类型

当内置类型不能够满足需求的时候,支持自定义一些类型

1>结构体

2>枚举

3>联合体


一. 结构体类型的声明

1.1 结构体的概念

结构体是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

1.2 结构体的声明

举例描述⼀个学⽣:

struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}s3,s4;//全局变量
int  main()
{
struct Stu s1 ,s2;//局部变量
return 0;
}

1.3  特殊的声明

在声明结构的时候,可以不完全的声明。

⽐如:

//匿名结构体类型
struct
{
 int a;
 char b;
 float c;
}x;
struct
{
 int a;
 char b;
 float c;
} *p;

上⾯的两个结构在声明的时候省略掉了结构体标签(tag)。

那么问题来了?

//在上⾯代码的基础上,下⾯的代码合法吗?
p = &x;

解析:不合法,会出现警告: 编译器会把上⾯的两个声明当成完全不同的两个类型,所以是⾮法的。


注:匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。

1.4 结构体的初始化

struct Stu
{
char name[20];//名字
int age;//年龄
float score;//成绩
}s3,s4;//全局变量
int  main()
{
struct Stu s1 ={"zhangsan",20,98.5f};
struct Stu s2={.age=22,.name="lisi",.score=93.0f};
return 0;
}

1.5  结构的自引用

5f54d3e3c52ad5e3925126c9bae5d122_ee4d7f4db30a458cbed929277acf9cf3.png


以上链表中存储1的结构叫一个节点。

在结构中包含⼀个类型为该结构本⾝的成员是否可以呢?

⽐如,定义⼀个链表的节点:

struct Node
{
 int data;
 struct Node next;
};

上述代码正确吗?如果正确,那 sizeof(struct Node) 是多少?

仔细分析,其实是不⾏的,因为⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的⼤⼩就会⽆穷的⼤,是不合理的。

正确的⾃引⽤⽅式:

struct Node
{
int data;
struct Node* next;//下一个节点的地址
};

sizeof(stcurt Node)大小就可以计算了


在结构体⾃引⽤使⽤的过程中,夹杂了typedef对匿名结构体类型重命名,也容易引⼊问题,看看下⾯的代码,可⾏吗?

typedef struct
{
int data;
Node* next;
}Node;

答案是不⾏的,因为Node是对前⾯的匿名结构体类型的重命名产⽣的,但是在匿名结构体内部提前使⽤Node类型来创建成员变量,这是不⾏的。

解决⽅案如下:定义结构体不要使⽤匿名结构体了

typedef struct Node
{
int data;
struct Node* next;
}Node;


二. 结构体内存对⻬

我们已经掌握了结构体的基本使⽤了。

现在我们深⼊讨论⼀个问题:计算结构体的⼤⼩。

这也是⼀个特别热⻔的考点: 结构体内存对⻬

下面我们看这样一个例子

struct S1
{
  char c1;
  int i;
  char c2;
};
struct S2
{
  char c1;
  char c2;
  int i;
};
int main()
{
  struct S1 s1 = { 'a',100, 'b'};
  struct S2 s2 = { 'a','b','100' };
  printf("%zd\n", sizeof(s1));
  printf("%zd\n", sizeof(s2));
  return 0;
}

这俩个结构变量类型和数据一样,只是顺序不一样,那么大小会一样码?


输出:


a1c83a2bd97212ab6d27dca2f8f6675d_af060c9a3fce4847a9597c8632f645c1.png


我们发现大小不同,它们是如何分配空间的呢?

这就涉及到内存对齐!

2.1  对齐规则

首先先得掌握结构体的对齐规则:

1. 结构体的第⼀个成员对⻬到相对结构体变量起始位置偏移量为0的地址处

2. 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。

对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值。

- VS中默认的值为8

- Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

3. 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的

整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构

体的整体大小就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

由对齐规则对上面程序分析有:

f008466f51c1391df8d100183964c790_06692ccd781148159302ef96c8900225.png


02b8f4c211ed150e3d87922aa786b67a_2968cb7630a14babac63d0c415967e52.png


2.11 练习1

struct S3
{
double d;
char c;
int i;
};
int main()
{
printf("%d\n", sizeof(struct S3));
return 0;
}

解析:根据分析可知,double的对齐数 8,char对齐数 1,int 对齐数 4,首先double放8个字节,紧接连续放char,此时地址到8了,下一个地址位9,9不是4的倍数,所以放在地址12,放四个字节。共16个字节,16是结构体最大对齐数8的倍数,所以答案是16


输出:  0c1b8ea3930e8602ef5b5b7ddedc4e6d_490b0e557c10471c9f8a9fd2be9cedd9.png


相关文章
|
6月前
|
C语言 C++
自定义类型结构体(上)
自定义类型结构体(上)
41 0
|
6月前
|
编译器 Linux C++
自定义类型结构体(中)
自定义类型结构体(中)
22 0
|
6月前
|
存储 网络协议 编译器
自定义类型结构体(下)
自定义类型结构体(下)
37 0
|
4月前
|
存储 编译器 Linux
结构体,自定义类型
结构体,自定义类型
29 0
|
9月前
|
存储 编译器
自定义类型——结构体(二)
自定义类型——结构体
|
5月前
|
存储 开发框架 .NET
自定义类型:联合体和枚举类型(联合体与结构体的区别)
自定义类型:联合体和枚举类型(联合体与结构体的区别)
|
5月前
|
网络协议 编译器 C语言
自定义类型:结构体
自定义类型:结构体
60 0
|
5月前
|
存储 编译器 C语言
自定义类型:结构体-2
自定义类型:结构体
36 0
|
6月前
|
编译器
自定义类型【结构体篇】
自定义类型【结构体篇】
|
6月前
|
编译器
自定义类型联合体(上)
自定义类型联合体
29 0
自定义类型联合体(上)