- C++
C++ 结构体初始化和结构体的动态内存分配初始化学习笔记教程
- 2025-8-10 14:31:21 @
C++ 结构体初始化与动态内存分配学习笔记
结构体是C++中一种重要的数据结构,允许将不同类型的数据组合在一起形成一个新的类型。本文将详细介绍结构体的初始化方法以及动态内存分配相关知识。
一、结构体的定义
首先,我们需要了解如何定义一个结构体:
// 定义一个学生结构体
struct Student {
std::string name; // 姓名
int age; // 年龄
float score; // 分数
};
二、结构体的初始化方法
1. 声明时初始化
最直接的初始化方式是在声明结构体变量时进行初始化:
// C++11之前的初始化方式
Student s1 = {"张三", 18, 90.5f};
// C++11及以后支持的列表初始化(推荐)
Student s2{"李四", 19, 88.0f};
2. 使用构造函数初始化
结构体可以像类一样拥有构造函数,这是更灵活的初始化方式:
struct Student {
std::string name;
int age;
float score;
// 构造函数
Student(std::string n, int a, float s) {
name = n;
age = a;
score = s;
}
// 带默认参数的构造函数
Student(std::string n = "未知", int a = 0, float s = 0.0f) {
name = n;
age = a;
score = s;
}
};
// 使用构造函数初始化
Student s3("王五", 20, 95.5f);
Student s4; // 使用默认参数初始化
3. 成员逐个初始化
可以先声明结构体变量,再逐个初始化其成员:
Student s5;
s5.name = "赵六";
s5.age = 19;
s5.score = 89.0f;
三、结构体的动态内存分配
当需要在程序运行时创建结构体实例时,我们可以使用new
运算符进行动态内存分配。
1. 动态分配单个结构体
// 动态分配一个Student结构体
Student* pStudent1 = new Student;
// 初始化动态分配的结构体
pStudent1->name = "钱七";
pStudent1->age = 20;
pStudent1->score = 92.5f;
// 使用构造函数初始化
Student* pStudent2 = new Student("孙八", 19, 87.0f);
2. 动态分配结构体数组
// 动态分配结构体数组
Student* pStudents = new Student[3];
// 初始化数组元素
pStudents[0] = Student("周九", 18, 91.0f);
pStudents[1] = Student("吴十", 19, 85.5f);
pStudents[2] = Student("郑十一", 20, 88.0f);
3. 释放动态分配的内存
动态分配的内存需要手动释放,否则会导致内存泄漏:
// 释放单个结构体
delete pStudent1;
delete pStudent2;
// 释放结构体数组(注意使用delete[])
delete[] pStudents;
// 释放后将指针置空,避免野指针
pStudent1 = nullptr;
pStudent2 = nullptr;
pStudents = nullptr;
四、完整示例代码
下面是一个包含上述所有知识点的完整示例:
#include <iostream>
#include <string>
// 定义带构造函数的结构体
struct Student {
std::string name;
int age;
float score;
// 默认构造函数
Student() : name("未知"), age(0), score(0.0f) {}
// 带参数的构造函数
Student(std::string n, int a, float s)
: name(n), age(a), score(s) {}
// 显示学生信息的成员函数
void display() {
std::cout << "姓名: " << name
<< ", 年龄: " << age
<< ", 分数: " << score << std::endl;
}
};
int main() {
// 1. 基本初始化方式
Student s1 = {"张三", 18, 90.5f}; // 传统方式
Student s2{"李四", 19, 88.0f}; // C++11列表初始化
// 2. 使用构造函数初始化
Student s3("王五", 20, 95.5f);
Student s4; // 使用默认构造函数
// 3. 成员逐个初始化
Student s5;
s5.name = "赵六";
s5.age = 19;
s5.score = 89.0f;
// 4. 动态分配单个结构体
Student* pStudent1 = new Student;
pStudent1->name = "钱七";
pStudent1->age = 20;
pStudent1->score = 92.5f;
Student* pStudent2 = new Student("孙八", 19, 87.0f);
// 5. 动态分配结构体数组
Student* pStudents = new Student[3];
pStudents[0] = Student("周九", 18, 91.0f);
pStudents[1] = Student("吴十", 19, 85.5f);
pStudents[2] = Student("郑十一", 20, 88.0f);
// 显示所有学生信息
std::cout << "学生信息列表:" << std::endl;
s1.display();
s2.display();
s3.display();
s4.display();
s5.display();
pStudent1->display();
pStudent2->display();
for (int i = 0; i < 3; i++) {
pStudents[i].display();
}
// 释放动态分配的内存
delete pStudent1;
delete pStudent2;
delete[] pStudents;
// 避免野指针
pStudent1 = nullptr;
pStudent2 = nullptr;
pStudents = nullptr;
return 0;
}
五、注意事项
-
内存管理:使用
new
分配的内存必须用delete
释放,数组则用delete[]
,否则会导致内存泄漏。 -
构造函数:如果定义了带参数的构造函数,C++不会自动生成默认构造函数,需要手动定义。
-
初始化列表:在构造函数中使用初始化列表(如
Student(std::string n) : name(n) {}
)比在构造函数体内赋值更高效。 -
空指针:释放内存后,应将指针设置为
nullptr
,避免成为野指针。 -
C++11特性:列表初始化是C++11引入的特性,使初始化更加简洁直观,推荐使用。
通过以上学习,你应该已经掌握了C++结构体的各种初始化方法和动态内存分配技巧。在实际编程中,根据具体场景选择合适的初始化方式,可以使代码更加高效和易读。
2 条评论
-
admin SU @ 2025-8-10 14:41:06
C++结构体使用new{}初始化教程
在C++11及以后的标准中,引入了列表初始化(List Initialization)语法,使用大括号
{}
进行初始化,这为结构体的动态内存分配提供了更灵活、更安全的方式。本教程将详细介绍如何使用new{}
语法初始化结构体。一、new{}初始化的基本语法
使用
new{}
初始化结构体的基本语法如下:// 动态分配并初始化单个结构体 结构体类型* 指针变量 = new 结构体类型{初始化值列表}; // 动态分配并初始化结构体数组 结构体类型* 指针变量 = new 结构体类型[数组大小]{初始化值列表1, 初始化值列表2, ...};
二、使用new{}初始化不同类型的结构体
1. 聚合结构体(无自定义构造函数)
对于没有定义任何构造函数的结构体(聚合类型),
new{}
可以直接初始化其成员:#include <iostream> #include <string> // 1. 聚合结构体(无自定义构造函数) struct Point { int x; int y; }; struct Person { std::string name; int age; double height; }; // 2. 带构造函数的结构体 struct Student { std::string name; int id; float score; // 带参数的构造函数 Student(std::string n, int i, float s) : name(n), id(i), score(s) {} // 显示信息 void display() const { std::cout << "姓名: " << name << ", 学号: " << id << ", 成绩: " << score << std::endl; } }; // 3. 嵌套结构体 struct Rectangle { Point topLeft; Point bottomRight; std::string color; }; int main() { // 示例1: 初始化聚合结构体 std::cout << "=== 初始化聚合结构体 ===" << std::endl; // 初始化Point结构体 Point* p1 = new Point{10, 20}; std::cout << "Point p1: (" << p1->x << ", " << p1->y << ")" << std::endl; // 初始化Person结构体 Person* person1 = new Person{"张三", 25, 1.75}; std::cout << "Person: " << person1->name << ", " << person1->age << "岁, " << person1->height << "米" << std::endl; // C++20支持指定成员初始化 Person* person2 = new Person{.name="李四", .age=30}; std::cout << "Person: " << person2->name << ", " << person2->age << "岁, " << person2->height << "米" << std::endl; // 示例2: 初始化带构造函数的结构体 std::cout << "\n=== 初始化带构造函数的结构体 ===" << std::endl; // new{}会调用匹配的构造函数 Student* stu1 = new Student{"王五", 1001, 92.5f}; stu1->display(); // 示例3: 初始化嵌套结构体 std::cout << "\n=== 初始化嵌套结构体 ===" << std::endl; Rectangle* rect = new Rectangle{ {0, 0}, // topLeft {100, 200}, // bottomRight "blue" // color }; std::cout << "矩形: 左上角(" << rect->topLeft.x << "," << rect->topLeft.y << "), 右下角(" << rect->bottomRight.x << "," << rect->bottomRight.y << "), 颜色:" << rect->color << std::endl; // 示例4: 初始化结构体数组 std::cout << "\n=== 初始化结构体数组 ===" << std::endl; // 初始化Point数组 Point* points = new Point[3]{ {0, 0}, {10, 10}, {20, 20} }; std::cout << "Points数组:" << std::endl; for (int i = 0; i < 3; i++) { std::cout << "(" << points[i].x << ", " << points[i].y << ")" << std::endl; } // 初始化Student数组 Student* students = new Student[2]{ {"赵六", 1002, 88.0f}, {"孙七", 1003, 95.5f} }; std::cout << "Students数组:" << std::endl; for (int i = 0; i < 2; i++) { students[i].display(); } // 释放内存 delete p1; delete person1; delete person2; delete stu1; delete rect; delete[] points; delete[] students; // 避免野指针 p1 = nullptr; person1 = person2 = nullptr; stu1 = nullptr; rect = nullptr; points = nullptr; students = nullptr; return 0; }
2. 带构造函数的结构体
当结构体有自定义构造函数时,
new{}
会根据初始化列表调用相应的构造函数:// 结构体定义 struct Student { std::string name; int id; float score; // 带参数的构造函数 Student(std::string n, int i, float s) : name(n), id(i), score(s) {} }; // 使用new{}初始化 Student* stu = new Student{"王五", 1001, 92.5f};
3. 嵌套结构体
对于包含其他结构体的嵌套结构体,
new{}
可以通过嵌套的大括号进行初始化:// 嵌套结构体初始化 Rectangle* rect = new Rectangle{ {0, 0}, // 内部结构体topLeft的初始化 {100, 200}, // 内部结构体bottomRight的初始化 "blue" // color成员 };
4. 结构体数组
使用
new[]
配合{}
可以方便地初始化结构体数组:// 初始化结构体数组 Point* points = new Point[3]{ {0, 0}, {10, 10}, {20, 20} };
三、new{}初始化的优势
- 一致性:统一的初始化语法,适用于各种数据类型
- 安全性:不允许窄化转换(如将double隐式转换为int)
- 灵活性:可以初始化聚合类型、带构造函数的类型和嵌套类型
- 明确性:初始化值与成员的对应关系清晰
- C++20增强:支持指定成员初始化(如
.name="李四"
)
四、注意事项
- C++版本:
new{}
是C++11引入的特性,需要编译器支持C++11及以上标准 - 窄化转换:
new{}
不允许窄化转换,例如new Point{10.5, 20}
会编译错误 - 聚合类型:如果结构体有用户定义的构造函数,就不再是聚合类型,不能使用聚合初始化
- 内存释放:使用
new
分配的内存必须用delete
释放,数组用delete[]
- 指针安全:释放内存后,应将指针置为
nullptr
,避免野指针
五、总结
new{}
初始化语法为C++结构体的动态内存分配提供了一种现代、安全且灵活的方式。无论是简单的聚合结构体,还是复杂的带构造函数的结构体,甚至是结构体数组和嵌套结构体,new{}
都能提供一致且清晰的初始化体验。在实际开发中,推荐优先使用new{}
语法进行结构体的动态初始化。 -
2025-8-10 14:37:32@
C++结构体使用new()和new{}初始化教程
在C++中,使用
new
运算符动态分配结构体时,可以通过不同的语法进行初始化。本教程将详细介绍使用new()
和new{}
初始化结构体的方法及区别。一、基础概念
new()
:使用圆括号进行初始化,支持构造函数参数传递new{}
:使用大括号进行列表初始化(C++11及以后),支持列表初始化语法
这两种方式在初始化结构体时各有特点,适用于不同场景。
二、使用new()初始化结构体
new()
语法主要用于调用结构体的构造函数进行初始化,语法格式为:结构体指针 = new 结构体名(构造函数参数);
示例代码:
#include <iostream> #include <string> // 定义一个学生结构体 struct Student { std::string name; int age; float score; // 默认构造函数 Student() : name("未知"), age(0), score(0.0f) { std::cout << "调用了默认构造函数" << std::endl; } // 带参数的构造函数 Student(std::string n, int a, float s) : name(n), age(a), score(s) { std::cout << "调用了带参数的构造函数" << std::endl; } // 显示信息 void showInfo() const { std::cout << "姓名: " << name << ", 年龄: " << age << ", 分数: " << score << std::endl; } }; int main() { // 1. 使用new()初始化 std::cout << "=== 使用new()初始化 ===" << std::endl; // 1.1 调用默认构造函数 Student* s1 = new Student(); s1->showInfo(); // 1.2 调用带参数的构造函数 Student* s2 = new Student("张三", 18, 90.5f); s2->showInfo(); // 2. 使用new{}初始化 (C++11及以后) std::cout << "\n=== 使用new{}初始化 ===" << std::endl; // 2.1 不带参数,调用默认构造函数 Student* s3 = new Student{}; s3->showInfo(); // 2.2 使用列表初始化,相当于调用相应的构造函数 Student* s4 = new Student{"李四", 19, 88.0f}; s4->showInfo(); // 2.3 部分成员初始化(需要结构体没有用户定义的构造函数) // 注意:如果结构体有用户定义的构造函数,这种方式会报错 struct Point { int x; int y; }; Point* p1 = new Point{10, 20}; // 正确,初始化x=10, y=20 Point* p2 = new Point{x=30, y=40}; // C++20支持指定成员初始化 std::cout << "\nPoint p1: (" << p1->x << ", " << p1->y << ")" << std::endl; std::cout << "Point p2: (" << p2->x << ", " << p2->y << ")" << std::endl; // 3. 动态分配结构体数组 std::cout << "\n=== 动态分配结构体数组 ===" << std::endl; // 3.1 使用new[]() Student* class1 = new Student[2]{{"王五", 20, 92.0f}, {"赵六", 19, 89.5f}}; // 3.2 使用new[]{} Student* class2 = new Student[2]{"钱七", 21, 95.0f, "孙八", 20, 87.5f}; std::cout << "class1 学生信息:" << std::endl; for (int i = 0; i < 2; i++) { class1[i].showInfo(); } std::cout << "class2 学生信息:" << std::endl; for (int i = 0; i < 2; i++) { class2[i].showInfo(); } // 释放内存 delete s1; delete s2; delete s3; delete s4; delete p1; delete p2; delete[] class1; delete[] class2; // 避免野指针 s1 = s2 = s3 = s4 = nullptr; p1 = p2 = nullptr; class1 = class2 = nullptr; return 0; }
三、new()与new{}的主要区别
-
初始化方式:
new()
主要通过调用构造函数进行初始化new{}
使用列表初始化,更灵活
-
对聚合类型的处理:
- 对于没有用户定义构造函数的结构体(聚合类型),
new{}
可以直接初始化成员 new()
不能直接初始化聚合类型的成员
- 对于没有用户定义构造函数的结构体(聚合类型),
-
窄化转换:
new{}
不允许窄化转换(如int到float的隐式转换)new()
允许窄化转换
-
数组初始化:
- 两者都可以初始化数组,但
new{}
的语法更直观
- 两者都可以初始化数组,但
四、使用建议
- 当结构体有定义好的构造函数时,两种方式均可使用,但
new{}
的语法更统一 - 对于简单的聚合结构体(无自定义构造函数),优先使用
new{}
- 在需要明确指定初始化成员时(C++20),使用
new{成员名=值}
的形式 - 初始化数组时,
new{}
的列表初始化语法更清晰
通过合理选择
new()
和new{}
初始化方式,可以使代码更加清晰、安全和高效。在实际开发中,推荐优先使用new{}
语法,因为它提供了更一致的初始化体验和更好的类型安全检查。
- 1