C++指针的使用

文章目录

  • 1.C++指针
    • 1.1 定义指针
    • 1.2 使用指针
  • 2.空指针和野指针
    • 2.1 空指针
    • 2.2 野指针
  • 3.指针所占空间
  • 4.使用const修饰指针
    • 4.1 const修饰指针
    • 4.2 const修饰常量
    • 4.3 const 既修饰指针也修饰常量
  • 5.指针操作数组
  • 6.指针做函数参数
  • 7.使用指针知识实现冒泡排序

1.C++指针

指针其实就是一块地址,可以用来保存我们想要访问或者修改的变量地址,当我们需要访问或者修改保存的地址时,直接通过指针变量去操作就可以了。

1.1 定义指针

定义指针的语法也很简单:数据类型 *指针变量名; ,比如定义一个整型指针变量: int* p; ,假设我们要为指针变量赋值,我们需要用的取地址符&,如下面代码所示:

  int a = 10;int* p;p = &a;

如上面代码所示,我们定义了一个变量a,一个指针变量p,并且把a的地址保存到指针变量p中。

1.2 使用指针

我们定义了指针变量并且赋值后应该如何读取指针变量保存的地址对应的值呢?也就是假设我们定义了一个整型变量a,赋值为10,一个指针变量p,将变量a的地址赋给p,这时我们应该如何去通过指针p访问修改a的值呢?这时就需要用到指针的解引用了,需要用到符号*,代码如下所示:

#include<iostream>
using namespace std;int main() {int a = 10;// 定义指针语法:数据类型 *指针变量名;int* p;// 让指针记录变量a的地址p = &a;// 2.使用指针cout << "a的值未被修改前:" << a << endl;*p = 100;cout << "a的地址: " << (int) & a << endl;cout << "指针p为:" << p << endl;cout << "指针指向的值为:a= "<<a<< " ,*p = " << *p << endl;system("pause");return 0;
}

运行结果:
在这里插入图片描述如上面代码所示,为了对比,我们打印出了变量a之前的值,并且我们打印出了指针p的值,可以看到指针p是一个地址,然后是使用*p = 100的方式访问并修改了指针变量中保存的地址对应的值,而指针变量p中保存的地址正是a的地址,所以修改的其实是a的值。所以a的值变成了100;

注意:可以通过解引用的方式来找到指针指向的内存,*p的方式就是解引用,这样可以访问指针变量中保存的地址对应的值

2.空指针和野指针

2.1 空指针

空指针就是指针变量指向的内存编号为0的空间,我们可以使用空指针来初始化指针变量,比如:
int *p = NULL;,这里需要注意的是,空指针指向的内存是不可以被访问的,例如:

int *p = NULL;
*p = 100;// 错误

上面的代码会导致程序报空指针异常:
在这里插入图片描述这是因为空指针指向的内存是不可以访问的,0~255之间的内存是系统占用的,不可以访问,访问的话就会报异常。

2.2 野指针

野指针就是指针变量指向非法的内存空间,例如我们定义了一个指针变量:int* p = (int*)0x1100;,而0x1100这个地址我们不知道是谁的,就胡乱指的,这种情况特别危险,假设这块地址有重要数据,我们随便一指,然后一改,就会导致重要数据丢失,所以野指针需要被避免。假设我们强制访问未知内存,则会报异常:
在这里插入图片描述
所以我们尽量去访问自己申请的空间,空指针和野指针都不是我们申请的空间,因此不要访问

3.指针所占空间

现在我们知道了指针其实就是一块地址,它用于保存操作其他变量的地址,简单说它就是用来保存地址的,所以它占的空间不需要太大,根据操作系统的位数不同,指针占的空间也不一样,在32位操作系统上,指针占4个字节,在64位操作系统上,指针占8个字节,所有的类型都一样,不管是整型指针,还是浮点型指针,都是一样的,验证的代码如下所示。

#include<iostream>
using namespace std;int main() {// 指针所占内存空间,32位操作系统下,占用4个字节。64位下占用8个字节cout << "size of (int*)" << sizeof(int *) << endl;cout << "size of (float*)" << sizeof(float *) << endl;cout << "size of (double*)" << sizeof(double *) << endl;cout << "size of (char*)" << sizeof(char*) << endl;system("pause");return 0;
}

