目录
- 一、结构体的声明
- 二、结构体的定义和初始化
- 三、结构体成员访问
- 四、结构体传参
- 五、函数调用的参数压栈(了解)
在C语言中,我们知道数组是一组相同类型元素的集合,而结构体则更为灵活,它允许我们将不同类型的数据组合在一起,形成一个新的复合数据类型。本文将带你全面了解结构体的基础知识,从声明定义到成员访问,再到最后的结构体传参。
一、结构体的声明
结构体的声明使用struct
关键字,其基本语法如下:
struct 结构体标签 {类型 成员1;类型 成员2;// 更多成员...
};
与数组不同,结构体的成员可以是不同类型的变量。例如,我们可以创建一个学生结构体:
struct Stu {char name[20]; // 姓名int age; // 年龄float score; // 成绩
};
声明结构体后,我们可以创建该类型的变量:
struct Stu s; // 创建一个Stu类型的结构体变量s
当然我们也可以在声明结构体的同时创建变量(此时创建的是全局变量(因为在{}外定义)):
struct Stu {char name[20];int age;float score;
} s1, s2; // 全局变量s1和s2
而上面的在main函数内部创建的则是局部变量。
二、结构体的定义和初始化
结构体的初始化与数组类似,使用花括号{}
进行初始化:
struct Stu s = {"张三", 18, 90.5};
当结构体嵌套时(即成员中包含另一个结构体),可以使用嵌套的花括号来对结构体进行初始化:
struct Date {int year;int month;int day;
};struct Student {char name[20];struct Date birthday; // 嵌套结构体
};struct Student stu = {"李四", {2000, 5, 20}};
三、结构体成员访问
访问结构体成员有两种方式:
- 使用
.
操作符直接访问:
struct Stu s;
strcpy(s.name, "王五");
s.age = 19;
s.score = 88.5;
- 当有结构体指针时,使用
->
操作符:
struct Stu s;
struct Stu *ps = &s;
ps->age = 20; // 等价于 (*ps).age = 20;
如在这里ps->age,表示的意思是ps先找到指向的结构体变量s,再找其成员变量age
四、结构体传参
结构体作为函数参数传递时有两种方式:
- 传值调用:传递整个结构体对象的副本
void printStudent(struct Stu s) {printf("姓名: %s, 年龄: %d, 成绩: %.1f\n", s.name, s.age, s.score);
}// 调用
printStudent(s);
- 传址调用:传递结构体的指针
void printStudent(struct Stu *ps) {printf("姓名: %s, 年龄: %d, 成绩: %.1f\n", ps->name, ps->age, ps->score);
}// 调用
printStudent(&s);
这两种方式我们推荐使用传址调用,原因如下:
- 效率更高:传值调用需要临时拷贝整个结构体,会消耗更多内存和时间。而传址调用只需传递一个指针(32位系统4字节,64位系统8字节),大大提高了传参效率。
- 功能更强大:通过指针可以直接修改原结构体的值,而传值调用只能操作副本。
五、函数调用的参数压栈(了解)
在函数调用过程中,参数会被"压栈"(push onto the stack)。栈是一种先进后出(LIFO)的数据结构:
- 每次函数调用都会在内存的栈区开辟一段空间
- 参数通常从右向左依次压栈
- 例如
Add(a, b)
调用时,先压入b
,再压入a
了解函数栈帧的创建和销毁有助于深入理解函数调用机制,这相当于我们编程能力的"内功"。
结构体是C语言中非常重要的自定义数据类型,它允许我们将不同类型的数据组合成一个整体。通过本文,我们介绍了:
- 如何声明和定义结构体
- 结构体的初始化和成员访问方法
- 结构体传参的两种方式(优先使用传址调用)
- 函数调用时的参数压栈机制(了解)
掌握结构体的基础知识是学习更高级数据结构的前提,也是编写复杂程序的必备技能。在实际开发中,结构体经常与指针配合使用,能够极大地提高程序的灵活性和效率。在下一章,我们将介绍一些实用的调试技巧,敬请期待!
作者其他文章链接:
初识C语言—人生若只如初见(完结撒花!)
[C语言初阶]指针初阶
[C语言初阶]操作符
[C语言初阶]扫雷小游戏
Gitee详细使用教程