C语言结构体详解
系列文章目录
文章目录
1. 结构体的声明
结构体(Structure)是一种允许将多个不同类型的数据项组合成一个单一实体的复合数据类型。
1.1 结构的声明
结构体是通过关键字 struct
定义的。结构体的声明包括结构体的名称和它所包含的数据项(称为成员)。成员可以是任意类型,包括基本类型(如 int
、char
)、数组、指针,甚至包含其他结构体。
基本语法:
struct 结构体名称 {
数据类型 成员1名称;
数据类型 成员2名称;
...
};
代码示例:
假设需要定义一个结构体来存储一个学生的信息,包括姓名、年龄和分数。
struct Student {
char name[50];
int age;
float score;
};
在这个例子中,struct Student 是一个结构体,它有三个成员:
name 是一个字符数组,用于存储学生的名字。
age 是一个整型(int),用于存储学生的年龄。
score 是一个浮点型(float),用于存储学生的分数。
1.2 使用结构体
定义结构体之后可以创建该类型的变量,并使用点运算符(.
)来访问其成员。
访问和设置成员值:代码示例:
#include <stdio.h>
#include <string.h> // 用于 strcpy 函数
int main() {
struct Student stu1; //创建结构体变量
// 设置结构体成员的值
strcpy(stu1.name, "John Doe"); // 使用 strcpy 来赋值字符串
stu1.age = 20;
stu1.score = 92.5;
// 打印结构体成员的值
printf("Name: %s\n", stu1.name);
printf("Age: %d\n", stu1.age);
printf("Score: %.2f\n", stu1.score);
return 0;
}
1.3 结构体的高级用法
结构体指针
创建指向结构体的指针,并通过箭头运算符(->
)访问结构体的成员。
struct Student *ptr = &stu1;
printf("Name: %s\n", ptr->name);
结构体数组
结构体可以组成数组,用于存储多个结构体变量。
struct Student class[30]; // 创建一个包含30个学生的数组
嵌套结构体
结构体可以嵌套使用,即一个结构体的成员可以是另一个结构体。
struct Date {
int day;
int month;
int year;
};
struct Profile {
char name[50];
struct Date birthday;
};
1.4 代码示例
// 定义一个名为 Point 的结构体类型,包含两个整型成员 x 和 y
struct Point
{
int x;
int y;
} p1; // 在声明结构体类型的同时定义了一个名为 p1 的变量
// 定义一个结构体变量 p2,类型为 struct Point
struct Point p2;
// 定义并初始化结构体变量 p3,假设 x 和 y 在此上下文中已定义
struct Point p3 = {x, y};
// 定义一个名为 Stu 的结构体类型,包含一个字符数组 name 和一个整型 age
struct Stu
{
char name[15]; // 名字
int age; // 年龄
};
// 定义并初始化结构体变量 s
struct Stu s = {"zhangsan", 20}; // 用具体的值初始化 name 和 age
// 定义一个名为 Node 的结构体类型,包含一个整型 data,一个 Point 类型的结构体成员 p,和一个指向 Node 类型的指针 next
struct Node
{
int data;
struct Point p;
struct Node* next;
} n1 = {10, {4, 5}, NULL}; // 初始化,包括嵌套的 Point 结构体成员和 NULL 指针
// 定义并初始化另一个 Node 类型的结构体变量 n2
struct Node n2 = {20, {5, 6}, NULL}; // 类似地初始化
2. 结构体成员的访问
结构体成员的访问是通过结构体变量来实现的,使用点操作符(.
)或箭头操作符(->
)来访问结构体的成员。点操作符用于普通的结构体变量,而箭头操作符用于指向结构体的指针。下面详细解释这两种访问方式。
2.1 使用点操作符(.
)
当有一个结构体类型的变量时,可以使用点操作符来访问其任何成员。这是最直接的方式来访问结构体中的字段。
#include <stdio.h>
struct Person {
char name[100];
int age;
};
int main() {
struct Person person;
// 设置结构体成员的值
strcpy(person.name, "Alice");
person.age = 30;
// 访问结构体成员的值
printf("Name: %s\n", person.name);
printf("Age: %d\n", person.age);
return 0;
}
在这个例子中创建了一个 Person 结构体,它有两个成员:name 和 age。通过结构体变量 person 和点操作符,可以设置和获取这些成员的值。
2.2 使用箭头操作符(->
)
当有一个指向结构体的指针时,可以使用箭头操作符来访问指针指向的结构体的成员。这是处理结构体指针时的标准方法。
#include <stdio.h>
struct Person {
char name[100];
int age;
};
int main() {
struct Person person;
struct Person *ptr = &person;
// 使用指针设置结构体成员的值
strcpy(ptr->name, "Bob");
ptr->age = 25;
// 使用指针访问结构体成员的值
printf("Name: %s\n", ptr->name);
printf("Age: %d\n", ptr->age);
return 0;
}
在这个例子中再次使用 Person 结构体,但这次通过一个指向 person 的指针 ptr 来访问和设置成员。注意使用了箭头操作符 (->) 而不是点操作符。
3. 结构体传参
结构体可以作为函数的参数进行传递。尤其是需要在函数间共享或操作复杂数据时。结构体传参可以通过两种主要方式实现:按值传递和按引用(指针)传递。
3.1 结构体按值传递
当结构体按值传递时,实际上传递的是结构体的一个副本。这意味着,在函数中对结构体成员的任何修改都不会影响原始结构体。
优点
- 安全:函数中的更改不会影响原始数据。
- 简单:直接操作结构体,不涉及指针。
缺点
- 效率低:对于较大的结构体,复制整个结构可能导致显著的性能开销。
- 内存使用:增加内存消耗,特别是结构体较大时。
示例代码:
#include <stdio.h>
struct Point {
int x;
int y;
};
// 函数定义:按值传递结构体,接收一个 Point 结构体的副本
void movePoint(struct Point p) {
p.x += 10; // 在副本上修改 x 坐标
p.y += 10; // 在副本上修改 y 坐标
printf("Inside function: x = %d, y = %d\n", p.x, p.y); // 打印修改后的副本坐标
}
int main() {
struct Point point = {100, 100}; // 初始化一个 Point 结构体实例
movePoint(point); // 调用函数,传入 point 的副本
printf("Outside function: x = %d, y = %d\n", point.x, point.y); // 打印原始坐标,观察是否有变化
return 0;
}
在这个例子中,movePoint
函数按值接收一个 Point
结构体。在函数内部修改结构体不会影响原始结构体的值。
3.2 结构体按引用传递(使用指针)
当结构体通过指针传递时,传递的是结构体地址的副本,因此在函数中对结构体的修改将影响原始结构体。
优点
- 高效:无论结构体大小如何,传递的都只是一个地址。
- 功能强大:可以在函数内部修改原始结构体。
缺点
- 安全性:需要确保传入的指针有效,避免野指针等问题。
- 稍复杂:需要正确处理指针。
示例代码
#include <stdio.h>
struct Point {
int x;
int y;
};
// 函数定义:按引用传递结构体,接收一个指向 Point 结构体的指针
void movePoint(struct Point *p) {
p->x += 10; // 通过指针修改原始结构体的 x 坐标
p->y += 10; // 通过指针修改原始结构体的 y 坐标
printf("Inside function: x = %d, y = %d\n", p->x, p->y); // 打印修改后的坐标
}
int main() {
struct Point point = {100, 100}; // 初始化一个 Point 结构体实例
movePoint(&point); // 调用函数,传入 point 的地址
printf("Outside function: x = %d, y = %d\n", point.x, point.y); // 打印坐标,检查修改是否影响到原始数据
return 0;
}
在这个例子中,movePoint
函数接受一个指向 Point
结构体的指针。通过指针对结构体的修改会反映到原始结构体上。
原文地址:https://blog.csdn.net/TENET123/article/details/137980044
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!