数组和auto的问题。

数组和auto的问题。

写在前面的话:可以先看看文章末尾的总结,如果可以明白答案就不必浪费时间。如果想看内容建议先了解一下数组指针的问题,比如大概知道 int(*)[][]、int **、int(*)[]这些都代表什么。

  • 问题起源:

在看书时学习了范围for,于是乎就操作一下

int arr[5]={1,2,3,4,5};
for(auto i:arr)
    cout<<i<<endl;

跑了一下感觉挺舒服,减少代码长度,看起来也很简洁,而且不用考率数组越界等什么乱七八糟的问题。那么一个二维数组的范围for怎么写呢?我抖了个激灵大手一挥写下下面的代码

int arrt[2][3]={1,2,3,4,5,6};
for(auto i:arr)
    for(auto j: i)
        cout<<j<<endl;

感觉自己很机智,巧用i来做内层范围,然而编译一下……bang~炸了。网上搜了一下说要这么写

int arrt[2][3]={1,2,3,4,5,6};
for(auto &i:arr)
    for(auto j: i)
        cout<<j<<endl;

why?仅仅相差一个&(引用),就导致不同的结果。Google一番,各种花式解决问题,但是根本不能说明其到底为什么错误。各种分析含糊其词有甚者大谈特谈int**类型。好吧,幸好我读了一点点书,不然就信了他们的鬼话。于是就只能自己慢慢往出来试了。(我承认博客有错误是正常的,每个人在初学的时候都有理解不透彻的时候,但是在查找很久仍然没有找到结果的我心里很难受,忍不住想要吐槽……这就像现在正在看这个博客的你一样,心里在大骂这个博主戏精一个,废话真多,说了这么多还没讲到重点,浪费我时间……)好好好,废话就不说了我们开始来思考这个问题。

  • 多维数组范围for循环遍历时,外层循环变量为什么要引用。
    • 这个问题的本质是auto一个数组会是什么结果
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
    int arrt[2][3]={1,2,3,4,5,6};//ok,这是一个二维数组,下面让我们看看arrt到底是个什么玩意
    int (*p0)[2][3]=&arrt;//可以看到arrt这个变量的地址是一个int(*)[2][3]型,并不是什么int**,可以用一个这样的指针指向这样的数组。
    int (*p1)[3]=arrt;//arrt是一个二维数组,他的数组名表示一个他里面的第一个一维数组的首地址,可以用一个类型int(*)[3](长度为三的一维数组指针)来指向他。
    int *p2 =arrt[0];//arrt[0]这是一个一维数组,他表示一维数组的第一个元素的首地址(int *),自然可以让int *来指向他。
//搞清楚这些,我们来看看auto一个数组有什么结果(可以和上面对比)
    auto &art0=arrt;//q0,一个二位数组(别名)
    auto q0=&arrt;  //q1,一个int(*)[2][3](指向一个两行三列的数组指针)
    auto q1=arrt;   //q2,一个int(*)[3](指向一个长度为三的一维数组指针)
    auto q2=arrt[0];//q3,一个int *(指向一个int型)
/*  这里我们可以看出:aout加上&,结果是引用一个数组
                   auot不加&,结果是其对应的指针
    这就是问题的关键,一个是 数组,一个是指针。下面是打印他们的类型。
*/
    cout <<"arrt=  "<<typeid(arrt).name()<<endl;
    cout <<"p0  =  "<<typeid(p0).name()<<endl;
    cout <<"p1  =  "<<typeid(p1).name()<<endl;
    cout <<"p2  =  "<<typeid(p2).name()<<endl;
    cout <<"art0=  "<<typeid(art0).name()<<endl;
    cout <<"q0  =  "<<typeid(q0).name()<<endl;
    cout <<"q1  =  "<<typeid(q1).name()<<endl;
    cout <<"q2  =  "<<typeid(q2).name()<<endl;
}

这里写图片描述

  • 理清楚上面的东西后我们就可以继续分析最上面范围for 里的 i 的类型
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
    int arrt[2][3]={1,2,3,4,5,6};//ok,依然这是一个二维数组
    /***
    for(auto i:arrt)
    这里是要把arrt的第一个元素拿出来对i进行初始化,具体看下面
    */
    for(auto i:arrt)//auto i=arrt[0];
    {
        cout <<typeid(i).name()<<endl;
        //arrt中有两个成员所以循环两次
    }
    for(auto &i:arrt)//auto &i=arrt[0];
    {
        cout <<typeid(i).name()<<endl;
        //arrt中有两个成员所以循环两次
    }
    /***
    有了上面的分析,我们很容易知道,第一个i是一个指针(int *)
                               第二个i是一个数组(引用)
    而在范围for循环里面的范围(只能是一个集合,例如数组,string,vector……)是不允许是一个指针的。
    所以编译器自然就会报错。
    */
}

这里写图片描述
OK!大功告成,终于把你们忽悠的看到这里了……嘿~
总结一下,其实就是不加&,i是一个int * 指针,就不能作为下一次范围for 的范围。加了&就是引用一个数组,就可以作为下一次范围for 的范围。
最后吐槽写一篇博客好**累啊,好**麻烦啊。青山不改绿水长流,各位看客咱们有缘再见。
对了如果有朋友觉得上面的知识有问题,有困惑敬请留言,一起讨论学习~。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值