【C++】指针是啥东西?看这篇博客就够了!

指针到底是啥东西?很多人都有这样的问题,今天我就为大家来解答

首先看一行代码:

int a;

很显然,这行代码的用途是定义变量,那么再看一行代码

int *a;

这下懵了吧,你们以为这是一行错误的代码,但恰恰相反,这行代码能够正常运行

这行代码定义的就叫做 指针

前期我们可以把它认为是一个数据结构,像这样

int* a;

 这样也是不会报错的。废话不多说,先来了解作用

1、认识指针

指针指针,顾名思义就是指向一个东西的针,但是编程中并没有针,所以我们只需要把它理解成指向一个东西的东西就行了,而它指向的那个东西叫做 地址 。

地址说白了就是存储变量的地方,比如说我们int a,就相当于定义了一个整型变量a,它有一个地址,也只有它有那个地址。

地址的格式一般是0x开头,后面一大串数字。行了,回归正题。

int* a是指向int类型的指针,同样地,char* a就是指向字符类型的指针。

int *a[10];
int[10] *a;

 看上面的两行代码。

第一行是指针数组,是一个全是指针的数组,数组的每个下标都是一个指针

第二行是数组指针,是指向数组的指针。

现在,指针你基本就了解了大概,接下来直接上代码来实际操作

注意:如果你是第一次接触指针,请你务必要自己用编译器,跟着我输入我提供的代码,你也可以修改代码中的值,自己去探索指针的功能

2、学习指针

接下来我们就该学习怎么用指针来指东西了。

int a;
int *b=&a;

注意,这里的&很重要,这是取地址符,你们学习scanf的时候应该接触过。一定要加上,不然程序会报错

这段代码是让指针b指向指针a的过程。 

是不是很简单?那怎么通过b来知道a的值呢

同样非常简单,只需要

cout << *b;

这里的*同样很重要!!!

很好,那指针之间怎么互相复制呢?

int* p1  = &a;
int* p2 = p1;

在看一段代码

int *a=NULL;

 你一定以为NULL不能赋给指针对不对,恰恰相反,这样是完全正确的,指针不能乱赋值,万一赋值道系统重要信息的地址,你的电脑就惨咯

当然,这种错误代码我就不给了,省的你们自己非想要尝试

任何指针都可以被赋值为NULL。

接着再看一段代码

char array1[20] = "abcdefghijklmnopqrs";
char *ptr1 = array1;
int *ptr2 = (int*)ptr1;ptr1++;
ptr2++;
cout << &array1 << endl;
cout << *ptr1 << endl;
cout << ptr2 << endl;
cout << *(char*)ptr2 << endl;
  1. array1 是一个字符数组,已被初始化为包含19个字符的字符串,并以空字符\0作为结尾,尽管在初始化时未显式包含。

  2. ptr1 是一个指向字符的指针,它已被初始化为指向array1的首地址。

  3. ptr2 是一个指向整数的指针,它通过将ptr1强制转换为整数指针类型来获得。

  4. ptr1 和 ptr2 都执行了递增操作。

接下来,我们逐一分析 cout 语句的输出:

cout << &array1 << endl;

这条语句输出array1数组的地址。

cout << *ptr1 << endl;

由于ptr1是字符指针,并且已经递增,所以这条语句输出array1中的第二个字符,即b

cout << ptr2 << endl;

ptr2是指向整数的指针,递增后它指向array1中原本第二个字符的地址,但以整数指针的视角来看。这条语句输出ptr2当前指向的地址。

cout << *(char*)ptr2 << endl;

这条语句首先将ptr2强制转换回字符指针,然后解引用以输出当前指向的字符。由于ptr2原本指向array1的第二个字符(在转换为整数指针并递增后),并且整数指针的递增通常基于整数的大小(在大多数平台上为4字节),这条语句实际上可能输出array1中第六个字符之后的内容,具体取决于整数大小和字节对齐。

下面是输出

上面就是指针的基础,接下来该学点新的了

函数指针

void change(int a)
{a++;      //在函数中改变的只是这个函数的局部变量a,而随着函数执行结束,a被销毁。
}int main()
{int age = 19;change(age);printf("age = %d\n",age);   // age = 19return 0;
}

实参传递给形参,是按值传递的,也就是说,函数中的形参是实参的拷贝份,形参和实参只是在值上面一样,而不是同一个内存数据对象。这就意味着:这种数据传递是单向的,即从调用者传递给被调函数,而被调函数无法修改传递的参数达到回传的效果。

有时候我们可以使用函数的返回值来回传数据,在简单的情况下是可以的,但是如果返回值有其它用途(例如返回函数的执行状态量),或者要回传的数据不止一个,返回值就解决不了了。

传递变量的指针可以轻松解决上述问题。

void change(int* pa)
{(*pa)++;   //因为传递的是age的地址,因此pa指向内存数据age。当在函数中对指针pa解地址时//会直接去内存中找到age这个数据,然后把它增1。
}
int main(void)
{int age = 19;change(&age);printf("age = %d\n",age);   // age = 20return 0;
}

