结构体
本章浅入了解结构体,在后面的自定义类型进阶会重点讲这部分内容。
一、结构体类型的声明
结构体:用于描述属性不止一个的复杂对象
结构体是一些值的集合,这些值成为成员变量,且结构的成员可以是不同类型变量。
我们已经学习过:int
、char
、float
、double
等单一变量类型,但这些只能描述单一属性,所以C语言创造了包含多种单一变量结构体,方便描述复杂对象。比如一本书有书名、作者、价格等属性。
结构体的声明语法:
struct tag//struct - 结构体关键字;tag - 结构体标签;struct tag - 结构体类型名
{
member-list;//成员列表
}variable-list;//变量列表
int类型
本身不占据空间,当用int类型
创建int整型变量
时才会在内存中开辟空间。
同理,struct tag结构体类型
本身不占据空间,当用结构体类型
创建结构体变量
才会在内存中开辟空间
如要声明一个学生类型,它的成员变量包括:名字、年龄、性别、学号。
struct Stu
{
//成员变量
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
};
当觉得上述struct Stu
结构体类型名太长,这时候需要用到类型重定义typedef
typedef struct Stu
{
//成员变量
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}Stu;
这样,
struct Stu
就等效于Stu
结构体成员的类型:
结构的成员可以是标量、数组、指针,甚至是其他结构体(内嵌)。
二、结构体初始化
有了结构体类型,定义结构体变量就简单啦!
struct Stu
{
//成员变量
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}s1;//①声明类型的同时定义变量s1
struct Stu s2;//定义全局变量s2
int main()
{
struct Stu s3;//③定义局部变量s3
struct Stu s4 = {
"张三",17,"男","20200360318" };//④定义结构体变量s4的同时可初始化
return 0;
}
以上是创建结构体变量的方式。当执行类型重定义
typedef struct {...} Stu;
后代码中的struct Stu
可替换成Stu
。
注:在main
函数内创建的结构体变量是局部变量,在栈区开辟空间;在main
函数外,则为全局变量,在静态区开辟空间。
结构体内可嵌套结构体:
struct S
{
int a;
char c;
double d;
};
struct T
{
struct S s;
char name[20];
int num;
};
int main()
{
struct T t = {
{
100, 'w', 3.14}, "张三", 17 };
return 0;
}
结构体变量t内含有用
结构体类型S
创建的s
。在给s
初始化时,得用{}
。
三、结构体成员访问
.
操作符
结构体变量成员可通过.
操作符访问,它有两个操作数,左边为结构体变量名,右边为结构体成员变量名。
借用上面结构体嵌套的例子:
s
是t
的成员变量,a
,b
,c
是s
的成员变量,访问a
,b
,c
则为t.s.a
,t.s.b
,t.s.c
->
操作符
结构体变量成员也可通过->
操作符访问,它有两个操作数,左边为结构体指针变量,右边为结构体成员变量。
struct T t = {
{
100, 'w', 3.14}, "张三", 17 };
struct T* pt = &t;//结构体指针变量pt
//1.对结构体指针解引用找到指针所指向的结构体
printf("%d %c %lf %s %d\n", (*pt).s.a, (*pt).s.c, (*pt).s.d, (*pt).name, (*pt).num);
//2.通过结构体指针直接获得成员变量
printf("%d %c %lf %s %d\n", pt->s.a, pt->s.c, pt->s.d, pt->name, pt->num);
四、结构体传参
#include<stdio.h>
struct S
{
int data[1000];
int num;
};//结构体类型的声明
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
struct S s = {
{
1,2,3,4}, 1000 };
print1(s); //传结构体
print2(&s); //传地址
return 0;
}
上面的 print1
和 print2
函数哪个好些?
答案是:首选print2
函数。
原因:
函数传参的时候,参数是需要压栈的。 如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。
结论:
结构体传参的时候,建议传结构体的地址。