12 指针进阶

12 指针进阶 写的烦且烂,别看

0. 写在前面

定义纯地址数值运算:
运算过程用【】括起来,内部运算只考虑地址值不考虑指针类型,表示地址单位字节的常数应当加上符号byte.
例如:int a[3][4]

 a=&a[0][0]
 a+1=a+16byte

  1. 这里指a的地址值和a[0][0]的地址值数值相等,而不考虑a应为int(*)[4]类型,而a[0][0]为int*类型;
  2. a+1在C++中表示指针运算,增加sizeof(基类型)个字节,这里转换字节数后填上单位以免引起误解.

1. 一维数组与指针

short a[10];
一维数组的数组指针和数组元素指针具有相同的基类型,但本质上还是有区别的
sizeof(a)=20sizeof(*(&a[0]))
当然,如果类似于fun(short a[])这样的函数:
将a作为参数传入,sizeof(short)只会当指针处理输出4,而非20,形参的传递的为指针,长度数据丢失了.

然后就是 p[i]=*(p+i) ,总之比较简单基础.

3. 多维数组与指针

3.1 从二维数组开始

3.1.1 基本描述

先理解从一维数组拓展过来的几个等价关系:
地址: & a [ i ] ⇔ a + i \&a[i] \Leftrightarrow a+i &a[i]a+i
: a [ i ] ⇔ ∗ ( a + i ) a[i]\Leftrightarrow *(a+i) a[i](a+i)

特殊的:
a ⇔ a + 0 ⇔ & a [ 0 ] a\Leftrightarrow a+0\Leftrightarrow\&a[0] aa+0&a[0]
∗ a ⇔ ∗ ( a + 0 ) ⇔ a [ 0 ] *a\Leftrightarrow *(a+0)\Leftrightarrow a[0] a(a+0)a[0]

例如:
int a[3][4];
在这里插入图片描述

这个二维数组可以看成一个3元的一维数组,元素类型为4元一维数组,而4元一维数组的元素为int类型.

讨论 a , a+i , &a[i]:

  1. 二维数组数组名为a;
  2. 数组名=数组地址=数组首元素地址;
    ∴ \therefore 二维数组地址为a
    a=&a[0]
    ∴ \therefore 数组是一个三元数组,其首元素为第一个四元一维数组,a为该元素(四元一维数组)的地址,行地址

    那么 a+i=&a[i] =第i+1个四元一维数组的地址…行地址


    延伸一下:
     既然a=&a[0]是第一个四元一维数组的地址,那么根据数组名=数组地址可不可以理解a为该一维数组的名称呢?根据数组地址=数组首元素地址是否又可以理解a也为四元一维数组首个int元素的地址呢?
     先回答第二个问题:是的,如上图所示,a=2000,&a[0]=2000,&a[0][0]=2000,这不难理解;
     第一个问题的答案是显然错误的,如果a能够理解为四元一维数组名称,那么推出a[1]对应int,明显与实际上对应的一维数组类型错误.
    原因是:尽管对应的地址值一致,但用来承载该地址的指针类型是不同的.在这里编译器已经帮你做了处理,使得:
    a. 使用int*指针承载的a对应地址(0097FD6C),理解为元素地址,通过pt[i]访问int元素;
    b. 使用int (*)[4]指针承载的a对应地址(0097FD6C)的p[i],理解为行地址访问一维数组元素,通过p[i][j]访问int元素.
     因此这条规则应当加上一个注解:数组地址=数组首元素地址=数组名地址,而当地址被指针承载后,具体的使用依赖于指针对应的基类型!
    在这里插入图片描述

讨论 a[i],*(a+i):
 一般来说二维数组a的元素为一维数组,那么a[i]就应该是取出这个一维数组元素.
 取出一个数组,可能不像取出一个int值得到100一样好理解,实际上取出的一个地址,大致可以理解为取出数组变量,取出数组名.数组的值是抽象的,只有访问其中具体元素时才能具象成100,123.5这样的数据.
 a[i]的元素数组的值就是数组变量即数组名,如a[3][4]含有的3个一维数组元素的数组名依次为a[0],a[1],a[2].

  1. a[i]=四元一维数组的数组名=四元一维数组首元素地址=int类型的元素地址
3.1.2 绕晕你的辨析题

在这里插入图片描述
地址: & a [ i ] ⇔ a + i \&a[i] \Leftrightarrow a+i &a[i]a+i
值: a [ i ] ⇔ ∗ ( a + i ) a[i]\Leftrightarrow *(a+i) a[i](a+i)
基本思路还是按如上两个公式来,尽可能向a[ ]和a[ ][ ]形式转换:

  • 行地址:

    1. a=a+0=&a[ 0 ]
    2. &a[ i ]
    3. a+i=&a[ i ]
  • 元素地址:

    1. a[ i ]=a[ i ]+0=&a[ i ][ 0 ]
    2. *(a+i)=a[ i ]=a[ i ]+0=&a[ i ][ 0 ]
    3. &a[ i ][ j ]
    4. a[ i ]+j=p+j=&p[ j ]=&a[ i ][ j ]
    5. *(a+i)+j=a[ i ]+j=&a[ i ][ j ]
    1. a[ i ][ j ]
    2. *(a[ i ]+j)=*(&a[ i ][ j ]) =a[ i ][ j ]
    3. *(*(a+i)+j)=*(a[ i ]+j)=*(&a[ i ][ j ])=a[ i ] [ j ]
3.1.3 指针加法测试

在这里插入图片描述
怎么理解?指针类型的分析先化为&形式

  1. a属于行指针,a+1,(a+1)+1均为行指针的加法,改变量为基类型大小,int(*)[4]行指针的基类型为int[4]数组,因此与a差16和32
  2. *(a+1)=a[1]=a[1]+0=&a[1][0],说明*(a+1)和*(a+1)+1为元素指针,两者相差sizeof(int)=4.a[1]首元地址值和a[1]地址相同 ⇒ \Rightarrow a[1]地址值等于a[0]地址值+16 ⇒ \Rightarrow a[0]地址值等于a地址值,因此为a+16
  3. a[2]=a[2]+0=&a[2][0],是元素指针,因此两者相差4;与a相比:
    (地址运算,单位字节)
    &a[2][0]=&a[2]=&a[0]+244=a+32
  4. &a[2],行指针,差32
    完整解答如下:
    在这里插入图片描述
3.1.4 sizeof测试

在这里插入图片描述

3.1.5 行指针
  1. int (*p)[4];
    指向4个int组成的一维数组的指针.

分析步骤:
int (*p)[4]=a;
(*p)视为整体(类似数组名),有四个int元素;
p指向的东西有四个int元素
p指向一个int[4]数组
同时:a=&a[0],即a[0]数组的地址赋给p.

判断指针类型!
type* p=&type!,所以想办法化出&
判断指针运算!化出&知道type,用sizeof(type)就行!

  1. p[i][j]=(p[i]+j)=(*(p+i)+j)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值