那么函数的指针是什么呢

每一个函数本身也是一种程序数据,一个函数包含了多条执行语句,它被编译后,实质上是多条机器指令的合集。在程序载入到内存后,函数的机器指令存放在一个特定的逻辑区域:代码区。既然是存放在内存中,那么函数也是有自己的指针的。

其实函数名单独进行使用时就是这个函数的指针。

int add(int a,int b)		//函数的定义
{return a + b;
}int (*function)(int,int); 	//函数指针的声明function = add;		//给函数指针赋值
function = &add;		//跟上面是一样的int c = function(1,2);	 	//跟函数名一样使用
int d = (*function)(1,2);	//跟上面的调用是一样的

 上面的代码就实现了函数指针

 

 除了函数,还有一个东西有指针,它常常出现在我们的程序中,但是却很容易被忽视

它就是常量,你没听错,常量也有指针

int	a = 97;
int	b = 98;
int* const p = &a;
*p 	= 98;		//正确
//p 	= &b;		编译出错

常量指针本身就是个常量 。常量指针必须初始化,而且一旦初始化完成,则它的值就不能改变了。

同理,指向常量的指针也很容易

int a = 97;
int b = 98;       
const int* p = &a;
int const *p = &a; 	//两者的含义是一样的
//*p = 98;	    编译出错
p = &b;			//正确

3、练习 

最后的最后,给大家准备一些题,确保你学会了指针

void GetMemory(char* p)
{
    p = (char*)malloc(100);
}

void Test(void)
{
    char* str = NULL;
    GetMemory(str);
    strcpy(str,"hello world");
    printf(str);
}
运行的结果是什么?
 

