「C++系列」指针

embedded/2024/11/17 3:40:36/

文章目录

  • 一、指针的定义
  • 二、指针的基本概念
    • 1. 基本概念
    • 2. 案例代码
      • 示例 1:基本指针使用
      • 示例 2:指针与数组
    • 3. 注意事项
  • 三、指针的用途
    • 1. 指针的用途
    • 2. 案例代码
      • 案例1. 动态内存分配
      • 案例2. 函数参数(通过指针修改值)
      • 案例3. 数组和字符串
      • 案例4. 链表节点(简化示例)
  • 四、指针的注意事项
    • 1. 注意事项
    • 2. 详细案例代码
      • 动态内存分配与释放
      • 函数参数传递
      • 指针与数组
  • 五、相关链接

一、指针的定义

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。

二、指针的基本概念

C++ 中的指针是编程中的一个核心概念,它允许你直接访问和操作内存地址。以下是关于 C++ 指针的一些基本概念和案例代码。

1. 基本概念

  1. 定义指针:指针变量通过类型名后加上星号 * 来定义。例如,int* ptr; 定义了一个名为 ptr 的指针变量,它可以存储一个 int 类型变量的地址。

  2. 赋值给指针:你可以将一个变量的地址赋给指针。使用 & 操作符来获取变量的地址。例如,int var = 10; int* ptr = &var; 这里,&var 是变量 var 的地址,它被赋给了指针 ptr

  3. 通过指针访问值:使用解引用操作符 * 来访问指针指向的值。例如,*ptr 会访问 ptr 指向的内存地址中的值。

  4. 指针的算术运算:对于指向数组元素的指针,你可以进行算术运算(如递增 ++ 或递减 --),这会改变指针指向的数组元素。

  5. 空指针:未初始化的指针可能指向任意内存地址,这是不安全的。通常将指针初始化为 nullptr(或 NULL,但在 C++11 及更高版本中推荐使用 nullptr),以表示它不指向任何有效的内存地址。

  6. 指针与数组:在 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. 注意事项

  • 指针操作需要谨慎,因为错误的指针算术或解引用可能导致未定义行为,如访问无效内存或程序崩溃。
  • 在使用指针时,务必确保指针指向有效的内存地址,并在不再需要时释放动态分配的内存(如果使用 newmalloc 分配了内存)。
  • 指针类型必须与其指向的数据类型匹配,以确保类型安全。

三、指针的用途

C++ 中的指针具有多种用途,从动态内存管理到数组和字符串的处理,再到复杂数据结构的实现,指针都扮演着至关重要的角色。下面我将列举一些指针的用途,并提供相应的案例代码。

1. 指针的用途

  1. 动态内存分配
    指针可以与 newdelete 操作符一起使用,在堆上动态地分配和释放内存。

  2. 函数参数
    通过将指针作为函数参数传递,函数可以直接修改传递给它的变量的值。

  3. 数组和字符串
    在 C++ 中,数组名通常被视为指向数组第一个元素的指针,而字符串(字符数组)也常通过字符指针来处理。

  4. 链表、树等数据结构的实现
    指针是实现链表、树等复杂数据结构的关键,因为它们允许节点之间建立直接的连接。

  5. 函数指针
    函数指针可以指向函数,使得函数可以作为参数传递给其他函数,或者作为其他函数的返回值。

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. 注意事项

  1. 初始化指针
  • 在使用指针之前,一定要确保它被正确初始化。未初始化的指针可能指向任何随机的内存地址,这可能导致程序崩溃或不可预测的行为。
  • 示例代码(未初始化指针的潜在问题):
int* ptr; // 未初始化
*ptr = 10; // 可能导致程序崩溃,因为ptr可能指向无效内存
  1. 检查空指针
  • 在解引用指针之前,检查它是否为NULL(或在C++11及以后使用nullptr)是一个好习惯。尝试解引用空指针将导致程序崩溃。
  • 示例代码:
int* ptr = nullptr;
if (ptr != nullptr) {std::cout << *ptr << std::endl; // 不会执行,因为ptr是nullptr
}
  1. 避免内存泄漏
  • 动态分配的内存(使用newmalloc)必须在不再需要时释放(使用deletefree)。否则,程序将占用越来越多的内存,最终导致内存泄漏。
  • 示例代码:
int* ptr = new int(10);
// ... 使用ptr ...
delete ptr; // 释放内存
  1. 释放内存后设置指针为NULL
  • 释放内存后,将指针设置为NULL(或在C++11及以后使用nullptr)是一个好习惯,这有助于避免悬挂指针(dangling pointers)的问题。
  • 示例代码:
