目录
一.结构
1.结构声明
2.初始化结构
3.访问结构成员
4.结构的初始化器
5.定义无结构标记
6.结构数组
7.嵌套结构
8.复合字面量和结构(C99)
9.伸缩性数组成员
10.伸缩性数组得特殊处理请求
11.匿名结构(C11)
12.使用结构数组得函数
一.结构
1.结构声明
结构声明时描述一个数据结构的组织布局,我们来看个例子
struct book{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
该声明描述了一个由两个字符数组和一个float数组变量组成的结构。该声明并未创建实际的数组对象。只描述了改对象由什么组成(而我们也把结构声明为模板,因为它描述了结构是如何存储数据的),你可以把它理解成int,double类型,其实它们本质都是一样的,都是为了存储对应的数据。
主要是为了存储图书信息,这里我们知道图书的信息其实分类很多,要有书名,作者,价格,内容等。这里我们用title数组存储书名,用author数组存储作者名,value变量存储书价格。
struct就是声明结构的关键字。
book是结构布局。
title,author,value我们成为成员或字段,它们可以是普遍的数据类型,也可以是其他结构(和自己本身一样的结构也可以)
存储在一个结构中的整套信息被称为记录
而我们创建这个结构声明,而struct book就类似于int,double这样的数据类型名。
下面我们来使用这个结构
struct book library;
这把library声明为一个使用book结构布局的结构变量
可以把这个声明放在所有函数的外部,也可以放在一个函数定义的内部。如果把结构声明置于一个函数的内部,它的标记就只限于该函数内部使用。如果把结构声明置于函数的外部,那么该声明之后的所有函数都能使用它的标记
struct book所起的作用相当于一般声明中的int或float,可以定义两个struct book类型的变量,或者甚至是指向struct book类型的指针
struct book doyle,panshin,* ptbook;
结构变量doyle和panshin中都包含title,author和value部分。指针ptbook可以指向doyle,panshin或者任何其他book类型的结构变量
2.初始化结构
struct book library = {
"hello world",
"you",
13
};
这里"hello world"就初始化给了title成员
和char title[MAXTITL] = "hello world";一样
"you"初始化给了author成员,13初始化给了value成员。
3.访问结构成员
使用结构成员运算符(.)访问结构中的成员。
library.value即使访问library的value的部分,.value的作用相当于book结构的下标。
这里我们使用libray.title来打印书名。因为title成员的类型就是char数组,所以在任何使用char数组的地方都可以正常的使用libray.title。
libray你可以理解为一个包含不同类型的袋子。而int,float这些类型变量就是存储数据的工具,工具在哪都是工具,而针对不同的任务,有目的的选择工具装入到袋子中,可以方便我们存储数据。
而前面我们说过,结构本质上来说就是一个存储数据的复杂类型,因为它其中可能包含了众多类型的数据。而只要是数据类型,我们就可以使用指针来操作。我们先来看例子。
struct book* pf = &libray;
这里我们使用了一个指针pf,pf指向一个struct book数据类型的指针。所以我们把libray变量的地址赋给了pf。这个时候pf的保存的就是libray变量的地址。
而如果我们想要访问这个变量地址上面对象成员的值,有两种方法,第一种就是将.变为->。还有一种就是使用(*pf).title的方式进行访问,这里主要因为*pf其实就是libray了,所以可以使用.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define MAXTITL 100
#define MAXAUTL 40
struct book {
char title[MAXTITL]; //书名
char author[MAXAUTL]; //作者名
float value; //价格
};
int main()
{
struct book libray = { "hello world","you",13 };
struct book* pf = &libray;
printf("%s %s %f", pf->title,(*pf).author,libray.value);
return 0;
}
4.结构的初始化器
C99和C11为结构提供了指定初始化器,这个语法和数组的指定初始化器类似。结构的指定初始化器使用点运算符和成员们标识特定的元素。
struct book library = {
.title = "hello world",
.author = "ycj",
0.25,
.author = "me",
};
与数组的初始化器类似,在指定初始化器后面的普通初始化器,为指定成员后面的成员提供初始值。另外对特定成员的最后一次赋值才是它实际的值。
所以author的作者的名字以最后一个.author = "me"确定。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define MAXTITL 100
#define MAXAUTL 40
struct book {
char title[MAXTITL]; //书名
char author[MAXAUTL]; //作者名
float value; //价格
};
int main()
{
struct book libray =
{ .title = "hello world",
.author = "you",
13,
.author = "me"};
struct book* pf = &libray;
printf("%s %s %f", pf->title,(*pf).author,libray.value);
return 0;
}
5.定义无结构标记
这样的情况下,如果要使用结构布局,就必须在声明布局的地方的右花括号右边使用变量名。不然后面就因为没有结构布局名的原因无法使用了
struct{
char title[MAXTITL];
char author[MAXAUTL];
float value;
}library
相当于struct book library;
这种布局可以在很多地方给我们省去给非必要结构布局起名的麻烦,后面的例子当中会有应用。
6.结构数组
之前说过结构就是复杂的数据类型,那么既然是类型,那么使用变量进行同类数据的存储是很有必要的。
struct book library[100];
数组的每个元素都是一个book类型的结构
而使用结构数组
Library[1].title,这里是使用第二个数组元素的title
而如果要取第二个数组元素的title字符串的第五个字符可以用
Library[1].title[4];
7.嵌套结构
有时,我们可以在一个结构这种包含另一个结构
这里我们在book结构中又嵌套了一个names结构
而在访问上,我们用library.option.age。进行二次(.)的解引用
8.复合字面量和结构(C99)
C99的复合字面量特性可用于结构和数组。如果只需要一个临时结构值,复合字面量很好用。列如,可以使用复合字面量创建一个结构作为参数或赋给另一个结构。语法是把类型名放在圆括号中,后面紧跟一个用花括号括起来的初始化列表。
struct book {
char title[MAXTITL]; //书名
char author[MAXAUTL]; //作者名
float value; //价格
};
struct book libray = (struct book){ "hello world","ycj",13 };
这里我们其实就是创建了一个临时的结构变量,这个变量把对应成员值都赋给了libray。最终的打印效果是完全一样的。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define MAXTITL 100
#define MAXAUTL 40
struct book {
char title[MAXTITL]; //书名
char author[MAXAUTL]; //作者名
float value; //价格
};
int main()
{
struct book libray = (struct book){ "hello world","ycj",13 };
struct book* pf = &libray;
printf("%s %s %f", pf->title,(*pf).author,libray.value);
return 0;
}
还可以把复合字面量作为函数的参数,如果函数接受一个结构,可以把复合字面量作为实际参数传递
在这个例子中,我们使用一个liaray,和一个符合变量地址,将libray原本的价格加上复合变量对应的价格。
9.伸缩性数组成员
C99新增了一个特性:伸缩性数组成员,利用这项特性声明的结构,其最后一个数组成员具有一些特性。其最后一个数组成员具有一些特性。
第一个特性,该数组不会立即存在。
第二个特性,使用这个伸缩性数组成员可以编写合适的代码,就好像它确实存在并具有所需数目的元素一样。
声明一个伸缩性数组成员又如下规则:
1.伸缩性数组成员必须随时结构的最后一个成员
2.结构中必须有一个成员
3.伸缩性数组的声明类似于普通数组,只是它的方括号是空的
struct flex{
Int count;
Double average;
Double scores[]; //伸缩性数组成员
}
伸缩性数组的意图并不是让我们声明struct flex类型的变量,而是希望我们声明一个指向struct flex类型的指针,然后用malloc()来分配足够的空间,以存储struct flex类型结构的常规内容和伸缩性数组成员所需的额外空间。
比如,假设用scores表示一个内含5个double类型值得数组
Struct flex * fp;
Pf = malloc(sizeof(struct flex) + 5 * sizeof(double));
现在有足够得存储空间存储count,average和一个内含5个double类型值得数组,可以用指针fp来访问这些成员
10.伸缩性数组得特殊处理请求
第一,不能用结构进行赋值或拷贝
Struct flex * pf1,*pf2;
…
*pf2 = *pf1; //不能这样做
不要这样操作,记住就好了
第二,不要以按值方法把这种结构传递给函数。原因相同,按值传递一个参数与赋值类似(和第一条原理类似)。要把结构得地址传递给函数
11.匿名结构(C11)
匿名结构和无结构标记类似,只不过匿名结构连变量名都不给了
不适用匿名结构
这里我们想要访问嵌套结构必须要使用x.names.last;
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
struct name
{
char first[20];
char last[20];
};
struct person
{
int id;
struct name names;
};
int main()
{
struct person x = { 1,{"yu","tiancai"} };
printf("%s", x.names.last);
return 0;
}
如果使用匿名结构
不仅整个结构更加清晰明了,而且也会节省时间
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
struct person
{
int id;
struct {
char first[20];
char last[20];
};
};
int main()
{
struct person x = { 1,{"yu","tiancai"} };
printf("%s", x.last);
return 0;
}
12.使用结构数组得函数
这里我们演示一下如何将结构传入到函数当中
首先数组名就是数组的地址,所以我们可以直接把结构数组名可以把它传递给函数。我们传入到函数当中的是一个不可修改值的指针。最后这个函数会分别取出bankfund和savefund的值进行相加返回。