int array[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int *p = array;
p += 5;
int* q = NULL;
*q = *(p+5);
printf("%d %d",*p,*q);
运行结果是什么?
 

int arr[5] = {0,1,2,3,4};
const int *p1 = arr;
int* const p2 = arr;
*p1++;
*p2 = 5;
printf("%d,%d",*p1,*p2);
*p1++ = 6;
*p2++ = 7;
printf("%d %d \n", *p1, *p2);
 

4、解析

第一道题:我们一看函数传递,指针只是浅拷贝,申请的内存在临时对象p中,并没有传递到函数外面,然后又对str地址进行写操作,str初始地址为NULL,不能进行书写,所以系统会崩溃。

第二道题:一看很开心是指针类型的加减法,下标从0开始,但是数字从1开始,所以应该是6 11。但是你忽略了q是一个NULL指针,不能进行书写,所以会崩溃。

第三道题:指针指向数组,数组退化成指针,前两个指针操作是对的。但是后面*p1++ = 6; 不可以通过p1进行值的修改,*p2++ = 7;不能对p2进行修改。所以这道题是编译出错。

好了,相信你看完本篇博客,一定对指针有所了解,点赞过20更新下一篇C++教程!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【规控+slam】探索建图方案及代码分享

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言背景建图描述SLAM定位+感知数据标记构建地图自动探索建图规划方法一:手动遥控探索建图算法步骤方法二:手动给定目标点探索建图算法原理方法三:f…

动态规划最低票价

前言&#xff1a;之前看到过这个题目归结到动态规划&#xff0c;当初还没什么思路&#xff0c;其实就是定义好dp [ i ] 为到第 i 个的最小费用就行&#xff0c;我们可以用upper_bound来优化我们的查找下标 题目地址 class Solution { public:int mincostTickets(vector<int&…

Minstrel自动生成结构化提示,让AI为AI写提示词的多代理提示生成框架

在人工智能快速发展的今天&#xff0c;如何有效利用大型语言模型&#xff08;LLMs&#xff09;成为了一个普遍关注的话题。这是9月份的一篇论文&#xff0c;提出了LangGPT结构化提示框架和Minstrel多代理提示生成系统&#xff0c;为非AI专家使用LLMs提供了强大支持。 对于非人…

SpringBoot框架下的社区医院信息系统开发

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理社区医院信息平台的相关信息成为必然。开发…

关于pip install -e .的一点理解

笔者在安装库时对教程里面的pip install -e .产生了一些疑惑&#xff0c;查资料解决如下 参考资料&#xff1a;【python pip特殊用法】pip install -v -e . 命令详解-CSDN博客 首先Sources Root就是根目录 笔者最开始将ultralytics以pip install -e .方式安装在了D盘ultraly…

家用高清投影仪怎么选?目前口碑最好的投影仪推荐

双十一马上要到了&#xff0c;而且今年还有投影仪的家电国补&#xff0c;所以大家入手投影仪的需求也越来越多&#xff0c;但是家用高清投影仪怎么选&#xff1f;什么投影仪最适合家用&#xff1f;家庭投影仪哪个牌子质量最好&#xff1f;今天就给大家做一个2024性价比高的家用…

国庆节快乐

葡萄城在这里祝大家国庆快快乐&#xff1a; 10月葡萄城活动&#xff1a; 公开课 【从软件应用走向数据应用——葡萄城技术赋能数据挖掘】 新版本发布&#xff1a; 活字格 V10.0 Update1新版本发布

等保测评:企业数字安全的坚实盾牌

1.1 企业数字化转型的浪潮 在当今时代&#xff0c;企业数字化转型的浪潮正以前所未有的速度席卷全球&#xff0c;据IDC预测&#xff0c;到2023年&#xff0c;全球数字化转型支出将达到惊人的2.3万亿美元。这一趋势不仅重塑了企业的运营模式&#xff0c;更对企业的信息安全提出…

昇思MindSpore进阶教程--使能图算融合

大家好&#xff0c;我是刘明&#xff0c;明志科技创始人&#xff0c;华为昇思MindSpore布道师。 技术上主攻前端开发、鸿蒙开发和AI算法研究。 努力为大家带来持续的技术分享&#xff0c;如果你也喜欢我的文章&#xff0c;就点个关注吧 正文开始 图算融合是MindSpore特有的网络…

氨基酸在PDB文件中的原子命名规则

氨基酸在PDB文件中的原子命名规则 氨基和羧基上的原子都采用本名&#xff0c;C, N, O, H, etc. 其它原子除 H 外&#xff0c;所有原子命名均采用“原子名后缀[编号]”形式。整体命名方法类似于图论中求解最大流问题时所采用的标号法。首先α-C被命名为CA。其后按照成键关系逐级…

Markdown笔记管理工具Haptic

什么是 Haptic &#xff1f; Haptic 是一个新的本地优先、注重隐私的开源 Markdown 笔记管理工具。它简约、轻量、高效&#xff0c;旨在提供您所需的一切&#xff0c;而不包含多余的功能。 目前官方提供了 docker 和 Mac 客户端。 Haptic 仍在积极开发中。以下是未来计划的一些…

尝鲜使用 YOLO V11 Fine-Tuning 训练自定义的目标检测模型

一、YOLO V11 2024年9月30日&#xff0c;Ultralytics官方团队宣布YOLOv11正式发布&#xff0c;标志着YOLO系列实时目标检测器的又一次重大升级。这一新版本不仅在准确性和检测速度上再创新高&#xff0c;还通过架构和训练方法的革新&#xff0c;极大地提升了目标检测的综合性能…

构建现代化社区医疗服务:SpringBoot平台

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理社区医院信息平台的相关信息成为必然。开发…

银行CRM系统的核心功能解析与应用价值

在当今竞争激烈的金融市场中&#xff0c;银行业务的成功与否&#xff0c;越来越依赖于高效而精准的客户关系管理系统&#xff08;CRM&#xff09;。Zoho CRM系统不仅帮助银行提升服务质量、增强客户满意度&#xff0c;还能有效地促进业务发展和风险控制。为了帮助读者更好地理解…

社区医疗健康管理:SpringBoot技术应用

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理社区医院信息平台的相关信息成为必然。开发…

如何从损坏的 USB 闪存驱动器中恢复文件

与您的内部硬盘驱动器一样&#xff0c;USB 闪存驱动器也将数据存储在其内存中。与笨重的硬盘不同&#xff0c;这些便携式拇指驱动器易于携带&#xff0c;并且很容易从中获取数据。除了有一天&#xff0c;当我们将其连接到 PC 只是为了发现数据无法访问时。您知道您保存了它&…

【算法竞赛】堆

堆是一种树形结构,树的根是堆顶,堆顶始终保持为所有元素的最优值。 有最大堆和最小堆,最大堆的根节点是最大值,最小堆的根节点是最小值。 本节都以最小堆为例进行讲解。 堆一般用二叉树实现,称为二叉堆。 二叉堆的典型应用有堆排序和优先队列。 二叉堆的概念 二叉堆是一棵…

vue2圆形标记(Marker)添加点击事件不弹出信息窗体(InfoWindow)的BUG解决

目录 一、问题详情 二、问题排查 三、解决方案 一、问题详情 地图上面的轨迹点希望能通过点击看到详细的经纬度信息&#xff0c;但是点击的时候就是显示不出来。 二、问题排查 代码都是参考高德的官方文档&#xff0c;初步看没有问题啊&#xff0c;但是点击事件就感觉失效…

Linux中的软硬链接和动静态库

硬链接 ln myfile.txt hard_file.link 264962 -rw-rw-r-- 2 zhangsan zhangsan 0 Sep 30 03:16 hard_file.link 264962 -rw-rw-r-- 2 zhangsan zhangsan 0 Sep 30 03:16 myfile.txt 273922 lrwxrwxrwx 1 zhangsan zhangsan 10 Sep 30 03:17 soft_file.link -> …

【Python报错已解决】error: subprocess-exited-with-error

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…