int* ptr = new int(10);
// ... 使用ptr ...
delete ptr;
ptr = nullptr; // 防止悬挂指针
  1. 指针类型匹配
  • 确保指针的类型与它所指向的数据类型相匹配。例如,一个int类型的指针不应该用来指向float类型的数据。
  1. 避免指针运算错误
  • 指针的加减运算不是简单的数学加减,而是根据指针类型的大小来移动的。例如,int* ptr; ptr++; 实际上是将ptr向后移动了一个int类型的大小(通常是4个字节,但这也取决于编译器和平台)。
  1. 使用智能指针
  • 在C++中,可以使用智能指针(如std::unique_ptrstd::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;
}

在这里插入图片描述

五、相关链接

  1. Visual Studio Code下载地址
  2. Sublime Text下载地址
  3. 「C++系列」C++简介、应用领域
  4. 「C++系列」C++ 基本语法
  5. 「C++系列」C++ 数据类型
  6. 「C++系列」C++ 变量类型
  7. 「C++系列」C++ 变量作用域
  8. 「C++系列」C++ 常量知识点-细致讲解
  9. 「C++系列」C++ 修饰符类型
  10. 「C++系列」一篇文章说透【存储类】
  11. 「C++系列」一篇文章讲透【运算符】
  12. 「C++系列」循环
  13. 「C++系列」判断
  14. 「C++系列」函数/内置函数
  15. 「C++系列」数字/随机数
  16. 「C++系列」数组
  17. 「C++系列」字符串

http://www.ppmy.cn/embedded/90834.html

相关文章

docker环境下php安装扩展步骤 以mysqli为例

docker环境下php安装扩展步骤 以mysqli为例 1.0 前言2.0 php 扩展安装原理3.0 docker 环境下 php 扩展安装3.1 docker php 容器扩展安装路径及原理3.2 docker php 扩展脚本安装过程 同步发布在个人笔记[docker环境下php安装扩展步骤 以mysqli为例]( https://blog.lichenrobo.co…

C# 类型转换

隐式&#xff08;implicit&#xff09;类型转换 1.不丢失精度的转换 2.显示&#xff08;explicit&#xff09;类型的转换 有可能丢失精度的转换 使用convert转换 ToString方法&#xff1a;将数值类型转换成字符串型

git将自己工作分支多次提交合并为一次提交到主分支

首先&#xff0c;你需要确认你当前的分支和主分支的状态&#xff0c;确保所有的改动都已经commit。然后切换到主分支&#xff1a; git checkout 主分支名 然后&#xff0c;使用git merge --squash命令将你的开发分支的改动合并到主分支&#xff1a; git merge --squash 开发…

JavaScript 中的闭包和事件委托

包 (Closures) 闭包是 JavaScript 中一个非常强大的特性&#xff0c;它允许函数访问其外部作用域中的变量&#xff0c;即使在该函数被调用时&#xff0c;外部作用域已经执行完毕。闭包可以帮助我们实现数据的私有化、封装和模块化&#xff0c;使代码更简洁、易读和可维护。 闭包…

移动端支持自定义导航配置

07/31 主要更新模块概览 日程展开 成员组件 字段校验 自定义导航 01 表单管理 1.1 【表单视图】-日历视图-日程表-全天日程新增展开功能 在日历视图中&#xff0c;日程表-全天日程新增展开功能&#xff0c;默认只显示2条日程&#xff0c;超出部分可以点击展开按钮显示…

Hyper-V创建虚拟机安装OpenEulerOS

文章目录 下载OpenEulerHyper-V创建虚拟机 下载OpenEuler 进入官网下载&#xff0c;我选择的是 openEuler 24.03 LTS &#xff0c;选择第一个版本即可&#xff1a; Hyper-V创建虚拟机 点击新建->虚拟机&#xff1a; 点击下一步&#xff1a; 输入虚拟机名称&#xff0c…

排序算法:插入排序,golang实现

目录 前言 插入排序 代码示例 1. 算法包 2. 插入排序代码 3. 模拟程序 4. 运行程序 5. 从大到小排序 插入排序的思想 循环细节 外层循环 内层循环 循环次数测试 假如 10 条数据进行排序 假如 20 条数据进行排序 假如 30 条数据进行排序 假设 5000 条数据&…

C++——智能指针

前言&#xff1a;哈喽小伙伴们&#xff0c;今天我们继续来分享C的一个全新知识——智能指针。 目录 一.何为智能指针 RAII 二.智能指针的种类 三.内存泄漏 结语 一.何为智能指针 RAII RAII&#xff08;Resource Acquisition Is Initialization&#xff09;是一种利用对象生…