C++指针完全指南
·
C++指针完全指南
指针是C++中最强大但也最容易让人困惑的特性之一。本文将带你从零开始全面理解指针的概念、用法和最佳实践。
目录
- 什么是指针?
- 指针的基本操作
- 指针与数组
- 动态内存分配
- 指针与函数
- 智能指针
- 常见错误与调试技巧
什么是指针?
基本概念
指针是一个变量,其值是另一个变量的内存地址。就像现实生活中的地址可以找到具体的房子一样,指针可以找到内存中的数据。
#include <iostream>
using namespace std;
int main() {
int var = 10; // 普通整型变量
int *ptr = &var; // 指针变量,存储var的地址
cout << "变量var的值: " << var << endl;
cout << "变量var的地址: " << &var << endl;
cout << "指针ptr的值: " << ptr << endl;
cout << "指针ptr指向的值: " << *ptr << endl;
return 0;
}
指针的声明
int *p; // 指向整型的指针
double *dp; // 指向双精度浮点数的指针
char *cp; // 指向字符的指针
指针的基本操作
取地址运算符(&)和解引用运算符(*)
int main() {
int value = 42;
int *pointer = &value; // &获取地址
cout << "直接访问: " << value << endl;
cout << "通过指针访问: " << *pointer << endl; // *解引用
// 通过指针修改变量值
*pointer = 100;
cout << "修改后的值: " << value << endl;
return 0;
}
指针的算术运算
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // 指向数组第一个元素
cout << "第一个元素: " << *ptr << endl;
ptr++; // 移动到下一个元素
cout << "第二个元素: " << *ptr << endl;
ptr += 2; // 向前移动两个元素
cout << "第四个元素: " << *ptr << endl;
// 指针比较
int *ptr2 = &arr[3];
if (ptr == ptr2) {
cout << "指针指向相同位置" << endl;
} else {
cout << "指针指向不同位置" << endl;
}
return 0;
}
指针与数组
数组名作为指针
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
// 三种访问数组元素的方式
cout << "传统数组访问:" << endl;
for (int i = 0; i < 5; i++) {
cout << numbers[i] << " ";
}
cout << endl;
cout << "指针算术访问:" << endl;
for (int i = 0; i < 5; i++) {
cout << *(numbers + i) << " ";
}
cout << endl;
cout << "指针变量访问:" << endl;
int *ptr = numbers;
for (int i = 0; i < 5; i++) {
cout << *(ptr++) << " ";
}
cout << endl;
return 0;
}
指针数组 vs 数组指针
int main() {
int a = 1, b = 2, c = 3;
// 指针数组 - 存储指针的数组
int *ptrArray[3] = {&a, &b, &c};
// 数组指针 - 指向数组的指针
int arr[3] = {10, 20, 30};
int (*arrayPtr)[3] = &arr;
cout << "指针数组演示:" << endl;
for (int i = 0; i < 3; i++) {
cout << *ptrArray[i] << " ";
}
cout << endl;
cout << "数组指针演示:" << endl;
for (int i = 0; i < 3; i++) {
cout << (*arrayPtr)[i] << " ";
}
cout << endl;
return 0;
}
动态内存分配
new和delete操作符
int main() {
// 动态分配单个变量
int *single = new int(42);
cout << "动态分配的整数: " << *single << endl;
// 动态分配数组
int size = 5;
int *array = new int[size];
// 初始化数组
for (int i = 0; i < size; i++) {
array[i] = i * 10;
}
cout << "动态数组内容: ";
for (int i = 0; i < size; i++) {
cout << array[i] << " ";
}
cout << endl;
// 释放内存
delete single;
delete[] array;
return 0;
}
二维数组的动态分配
int main() {
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;
return 0;
}
指针与函数
指针作为函数参数
// 传值 vs 传指针
void swapByValue(int a, int b) {
int temp = a;
a = b;
b = temp;
}
void swapByPointer(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
cout << "交换前: x = " << x << ", y = " << y << endl;
swapByValue(x, y);
cout << "传值交换后: x = " << x << ", y = " << y << endl;
swapByPointer(&x, &y);
cout << "传指针交换后: x = " << x << ", y = " << y << endl;
return 0;
}
函数返回指针
// 返回动态分配的内存
int* createArray(int size) {
int *arr = new int[size];
for (int i = 0; i < size; i++) {
arr[i] = i * i; // 平方数
}
return arr;
}
// 危险的返回局部变量地址的例子
int* dangerousFunction() {
int localVar = 100;
return &localVar; // 错误!局部变量在函数结束后销毁
}
int main() {
int size = 5;
int *myArray = createArray(size);
cout << "创建的数组: ";
for (int i = 0; i < size; i++) {
cout << myArray[i] << " ";
}
cout << endl;
delete[] myArray; // 记得释放内存
return 0;
}
函数指针
#include <iostream>
#include <cmath>
using namespace std;
// 普通函数
double add(double a, double b) {
return a + b;
}
double multiply(double a, double b) {
return a * b;
}
// 函数指针作为参数
void calculate(double a, double b, double (*operation)(double, double)) {
double result = operation(a, b);
cout << "计算结果: " << result << endl;
}
int main() {
double x = 5.5, y = 2.5;
// 声明函数指针
double (*funcPtr)(double, double);
// 指向add函数
funcPtr = add;
cout << "加法: " << funcPtr(x, y) << endl;
// 指向multiply函数
funcPtr = multiply;
cout << "乘法: " << funcPtr(x, y) << endl;
// 使用函数指针作为参数
calculate(x, y, add);
calculate(x, y, multiply);
calculate(x, y, pow); // 使用标准库的pow函数
return 0;
}
智能指针
为什么需要智能指针?
传统指针需要手动管理内存,容易导致内存泄漏。智能指针自动管理内存生命周期。
unique_ptr
#include <memory>
void uniquePtrDemo() {
// 创建unique_ptr
unique_ptr<int> uptr1 = make_unique<int>(42);
cout << "unique_ptr值: " << *uptr1 << endl;
// unique_ptr不能复制,只能移动
unique_ptr<int> uptr2 = move(uptr1);
if (uptr1 == nullptr) {
cout << "uptr1现在为空" << endl;
}
cout << "uptr2的值: " << *uptr2 << endl;
// 自动释放内存,无需手动delete
}
shared_ptr
#include <memory>
class MyClass {
public:
MyClass(int val) : value(val) {
cout << "MyClass构造函数,值: " << value << endl;
}
~MyClass() {
cout << "MyClass析构函数,值: " << value << endl;
}
void print() {
cout << "值: " << value << endl;
}
private:
int value;
};
void sharedPtrDemo() {
// 创建shared_ptr
shared_ptr<MyClass> ptr1 = make_shared<MyClass>(100);
{
shared_ptr<MyClass> ptr2 = ptr1; // 共享所有权
cout << "引用计数: " << ptr1.use_count() << endl;
ptr2->print();
}
cout << "引用计数: " << ptr1.use_count() << endl;
ptr1->print();
// 离开作用域时自动释放
}
weak_ptr
#include <memory>
void weakPtrDemo() {
shared_ptr<int> shared = make_shared<int>(99);
weak_ptr<int> weak = shared;
cout << "shared引用计数: " << shared.use_count() << endl;
if (auto temp = weak.lock()) { // 尝试获取shared_ptr
cout << "weak_ptr的值: " << *temp << endl;
cout << "临时shared_ptr引用计数: " << temp.use_count() << endl;
}
shared.reset(); // 释放资源
if (weak.expired()) {
cout << "资源已被释放" << endl;
}
}
常见错误与调试技巧
常见指针错误
void commonMistakes() {
// 1. 未初始化指针
int *uninitialized;
// *uninitialized = 5; // 未定义行为!
// 2. 空指针解引用
int *nullPtr = nullptr;
// *nullPtr = 10; // 程序崩溃!
// 3. 野指针
int *wildPtr;
{
int temp = 15;
wildPtr = &temp;
}
// *wildPtr = 20; // temp已销毁,未定义行为!
// 4. 内存泄漏
int *leaked = new int[100];
// 忘记delete[] leaked;
// 5. 重复释放
int *doubleDelete = new int(50);
delete doubleDelete;
// delete doubleDelete; // 错误!重复释放
}
调试技巧
#include <cassert>
void debugTechniques() {
// 1. 使用断言
int *ptr = new int(25);
assert(ptr != nullptr); // 确保指针有效
cout << "指针值: " << *ptr << endl;
delete ptr;
// 2. 初始化指针
int *alwaysInitialize = nullptr; // 好习惯
// 3. 检查空指针
if (alwaysInitialize != nullptr) {
*alwaysInitialize = 30;
}
// 4. 使用RAII(资源获取即初始化)
// 优先使用智能指针而不是裸指针
// 5. 内存泄漏检测工具
// 使用Valgrind、AddressSanitizer等工具
}
最佳实践总结
// 好的指针实践示例
class GoodPractices {
public:
GoodPractices() : data(make_unique<int[]>(100)) {
// 使用智能指针自动管理内存
}
void processData() {
if (data) { // 检查指针有效性
for (int i = 0; i < 100; i++) {
data[i] = i;
}
}
}
private:
unique_ptr<int[]> data; // 自动内存管理
};
int main() {
GoodPractices example;
example.processData();
// 不需要手动释放内存
return 0;
}
总结
指针是C++中强大而重要的特性,正确使用指针可以:
- 实现高效的内存访问
- 支持动态数据结构
- 实现多态和回调机制
- 优化程序性能
记住关键要点:
- 理解指针的基本概念(地址和解引用)
- 掌握指针算术和数组关系
- 正确使用动态内存分配
- 优先使用智能指针而不是裸指针
- 遵循最佳实践避免常见错误
通过不断练习和理解,指针将成为你C++编程中的有力工具!
更多推荐


所有评论(0)