大家好,我是苏貝,本篇博客带大家了解C语言的结构体(初阶),以后会出进阶的,如果大家觉得我写的不错的话,可以给我一个赞👍吗,感谢❤️
① WHO IS 结构体
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量(这与数组不同,数组是一组相同类型元素的集合)
② 结构体的作用
1.首先,我们之前所学的int,char,double等类型都是内置类型,单个的它们无法描述一个复杂对象,比如描述一个人,那就可能要描述他的名字、性别、年龄等,这些显然是不能通过某个内置类型来很好的描述的,所以结构体应运而生
2.在实际项目中,结构体是大量存在的。研发人员常使用结构体来封装一些属性来组成新的类型。由于C语言内部程序比较简单,研发人员通常使用结构体创造新的“属性”,其目的是简化运算。
3.结构体在函数中的作用不是简便,最主要的作用就是封装。封装的好处就是可以再次利用。让使用者不必关心这个是什么,只要根据定义使用就可以了。
③ 结构体细节
1. 结构体的声明
首先,要使用结构体就必须先声明一个结构体类型。其中,struct是关键字,不能省略(若一定要省略也行,用typedef,下面会讲到);struct后接结构体名;struct+结构体名表示一个结构体类型,这与内置类型(如:int,double,long等)一样可以用来定义变量; member-list是成员变量的列表,包含不同的基本类型;variable-list是变量列表,可写可不写,写了该变量就是全局变量。
struct 结构体名
{
member-list;//成员变量的列表
}variable-list;//变量列表
例如描述一个学生:
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
};//分号不能丢
注意:
1.结构体类型{ }后面的 ;(分号)不能省略
2.struct后面也可没有结构体名,如下
struct
{
int a;
char b;
}s1;
这种形式是被C语言允许的,但是我们一般不去使用,因为这种结构体类型的声明只能定义一次变量,以后不能再定义,这就不方便该结构体以后的使用,因此不推荐写这种形式的结构体类型
上面有讲到,struct是关键字,不能省略,但如果用typedef就可以省略,这是怎么回事呢,让我们往下看
typedef即类型重定义,意思是给数据类型起一个新的名字。
所以下面的stu并非定义的变量,而是struct Stu的重命名,所以以后既可用struct Stu定义变量,也可用stu定义变量
typedef struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}stu;
2. 结构成员的类型
结构的成员可以是标量、数组、指针,甚至是其他结构体。
struct B
{
char ch[5];
int age;
};
struct A
{
char c;
int arr[10];
double* pd;
struct B b;
struct B* pb;
};
3. 结构体变量的定义和初始化
(1) 定义:可以在以下地方定义结构体变量(应该尽量少的使用全局变量)
1.结构体类型{ }的后面,;(分号)的前面(全局变量)
2.结构体类型的后面,main函数上面(全局变量)
3.main函数里面(局部变量)
struct B
{
char ch[5];
int age;
};
struct A
{
char c;
int arr[10];
double* pd;
}a, b;//a,b是全局变量
struct A d;//d是全局变量
int main()
{
struct A f;//f是局部变量
return 0;
}
(2)初始化
1.按照顺序初始化
2.指定成员来初始化
3.单个初始化
struct A
{
char m;
int arr[10];
double* pd;
}s1 = { .m = 'c',.arr = {1,2,3} }; //指定成员来初始化;
int main()
{
double d = 3.14;
//1.按照顺序初始化
struct A s3 = { 'q',{ 1,2,3,4,5 } ,&d };
//2.指定成员来初始化
struct A s4 = { .m = 'r',.pd = &d };
//3.单个初始化
struct A s5;
s5.m = 'w';
return 0;
}
4. 结构体成员的访问
1.结构体变量访问成员
结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数
例如:
struct stu
{
char name[20];
int age;
};
int main()
{
struct stu s1 = { "zhangsan",18 };//s1初始化
printf("%s %d\n", s1.name, s1.age);//s1的成员访问
return 0;
}
2.结构体指针访问指向变量的成员
有时候我们得到的不是一个结构体变量,而是指向一个结构体的指针。那该如何访问成员?
答案:使用 ->
struct Stu
{
char name[20];
int age;
};
void print(struct Stu* ps)
{
//以下两种方式都可以
printf("name = %s age = %d\n", (*ps).name, (*ps).age);//*ps=s
//使用结构体指针访问指向对象的成员
printf("name = %s age = %d\n", ps->name, ps->age);
}
int main()
{
struct Stu s = { "zhangsan", 18 };
//写一个函数打印s中的数据
print(&s);//结构体地址传参
return 0;
}
5. 结构体作为函数参数
直接上代码:
struct Stu
{
char name[20];
int age;
};
void set(struct Stu* bs)
{
bs->age = 18;
//bs->name = "zhangsan";//err
//因为name是数组名,在此情况下,数组名是首元素地址,为常量
//因此如果想将name改变,可以:
strcpy(bs->name, "zhangsan");
}
void print1(struct Stu ps)
{
printf("%s %d\n", ps.name, ps.age);
}
void print2(struct Stu* ps)
{
printf("%s %d\n", ps->name, ps->age);
}
int main()
{
struct Stu s = { 0 };
//写一个函数打印s中的数据
set(&s);
//写一个函数打印s中的数据
print1(s);
print2(&s);
return 0;
}
由上述代码可知:函数传参既可传值,也可传址。在结构体作为函数参数时,参数可以是结构体变量,也可以是结构体变量的地址。那两者谁更好呢?
答案是传结构体变量的地址。因为函数传参的时候,参数是需要压栈的。如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降 。简单来讲就是因为形参是实参的一份临时拷贝,若实参(即结构体)过大,那么形参也会较大,这样就会导致效率降低。但传结构体变量的地址的话,形参的大小只是4个或8个字节,效率较传结构体更高
结论:
结构体传参的时候,要传结构体的地址。
好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️