初试二级指针

初学二级指针与二维数组的关系

以一道例题来加深学习,上图
在这里插入图片描述在这里插入图片描述

题意:定义一个二级指针,指向3行3列的二维数组行地址,利用for循环嵌套,输出每一行首地址
和每一行的元素值
先看上面的两张图片,看似差不多每一行元素输出符合要求,再看地址值,咋一看一样,你品你细品。发现错误了吧,以16进制输出的地址值不一样,嗯有猫腻。仔细分析
先说明一下16进制,逢十六进一,由数字0-9和字母A-F组成(字母不区分大小写)第一张正确的地址输出为

0x6dfec0
0x6dfec8
0x6dfed8

我们只需要看到后两位即可,c8-c0=12
想想,二级指针变量+1=二级指针变量值(地址)+sizeof(二级指针变量指向的一级指针变量类型(int*))*n(这里的n是二维数组第一行元素的字节数4)。
p++===p+1
二位数组每一行可以当成一个一维数组,一维数组+1=一级指针变量值(地址)+size of(int)*1也就是加一个整型变量所占的内存单元数(4个字节)4byte.
这里可能不是那么好理解。
总之二级指针变量+1指向二维数组下一行首地址,而不是加一个内存单元数(4 byte)指向第一行第二列元素地址!!!
经过仔细思考,加上程序实践上述结论是错误的。

好,先决条件知道了,再来看看基础知识,二维数组。了解了他这个题便可以迎刃而解

二维数组可以省略行数。

原因:因为二维数组存储的时候是"先行后列", 如果不指定列数,
它就不能知道一行放几个数据了
。在初始化的时候,第二维的数字代表分配内存的长度,第一维的数字代表分配内存倍数;倍数可以让机器去数,但长度没有的话就不好开辟空间了。
只要知道了列数,
排头就可以知道一共能放多少行。定义二维数组时,省略之后要让计算机能够确定你定义的几行几列才可以假如你省略行数,但是确定了列数,计算机会根据你的列数的数值以及你初始化时给的数据,自动确定行数,因此行数可以省略。
但是如果给了行数但没有确定列数,对于你初始化的数据,计算机不知道怎么划分,是平均分呢?还是其他方式分呢?这是没有规定的,这样子会出现错误。

举个例子,你可能直接把一串元素值放在第一行,这样二维数组就没有任何意义了。

开始最后一步了,到这里你们应该恍然大悟了。还没有的同学跟我来。

#include <iostream>
using namespace std;
int main()
{
    int a[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
    int** p, i, j;
    p = (int**)a;
    int* p1;
    for (i = 0; i < 3; i++)
    {
        cout << p << endl;
        for (j = 0; j < 3; j++)
        {
            p1 = (int*)p ;
            cout << *p1 << " ";
            p++;
        }cout << endl;
	}
	return 0;
}

输出结果如下

   /*00D3F880-->13891712
    1 2 3
    00D3F88C-->13891724
    4 5 6
    00D3F898-->13891736
    7 8 9*/
#include <iostream>
using namespace std;
int main()
{
    int a[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
    int **p1, i, j,*p;
    for (i = 0; i < 3; i++)
    {
        p1 = (int**)a[i];//每一次循环p1-->二维数组每一行首地址
        cout << p1 << endl;//类似于p1=(int**)a 
        for (j = 0; j < 3; j++)//then p1=p1+3 or p1++放入for循环之中
        {
            p = (int*)p1 + j;
            cout << *p << " ";
        }cout << endl;
    }
    return 0;
}

在这里插入图片描述
在这里插入图片描述

我们可以看出p++在这里是没有起到我们以为的作用。
在这里插入图片描述
那么实际老师想要达到什么样效果呢? 我们先看p++在这个cpp中起到的作用。

#include <iostream>
using namespace std;
int main()
{
    int a[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
    int **p1, i, j,*p;
    p1 = (int**)a;
    for (i = 0; i < 3; i++)
    {
        cout << p1 << endl;//类似于p1=(int**)a 
        for (j = 0; j < 3; j++)//then p1=p1+3 or p1++放入for循环之中
        {
            p = (int*)p1 + j;
            cout << *p << " ";
        }cout << endl;
        p1++;//每一次循环p1-->二维数组第一行后一个元素地址
        //因为p1=p1+4只是加了一个数组元素所占的内存单元-->+4 byte;
        //then 二级指针的指向就发生了改变,并不是像我们想像的那样,p1指向了下一行首地址
        //now 他指向了a[0]+1的地址,并未指向a[1],所以就造成了控制台输出的outcome!
    }
    return 0;
}

输出结果,看样子并不是我们想要的。

0115FC6C
1 2 3
0115FC70
2 3 4
0115FC74
3 4 5

我们分析老师想要达到的effect。这里使用了指向数组的指针

#include <iostream>
using namespace std;
int main()
{
    int a[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
    int **p1, i, j,*p;
    //p1 = (int**)a;
    int(*ip)[3];
    ip = a;
    for (i = 0; i < 3; i++)
    {
        cout << ip << endl;
        for (j = 0; j < 3; j++)
        {
            p = (int*)ip + j;
            cout << *p << " ";
        }cout << endl;
        ip++;
    }
    return 0;
}

在这里插入图片描述
最后老师的效果更改一下就可以了。
在这里插入图片描述
最后再看看
理论与现实的差距
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值