前言:
结构体是很重要的C语言内容,打好结构体的基础是很有必要的!另外,再把程序员必备的硬技能---调试技巧掌握好,可以让我们高效的找出bug的地方。调试就是在寻找使程序出现不符合预期的错误逻辑代码。
一.结构体
结构体是用来描述有多种参数特征的复杂对象,比如描述一本书,有书名、有价格、作者、书号等。但是如果只说书名,是描述不清楚的具体是哪一本书的---(也就是用一个字符数组)。用一个书的价格更不可能描述清楚~。
结构体使用的关键字是struct,和枚举类型(enum)一样,都是使用关键字创建一个新的数据类型;结构体成员可以是不同的数据类型。
#include <stdio.h>
struct Book
{
char author[7];
char BookName[20];
float Price;
int ed;
}b2;//参数列表 在结构体后面可以创建该结构体类型的全局变量
int main()
{
struct Book b1 = {"张三", "我的牢底生活", "55.5", 2};
}
使用struct创建一个名为Book的结构体类型,在C++中,创建b1结构体变量的时候,不需要加struct,在C语言中struct不能省略。在C语言想要这么做的话,可以typedef重命名一下,一般都会这么做,因为每次都要多写一个struct,不仅显的长,还麻烦。
#include <stdio.h>
typedef struct Book
{
//结构体成员 --- 成员列表
char author[7];
char BookName[20];
float Price;
int ed;
}Book;//Book和struct Book等效
//重命名和参数列表是不能一起表示的
int main()
{
struct Book b1 = {"张三", "我的牢底生活", "55.5", 2};
}
1.1结构体的初始化和访问
结构体的初始化和数组一样使用列表{}初始化,注意不能在创建结构体类型的时候给结构体成员初始化,因为它只是一个类型,是一张蓝图,并没有实际的空间。只有在实例化(使用结构体类型创建结构体变量)才有分配空间。
结构体初始化有两种方式:第一种就是按照成员列表依次初始化;第二种就是不根据列表的顺序初始化,但第二种需要加上一些指定性的东西才能实现,请看代码:

在打印的时候,点操作符(.)是访问结构体成员的一种方式,使用结构体变量名.成员变量的方式访问。所以在使用第二种方式初始化可以这样理解,.height其实就是在访问s2里的height成员,因为这是在初始化s2。
补充:不要第一种方式和第二种方式混合使用。
结构体访问的两种方法:
第一种是前面提到的结构体变量.成员
第二种是结构体指针->成员

第一种方法和第二种方法都行,第三种其实就是指针解引用拿到结构体变量,再使用第一种方法,duck不必~
二.结构体传参
传值方式和传址方式:
#include <stdio.h>
struct Stu
{
char number[12];
char name[10];
int age;
char address[50];
};
void Print1(struct Stu s1)
{
printf("%s %s %d %s\n", s1.number, s1.name, s1.age, s1.address);
s1.age = 70;
}
void Print2(struct Stu* ps)
{
printf("%s %s %d %s\n", ps->number, ps->name, ps->age, ps->address);
(*ps).age = 80;
}
int main()
{
struct Stu s1 = {"1111", "张三", 23, "阿拉斯加"};
Print1(s1);
printf("%d\n", s1.age);
Print2(&s1);
printf("%d\n", s1.age);
return 0;
}

Print1是把s1这一整个变量传给形参,相比与传址而言,传值浪费空间严重,因为结构体本身是很大的,形参是实参的一份临时拷贝,传值会在栈区上开辟一模一样结构体s1。而地址的大小无非就是4个或者8个字节。
第二就是传地址可以在函数内改变函数外部的变量,因为使用的是s1本身。传值改变不了的原因是,形参是一块新的空间,改变不了原来的。

总结:对于结构体,传地址可以节省空间,可以改变外部变量,一般情况下传的是结构体的地址。