概念:结构体是一些值的集合,这些值被称为成员变量。结构体内的每个成员可以是不同类型的变量,可以是标量,数组指针,甚至可以是其他结构体。
理解:结构体是一个类型,类似于int,float,double等,但这个类型的名字是可以自定义的。这样讲可能也很难理解,我们可以在下面的讲解中慢慢理解。
结构体的声明: struct tag struct为结构体的关键字,tag是可以自定义的结构体标签,也就是给结构体的类型起个名字(类似于整型的类型名字是int,单精度的类型名字是float)。
下面我们定义一个结构体类型,为了描述一个学生:
struct stu { char name[10]; short age[5]; char tele[20]; char sex[2]; };
阅读上面定义的结构体类型,里面包含了学生的名字,年龄,电话号,性别。像上面这样就成功的定义了一个结构体类型,类型的名字叫stu。一定要注意的是,‘}’后面的‘;’是不可以省略的。这个结构体类型的名字虽然是stu,但是在mian函数中定义变量时不能直接在stu后面加上变量名的。如下面程序:
注:为讲解方便,在下面程序中并没有给结构体变量初始化。
int main() { struct stu s; }
我们在使用这个类型时,是把结构体标签加上的。如果在main函数中要经常使用这个结构体类型,这样就会显得特别麻烦,于是我们可以这样改进:
#include<stdio.h> typedef struct stu { char name[10]; short age[5]; char tele[20]; char sex[2]; }stu; int main() { stu s; }
我们在定义结构体类型时,在关键字前面加上了“typedef”,并且在“}”后面加上了变量名,这样子在后面main函数中使用时就可以直接类型名加上变量名。
我们也可以在定义结构体类型时,直接定义结构体类型的变量,操作如下:
struct stu { char name[10]; short age[5]; char tele[20]; char sex[2]; }s1,s2,s3;
在结构体类型的后面直接加上想要定义的变量名,就可以直接定义结构体类型的变量,但需要注意的是这样定义的变量是全局变量,在平常使用时非到万不得已,最好不要这样写。我们还需要注意的是这段代码与上一段代码的区别,一个加了typedf,后面跟的是类型名,不加typedf后面跟的是变量名。
结构体变量的初始化:在定义一个结构体变量后,我们就得给这个变量初始化,初始化的方法入下:
#include<stdio.h> struct stu { char name[6]; char sex[4]; char tele[20]; short age; }; int main() { struct stu s = { "张三" , "男" , "18888888" , 14}; }
我们可以在使用结构体时,按照结构体,将结构体变量逐一初始化。
这只是一种初始化的方法,还其他方法,直接用代码来演示:
struct stu { char name[20]; char sex[20]; int age; }s={"zhangsan","男“,18}; 或者 struct stu { char name[20]; char sex[20]; int age; }; struct stu s={"李四”,“男”,18}; //这两种方法都是对全局变量的初始化
结构体概念中我们提到,结构体中还可以是指针或其他结构体,我们用一段代码来演示:
#include<stdio.h> struct stu1 { char name[6]; char sex[4]; char tele[20]; short age; }; struct stu2 { struct stu1 s1;//我们在stu2中用stu1定义了一个变量,变量名叫是s1 char* pc;//定义了一个指针变量pc }; int main() { char arr[20] = { "点赞收藏加关注" }; struct stu2 s2 = { { "张三" , "男" , "1888888888" , 14},arr}; //初始化结构体类型变量中的结构体类型需要加上花括号 }
结构体成员的访问
如果想要打印结构体变量中的某一成员是,我们可以使用(.)操作符,若想要将上一个程序里面s2的成员打印出来,我们可以进行以下操作:
printf("%s\n", s2.pc);//打印s2中的指针变量所指向的值 printf("%s", s2.s1.tele);//打印s2中的结构体s1中的tele
运行结果如下:
结构体在函数中的传参:
直接上代码:
方法一:
#include<stdio.h> typedef struct stu { char name[10]; char sex[4]; char tele[20]; int age; }stu; void Printf(stu x)//接收变量x时,要使用与x类型相同的实参 { printf("%s", x.name); } int main() { stu s = { "奥特曼","男","不明",500 }; Printf(s);//将s传给Printf函数 }
方法二:
#include<stdio.h> typedef struct stu { char name[10]; char sex[4]; char tele[20]; int age; }stu; void Printf(stu* x)//接收变量x时,要使用与x类型相同的实参 { printf("%s", x->name);//->用于指向结构体成员数据的指针,用来取成员数据。 } int main() { stu s = { "奥特曼","男","不明",500 }; Printf(&s);//将s的地址传给Printf函数 }
对比放方法一与方法二,哪一个好呢?
显然是第二个,因为第一个会在Printf函数中开辟一个与s一样大小的空间,如果s成员所占空间很大的话,就会造成空间浪费。第二种方法是传输地址,在Printf中开辟空间与s中成员大小无关,只与成员个数有关,因为地址的大小要么是4要么是8(在32位操作系统中地址大小为4,在64位操作系统中地址大小为8),这样就会节省很多内存空间。