结构体类型的定义
一般形式为:
struct 结构体名 {
类型名1 成员名1;
...
类型名n 成员名n;
};
struct是结构体类型的标志。结构体名是由用户定义的标识符,它规定了所定义的结构体类型的名称。结构体类型的组成成分称为成员,成员名的命名规则与变量名相同。
用途:把不同类型的数据组合成一个整体--自定义数据类型。
结构体类型定义可以包含另外的结构体,即结构体是可以嵌套的。
定义结构体类型只是说明了该类型的组成情况,编译系统并没有给它分配内存空间,就像系统不为int等类型本身分配空间一样。只有当定义属于结构体类型的变量时,系统才会分配存储空间给该变量。
结构体变量的定义:
1.先定义结构体类型,再定义结构体变量:
struct 结构体名 {
类型名1 成员名1;
...
类型名n 成员名n;
};
struct 结构体名 变量名;
2.定义结构体类型的同时定义结构体变量:
struct 结构体名 {
类型名1 成员名1;
...
类型名n 成员名n;
}变量名1,变量名2,...;
3.直接定义结构体类型变量,省略结构体类型名,由于这种定义形式没有说明结构体类型,所以这种方式通常用在不需要再次定义此类型结构体变量的情况下:
struct {
类型名1 成员名1;
...
类型名n 成员名n;
}变量名1,变量名2,...;
结构体变量中的各成员在内存中是按定义顺序依次排列的。
结构体变量的初始化
对结构体类型变量赋初值时,按每个成员的结构体中的顺序一一对应赋值。
在定义时初始化的3种方式:
struct 结构体名 {
类型名1 成员名1;
...
类型名n 成员名n;
};
struct 结构体名 变量名 = {初始数据};
struct 结构体名 {
类型名1 成员名1;
...
类型名n 成员名n;
}变量名1 = {初始数据};
struct {
类型名1 成员名1;
...
类型名n 成员名n;
}变量名1 = {初始数据};
结构体变量的引用
对结构体变量的引用分为对结构体变量中成员的引用和对整个结构体变量的引用,对成员的引用方式:
结构体变量名.成员名
结构体嵌套时逐级引用,如:
#include<stdio.h>
struct Date
{
int year;
int month;
int day;
};
struct Student
{
char name[20];
char sex;
struct Date birthday;
};
void main() {
struct Student xiaoming = { "zhangsan", 'm',{ 2017,1,3 } };
// 对整个结构体变量的引用
struct Student xiaowang = xiaoming;
// 对结构体变量成员的引用
xiaowang.sex = 'w';
printf("xiaoming's name is %s, he's birthday is %d\n", xiaoming.name, xiaoming.birthday.year);
printf("xiaowang's sex is %c\n", xiaowang.sex);
system("pause");
}
输出结果:
xiaoming's name is zhangsan, he's birthday is 2017
xiaowang's sex is w
结构体数组
定义结构体数组的方式和定义结构体变量的方法一样,只是必须说明其为数组。
// 1
struct 结构体名 {
类型名1 成员名1;
...
类型名n 成员名n;
};
struct 结构体名 变量名[3];
// 2
struct 结构体名 {
类型名1 成员名1;
...
类型名n 成员名n;
}变量名1[3];
// 3
struct {
类型名1 成员名1;
...
类型名n 成员名n;
}变量名1[3];
结构体数组的初始化与引用
void main() {
struct Student student[2] = { {"xiaoming", 'm',{ 2017,1,3 }},{ "xiaowang", 'w',{ 2016,1,3 } } };
printf("xiaoming's name is %s, he's birthday is %d\n", student[0].name, student[0].birthday.year);
printf("xiaowang's sex is %c\n", student[1].sex);
system("pause");
}
输出结果:
xiaoming's name is xiaoming, he's birthday is 2017
xiaowang's sex is w
结构体与指针
指向结构体的指针存放结构体变量在内存中的起始地址。
定义形式:struct 结构体名 *结构体指针名;
使用结构体指针变量引用成员的形式:
(*结构体指针名).成员名 <==> 结构体指针名->成员名 <==> 结构体变量名.成员名
如:
void main() {
struct Student xiaoming = { "zhangsan", 'm',{ 2017,1,3 } };
struct Student *p = &xiaoming;
(*p).sex = 'w';
printf("xiaoming's sex is %c, he's birthday is %d\n", xiaoming.sex, p->birthday.year);
system("pause");
}
输出结果:
xiaoming's sex is w, he's birthday is 2017
指向结构体数组的指针
void main() {
struct Student student[2] = { { "xiaoming", 'm',{ 2017,1,3 } },{ "xiaowang", 'w',{ 2016,1,3 } } };
struct Student *p;
for (p = student; p < student + 2; p++) {
printf("name is %s, sex is %c, birthday is %d\n", (*p).name, p->sex, p->birthday.year);
}
system("pause");
}
输出结果:
name is xiaoming, sex is m, birthday is 2017
name is xiaowang, sex is w, birthday is 2016
共用体/联合体
构造数据类型,也叫联合体。
用途:使几个不同类型的变量共占一段内存(相互覆盖)。
定义形式:
union 共用体名 {
类型标识符 成员名;
...
类型标识符 成员名;
};
共用体变量的定义、调用跟结构体类似。
共用体变量的初始化:与结构体变量的初始化不同的是,只能对共用体变量列表中的一个变量进行初始化。且不能在声明变量时进行初始化操作。
共用体成员访问与赋值:不论共用体在定义时成员列表中有多少项,在某个确定时刻,共用体变量只能存储一个成员。共用体实际上是为不同的成员分配一块共用内存,编译器并不会约束存入这块内存的值,关键在于程序员如何解析这块内存,如何使用存入的内容。
如:
#include<stdio.h>
union He {
char a;
int age;
}hehe;
void main() {
hehe.a = 'A';
printf("%c\n", hehe.a);
printf("%d\n", hehe.age); // 此时该成员无效
hehe.age = 20;
printf("%c\n", hehe.a); // 此时该成员无效
printf("%d\n", hehe.age);
system("pause");
}
输出结果:
A
-858993599
20
结构体变量的每个成员分别占有独立的内存区域,因此结构体变量所占内存字节数是其成员所占内存字节数之和。而共用体的所有成员共同占用一段内存区域,所以共用体变量所占字节数是其成员中占内存空间最大的成员的字节数。
结构体变量和共用体变量内存形式的不同:
编译器会为结构体变量中的每个数据成员分配不同的地址空间,也就是说结构体变量中的数据程序是并列关系,而编译器为共用体变量中的数据成员分配的是同一块内存,每个时刻只有一个数据成员有意义,从地址的角度来看两者的差异形象地说明了这一点。
结构体和共用体可以互相嵌套使用。
枚举类型
在定义枚举类型时,需指明其取值集合,用枚举类型声明枚举变量时,只能取集合中的某项作为其值,这在一定程度上保证了取值的安全性。
枚举类型定义的一般形式:
enum 枚举名 {
枚举元素1,
...
枚举元素n
};
如果不给枚举常量赋初值,编译器会为每一个枚举常量赋一个不同的整型值,第一个为0,第二个为1等等。当枚举表中某个常量赋值后,其后的成员则按顺序依次加1的规则确定其值。
例子:
#include<stdio.h>
enum Week
{
HEHE,
HAHA
};
enum Haha {
HEIHEI = 2,
XIXI,
GAGA = 9
};
void main() {
printf("HEHE=%d,HAHA=%d\n", HEHE, HAHA);
printf("HEIHEI=%d,XIXI=%d,GAGA=%d\n", HEIHEI, XIXI,GAGA);
system("pause");
}
输出结果:
HEHE=0,HAHA=1
HEIHEI=2,XIXI=3,GAGA=9
类型定义typedef
用自定义名字为已有数据类型命名。
类型定义的简单形式:
typedef 已有数据类型名 自定义名;
typedef只是对已经存在的类型指定一个新的类型名,而没有创造新数据类型。
用typedef声明数组类型、指针类型、结构体类型、共用体类型、枚举类型等使得编程更加方便。
当不同源文件中用到同一类型数据时,常用typedef声明一些数据类型。可以把所有的typedef名称声明单独放在一个头文件中,然后在需要用到它们的文件中用#include指令把它们包含到文件中。这样编程者就不需要在各文件中自己定义typedef名称了。
例子:
#include<stdio.h>
typedef int INTEGER;
void main() {
INTEGER a = 1;
printf("a = %d\n", a);
system("pause");
}
输出结果:a = 1
#define用法
#define语句称为预定义语句,是预处理指令,在编译预处理时进行简单的替换,不做正确性检查,不管含义是否正确,只是简单的替换。
typedef语句后的分号一定要写,#define不是语句,后面不能加分号,如果#define结构后面出现分号,会一起被替换。