1、结构体的定义
结构体是一种用户自定义的数据类型,它允许存储不同类型的数据项。
结构体由一系列具有相同类型或不同类型的数据成员构成,可以像基本数据类型一样被声明和使用。
其中,结构体名为自定义的标识符,可以是任何合法的标识符;成员可以是基本数据类型(例如 int、float、char 等),也可以是其他结构体类型、指针类型等。
例如,我们可以定义一个表示学生信息的结构体,包括姓名、年龄和分数。
struct Student { char name[20]; int age; double score; };
我们可以使用这个结构体来定义一个 Student 类型的变量
struct Student stu;// 声明一个名为 stu 的 Student 类型的结构体变量
我们也可以使用 typedef 来定义一个结构体类型的别名(对结构体进行重命名)
typedef struct Student
{
char name[20];
int age;
double score;
} s1;//此时s1就相当于是struct Student
2、结构体的访问
通过结构体变量名和成员名使用“.”操作符进行访问,例如:
struct Student s1;
s1.score = 94;
strcpy(s1.name, "lzy");
s1.age = 20;
通过指向结构体的指针使用“->”操作符进行访问,例如:
struct Student* ps1;
ps1 = &s1;
ps1->score = 94;
strcpy(ps1->name, "lzy");
ps1->age = 20;
两种方法的具体应用
#include <stdio.h>
// 定义结构体类型
struct student
{
char name[20];
int age;
double score;
};
int main()
{
// 定义结构体变量并初始化
struct student s1 = { "lisi", 18, 94};
// 定义结构体指针变量并赋值
struct student* ps = &s1;
// 使用点操作符访问结构体变量的成员
printf("%s, %d\n", s1.name, s1.age, s1.score);
// 使用箭头操作符访问结构体指针变量的成员
printf("%s, %d\n", ps->name, ps->age, ps->score);
return 0;
}
3、结构体的自引用
结构体的自引用指的是结构体中包含指向本身类型的指针成员。
这种结构体的定义方式可以让我们在一个结构体中嵌套另一个相同类型的结构体,从而实现对数据的更加复杂的描述。struct Node { int data; struct Node* next; }; //通过这种方式,我们就可以使用链表来存储一系列数据了。
错误的自引用方式
struct Node { int data; struct Node next; };
在这段代码中,结构体 Node 的成员 next 的类型是 struct Node(即 Node 结构体本身),这会导致结构体无限递归地包含自身,最终导致无限扩大结构体的大小,从而可能导致程序崩溃。
使用typedef时的错误的自引用方式
typedef struct { int data; Node* next; }Node;
这段代码中的 Node 在定义时是没有被声明的,但在结构体定义时已经使用,且定义时的 Node 是指向自身的指针,这就需要先声明一个 Node 类型的结构体再定义它
修正后typedef struct Node { int data; struct Node* next; }Node;
4、结构体的初始化
结构体变量可以在定义的同时进行初始化,或者在定义之后通过赋值或memset()函数进行初始化。
①定义的同时进行初始化(直接赋值)
struct Student s1 { char name[20]; int age; double score; }s1 = { 张三,21,91 };
②逐个赋值
struct Student s2; s2.age = 19; // 赋值年龄 strcpy(s2.name, "Jack"); // 结构体变量中的字符串类型需要使用strcpy()函数进行赋值 s2.score = 90; // 赋值分数
③使用memset()函数
struct Student s3; memset(&s3, 0, sizeof(s3)); // 使用memset()函数将整个结构体变量置零
5、结构体传参
结构体传参的有两种方式,分别是通过传递结构体和传递指针的方式传递结构体变量。
例如struct Student { char name[20]; int age; }; struct Student s1 = { "wangwu",25 }; void print1(struct Student s1) { printf("%d\n", s1.name,s1.age); } void print2(struct Student* ps1) { printf("%d\n", ps1->name,ps1->age); } int main() { print1(s1); //传递结构体 print2(&s1); //传递指针 return 0; }
如果使用传值方式将一个结构体传递给函数,那么这个结构体就需要在内存中复制一份,这样会占用较多的时间和硬件资源。
而使用传指针的方式来传递结构体参数时,只需要传递结构体的地址,这不仅减少了在内存中复制结构体所需的时间和资源,还可以避免由于结构体复制造成的内存泄漏问题。
所以,结构体传参首选传地址的方式。