在之前的章节中我们学习了很多数据结构,变量,数组,结构体。
在接下来我们学习一种不同于数组的数据结构 - 结构体。数组用于存储多种相同类型的数据,而结构体可以存储多种不同的数据类型。数据结构是一种存储和管理数据的结构,其本身并没有什么意义。
1.接下来我们要区分 结构 和 结构体 之间的区别
自定义一种新的数据类型称为结构,不占用内存。按照结构创建一种变量,占用内存称之为结构体。
建立结构声明
结构声明创建了一个组织布局
struct book { 我们创建一个book模板,一个结构勾勒出如
char title[ x ] ; 何存储数据。book称为标记,我们可以通过标
char author[ y ] ; 计来引用结构。
float value ;
};
如果将结构和标记放置于函数的外部,那么标记具有全局作用域,之后的函数都可以引用它。
如果将结构和标记放置于函数的内部,那么标记只限于这个函数进行使用。
2.结构体的定义
我们建立了一个坐标,用x和y来表示它,坐标x和y都是整数。
我们可以采用结构来存放这两个坐标
struct point{ int x ; int y ;} ;
其中point为结构标记,结构标记用于结构命名。结构定义中的变量称为成员。
在标志结构成员表结束的右花括号之后可以跟一个变量表
struct{ . . . } x , y , z ;
x , y , z 声明为指定类型的变量,并且为它们分配存储空间。
定义结构变量
在结构体的声明中 struct book 的作用类似于 int 或 float
可以定义两个struct book类型的变量和指向struct结构的指针
struct book liabrary , library2 , *pbook ;
在结构变量中library和library2的结构相同都包含title部分author部分和value部分。
指针pbook可以指向 library 和 library2 任意的book类型结构变量。
图-结构的三种写法3 , 无结构标记。
声明结构的过程和定义结构变量的过程可以组合成一个步骤,组合后不需要使用结构标记。
初始化结构
初始化结构和初始化变量是一样的
struct book libraty={ "了不起的盖茨比","菲茨杰拉德",35.5};
初始化结构和类别存储期
注意:字符型数组可以在初始化的时候之间赋值 char name[x] 初始化"了不起的盖茨比"
但是 在主程序中无法对字符串数组这种复杂的数据结构进行直接赋值。
我们可以通过
strcpy(library.name , " 了不起的盖茨比") ;
进行赋值
结构的初始化器
3.访问结构体的成员
我们用 结构标记.结构成员 的方式引用结构体中的成员
1)字符数组不能直接赋值,在初始化时可以直接赋值。
2)结构体复杂数据结构不能直接赋值,只能通过strcpy()函数赋值。
3)运算符.属于偏移
1)for 循环遍历s[3]的嵌套
2)结构体teacher中嵌套结构体xiaoshu
3)多重引用
在之前的book结构中的例子,library.value是一个float类型的变量。
可以像使用float变量一样使用它,scanf(" %f ", &(library.value)需要一个float类型变量的地址。
可以用library.float去访问value
4.结构体在内存
结构体在内存中的结构
5.结构体内存中的对齐和补齐
此时我们注释掉了第二个结构体成员,4+8=12,而输出结果依旧是4+4+8=16,那么就引出了我们的结构体内存的对齐和补齐。(其实是为了引用符 . 在访问时指针的偏移)
这里指针的用法,我们定义了一个指针p(void类型)指向了结构体 a,再开辟了一个指针pChar指向了结构体的第一个成员char类型。
6.(重点) 结构体的引用符,指针和偏移
注意区分:char*p和(char*)p , char*p是定义了一个指针,指针指向char类型,(char*)p是强制类型转换指针p为char类型。
%c对应char类型,为一个字符
重点结构体指针偏移算法
这段程序我们用指针来访问结构体中的每个成员,那么最关键的是 指针的偏移再强制类型转换。每次我们访问下一个成员的时候将指针偏移到下一一个位置,并且强制转换成成员类型,这样我们就不用计算成员的字节数来进行偏移
所以结构体中成员再内存中的对齐和补齐,就为引用符号 . 提供了极大的便利。
结果
我们成功用指针访问了结构体的每个成员。
7.结构体与函数
我们上面例题中创建了void类型setstruct函数,我们想通过函数对结构体赋值。而变量名具有局部作用域,所以我只能通过指针来传递改变变量的参数。
如果我们知道了结构体的指针想访问成员可以用 -> 来访问成员;
*a->n; 来访问成员的值。
8.结构数组
声明结构数组
library[2].author[4]; 访问library[2]的author的5个字符
标识结构数组的成员
总结
9.嵌套结构
在结构中包含另一个结构称为嵌套。
结果
10.指向结构的指针
11.初始化结构指针
声明结构指针
struct B*p ,关键字struct其次结构标记B,(struct B *)类似于int,声明了一个结构指针却未向它指向何处。
如果fellow属于B结构,可以让fellow和B连接起来
B=&fellow[0]; //本例中fellow是一个结构体数组,所以我们将B指向第一个结构体。
B++
B指向了fellow[1]
和 数组 不同的是,结构名并不是结构的地址,因此要在结构名前加&
12.用指针访问结构成员
第一种: p=&fellow[0] ; p->income //用指针访问结构体成员
第二种: (*p).income
13.结构体和函数
14.向函数中传递结构体信息的三种方式
14.1 传递结构体的地址(指针)
结果
14.2 向函数传递整个结构体
14.3 向函数传递结构体的成员
结构和结构指针的选择
结构中字符数组和字符指针
结构 指针 和 malloc()
使用结构数组的函数
假设一个函数处理一个结构数组,数组名就是该数组的首地址,可以把它传递给函数。函数还需要访问结构模板
数组名money是该数组的首地址,即money[0]的地址,因此 money=&money[0];
因此money指向money数组的首元素。
1.可以把数组名作为数组中第1个结构的地址传递给函数。
2.