运行结果:
在这里插入图片描述如上面代码和运行结果可知,各个类型的指针都是占8个字节,因为我的操作系统是64位的。读者也可以验证下自己的操作系统下指针占多上字节。

4.使用const修饰指针

我们都知道,const是表示常量的意思,在C++中,被这个关键字修饰的变量是不可以被修改的,和Java的final关键字一样,因为指针可以访问并修改内存中的值,这样可能会引起安全问题,所以可以使用const关键字控制指针对内存的修改。const修饰指针主要有三种:

4.1 const修饰指针

const修饰指针,称为常量指针,例如:const int *p;,常量指针的特点就是,指针指向的值不可以被修改,但是指针的指向可以修改,如下代码所示:

#include<iostream>
using namespace std;
int main() {// const 修饰指针,常量指针int a = 10;int b = 10;const int* p = &a;// 指针指向的值不可以改,指针的指向可以改*p = 20;// 错误,常量指针指向的值不可以修改,编译会报错p = &b;//正确,常量指针指向的值可以修改system("pause");return 0;
}

如果强制修改无法编译通过

4.2 const修饰常量

const修饰常量,称为指针常量,例如:int * const p;,指针常量的特点就是:指针的指向不可以改,指针指向的值可以改,如下面代码所示:

#include<iostream>
using namespace std;
int main() {int a = 10;int b = 10;int* const p2 = &a;*p2 = 20; // 正确,指针常量指向的值可以修改p2 = &b; // 错误 指针常量的指向不可以改,编译会报错system("pause");return 0;
}

4.3 const 既修饰指针也修饰常量

当const既修饰指针也修饰常量的时候,例如: const int * const p;,这时候指针的指向和值都不允许修改。如下代码所示:

#include<iostream>
using namespace std;
int main() {int a = 10;int b = 10;const int* const p3 = &a;*p3 = 100;// 错误p3 = &b; // 错误system("pause");return 0;
}

5.指针操作数组

指针其实也可以用来访问数组,遍历数组,在C++中,数组名称就是数组的首地址,而数组的存储是连续的,所以我们只要把这个首地址给到指针变量,就可以操作遍历这个数组了,如下面代码所示:

#include<iostream>
using namespace std;
int main() {// 利用指针访问数组中的元素int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };cout << "first Element:" << arr[0] << endl;int* p = arr;//数组名就是数组的首地址cout << "指针访问第一个元素:" << *p << endl;p++; // 让指针向后偏移一个元素所占的字节数cout << "指针访问第二个元素: " << *p << endl;cout << "利用指针遍历数组" << endl;int* p2 = arr;for (int i = 0; i < 10; i++) {cout << *p2 << endl;p2++;}system("pause");return 0;
}

运行结果:
在这里插入图片描述

6.指针做函数参数

指针可以用来做函数的参数,这样可以实现真正的操作传进来的参数原始实参的值,我们给函数传递参数时有两种方式,一种是值传递,传递过去的是值,这个值的修改不会影响原始的实际值,另一种方式是地址传递,这种传递方式传递的是地址,假设我们修改了这个地址对应的值,那么就会影响原始变量的值。举个例子,实现两个数交换,我们使用值传递的方式代码如下:

#include<iostream>
using namespace std;
void swap(int a, int b) {int tmp = a;a = b;b = tmp;cout << "swap: a= " << a << endl;cout << "swap: b= " << b << endl;
}
int main() {// 指针作为函数参数// 1、值传递int a = 10;int b = 20;swap(a, b);// 实参没有改变cout << "a= " << a << endl;cout << "b= " << b << endl;system("pause");return 0;
}

运行结果:
在这里插入图片描述我们可以看到,虽然在swap函数种的值已经交换了,但是我们的原始变量a,b的值还是没有变化。我们使用地址传递的方式,代码如下:

