【C语言】结构体详解:声明、使用与优化技巧

C语言学习

结构体基础

友情链接:C语言专栏

文章目录

C语言学习

前言:

一、结构体类型的声明

[1.1 结构的基础知识](#1.1 结构的基础知识)

[1.2 结构的声明](#1.2 结构的声明)

[1.3 特殊的声明](#1.3 特殊的声明)

[1.4 结构的自引用](#1.4 结构的自引用)

[1.5 结构成员的类型](#1.5 结构成员的类型)

[1.6 结构体变量的定义和初始化](#1.6 结构体变量的定义和初始化)

二、结构体成员的访问

三、结构体传参

总结

附录

上文链接

下文链接

专栏

前言:

结构体是C语言中组织复杂数据的利器。本文将用最精炼的方式,带你快速掌握结构体的核心用法:从基础声明到自引用技巧,从成员访问到传参优化。让你彻底玩转结构体编程!

一、结构体类型的声明

1.1 结构的基础知识

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

1.2 结构的声明

**struct解释:**在C语言中,struct 是一个关键字,用于声明和定义结构体类型。

结构体描述学生:

c

复制代码

struct student

{

char name[20];//名字

int age;//年龄

char sex[5];//性别

int id[20];//学号

};

咱们还可以利用关键字typedef,对这个类型重命名,创建更简洁的类型名,代码实现:

c

复制代码

typedef struct student

{

char name[20];//名字

int age;//年龄

char sex[5];//性别

int id[20];//学号

}Stu;

可知:此时struct student与Stu等效,这两种声明方式是等价的,都会创建相同类型的结构体变量。

1.3 特殊的声明

在声明结构的时候,可以不完全的声明,即结构在声明的时候省略掉了结构体标签(tag)。

c

复制代码

struct

{

int a;

char b;

float c;

}x;

struct

{

int a;

char b;

float c;

}a[20], * p;

那么问题来了,咱们这样写的话 p = &x 可以吗?

答案是不行,解释:

编译器会把上面的两个声明当成完全不同的两个类型,所以是非法的。

1.4 结构的自引用

**结构的自引用解释:**在结构中包含一个类型为该结构本身的成员。

看代码:

c

复制代码

struct Node

{

int data;

struct Node next;

};

这种写法是否可行?

如果可以,那sizeof(struct Node)是多少?很显然,它会无限递归。

禁止直接嵌套:结构体不能包含自身类型的完整对象(会导致无限递归)。

那么咱们应该怎么来嵌套呢,指针,指针在固定的机器下是固定的。所以咱们可以这样来自引用:

c

复制代码

struct Node

{

int data;

struct Node* next;//利用指针来实现自引用

}

咱们再来看个代码:

c

复制代码

//是否可行?

typedef struct

{

int data;

Node* next;

}Node;

答案是不行,会报错,解释:

类型定义的顺序问题,

在typedef完成之前(typedef在遇到分号;时才算真正完成),Node这个名字还不存在。

但在结构体内部,已经尝试使用Node*,此时编译器会报错。

所以咱们应该怎么写呢?看正确代码:

c

复制代码

typedef struct Node

{

int data;

struct Node* next; // 使用"struct Node"引用自身

} Node; // typedef别名

1.5 结构成员的类型

结构的成员可以是标量、数组、指针,甚至是其他结构体。

1.6 结构体变量的定义和初始化

有了结构体类型,那如何定义变量,其实很简单。咱们以前的int、char、......怎么定义,结构体变量就怎么定义。

咱们还要辨析一个概念,结构体类型与咱们已知的int、char、float......都是相似的,只不过结构体类型是咱们自己根据需求来自己定义的类型而已。即结构体是用户根据需求自定义的复合类型 。

那咱们来看看结构体变量的定义和初始化:

c

复制代码

//1. 声明类型的同时定义变量p1

struct Point

{

int x;

int y;

}p1;

//2. 单独定义结构体变量p2

struct Point p2;

//初始化:以上两种定义变量同时都可以赋初值(初始化)。

struct Point p3 = { 1, 2 };

//结构体2声明

struct Stu //类型声明

{

char name[15];//名字

int age; //年龄

};

struct Stu s = { "zhangsan", 20 };//初始化

//结构体也可以嵌套定义和初始化

struct Node

{

int data;

struct Point p;//结构体嵌套定义

}n1 = { 10, {4,5} }; //结构体嵌套初始化

struct Node n2 = { 20, {5, 6} };//结构体嵌套初始化

二、结构体成员的访问

咱们现在已知结构的声明、结构体的定义......那么怎么修改、访问结构体成员呢?

这里主要涉及到两个操作符. ->,咱们来看看怎么用呢?

结构体变量访问成员

结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数。

看代码:

c

复制代码

typedef struct Stu

{

char name[20];

int age;

}Stu;

int main()

{

Stu s;//定义结构体变量

strcpy(s.name, "zhangsan");//使用.访问name成员

//注意:这里不能写为s.name = "zhangsan"

s.age =18;//使用.访问age成员

return 0;

}

看下调试结果:

结构体指针访问指向变量的成员

有时候我们得到的不是一个结构体变量,而是指向一个结构体的指针。

那该如何访问成员。

看代码:

c

复制代码

typedef struct Stu

{

char name[20];

int age;

}Stu;

void print(Stu* ps)

{

//结构体变量直接访问成员

printf("name = %s age = %d\n", (*ps).name, (*ps).age);

//使用结构体指针访问指向对象的成员

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

}

int main()

{

Stu s = { "zhangsan", 18 };

print(&s);//结构体地址传参

return 0;

}

输出:

三、结构体传参

直接看代码:

c

复制代码

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;

}

上面的print1和print2函数哪个好些?

答案是:首选print2函数。

原因:

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。

如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的

下降。

总结:

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

总结

希望本文能帮助你建立扎实的结构体知识体系,为后续的C语言开发打下坚实基础。如有任何疑问,欢迎在评论区交流讨论!

附录

上文链接

《浮点数在内存中的存储:从科学计数法到内存存储》

下文链接

《结构体内存对齐:为什么你的结构体比想象中更大?》

专栏

C语言专栏