1、结构体的定义及初始化
通过数据类型来定义一个一个的变量,当需要很多相同类型的变量时有数组。 基本数据类型在使用时很方便,但是利用它们来描述现实世界就显得捉襟见肘。 例如需要保存一个班学生的信息”姓名,年龄,分数”,按照前面的学习需要单独 定义三个数组,一个保存姓名,一个保存年龄,一个保存分数。这样定义对于后面 的维护,修改,删除会带来麻烦。好比你用三个记事本一个记录学生姓名,一个记 录年龄,一个记录分数,如果删除姓名记事本中的第十个学生,而在年龄,分数记 事本中却删除了第十一个,这是很容易发生的。实际中并不会这么做,我们会利用 一个 Excel 表来记录学生的信息,一行就是一个学生的所有信息,修改,添加,删 除都非常清晰。而这就是今天学习的内容-自定义数据类型。
自定义数据类型:根据自己的需要定义新的数据类型。
自定义数据类型包括结构体,位段,共用体和枚举。当然最重要的就是一号选 手-结构体。
例如:定义一个学生结构体,包含姓名和年龄
struct Student //定义学生结构体
{
char name[20];//姓名
int age; //年龄
}; //类型定义完成
这个类型定义好了之后就和基本类型一样使用,可以用来定义单个变量,数 组,指针或者作为另一个结构体的成员。
结构体变量定义好之后该如何访问它的成员呢?如何输出 stu3 中的信息呢? 结构体变量通过”.”号访问其成员。
输出 stu3 信息的代码如下:
printf("%s,%d\n",stu3.name,stu3.age);//通过.号访问成员
struct Student //定义学生结构体
{
char name[20];//姓名
int age; //年龄
}; //类型定义完成
int main()
{
struct Student stu1;
struct Student stu2 = {"caocao"};
struct Student stu3 = {"刘备",25};
printf("%s,%d\n",stu3.name,stu3.age);//通过.号访问成员
//修改成员的数据
strcpy(stu1.name,"孙权"); //字符串复制需要用 strcpy
stu1.age = 18; //通过.号访问成员
printf("%s,%d\n",stu1.name,stu1.age);//通过.号访问成员
strcpy(stu2.name,"曹操"); //通过.号访问成员
stu2.age = 24; //通过.号访问成员
printf("%s,%d\n",stu2.name,stu2.age);
return 0;
}
2、结构体指针定义及使用
结构体指针定义
结构体不仅能定义普通的变量,也可以定义指针,例如:
struct Student //定义学生结构体
{
char name[20];//姓名
int age; //年龄
};
int main()
{
int a = 10;
int *p = &a;
struct Student stu = {"曹操",23};
struct Student *ps = &stu;//类似 p
struct Student *ps2; //没有初始化,野指针
return 0;
}
结构体指针变量和整型指针变量类似,用于保存同类型变量的地址
结构体指针访问其成员 结构体指针 ps 如何访问结构体的成员呢?一个笨办法就是(*ps).age 这种形 式。注意一定要加”()”,因为”*”的优先级低于”.”,这个办法不仅容易出错, 写起来也繁琐,C 语言有一种更简洁的表达形式。
结构体指针通过”->”访问其成员。
例如下面代码。
int main()
{
int a = 10;
int *p = &a;
struct Student stu = {"曹操",23};
struct Student *ps = &stu; //类似 p
struct Student *ps2;
printf("%s,%d\n",(*ps).name,(*ps).age);//这个方法繁琐,易错
printf("%s,%d\n",ps->name,ps->age); //结构体指针访问其成员
ps2 = &stu;
ps2->age = 30; //通过 ps2 修改 stu 的年龄
printf("%s,%d\n",ps2->name,ps2->age);
return 0;
}
总结:结构体变量通过”.”访问其成员,结构体指针通过”->”访问其成员。
3、结构体数组定义及使用 结构体数组定义 结构体定义完成后和内置类型一样使用,能定义变量,指针当然也可以定义数组。
struct Student
{
char name[20];
int age;
};
int main()
{
//内置类型,定义变量,指针和数组
int a = 10;
int *p = &a;
int arr[10] = {1,2,3};
//结构体类型,定义变量,指针和数组
struct Student stu = {"曹操",23};
struct Student *pstu = &stu;
struct Student brr[3];
struct Student crr[3] = {{"曹操",23},{"刘备",25},{"孙权",18}};
struct Student drr[3] = {"曹操",23,"刘备",25,"孙权",18};
struct Student err[] = {"曹操",23,"刘备",25,"孙权",18};
return 0;
}
5、typedef 的使用
在 C 语言中使用结构体时必须加上 struct 这个关键字,那有没有办法省略这 个呢?要想达到这个目的就需要用到关键字 typedef,顾名思义”类型定义”。
typedef 数据类型 新的别名;
它是用来操作数据类型。其主要作用有两个:
1.给一个较长较复杂的类型取一个简单的别名。
2.给类型取一个和问题相关的别名。
如何在使用结构体时省略 struct 这个关键字呢?可以 按照如下方法定义结构体。例如:
//第一个方式
struct A
{
int a;
char b;
};
typedef struct A A;//给 struct A 起个别名叫 A
//第二种方式
typedef struct B
{
char a;
int b;
}B; //给 struct B 起个别名叫 B
int main()
{
A aa = {10,'x'}; //直接使用 A
B bb = {'y',20}; //直接使用 B
return 0;
}
6、共用体,位段和枚举
共用体
共用体也称为联合体,使用关键字 union,它的所有成员共用同一段内存。例如:
typedef struct A
{
int a;
int b;
}A;
typedef union B
{
int a;
int b;
}B;
int main()
{
A aa = {10,20};
//B bb = {10,20};//错误,B 中所有成员共用同一段内存,不能同时赋值
B bb;
bb.a = 10;
bb.b = 20;
printf("%d,%d\n",aa.a,aa.b);
printf("%d,%d\n",bb.a,bb.b);
return 0;
}
注意在上图中 bb.a = 10,但是在输出结果时却是 20,为什么会这样呢?见下 面的内存图:
原因还是因为共用体所有成员共用同一段内存,如上图在联合体 union B 中 a 和 b 的内存相同。第 19 行代码 bb.b = 20 时会将前面 bb.a 的值也修改成 20。
总而言之使用联合体的准则是:联合体定义的一个变量一定只使用其中的一 个成员。
位段
位段和结构体非常的类似,它成员表示一个或者多个位。由于不同平台,它的 定义有差异(C 标准没有详细定义),所以它不可移植,使用起来不如位运算方便, 在这不做过多介绍,大家只需要认识并知道它的大小即可。
struct A
{
int a;
int b;
};
struct B //定义位段
{
int a:10;//表示 a 占用 10 个位
int b:20;//表示 b 占用 20 个位
};
int main()
{
printf("sizeof(struct A)=%d\n",sizeof(struct A));
printf("sizeof(struct B)=%d\n",sizeof(struct B));
return 0;
}
位段的大小一定是 sizeof(int)的倍数,上例中位段 B 为 10+20 共 30 位,最 小为 4 字节(32 位)。
枚举
枚举:使用关键字 enum,把可能的值全部列举出来,变量的取值只能在列举 的值范围内。 例如枚举星期类型:
enum Weekday{sun,mon,tue,wed,thu,fri,sat};
int main()
{
enum Weekday day1; //定义变量,未初始化
enum Weekday day2 = sun; //初始化为星期天
enum Weekday day3 = mon; //初始化为星期一
return 0;
}