C++ 中如何定义和操作数据结构体

文章目录

1. 定义结构体

2. 访问结构成员

3. 结构作为函数参数

4. 指向结构的指针

5. typedef 关键字


1. 定义结构体

在C++中,结构体(struct)是一种用户定义的数据类型,它允许将不同类型的数据组合在一起形成一个复合数据类型。结构体在组织和管理相关数据方面非常有用,例如在表示复杂的实体(如学生、汽车、图形对象等)时,可以将相关的属性(如名称、年龄、颜色、位置等)组合在一起。通过使用结构体,程序员可以更清晰地表达和操作这些复杂的数据结构。

结构体的基本定义

在C++中,定义一个结构体通常使用struct关键字。结构体的定义包含结构体的名称和内部的成员变量。以下是一个简单的结构体定义示例:

#include <iostream>
using namespace std;

// 定义一个表示点(Point)的结构体
struct Point {
    int x; // x坐标
    int y; // y坐标
};

int main() {
    // 创建一个 Point 结构体变量
    Point p1;
    p1.x = 10; // 访问并设置 x 成员
    p1.y = 20; // 访问并设置 y 成员

    cout << "Point p1: (" << p1.x << ", " << p1.y << ")" << endl;

    return 0;
}

在这个例子中定义了一个名为Point的结构体,它包含两个成员变量xy,分别表示一个点的横坐标和纵坐标。在main函数中,我们创建了一个Point类型的变量p1,并设置了xy的值,最后输出这个点的坐标。

结构体定义的语法细节
  • struct关键字:在C++中,使用struct关键字来定义结构体。它与class关键字类似,但有一些区别,特别是在默认访问控制方面(struct默认是public,而class默认是private)。

  • 结构体名称:结构体名称紧随struct关键字之后,它是新数据类型的名称。在上例中,Point就是结构体的名称。

  • 成员变量:结构体的成员变量定义在大括号{}内,可以是任意基本数据类型(如intfloatchar)或其他结构体类型,甚至可以是指针、数组或对象。在结构体定义后需要使用分号;结束。

  • 访问结构体成员:一旦定义了结构体类型,就可以使用点操作符(.)来访问结构体变量的成员。通过结构体变量的名字和成员变量的名字,可以读取或修改成员的值。

结构体的初始化

直接赋值初始化:结构体变量可以在定义时通过大括号{}直接初始化:

Point p2 = {30, 40}; // 初始化 Point 变量 p2,x=30, y=40

逐成员赋值:也可以像之前的例子那样,通过逐个成员的方式进行赋值:

Point p3;
p3.x = 50;
p3.y = 60;

构造函数初始化:如果在结构体中定义了构造函数,则可以通过构造函数来初始化结构体变量:

struct Point {
    int x;
    int y;
    // 构造函数
    Point(int xVal, int yVal) : x(xVal), y(yVal) {}
};

Point p4(70, 80); // 通过构造函数初始化 p4,x=70, y=80

嵌套结构体

结构体可以嵌套定义,这意味着一个结构体的成员可以是另一个结构体类型。这在表示复杂的数据结构时非常有用。

#include <iostream>
using namespace std;

struct Circle {
    Point center; // 圆心
    double radius; // 半径
};

int main() {
    Circle c1;
    c1.center.x = 5;   // 设置圆心的 x 坐标
    c1.center.y = 10;  // 设置圆心的 y 坐标
    c1.radius = 15.5;  // 设置半径

    cout << "Circle c1: Center(" << c1.center.x << ", " << c1.center.y << "), Radius: " << c1.radius << endl;

    return 0;
}

在这个例子中定义了一个Circle结构体,包含一个Point类型的成员center(表示圆心),以及一个double类型的成员radius(表示半径)。

2. 访问结构成员

定义了结构体后,可以通过结构体变量访问其成员。访问结构体成员是指在使用结构体变量时,读取或修改结构体中的各个成员变量。

通过点操作符访问成员

最常见的访问结构体成员的方法是使用点操作符.)。点操作符用于连接结构体变量和成员变量,以便访问或修改该成员的值。

#include <iostream>
using namespace std;

struct Point {
    int x;
    int y;
};

int main() {
    Point p1;  // 定义一个 Point 结构体变量 p1

    // 使用点操作符访问和修改成员变量
    p1.x = 10;
    p1.y = 20;

    cout << "Point p1: (" << p1.x << ", " << p1.y << ")" << endl;

    return 0;
}
访问嵌套结构体的成员

如果一个结构体包含另一个结构体作为其成员,可以使用点操作符链式访问嵌套结构体的成员。这种方式非常直观,可以很好地表示嵌套的数据关系。

