Appearance
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++ 指针包括:
指针的基本概念:
- 声明指针:
类型* 指针名; - 初始化指针:
int* ptr = &var;
- 声明指针:
指针运算符:
- 地址运算符(
&):获取变量的地址 - 解引用运算符(
*):访问指针指向的值
- 地址运算符(
指针的运算:
- 指针的算术运算:
ptr++、ptr--、ptr + n等 - 指针的关系运算:
ptr1 < ptr2、ptr1 != ptr2等
- 指针的算术运算:
指针和数组:
- 使用指针遍历数组
- 数组名作为指针
指针和函数:
- 指针作为函数参数
- 函数返回指针
指针和 const:
- 指向常量的指针:
const int* ptr - 常量指针:
int* const ptr - 指向常量的常量指针:
const int* const ptr
- 指向常量的指针:
指针和动态内存:
- 动态内存分配:
new和delete - 智能指针(C++11):
std::unique_ptr、std::shared_ptr
- 动态内存分配:
指针的常见错误:
- 空指针:
nullptr - 野指针:未初始化的指针
- 内存泄漏:忘记释放内存
- 空指针:
函数指针:
- 指向函数的指针
关键概念:
- 指针:存储内存地址的变量
- 地址运算符(&):获取变量的地址
- 解引用运算符(*):访问指针指向的值
- 空指针:
nullptr - 内存泄漏:忘记释放动态分配的内存
掌握指针是编写 C++ 程序的基础,在后续章节中,我们将学习 C++ 的引用。