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.rhkb.cn/news/145936.html

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

相关文章

ciscn_2019_s_9

ciscn_2019_s_9 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments32位&#xff0c;啥也没开&#xff0c;开心愉悦写shellcode int pwn() {char s[24]; // [esp8…

cesium 雷达扫描 (波纹线性雷达扫描效果)

cesium 雷达扫描 (波纹线性雷达扫描效果) 1、实现方法 使用ellipse方法加载圆型,修改ellipse中material方法来实现效果 2、示例代码 2.1 <!DOCTYPE html> <html lang="en"><head>&l

UE学习记录06----根据Actor大小自适应相机位置

背景&#xff1a; staticMesh 会根据业务需要随时变化&#xff0c;然后通过staticMesh的大小自适应相机位置&#xff0c;捕捉画面用来预览该模型&#xff0c;使模型在画布中不会太大导致显示不全&#xff0c;也不会太小 参考&#xff1a; UE实现相机聚焦物体功能_右弦GISer的…

国庆10.1

用select实现服务器并发 ser #include <myhead.h> #define ERR_MSG(msg) do{\fprintf(stderr, "__%d__", __LINE__);\perror(msg);\ }while(0)#define PORT 8888 //端口号&#xff0c;范围1024~49151 #define IP "192.168.1.205" //本机…

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

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

【C语言】【结构体的位段】位段的内存分配及注意事项

1.什么是位段&#xff1a; struct A { int _a:2; int _b:5; int _c:10; int _d:30; };1.A就是一个位段类型的变量&#xff0c;位表示比特位&#xff0c;意思是 A中的变量申请内存的比特位数 比如 _a要占 2 个bit 2.位段的成员必须是 int ,unsigned int ,signed int 类型的&…

DataBinding双向绑定简介

一、简介 在Vue中使用的是MVVM架构。通过ViewModel可以实现M层和V层数据的双向绑定。Model层的数据发生变化后&#xff0c;会自动更新View层UI。UI层数据发生变化&#xff08;用户输入&#xff09;&#xff0c;可以驱动Model层的数据发生变化&#xff0c;借助于Vue框架中的View…

USART串口协议

通信接口 •通信的目的&#xff1a;将一个设备的数据传送到另一个设备&#xff0c;扩展硬件系统 • 通信协议&#xff1a;制定通信的规则&#xff0c;通信双方按照协议规则进行数据收发 全双工&#xff1a;指通信双方能够同时进行双向通信&#xff0c;一般来说&#xff0c;全双…

QT的ui设计中改变样式表的用法

在QT的ui设计中,我们右键会弹出一个改变样式表的选项,很多人不知道这个是干什么的。 首先我们来看下具体的界面 首先我们说一下这个功能具体是干嘛的, 我们在设置很多控件在界面上之后,常常都是使用系统默认的样式,但是当有些时候为了美化界面我们需要对一些控件进行美化…

计算机竞赛 深度学习手势识别 - 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 函数渐近上界…

SpringBoot整合RabbitMQ实现延迟队列功能

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

【vue3】toRef与toRefs的使用,toRef与ref的区别

假期第四篇&#xff0c;对于基础的知识点&#xff0c;我感觉自己还是很薄弱的。 趁着假期&#xff0c;再去复习一遍 1、toRef与toRefs 创建一个ref对象&#xff0c;其value值指向另一个对象中的某个属性 语法&#xff1a;const name toRef&#xff08;person,‘name’&#xf…

期权定价模型系列【7】:Barone-Adesi-Whaley定价模型

期权定价模型系列第7篇文章 1.前言 目前大连商品交易所、郑州商品交易所、以及上海期货交易所的所有商品期权都为美式期权&#xff0c;并且大商所的所有期权合约会根据BAW(Barone-Adesi-Whaley)美式期权定价模型计算新上市期权合约的挂牌基准价。 BAW模型(Barone-Adesi and W…

动态规划算法(1)--矩阵连乘和凸多边形剖分

目录 一、动态数组 1、创建动态数组 2、添加元素 3、删除修改元素 4、访问元素 5、返回数组长度 6、for each遍历数组 二、输入多个数字 1、正则表达式 2、has.next()方法 三、矩阵连乘 1、什么是矩阵连乘&#xff1f; 2、动态规划思路 3、手推m和s矩阵 4、完…

Vue之transition组件

Vue提供了transition组件&#xff0c;使用户可以更便捷地添加过渡动画效果。 transition组件 transition组件也是一个抽象组件&#xff0c;并不会渲染出真实dom。Vue会在其第一个真实子元素上添加过渡效果。 props render 这里将render分为两部分&#xff0c;第一部分界定真…

skywalking源码本地编译运行经验总结

前言 最近工作原因在弄skywalking&#xff0c;为了进一步熟悉拉了代码下来准备debug&#xff0c;但是编译启动项目我就费了老大劲了&#xff0c;所以准备写这篇&#xff0c;帮兄弟们少踩点坑。 正确步骤 既然是用开源的东西&#xff0c;那么最好就是按照人家的方式使用&…

云服务器租用价格表概览_阿里云腾讯云华为云

云服务器租用价格多少钱一年&#xff1f;阿腾云分享阿里云、腾讯云和华为云的云服务器租用价格表&#xff1a;阿里云2核2G服务器108元一年起、腾讯云2核2G3M带宽轻量服务器95元一年、华为云2核2G3M云耀L实例89元一年起&#xff0c;阿腾云分享更多关于云服务器租用价格明细&…

PICO首届XR开发者挑战赛正式启动,助推行业迈入“VR+MR”新阶段

9月25日&#xff0c;“PICO 2023首届XR开发者挑战赛”&#xff08;下文简称“挑战赛”&#xff09;媒体启动会在北京圆满落幕&#xff0c;官方赛事报名通道已于今日开启。据悉&#xff0c;本次挑战赛是PICO首次针对全球开发者举办的大型挑战赛事&#xff0c;旨在与开发者保持连…

第1篇 目标检测概述 —(4)目标检测评价指标

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。目标检测评价指标是用来衡量目标检测算法性能的指标&#xff0c;可以分为两类&#xff0c;包括框级别评价指标和像素级别评价指标。本节课就给大家重点介绍下目标检测中的相关评价指标及其含义&#xff0c;希望大家学习之后…