C语言(五)-结构体
C语言(五)-结构体
1. 结构体定义
在编程的时候需要将不同的类型的数据组合成为一个整体, 以便于引用。例如,一名学生有学号、姓名、性别、年龄、地址等属性,如果针对学生的学号、姓名、年龄等都单独定义一个变量,那么在有多名学生时,变量就难以分清。为此,C语言提供结构体来管理不同类型的数据组合。
语法:
struct 结构体名 { 结构体成员列表 };
示例:
// 结构体定义;
struct student{
char name[20];
int age;
}; // 结构体类型声明, 注意最后一定要加分号;
通过结构体创建变量的方式有三种:
struct 结构体名 变量名;
struct 结构体名 变量名 = {成员1值,成员2值};
// 定义结构体时顺便创建变量, 定义语句后的变量名;
struct 结构体名 {} 变量名;
-
方式一
该方式使用较少,主要使用的是方式二;
void test02(){ struct student s2 ; s2.id = 2; s2.score = 90.0; s2.age = 18; // s2.name[64] = "Jason"; 数组赋值出错; // 这里可以使用 strcpy 进行赋值,在方式三种查看 printf("id=%d\n", s2.id); // printf("name=%s\n", s2.name); printf("score=%f\n", s2.score); printf("age=%d\n", s2.age); } int main() { print_msg(); test02(); return 0; }
-
方式二
void test01(){ // 通过结构体类型, 创建结构体变量 // 给结构体变量的时候需要按照顺序赋值; struct student s1 = {1, "Tom", 99.9, 18}; printf("id=%d\n", s1.id); printf("name=%s\n", s1.name); printf("score=%f\n", s1.score); printf("age=%d\n", s1.age); } int main() { print_msg(); test01(); return 0; }
-
方式三
#include <string.h> // 在定义结构体时候, 顺便创建结构体变量 struct student2 { int id; //学号 char name[64]; //姓名 float score; //分数 int age; //年龄 }s3; // s3 代表通过 struct student2 创建的结构体变量; void test03(){ s3.id = 2; // s3.name = "Jerry"; //error strcpy(s3.name, "Jerry"); // 使用 strcpy 赋值; s3.score = 80; s3.age = 19; printf("id=%d\n", s3.id); printf("name=%s\n", s3.name); printf("score=%f\n", s3.score); printf("age=%d\n", s3.age); } int main() { print_msg(); test03(); return 0; }
总结:
结构体类型声明要放在 main 函数之前,这样 main 函数中才可以使用这个结构体,工作中往往把结构体声明放在头文件中。注意,结构体类型声明最后一定要加分号,否则会编译不通。另外,定义结构体变量时,使用struct student
来定义,不能只有struct
或student
,否则也会编译不通。
结构体的初始化只能在一开始定义,
// 已经定义
struct student s2;
// 不能够再进行结构体的的整体赋值
s2 = {1, "Jason", 60, 18}// error
如果结构体变量已经定义,那么只能对它的每个成员单独赋值,如:
s2.age = 18; // 单独赋值;
总结1:定义结构体时的关键字是struct,不可省略
总结2:创建结构体变量时,关键字 struct 可以省略
总结3:结构体变量利用操作符
.
访问成员
2. 结构体数组
作用:将自定义的结构体放入到数组中方便维护
语法:
struct 结构体名 数组名[元素个数] = { {} , {} , ... {} }
示例代码:
struct hero {
int id; //id号
char name[64]; //姓名
int height; //身高
int age; //年龄
};
void test04() {
struct hero arr[5] = {
{1, "刘备", 160, 30},
{2, "张飞", 180, 31},
{3, "关羽", 170, 32},
{4, "赵云", 188, 34},
{5, "吕布", 196, 33} //最后一行的 ',' 可以省略
};
// 计算数组的长度;
int num = sizeof(arr) / sizeof(struct hero);
for (int i = 0; i < num; i++) {
printf("id = %d name = %s height = %d age = %d\n", arr[i].id, arr[i].name, arr[i].height, arr[i].age);
}
//求年龄的平均值
int sum = 0;
for (int i = 0; i < num; i++) {
sum += arr[i].age;
}
printf("age mean :%d\n", sum / num);
}
int main() {
print_msg();
test04();
return 0;
}
3. 结构体对齐
结构体本身的对齐规则有好几条,比较难记,主要有一条:结构体的大小必须是其最大成员数的整数倍!
struct student_type1{
double score;
short age;
};
struct student_type2{
double score;
int height;
short age;
};
struct student_type3{
int height;
char sex;
short age;
};
void test05(){
struct student_type1 s1;
struct student_type2 s2;
struct student_type3 s3;
printf("s1 size=%d\n", sizeof(s1));
printf("s2 size=%d\n", sizeof(s2));
printf("s3 size=%d\n", sizeof(s3));
}
int main() {
print_msg();
test05();
return 0;
}
4. 结构体指针
一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设置一个指针变量,用它指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素,从而能够通过结构体指针快速访问结构体内的每个成员。
作用:通过指针访问结构体中的成员
- 利用操作符
->
可以通过结构体指针访问结构体属性
struct student3{
int id;
char name[64];
float score;
};
void test06(){
// 定义结构体变量
struct student3 s1 = { 1, "Tom", 100 };
// 定义结构体变量的指针;
struct student* p = &s1;
printf("id =%d name = %s score =%.2f\n", p->id,p->name,p->score);
printf("id =%d name = %s score =%.2f\n", s1.id,s1.name,s1.score);
printf("id = %d name = %s score = %.2f\n", (&s1)->id, (&s1)->name, (&s1)->score);
printf("id = %d name = %s score = %.2f\n", (*p).id, (*p).name, (*p).score);
}
int main() {
print_msg();
test06();
return 0;
}
总结:结构体指针可以通过 -> 操作符 来访问结构体中的成员
5. 结构体嵌套结构体
作用: 结构体中的成员可以是另一个结构体
例如:每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体
示例:
//学生结构体定义
struct student4
{
//成员列表
char name[64]; //姓名
int age; //年龄
int score; //分数
};
//教师结构体定义
struct teacher
{
//成员列表
int id; //职工编号
char name[64]; //教师姓名
int age; //教师年龄
// 结构体嵌套;
struct student4 stu; //子结构体 学生
};
void test07() {
// 定义结构体变量;
struct teacher t1;
t1.id = 10000;
strcpy(t1.name, "老王");
t1.age = 40;
// 为嵌套结构体赋值;
strcpy(t1.stu.name, "张三");
t1.stu.age = 18;
t1.stu.score = 100;
printf("教师的职工编号: %d 姓名:%s 年龄:%d\n", t1.id, t1.name, t1.age);
printf("辅导学员的姓名:%s 年龄: %d 分数:%d\n", t1.stu.name, t1.stu.age, t1.stu.score);
system("pause");
}
int main() {
print_msg();
test07();
return 0;
代码输出中包含中文字符,因此使用 VS 进行运行代码;
6. typedef
前面定义结构体变量时使用的语句是struct student s
,以这种方式来定义结构体变量有些麻烦,即每次都需要写struct student
,那么有没有简单一些的定义方式呢?答案是肯定的,可以选择使用typedef声明新的类型名来代替已有的类型名。
typedef struct student5 {
int num;
char name[20];
char sex;
} stu, *p_stu;
typedef int INTEGER; // 重命名;
void test08(){
// 省去了 struct student5
stu s = {1001, "wangle", 'M'};
p_stu p; // 省去了 struct student5 *
INTEGER i =10;
p=&s; // 为指针赋值;
printf("i=%d, p->num=%d", i, p->num);
}
int main() {
print_msg();
test08();
return 0;
}
使用stu
定义结构体变量和使用struct student5
定义结构体变量时等价的;使用INTEGER定义变量 i 和使用 int 定义变量 i 是等价的;pstu 等价于 struct student*
,所以 p 是结构体指针变量。
7. 结构体函数参数
作用:将结构体作为参数向函数中传递;
传递方式有两种:
- 值传递
- 地址传递
示例:
//
// Created by 86152 on 2024/8/9.
//
//学生结构体定义
#include <stdio.h>
#include <stdlib.h>
struct student {
//成员列表
char name[64]; //姓名
int age; //年龄
int score; //分数
};
void print_student(struct student stu) {
stu.age = 28;
printf("子函数中 姓名:%s 年龄: %d 分数: %d\n", stu.name, stu.age, stu.score);
}
// 使用指针, 传递地址;
void print_student2(struct student *stu) {
stu->age = 28;
printf("子函数中 姓名:%s 年龄: %d 分数: %d\n", stu->name, stu->age, stu->score);
}
void test09() {
struct student stu = {"Tom", 18, 100};
//值传递
print_student(stu);
printf("主函数中 姓名:%s 年龄: %d 分数: %d\n", stu.name, stu.age, stu.score);
printf("------------------------------\n");
//地址传递
print_student2(&stu);
printf("主函数中 姓名: %s 年龄: %d 分数: %d\n", stu.name, stu.age, stu.score);
system("pause");
}
int main() {
test09();
return 0;
}
8. 结构体中 const
作用:用const来防止误操作;
示例:
//
// Created by 86152 on 2024/8/9.
//
#include <stdio.h>
#include <stdlib.h>
//学生结构体定义
struct student {
//成员列表
char name[64]; //姓名
int age; //年龄
int score; //分数
};
//const使用场景
void printStudent(const struct student *stu) //加const防止函数体中的误操作
{
// stu->age = 100; //操作失败,因为加了const修饰
printf("姓名:%s 年龄:%d 分数: %d\n", stu->name, stu->age, stu->score);
}
int main() {
struct student stu = {"Tom", 18, 100};
printStudent(&stu);
system("pause");
return 0;
}
9. 结构体案例
案例描述:
设计一个英雄的结构体,包括成员姓名,年龄,性别;创建结构体数组,数组中存放5名英雄。
通过冒泡排序的算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果。
五名英雄信息如下:
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"},
示例
#include "func.h"
// 创建英雄结构体;
struct hero
{
char name[64];
int age;
char sex[32];
};
void bubble_sort_hero(struct hero arr[], int len) {
// 设置英雄冒泡的算法;
// 循环数组
for (int i = 0; i < len-1; i++) {
for (int j = 0; j < len - 1; j++) {
if (arr[j].age > arr[j + 1].age) {
struct hero temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
void print_hero_arr(const struct hero arr[], int len) {
// 定义打印英雄的数组;
for (int i = 0; i < len - 1; i++) {
printf("姓名:%s 年龄:%d 性别:%s\n", arr[i].name, arr[i].age, arr[i].sex);
}
}
int main() {
print_msg();
struct hero arr[5] =
{
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"},
};
int arr_len = sizeof(arr) / sizeof(struct hero);
bubble_sort_hero(arr,arr_len);
print_hero_arr(arr, arr_len);
return 0;
}
存在中文,使用 VS 进行编程;
度过大难,终有大成!
继续努力,终成大器!