文章目录
- 一、指针的定义
- 二、指针的基本概念
- 1. 基本概念
- 2. 案例代码
- 示例 1:基本指针使用
- 示例 2:指针与数组
- 3. 注意事项
- 三、指针的用途
- 1. 指针的用途
- 2. 案例代码
- 案例1. 动态内存分配
- 案例2. 函数参数(通过指针修改值)
- 案例3. 数组和字符串
- 案例4. 链表节点(简化示例)
- 四、指针的注意事项
- 1. 注意事项
- 2. 详细案例代码
- 动态内存分配与释放
- 函数参数传递
- 指针与数组
- 五、相关链接
一、指针的定义
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。
二、指针的基本概念
C++ 中的指针是编程中的一个核心概念,它允许你直接访问和操作内存地址。以下是关于 C++ 指针的一些基本概念和案例代码。
1. 基本概念
-
定义指针:指针变量通过类型名后加上星号
*
来定义。例如,int* ptr;
定义了一个名为ptr
的指针变量,它可以存储一个int
类型变量的地址。 -
赋值给指针:你可以将一个变量的地址赋给指针。使用
&
操作符来获取变量的地址。例如,int var = 10; int* ptr = &var;
这里,&var
是变量var
的地址,它被赋给了指针ptr
。 -
通过指针访问值:使用解引用操作符
*
来访问指针指向的值。例如,*ptr
会访问ptr
指向的内存地址中的值。 -
指针的算术运算:对于指向数组元素的指针,你可以进行算术运算(如递增
++
或递减--
),这会改变指针指向的数组元素。 -
空指针:未初始化的指针可能指向任意内存地址,这是不安全的。通常将指针初始化为
nullptr
(或NULL
,但在 C++11 及更高版本中推荐使用nullptr
),以表示它不指向任何有效的内存地址。 -
指针与数组:在 C++ 中,数组名通常被当作指向数组第一个元素的指针。
2. 案例代码
示例 1:基本指针使用
#include <iostream>
using namespace std;int main() {int var = 20; // 定义一个整型变量int* ptr; // 定义一个整型指针// 让指针指向变量的地址ptr = &var;// 通过指针访问变量的值cout << "Value of var through pointer: " << *ptr << endl;// 修改指针指向的值*ptr = 100;// 再次通过指针访问变量的值cout << "New value of var through pointer: " << *ptr << endl;return 0;
}
示例 2:指针与数组
#include <iostream>
using namespace std;int main() {int arr[] = {10, 20, 30, 40, 50}; // 定义一个整型数组int* ptr; // 定义一个整型指针// 让指针指向数组的第一个元素ptr = arr;// 通过指针遍历数组for (int i = 0; i < 5; i++) {cout << *(ptr + i) << " "; // 使用指针算术访问数组元素}cout << endl;return 0;
}
在这个例子中,ptr
最初指向数组的第一个元素(即 arr[0]
)。通过递增 ptr
(实际上是 ptr + i
),我们可以遍历数组中的每个元素。注意,这里的 ptr + i
实际上是对指针进行算术运算,使其指向数组中的第 i+1
个元素(因为数组索引从 0 开始)。
3. 注意事项
- 指针操作需要谨慎,因为错误的指针算术或解引用可能导致未定义行为,如访问无效内存或程序崩溃。
- 在使用指针时,务必确保指针指向有效的内存地址,并在不再需要时释放动态分配的内存(如果使用
new
或malloc
分配了内存)。 - 指针类型必须与其指向的数据类型匹配,以确保类型安全。
三、指针的用途
C++ 中的指针具有多种用途,从动态内存管理到数组和字符串的处理,再到复杂数据结构的实现,指针都扮演着至关重要的角色。下面我将列举一些指针的用途,并提供相应的案例代码。
1. 指针的用途
-
动态内存分配:
指针可以与new
和delete
操作符一起使用,在堆上动态地分配和释放内存。 -
函数参数:
通过将指针作为函数参数传递,函数可以直接修改传递给它的变量的值。 -
数组和字符串:
在 C++ 中,数组名通常被视为指向数组第一个元素的指针,而字符串(字符数组)也常通过字符指针来处理。 -
函数指针:
函数指针可以指向函数,使得函数可以作为参数传递给其他函数,或者作为其他函数的返回值。
2. 案例代码
案例1. 动态内存分配
#include <iostream>
using namespace std;int main() {int* ptr = new int; // 动态分配一个整型变量的内存*ptr = 10; // 通过指针赋值cout << "Value of dynamically allocated int: " << *ptr << endl;delete ptr; // 释放内存return 0;
}
案例2. 函数参数(通过指针修改值)
#include <iostream>
using namespace std;void modifyValue(int* ptr) {*ptr = 100; // 直接修改指针指向的值
}int main() {int var = 20;modifyValue(&var); // 传递变量的地址cout << "Value of var after modification: " << var << endl;return 0;
}
案例3. 数组和字符串
#include <iostream>
using namespace std;int main() {char str[] = "Hello, World!"; // 字符数组(字符串)char* ptr = str; // 指针指向字符串的首字符// 通过指针遍历字符串while (*ptr != '\0') { // 字符串以空字符 '\0' 结尾cout << *ptr++; // 输出当前字符,并将指针移动到下一个字符}cout << endl;return 0;
}
案例4. 链表节点(简化示例)
#include <iostream>
using namespace std;// 链表节点的简单定义
struct ListNode {int value;ListNode* next;ListNode(int x) : value(x), next(nullptr) {}
};int main() {// 创建链表:1 -> 2 -> 3ListNode* head = new ListNode(1);head->next = new ListNode(2);head->next->next = new ListNode(3);// 遍历链表并打印值(简化版,未释放内存)ListNode* current = head;while (current != nullptr) {cout << current->value << " ";current = current->next;}cout << endl;// 注意:在实际应用中,应该释放链表节点所占用的内存return 0;
}
注意:在上面的链表示例中,我为了简化而没有释放分配的内存。在实际应用中,你应该在链表不再需要时遍历链表并释放每个节点所占用的内存,以避免内存泄漏。
四、指针的注意事项
在C++中,指针是一种强大的工具,它允许直接访问和操作内存地址。然而,由于这种直接性,指针的使用也需要格外小心,以避免程序崩溃、内存泄漏等问题。以下是C++指针的注意事项及详细案例代码。
1. 注意事项
- 初始化指针:
- 在使用指针之前,一定要确保它被正确初始化。未初始化的指针可能指向任何随机的内存地址,这可能导致程序崩溃或不可预测的行为。
- 示例代码(未初始化指针的潜在问题):
int* ptr; // 未初始化
*ptr = 10; // 可能导致程序崩溃,因为ptr可能指向无效内存
- 检查空指针:
- 在解引用指针之前,检查它是否为NULL(或在C++11及以后使用
nullptr
)是一个好习惯。尝试解引用空指针将导致程序崩溃。 - 示例代码:
int* ptr = nullptr;
if (ptr != nullptr) {std::cout << *ptr << std::endl; // 不会执行,因为ptr是nullptr
}
- 避免内存泄漏:
- 动态分配的内存(使用
new
或malloc
)必须在不再需要时释放(使用delete
或free
)。否则,程序将占用越来越多的内存,最终导致内存泄漏。 - 示例代码:
int* ptr = new int(10);
// ... 使用ptr ...
delete ptr; // 释放内存
- 释放内存后设置指针为NULL:
- 释放内存后,将指针设置为NULL(或在C++11及以后使用
nullptr
)是一个好习惯,这有助于避免悬挂指针(dangling pointers)的问题。 - 示例代码:
int* ptr = new int(10);
// ... 使用ptr ...
delete ptr;
ptr = nullptr; // 防止悬挂指针
- 指针类型匹配:
- 确保指针的类型与它所指向的数据类型相匹配。例如,一个
int
类型的指针不应该用来指向float
类型的数据。
- 避免指针运算错误:
- 指针的加减运算不是简单的数学加减,而是根据指针类型的大小来移动的。例如,
int* ptr; ptr++;
实际上是将ptr
向后移动了一个int
类型的大小(通常是4个字节,但这也取决于编译器和平台)。
- 使用智能指针:
- 在C++中,可以使用智能指针(如
std::unique_ptr
和std::shared_ptr
)来自动管理内存,从而减少内存泄漏的风险。
2. 详细案例代码
动态内存分配与释放
#include <iostream>
using namespace std;int main() {int* ptr = new int(10); // 动态分配内存并初始化cout << "Value: " << *ptr << endl;// ... 使用ptr ...delete ptr; // 释放内存ptr = nullptr; // 防止悬挂指针return 0;
}
函数参数传递
#include <iostream>
using namespace std;void modifyValue(int* ptr) {*ptr = 20; // 修改指针指向的值
}int main() {int value = 10;modifyValue(&value); // 传递value的地址cout << "Modified Value: " << value << endl; // 输出: Modified Value: 20return 0;
}
指针与数组
#include <iostream>
using namespace std;int main() {int arr[] = {1, 2, 3, 4, 5};int* ptr = arr; // 指针指向数组的第一个元素for (int i = 0; i < 5; i++) {cout << *ptr++ << " "; // 输出当前值并移动指针}cout << endl; // 输出: 1 2 3 4 5return 0;
}
五、相关链接
- Visual Studio Code下载地址
- Sublime Text下载地址
- 「C++系列」C++简介、应用领域
- 「C++系列」C++ 基本语法
- 「C++系列」C++ 数据类型
- 「C++系列」C++ 变量类型
- 「C++系列」C++ 变量作用域
- 「C++系列」C++ 常量知识点-细致讲解
- 「C++系列」C++ 修饰符类型
- 「C++系列」一篇文章说透【存储类】
- 「C++系列」一篇文章讲透【运算符】
- 「C++系列」循环
- 「C++系列」判断
- 「C++系列」函数/内置函数
- 「C++系列」数字/随机数
- 「C++系列」数组
- 「C++系列」字符串