结构变量
目前接触到的唯一一种数据结构就是数组。数组有两个重要特性:
- 数组的所有元素具有相同的类型
- 为了选择数组元素,需要指明元素的位置(作为数组的下标)
而结构具有的特性和数组不同,比如结构的元素(C语言中称结构的元素为成员)。
- 结构的成员可能有不同的数据类型。
- 每个结构成员都有名字
所以为了选择特定的结构成员需要指明结构成员的名字,而不是他的位置。
声明结构变量
假如需要记录存储在仓库中的零件。用来存储每种零件的信息可能包括零件的编号(整数)、零件的名称(字符串)以及现有零件的数量(整数)。为了产生一个可以存储全部3种数据项的变量,可以使用类似下面这样的声明:
struct {
int number;
char name[25];
int on_hand;
} part1, part2;
每个结构变量都有3个成员:number(零件的编号)、name(零件的名称)和on_hand(现有数量)。
注意,这里的声明格式和C语言种其他变量的声明格式一样。
struct{.......} 指明了类型,而part1和part2则是具有 struct 结构类型的变量
结构的内存存储
结构的成员在内存中是按照声明的顺序存储的,我们假设:
- part1存储在地址为2000的内存单元中
- 每个整数在内存中占4个字节
- c 风格字符串name占用25个字节
- 成员之间没有间隙
那么part1在内存中的样子如下所示
一般情况下不用这么详细,这样表示即可:
结构的作用域相关
每个结构代表一种新的作用域,任何声明在此域内的名字都不会和程序中的其他名词冲突。例如:
struct {
int number;
char name[25];
int on_hand;
} part1, part2;
struct {
int number;
char name[25];
char sex;
} employee1,employee2;
结构 part1 和 part2 中的成员 number 和成员 name 不会与 employee1 和 employee2 中的成员 number 和成员 name 发生冲突。(有点拗口)
初始化结构变量
结构变量可以在声明的同时进行初始化。只需要把待存储到结构中的值的列表准备好,并用花括号把它括起来 :
struct {
int number;
char name[25];
int on_hand;
}part1 = {528,"disco",10},part2 = {914,"car",5}
初始化的值必须按照结构成员的顺序进行显示。所以part1的成员number值为528,name则是"disco",以此类推。不过还需要注意”
- 初始表达式,就是{528,"disco",10}中的值不能有变量,必须都是常量。
- 初始化成员中的成员数,可以少于结构的成员数,这句话意思用代码演示:
struct {
int number;
char name[25];
int on_hand;
}part1 = {528,"disco"}
就像这样,“剩余”的成员都用0作为他的初始值,但是字符数组有所不同,剩余的字符数组是一个空字符串。
访问结构成员
首先写出结构体的名字,然后写一个英文句点,再写出成员的名字。例如:
printf("%d",part1.number);
printf("%s",part1.name);
printf("%d",prat.on_hand);
还可以对他赋值,自增自减等。
part1.number = 258;
part.on_hangd ++;
用于访问结构成员的英文句点,实际上就是一个运算符。
结构类型
我们需要命名结构类型。因为如果程序想要声明多个具有相同成员的结构变量的话。如果一次能声明全部变量,则没有什么问题,但是如果需要在程序中的不同位置声明变量,问题便复杂了。比如,我们再程序的一处声明了part1,如下
struct {
int number;
char name[25];
int on_hand;
} part1;
我们还想在另一处声明一个part2,就得在另一处编写一个:
struct {
int number;
char name[25];
int on_hand;
} part2;
这样做会有比较大的问题,日后修改程序会有一定的风险。当然这还不是最大问题,最重要的是:
根据C语言的规则,part1 和 part2 不具有兼容的类型,因此不能把 part1 赋值给 part2 ,反之亦然。而且part 1 和 part2 的类型 都没有名字,所以也就不能把他们用作函数调用的参数。
所以我们一定要定义结构类型的名字,C语言提供了两种方法:
- 声明“结构标记”的方法。
- 定义结构类型(使用typedef来定义类型名)
声明结构标记
结构标记用于表示某种特定结构的名字。使用方法如下:
struct part {
int number;
char name[25];
int on_hand;
}; //注意本行花括号后的分号必不可少!它表示声明结束。
我们创建了标记 part ,就可以用它来声明结构变量了:
struct part part1, part2;
但是不能漏掉单词sturct,会报错的。因为 part 不是类型名,如果没有单词 struct 的话,part 没有任何意义。只有在结构标记前放置了单词 struct 才有意义,所以他们不会和程序中用到的其他变量名字起冲突。程序拥有名为part的变量是完全合法的(虽然很容易混淆,不建议哈)。
而且结构标记的声明可以和结构变量的声明合并:
struct part {
int number;
char name[25];
int on_hand;
}part1, part2;
我们不仅声明了结构标记part,还声明了结构变量part1,part2。我们还可以继续声明变量,而且所有声明为struct part 类型的结构彼此之间的是兼容的,可以相互赋值。
struct part part3 = {521,"wo ai ni",521};
struct part part4;
part4 = part3;
定义结构类型
这是我们上面说的第二种方法,他是使用 typedef 关键字来定义真实的类型名。例如,我们可以按照如下方式定义名为 Part 的类型:
typedef struct {
int number;
char name[25];
int on_hand;
}Part;
注意,类型 Part 的名字必须出现在定义的末尾,而不是在单词structural的后边。
因为我们这种方式定义出来的是真实的结构类型。所以我们可以直接使用 Part 声明变量:
Part part1,part2;
而且使用 typedef 定义结构类型的这种方式,以后是不允许书写 struct Part 来声明变量的。而且声明为Part类型的所有结构变量都是兼容的,可以相互赋值。