目录
前言:什么是结构体
在解决实际问题中除了已有的整形(int,long等)、浮点型(flaot,double)、字符型(char)、数组等数据类型是不够的。比如我们统计一本书的信息,就需要保存它的书名(char),作者(char),价格(double),出版时间(int)等等,这些数据类型不相同但又是一个整体,我们就需要定义一个新的数据类型——结构体。利用结构体把这些数据保存起来。
结构体是由一批数据组合而成的结构型数据。组成结构型数据的每个数据称为结构型数据的“成员” ,其描述了一块内存区间的大小及解释意义。结构体是C语言中一种重要的数据类型,该数据类型由一组称为成员(或称为域,或称为元素)的不同数据组成,其中每个成员可以具有不同的类型。结构体通常用来表示类型不同但是又相关的若干数据。
1.结构体的声明
//声明一个结构体的标准格式 struct 名称 //这里的名称在c语言中可以省略,但不推荐。 { 成员变量1; ········· //成员变量在c语言中不可省略,只是要有1个成员 成员变量n; }; //例: struct book { char name[10]; //表示书名的字符串 double price; //表示书价格的数 int time; //表示书的出版时间 };
struct 表示接下来的是一个结构体。
声明结构体的本质:声明结构体的本质就是新增一种数据类型。
2. 结构体变量的定义和初始化
2.1结构体变量的定义
1.假如我们声明过了结构体类型,那么就可以直接定义结构体变量b1。例如:
struct book b1; //格式:struct 名称 变量名
2.每次定义结构体变量时,都得 struct 名称 变量名;不方便。这里我们就用到了 typedef(类型重命名),可以用typedef为已有的数据类型取一个新的名字,可以使程序书写简单,增强程序的可读性。
//方法一: typedef struct 名称1 { 成员变量1; ········· 成员变量n; }名称2; //方法二: struct 名称1 { 成员变量1; ········· 成员变量n; } typedef struct 名称1 名称2;
在结构体变量的定义时,我们可以不再用 “ struct 名称1 变量名;” 这样的的方法来定义,可以直接“名称2 变量名;”来定义它。
例:
typedef struct book { char name[10]; double price; int time; }shu;
在结构体变量的定义时,我们可以不用 struct book b2;的方法来定义,可以直接 shu b2;来定义b2.
2.2结构体变量的初始化
定义结构体变量的同时可以被整体赋初始值。
例:
//方法1. struct book { char name[10]; double price; int time; }b3 = { "白夜行",49.80,1999 }; //方法2. struct book { char name[10]; double price; int time; } struct book b3 = { "白夜行",49.80,1999 };
结构体类似于数组,只可被整体初始化,不可被整体赋值!
不可以:
struct book { char name[10]; double price; int time; }b3; struct book b3 = { "白夜行",49.80,1999 };//不可以在声明之后这样赋值 或者 book b3 = { "白夜行",49.80,1999 };//不可以在声明之后这样赋值 或者 b3 = { "白夜行",49.80,1999 };//不可以在声明之后这样赋值
这样编译器会报错!
2.3结构体嵌套及初始化
现在我们要在刚才所声明的结构体:
struct book { char name[10]; //表示书名的字符串 double price; //表示书价格的数 int time; //表示书的出版时间 };
内部再嵌套一个结构体:
struct position { double x; //表示书在书架的几排 double y; //表示书在书架的几列 };
嵌套后:
struct book { char name[10]; //表示书名的字符串 double price; //表示书价格的数 int time; //表示书的出版时间 struct position;//表示书的位置 };
那么此时我们如何初始化结构体变量b3呢?和二维数组的初始化相似:
struct book b3={"白夜行",49.80,1999,{3,2}};
3. 结构体成员的访问
3.1可通过“ . ”操作符访问
其一 般形式为:结构体变量名.成员变量。
结构体中的成员变量用法和普通变量是一样的。
比如:可以给成员变量单独赋值(不可以被整体赋值!!!)
例子:
3.2 指向结构体变量的指针访问
struct book b3 = { "白夜行",49.80,1999 }; struct *p=&b3;
结构体变量的指针引用结构体变量的成员分量
方法一 :使用 * 运算符
printf("%d\n", (*p).time);
方法二 :使用 -> 指向运算符
printf("%d\n", p->time);
4. 结构体传参
#include<stdio.h> struct book { char name[10]; double price; int time; }; struct book b3 = { "白夜行", 49.80, 1999}; void ShowBook1(struct book n) { printf("%s\n", n.name); printf("%lf\n", n.price); printf("%d\n", n.time); } void ShowBook2(struct book *p) { printf("%s\n", p->name); printf("%lf\n",p->price); printf("%d\n", p->time); } int main() { ShowBook1(b3); ShowBook2(&b3); return 0; }
ShowBook1() 传的是结构体,ShowBook2() 传的是结构体的地址 。
函数传参时,会发生零时拷贝。往ShowBook1()传参时传的是结构体,所以零时拷贝的也是结构体。往ShowBook2()传参时传的是结构体的地址,所以零时拷贝的也是结构体的地址。若结构体所占的内存较大,往ShowBook1()传参时,临时拷贝的数据也会非常大,调用函数的成本会非常高。所以推荐使用ShowBook2() 函数,只需要拷贝结构体的地址,不管结构体有多大,都会非常稳定。总的来说:结构体传参的时候,要传结构体的地址。