#include <iostream>
using namespace std;

struct Point {
    int x;
    int y;
};

struct Rectangle {
    Point topLeft;    // 矩形的左上角坐标
    Point bottomRight; // 矩形的右下角坐标
};

int main() {
    Rectangle rect;  // 定义一个 Rectangle 结构体变量 rect

    // 访问并设置嵌套的 Point 结构体成员
    rect.topLeft.x = 0;
    rect.topLeft.y = 10;
    rect.bottomRight.x = 20;
    rect.bottomRight.y = 0;

    cout << "Rectangle corners: (" << rect.topLeft.x << ", " << rect.topLeft.y << ") to ("
         << rect.bottomRight.x << ", " << rect.bottomRight.y << ")" << endl;

    return 0;
}

在这个示例中,Rectangle结构体包含两个Point结构体作为其成员。我们通过点操作符链式访问这些嵌套的成员,设置和获取矩形的左上角和右下角的坐标。

通过指针访问结构体成员

在某些情况下,你可能会通过指针来操作结构体。C++允许通过指针访问结构体的成员,并提供了两种语法:**间接访问符(->)**和点操作符配合解引用操作符(*)。

  • 间接访问符->:当你有一个指向结构体的指针时,可以使用->符号直接访问结构体成员。

Point* pPtr = &p1;  // 定义一个指向结构体的指针
pPtr->x = 15;       // 使用间接访问符访问成员
pPtr->y = 25;

cout << "Point p1: (" << pPtr->x << ", " << pPtr->y << ")" << endl;
  • 点操作符与解引用操作符组合:也可以先解引用指针,然后使用点操作符访问成员。
(*pPtr).x = 30;  // 先解引用指针,再使用点操作符访问成员
(*pPtr).y = 40;

cout << "Point p1: (" << (*pPtr).x << ", " << (*pPtr).y << ")" << endl;

在实际编程中,使用->符号更为常见,因为它语法更加简洁且易读。

3. 结构作为函数参数

结构体不仅可以用于定义复杂的数据类型,还可以作为函数参数进行传递。在函数中,结构体可以通过值传递、引用传递或指针传递来处理。

通过值传递结构体

值传递是指将结构体的副本传递给函数。这意味着在函数内部对结构体参数所做的任何修改都不会影响原来的结构体。值传递的优点是简单直观,但如果结构体很大,传递的副本可能会占用较多的内存,并且由于复制的开销,效率较低。

#include <iostream>
using namespace std;

struct Point {
    int x;
    int y;
};

void printPoint(Point p) {  // 通过值传递结构体
    p.x += 10;  // 修改不会影响原始结构体
    cout << "Point inside function: (" << p.x << ", " << p.y << ")" << endl;
}

int main() {
    Point p1 = {10, 20};
    printPoint(p1);  // 传递结构体副本
    cout << "Point in main: (" << p1.x << ", " << p1.y << ")" << endl;

    return 0;
}

 输出结果:

Point inside function: (20, 20)
Point in main: (10, 20)

  • 在这个示例中,printPoint函数接受一个Point类型的参数p,这是通过值传递的。
  • printPoint函数内部,p.x的值被增加了10,但这不会影响原始的p1变量,因为修改的是p1的副本。
  • 当函数执行完毕返回到main时,p1的值保持不变。

 

通过引用传递结构体

引用传递是指将结构体的引用(即结构体本身的别名)传递给函数。这意味着函数内部对结构体的修改会影响到原始的结构体。引用传递的效率更高,因为不需要复制结构体的内容,只是传递了一个引用,适合处理大型结构体。

#include <iostream>
using namespace std;

struct Point {
    int x;
    int y;
};

void movePoint(Point &p, int dx, int dy) {  // 通过引用传递结构体
    p.x += dx;
    p.y += dy;
}

int main() {
    Point p1 = {10, 20};
    movePoint(p1, 5, -10);  // 直接修改原始结构体
    cout << "Point after moving: (" << p1.x << ", " << p1.y << ")" << endl;

    return 0;
}

输出结果:

Point after moving: (15, 10)
  • 在这个示例中,movePoint函数接受一个Point类型的引用p。函数对p的修改将直接作用于原始的p1变量。
  • movePoint函数执行完毕后,p1xy值已经被改变,这是因为引用传递操作的是同一个对象。

通过指针传递结构体

指针传递与引用传递类似,也是为了避免结构体的复制开销,但使用指针传递时,需要显式地解引用指针来访问结构体成员。指针传递在需要传递空指针(nullptr)的情况下特别有用,能够表示没有传递任何有效的结构体。

