1. 结构体的声明
1.1 结构体的基础知识
我们已经知道:数组是一组相同类型元素的集合。
可是在生活中我们经常描述一个人或一种事物的一些特征,这些特征却往往不是相同的数据类型。
例如:我需要描述一个人的基本信息:姓名、性别、年龄、身高、体重、身份证号、住址......
又例如:我需要描述一本书的情况:书名、作者、出版社、定价、书号......
等等很多复杂对象,我们不能通过像数组一样,用内置类型来直接进行表示和描述,正基于此,我们要学习结构体的知识:
结构体是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
1.2 结构体的声明
结构体的声明遵循以下方法:
例如描述一个人的信息:
①:
struct peo//所定义的结构体的名字 { //成员变量,用来描述结构体的相关属性 char name[20]; int age; char sex[5]; }p1,p2,p3;//peo结构体申请的变量名字—全局变量
也可以:
②:
struct peo//所定义的结构体的名字 { //成员变量,用来描述结构体的相关属性 char name[20]; int age; char sex[5]; }; int main() { //peo结构体申请的变量名字—局部变量 struct peo p1; struct peo p2; struct peo p3; return 0; }
当然,针对②,我们申请局部变量的时候要写struct peo p1;这么长的字母,为了省事方便,我们也可以使用typedef这样写:
typedef struct peo//所定义的结构体的名字 { //成员变量,用来描述结构体的相关属性 char name[20]; int age; char sex[5]; }peo;//简单来说,相当于把struct等价与peo,更方便下面创建局部变量 int main() { //peo结构体申请的变量名字—局部变量 peo p1; peo p2; peo p3; return 0; }
1.3 结构体变量的定义和初始化
有了结构体类型,那么又该如何进行变量的定义和初始化呢?
①:
struct peo { char name[20]; int age; char sex[5]; } p1 = { "xxk",22,"男" };
②:
struct peo { char name[20]; int age; char sex[5]; }; int main() { struct peo p1 = { "xxk",22,"男" }; return 0; }
观察①和②,我们发现变量的初始化都必须按照我们在结构体里按照变量的定义顺序来初始化,那么有没有不按照顺序初始化的方法吗?
答案当然是有的,这时我们需要使用到 . ——结构体成员访问操作符
具体方法如下:
struct peo { char name[20]; int age; char sex[5]; }; int main() { struct peo p1 = { .sex = "男",.age = 22,.name = "xxk" }; return 0; }
运行结果如下:
#include <stdio.h> struct peo { char name[20]; int age; char sex[5]; }; int main() { struct peo p1 = { .sex = "男",.age = 22,.name = "xxk" }; printf("%s %d %s", p1.name, p1.age, p1.sex); return 0; }
2. 结构体成员的访问
在1.3里,我们其实已经介绍了一种结构体成员的访问方法—— . 操作符
紧接着,按照这个逻辑,我们看下面代码:
#include <stdio.h> #include <string.h> struct peo { char name[20]; int age; char sex[5]; }; void func_peo(struct peo p) { //p.name = "徐霞客";//注意这样写错误,name是数组首元素的地址,而"徐霞客"是字符串呀!怎么能把字符串写到地址上呢? strcpy(p.name, "徐霞客");//字符串拷贝,应该把“徐霞客”写进地址所指向的那份空间里面去! p.age = 22; strcpy(p.sex, "男"); } int main() { struct peo p1 = { 0 }; func_peo(p1); printf("%s %d %s", p1.name, p1.age, p1.sex); return 0; }
运行结果:
运行结果显然是不对的,这是为什么呢?
因为在C语言的函数传参过程中,当实参传递给形参的时候,形参是实参的一份临时拷贝,所以对形参的修改不会对实参产生影响。(后续会针对此知识做详细解释)
我们这时就要用到传址调用:
#include <stdio.h> #include <string.h> struct peo { char name[20]; int age; char sex[5]; }; void func_peo(struct peo* p) { strcpy((*p).name, "徐霞客"); (*p).age = 22; strcpy((*p).sex, "男"); } int main() { struct peo p1 = { 0 }; func_peo(&p1); printf("%s %d %s", p1.name, p1.age, p1.sex); return 0; }
运行结果:
观察以上代码,用()再加*.会不会有些繁琐呢?所以C语言又提供了另外一种结构体指针(->)访问方法:
#include <stdio.h> #include <string.h> struct peo { char name[20]; int age; char sex[5]; }; void func_peo(struct peo* p) { strcpy(p->name, "徐霞客");//结构体指针->结构体成员 p->age = 22; strcpy(p->sex, "男"); } int main() { struct peo p1 = { 0 }; func_peo(&p1); printf("%s %d %s", p1.name, p1.age, p1.sex); return 0; }
经过以上叙述,我们也应该明白:结构体传参的时候,要传结构体的地址。