一:C语言结构体
1.1:概述
前面的章节学习了数组,他是一组具有相同类型的数据的集合。但在实际的编程过程中,我们往往还需要一组类型不同的数据,例如对于学生信息登记表,姓名为字符串,学号为整数,年龄为整数,所在的学习小组为字符,成绩为小数,因为数据类型不同,显然不能用一个数组来存放。
在C语言中,可以使用结构体来存放一组不同类型的数据。结构体的定义形式为:
struct 结构体名{
结构体所包含的变量或数组
};
结构体是一种集合,里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称之为结构体的成员。
struct stu{
char *name; // 姓名
int num; // 学号
int age; // 年龄
char group; // 所在学习小组
float score; // 成绩
};
注意大括号后面的分号;不能少,这是一条完整的语句。
像int、float、char等是由C语言本身提供的数据类型,不能再进行分拆,我们称之为基本数据类型;而结构体可以包含多个基本类型的数据,也可以包含其他的结构体,我们将它称为复杂数据类型或构造数据类型。
1.2:结构体变量
既然结构体是一种数据类型,那么就可以用它来定义变量。例如;
struct stu stu1, stu2;
定义了两个变量 stu1 和 stu2,它们都是 stu 类型,都由 5 个成员组成。注意关键字struct不能少。
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在学习小组
float score; //成绩
} stu1, stu2;
1.3:成员的获取与赋值
结构体和数组类似,也是一组数据的集合,整体使用没有太大的意义。数组使用下标[]获取单个元素,结构体使用点号.获取单个成员。
格式为:结构体变量名.成员名;
实例:
#include <stdio.h>
int main(){
struct{
char *name;
int num;
int age;
char group;
float score;
}stu1;
// 给结构体成员赋值
stu1.name = "tom";
stu1.num = 12;
stu1.age = 22;
stu1.group = 'A';
stu1.score = 123.5;
// 读取结构体成员的值
printf("%s 的学号是:%d, 年龄是 %d, 在%c组, 今年的成绩是%.1f \n", stu1.name, stu1.num, stu1.age, stu1.group,stu1.score);
}
结果:
┌──(root💀kali)-[~/Desktop/c_test]
└─# ./jiegoutichengyuan
tom 的学号是:12, 年龄是 22, 在A组, 今年的成绩是123.5
除了可以对成员进行逐一赋值,也可以在定义的时候整体赋值,例如;
struct{
char *name;
int num;
int age;
char group;
float score;
} stu1, stu2 = {"tom", 12, 22, 'A', 123.5};
需要注意的是,结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,需要内存空间来存储。
二:C语言结构体数组
所谓结构体数组,是指数组中的每个元素都是一个结构体。在实际应用中,结构体数组常被用来表示一个拥有相同数据结构的群体,比如一个班的学生,一个车间的职工等。
实例:
struct stu{
char *name; // 姓名
int num; // 学号
int age; // 年龄
char group; // 所在小组
float score; // 成绩
}class[5]; // 表示一个班级有5个学生
结构体数组在定义的同时也可以初始化,例如;
#include <stdio.h>
struct stu{
char *name; // 姓名
int num; // 学号
int age; // 年龄
char group; // 所在小组
float score; // 成绩
}class[5] = {
{"Li ping", 5, 18, 'C', 145.0},
{"Zhang ping", 4, 19, 'A', 130.5},
{"He fang", 1, 18, 'A', 148.5},
{"Cheng ling", 2, 17, 'F', 139.0},
{"Wang ming", 3, 17, 'B', 144.5}
};
获取Wang ming的成绩:class[4].score;
修改Li ping的学习小组:class[0].group = 'B';
三:C语言结构体和指针
3.1:定义结构体
指针也可以指向一个结构体,定义的形式一般为:struct 结构体名 *变量名;
实例:
下面是一个定义结构体指针的实例:
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
} stu1 = { "Tom", 12, 18, 'A', 136.5 };
//结构体指针
struct stu *pstu = &stu1;
也可以在定义结构体的同时定义结构体指针:
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
} stu1 = { "Tom", 12, 18, 'A', 136.5 }, *pstu = &stu1;
注意,结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加&,所以给 pstu 赋值只能写作:struct stu *pstu = &stu1;
而不能写作:struct stu *pstu = stu1;
还应该注意,结构体和结构体变量是两个不同的概念:结构体是一种数据类型,是一种创建变量的模板,编译器不会为它分配内存空间,就像 int、float、char 这些关键字本身不占用内存一样;结构体变量才包含实实在在的数据,才需要内存来存储。
下面的写法是错误的,不可能去取一个结构体名的地址,也不能将它赋值给其他变量:
struct stu *pstu = &stu;
struct stu *pstu = stu;
3.2:获取结构体成员
两种形式(等效,通常采用后者,更加直观):
(*pointer).memberName
.的优先级高于*,并且()也不能省略,若是省略则等价于:*(pointer.memberName)
pointer->memberName
有了->,就可以通过结构体指针直接去的结构体成员,这也是->在C语言中的唯一用途
看下例子:
实例1:
#include <stdio.h>
int main(){
struct{
char *name;
int num;
int age;
char group;
float score;
}stu1 = {"tom", 12, 18, 'A', 136.5}, *pstu = &stu1;
// 读取结构体成员你的值
printf("%s的学号是%d, 年龄是%d, 在%c组, 今年的成绩是%.1f \n", (*pstu).name, (*pstu).num, (*pstu).age, (*pstu).group, (*pstu).score);
printf("%s的学号是%d, 年龄是%d, 在%c组, 今年的成绩是%.1f \n", pstu->name, pstu->num, pstu->age, pstu->group, pstu->score);
}
结果:
┌──(root💀kali)-[~/Desktop/c_test]
└─# ./jiegoutizhizhen
tom的学号是12, 年龄是18, 在A组, 今年的成绩是136.5
tom的学号是12, 年龄是18, 在A组, 今年的成绩是136.5
实例2:
#include <stdio.h>
struct stu{
char *name; // 姓名
int num; // 学号
int age; // 年龄
char group; // 所在小组
float score; // 成绩
}stus[] = {
{"Zhou ping", 5, 18, 'C', 145.0},
{"Zhang ping", 4, 19, 'A', 130.5},
{"Liu fang", 1, 18, 'A', 148.5},
{"Cheng ling", 2, 17, 'F', 139.0},
{"Wang ming", 3, 17, 'B', 144.5}
},*ps;
int main(){
// 求数组长度
int len = sizeof(stus) / sizeof(struct stu);
printf("Name\t\tNum\tAge\tGroup\tScore\t\n");
for(ps=stus; ps<stus+len; ps++){
printf("%s\t%d\t%d\t%c\t%.1f \n", ps->name, ps->num, ps->age, ps->group, ps->score);
}
return 0;
}
结果:
┌──(root💀kali)-[~/Desktop/c_test]
└─# ./jiegoutishuzuzhizhen
Name Num Age Group Score
Zhou ping 5 18 C 145.0
Zhang ping 4 19 A 130.5
Liu fang 1 18 A 148.5
Cheng ling 2 17 F 139.0
Wang ming 3 17 B 144.5
四:C语言共用体
结构体(struct)是一种构造类型或复杂类型,可以包含多个类型不同的成员。在C语言中还有另一种和结构体非常类似的语法,叫做共用体(union)。
定义格式为:
union 共用体名{
成员列表
};
区别:
-
结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
-
结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。
-
共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
共用体也是一种自定义类型,可以通过它来创建变量,例如:
union data{
int n;
char ch;
double f;
};
union data a, b, c;
上面是先定义共用体,再创建变量,也可以在定义共用体的同时创建变量:
union data{
int n;
char ch;
double f;
} a, b, c;
共用体data中,成员f占用的内存最多,为8个字节,所以data类型的变量(也就是a,b,c)也占用8个字节的内存。
实例:
#include <stdio.h>
union data{
int n;
char ch;
short m;
};
int main(){
union data a;
printf("%d, %d\n", sizeof(a), sizeof(union data) );
a.n = 0x40;
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
a.ch = '9';
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
a.m = 0x2059;
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
a.n = 0x3E25AD54;
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
return 0;
}
结果:
┌──(root💀kali)-[~/Desktop/c_test]
└─# ./gongyongti
4, 4
40, @, 40
39, 9, 39
2059, Y, 2059
3E25AD54, T, AD54
这段代码不但验证了共用体的长度,还说明共用体成员之间会相互影响,修改一个成员的值会影响其他成员。