在 C 语言中,结构体是非常重要的一种自定义数据类型。它可以把多个不同类型的数据组合到一起,用来描述一个完整的"对象"。比如学生、员工、书本等信息,都很适合用结构体来表示。
本文将从 结构体变量 和 结构体指针 两个角度出发,系统梳理它们的定义、使用方法、区别、函数传参方式以及常见易错点,帮助你真正搞懂结构体相关知识。
一、什么是结构体
结构体(struct)是一种自定义数据类型,它允许我们把多个不同类型的数据成员组合在一起。
例如,定义一个学生信息结构体:
c
struct Student {
char name[20];
int age;
float score;
};
这个结构体中包含了:
name:姓名age:年龄score:成绩
通过结构体,我们可以更方便地管理一组相关数据。
二、结构体变量
1. 结构体变量的定义
结构体变量就是结构体类型的普通变量。
c
struct Student s1;
这表示定义了一个 Student 类型的结构体变量 s1。
2. 定义方式
方式一:先定义结构体类型,再定义变量
c
struct Student {
char name[20];
int age;
float score;
};
struct Student s1;
方式二:定义结构体类型时同时定义变量
c
struct Student {
char name[20];
int age;
float score;
} s1, s2;
方式三:使用 typedef 简化写法
c
typedef struct Student {
char name[20];
int age;
float score;
} Student;
Student s1;
这种方式更简洁,后续定义变量时可以直接写 Student s1;。
三、结构体变量的成员访问
结构体变量通过 点号 . 来访问成员。
c
s1.age = 18;
s1.score = 95.5;
如果是字符串数组成员,不能直接赋值,需要使用字符串处理函数:
c
strcpy(s1.name, "Tom");
示例代码
c
#include <stdio.h>
#include <string.h>
struct Student {
char name[20];
int age;
float score;
};
int main() {
struct Student s1;
strcpy(s1.name, "Tom");
s1.age = 18;
s1.score = 95.5;
printf("name = %s\n", s1.name);
printf("age = %d\n", s1.age);
printf("score = %.1f\n", s1.score);
return 0;
}
四、结构体指针
1. 什么是结构体指针
结构体指针是指向结构体变量的指针。
c
struct Student *p;
这里 p 是一个指向 struct Student 类型的指针。
2. 初始化结构体指针
结构体指针必须指向有效内存后才能使用,常见方式有两种:
方式一:指向已有结构体变量
c
struct Student s1 = {"Tom", 18, 95.5};
struct Student *p = &s1;
方式二:动态分配内存
c
struct Student *p = (struct Student *)malloc(sizeof(struct Student));
使用完后要记得释放内存:
c
free(p);
p = NULL;
五、结构体指针的成员访问
结构体指针通过 箭头 -> 访问成员。
c
p->age = 20;
p->score = 88.5;
strcpy(p->name, "Lucy");
它等价于:
c
(*p).age = 20;
(*p).score = 88.5;
strcpy((*p).name, "Lucy");
一般推荐直接使用 ->,更简洁可读。
示例代码
c
#include <stdio.h>
#include <string.h>
struct Student {
char name[20];
int age;
float score;
};
int main() {
struct Student s1 = {"Tom", 18, 95.5};
struct Student *p = &s1;
printf("name = %s\n", p->name);
printf("age = %d\n", p->age);
printf("score = %.1f\n", p->score);
return 0;
}
六、结构体变量和结构体指针的区别
| 对比项 | 结构体变量 | 结构体指针 |
|---|---|---|
| 保存内容 | 结构体数据本身 | 结构体地址 |
| 成员访问 | . |
-> |
| 内存占用 | 占用整个结构体大小 | 只占用指针大小 |
| 传参方式 | 值传递,复制整个结构体 | 传地址,效率更高 |
| 常见用途 | 普通数据存储 | 函数参数、动态内存、数组操作 |
理解方式
- 结构体变量:像一个"实体对象"
- 结构体指针:像一个"指向对象的地址"
七、结构体作为函数参数
结构体作为函数参数有两种常见方式。
1. 传结构体变量
c
void printStudent(struct Student s) {
printf("%s %d %.1f\n", s.name, s.age, s.score);
}
这种方式会复制一份结构体,结构体较大时效率不高。
2. 传结构体指针
c
void printStudent(struct Student *p) {
printf("%s %d %.1f\n", p->name, p->age, p->score);
}
这种方式更常用,既高效,又可以修改原结构体内容。
示例:通过指针修改结构体内容
c
#include <stdio.h>
#include <string.h>
struct Student {
char name[20];
int age;
float score;
};
void updateStudent(struct Student *p) {
strcpy(p->name, "Alice");
p->age = 20;
p->score = 99.0;
}
int main() {
struct Student s1 = {"Tom", 18, 95.5};
updateStudent(&s1);
printf("%s %d %.1f\n", s1.name, s1.age, s1.score);
return 0;
}
八、结构体数组与结构体指针
结构体数组是多个结构体变量组成的数组。
c
struct Student arr[3];
访问方式:
c
arr[0].age = 18;
arr[1].age = 19;
如果用指针指向数组首元素:
c
struct Student *p = arr;
则可以这样访问:
c
p->age
(p + 1)->age
示例代码
c
#include <stdio.h>
struct Student {
char name[20];
int age;
float score;
};
int main() {
struct Student arr[2] = {
{"Tom", 18, 95.5},
{"Lucy", 20, 88.8}
};
struct Student *p = arr;
printf("%s %d %.1f\n", p->name, p->age, p->score);
printf("%s %d %.1f\n", (p + 1)->name, (p + 1)->age, (p + 1)->score);
return 0;
}
九、常见易错点总结
1. 结构体变量不能用 ->
错误写法:
c
s1->age = 18;
正确写法:
c
s1.age = 18;
2. 结构体指针未初始化就使用
错误写法:
c
struct Student *p;
p->age = 18;
此时 p 没有指向有效内存,属于野指针,容易导致程序崩溃。
正确写法:
c
struct Student s1;
struct Student *p = &s1;
p->age = 18;
3. 字符数组成员不能直接赋值
错误写法:
c
s1.name = "Tom";
正确写法:
c
strcpy(s1.name, "Tom");
4. *p.age 写法错误
错误写法:
c
*p.age
正确写法:
c
(*p).age
或者更推荐:
c
p->age
5. 动态分配后忘记释放内存
c
struct Student *p = malloc(sizeof(struct Student));
使用结束后一定要释放:
c
free(p);
p = NULL;
6. sizeof 写错对象
错误写法:
c
malloc(sizeof(p));
sizeof(p) 只是指针大小,不是结构体大小。
正确写法:
c
malloc(sizeof(struct Student));
十、结构体指针的本质理解
p->age 实际上等价于:
c
(*p).age
也就是说:
p是指针*p表示取出指针指向的结构体(*p).age表示访问结构体成员age
因此,-> 其实只是语法上的简写。
十一、小结
结构体变量
- 保存的是结构体数据本身
- 使用
.访问成员 - 适合普通对象使用
结构体指针
- 保存的是结构体地址
- 使用
->访问成员 - 常用于函数传参、动态内存、数组遍历
十二、结语
结构体变量和结构体指针是 C 语言中非常基础但也非常重要的内容。
只要记住下面这几个核心点,基本就不会出错:
- 变量用
.,指针用-> - 变量存数据,指针存地址
- 字符数组不能直接赋值,要用
strcpy - 指针必须先指向有效内存再使用
- 函数传参时,传指针更高效
如果你正在学习 C 语言,建议多动手写几遍代码,尤其是"结构体变量"和"结构体指针"之间的转换,理解会更快。