当前位置: 首页 > news >正文

07.指针

07.指针

目录介绍
  • 7.1 指针基本概念
    • 7.1.1 什么是指针
    • 7.1.2 指针声明
    • 7.1.3 指针初始化
    • 7.1.4 指针占用空间
  • 7.2 指针基本操作
    • 7.2.1 取地址运算符
    • 7.2.2 解引用运算符
  • 7.3 指针和数组
  • 7.4 指针和函数
    • 7.4.1 指针作为函数参数
    • 7.4.2 指针作为函数返回值
  • 7.5 指针与常量
    • 7.5.1 指向常量的指针
    • 7.5.2 常量指针
    • 7.5.3 指向常量的常量指针
    • 7.5.4 综合案例
  • 7.6 指针高级用法
    • 7.6.1 指针的指针
    • 7.6.2 函数指针
  • 7.7 指针注意实现
    • 7.7.1 空指针
    • 7.7.2 野指针
  • 7.8 综合案例练习
    • 7.8.1 数组的升序
    • 7.8.2 遍历数组案例
    • 7.8.3 指针vs普通对象

7.1 指针基本概念

7.1.1 什么是指针

指针的作用: 可以通过指针间接访问内存

  • 内存编号是从0开始记录的,一般用十六进制数字表示
  • 可以利用指针变量保存地址

指针,它存储了一个内存地址。指针可以指向其他变量或对象的内存地址,通过指针,可以直接访问和操作内存中的数据。

7.1.2 指针声明

指针变量定义语法:

数据类型 *指针变量名;
  • 数据类型:指针指向的变量的类型(如 intdouble 等)。
  • *:表示这是一个指针变量。
  • 指针变量名:指针的名称。

7.1.3 指针初始化

指针在使用前必须初始化,否则会指向一个未知的内存地址,可能导致程序崩溃。

int *ptr = nullptr; // 初始化为空指针

看如下案例所示:

int main() {int a = 10; //定义整型变量a//1、指针的定义//指针定义语法: 数据类型 * 变量名 ;int * p;//初始化,指针变量赋值p = &a; //指针指向变量a的地址cout << &a << endl; //打印数据a的地址cout << p << endl;  //打印指针变量p//2、指针的使用//通过*操作指针变量指向的内存cout << "*p = " << *p << endl;return 0;
}

指针变量和普通变量的区别

  • 普通变量存放的是数据,指针变量存放的是地址
  • 指针变量可以通过" * "操作符,操作指针变量指向的内存空间,这个过程称为解引用
  1. 总结1:我们可以通过 & 符号 获取变量的地址
  2. 总结2:利用指针可以记录地址
  3. 总结3:对指针变量解引用,可以操作指针指向的内存

7.1.3 指针占用空间

提问:指针也是种数据类型,那么这种数据类型占用多少内存空间?示例:

int main() {int a = 10;int * p;p = &a; //指针指向数据a的地址cout << *p << endl; //* 解引用cout << sizeof(p) << endl;cout << sizeof(char *) << endl;cout << sizeof(float *) << endl;cout << sizeof(double *) << endl;\return 0;
}
//10
//8
//8
//8
//8

在 C++ 中,指针的大小取决于编译器和操作系统的位数。通常情况下,指针在 C++ 中也会占用一定的内存空间,这个空间大小与系统的位数相关。

在大多数现代计算机系统中,指针的大小通常如下:

32 位系统:在 32 位系统中,指针通常占用 4 个字节(32 位)的内存空间。

64 位系统:在 64 位系统中,指针通常占用 8 个字节(64 位)的内存空间。

7.2 指针基本操作

7.2.1 取地址运算符

& 用于获取变量的内存地址。

int num = 10;
int *ptr = &num; // ptr 指向 num 的地址

7.2.2 解引用运算符

* 用于访问指针指向的内存地址中的值。

int num = 10;
int *ptr = &num;
cout << *ptr; // 输出 10

7.3 指针使用场景

7.3.1 指针和数组

数组名本身就是一个指针,指向数组的第一个元素。示例

#include <iostream>
using namespace std;int main() {int arr[3] = {10, 20, 30};int *ptr = arr; // ptr 指向数组的第一个元素for (int i = 0; i < 3; i++) {cout << "Element " << i << ": " << *(ptr + i) << endl;}return 0;
}

输出

Element 0: 10
Element 1: 20
Element 2: 30

7.4 指针和函数

指针可以作为函数的参数或返回值,用于传递或返回内存地址。

