在 C 语言中,结构体(struct
)是一种用户自定义的数据类型,它允许你将不同类型的数据成员组合在一起,方便对相关数据进行统一管理和操作。以下是关于结构体的定义和使用的详细介绍:
结构体的定义
基本语法格式
c
struct 结构体名 {
数据类型 成员1;
数据类型 成员2;
//...
数据类型 成员n;
};
例如,定义一个表示学生信息的结构体:
c
struct Student {
char name[20]; // 学生姓名,字符数组类型,用于存储字符串形式的姓名
int age; // 学生年龄,整型
float score; // 学生成绩,单精度浮点型
};
带 typedef 的定义(方便使用结构体类型)
除了上述基本定义方式外,常使用 typedef
关键字来给结构体类型定义一个别名,这样在后续代码中使用结构体类型时会更加简洁方便。语法格式如下:
c
typedef struct 结构体名 {
数据类型 成员1;
数据类型 成员2;
//...
数据类型 成员n;
} 结构体别名;
使用 typedef
重新定义上述 Student
结构体的示例:
c
typedef struct Student {
char name[20];
int age;
float score;
} Student;
这样,后续在代码中就可以直接使用 Student
来声明变量,而不需要写 struct Student
这么长的类型名了。
结构体变量的声明和初始化
声明结构体变量
在定义好结构体类型后,可以声明该结构体类型的变量,有以下几种声明方式:
- 先定义结构体类型,再声明变量:
例如,基于前面定义的struct Student
结构体类型声明变量:
c
struct Student student1, student2;
如果是使用了 typedef
定义的结构体别名,声明变量就更简洁了,比如:
c
Student student3, student4;
- 在定义结构体类型的同时声明变量:
c
struct Student {
char name[20];
int age;
float score;
} student5, student6;
初始化结构体变量
- 顺序初始化:
按照结构体成员定义的顺序依次给成员赋初值,例如:
c
Student student7 = {"张三", 18, 90.5};
这里 "张三"
赋值给 name
成员,18
赋值给 age
成员,90.5
赋值给 score
成员。
- 指定成员初始化(C99 及之后支持):
可以指定具体的成员进行初始化,顺序就不那么严格了,例如:
c
Student student8 = {.score = 85.0,.age = 19,.name = "李四"};
结构体成员的访问
使用 .
运算符(针对普通结构体变量)
通过结构体变量名加上 .
运算符,再跟上成员名,就可以访问结构体变量中的各个成员了,并且可以对成员进行赋值、读取等操作。例如:
c
Student student9;
strcpy(student9.name, "王五"); // 给 name 成员赋值
student9.age = 20; // 给 age 成员赋值
student9.score = 88.0; // 给 score 成员赋值
printf("学生姓名:%s,年龄:%d,成绩:%f\n", student9.name, student9.age, student9.score);
使用 ->
运算符(针对结构体指针变量)
如果定义的是结构体指针变量,要访问其指向的结构体的成员时,就需要使用 ->
运算符了。例如:
c
Student student10 = {"赵六", 21, 92.0};
Student *p_student = &student10;
printf("学生姓名:%s,年龄:%d,成绩:%f\n", p_student->name, p_student->age, p_student->score);
在这里,p_student
是指向 Student
结构体的指针,通过 p_student->name
等形式就能访问到对应的成员了。
结构体数组
定义结构体数组
和普通数组类似,只是数组元素的类型是结构体类型,例如:
c
Student classStudents[3]; // 定义一个包含3个 Student 结构体元素的数组
初始化结构体数组
- 顺序初始化:
c
Student classStudents[3] = {
{"孙七", 17, 80.0},
{"周八", 18, 85.0},
{"吴九", 19, 90.0}
};
- 部分初始化(未初始化的成员会被赋予默认值,数值类型默认是 0,字符数组默认是空字符串等):
c
Student classStudents[3] = {{"郑十", 20, 88.0}};
这里只初始化了第一个元素,后面两个元素的成员会取默认值。
访问结构体数组元素的成员
同样使用 .
运算符或者 ->
运算符(如果是指针指向结构体数组元素的情况)来访问成员,例如:
c
for (int i = 0; i < 3; i++) {
printf("第 %d 个学生姓名:%s,年龄:%d,成绩:%f\n", i + 1, classStudents[i].name, classStudents[i].age, classStudents[i].score);
}
结构体作为函数参数和返回值
结构体作为函数参数
可以将结构体变量或者结构体指针作为函数的参数传递给函数,它们各有特点:
- 传递结构体变量(值传递):
在函数调用时,会将实参结构体变量的值复制一份传递给形参,函数内部对形参结构体的修改不会影响到实参结构体。例如:
c
void printStudentInfo(Student s) {
printf("姓名:%s,年龄:%d,成绩:%f\n", s.name, s.age, s.score);
}
Student student11 = {"陈十一", 22, 95.0};
printStudentInfo(student11);
- 传递结构体指针(地址传递):
传递结构体指针时,函数接收的是结构体变量的地址,通过这个地址可以直接访问和修改原结构体变量的成员,效率更高,尤其是对于大型结构体,避免了大量数据的复制。例如
c
void modifyStudentAge(Student *p_s) {
p_s->age++;
}
Student student12 = {"刘十二", 20, 88.0};
modifyStudentAge(&student12);
printf("修改后年龄:%d\n", student12.age);
结构体作为函数返回值
函数也可以返回结构体类型的数据,例如
c
Student createStudent(const char *name, int age, float score) {
Student s;
strcpy(s.name, name);
s.age = age;
s.score = score;
return s;
}
Student newStudent = createStudent("杨十三", 19, 90.0);
printf("新学生信息:姓名:%s,年龄:%d,成绩:%f\n", newStudent.name, newStudent.age, newStudent.score);
不过要注意,返回结构体时,如果结构体比较大,会涉及到数据复制等开销,在一些性能要求高的场景下,可以考虑返回结构体指针并合理管理内存(比如通过动态分配内存来创建结构体对象,使用完后记得释放内存等)。