Skip to content

C++ 指针

指针是存储内存地址的变量。指针是 C++ 中最强大但也最容易出错的概念之一。

1. 指针的基本概念

1.1 声明指针

cpp
类型* 指针名;

示例

cpp
#include <iostream>

int main() {
    int* ptr;           // 声明一个整型指针
    double* dptr;       // 声明一个双精度浮点型指针
    char* cptr;         // 声明一个字符型指针
    
    return 0;
}

1.2 指针的初始化

cpp
#include <iostream>

int main() {
    int var = 10;
    int* ptr = &var;    // ptr 指向 var 的地址
    
    std::cout << "var 的值: " << var << std::endl;
    std::cout << "var 的地址: " << &var << std::endl;
    std::cout << "ptr 的值: " << ptr << std::endl;
    std::cout << "*ptr 的值: " << *ptr << std::endl;
    
    return 0;
}

2. 指针运算符

2.1 地址运算符(&)

地址运算符&用于获取变量的地址。

cpp
#include <iostream>

int main() {
    int var = 10;
    int* ptr = &var;    // 获取 var 的地址
    
    std::cout << "var 的地址: " << &var << std::endl;
    std::cout << "ptr 的值: " << ptr << std::endl;
    
    return 0;
}

2.2 解引用运算符(*)

解引用运算符*用于访问指针指向的值。

cpp
#include <iostream>

int main() {
    int var = 10;
    int* ptr = &var;
    
    std::cout << "*ptr 的值: " << *ptr << std::endl;  // 访问 ptr 指向的值
    
    *ptr = 20;  // 修改 ptr 指向的值
    std::cout << "var 的值: " << var << std::endl;
    
    return 0;
}

3. 指针的运算

3.1 指针的算术运算

cpp
#include <iostream>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int* ptr = arr;
    
    // 指针加法
    std::cout << "ptr: " << ptr << ", *ptr: " << *ptr << std::endl;
    ptr++;
    std::cout << "ptr: " << ptr << ", *ptr: " << *ptr << std::endl;
    
    // 指针减法
    ptr--;
    std::cout << "ptr: " << ptr << ", *ptr: " << *ptr << std::endl;
    
    // 指针与整数的运算
    ptr = ptr + 2;
    std::cout << "ptr: " << ptr << ", *ptr: " << *ptr << std::endl;
    
    return 0;
}

3.2 指针的关系运算

cpp
#include <iostream>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int* ptr1 = &arr[0];
    int* ptr2 = &arr[4];
    
    if (ptr1 < ptr2) {
        std::cout << "ptr1 小于 ptr2" << std::endl;
    }
    
    if (ptr1 != ptr2) {
        std::cout << "ptr1 不等于 ptr2" << std::endl;
    }
    
    return 0;
}

4. 指针和数组

4.1 使用指针遍历数组

cpp
#include <iostream>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int* ptr = arr;
    
    // 使用指针遍历数组
    for (int i = 0; i < 5; i++) {
        std::cout << *(ptr + i) << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

4.2 数组名作为指针

cpp
#include <iostream>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    
    // 数组名是指向数组第一个元素的指针
    std::cout << "arr: " << arr << std::endl;
    std::cout << "&arr[0]: " << &arr[0] << std::endl;
    std::cout << "*arr: " << *arr << std::endl;
    
    return 0;
}

5. 指针和函数

5.1 指针作为函数参数

cpp
#include <iostream>

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 10;
    int y = 20;
    
    std::cout << "交换前: x = " << x << ", y = " << y << std::endl;
    swap(&x, &y);
    std::cout << "交换后: x = " << x << ", y = " << y << std::endl;
    
    return 0;
}

5.2 函数返回指针

cpp
#include <iostream>

int* get_element(int arr[], int index) {
    return &arr[index];
}

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int* ptr = get_element(arr, 2);
    
    std::cout << "*ptr = " << *ptr << std::endl;
    
    return 0;
}