7.4.1 指针作为函数参数

#include <iostream>
using namespace std;void increment(int *ptr) {(*ptr)++; // 修改指针指向的值
}int main() {int num = 10;increment(&num); // 传递 num 的地址cout << "Incremented value: " << num << endl;return 0;
}

输出

Incremented value: 11

7.4.2 指针作为函数返回值

#include <iostream>
using namespace std;int* getMax(int *a, int *b) {return (*a > *b) ? a : b;
}int main() {int x = 10, y = 20;int *maxPtr = getMax(&x, &y);cout << "Max value: " << *maxPtr << endl;return 0;
}

输出

Max value: 20

7.5 指针与常量

指针可以与 const 关键字结合,表示指针指向的值或指针本身不可修改。

const修饰指针有三种情况

  1. const修饰指针 — 常量指针。常量指针(Constant Pointer):在这种情况下,const 修饰指针本身,表示指针本身是常量,不能通过该指针修改指向的地址。
  2. const修饰常量 — 指针常量。指向常量的指针(Pointer to Constant):在这种情况下,const 修饰指针所指向的值,表示指针指向的值是常量,不能通过该指针修改所指向的值。
  3. const即修饰指针,又修饰常量。指向常量的常量指针(Constant Pointer to Constant):结合上述两种情况,指针本身和指针所指向的值都是常量,既不能通过指针修改所指向的值,也不能修改指针本身指向的地址。

7.5.1 指向常量的指针

const int *ptr; // ptr 指向的值不可修改

7.5.2 常量指针

int *const ptr = &num; // ptr 本身不可修改

7.5.3 指向常量的常量指针

const int *const ptr = &num; // ptr 和 ptr 指向的值都不可修改

7.5.4 综合案例

示例:

int main() {int a = 10;int b = 10;//const修饰的是指针,指针指向可以改,指针指向的值不可以更改const int * p1 = &a;p1 = &b; //正确//*p1 = 100;  报错//const修饰的是常量,指针指向不可以改,指针指向的值可以更改int * const p2 = &a;//p2 = &b; //错误*p2 = 100; //正确//const既修饰指针又修饰常量const int * const p3 = &a;//p3 = &b; //错误//*p3 = 100; //错误return 0;
}

技巧:看const右侧紧跟着的是指针还是常量, 是指针就是常量指针,是常量就是指针常量

7.6 指针高级用法

7.6.1 指针的指针

指针可以指向另一个指针。

int num = 10;
int *ptr = &num;
int **ptr2 = &ptr; // ptr2 指向 ptr

7.6.2 函数指针

函数指针是指向函数的指针变量,可以用于动态调用函数。

#include <iostream>
using namespace std;// 函数
int add(int a, int b) {return a + b;
}int main() {// 声明函数指针int (*funcPtr)(int, int) = add;// 使用函数指针调用函数int result = funcPtr(3, 5);cout << "Sum: " << result << endl;return 0;
}

输出

Sum: 8

7.7 指针注意实现

7.7.1 空指针

空指针:空指针是指不指向任何有效内存地址的指针。空指针通常用来表示指针没有被初始化或者指向了无效的内存地址。在 C++ 中,空指针的值通常是 0 或者使用 nullptr 关键字表示。

用途:初始化指针变量

注意:空指针指向的内存是不可以访问的

示例1:空指针

int main() {//指针变量p指向内存地址编号为0的空间int * p = NULL;//访问空指针报错 //内存编号0 ~255为系统占用内存,不允许用户访问cout << *p << endl;return 0;
}

7.7.2 野指针

野指针:指针变量指向非法的内存空间。

野指针是指指向未知内存地址或已释放的内存地址的指针。野指针通常是由于指针未正确初始化、指向已释放的内存或者超出作用域而导致的。

int main() {//指针变量p指向内存地址编号为0x1100的空间int * p = (int *)0x1100;//访问野指针报错 cout << *p << endl;return 0;
}

总结:空指针和野指针都不是我们申请的空间,因此不要访问。

使用野指针可能会导致程序崩溃、内存泄漏或产生不可预测的行为。如何避免野指针:避免野指针的最佳方法是谨慎管理指针的生命周期,确保正确初始化、释放内存后置空指针,并避免超出指针的作用域。

7.8 综合案例练习

7.8.1 数组的升序

案例描述: 封装一个函数,利用冒泡排序,实现对整型数组的升序排序

例如数组:int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };

示例:

