指针学习笔记


最近SZU开始教指针,对于比较基础的概念和问题有一些自己的理解

特此将自己的学习过程记录下来

目录

二级指针

动态分配数组空间(二维及以上)与memset

int (*p)[3] 和 int *p[3]的区别

对数组名取&

函数指针

 一些零零碎碎


二级指针

输出结果:

可以看到注释的猜想基本正确。每一次new出来的空间是连续的,不同的new空间之间一般不连续

对于二级指针的理解这里有一篇很好的博客:

https://blog.csdn.net/yongheng_1999/article/details/52765130


动态分配数组空间(二维及以上)与memset

以前敲题经常会遇到动态分配的数组memet赋初值有误的问题,学懂了其原理以后就理解了

问题演示:

实际上会出现错误,甚至无法输出:

那么问题出在哪里呢,首先看一下memset的源码:

可以看出来memset是对连续空间进行逐字节赋初值的(关于其更深入的理解可以看下面链接),而对于以下数组定义方式,结果却是正确的:

仔细对比其中的区别就能轻松知道问题的根源:数组空间定义,还有sizeof()

数组空间定义:

结合前面我们对二级指针的理解,我们可以知道:当我们用动态分配的方式(new)来分配数组空间的时候,以a数组为例,(a[0][0], a[0][1], a[0][2])之间是连续的,(a[0][0], a[1][0], a[2][0])不一定是连续的,这个不一定来源于概率,我们当然不能期望这个概率,所以对于动态分配空间的数组,数组空间不连续,参考一下源码就知道memset无法对其进行赋值。而对于直接定义的a[3][3],数组空间是以a为首地址的3*3*sizeof(int)空间的连续空间,自然memset并没有问题

sizeof() :

输出直接定义的a和动态分配内存的b的sizeof()结果

可以看到结果并不一致

原因是这里的a是数组类型,空间大小是数组大小,b是指针类型(指向int*类型的指针),空间大小是sizof(int*)

此时有人会提问:a作为数组名不也是一个指针吗?其实不然,a其实是一种数据结构,名为数组。但是int *p=a为什么又合法呢?原因是数组名可以隐式转化为指代实体的指针常量。关于数组和数组名这里附一篇解读:数组名和指针的深入理解(C++) - fenghuan - 博客园

另附一篇关于memset原理的文章:

memset函数的使用原理_catTom的博客-CSDN博客_memset原理


int (*p)[3] 和 int *p[3]的区别

首先有:[]优先级高于*

int (*p)[3]:数组指针(行指针),数据类型 int(*)[3],指针p指向int[3]的数组,(*p)使得p优先被解释成指针,步长sizeof(int)*3

int *p[3]:  其实看成int* p[3]更有助于理解,数据类型为int*,空间大小为3*sizeof(int*),首地址为p的指针数组,[]使得p优先被解释为数组


对数组名取&

既然数组a可以隐式转化为其首地址,那么对a取地址结果又会是什么呢?

可以看到,两者的值是一样的,但这并不意味着两者可以等价

我们可以做一个实验:

可以看到:

&a[0]=a,这是正确的,因为a隐式转化为了数组的首地址

a+4=&a[1],这也是对的,因为&a[1]是数组第二个元素(下标从0开始)的地址,应该是首地址加上sizeof(int),也就是4

&a+1=a+12!=&a[1],这里看上去和我们的“数组名取地址等于数组名”的猜想不一致,事实上证明这个猜想是错误

《C和指针》p142中:在以下两种场合下,数组名并不是用指针常量来表示,就是当数组名作为sizeof操作符单目操作符&的操作数时。 sizeof返回整个数组的长度,而不是指向数组的指针的长度。 取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量的指针。

也就是说&a的类型实际上是数组指针int(*)[3],如果仔细阅读上文的话,就会知道其步长等于sizeof(int)*3=12,与测试中&a+1=a+12相吻合

总结:&a和a的结果一致,但数据类型是 数组指针int(*)[ ] 和 指针常量int* const 的区别


函数指针

函数指针类型可以理解为 数据类型+(*函数指针名)+参数类型 ,每一个函数对需要内存分配空间,而指针可以指向函数的首地址,函数指针示例如下图:

然而在以前敲Leetcode的时候,遇到过需要对sort函数自定义比较函数的情况,众所周知sort第三个参数是函数指针,但是单纯的写bool cmp()会报一下错误:

 翻译一下就是函数指针为非静态成员,加上static修饰即可通过

问题出在this指针。Leetcode的Solution是类形式存在,非静态成员函数参数列表会隐式添加this指针,普通类成员需要通过 对象名.cmp() 来调用cmp函数,但是sort在编译的时候无法访问对象,所以会出错,而static修饰类成员不用加对象名就可以直接访问函数

参考博客:恼人的函数指针(二):指向类成员的指针 - AnnieKim - 博客园


 一些零零碎碎

指针与左值、右值

引用:数组类型、函数类型到左值和右值的转换 - CG@CPPBLOG - C++博客

输出指针值的严格格式

printf, fprintf, sprintf, snprintf, printf_s, fprintf_s, sprintf_s, snprintf_s - cppreference.com

关于int* p和int *p

两者实际上不太存在差别,我个人建议用int *p的写法,这样更能强调p是个指针

关于delete和delete[]

参考博客:C++中的delete和delete[ ]的区别_Fearless的博客-CSDN博客_delete和delete[]

关于void*

参考博客:C 语言中 void* 详解及应用 | 菜鸟教程


指针内容博大精深,C++作为一门基础语言,很有必要学的透彻,这边建议人手一本C++ primer

发个钢铁侠:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值