首页 > 你问我答 >

问 C 语言 struct 函数 结构体与自定义数据类型

2026-11-05 08:41:49
最佳答案

答

首先要纠正一个基础认知,struct 本身不是函数,它是 C 语言的自定义复合数据类型关键字,作用是把多个不同类型的数据打包组合成一个新的数据类型,很多初学者习惯叫成 struct 函数,实际是结构体类型,后续可以配合普通函数来操作这个结构体里面的数据。之所以需要 struct,是因为基础类型 int char float 只能单独保存一种数据,现实业务经常需要把相关联的数据放在一起,比如学生信息包含姓名学号成绩,这些数据属于同一个对象,分散定义多个独立变量不方便管理,使用 struct 就可以把它们封装成一套整体类型。使用的时候第一步使用 struct 关键字声明结构体模板,定义里面包含的各个成员变量,第二步可以用这个模板创建结构体变量,第三步给结构体各个成员赋值,第四步编写普通函数,传入结构体变量或者结构体指针,在函数内部读写成员,实现对结构体的业务处理,第五步也可以给结构体搭配 typedef 起别名,简化后续书写。整体理解思路就是 struct 是类型定义工具,函数是处理这个类型数据的代码块,二者是搭配使用的关系,并不是 struct 自带函数,C 语言的结构体不像 C++ 类那样内置成员函数,这点是 C 和 C++ 非常重要的区别。

基础语法

声明结构体模板写法

struct 标签名

{

成员 1 类型 成员 1 名字;

成员 2 类型 成员 2 名字;

成员 3 类型 成员 3 名字;

};

创建变量有三种方式

第一种 声明模板之后单独创建变量

struct Student s1;

第二种 声明模板的时候直接创建变量

struct Student

{

int id;

char name [20];

float score;

} s1;

第三种 使用 typedef 给结构体起别名,后续不用每次写 struct 关键字

typedef struct Student

{

int id;

char name [20];

float score;

} Student;

成员访问方式

普通结构体变量 使用点运算符访问成员

s1.id = 1001;

结构体指针 使用箭头运算符访问成员

Student p = &s1;

p->score = 90.5;

结构体搭配函数示例代码

include

typedef struct Student

{

int id;

char name[20];

float score;

} Student;

void printStudent (Student stu)

{

printf ("学号 % d 姓名 % s 成绩 %.2f\n", stu.id, stu.name, stu.score);

}

void updateScore(Student pstu, float newScore)

{

pstu->score = newScore;

}

int main ()

{

Student s = {1001, "tom", 85};

printStudent (s);

updateScore (&s, 92);

printStudent (s);

return 0;

}

上面代码里面 printStudent 是传值调用,把结构体整体拷贝一份传入函数,函数内部修改副本不会影响外面原始结构体,updateScore 是传指针调用,直接操作原始内存,可以修改外部结构体数据,这是结构体函数设计最核心的知识点。

深度重点知识

第一 内存对齐,struct 里面成员会按照编译器规则做内存对齐,结构体实际占用字节数不一定是所有成员字节相加,会存在填充字节,这个会影响数组嵌入式开发内存占用计算,可以使用 sizeof 计算结构体总大小。

第二 结构体赋值,同类型结构体变量可以直接整体赋值 s2 = s1,本质是按内存逐字节拷贝,但是如果成员里面包含指针,只会拷贝指针地址,不会拷贝指针指向的内容,也就是浅拷贝,容易产生悬空指针问题。

第三 结构体数组,可以定义 Student stuArr [10],批量保存多个同类型结构体对象,配合循环和函数批量处理,这是管理一组对象最常用方案。

第四 嵌套结构体,结构体成员还可以是另外一个 struct 类型,实现层级数据结构,比如学生结构体里面嵌套出生日期结构体。

第五 函数返回结构体,C 语言函数可以直接返回整个结构体变量,但是返回大体积结构体的时候会发生拷贝,性能较差,一般优先使用传入指针的方式。

传值调用和传指针调用对比表

对比项目传结构体值传结构体指针
内存行为完整拷贝一份结构体副本只传递地址,不拷贝全部数据
是否能修改原数据不能修改外部原始结构体可以修改外部原始结构体
性能结构体很大的时候拷贝开销高开销很小
访问成员符号点运算符箭头运算符

【常见问题】

问题 1 C 语言 struct 函数是不是和 C++ 类一样自带成员函数

回答 1 C 语言 struct 函数并不是内置成员函数,struct 只是自定义复合数据类型,C 语言结构体不能像 C++ 类那样在 struct 内部写函数,只能额外编写普通函数,通过传值或者传指针的方式操作 struct 数据。

问题 2 C 语言 struct 函数传值调用为什么修改不了外部数据

回答 1 C 语言 struct 函数传值调用的时候,会把结构体完整拷贝一份副本传入函数,函数内部操作的是副本内存,外部原始 struct 变量不会发生改变,如果想要修改外部数据,struct 函数就要改成传入结构体指针。

问题 3 C 语言 struct 函数里面箭头运算符和点运算符怎么选择

回答 1 C 语言 struct 函数中,如果参数是普通 struct 变量,使用点运算符访问成员,如果参数是 struct 指针,就要使用箭头运算符访问成员,这是 struct 函数编写必须记住的语法规则。

问题 4 C 语言 struct 函数使用 typedef 有什么好处

回答 1 C 语言 struct 函数搭配 typedef 可以给 struct 自定义别名,后续创建 struct 变量的时候不用重复书写 struct 关键字,简化 struct 函数相关代码书写,提升代码可读性。

【免责申明】

本文内容基于标准 C 语言语法编写,不同编译器对内存对齐的默认规则存在差异,代码示例仅用于学习演示,嵌入式平台部分编译器会提供修改对齐方式的扩展选项,实际项目开发请结合编译环境测试,因浅拷贝内存对齐理解错误造成程序异常,使用者自行承担相关风险。