C语言结构体讲解

目录

文章目录

 定义结构体并初始化

创建普通结构体

创建嵌套的结构体

 结构成员的访问操作符

 结构成员的直接访问

 结构体成员的间接访问

 结构的特殊声明

匿名结构体类型

结构体重命名

 结构体的自引用

结构体的自引用

 结构体自引用不能匿名

 结构体的内存对齐

修改默认对齐数 

 结构体传参

 位段



在讲结构体之前,我们用C和指针的一段话来引入。

 

 定义结构体并初始化

创建普通结构体

struct tag {
	int a;
	char b;
	float c;
};
int main()
{
	struct tag s1 = { 1,'a',1.1 };
	struct tag s2 = { 2,'b',2.2 };
	//此时我不想按照顺序赋值,就得按照下面这种做法
	struct tag s5 = { .b = 'c',.a = 3,.c = 3.3 };
}

创建嵌套的结构体

struct tag
{
	int x;
	int y;
};

struct Data
{
	int sum;
	struct tag p;
};

int main()
{
	struct Data d = { 200,{10,11} };

	return 0;
}

 结构成员的访问操作符

 结构成员的直接访问

#include 
struct tag
{
	int x;
	int y;
};

struct Data
{
	int sum;
	struct tag p;
};

int main()
{
	struct Data d = { 200,{10,11} };
	printf("%d %d %d", d.sum, d.p.x, d.p.y);
	return 0;
}

 C语言结构体讲解_第1张图片

 结构体成员的间接访问

 

结构体指针

对于结构体类型的s1

struct Stu* ps=&s1;//取出s1的地址

printf(%s %d %f\n",ps->name,ps->age,pa->score);

 结构的特殊声明

匿名结构体类型

#include 
struct
{
	int a;
	char b;
	float c;
}x;

int main()
{
	return 0;
}

 

针对于匿名结构体类型来说,他只能使用一次

即使两个匿名结构体成员类型一模一样,在编译器看来,他们是两种不同的类型

结构体重命名

针对于结构体来说,我们可以对其进行重新命名

typedef struct
{
	int a;
	char b;
	float c;
} S;

int main()
{
	S s1 = { 0 };
	return 0;
}

 结构体的自引用

结构体包含一个同类型的结构体的地址我们就称为自引用

结构体的自引用

struct Node
{
	int data;//存放数据
	struct Node* next;//存放同类型的结构体的地址
};

int main()
{
	return 0;
}

 结构体自引用不能匿名

typedef struct 
{
	int data;//存放数据
	struct Node* next;//存放同类型的结构体的地址
}Node;

int main()
{
	return 0;
}

结构体的自引用不能写成匿名

 结构体的内存对齐

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

int main()
{
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));

	return 0;
}

 C语言结构体讲解_第2张图片

 

为什么大小是有差异的呢?

我们先看一下结构体的对齐规则

⾸先得掌握结构体的对⻬规则:

  1. 结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
  2. 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
    对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值。
  • VS 中默认的值为 8
  • Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

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

     4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数整数倍处,结构
体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

然后我们再看一下C和指针的讲解:

 

 C语言结构体讲解_第3张图片

 接下来我们打开画图:(被迫展现优秀的画图

C语言结构体讲解_第4张图片

 

ok,知道了内存对齐,那么内存对齐的作用是什么呢?

1.平台原因 (移植原因)

2.性能原因

修改默认对齐数 

 

#include 
#pragma pack(1)//设置默认对⻬数为1
struct S
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{
	
	printf("%d\n", sizeof(struct S));//6
	return 0;
}

C语言结构体讲解_第5张图片

 结构体传参

 

#include 
struct S
{
	int data[1000];
	int num;
};

void print1(struct S t)
{
	printf("%d %d\n", t.data[0], t.num);
}

void print2(struct S* ps)
{
	printf("%d %d\n", ps->data[0], ps->num);
}

int main()
{
	struct S s = { {1,2,3,4,5},100 };
	print1(s);
	print2(&s);

	return 0;
}

C语言结构体讲解_第6张图片

 对于上述的两个函数,我们认为print2更加好,因为他无论目标有多大,他只会传递一份地址,空间不浪费。

 位段

 

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

1.位段的成员必须是 intunsigned intsigned int ,在C99中位段成员的类型也可以 选择其他类型。
2.位段的成员名后边有⼀个冒号和⼀个数字。

位段的出现就是为了节省空间
位段对计算机底层的实现还是比较重要的。

若有收获,就点个赞吧

你可能感兴趣的:(C语言相关知识分享,c语言,开发语言)