#include<iostream>
using namespace std;
void swap1(int* p1, int* p2) {int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
int main() {int a = 10;int b = 20;// 地址传递: 可以修改实参swap1(&a, &b);cout << "地址传递:a= " << a << endl;cout << "地址传递:b= " << b << endl;system("pause");return 0;
}

运行结果:
在这里插入图片描述
如上面的代码所示,我们传递参数的时候将参数的地址传递给函数,在swap1函数中解析出地址对应的值并且做交换,这样就能修改原始实参的值了。所以指针做函数参数其实就是一种地址传递。

7.使用指针知识实现冒泡排序

学习完指针,我们用指针做一个冒泡排序的算法。代码如下所示:

#include<iostream>
using namespace std;
// 参数1:数组首地址,参数2:数组长度
void bubbleSort(int* arr, int len) {for (int i = 0; i < len - 1; i++) {for (int j = 0; j < len - i - 1; j++) {// 如果j>j+1的值,就交换if(arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}
void printArr(int *arr,int len) {for (int i = 0; i < len; i++) {cout << arr[i] << endl;}
}
int main() {// 利用冒泡排序,对整型数组进行升序排序// 1.先创建数组int arr[10] = { 1,3,2,5,7,1,9,10,7,13 };// 2.创建函数,实现冒泡排序int len = sizeof(arr) / sizeof(arr[0]);bubbleSort(arr, len);// 3.打印结果printArr(arr,len);system("pause");return 0;
}

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/92330.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot整合数据库连接

JDBC 1、数据库驱动 JDBC&#xff08;Java DataBase Connectivity&#xff09;&#xff0c;即Java数据库连接。简而言之&#xff0c;就是通过Java语言来操作数据库。 JDBC是sun公司提供一套用于数据库操作的接口. java程序员只需要面向这套接口编程即可。不同的数据库厂商&…

Ubuntu配置深度学习环境(TensorFlow和pyTorch)

文章目录 一、CUDA安装1.1 安装显卡驱动1.2 CUDA安装1.3 安装cuDNN 二、Anaconda安装三、安装TensorFlow和pyTorch3.1 安装pyTorch3.2 安装TensorFlow2 四、安装pyCharm4.1 pyCharm的安装4.2 关联anaconda的Python解释器 五、VScode配置anaconda的Python虚拟环境 前言&#xff…

计算机竞赛 深度学习手势识别 - yolo python opencv cnn 机器视觉

文章目录 0 前言1 课题背景2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存 5 模型训练5.1 修…

数据结构:复杂度分析

目录 1 算法效率评估 1.1 实际测试 1.2 理论估算 2 迭代与递归 2.1 迭代 1. for 循环 2. while 循环 3. 嵌套循环 2.2 递归 1. 调用栈 2. 尾递归 3. 递归树 2.3 两者对比 3 时间复杂度 3.1 统计时间增长趋势 3.2 函数渐近上界…

MySQL学习笔记26

MySQL主从复制的搭建&#xff08;AB复制&#xff09; 传统AB复制架构&#xff08;M-S)&#xff1a; 说明&#xff1a;在配置MySQL主从架构时&#xff0c;必须保证数据库的版本高度一致&#xff0c;统一版本为5.7.31 环境规划&#xff1a; 编号主机名称主机IP地址角色信息1ma…

盛最多水的容器 接雨水【基础算法精讲 02】

盛雨水最多的容器 链接 : 11 盛最多水的容器 思路 : 双指针 &#xff1a; 1.对于两条确定的边界&#xff0c;l和r,取中间的线m与r组成容器&#xff0c;如果m的高度>l的高度&#xff0c;那么整个容器的长度会减小&#xff0c;如果低于l的高度&#xff0c;那么不仅高度可…

Flink安装及简单使用

目录 转载处&#xff08;个人用最新1.17.1测试&#xff09; 依赖环境 安装包下载地址 Flink本地模式搭建 安装 启动集群 查看WebUI 停止集群 Flink Standalone搭建 安装 修改flink-conf.yaml配置文件 修改workers文件 复制Flink安装文件到其他服务器 启动集群 查…

cesium 热力图(CesiumHeatmap)

cesium 热力图 可添加、删除、显示、隐藏 完整代码 <!DOCTYPE html> <html lang="en"><head><meta charset="utf-8">

mac如何卸载应用并删除文件,2023年最新妙招大公开!

大家好&#xff0c;今天小编要为大家分享一些关于mac电脑的小技巧&#xff0c;特别是关于如何正确卸载应用程序以及清理卸载后的残留文件。你知道吗&#xff1f;很多人都不知道&#xff0c;mac系统默认的卸载方式可能会导致一些残留文件滞留在你的电脑上&#xff0c;慢慢地占用…

openGauss学习笔记-86 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署配置

文章目录 openGauss学习笔记-86 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署配置86.1 总体原则86.2 重做日志&#xff08;MOT&#xff09;86.3 检查点&#xff08;MOT&#xff09;86.4 恢复&#xff08;MOT&#xff09;86.5 统计&#xff08;MOT&#xff09;86…

进入IT行业:选择前端开发还是后端开发?

一、前言 开发做前端好还是后端好&#xff1f;这是一个常见的问题&#xff0c;特别是对于初学者来说。在编程世界中&#xff0c;前端开发和后端开发分别代表着用户界面和数据逻辑&#xff0c;就像城市的两个不同街区一样。但是&#xff0c;究竟哪个街区更适合我们作为开发者呢…

Mapfree智驾方案,怎样实现成本可控?

整理|睿思 编辑|祥威 编者注&#xff1a;本文是HiEV出品的系列直播「智驾地图之变」第二期问答环节内容整理。 元戎启行副总裁刘轩与连线嘉宾奥维咨询董事合伙人张君毅、北汽研究总院智能网联中心专业总师林大洋、主持嘉宾周琳展开深度交流&#xff0c;并进行了答疑。 本期元…

【算法|贪心算法系列No.3】leetcode334. 递增的三元子序列

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

oracle分组合并数值带顺序

比如&#xff1a;有如下一张设备电子围栏位置坐标的表&#xff08;tb_equ_point&#xff09;。 equ_name:设备电子围栏名称 point_id:点位坐标id point_x:点位x坐标 point_y:点位y坐标。 附数据&#xff1a; INSERT INTO "tb_equ_point" ("EQU_NAME",…

番外3:下载+安装VMware(前期准备)

step1: 查看自己笔记本电脑配置&#xff1b; step2: 下载并安装VMware&#xff08;下载地址www..kkx.net/soft/16841.html&#xff09;这里选择本地普通下载&#xff1b; step3: 安装VMware过程中需要填写密钥&#xff08;本人用的最后一个&#xff09;; #UU54R-FVD91-488PP-7N…

友思特案例|友思特 Ensenso 3D相机:汽车工业自动化的革命性力量

01 内容摘要 在竞争激烈的汽车行业&#xff0c;自动化生产至关重要。友思特 Ensenso 3D相机为汽车制造商提供了可靠的工具和技术支持&#xff0c;助力多个关键环节。它在汽车座位泡棉切割中提高精确度&#xff0c;降低浪费&#xff0c;提高生产效率&#xff1b;在汽车压铸零部…

<泛型>带你更详细的认识泛型

了解泛型 现在有一个需求&#xff1a;写一个打印类&#xff0c;用来打印不同类型的数据 //类1 &#xff1a;打印Integer类型的数据 public class IntegerPrint {Integer content;public void Integer(Integer content) {this.content content;}public void print(){System.o…

Python3数据科学包系列(二):数据分析实战

Python3中类的高级语法及实战 Python3(基础|高级)语法实战(|多线程|多进程|线程池|进程池技术)|多线程安全问题解决方案 Python3数据科学包系列(一):数据分析实战 Python3数据科学包系列(二):数据分析实战 一&#xff1a;通过read_table函数读取数据创建(DataFrame)数据框 #…

九、GC收集日志

JVM由浅入深系列一、关于Java性能的误解二、Java性能概述三、了解JVM概述四、探索JVM架构五、垃圾收集基础六、HotSpot中的垃圾收集七、垃圾收集中级八、垃圾收集高级👋GC收集日志 ⚽️1. 认识GC收集日志 垃圾收集日志是一个重要的信息来源,对于与性能相关的一些悬而未决的…

1.5.C++项目:仿muduo库实现并发服务器之socket模块的设计

项目完整版在&#xff1a; 一、socket模块&#xff1a;套接字模块 二、提供的功能 Socket模块是对套接字操作封装的一个模块&#xff0c;主要实现的socket的各项操作。 socket 模块&#xff1a;套接字的功能 创建套接字 绑定地址信息 开始监听 向服务器发起连接 获取新连接 …