文章目录
-
- [第10章 指针基础](#第10章 指针基础)
-
- [10.1 内存地址与指针概念](#10.1 内存地址与指针概念)
-
- [10.1.1 理解内存地址](#10.1.1 理解内存地址)
- [10.1.2 指针的基本概念](#10.1.2 指针的基本概念)
- [10.2 指针与数组](#10.2 指针与数组)
-
- [10.2.1 指针与一维数组](#10.2.1 指针与一维数组)
- [10.2.2 指针与多维数组](#10.2.2 指针与多维数组)
- [10.3 指针与字符串](#10.3 指针与字符串)
-
- [10.3.1 C风格字符串操作](#10.3.1 C风格字符串操作)
- [10.4 函数指针](#10.4 函数指针)
-
- [10.4.1 函数指针基础](#10.4.1 函数指针基础)
- [10.5 动态内存管理](#10.5 动态内存管理)
-
- [10.5.1 new和delete操作符](#10.5.1 new和delete操作符)
- [10.5.2 动态内存管理的最佳实践](#10.5.2 动态内存管理的最佳实践)
- [10.6 实践练习](#10.6 实践练习)
第10章 指针基础
10.1 内存地址与指针概念
10.1.1 理解内存地址
cpp
#include <iostream>
using namespace std;
void demonstrateMemoryAddress() {
cout << "=== 内存地址与指针概念 ===" << endl;
// 1. 变量的内存地址
int num = 42;
char ch = 'A';
double pi = 3.14159;
cout << "变量值及其内存地址:" << endl;
cout << "num = " << num << ", 地址: " << &num << endl;
cout << "ch = '" << ch << "', 地址: " << (void*)&ch << endl; // 需要类型转换
cout << "pi = " << pi << ", 地址: " << &pi << endl;
// 2. 内存地址的特性
cout << "\n内存地址的特性:" << endl;
int arr[3] = {10, 20, 30};
cout << "数组元素地址:" << endl;
for (int i = 0; i < 3; i++) {
cout << "arr[" << i << "] = " << arr[i]
<< ", 地址: " << &arr[i] << endl;
}
// 相邻元素的地址差 = 类型大小
cout << "地址差: " << (char*)&arr[1] - (char*)&arr[0]
<< " 字节 (int类型大小: " << sizeof(int) << " 字节)" << endl;
// 3. 结构体的内存布局
struct Student {
int id;
double score;
char grade;
};
Student s = {1001, 95.5, 'A'};
cout << "\n结构体内存地址:" << endl;
cout << "s.id = " << s.id << ", 地址: " << &s.id << endl;
cout << "s.score = " << s.score << ", 地址: " << &s.score << endl;
cout << "s.grade = '" << s.grade << "', 地址: " << (void*)&s.grade << endl;
// 结构体总大小
cout << "结构体总大小: " << sizeof(Student) << " 字节" << endl;
cout << "可能存在内存对齐(padding)" << endl;
// 4. 指针的大小
cout << "\n指针的大小(与平台相关):" << endl;
cout << "int* 大小: " << sizeof(int*) << " 字节" << endl;
cout << "char* 大小: " << sizeof(char*) << " 字节" << endl;
cout << "double* 大小: " << sizeof(double*) << " 字节" << endl;
cout << "void* 大小: " << sizeof(void*) << " 字节" << endl;
// 5. 不同平台的指针大小
cout << "\n不同平台的典型指针大小:" << endl;
cout << "32位系统: 4 字节" << endl;
cout << "64位系统: 8 字节" << endl;
cout << "当前系统: " << sizeof(void*) * 8 << " 位" << endl;
}
void demonstrateEndianness() {
cout << "\n=== 字节序(Endianness)===" << endl;
// 测试系统字节序
int test = 0x12345678;
unsigned char* bytes = (unsigned char*)&test;
cout << "整数 0x12345678 在内存中的存储:" << endl;
cout << "地址: " << &test << endl;
cout << "字节顺序: ";
for (int i = 0; i < sizeof(int); i++) {
printf("%p: 0x%02X\n", (void*)(bytes + i), bytes[i]);
}
if (bytes[0] == 0x78) {
cout << "小端序 (Little Endian): 低位字节在前" << endl;
} else if (bytes[0] == 0x12) {
cout << "大端序 (Big Endian): 高位字节在前" << endl;
}
// 字节序的影响
union EndianTest {
int num;
char bytes[4];
};
EndianTest et;
et.num = 0x12345678;
cout << "\n通过union测试:" << endl;
if (et.bytes[0] == 0x78) {
cout << "小端序系统" << endl;
} else {
cout << "大端序系统" << endl;
}
}
int main() {
demonstrateMemoryAddress();
demonstrateEndianness();
return 0;
}
10.1.2 指针的基本概念
cpp
#include <iostream>
using namespace std;
void demonstrateBasicPointers() {
cout << "=== 指针的基本概念 ===" << endl;
// 1. 指针的声明和初始化
cout << "1. 指针的声明和初始化:" << endl;
int num = 100;
int* ptr; // 声明指针(未初始化)
ptr = # // 初始化指针,指向num的地址
cout << "num = " << num << endl;
cout << "&num = " << &num << endl;
cout << "ptr = " << ptr << " (存储的地址)" << endl;
cout << "*ptr = " << *ptr << " (解引用)" << endl;
// 2. 不同类型的指针
cout << "\n2. 不同类型的指针:" << endl;
char ch = 'X';
double value = 3.14;
bool flag = true;
char* charPtr = &ch;
double* doublePtr = &value;
bool* boolPtr = &flag;
cout << "char指针: " << (void*)charPtr << ", 值: " << *charPtr << endl;
cout << "double指针: " << doublePtr << ", 值: " << *doublePtr << endl;
cout << "bool指针: " << boolPtr << ", 值: " << *boolPtr << endl;
// 3. void指针(通用指针)
cout << "\n3. void指针(通用指针):" << endl;
void* voidPtr = # // 可以指向任何类型
cout << "voidPtr指向int: " << voidPtr << endl;
voidPtr = &ch; // 现在指向char
cout << "voidPtr指向char: " << voidPtr << endl;
// void指针不能直接解引用
// cout << *voidPtr << endl; // 错误
// 需要类型转换后才能使用
cout << "通过类型转换解引用: " << *(char*)voidPtr << endl;
// 4. 空指针
cout << "\n4. 空指针 (nullptr):" << endl;
int* nullPtr = nullptr; // C++11 空指针字面量
int* oldNull = NULL; // 传统方式(C风格)
int* zeroNull = 0; // 不推荐
cout << "nullptr: " << nullPtr << endl;
cout << "NULL: " << oldNull << endl;
cout << "0: " << zeroNull << endl;
// 检查指针是否为空
if (nullPtr == nullptr) {
cout << "指针为空" << endl;
}
// 5. 野指针和悬垂指针
cout << "\n5. 野指针和悬垂指针(危险!):" << endl;
// 野指针:未初始化的指针
int* wildPtr; // 野指针,值不确定
// cout << *wildPtr << endl; // 未定义行为
// 悬垂指针:指向已释放内存的指针
int* danglingPtr = new int(999);
cout << "分配内存,值: " << *danglingPtr << endl;
delete danglingPtr; // 释放内存
danglingPtr = nullptr; // 好习惯:立即设为空指针
// 现在danglingPtr是悬垂指针
// cout << *danglingPtr << endl; // 未定义行为
// 6. 常量指针 vs 指针常量
cout << "\n6. 常量指针与指针常量:" << endl;
int a = 10, b = 20;
// 指针常量:指针本身是常量(不能改变指向)
int* const ptrConst = &a;
cout << "指针常量: ptrConst = " << ptrConst << ", *ptrConst = " << *ptrConst << endl;
*ptrConst = 30; // 可以修改指向的值
// ptrConst = &b; // 错误:不能改变指向
// 常量指针:指向常量的指针(不能修改值)
const int* constPtr = &a;
cout << "常量指针: constPtr = " << constPtr << ", *constPtr = " << *constPtr << endl;
// *constPtr = 40; // 错误:不能修改值
constPtr = &b; // 可以改变指向
// 常量指针常量:都不能修改
const int* const constPtrConst = &a;
// *constPtrConst = 50; // 错误
// constPtrConst = &b; // 错误
}
void demonstratePointerArithmetic() {
cout << "\n=== 指针算术运算 ===" << endl;
// 1. 指针加减整数
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr; // 指向数组第一个元素
cout << "数组地址: " << arr << endl;
cout << "ptr = " << ptr << endl;
cout << "\n指针加法:" << endl;
for (int i = 0; i < 5; i++) {
cout << "ptr + " << i << " = " << (ptr + i)
<< ", *(ptr + " << i << ") = " << *(ptr + i) << endl;
}
cout << "\n指针减法:" << endl;
int* endPtr = ptr + 4;
for (int i = 4; i >= 0; i--) {
cout << "endPtr - " << (4 - i) << " = " << (endPtr - (4 - i))
<< ", 值 = " << *(endPtr - (4 - i)) << endl;
}
// 2. 指针相减(得到元素个数)
cout << "\n指针相减(计算距离):" << endl;
int* ptr1 = &arr[0];
int* ptr2 = &arr[3];
ptrdiff_t distance = ptr2 - ptr1;
cout << "ptr2 - ptr1 = " << distance << " 个元素" << endl;
cout << "实际字节距离: " << (char*)ptr2 - (char*)ptr1 << " 字节" << endl;
// 3. 指针比较
cout << "\n指针比较:" << endl;
cout << "ptr1 < ptr2? " << (ptr1 < ptr2) << endl;
cout << "ptr1 > ptr2? " << (ptr1 > ptr2) << endl;
cout << "ptr1 == ptr1? " << (ptr1 == ptr1) << endl;
// 4. void指针的算术运算限制
cout << "\nvoid指针算术运算限制:" << endl;
void* voidPtr = arr;
// voidPtr++; // 错误:void指针不知道类型大小
// voidPtr = voidPtr + 1; // 错误
// 需要转换为具体类型
voidPtr = (char*)voidPtr + sizeof(int); // 正确
cout << "voidPtr移动一个int大小后: " << voidPtr << endl;
}
int main() {
demonstrateBasicPointers();
demonstratePointerArithmetic();
return 0;
}
10.2 指针与数组
10.2.1 指针与一维数组
cpp
#include <iostream>
using namespace std;
void demonstratePointersAndArrays() {
cout << "=== 指针与一维数组 ===" << endl;
// 1. 数组名作为指针
int arr[5] = {10, 20, 30, 40, 50};
cout << "数组元素:" << endl;
for (int i = 0; i < 5; i++) {
cout << "arr[" << i << "] = " << arr[i] << endl;
}
cout << "\n数组名的本质:" << endl;
cout << "arr = " << arr << " (数组首地址)" << endl;
cout << "&arr[0] = " << &arr[0] << " (第一个元素地址)" << endl;
cout << "arr == &arr[0]? " << (arr == &arr[0]) << endl;
// 2. 使用指针遍历数组
cout << "\n2. 使用指针遍历数组:" << endl;
// 方法1:指针作为迭代器
int* ptr = arr;
cout << "使用指针遍历: ";
for (int i = 0; i < 5; i++) {
cout << *ptr << " ";
ptr++; // 移动到下一个元素
}
cout << endl;
// 方法2:指针算术运算
cout << "使用指针算术: ";
for (int i = 0; i < 5; i++) {
cout << *(arr + i) << " ";
}
cout << endl;
// 3. 数组指针 vs 指针数组
cout << "\n3. 数组指针与指针数组:" << endl;
// 数组指针:指向整个数组的指针
int (*arrayPtr)[5] = &arr; // 指向包含5个int的数组
cout << "数组指针 arrayPtr = " << arrayPtr << endl;
cout << "*arrayPtr = " << *arrayPtr << " (等价于arr)" << endl;
cout << "(*arrayPtr)[2] = " << (*arrayPtr)[2] << endl;
// 指针数组:元素都是指针的数组
int x = 1, y = 2, z = 3;
int* ptrArray[3] = {&x, &y, &z};
cout << "\n指针数组元素:" << endl;
for (int i = 0; i < 3; i++) {
cout << "ptrArray[" << i << "] = " << ptrArray[i]
<< ", *ptrArray[" << i << "] = " << *ptrArray[i] << endl;
}
// 4. 数组作为函数参数(退化为指针)
cout << "\n4. 数组作为函数参数:" << endl;
auto printArray = [](int* arr, int size) {
cout << "在函数中: sizeof(arr) = " << sizeof(arr) << " (指针大小)" << endl;
cout << "数组元素: ";
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
};
cout << "在main中: sizeof(arr) = " << sizeof(arr) << " (数组总大小)" << endl;
printArray(arr, 5);
// 5. 指针和多维数组
cout << "\n5. 指针和多维数组:" << endl;
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 指向一维数组的指针
int (*rowPtr)[4] = matrix; // 指向包含4个int的数组
cout << "使用数组指针访问多维数组:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
cout << rowPtr[i][j] << "\t";
}
cout << endl;
}
}
void demonstrateArrayDecay() {
cout << "\n=== 数组退化(Array Decay)===" << endl;
// 数组退化为指针的各种情况
int arr[5] = {1, 2, 3, 4, 5};
cout << "1. 赋值给指针:" << endl;
int* ptr = arr; // 数组退化为指针
cout << "ptr = arr; // 数组名退化为指针" << endl;
cout << "\n2. 作为函数参数:" << endl;
cout << "void func(int arr[]) 等价于 void func(int* arr)" << endl;
cout << "\n3. 与指针比较:" << endl;
if (arr == &arr[0]) {
cout << "arr == &arr[0] 为真" << endl;
}
cout << "\n4. 但有几个例外(不会退化):" << endl;
cout << "a) sizeof(arr) = " << sizeof(arr) << " (得到数组总大小)" << endl;
cout << "b) &arr = " << &arr << " (得到整个数组的地址)" << endl;
// 整个数组的地址 vs 第一个元素的地址
cout << "\n整个数组地址与第一个元素地址:" << endl;
cout << "arr = " << arr << endl;
cout << "&arr = " << &arr << endl;
cout << "arr + 1 = " << arr + 1 << " (移动4字节)" << endl;
cout << "&arr + 1 = " << &arr + 1 << " (移动" << sizeof(arr) << "字节)" << endl;
// 类型不同
cout << "\n类型信息:" << endl;
cout << "typeid(arr).name() = " << typeid(arr).name() << endl;
cout << "typeid(&arr).name() = " << typeid(&arr).name() << endl;
}
// 字符串与指针
void demonstrateStringsAndPointers() {
cout << "\n=== 字符串与指针 ===" << endl;
// 1. C风格字符串
char str1[] = "Hello"; // 字符数组
const char* str2 = "World"; // 字符串字面量(只读)
cout << "字符数组: " << str1 << endl;
cout << "字符串指针: " << str2 << endl;
cout << "\n内存布局:" << endl;
cout << "str1地址: " << (void*)str1 << endl;
cout << "str2地址: " << (void*)str2 << endl;
cout << "str2指向的内容地址: " << (void*)str2 << endl;
// 2. 修改字符串
str1[0] = 'h'; // 可以修改,因为str1是数组
// str2[0] = 'w'; // 错误:字符串字面量是只读的
cout << "\n修改后:" << endl;
cout << "str1: " << str1 << endl;
// 3. 字符串数组
const char* colors[] = {
"Red",
"Green",
"Blue",
"Yellow",
"Purple"
};
cout << "\n字符串数组(实际上是指针数组):" << endl;
for (int i = 0; i < 5; i++) {
cout << colors[i] << " ";
}
cout << endl;
// 4. 字符串长度
cout << "\n字符串长度计算:" << endl;
const char* message = "C++ Programming";
int length = 0;
const char* p = message;
while (*p != '\0') {
length++;
p++;
}
cout << "字符串: " << message << endl;
cout << "长度: " << length << endl;
cout << "使用strlen: " << strlen(message) << endl;
// 5. 字符串复制
char source[] = "Copy this";
char destination[20];
char* destPtr = destination;
const char* srcPtr = source;
while (*srcPtr != '\0') {
*destPtr = *srcPtr;
destPtr++;
srcPtr++;
}
*destPtr = '\0'; // 添加终止符
cout << "\n字符串复制:" << endl;
cout << "源: " << source << endl;
cout << "目标: " << destination << endl;
}
int main() {
demonstratePointersAndArrays();
demonstrateArrayDecay();
demonstrateStringsAndPointers();
return 0;
}
10.2.2 指针与多维数组
cpp
#include <iostream>
#include <iomanip>
using namespace std;
void demonstrateMultidimensionalPointers() {
cout << "=== 指针与多维数组 ===" << endl;
// 1. 二维数组的内存布局
cout << "1. 二维数组的内存布局:" << endl;
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
cout << "3x4矩阵:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
cout << setw(4) << matrix[i][j];
}
cout << endl;
}
// 2. 二维数组在内存中是连续的
cout << "\n2. 内存连续性验证:" << endl;
int* flat = &matrix[0][0]; // 指向第一个元素
cout << "以一维数组方式访问:" << endl;
for (int i = 0; i < 12; i++) {
cout << flat[i] << " ";
if ((i + 1) % 4 == 0) cout << endl;
}
// 3. 指向一维数组的指针
cout << "\n3. 指向一维数组的指针:" << endl;
// 声明指向包含4个int的数组的指针
int (*rowPtr)[4] = matrix;
cout << "rowPtr指向包含4个int的数组" << endl;
cout << "rowPtr = " << rowPtr << endl;
cout << "rowPtr + 1 = " << rowPtr + 1 << " (移动一行)" << endl;
cout << "移动字节数: " << (char*)(rowPtr + 1) - (char*)rowPtr << endl;
// 使用这种指针访问数组
cout << "\n使用rowPtr访问:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
cout << setw(4) << rowPtr[i][j];
}
cout << endl;
}
// 4. 指针数组模拟二维数组
cout << "\n4. 指针数组模拟二维数组:" << endl;
int row1[4] = {1, 2, 3, 4};
int row2[4] = {5, 6, 7, 8};
int row3[4] = {9, 10, 11, 12};
int* ptrArray[3] = {row1, row2, row3}; // 指针数组
cout << "指针数组访问:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
cout << setw(4) << ptrArray[i][j];
}
cout << endl;
}
// 5. 动态二维数组
cout << "\n5. 动态二维数组:" << endl;
int rows = 3, cols = 4;
// 方法1:使用指针数组
int** dynamicMatrix = new int*[rows];
for (int i = 0; i < rows; i++) {
dynamicMatrix[i] = new int[cols];
}
// 初始化
int counter = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
dynamicMatrix[i][j] = counter++;
}
}
cout << "动态二维数组:" << endl;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << setw(4) << dynamicMatrix[i][j];
}
cout << endl;
}
// 释放内存
for (int i = 0; i < rows; i++) {
delete[] dynamicMatrix[i];
}
delete[] dynamicMatrix;
// 方法2:使用一维数组模拟
cout << "\n6. 使用一维数组模拟二维数组:" << endl;
int* flatMatrix = new int[rows * cols];
// 初始化
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
flatMatrix[i * cols + j] = i * cols + j + 1;
}
}
cout << "扁平化矩阵:" << endl;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << setw(4) << flatMatrix[i * cols + j];
}
cout << endl;
}
delete[] flatMatrix;
}
// 三维数组与指针
void demonstrate3DArraysAndPointers() {
cout << "\n=== 三维数组与指针 ===" << endl;
// 1. 静态三维数组
int cube[2][3][4] = {
{ // 第一层
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
},
{ // 第二层
{13, 14, 15, 16},
{17, 18, 19, 20},
{21, 22, 23, 24}
}
};
// 2. 指向二维数组的指针
int (*layerPtr)[3][4] = cube; // 指向包含3x4个int的二维数组
cout << "使用指针访问三维数组:" << endl;
for (int i = 0; i < 2; i++) {
cout << "第 " << i << " 层:" << endl;
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 4; k++) {
cout << setw(4) << layerPtr[i][j][k];
}
cout << endl;
}
cout << endl;
}
// 3. 三维数组的内存布局
cout << "三维数组的内存连续性验证:" << endl;
int* flat = &cube[0][0][0];
cout << "连续内存访问:" << endl;
for (int i = 0; i < 24; i++) {
cout << flat[i] << " ";
if ((i + 1) % 4 == 0) cout << " ";
if ((i + 1) % 12 == 0) cout << endl;
}
// 4. 动态三维数组
cout << "\n动态三维数组:" << endl;
int x = 2, y = 3, z = 4;
// 分配三维数组
int*** dynamicCube = new int**[x];
for (int i = 0; i < x; i++) {
dynamicCube[i] = new int*[y];
for (int j = 0; j < y; j++) {
dynamicCube[i][j] = new int[z];
}
}
// 初始化
int count = 1;
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
for (int k = 0; k < z; k++) {
dynamicCube[i][j][k] = count++;
}
}
}
// 显示
for (int i = 0; i < x; i++) {
cout << "第 " << i << " 层:" << endl;
for (int j = 0; j < y; j++) {
for (int k = 0; k < z; k++) {
cout << setw(4) << dynamicCube[i][j][k];
}
cout << endl;
}
cout << endl;
}
// 释放内存(必须按分配顺序的逆序)
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
delete[] dynamicCube[i][j];
}
delete[] dynamicCube[i];
}
delete[] dynamicCube;
}
// 数组指针与函数参数
void demonstrateArrayPointersAsParameters() {
cout << "\n=== 数组指针作为函数参数 ===" << endl;
// 1. 传递一维数组
auto print1DArray = [](int* arr, int size) {
cout << "一维数组: ";
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
};
int arr1D[5] = {1, 2, 3, 4, 5};
print1DArray(arr1D, 5);
// 2. 传递二维数组(必须指定列数)
auto print2DArray = [](int arr[][4], int rows) {
cout << "二维数组 (" << rows << "x4):" << endl;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 4; j++) {
cout << setw(4) << arr[i][j];
}
cout << endl;
}
};
int arr2D[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
print2DArray(arr2D, 3);
// 3. 使用指针传递二维数组
auto print2DArrayWithPointer = [](int (*arr)[4], int rows) {
cout << "使用数组指针传递:" << endl;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 4; j++) {
cout << setw(4) << arr[i][j];
}
cout << endl;
}
};
print2DArrayWithPointer(arr2D, 3);
// 4. 传递动态二维数组
auto printDynamic2DArray = [](int** arr, int rows, int cols) {
cout << "动态二维数组 (" << rows << "x" << cols << "):" << endl;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << setw(4) << arr[i][j];
}
cout << endl;
}
};
// 创建动态二维数组
int rows = 3, cols = 4;
int** dynamicArr = new int*[rows];
for (int i = 0; i < rows; i++) {
dynamicArr[i] = new int[cols];
for (int j = 0; j < cols; j++) {
dynamicArr[i][j] = i * cols + j + 1;
}
}
printDynamic2DArray(dynamicArr, rows, cols);
// 清理
for (int i = 0; i < rows; i++) {
delete[] dynamicArr[i];
}
delete[] dynamicArr;
}
int main() {
demonstrateMultidimensionalPointers();
demonstrate3DArraysAndPointers();
demonstrateArrayPointersAsParameters();
return 0;
}
10.3 指针与字符串
10.3.1 C风格字符串操作
cpp
#include <iostream>
#include <cstring> // C字符串函数
#include <cctype> // 字符处理
using namespace std;
void demonstrateCStringOperations() {
cout << "=== C风格字符串操作 ===" << endl;
// 1. 字符串声明和初始化
cout << "1. 字符串声明和初始化:" << endl;
char str1[] = "Hello"; // 字符数组
char str2[10] = "World"; // 指定大小的数组
char str3[] = {'H', 'i', '\0'}; // 手动添加终止符
const char* str4 = "C++"; // 字符串字面量(常量)
cout << "str1: " << str1 << endl;
cout << "str2: " << str2 << endl;
cout << "str3: " << str3 << endl;
cout << "str4: " << str4 << endl;
// 2. 字符串长度
cout << "\n2. 字符串长度:" << endl;
const char* text = "Programming";
cout << "字符串: " << text << endl;
cout << "strlen: " << strlen(text) << endl;
// 手动计算长度
int length = 0;
const char* p = text;
while (*p != '\0') {
length++;
p++;
}
cout << "手动计算: " << length << endl;
// 3. 字符串复制
cout << "\n3. 字符串复制:" << endl;
char source[] = "Copy this text";
char dest1[20];
char dest2[20];
// 使用strcpy
strcpy(dest1, source);
cout << "strcpy: " << dest1 << endl;
// 使用strncpy(安全版本)
strncpy(dest2, source, sizeof(dest2) - 1);
dest2[sizeof(dest2) - 1] = '\0'; // 确保终止符
cout << "strncpy: " << dest2 << endl;
// 4. 字符串连接
cout << "\n4. 字符串连接:" << endl;
char greeting[50] = "Hello";
char name[] = " Alice";
strcat(greeting, name);
cout << "strcat: " << greeting << endl;
// 安全版本
char safeGreeting[20] = "Hello";
strncat(safeGreeting, " World!", sizeof(safeGreeting) - strlen(safeGreeting) - 1);
cout << "strncat: " << safeGreeting << endl;
// 5. 字符串比较
cout << "\n5. 字符串比较:" << endl;
const char* s1 = "apple";
const char* s2 = "banana";
const char* s3 = "apple";
cout << "strcmp(\"apple\", \"banana\"): " << strcmp(s1, s2) << endl;
cout << "strcmp(\"banana\", \"apple\"): " << strcmp(s2, s1) << endl;
cout << "strcmp(\"apple\", \"apple\"): " << strcmp(s1, s3) << endl;
// 不区分大小写比较
cout << "strcasecmp(\"Hello\", \"hello\"): "
<< strcasecmp("Hello", "hello") << endl;
// 6. 字符串查找
cout << "\n6. 字符串查找:" << endl;
const char* haystack = "The quick brown fox jumps over the lazy dog";
const char* needle = "fox";
char* found = strstr(haystack, needle);
if (found) {
cout << "找到 '" << needle << "' 在位置: " << (found - haystack) << endl;
cout << "上下文: ..." << found << "..." << endl;
}
// 查找字符
char* charFound = strchr(haystack, 'q');
if (charFound) {
cout << "找到字符 'q' 在位置: " << (charFound - haystack) << endl;
}
// 从后往前查找
char* lastFound = strrchr(haystack, 'o');
if (lastFound) {
cout << "最后找到字符 'o' 在位置: " << (lastFound - haystack) << endl;
}
// 7. 字符串分割
cout << "\n7. 字符串分割:" << endl;
char data[] = "apple,banana,cherry,date,elderberry";
cout << "原始字符串: " << data << endl;
cout << "分割结果:" << endl;
char* token = strtok(data, ",");
int count = 1;
while (token != nullptr) {
cout << " " << count++ << ". " << token << endl;
token = strtok(nullptr, ",");
}
// 注意:strtok会修改原始字符串!
// 8. 字符串转换
cout << "\n8. 字符串转换:" << endl;
// 字符串转数值
const char* numStr = "123.45";
int intVal = atoi("123");
long longVal = atol("123456789");
double doubleVal = atof(numStr);
cout << "atoi(\"123\"): " << intVal << endl;
cout << "atol(\"123456789\"): " << longVal << endl;
cout << "atof(\"123.45\"): " << doubleVal << endl;
// 数值转字符串
char buffer[50];
int num = 255;
sprintf(buffer, "数字: %d, 十六进制: 0x%X", num, num);
cout << "sprintf: " << buffer << endl;
// 安全版本
char safeBuffer[50];
snprintf(safeBuffer, sizeof(safeBuffer),
"格式化: %d %.2f %s", 100, 3.14159, "test");
cout << "snprintf: " << safeBuffer << endl;
}
// 手动实现字符串函数
void demonstrateManualStringFunctions() {
cout << "\n=== 手动实现字符串函数 ===" << endl;
// 1. 字符串长度
auto myStrlen = [](const char* str) -> int {
int len = 0;
while (str[len] != '\0') {
len++;
}
return len;
};
cout << "myStrlen(\"Hello\"): " << myStrlen("Hello") << endl;
// 2. 字符串复制
auto myStrcpy = [](char* dest, const char* src) -> char* {
char* start = dest;
while ((*dest++ = *src++) != '\0');
return start;
};
char dest[20];
myStrcpy(dest, "Copied!");
cout << "myStrcpy: " << dest << endl;
// 3. 字符串比较
auto myStrcmp = [](const char* s1, const char* s2) -> int {
while (*s1 && (*s1 == *s2)) {
s1++;
s2++;
}
return *(unsigned char*)s1 - *(unsigned char*)s2;
};
cout << "myStrcmp(\"abc\", \"abd\"): " << myStrcmp("abc", "abd") << endl;
// 4. 字符串连接
auto myStrcat = [](char* dest, const char* src) -> char* {
char* start = dest;
// 找到dest的结尾
while (*dest != '\0') {
dest++;
}
// 复制src
while ((*dest++ = *src++) != '\0');
return start;
};
char catDest[30] = "Hello";
myStrcat(catDest, " World!");
cout << "myStrcat: " << catDest << endl;
// 5. 查找子串
auto myStrstr = [](const char* haystack, const char* needle) -> const char* {
if (*needle == '\0') {
return haystack;
}
for (; *haystack != '\0'; haystack++) {
const char* h = haystack;
const char* n = needle;
while (*h && *n && (*h == *n)) {
h++;
n++;
}
if (*n == '\0') {
return haystack;
}
}
return nullptr;
};
const char* result = myStrstr("Hello World", "World");
if (result) {
cout << "myStrstr找到: " << result << endl;
}
}
// 字符串处理应用
void demonstrateStringApplications() {
cout << "\n=== 字符串处理应用 ===" << endl;
// 1. 统计单词
cout << "1. 统计单词数量:" << endl;
char sentence[] = "C++ is a powerful programming language";
int wordCount = 0;
bool inWord = false;
for (int i = 0; sentence[i] != '\0'; i++) {
if (isspace(sentence[i])) {
inWord = false;
} else if (!inWord) {
wordCount++;
inWord = true;
}
}
cout << "句子: " << sentence << endl;
cout << "单词数: " << wordCount << endl;
// 2. 字符串反转
cout << "\n2. 字符串反转:" << endl;
char text[] = "Hello World";
cout << "原始: " << text << endl;
int len = strlen(text);
for (int i = 0; i < len / 2; i++) {
swap(text[i], text[len - 1 - i]);
}
cout << "反转: " << text << endl;
// 3. 回文检查
cout << "\n3. 回文检查:" << endl;
char palindrome[] = "A man a plan a canal Panama";
char cleaned[100];
int cleanIndex = 0;
// 清理字符串(移除空格,转小写)
for (int i = 0; palindrome[i] != '\0'; i++) {
if (isalpha(palindrome[i])) {
cleaned[cleanIndex++] = tolower(palindrome[i]);
}
}
cleaned[cleanIndex] = '\0';
// 检查回文
bool isPalindrome = true;
int cleanLen = strlen(cleaned);
for (int i = 0; i < cleanLen / 2; i++) {
if (cleaned[i] != cleaned[cleanLen - 1 - i]) {
isPalindrome = false;
break;
}
}
cout << "字符串: " << palindrome << endl;
cout << "清理后: " << cleaned << endl;
cout << "是否回文: " << (isPalindrome ? "是" : "否") << endl;
// 4. 简单加密解密
cout << "\n4. 凯撒密码加密解密:" << endl;
char message[] = "Hello World";
int shift = 3;
cout << "原始消息: " << message << endl;
// 加密
char encrypted[100];
for (int i = 0; message[i] != '\0'; i++) {
if (isalpha(message[i])) {
char base = islower(message[i]) ? 'a' : 'A';
encrypted[i] = base + (message[i] - base + shift) % 26;
} else {
encrypted[i] = message[i];
}
}
encrypted[strlen(message)] = '\0';
cout << "加密后: " << encrypted << endl;
// 解密
char decrypted[100];
for (int i = 0; encrypted[i] != '\0'; i++) {
if (isalpha(encrypted[i])) {
char base = islower(encrypted[i]) ? 'a' : 'A';
decrypted[i] = base + (encrypted[i] - base - shift + 26) % 26;
} else {
decrypted[i] = encrypted[i];
}
}
decrypted[strlen(encrypted)] = '\0';
cout << "解密后: " << decrypted << endl;
}
int main() {
demonstrateCStringOperations();
demonstrateManualStringFunctions();
demonstrateStringApplications();
return 0;
}
10.4 函数指针
10.4.1 函数指针基础
cpp
#include <iostream>
#include <cmath>
#include <functional> // C++11 std::function
using namespace std;
// 函数指针:指向函数的指针
void demonstrateFunctionPointers() {
cout << "=== 函数指针基础 ===" << endl;
// 1. 函数指针的声明
cout << "1. 函数指针的声明:" << endl;
// 函数原型
int add(int a, int b);
double multiply(double a, double b);
void printMessage(const char* message);
// 声明函数指针
int (*funcPtr1)(int, int); // 指向返回int,接受两个int的函数
double (*funcPtr2)(double, double); // 指向返回double,接受两个double的函数
void (*funcPtr3)(const char*); // 指向返回void,接受const char*的函数
// 2. 初始化函数指针
cout << "\n2. 初始化函数指针:" << endl;
// 定义实际函数
auto addImpl = [](int a, int b) -> int { return a + b; };
auto multiplyImpl = [](double a, double b) -> double { return a * b; };
auto printImpl = [](const char* msg) { cout << "消息: " << msg << endl; };
// 初始化函数指针
funcPtr1 = addImpl;
funcPtr2 = multiplyImpl;
funcPtr3 = printImpl;
// 3. 通过函数指针调用函数
cout << "\n3. 通过函数指针调用函数:" << endl;
int sum = funcPtr1(10, 20);
cout << "add(10, 20) = " << sum << endl;
double product = funcPtr2(3.14, 2.0);
cout << "multiply(3.14, 2.0) = " << product << endl;
funcPtr3("Hello from function pointer!");
// 4. 函数指针作为参数
cout << "\n4. 函数指针作为参数:" << endl;
auto calculator = [](double a, double b, double (*operation)(double, double)) {
return operation(a, b);
};
// 定义一些数学运算
auto power = [](double a, double b) -> double { return pow(a, b); };
auto maximum = [](double a, double b) -> double { return a > b ? a : b; };
cout << "5^3 = " << calculator(5, 3, power) << endl;
cout << "max(7.5, 3.2) = " << calculator(7.5, 3.2, maximum) << endl;
// 5. 函数指针数组
cout << "\n5. 函数指针数组:" << endl;
// 定义一些运算函数
auto addFunc = [](double a, double b) -> double { return a + b; };
auto subtractFunc = [](double a, double b) -> double { return a - b; };
auto multiplyFunc = [](double a, double b) -> double { return a * b; };
auto divideFunc = [](double a, double b) -> double {
return b != 0 ? a / b : 0;
};
// 创建函数指针数组
double (*operations[])(double, double) = {
addFunc, subtractFunc, multiplyFunc, divideFunc
};
const char* operationNames[] = {"加", "减", "乘", "除"};
double x = 10.0, y = 4.0;
for (int i = 0; i < 4; i++) {
cout << x << " " << operationNames[i] << " " << y
<< " = " << operations[i](x, y) << endl;
}
// 6. 返回函数指针的函数
cout << "\n6. 返回函数指针的函数:" << endl;
auto getOperation = [](char op) -> double (*)(double, double) {
switch (op) {
case '+': return addFunc;
case '-': return subtractFunc;
case '*': return multiplyFunc;
case '/': return divideFunc;
default: return nullptr;
}
};
char ops[] = {'+', '-', '*', '/'};
for (char op : ops) {
double (*func)(double, double) = getOperation(op);
if (func) {
cout << "8 " << op << " 2 = " << func(8, 2) << endl;
}
}
}
// 函数指针与回调函数
void demonstrateCallbacks() {
cout << "\n=== 回调函数 ===" << endl;
// 1. 排序回调
cout << "1. 排序回调示例:" << endl;
// 比较函数类型
typedef bool (*CompareFunc)(int, int);
// 不同的比较函数
auto ascending = [](int a, int b) -> bool { return a < b; };
auto descending = [](int a, int b) -> bool { return a > b; };
auto byLastDigit = [](int a, int b) -> bool { return a % 10 < b % 10; };
// 通用排序函数(使用回调)
auto bubbleSort = [](int arr[], int size, CompareFunc compare) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (compare(arr[j + 1], arr[j])) {
swap(arr[j], arr[j + 1]);
}
}
}
};
int numbers[] = {42, 17, 89, 33, 56, 21, 78, 5, 91, 12};
int size = sizeof(numbers) / sizeof(numbers[0]);
cout << "原始数组: ";
for (int i = 0; i < size; i++) cout << numbers[i] << " ";
cout << endl;
// 升序排序
int ascCopy[10];
copy(numbers, numbers + size, ascCopy);
bubbleSort(ascCopy, size, ascending);
cout << "升序排序: ";
for (int i = 0; i < size; i++) cout << ascCopy[i] << " ";
cout << endl;
// 降序排序
int descCopy[10];
copy(numbers, numbers + size, descCopy);
bubbleSort(descCopy, size, descending);
cout << "降序排序: ";
for (int i = 0; i < size; i++) cout << descCopy[i] << " ";
cout << endl;
// 按个位数排序
int digitCopy[10];
copy(numbers, numbers + size, digitCopy);
bubbleSort(digitCopy, size, byLastDigit);
cout << "按个位数排序: ";
for (int i = 0; i < size; i++) cout << digitCopy[i] << " ";
cout << endl;
// 2. 事件处理回调
cout << "\n2. 事件处理回调示例:" << endl;
// 事件类型
enum Event { CLICK, HOVER, KEY_PRESS, MOUSE_MOVE };
// 事件处理函数类型
typedef void (*EventHandler)(Event, void*);
// 模拟事件系统
class EventSystem {
private:
EventHandler handlers[4] = {nullptr};
void* userData[4] = {nullptr};
public:
void registerHandler(Event event, EventHandler handler, void* data = nullptr) {
handlers[event] = handler;
userData[event] = data;
}
void triggerEvent(Event event) {
if (handlers[event]) {
handlers[event](event, userData[event]);
}
}
};
// 事件处理函数
auto clickHandler = [](Event e, void* data) {
cout << "点击事件处理";
if (data) {
cout << ",数据: " << *(int*)data;
}
cout << endl;
};
auto keyHandler = [](Event e, void* data) {
cout << "按键事件处理";
if (data) {
char* key = (char*)data;
cout << ",按键: " << *key;
}
cout << endl;
};
// 使用事件系统
EventSystem system;
int clickData = 42;
char keyData = 'A';
system.registerHandler(CLICK, clickHandler, &clickData);
system.registerHandler(KEY_PRESS, keyHandler, &keyData);
system.triggerEvent(CLICK);
system.triggerEvent(KEY_PRESS);
// 3. 定时器回调
cout << "\n3. 定时器回调示例:" << endl;
typedef void (*TimerCallback)(int, void*);
// 模拟定时器
class Timer {
private:
TimerCallback callback;
void* userData;
int interval;
int count;
public:
Timer(TimerCallback cb, void* data = nullptr, int interv = 1)
: callback(cb), userData(data), interval(interv), count(0) {}
void tick() {
count++;
if (count % interval == 0) {
if (callback) {
callback(count, userData);
}
}
}
};
auto printTick = [](int tick, void* data) {
cout << "定时器触发,次数: " << tick;
if (data) {
cout << ",消息: " << (const char*)data;
}
cout << endl;
};
const char* message = "定时器工作正常";
Timer timer(printTick, (void*)message, 3);
cout << "模拟10次tick:" << endl;
for (int i = 0; i < 10; i++) {
timer.tick();
}
}
// C++11的替代方案:std::function
void demonstrateStdFunction() {
cout << "\n=== C++11 std::function ===" << endl;
// 1. std::function的基本使用
cout << "1. std::function的基本使用:" << endl;
#include <functional>
// 声明函数对象
function<int(int, int)> func;
// 可以绑定各种可调用对象
func = [](int a, int b) { return a + b; };
cout << "lambda: " << func(10, 20) << endl;
// 普通函数
int subtract(int a, int b) { return a - b; }
func = subtract;
cout << "普通函数: " << func(20, 10) << endl;
// 函数对象(仿函数)
struct Multiplier {
int factor;
Multiplier(int f) : factor(f) {}
int operator()(int a, int b) const {
return a * b * factor;
}
};
func = Multiplier(2);
cout << "函数对象: " << func(3, 4) << endl;
// 2. 更灵活的参数传递
cout << "\n2. 更灵活的回调系统:" << endl;
class EventHandler {
private:
function<void(int, const string&)> callback;
public:
void setCallback(function<void(int, const string&)> cb) {
callback = cb;
}
void trigger(int id, const string& message) {
if (callback) {
callback(id, message);
}
}
};
EventHandler handler;
// 设置不同的回调
handler.setCallback([](int id, const string& msg) {
cout << "事件 " << id << ": " << msg << endl;
});
handler.trigger(1, "用户登录");
handler.trigger(2, "文件保存");
// 3. 函数组合
cout << "\n3. 函数组合:" << endl;
function<double(double)> f = [](double x) { return x * 2; };
function<double(double)> g = [](double x) { return x + 3; };
// 组合函数 g(f(x))
auto compose = [](function<double(double)> f, function<double(double)> g) {
return [f, g](double x) { return g(f(x)); };
};
auto h = compose(f, g);
cout << "f(x) = 2x, g(x) = x + 3" << endl;
cout << "g(f(5)) = " << h(5) << endl;
// 4. 与函数指针的比较
cout << "\n4. std::function vs 函数指针:" << endl;
cout << "函数指针的优点:" << endl;
cout << " - 更简单,更轻量" << endl;
cout << " - 与C兼容" << endl;
cout << " - 编译时类型检查" << endl;
cout << "\nstd::function的优点:" << endl;
cout << " - 可以存储任何可调用对象" << endl;
cout << " - 更安全,避免空指针" << endl;
cout << " - 支持函数组合" << endl;
cout << " - 更好的类型擦除" << endl;
}
int main() {
demonstrateFunctionPointers();
demonstrateCallbacks();
demonstrateStdFunction();
return 0;
}
10.5 动态内存管理
10.5.1 new和delete操作符
cpp
#include <iostream>
#include <cstdlib> // malloc, free
#include <new> // bad_alloc, nothrow
using namespace std;
void demonstrateNewDelete() {
cout << "=== new和delete操作符 ===" << endl;
// 1. 基本动态内存分配
cout << "1. 基本动态内存分配:" << endl;
// 分配单个整数
int* singleInt = new int;
*singleInt = 42;
cout << "单个整数: " << *singleInt << endl;
delete singleInt; // 释放单个对象
singleInt = nullptr; // 好习惯
// 分配整数数组
int* intArray = new int[5];
for (int i = 0; i < 5; i++) {
intArray[i] = i * 10;
}
cout << "整数数组: ";
for (int i = 0; i < 5; i++) {
cout << intArray[i] << " ";
}
cout << endl;
delete[] intArray; // 释放数组
intArray = nullptr;
// 2. 对象动态分配
cout << "\n2. 对象动态分配:" << endl;
class Point {
public:
int x, y;
Point(int x = 0, int y = 0) : x(x), y(y) {
cout << "Point构造函数 (" << x << ", " << y << ")" << endl;
}
~Point() {
cout << "Point析构函数 (" << x << ", " << y << ")" << endl;
}
void print() const {
cout << "(" << x << ", " << y << ")" << endl;
}
};
// 分配单个对象
Point* p1 = new Point(10, 20);
p1->print();
delete p1;
p1 = nullptr;
// 分配对象数组
Point* points = new Point[3];
for (int i = 0; i < 3; i++) {
points[i].x = i * 10;
points[i].y = i * 20;
}
cout << "对象数组: ";
for (int i = 0; i < 3; i++) {
points[i].print();
}
delete[] points; // 调用每个对象的析构函数
points = nullptr;
// 3. 分配失败处理
cout << "\n3. 分配失败处理:" << endl;
// 方法1:使用nothrow
int* hugeArray = new(nothrow) int[1000000000000LL]; // 尝试分配巨大内存
if (hugeArray == nullptr) {
cout << "内存分配失败 (nothrow版本)" << endl;
} else {
delete[] hugeArray;
}
// 方法2:捕获bad_alloc异常
try {
int* anotherHuge = new int[1000000000000LL];
delete[] anotherHuge;
} catch (const bad_alloc& e) {
cout << "内存分配失败 (异常版本): " << e.what() << endl;
}
// 4. 定位new(Placement new)
cout << "\n4. 定位new (Placement new):" << endl;
// 预分配内存缓冲区
char buffer[sizeof(Point) * 3];
// 在缓冲区中构造对象
Point* p2 = new(buffer) Point(1, 2);
Point* p3 = new(buffer + sizeof(Point)) Point(3, 4);
Point* p4 = new(buffer + 2 * sizeof(Point)) Point(5, 6);
p2->print();
p3->print();
p4->print();
// 需要手动调用析构函数
p2->~Point();
p3->~Point();
p4->~Point();
// 注意:不需要delete,因为内存不是new分配的
// 5. 多维动态数组
cout << "\n5. 多维动态数组:" << endl;
int rows = 3, cols = 4;
// 分配二维数组
int** matrix = new int*[rows];
for (int i = 0; i < rows; i++) {
matrix[i] = new int[cols];
}
// 初始化
int counter = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = counter++;
}
}
// 显示
cout << "动态二维数组:" << endl;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << matrix[i][j] << "\t";
}
cout << endl;
}
// 释放内存(逆序)
for (int i = 0; i < rows; i++) {
delete[] matrix[i];
}
delete[] matrix;
}
// 与malloc/free的对比
void demonstrateMallocFree() {
cout << "\n=== 与malloc/free的对比 ===" << endl;
// 1. malloc/free的基本使用
cout << "1. malloc/free的基本使用:" << endl;
// 分配单个整数
int* p1 = (int*)malloc(sizeof(int));
if (p1 != nullptr) {
*p1 = 100;
cout << "malloc分配: " << *p1 << endl;
free(p1);
p1 = nullptr;
}
// 分配整数数组
int* arr = (int*)malloc(5 * sizeof(int));
if (arr != nullptr) {
for (int i = 0; i < 5; i++) {
arr[i] = i * 5;
}
cout << "malloc数组: ";
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
cout << endl;
free(arr);
arr = nullptr;
}
// 重新分配内存
int* dynamic = (int*)malloc(3 * sizeof(int));
if (dynamic != nullptr) {
for (int i = 0; i < 3; i++) dynamic[i] = i + 1;
cout << "原始数组: ";
for (int i = 0; i < 3; i++) cout << dynamic[i] << " ";
cout << endl;
// 扩大数组
dynamic = (int*)realloc(dynamic, 6 * sizeof(int));
if (dynamic != nullptr) {
for (int i = 3; i < 6; i++) dynamic[i] = i + 1;
cout << "扩展后: ";
for (int i = 0; i < 6; i++) cout << dynamic[i] << " ";
cout << endl;
}
free(dynamic);
dynamic = nullptr;
}
// 2. new/delete vs malloc/free的区别
cout << "\n2. new/delete vs malloc/free的区别:" << endl;
class ComplexObject {
public:
int* data;
ComplexObject(int size) {
data = new int[size];
cout << "构造函数调用" << endl;
}
~ComplexObject() {
delete[] data;
cout << "析构函数调用" << endl;
}
};
// 使用new/delete(正确)
cout << "使用new/delete:" << endl;
ComplexObject* obj1 = new ComplexObject(10);
delete obj1;
// 使用malloc/free(错误:不会调用构造函数和析构函数)
cout << "\n使用malloc/free:" << endl;
ComplexObject* obj2 = (ComplexObject*)malloc(sizeof(ComplexObject));
// 构造函数没有被调用!
// obj2->data = new int[10]; // 需要手动初始化
// 手动调用构造函数(C++11之前的方式)
// new(obj2) ComplexObject(10);
// 手动调用析构函数
// obj2->~ComplexObject();
free(obj2);
// 3. 内存泄漏检测
cout << "\n3. 内存泄漏检测(简化示例):" << endl;
class MemoryTracker {
private:
static int allocationCount;
static int deallocationCount;
public:
static void* trackAlloc(size_t size) {
allocationCount++;
void* ptr = malloc(size);
cout << "分配 #" << allocationCount << ": " << size
<< " 字节, 地址: " << ptr << endl;
return ptr;
}
static void trackFree(void* ptr) {
if (ptr != nullptr) {
deallocationCount++;
cout << "释放 #" << deallocationCount
<< ": 地址: " << ptr << endl;
free(ptr);
}
}
static void report() {
cout << "\n内存追踪报告:" << endl;
cout << "总分配次数: " << allocationCount << endl;
cout << "总释放次数: " << deallocationCount << endl;
cout << "潜在泄漏: " << (allocationCount - deallocationCount) << endl;
}
};
int MemoryTracker::allocationCount = 0;
int MemoryTracker::deallocationCount = 0;
// 使用追踪器
int* tracked1 = (int*)MemoryTracker::trackAlloc(sizeof(int));
int* tracked2 = (int*)MemoryTracker::trackAlloc(10 * sizeof(int));
MemoryTracker::trackFree(tracked1);
// 故意不释放tracked2来模拟内存泄漏
MemoryTracker::report();
cout << "\n=== 总结 ===" << endl;
cout << "new/delete 的优点:" << endl;
cout << " - 自动调用构造函数/析构函数" << endl;
cout << " - 类型安全" << endl;
cout << " - 自动计算大小" << endl;
cout << " - 支持异常" << endl;
cout << "\nmalloc/free 的适用场景:" << endl;
cout << " - 与C代码交互" << endl;
cout << " - 需要realloc功能" << endl;
cout << " - 极致的性能要求(某些情况)" << endl;
}
// 智能指针(C++11)
#include <memory>
void demonstrateSmartPointers() {
cout << "\n=== 智能指针(C++11)===" << endl;
// 1. unique_ptr(独占所有权)
cout << "1. unique_ptr(独占所有权):" << endl;
// 创建unique_ptr
unique_ptr<int> u1(new int(42));
cout << "u1: " << *u1 << endl;
// 移动语义(转移所有权)
unique_ptr<int> u2 = move(u1);
if (!u1) {
cout << "u1变为空(所有权转移)" << endl;
}
cout << "u2: " << *u2 << endl;
// 数组版本
unique_ptr<int[]> u3(new int[5]);
for (int i = 0; i < 5; i++) {
u3[i] = i * 10;
}
cout << "u3数组: ";
for (int i = 0; i < 5; i++) {
cout << u3[i] << " ";
}
cout << endl;
// make_unique(C++14)
#if __cplusplus >= 201402L
auto u4 = make_unique<double>(3.14159);
cout << "make_unique: " << *u4 << endl;
auto u5 = make_unique<int[]>(3);
for (int i = 0; i < 3; i++) u5[i] = i * 100;
#endif
// 2. shared_ptr(共享所有权)
cout << "\n2. shared_ptr(共享所有权):" << endl;
class Resource {
public:
string name;
Resource(const string& n) : name(n) {
cout << "创建资源: " << name << endl;
}
~Resource() {
cout << "销毁资源: " << name << endl;
}
};
// 创建shared_ptr
shared_ptr<Resource> s1 = make_shared<Resource>("资源A");
// 共享所有权
shared_ptr<Resource> s2 = s1;
shared_ptr<Resource> s3 = s2;
cout << "引用计数: " << s1.use_count() << endl;
// 当所有shared_ptr都销毁时,资源才会被释放
s1.reset();
cout << "s1释放后引用计数: " << s2.use_count() << endl;
s2.reset();
cout << "s2释放后引用计数: " << s3.use_count() << endl;
s3.reset(); // 资源在这里被销毁
cout << "所有shared_ptr已释放" << endl;
// 3. weak_ptr(弱引用)
cout << "\n3. weak_ptr(弱引用):" << endl;
shared_ptr<Resource> shared = make_shared<Resource>("共享资源");
weak_ptr<Resource> weak = shared;
cout << "原始引用计数: " << shared.use_count() << endl;
cout << "weak_ptr不增加引用计数" << endl;
// 使用weak_ptr前需要转换为shared_ptr
if (auto temp = weak.lock()) {
cout << "通过weak_ptr访问: " << temp->name << endl;
}
// 释放共享所有权
shared.reset();
// 检查weak_ptr是否还有效
if (weak.expired()) {
cout << "weak_ptr已过期" << endl;
}
// 4. 智能指针与动态数组
cout << "\n4. 智能指针与动态数组:" << endl;
// 对于数组,使用unique_ptr<T[]>或shared_ptr(带自定义删除器)
unique_ptr<int[]> smartArray(new int[10]);
for (int i = 0; i < 10; i++) {
smartArray[i] = i * 10;
}
cout << "智能指针数组: ";
for (int i = 0; i < 10; i++) {
cout << smartArray[i] << " ";
}
cout << endl;
// 5. 自定义删除器
cout << "\n5. 自定义删除器:" << endl;
// 文件指针的自定义删除器
auto fileDeleter = [](FILE* f) {
if (f) {
fclose(f);
cout << "文件已关闭" << endl;
}
};
unique_ptr<FILE, decltype(fileDeleter)> filePtr(fopen("test.txt", "w"), fileDeleter);
if (filePtr) {
fprintf(filePtr.get(), "Hello, Smart Pointer!");
cout << "文件写入完成" << endl;
}
cout << "\n=== 智能指针的优点 ===" << endl;
cout << "1. 自动内存管理,防止内存泄漏" << endl;
cout << "2. 异常安全" << endl;
cout << "3. 明确的所有权语义" << endl;
cout << "4. 避免悬垂指针" << endl;
cout << "5. 简化代码" << endl;
}
int main() {
demonstrateNewDelete();
demonstrateMallocFree();
demonstrateSmartPointers();
return 0;
}
10.5.2 动态内存管理的最佳实践
cpp
#include <iostream>
#include <memory>
#include <vector>
#include <stdexcept>
using namespace std;
class MemoryManager {
private:
struct AllocationInfo {
void* ptr;
size_t size;
const char* file;
int line;
const char* function;
AllocationInfo(void* p, size_t s, const char* f, int l, const char* fn)
: ptr(p), size(s), file(f), line(l), function(fn) {}
};
static vector<AllocationInfo> allocations;
public:
// 追踪分配
static void* trackAlloc(size_t size, const char* file, int line, const char* function) {
void* ptr = malloc(size);
if (ptr) {
allocations.emplace_back(ptr, size, file, line, function);
}
return ptr;
}
// 追踪释放
static void trackFree(void* ptr) {
if (ptr) {
// 从列表中移除
for (auto it = allocations.begin(); it != allocations.end(); ++it) {
if (it->ptr == ptr) {
allocations.erase(it);
free(ptr);
return;
}
}
cout << "警告:尝试释放未追踪的指针!" << endl;
free(ptr);
}
}
// 报告内存泄漏
static void reportLeaks() {
if (allocations.empty()) {
cout << "未检测到内存泄漏" << endl;
} else {
cout << "检测到 " << allocations.size() << " 处内存泄漏:" << endl;
for (const auto& alloc : allocations) {
cout << " 泄漏 " << alloc.size << " 字节在 "
<< alloc.file << ":" << alloc.line
<< " (" << alloc.function << ")" << endl;
}
}
}
// 重置追踪器
static void reset() {
allocations.clear();
}
};
vector<MemoryManager::AllocationInfo> MemoryManager::allocations;
// 重载new/delete操作符进行追踪
void* operator new(size_t size, const char* file, int line) {
void* ptr = MemoryManager::trackAlloc(size, file, line, __func__);
if (!ptr) throw bad_alloc();
return ptr;
}
void* operator new[](size_t size, const char* file, int line) {
return operator new(size, file, line);
}
void operator delete(void* ptr) noexcept {
MemoryManager::trackFree(ptr);
}
void operator delete[](void* ptr) noexcept {
MemoryManager::trackFree(ptr);
}
// 宏简化使用
#define new new(__FILE__, __LINE__)
void demonstrateMemoryBestPractices() {
cout << "=== 动态内存管理的最佳实践 ===" << endl;
// 1. RAII(资源获取即初始化)原则
cout << "\n1. RAII(资源获取即初始化)原则:" << endl;
class RAIIFile {
private:
FILE* file;
public:
RAIIFile(const char* filename, const char* mode) {
file = fopen(filename, mode);
if (!file) {
throw runtime_error("无法打开文件");
}
cout << "文件已打开" << endl;
}
~RAIIFile() {
if (file) {
fclose(file);
cout << "文件已关闭" << endl;
}
}
// 禁止拷贝
RAIIFile(const RAIIFile&) = delete;
RAIIFile& operator=(const RAIIFile&) = delete;
// 允许移动
RAIIFile(RAIIFile&& other) noexcept : file(other.file) {
other.file = nullptr;
}
RAIIFile& operator=(RAIIFile&& other) noexcept {
if (this != &other) {
if (file) fclose(file);
file = other.file;
other.file = nullptr;
}
return *this;
}
void write(const string& content) {
if (file) {
fprintf(file, "%s", content.c_str());
}
}
};
try {
RAIIFile file("test.txt", "w");
file.write("RAII示例\n");
// 不需要手动关闭文件,析构函数会自动处理
} catch (const exception& e) {
cout << "错误: " << e.what() << endl;
}
// 2. 内存池(简化版)
cout << "\n2. 内存池(简化版):" << endl;
class MemoryPool {
private:
struct Block {
Block* next;
};
Block* freeList;
vector<void*> allocatedBlocks;
size_t blockSize;
size_t poolSize;
public:
MemoryPool(size_t blockSize, size_t numBlocks)
: blockSize(max(blockSize, sizeof(Block))), poolSize(blockSize * numBlocks) {
// 分配大块内存
char* pool = static_cast<char*>(malloc(poolSize));
if (!pool) throw bad_alloc();
allocatedBlocks.push_back(pool);
freeList = nullptr;
// 将内存块添加到空闲链表
for (int i = numBlocks - 1; i >= 0; i--) {
Block* block = reinterpret_cast<Block*>(pool + i * blockSize);
block->next = freeList;
freeList = block;
}
cout << "内存池已创建: " << numBlocks
<< " 个块,每块 " << blockSize << " 字节" << endl;
}
~MemoryPool() {
for (void* block : allocatedBlocks) {
free(block);
}
cout << "内存池已销毁" << endl;
}
void* allocate() {
if (!freeList) {
cout << "内存池耗尽" << endl;
return nullptr;
}
Block* block = freeList;
freeList = freeList->next;
cout << "从内存池分配: " << block << endl;
return block;
}
void deallocate(void* ptr) {
if (ptr) {
Block* block = static_cast<Block*>(ptr);
block->next = freeList;
freeList = block;
cout << "返回到内存池: " << ptr << endl;
}
}
};
// 使用内存池
MemoryPool pool(sizeof(int), 5);
int* p1 = static_cast<int*>(pool.allocate());
int* p2 = static_cast<int*>(pool.allocate());
int* p3 = static_cast<int*>(pool.allocate());
if (p1) *p1 = 100;
if (p2) *p2 = 200;
if (p3) *p3 = 300;
pool.deallocate(p2);
pool.deallocate(p1);
int* p4 = static_cast<int*>(pool.allocate());
if (p4) *p4 = 400;
// 3. 避免常见错误
cout << "\n3. 避免常见错误:" << endl;
// 错误1:忘记检查分配失败
auto safeNew = [](size_t size) -> void* {
void* ptr = malloc(size);
if (!ptr) {
throw bad_alloc();
}
return ptr;
};
// 错误2:不匹配的new/delete
class CorrectDeallocation {
public:
void demonstrate() {
// 单个对象
int* single = new int;
delete single; // 不是delete[]
// 数组
int* array = new int[10];
delete[] array; // 不是delete
// 使用智能指针避免问题
auto smartSingle = make_unique<int>(42);
auto smartArray = make_unique<int[]>(10);
}
};
// 错误3:双重释放
auto noDoubleFree = []() {
int* ptr = new int(42);
delete ptr;
ptr = nullptr; // 立即设为nullptr
// delete ptr; // 安全:删除nullptr是空操作
};
// 4. 内存对齐
cout << "\n4. 内存对齐:" << endl;
struct AlignedData {
alignas(16) double data1; // 16字节对齐
alignas(8) int data2; // 8字节对齐
char data3;
};
cout << "AlignedData大小: " << sizeof(AlignedData) << endl;
cout << "对齐要求: " << alignof(AlignedData) << endl;
// 对齐的动态内存分配
void* alignedMemory = aligned_alloc(16, 1024); // C++17
if (alignedMemory) {
cout << "对齐内存分配成功: " << alignedMemory << endl;
free(alignedMemory);
}
// 5. 自定义内存分配器(简化版)
cout << "\n5. 自定义内存分配器:" << endl;
template<typename T>
class SimpleAllocator {
private:
MemoryPool& pool;
public:
using value_type = T;
SimpleAllocator(MemoryPool& p) : pool(p) {}
template<typename U>
SimpleAllocator(const SimpleAllocator<U>& other) : pool(other.pool) {}
T* allocate(size_t n) {
if (n != 1) {
throw bad_alloc(); // 简化:只支持单个元素
}
return static_cast<T*>(pool.allocate());
}
void deallocate(T* p, size_t n) {
pool.deallocate(p);
}
template<typename U>
bool operator==(const SimpleAllocator<U>& other) const {
return &pool == &other.pool;
}
template<typename U>
bool operator!=(const SimpleAllocator<U>& other) const {
return !(*this == other);
}
};
// 使用自定义分配器的vector
MemoryPool intPool(sizeof(int), 100);
vector<int, SimpleAllocator<int>> customVector({1, 2, 3, 4, 5}, SimpleAllocator<int>(intPool));
cout << "使用自定义分配器的vector: ";
for (int num : customVector) {
cout << num << " ";
}
cout << endl;
}
// 内存泄漏检测演示
void demonstrateMemoryLeakDetection() {
cout << "\n=== 内存泄漏检测演示 ===" << endl;
// 启用内存追踪
MemoryManager::reset();
// 模拟内存泄漏
int* leaked1 = new int(100);
int* leaked2 = new int[10];
// 正常分配和释放
int* normal = new int(200);
delete normal;
// 报告泄漏
MemoryManager::reportLeaks();
// 清理泄漏(在实际程序中应该修复泄漏)
delete leaked1;
delete[] leaked2;
MemoryManager::reset();
}
// 性能考虑
void demonstratePerformanceConsiderations() {
cout << "\n=== 性能考虑 ===" << endl;
const int ITERATIONS = 1000000;
// 1. 测量new/delete的性能开销
auto start = chrono::high_resolution_clock::now();
for (int i = 0; i < ITERATIONS; i++) {
int* ptr = new int(i);
delete ptr;
}
auto end = chrono::high_resolution_clock::now();
auto duration1 = chrono::duration_cast<chrono::milliseconds>(end - start);
cout << "new/delete循环 " << ITERATIONS << " 次: " << duration1.count() << "ms" << endl;
// 2. 一次性分配的性能
start = chrono::high_resolution_clock::now();
int* bulkArray = new int[ITERATIONS];
for (int i = 0; i < ITERATIONS; i++) {
bulkArray[i] = i;
}
delete[] bulkArray;
end = chrono::high_resolution_clock::now();
auto duration2 = chrono::duration_cast<chrono::milliseconds>(end - start);
cout << "一次性分配: " << duration2.count() << "ms" << endl;
cout << "性能提升: "
<< (duration1.count() - duration2.count()) * 100.0 / duration1.count()
<< "%" << endl;
// 3. 缓存局部性
cout << "\n3. 缓存局部性测试:" << endl;
const int SIZE = 10000;
int** matrix1 = new int*[SIZE]; // 指针数组
for (int i = 0; i < SIZE; i++) {
matrix1[i] = new int[SIZE];
}
int* matrix2 = new int[SIZE * SIZE]; // 扁平数组
// 测试指针数组的访问速度
start = chrono::high_resolution_clock::now();
long sum1 = 0;
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
sum1 += matrix1[i][j];
}
}
end = chrono::high_resolution_clock::now();
auto duration3 = chrono::duration_cast<chrono::milliseconds>(end - start);
// 测试扁平数组的访问速度
start = chrono::high_resolution_clock::now();
long sum2 = 0;
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
sum2 += matrix2[i * SIZE + j];
}
}
end = chrono::high_resolution_clock::now();
auto duration4 = chrono::duration_cast<chrono::milliseconds>(end - start);
cout << "指针数组访问: " << duration3.count() << "ms" << endl;
cout << "扁平数组访问: " << duration4.count() << "ms" << endl;
cout << "性能差异: "
<< (duration3.count() - duration4.count()) * 100.0 / duration3.count()
<< "%" << endl;
// 清理
for (int i = 0; i < SIZE; i++) {
delete[] matrix1[i];
}
delete[] matrix1;
delete[] matrix2;
}
int main() {
demonstrateMemoryBestPractices();
demonstrateMemoryLeakDetection();
demonstratePerformanceConsiderations();
return 0;
}
10.6 实践练习
练习1:智能指针实现
cpp
/*
* 作业:实现简化版智能指针
* 功能:
* 1. 实现UniquePtr(独占所有权)
* 2. 实现SharedPtr(共享所有权,引用计数)
* 3. 实现WeakPtr(弱引用)
* 4. 支持自定义删除器
* 5. 支持移动语义
*
* 要求:
* - 不使用标准库智能指针
* - 实现完整的RAII原则
* - 处理自我赋值
* - 提供异常安全保证
* - 实现swap函数
*/
#include <iostream>
#include <type_traits>
using namespace std;
int main() {
// 在这里编写你的代码
return 0;
}
练习2:内存池分配器
cpp
/*
* 作业:高性能内存池分配器
* 功能:
* 1. 预分配大块内存
* 2. 维护空闲链表
* 3. 支持不同大小的内存块
* 4. 线程安全(可选)
* 5. 内存对齐
* 6. 检测内存泄漏
*
* 要求:
* - 比标准new/delete更快
* - 减少内存碎片
* - 支持重新分配
* - 与标准容器兼容
* - 提供性能测试
*/
#include <iostream>
#include <vector>
#include <chrono>
#include <mutex>
using namespace std;
int main() {
// 在这里编写你的代码
return 0;
}
练习3:字符串类实现
cpp
/*
* 作业:实现C++字符串类
* 功能:
* 1. 动态内存管理
* 2. 拷贝构造函数和赋值运算符
* 3. 移动构造函数和移动赋值
* 4. 常用字符串操作(连接、查找、替换)
* 5. 迭代器支持
* 6. 与C风格字符串互操作
*
* 要求:
* - 实现完整的RAII
* - 避免不必要的拷贝
* - 支持写时复制(可选)
* - 异常安全
* - 性能优化
*/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main() {
// 在这里编写你的代码
return 0;
}
恭喜! 你已经完成了第六部分的学习。在这一部分中,你掌握了:
- ✓ 指针基础:内存地址、指针概念、指针运算
- ✓ 指针与数组:数组退化、多维数组指针
- ✓ 指针与字符串:C风格字符串操作
- ✓ 函数指针:回调函数、事件处理
- ✓ 动态内存管理:new/delete、malloc/free
- ✓ 智能指针:unique_ptr、shared_ptr、weak_ptr
- ✓ 最佳实践:RAII、内存池、性能优化
指针和动态内存是C++中最强大但也最容易出错的部分。现在你已经具备了安全、高效管理内存的能力。在接下来的第七部分中,我们将学习引用类型,这是C++中另一个重要的概念。