6. 指针和 const

6.1 指向常量的指针

cpp
#include <iostream>

int main() {
    int a = 10;
    const int* ptr = &a;  // 指向常量的指针
    
    std::cout << "*ptr = " << *ptr << std::endl;
    // *ptr = 20;  // 错误:不能通过指针修改值
    
    a = 20;  // 可以直接修改
    std::cout << "*ptr = " << *ptr << std::endl;
    
    return 0;
}

6.2 常量指针

cpp
#include <iostream>

int main() {
    int a = 10;
    int b = 20;
    int* const ptr = &a;  // 常量指针
    
    std::cout << "*ptr = " << *ptr << std::endl;
    *ptr = 20;  // 可以通过指针修改值
    std::cout << "*ptr = " << *ptr << std::endl;
    
    // ptr = &b;  // 错误:不能修改指针指向
    
    return 0;
}

6.3 指向常量的常量指针

cpp
#include <iostream>

int main() {
    int a = 10;
    int b = 20;
    const int* const ptr = &a;  // 指向常量的常量指针
    
    std::cout << "*ptr = " << *ptr << std::endl;
    // *ptr = 20;  // 错误:不能通过指针修改值
    // ptr = &b;   // 错误:不能修改指针指向
    
    return 0;
}

7. 指针和动态内存

7.1 动态内存分配

cpp
#include <iostream>

int main() {
    // 动态分配一个整型变量
    int* ptr = new int;
    *ptr = 10;
    std::cout << "*ptr = " << *ptr << std::endl;
    delete ptr;  // 释放内存
    
    // 动态分配数组
    int* arr = new int[5];
    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;
    }
    for (int i = 0; i < 5; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
    delete[] arr;  // 释放数组内存
    
    return 0;
}

7.2 智能指针(C++11)

cpp
#include <iostream>
#include <memory>

int main() {
    // unique_ptr
    std::unique_ptr<int> ptr1(new int(10));
    std::cout << "*ptr1 = " << *ptr1 << std::endl;
    
    // shared_ptr
    std::shared_ptr<int> ptr2 = std::make_shared<int>(20);
    std::cout << "*ptr2 = " << *ptr2 << std::endl;
    
    return 0;
}

8. 指针的常见错误

8.1 空指针

cpp
#include <iostream>

int main() {
    int* ptr = nullptr;  // 空指针
    
    if (ptr != nullptr) {
        std::cout << "*ptr = " << *ptr << std::endl;
    } else {
        std::cout << "ptr 是空指针" << std::endl;
    }
    
    return 0;
}

8.2 野指针

cpp
#include <iostream>

int main() {
    int* ptr;  // 未初始化的指针(野指针)
    // *ptr = 10;  // 错误:未定义行为
    
    ptr = nullptr;  // 将指针初始化为 nullptr
    
    return 0;
}

8.3 内存泄漏

cpp
#include <iostream>

int main() {
    int* ptr = new int(10);
    // delete ptr;  // 忘记释放内存(内存泄漏)
    
    return 0;
}

9. 函数指针

函数指针是指向函数的指针。

9.1 基本用法

cpp
#include <iostream>

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int main() {
    // 声明函数指针
    int (*operation)(int, int);
    
    // 指向 add 函数
    operation = add;
    std::cout << "add(10, 20) = " << operation(10, 20) << std::endl;
    
    // 指向 subtract 函数
    operation = subtract;
    std::cout << "subtract(10, 20) = " << operation(10, 20) << std::endl;
    
    return 0;
}

10. 示例:综合运用

现在,让我们看一个综合运用各种指针特性的例子:

cpp
#include <iostream>
#include <memory>

// 函数声明
void swap(int* a, int* b);
int* get_element(int arr[], int index);
int add(int a, int b);
int subtract(int a, int b);

