2人参与 • 2026-09-21 • Java
c 语言中的结构体(struct)确实是一种将不同类型的相关数据组合成一个整体的自定义数据类型。它解决了基本数据类型无法描述复杂对象的问题,是 c 语言中实现数据封装和组织的核心工具。
在实际程序中,一个对象往往不只有一个属性。例如学生有姓名、年龄、性别和学号,坐标有横坐标和纵坐标,链表节点还需要保存数据和下一个节点的位置。如果把这些信息拆散成许多独立变量,代码很快会变得难以维护。
c 语言的结构体可以把多个相关的数据成员组合成一个新的类型。结构体的每个成员可以使用不同的数据类型,也可以是数组、指针,甚至另一个结构体。它既保留了 c 语言贴近内存的特点,又让数据表达更清晰。
结构体是一组值的集合,这些值称为成员变量。与数组要求所有元素类型相同不同,结构体中的成员可以完全不同:
struct student {
char name[20];
int age;
char sex[8];
char id[20];
};上面的声明描述了一个名为 struct student 的结构体类型。它定义了“学生应该包含哪些信息”,但仅有类型声明并不会自动创建一个具体的学生对象。
结构体声明最后的分号不能省略。结构体标签 student 只是类型名称的一部分,使用时需要写成 struct student:
struct student student;
如果希望像使用 int 一样省略 struct,可以配合 typedef:
typedef struct student {
char name[20];
int age;
char id[20];
} student;
student student;这里的 student 是结构体类型的别名,后续声明变量时会更加简洁。
结构体类型声明和变量定义可以分开,也可以写在一起:
struct point {
int x;
int y;
} point1;
struct point point2;point1 在声明结构体类型的同时被定义,point2 则是在类型已经存在后单独定义。两种方式得到的变量类型相同。
结构体变量可以在定义时初始化。初始化值按照成员声明的顺序排列:
struct student student = {"zhang san", 20, "m", "s001"};
也可以使用指定成员初始化,让代码更直观,并避免依赖成员顺序:
struct student student = {
.name = "zhang san",
.age = 20,
.sex = "m",
.id = "s001"
};
未提供初始值的成员会被初始化为零值。对字符数组等成员进行字符串初始化时,要确保数组容量能够容纳字符串结尾的 \0。
结构体成员不仅可以是基本类型,还可以是多种复合类型:
struct example {
int count; // 标量成员
char title[32]; // 数组成员
int *value_ptr; // 指针成员
struct point position; // 另一个结构体成员
};
这种组合能力使结构体能够描述更真实的对象。例如链表节点可以同时保存一个整数、一个坐标和下一个节点的地址:
struct node {
int data;
struct point position;
struct node *next;
};
其中 next 是指向同类型结构体的指针。结构体不能直接包含一个自身类型的成员,否则对象大小会无限递归;但可以包含指向自身的指针,因为指针大小是确定的。
当手里有一个结构体变量时,使用点运算符 . 访问成员:
#include <stdio.h>
#include <string.h>
struct student {
char name[20];
int age;
};
int main(void)
{
struct student student;
strcpy(student.name, "zhang san");
student.age = 20;
printf("name = %s, age = %d\n", student.name, student.age);
return 0;
}student.name 表示 student 对象中的 name 成员,student.age 表示其中的 age 成员。数组成员不能直接用赋值运算符接收字符串,因此示例使用 strcpy 复制内容;在真实项目中还要注意目标数组的容量,避免越界。
如果手里保存的是结构体地址,通常使用箭头运算符 ->:
void print_student(const struct student *student)
{
printf("name = %s, age = %d\n", student->name, student->age);
}
student->name 等价于 (*student).name,只是箭头写法更简洁,也更容易阅读。注意括号不能省略:
(*student).name // 正确 *student.name // 含义不同,因为 . 的优先级更高
使用结构体指针前,应确认指针指向一个有效对象,必要时先判断它是否为 null。
结构体成员可以是另一个结构体,因此可以自然地表达层次关系:
struct point {
int x;
int y;
};
struct node {
int data;
struct point position;
struct node *next;
};初始化嵌套结构体时,可以按层次写出初始值:
struct node node = {
10,
{4, 5},
null
};
也可以使用指定成员初始化,使层次更明显:
struct node node = {
.data = 10,
.position = {.x = 4, .y = 5},
.next = null
};
访问嵌套成员时连续使用点运算符即可,例如 node.position.x。如果外层对象是指针,则可以写成 node_ptr->position.x。
结构体可以像普通变量一样作为函数参数:
struct record {
int data[1000];
int count;
};
void print_by_value(struct record record)
{
printf("%d\n", record.count);
}这种写法会把整个结构体复制一份传给函数。结构体较小时,复制成本通常不明显;但当结构体包含很大的数组或许多成员时,复制会增加参数传递的开销,而且函数内部修改的是副本,不会影响原对象。
更常见的方式是传递结构体地址:
void print_by_pointer(const struct record *record)
{
printf("%d\n", record->count);
}
int main(void)
{
struct record record = {{1, 2, 3, 4}, 4};
print_by_pointer(&record);
return 0;
}传递地址只需要复制一个指针,通常更节省开销;函数通过指针访问原对象,也可以在需要时修改它。如果函数只负责读取数据,建议加上 const:
void show_student(const struct student *student);
const 表明函数不会通过该指针修改结构体成员,既能表达意图,也能减少误操作。
如果确实需要让函数修改调用者的结构体,可以不使用 const:
void update_age(struct student *student, int age)
{
student->age = age;
}
调用时传入地址:
update_age(&student, 21);
结构体成员通常按照声明顺序排列,但编译器可能为了满足对齐要求,在成员之间插入填充字节。因此 sizeof(struct type) 不一定等于所有成员 sizeof 之和。
printf("%zu\n", sizeof(struct student));
在大多数业务代码中,不需要手动依赖具体布局;如果结构体用于文件格式、网络协议或硬件寄存器映射,则需要额外考虑对齐、字节序和编译器扩展,不能仅凭成员声明推断二进制格式。
良好的结构体设计还应做到:成员名称清晰、字段职责集中、避免把无关数据硬塞到同一个类型中。结构体的价值不只是“把变量放在一起”,更是用一个有意义的类型表达一个完整对象。
const。., 访问结构体指针使用 ->。strcpy 等操作造成越界。null。结构体让 c 语言从“处理一组零散变量”变成“描述一个完整对象”。掌握类型声明、初始化、成员访问和指针传参之后,就可以进一步构建链表、树、哈希表以及各种更复杂的数据结构。
到此这篇关于c 语言结构体如何把相关数据组织成一个整体的文章就介绍到这了,更多相关c 语言结构体内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论