一. 指针的基本概念
什么是指针?
指针是一个变量,其值是另一个变量的内存地址。通俗点理解为。
指针就像快递单
- 变量:就像是一个包裹,里面装着实际的东西(数据)。
- 指针:就像是一张快递单,上面写着包裹的存放地址(内存地址)。
- 解引用:就是根据快递单上的地址,去找到那个包裹,取出里面的东西
二. C语言中的指针
1. C指针基本概念
什么是指针?
在C语言中,指针是一个变量,其值为另一个变量的内存地址。
#include
int main() {
int num = 42; // 普通变量
int *ptr = # // 指针变量,存储num的地址
printf("num的值: %d\n", num); // 42
printf("num的地址: %p\n", &num); // 内存地址
printf("ptr存储的地址: %p\n", ptr); // 与&num相同
printf("ptr指向的值: %d\n", *ptr); // 42
return 0;
}
指针声明语法
int *ptr; // 指向整型的指针
char *cptr; // 指向字符的指针
float *fptr; // 指向浮点数的指针
void *vptr; // 通用指针(可指向任何类型)
2. C指针的核心应用
2.1 动态内存管理
#include
#include
int main() {
int n = 5;
// 动态分配数组
int *arr = (int*)malloc(n * sizeof(int));
if (arr == NULL) {
printf("内存分配失败\n");
return 1;
}
// 使用动态数组
for (int i = 0; i < n; i++) {
arr[i] = i * 10;
printf("arr[%d] = %d\n", i, arr[i]);
}
// 重新调整内存大小
int *new_arr = (int*)realloc(arr, 10 * sizeof(int));
if (new_arr != NULL) {
arr = new_arr;
}
// 必须手动释放内存
free(arr);
arr = NULL; // 避免悬空指针
return 0;
}
2.2 函数参数传递(按引用传递)
#include
// 交换两个变量的值
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 通过指针返回多个值
void getMinMax(int arr[], int size, int *min, int *max) {
*min = *max = arr[0];
for (int i = 1; i < size; i++) {
if (arr[i] < *min) *min = arr[i];
if (arr[i] > *max) *max = arr[i];
}
}
int main() {
int x = 10, y = 20;
swap(&x, &y);
printf("交换后: x=%d, y=%d\n", x, y); // 20, 10
int numbers[] = {3, 1, 4, 1, 5, 9, 2};
int min_val, max_val;
getMinMax(numbers, 7, &min_val, &max_val);
printf("最小值: %d, 最大值: %d\n", min_val, max_val);
return 0;
}
2.3 数组和指针的关系
#include
void arrayPointerDemo() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // 数组名就是首元素地址
printf("数组元素访问:\n");
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d, *(ptr+%d) = %d, *(arr+%d) = %d\n",
i, arr[i], i, *(ptr + i), i, *(arr + i));
}
printf("\n指针算术运算:\n");
printf("ptr = %p\n", ptr);
printf("ptr + 1 = %p (移动了%d字节)\n", ptr + 1, sizeof(int));
printf("ptr + 2 = %p (移动了%d字节)\n", ptr + 2, 2 * sizeof(int));
}
2.4 字符串处理
#include
#include
void stringDemo() {
char str[] = "Hello World";
char *p = str;
// 使用指针遍历字符串
printf("字符串: ");
while (*p != '\0') {
printf("%c", *p);
p++;
}
printf("\n");
// 字符串复制函数的手动实现
char source[] = "Source string";
char destination[20];
char *src_ptr = source;
char *dest_ptr = destination;
while (*src_ptr != '\0') {
*dest_ptr = *src_ptr;
src_ptr++;
dest_ptr++;
}
*dest_ptr = '\0';
printf("复制后的字符串: %s\n", destination);
}
2.5 函数指针
#include
// 函数声明
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
void calculate(int a, int b, int (*operation)(int, int)) {
int result = operation(a, b);
printf("计算结果: %d\n", result);
}
int main() {
int x = 10, y = 5;
// 函数指针声明和赋值
int (*func_ptr)(int, int);
func_ptr = add;
calculate(x, y, func_ptr); // 15
func_ptr = subtract;
calculate(x, y, func_ptr); // 5
func_ptr = multiply;
calculate(x, y, func_ptr); // 50
return 0;
}
2.6 多级指针
#include
void multiLevelPointer() {
int value = 100;
int *ptr1 = &value;
int **ptr2 = &ptr1; // 指向指针的指针
int ***ptr3 = &ptr2; // 三级指针
printf("value = %d\n", value); // 100
printf("*ptr1 = %d\n", *ptr1); // 100
printf("**ptr2 = %d\n", **ptr2); // 100
printf("***ptr3 = %d\n", ***ptr3); // 100
// 修改值
***ptr3 = 200;
printf("修改后 value = %d\n", value); // 200
}
三.C++中的指针
1. C++指针基础(兼容C)
C++完全支持C的所有指针特性,即包含支持C的指针操作还在此基础上进行扩展,但是它提供了更安全和现代化的替代方案。
#include
using namespace std;
int main() {
int num = 42;
int *ptr = #
cout << "num的值: " << num << endl; // 42
cout << "num的地址: " << &num << endl; // 地址
cout << "ptr指向的值: " << *ptr << endl; // 42
return 0;
}
2. C++特有的指针特性
2.1 引用(指针的替代方案)
#include
using namespace std;
void swap(int &a, int &b) { // 使用引用,语法更简洁
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
cout << "交换前: x=" << x << ", y=" << y << endl;
swap(x, y); // 不需要取地址符&
cout << "交换后: x=" << x << ", y=" << y << endl;
return 0;
}
2.2 智能指针(现代C++核心特性)
unique_ptr - 独占所有权
#include
#include
void uniquePtrDemo() {
// 创建unique_ptr
std::unique_ptr uptr1 = std::make_unique(42);
std::unique_ptr arrPtr = std::make_unique(5);
// 使用指针
std::cout << "*uptr1 = " << *uptr1 << std::endl;
for (int i = 0; i < 5; i++) {
arrPtr[i] = i * 10;
std::cout << "arrPtr[" << i << "] = " << arrPtr[i] << std::endl;
}
// 所有权转移(移动语义)
std::unique_ptr uptr2 = std::move(uptr1);
if (!uptr1) {
std::cout << "uptr1 已转移所有权" << std::endl;
}
// 自动释放内存,无需手动delete
}
shared_ptr - 共享所有权
#include
#include
class MyClass {
public:
MyClass(int val) : value(val) {
std::cout << "MyClass 构造函数,value=" << value << std::endl;
}
~MyClass() {
std::cout << "MyClass 析构函数,value=" << value << std::endl;
}
void print() {
std::cout << "Value: " << value << std::endl;
}
private:
int value;
};
void sharedPtrDemo() {
// 创建shared_ptr
std::shared_ptr ptr1 = std::make_shared(100);
{
std::shared_ptr ptr2 = ptr1; // 共享所有权,引用计数+1
std::cout << "引用计数: " << ptr1.use_count() << std::endl; // 2
ptr2->print();
} // ptr2离开作用域,引用计数-1
std::cout << "引用计数: " << ptr1.use_count() << std::endl; // 1
ptr1->print();
// ptr1离开作用域,引用计数为0,自动删除对象
}
weak_ptr - 观察指针
#include
#include
void weakPtrDemo() {
std::shared_ptr shared = std::make_shared(42);
std::weak_ptr weak = shared; // 创建weak_ptr,不增加引用计数
std::cout << "shared引用计数: " << shared.use_count() << std::endl; // 1
// 使用weak_ptr前需要lock()获取shared_ptr
if (auto temp = weak.lock()) {
std::cout << "通过weak_ptr访问值: " << *temp << std::endl;
} else {
std::cout << "对象已被销毁" << std::endl;
}
}
2.3 基于RAII的资源管理
#include
#include
#include
// 使用智能指针管理文件资源
class FileManager {
private:
std::unique_ptr file_;
public:
FileManager(const std::string& filename) {
file_ = std::make_unique(filename, std::ios::out);
if (!file_->is_open()) {
throw std::runtime_error("无法打开文件");
}
}
void write(const std::string& content) {
*file_ << content << std::endl;
}
// 不需要手动关闭文件,析构函数会自动处理
};
void raiiDemo() {
try {
FileManager fm("test.txt");
fm.write("Hello RAII!");
// 离开作用域时自动关闭文件
} catch (const std::exception& e) {
std::cout << "错误: " << e.what() << std::endl;
}
}
2.4 面向对象编程中的指针
#include
#include
#include
class Shape {
public:
virtual void draw() const = 0;
virtual double area() const = 0;
virtual ~Shape() = default;
};
class Circle : public Shape {
private:
double radius_;
public:
Circle(double radius) : radius_(radius) {}
void draw() const override {
std::cout << "绘制圆形,半径: " << radius_ << std::endl;
}
double area() const override {
return 3.14159 * radius_ * radius_;
}
};
class Rectangle : public Shape {
private:
double width_, height_;
public:
Rectangle(double w, double h) : width_(w), height_(h) {}
void draw() const override {
std::cout << "绘制矩形,尺寸: " << width_ << "x" << height_ << std::endl;
}
double area() const override {
return width_ * height_;
}
};
void polymorphismDemo() {
std::vector> shapes;
shapes.push_back(std::make_unique(5.0));
shapes.push_back(std::make_unique(4.0, 6.0));
for (const auto& shape : shapes) {
shape->draw();
std::cout << "面积: " << shape->area() << std::endl;
}
}
2.5 new和delete操作符
#include
void newDeleteDemo() {
// 单个对象
int *ptr = new int(42);
std::cout << "*ptr = " << *ptr << std::endl;
delete ptr;
// 对象数组
int *arr = new int[5];
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
delete[] arr; // 注意使用delete[]
// 推荐使用智能指针替代new/delete
auto smartPtr = std::make_unique(100);
// 无需手动释放
}
4.C vs C++指针对比总结
| 特性 | C语言 | C++ |
|---|---|---|
| 基本指针语法 | 支持 | 完全兼容 |
| 动态内存分配 | malloc/free | new/delete + 智能指针 |
| 引用类型 | 不支持 | 支持引用(&) |
| 自动内存管理 | 无 | 智能指针(unique_ptr, shared_ptr) |
| 异常安全 | 无 | RAII模式保证 |
| 面向对象 | 需要手动管理 | 与多态完美配合 |
| 推荐用法 | 必须手动管理 | 优先使用智能指针和引用 |
现代C++最佳实践:
- 优先使用智能指针而不是裸指针
- 优先使用引用而不是指针作为函数参数
- 使用
std::make_unique和std::make_shared创建智能指针 - 避免使用
new和delete - 利用RAII模式管理所有资源