首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C语言】结构体详解:声明、使用与优化技巧

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

作者头像
苏兮
发布2026-01-13 17:06:24
发布2026-01-13 17:06:24
2950
举报

前言:

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

一、结构体类型的声明

1.1 结构的基础知识

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

1.2 结构的声明

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

代码语言:javascript
复制
struct student
{
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	int id[20];//学号
};

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

代码语言:javascript
复制
typedef struct student
{
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	int id[20];//学号
}Stu;

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

1.3 特殊的声明

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

代码语言:javascript
复制
struct
{
	int a;
	char b;
	float c;
}x;
struct
{
	int a;
	char b;
	float c;
}a[20], * p;

那么问题来了,咱们这样写的话 p = &x 可以吗? 答案是不行,解释:

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

1.4 结构的自引用

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

代码语言:javascript
复制
struct Node
{
	int data;
	struct Node next;
};

这种写法是否可行? 如果可以,那sizeof(struct Node)是多少?很显然,它会无限递归。 禁止直接嵌套:结构体不能包含自身类型的完整对象(会导致无限递归)。 那么咱们应该怎么来嵌套呢,指针,指针在固定的机器下是固定的。所以咱们可以这样来自引用:

代码语言:javascript
复制
struct Node
{
	int data;
	struct Node* next;//利用指针来实现自引用
}

咱们再来看个代码:

代码语言:javascript
复制
//是否可行?
typedef struct
{
	int data;
	Node* next;
}Node;

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

类型定义的顺序问题, 在typedef完成之前(typedef在遇到分号;时才算真正完成),Node这个名字还不存在。 但在结构体内部,已经尝试使用Node*,此时编译器会报错。

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

代码语言:javascript
复制
typedef struct Node 
{ 
    int data;
    struct Node* next;  // 使用"struct Node"引用自身
} Node;                // typedef别名

1.5 结构成员的类型

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

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

有了结构体类型,那如何定义变量,其实很简单。咱们以前的int、char、……怎么定义,结构体变量就怎么定义。 咱们还要辨析一个概念,结构体类型与咱们已知的int、char、float……都是相似的,只不过结构体类型是咱们自己根据需求来自己定义的类型而已。即结构体是用户根据需求自定义的复合类型。 那咱们来看看结构体变量的定义和初始化:

代码语言:javascript
复制
//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} };//结构体嵌套初始化

二、结构体成员的访问

咱们现在已知结构的声明、结构体的定义……那么怎么修改、访问结构体成员呢? 这里主要涉及到两个操作符. ->,咱们来看看怎么用呢? 结构体变量访问成员 结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数。 看代码:

代码语言:javascript
复制
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;
}

看下调试结果:

在这里插入图片描述
在这里插入图片描述

结构体指针访问指向变量的成员 有时候我们得到的不是一个结构体变量,而是指向一个结构体的指针。 那该如何访问成员。 看代码:

代码语言:javascript
复制
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;
}

输出:

在这里插入图片描述
在这里插入图片描述

三、结构体传参

直接看代码:

代码语言:javascript
复制
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;
}

上面的print1print2函数哪个好些? 答案是:首选print2函数。 原因:

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的 下降。

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

总结

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-08-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 一、结构体类型的声明
    • 1.1 结构的基础知识
    • 1.2 结构的声明
    • 1.3 特殊的声明
    • 1.4 结构的自引用
    • 1.5 结构成员的类型
    • 1.6 结构体变量的定义和初始化
  • 二、结构体成员的访问
  • 三、结构体传参
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档