//冒泡排序函数
void bubbleSort(int * arr, int len)  //int * arr 也可以写为int arr[]
{for (int i = 0; i < len - 1; i++){for (int j = 0; j < len - 1 - i; j++){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}//打印数组函数
void printArray(int arr[], int len)
{for (int i = 0; i < len; i++){cout << arr[i] << endl;}
}int main() {int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };int len = sizeof(arr) / sizeof(int);bubbleSort(arr, len);printArray(arr, len);return 0;
}

总结:当数组名传入到函数作为参数时,被退化为指向首元素的指针

7.8.2 遍历数组案例

作用:利用指针访问数组中元素。数组名本身是一个指针,指向数组的第一个元素。

示例:

int main() {int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int *p = arr;  //指向数组的指针。看解释1cout << "第一个元素: " << arr[0] << endl;cout << "指针访问第一个元素: " << *p << endl;  //指向数组第一个元素的指针。看解释2for (int i = 0; i < 10; i++) {//利用指针遍历数组。看解释3cout << *p << endl;p++;}return 0;
}
  1. 解释1,数组名是指针:在 C++ 中,数组名可以被隐式转换为指向数组第一个元素的指针。这意味着p可以将数组名视为指向数组的第一个元素的指针。
  2. 解释2,指针和数组的关系:指针可以用来访问数组中的元素。通过指针算术运算,可以遍历数组中的元素。
  3. 解释3,指针和数组的传递:当传递数组给函数时,实际上传递的是数组的地址,即数组名被隐式转换为指向数组第一个元素的指针。

7.8.3 指针vs普通对象

值语义 vs 指针语义,核心概念理解:

// 值语义:操作副本
Account copy = original;    // 创建副本
copy.deposit(100);         // 修改副本,原对象不变// 指针语义:操作原对象
Account* ptr = &original;  // 指向原对象
ptr->deposit(100);         // 修改原对象

性能影响分析,内存使用对比

// Account对象大小估算
class Account {std::string accountNumber;  // ~24字节(小字符串优化)std::string name;          // ~24字节double balance;            // 8字节// 总计:约56字节
};// 使用指针:8字节(64位系统)
Account* ptr;// 使用对象:56字节 + 复制开销
Account obj;

时间复杂度对比:

  1. 指针方式:O(1) 赋值操作
  2. 对象方式:O(n) 复制操作(n为对象大小)
http://www.dtcms.com/a/606493.html

相关文章:

  • 【gas优化】2.9 使用sstore2或sstore3存储大量数据
  • 来宾北京网站建设网站浏览思路
  • 网站建设模式化的体现企业个人邮箱怎么注册
  • 分布式部署
  • 保障电网安全,赋能绿色能源:AM5SE-PV系列主从机防逆流保护装置在江西丰城曲江煤炭开发公司5.8MW分布式光伏项目的关键角色
  • C/C++ Linux网络编程3 - Socket编程与TCP服务器客户端
  • 镇江大港南站wordpress 新闻 通知
  • 【ZeroRange WebRTC】RFC 5389:STUN 协议规范(中文整理与译注)
  • 苏州网站制作及推广二手闲置平台网站怎么做
  • Unity零碎物体合并为一个整体mesh
  • 做响应式网站图片需要做几版在哪个网站找学做包子
  • 国内大型php网站建设商务网站开发背景
  • HarmonyOS开发-ArkWeb开发指导
  • kotlin:if、when语句介绍
  • 扩展函数练习题
  • Java后端常用技术选型 |(一)数据库篇
  • 婚纱摄影网站应该如何做优化室内装修设计软件下载
  • 从零开始写算法——二分-寻找旋转排序数组中的最小值
  • 一站式网站建设与运营简述网站开发平台及常用工具
  • 易语言程序反编译 | 深入了解反编译技术与应用
  • 本地部署数据库管理工具 NocoDB 并实现外部访问(Linux 版本)
  • 9V-36V转3.3V4A同步降压WT6043A
  • P10668 BZOJ2720 [Violet 5] 列队春游(自己加强版) 题解
  • 学做立体书的网站wordpress小人插件
  • 网站图片地址怎么做的搜索指数的数据来源是什么
  • c# 上位机作为控制端与下位机通信方式
  • 一文了解UI自动化测试
  • 使用ZYNQ芯片和LVGL框架实现用户高刷新UI设计系列教程(第三十六讲)
  • MySQL 缓存机制与查询缓存的消亡史
  • 平凡前端之路_19.数组的扩展