int main() {
    // 指针的基本概念
    std::cout << "指针的基本概念:" << std::endl;
    int var = 10;
    int* ptr = &var;
    std::cout << "var 的值: " << var << std::endl;
    std::cout << "var 的地址: " << &var << std::endl;
    std::cout << "ptr 的值: " << ptr << std::endl;
    std::cout << "*ptr 的值: " << *ptr << std::endl;
    std::cout << std::endl;
    
    // 指针和数组
    std::cout << "指针和数组:" << std::endl;
    int arr[] = {10, 20, 30, 40, 50};
    int* arr_ptr = arr;
    for (int i = 0; i < 5; i++) {
        std::cout << *(arr_ptr + i) << " ";
    }
    std::cout << std::endl;
    std::cout << std::endl;
    
    // 指针和函数
    std::cout << "指针和函数:" << std::endl;
    int x = 10;
    int y = 20;
    std::cout << "交换前: x = " << x << ", y = " << y << std::endl;
    swap(&x, &y);
    std::cout << "交换后: x = " << x << ", y = " << y << std::endl;
    std::cout << std::endl;
    
    // 指针和 const
    std::cout << "指针和 const:" << std::endl;
    int a = 10;
    const int* const const_ptr = &a;
    std::cout << "*const_ptr = " << *const_ptr << std::endl;
    std::cout << std::endl;
    
    // 指针和动态内存
    std::cout << "指针和动态内存:" << std::endl;
    int* dynamic_ptr = new int(10);
    std::cout << "*dynamic_ptr = " << *dynamic_ptr << std::endl;
    delete dynamic_ptr;
    std::cout << std::endl;
    
    // 智能指针
    std::cout << "智能指针:" << std::endl;
    std::unique_ptr<int> unique_ptr(new int(20));
    std::cout << "*unique_ptr = " << *unique_ptr << std::endl;
    std::cout << std::endl;
    
    // 空指针
    std::cout << "空指针:" << std::endl;
    int* null_ptr = nullptr;
    if (null_ptr != nullptr) {
        std::cout << "*null_ptr = " << *null_ptr << std::endl;
    } else {
        std::cout << "null_ptr 是空指针" << std::endl;
    }
    std::cout << std::endl;
    
    // 函数指针
    std::cout << "函数指针:" << std::endl;
    int (*operation)(int, int);
    operation = add;
    std::cout << "add(10, 20) = " << operation(10, 20) << std::endl;
    operation = subtract;
    std::cout << "subtract(10, 20) = " << operation(10, 20) << std::endl;
    
    return 0;
}

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int* get_element(int arr[], int index) {
    return &arr[index];
}

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

小结

C++ 指针包括:

  1. 指针的基本概念

    • 声明指针:类型* 指针名;
    • 初始化指针:int* ptr = &var;
  2. 指针运算符

    • 地址运算符(&):获取变量的地址
    • 解引用运算符(*):访问指针指向的值
  3. 指针的运算

    • 指针的算术运算:ptr++ptr--ptr + n
    • 指针的关系运算:ptr1 < ptr2ptr1 != ptr2
  4. 指针和数组

    • 使用指针遍历数组
    • 数组名作为指针
  5. 指针和函数

    • 指针作为函数参数
    • 函数返回指针
  6. 指针和 const

    • 指向常量的指针:const int* ptr
    • 常量指针:int* const ptr
    • 指向常量的常量指针:const int* const ptr
  7. 指针和动态内存

    • 动态内存分配:newdelete
    • 智能指针(C++11):std::unique_ptrstd::shared_ptr
  8. 指针的常见错误

    • 空指针:nullptr
    • 野指针:未初始化的指针
    • 内存泄漏:忘记释放内存
  9. 函数指针

    • 指向函数的指针

关键概念:

  • 指针:存储内存地址的变量
  • 地址运算符(&):获取变量的地址
  • 解引用运算符(*):访问指针指向的值
  • 空指针nullptr
  • 内存泄漏:忘记释放动态分配的内存

掌握指针是编写 C++ 程序的基础,在后续章节中,我们将学习 C++ 的引用。