C++ 中,结构体(struct) 是一种用户自定义的数据类型,用于将不同类型的数据(变量)组合在一起,形成一个逻辑整体,方便管理和操作相关联的数据。结构体可以理解为 “数据的集合”,尤其适合表示具有多个属性的实体(如学生、坐标点、汽车等)。
结构体的核心特点:
- 组合多种数据类型:结构体中可以包含不同类型的成员(如
int、string、double等),甚至可以包含其他结构体。 - 支持成员函数:C++ 中的结构体不仅可以有成员变量,还可以有成员函数(用于操作结构体数据),这一点与
class类似(主要区别是默认访问权限:struct默认public,class默认private)。 - 自定义类型:定义结构体后,可以像内置类型(如
int)一样声明变量、作为函数参数或返回值。
结构体的基本用法
1. 结构体的定义
使用struct关键字定义结构体,语法如下:
struct 结构体名 {
// 成员变量(属性)
数据类型 成员名1;
数据类型 成员名2;
...
// 成员函数(操作)
返回值类型 函数名(参数列表) {
// 函数体(操作成员变量)
}
};
2. 结构体变量的声明与初始化
定义结构体后,可以声明结构体变量,并对其成员初始化。
3. 访问结构体成员
通过 点运算符(.) 访问结构体变量的成员;如果是结构体指针,则通过 箭头运算符(->) 访问。
代码示例
下面通过 3 个示例逐步展示结构体的用法:
示例 1:基础结构体(仅成员变量)
定义一个表示 “二维坐标点” 的结构体,包含x和y坐标,演示变量声明、赋值和访问。
#include <iostream>
using namespace std;
// 定义结构体:表示二维坐标点
struct Point {
int x; // x坐标
int y; // y坐标
};
int main() {
// 声明结构体变量并初始化(方式1:定义时初始化)
Point p1 = {3, 4}; // p1的x=3,y=4
// 声明结构体变量后单独赋值(方式2:逐个成员赋值)
Point p2;
p2.x = 5; // 用.访问成员变量
p2.y = 6;
// 输出坐标
cout << "p1坐标:(" << p1.x << ", " << p1.y << ")" << endl; // 输出:(3, 4)
cout << "p2坐标:(" << p2.x << ", " << p2.y << ")" << endl; // 输出:(5, 6)
return 0;
}
示例 2:带成员函数的结构体
定义一个 “学生” 结构体,包含姓名、年龄、成绩等成员变量,以及用于显示信息和修改成绩的成员函数。
#include <iostream>
#include <string> // 需包含string头文件
using namespace std;
// 定义结构体:表示学生
struct Student {
// 成员变量(属性)
string name; // 姓名
int age; // 年龄
double score; // 成绩
// 成员函数(操作):显示学生信息
void showInfo() {
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
cout << "成绩:" << score << endl;
}
// 成员函数:修改成绩
void setScore(double newScore) {
score = newScore; // 直接操作成员变量
}
};
int main() {
// 声明学生变量并初始化
Student s1 = {"张三", 18, 90.5};
// 调用成员函数显示信息
cout << "修改前的信息:" << endl;
s1.showInfo(); // 输出:姓名:张三 年龄:18 成绩:90.5
// 调用成员函数修改成绩
s1.setScore(95.0);
// 再次显示信息
cout << "\n修改后的信息:" << endl;
s1.showInfo(); // 输出:姓名:张三 年龄:18 成绩:95.0
return 0;
}
示例 3:结构体指针与函数参数
演示结构体指针的使用,以及结构体作为函数参数(值传递 / 引用传递)。
#include <iostream>
using namespace std;
// 定义结构体:表示矩形
struct Rectangle {
int length; // 长度
int width; // 宽度
};
// 函数:计算矩形面积(结构体值传递)
int getArea(Rectangle rect) {
return rect.length * rect.width;
}
// 函数:修改矩形尺寸(结构体引用传递,直接修改原变量)
void resize(Rectangle& rect, int newLen, int newWid) {
rect.length = newLen;
rect.width = newWid;
}
int main() {
// 声明矩形变量
Rectangle rect = {10, 5}; // 长10,宽5
// 结构体指针(用->访问成员)
Rectangle* pRect = ▭
cout << "初始长度:" << pRect->length << ",初始宽度:" << pRect->width << endl; // 10,5
// 计算面积
cout << "初始面积:" << getArea(rect) << endl; // 10*5=50
// 修改尺寸(引用传递)
resize(rect, 20, 8);
cout << "修改后长度:" << rect.length << ",修改后宽度:" << rect.width << endl; // 20,8
cout << "修改后面积:" << getArea(rect) << endl; // 20*8=160
return 0;
}
总结
结构体是 C++ 中组织关联数据的重要工具,通过将变量和操作函数封装在一起,使代码更清晰、逻辑更紧凑。它与类(class)的核心功能类似,主要差异在于默认访问权限(struct默认public,class默认private),实际开发中可根据需求选择使用。
示例二详解:
在 void setScore(double newScore) 这个成员函数中,double newScore 是一个函数参数,它的作用和可传入的数据类型可以从两方面理解:
1. 可以传入什么数据?
double 是 C++ 中的双精度浮点数类型,因此 newScore 可以接收以下几类数据:
-
double类型的字面量(带小数点的数值):比如95.0、88.5、100.0等(示例中传入的95.0就是这类)。 -
int类型的整数:C++ 会自动进行隐式类型转换,将整数转换为对应的double类型。例如传入90,会被自动转为90.0。 -
其他可转换为
double的类型:比如float类型(单精度浮点数),也会被隐式转换为double后传入(但double精度更高,更适合表示成绩这类可能带小数的数据)。
2. 这个参数的作用是什么?
newScore 的核心作用是传递一个 “新的成绩值”,供 setScore 函数使用,最终目的是更新结构体 Student 中的 score 成员变量。
具体来说:
-
当调用
s1.setScore(95.0)时,95.0会被传递给newScore,函数内部通过score = newScore将s1的score从原来的90.5改成95.0。 -
这种通过函数修改成员变量的方式,体现了 “封装” 的思想(即使当前
score是public的,后续如果将score改为private,仍可通过setScore安全修改,避免直接暴露成员变量)。
总结
double newScore 是一个接收 “新成绩” 的参数,可传入小数(double)、整数(int 等可转换类型),作用是将新的成绩值传递给函数,用于更新学生对象的成绩。
示例三详解:
在函数 int getArea(Rectangle rect) 中,结构体 Rectangle 作为参数的传递方式是值传递(pass-by-value)。这种传递方式的核心是 “复制原结构体的数据,函数内部操作副本,不影响原结构体”。下面详细拆解其传递步骤和作用:
一、结构体值传递的详细步骤
假设在 main 函数中调用 getArea(rect)(其中 rect 是已初始化的 Rectangle 变量,length=10,width=5),整个传递和执行过程如下:
步骤 1:调用函数时,创建结构体参数的 “副本”
当执行 getArea(rect) 时,编译器会为函数参数 rect(形参)创建一个全新的、与实参 rect 完全相同的副本。
- 复制规则:对结构体的每个成员变量逐一复制(即 “浅拷贝”)。这里会将实参
rect的length(10)复制到形参rect的length,将实参的width(5)复制到形参的width。 - 此时内存中存在两个独立的
Rectangle变量:原变量rect(在main函数中)和形参副本rect(在getArea函数的栈空间中)。
步骤 2:函数内部使用副本进行计算
getArea 函数内部的逻辑 return rect.length * rect.width,实际操作的是步骤 1 中创建的副本:
- 副本的
length=10,width=5,因此计算结果为10*5=50。
步骤 3:函数执行结束,副本被销毁
getArea 函数返回结果(50)后,其栈空间中的形参副本(结构体 rect)会被自动释放(内存回收),不会残留。
关键结论:
整个过程中,原结构体变量 rect(在 main 中)没有任何改变,因为函数操作的是它的副本。
二、结构体值传递的作用
这种传递方式的设计目的和适用场景如下:
1. 保护原数据不被修改
值传递中,函数内部对形参(副本)的任何修改都不会影响实参(原结构体)。
- 例如,即使在
getArea中添加rect.length = 100,原main函数中的rect.length仍然是 10(因为修改的是副本)。 - 这对
getArea这类 “只读” 函数(仅需使用结构体数据,无需修改)非常重要,能避免原数据被意外篡改。
2. 适合 “小结构体” 的传递
当结构体成员较少(如 Rectangle 只有两个 int 成员)时,复制副本的开销(内存和时间)很小,值传递高效且直观。
3. 符合 “函数独立性” 原则
函数的计算结果仅依赖于输入的参数(副本),不依赖外部变量的状态,也不影响外部变量,使函数更独立、易维护。
在函数 void resize(Rectangle& rect, int newLen, int newWid) 中,结构体 Rectangle 作为参数的传递方式是引用传递(pass-by-reference)。引用本质是 “变量的别名”,因此引用传递的核心是 “直接操作原结构体变量,不创建副本”。下面详细说明其传递步骤和作用:
一、结构体引用传递的详细步骤
假设在 main 函数中调用 resize(rect, 20, 8)(其中 rect 是原结构体变量,初始 length=10,width=5),整个过程如下:
步骤 1:函数调用时,为原结构体创建 “别名”
当执行 resize(rect, 20, 8) 时,函数的第一个参数 Rectangle& rect(形参)会成为实参 rect(原结构体变量)的别名。
- 这里的 “引用”(
&)表示形参rect不是新的变量,而是直接绑定到实参rect上,两者共享同一块内存空间。 - 此时内存中不会创建任何副本,形参和实参指向同一个
Rectangle结构体(地址相同)。
步骤 2:函数内部直接修改原结构体的成员
函数内部的代码 rect.length = newLen; rect.width = newWid; 看似操作的是形参 rect,但由于形参是原变量的别名,实际修改的是原结构体 rect 的成员:
newLen=20被赋值给rect.length,原结构体的长度从 10 变为 20;newWid=8被赋值给rect.width,原结构体的宽度从 5 变为 8。
步骤 3:函数执行结束,引用失效但原结构体已被修改
resize 函数执行完毕后,形参的引用(别名)会被销毁(不再作为原变量的别名),但原结构体 rect 已经被永久修改(length=20,width=8)。
二、结构体引用传递的作用
引用传递的设计完全是为了满足 “需要修改原结构体” 的场景,具体作用如下:
1. 直接修改原结构体变量
这是引用传递最核心的作用。resize 函数的目的是 “调整原矩形的尺寸”,而引用传递允许函数直接操作原变量,无需通过指针间接访问,修改结果能直接反映到原结构体上。
- 如果改用值传递(
void resize(Rectangle rect, ...)),函数内部修改的只是副本,原结构体不会有任何变化,无法实现 “调整尺寸” 的功能。
2. 避免结构体复制的开销
当结构体成员较多或包含大型数据(如长字符串、数组等)时,值传递会复制整个结构体(逐个成员复制),导致额外的内存占用和时间消耗。
- 引用传递无需复制,直接绑定原变量,能显著提高效率(尤其对大型结构体)。
- 示例中的
Rectangle只有两个int成员,复制开销很小,但换成包含 100 个成员的结构体时,引用传递的优势会非常明显。
3. 代码更简洁、易读
相比指针传递(如 void resize(Rectangle* rect, ...)),引用传递无需使用 * 解引用或 -> 访问成员,语法更接近直接操作变量,代码更直观。
- 例如:引用传递用
rect.length访问成员,而指针传递需要rect->length,引用的写法更简洁。
4. 保证参数的 “可读性”(非空性)
引用必须绑定到一个已存在的变量(不能为 nullptr),而指针可能为空(nullptr)。因此使用引用传递可以避免函数内部判断指针是否为空的额外逻辑,减少出错风险。
对比:引用传递与值传递的核心差异
| 传递方式 | 传递方式 | 能否修改原变量 | 适用场景 |
| 值传递 | 是(复制实参) | 不能 | 仅需读取数据,不修改原变量(如 getArea) |
| 引用传递 | 否(绑定原变量) | 能 | 需要修改原变量(如 resize) |
总结
resize 函数中结构体的引用传递步骤是:绑定原结构体为别名→直接修改原结构体成员→函数结束后原结构体已更新;核心作用是:实现对原结构体的修改,同时避免复制开销,让代码更简洁高效,非常适合需要 “修改输入参数” 的场景。

8557

被折叠的 条评论
为什么被折叠?