#include <iostream>
using namespace std;

struct Point {
    int x;
    int y;
};

void scalePoint(Point *p, int factor) {  // 通过指针传递结构体
    p->x *= factor;  // 使用箭头操作符访问结构体成员
    p->y *= factor;
}

int main() {
    Point p1 = {10, 20};
    scalePoint(&p1, 2);  // 传递结构体的指针
    cout << "Point after scaling: (" << p1.x << ", " << p1.y << ")" << endl;

    return 0;
}

输出结果:

Point after scaling: (20, 40)
  • 在这个示例中,scalePoint函数接受一个Point类型的指针p。函数内部使用p->语法来访问结构体的成员变量。
  • 通过指针传递,函数可以直接修改原始结构体p1的值,操作完成后,p1xy值被成倍增加。

4. 指向结构的指针

指向结构体的指针是一个非常有用的工具,特别是在处理动态内存分配、结构体数组以及传递结构体参数时。

定义和初始化指向结构体的指针

定义指向结构体的指针与定义其他类型的指针类似。首先,我们定义一个结构体类型,然后定义一个指向这种结构体的指针。

#include <iostream>
using namespace std;

struct Point {
    int x;
    int y;
};

int main() {
    Point p1 = {10, 20};  // 定义一个 Point 结构体变量
    Point* pPtr = &p1;    // 定义一个指向 Point 结构体的指针

    cout << "Address of p1: " << pPtr << endl;
    cout << "Point p1: (" << pPtr->x << ", " << pPtr->y << ")" << endl;

    return 0;
}
  • Point* pPtr = &p1;:这里定义了一个指针pPtr,它指向结构体p1的地址。
  • 使用pPtr可以访问结构体p1的成员变量,通过pPtr->xpPtr->y来读取和修改结构体成员。

动态分配结构体内存

在C++中,指针非常有用的一部分是能够动态分配内存。这对于需要在运行时创建结构体实例的情况特别重要。可以使用new操作符来动态分配结构体内存,并使用指针来管理它。

#include <iostream>
using namespace std;

struct Point {
    int x;
    int y;
};

int main() {
    // 动态分配一个 Point 结构体的内存
    Point* pPtr = new Point;

    // 通过指针设置结构体成员
    pPtr->x = 50;
    pPtr->y = 100;

    cout << "Dynamically allocated Point: (" << pPtr->x << ", " << pPtr->y << ")" << endl;

    // 释放动态分配的内存
    delete pPtr;

    return 0;
}

输出结果:

Dynamically allocated Point: (50, 100)

5. typedef 关键字

typedef关键字用于为已有的数据类型创建一个新的名称(别名)。这可以使代码更简洁、易读,并且在某些情况下提供了更好的可维护性。typedef特别有用,当你需要频繁使用复杂的数据类型时,或者希望为某些类型创建一个更具描述性的名字时。

基本用法

typedef 的基本语法是:typedef 原始类型 新类型名;。使用typedef定义的新类型名,可以像使用原始类型一样使用。

#include <iostream>
using namespace std;

typedef unsigned long int ulong;  // 为 unsigned long int 定义别名

int main() {
    ulong largeNumber = 1000000;  // 使用 typedef 定义的新类型名
    cout << "Large Number: " << largeNumber << endl;

    return 0;
}
  • typedef unsigned long int ulong;:这行代码将unsigned long int重命名为ulong,使得在代码中可以用ulong来代替unsigned long int,使代码更简洁。
  • main函数中,ulong类型的变量largeNumber被定义为1000000,并输出其值。
使用 typedef 定义结构体别名

结构体的类型名通常比较长或复杂,使用typedef可以为结构体类型定义一个简短的别名,使代码更加易读。

#include <iostream>
using namespace std;

struct Point {
    int x;
    int y;
};

typedef struct Point Point2D;  // 定义 Point 结构体的别名为 Point2D

int main() {
    Point2D p1;  // 使用别名 Point2D 定义结构体变量
    p1.x = 10;
    p1.y = 20;

    cout << "Point p1: (" << p1.x << ", " << p1.y << ")" << endl;

    return 0;
}
  • typedef struct Point Point2D;:将struct Point类型重命名为Point2D,在后续代码中可以使用Point2D来定义结构体变量。
  • main函数中,使用Point2D类型定义了一个结构体变量p1,并设置其成员值。

注意: 在C++中,可以直接省略struct前缀,在结构体定义时直接使用typedef来简化结构体的定义:

typedef struct {
    int x;
    int y;
} Point2D;

这样在定义结构体时就不需要显式给出结构体的名字,只需要使用别名Point2D

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TENET-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值