zoukankan      html  css  js  c++  java
  • C++数组,指针,引用以及三者的复合类型

    C++数组,指针,引用以及三者的复合类型

    这里省去了对这三者的单独介绍,仅仅介绍使用这三者组成的组合类型。

    一、两两组合

    这三者的两两组合有9种:

    数组

    指针

    引用

    数组

    数组的数组

    数组的指针

    数组的引用

    指针

    指针的数组

    指针的指针

    指针的引用

    引用

    引用的数组

    引用的指针

    引用的引用

    1、指针的指针、数组的数组、数组的指针、指针的数组

    指针的指针(二维指针),数组的数组(二维数组),数组的指针和指针的数组这里就不介绍了,很多博客文章书籍都有详细的介绍。它们的形式是:

    指针的指针: int** a = NULL;

    数组的数组: int a[2][3] = {0};

    数组的指针:int (*a)[10];//a指向有10个元素的int型数组

    指针的数组:int *a[10];//a是一个数组,有10个元素,元素的类型是(int *)

    下面才是讨论的主题,C++中引入引用类型的时候,事情有点复杂了。我在尝试使用一个指针数组的时候,发现以后会以引用的方式将该数组传入函数,第一次发现自己完全不会定义这三者的组合类型,找了一些资料,将这三者的复合类型总结成这篇文章。

    2、数组的引用,引用的数组

    引用与数组,引用与指针进行组合的时候,网上还是有一些介绍的,它们的形式是:

    数组的引用:

    int a[3] = {1,2,3};

    int (&b)[3]=a;

    和数组的指针是不是很相似??所以引用的数组是不是也应该是以下这样的?

    int h = 4;

    int &c = h;

    int &d = a[1];

    int &e = a[1];

    int &f[3] = {c,d,e};//error

    但这是错误的,C++无法定义引用的数组,编译器不会通过。经典的解释(《C++ Primer》)是:引用不是对象。我自己的想法是:引用传递的不仅仅是值,还有变量的地址信息,多个引用指向的变量内存上不一定是连续的(如上例中的ha[1]),不一定是不同的地址(如上例中的引用de指向同一个变量);但是数组的元素地址必须是连续的。

    太好了,下面就不会有由引用的数组组成的麻烦的复合类型了!!

    3、指针的引用,引用的指针

    指针的引用和引用的指针,对这两者的介绍也不少,

    指针的引用:

      int a = 0;

    int * p = &a;

    int* &b = p; 

    引用的指针:和引用的数组一样,没有这种东西,依然采用经典的解释:引用不是对象。

    这样我们又去掉了一种组合,以后也不会有由引用的指针组成的复合类型了。

    4、引用的引用

    引用的引用,你当然可以这么做:

    int a = 0

    int  &b = a;

    int &c = b;

    但是不能定义这样的引用:

    int  a = 0;

    int &&b = a;//error

    int &(&b) = a;//error

    (指针也不能这么干:int ** p = &&a;//error,不解释)

    总之,忘了以上两种错误的方式:

    第一种,g++给出的编译信息如下:

    error: expected unqualified-id before ‘&&’ token

         int &&p = a;

    第二种,g++给出的编译信息如下:

    error: cannot declare reference to ‘int&’, which is not a typedef or a template type argument

         int &(&p) = a;

    好了,这样我们进行三者组合的时候就可以去掉了9种中的3种。

    我们先列出可以使用的两者组合:

    数组

    指针

    引用

    数组

    数组的数组

    数组的指针

    数组的引用

    指针

    指针的数组

    指针的指针

    指针的引用

    引用

    二、三者的组合情况

    1、指针的指针的指针、数组的数组的数组

    数组

    指针

    引用

    数组的数组

    数组的数组的数组

    数组的数组的指针

    数组的数组的引用

    数组的指针

    数组的指针的数组

    数组的指针的指针

    数组的指针的引用

    数组的引用

    数组的引用的数组

    数组的引用的指针

    数组的引用的引用

    指针的数组

    指针的数组的数组

    指针的数组的指针

    指针的数组的引用

    指针的指针

    指针的指针的数组

    指针的指针的指针

    指针的指针的引用

    指针的引用

    指针的引用的数组

    指针的引用的指针

    指针的引用的引用

    1、不存在的类型

    数组的引用的数组,数组的引用的指针,数组的引用的引用,指针的引用的数组,指针的引用的指针,指针的引用的引用这些复合类型不存在,参考两两组合。

    2、指针的指针的指针、数组的数组的数组

    指针的指针的指针,数组的数组的数组:三维指针和数组,它们的形式分别为:

    int *** p = NULL;

    int a[2][4][3] = {0};

    3、指针的指针的数组

    指针的指针的数组:参考指针的数组,毕竟指针的指针也是指针,它的形式如下:

    int ** a[2];//a是一个有两个元素的数组,元素的类型是int**

    4、指针的指针的引用

    指针的指针的引用:参考指针的引用,它的形式如下:

    int **&b = a[0];

    5、数组的数组的指针

    数组的数组的指针:参考数组的指针,毕竟数组的数组也是数组,它的形式如下:

    int (*p)[2][3] = NULL// p是一个指针,指向一个23列元素为int型的数组。

    6、数组的数组的引用

    数组的数组的引用:参考数组的引用,和数组的数组的指针类似,形式如下:

    int a[2][3] = {0};

    int (&r)[2][3] = a;

    7、数组的指针的数组

    我读的程序不多,没见过有这么用的程序,我自然也没这么用过,不过依然不妨碍我们给出此类对象的定义:

    指针的数组是这么定义的:

    int *b[2] = {NULL,NULL};

    其实写成这样也没问题:

    int *(b)[2] = {NULL,NULL};

    这个指针的数组中存放的指针指向int型,现在要改成指向int数组型,比如 int [2],只要将b替换成一个int数组就可以了:

    int *(b[2])[2] = {NULL,NULL};

    好了,数组的指针的数组类型定义好了,这是一个存放两个指针的数组,这种指针指向有两个int型元素的数组。

    我想以后如果你想定义数组的指针的数组的指针的数组的时候,也可以这样一步步代入来完成这种复合类型。

    int *(*(a[2])[2])[2] = {NULL,NULL};

    如果选择从数组的指针开始推导会挺困难的。我是没有推出来。

    8、数组的指针的指针

    数组的指针类型是这么定义的: int (*a)[2] = NULL;

    也可以这么写:int (*(a))[2] = NULL;

    所以如果想对a再次取地址,那么使用*a替换a,所以数组的指针的指针对象的定义是这样子的:

    int (*(*a))[2] = NULL;

    对比上一个数组的指针的数组,你可能会有如下的疑问:

    指针的指针是这样的:int ** a = NULL;

    根据数组的指针的数组的推导经验,数组的指针的指针应该这样得出:

    int ** (a) = NULL;

    int ** (a[2]) =NULL; //error 

    遗憾的是,编译不通过。我暂时不知道什么原因。

    比较以上两种复合类型的推导,我们似乎没发现有什么很固定的规律。一切都是经验之谈。再等等,后面应该会看到规律。

    9、指针的数组的数组

    这个比较容易,因为指针的数组是这样的:int *a[2] = {NULL,NULL};

    所以可以很容易就写出来:

    int *a[2][2] = {0};

    10、指针的数组的指针

    指针的数组:int *a[2] = {0};

    也即:int *(a)[2] = {0};

    所以,指针的数组的指针:int *(*a)[2] = NULL;

    规律我也不知道该怎么总结,不过我把我的经验写成一个例子应该比较好理解。

    综合以上几种复合类型,我们就可以在c或者c++中组合出非常丧心病狂的复合类型,比如:数组的指针的指针的数组的数组的指针的数组的指针的指针

    我的方法是这样的:

    从右面数,找到第一个数组

    数组的指针的指针的数组的数组的指针的数组的指针的指针

    什么样的数组?指针的数组

    数组的指针的指针的数组的数组的指针的数组的指针的指针

    所以先定义的一个指针的数组

    int *(a)[2] = {0};

    那么a是一个什么样的指针呢?数组的指针?还是数组的数组的指针?我们把所有的修饰型数组全部取完,所以是数组的数组的指针:

    数组的指针的指针的数组的数组的指针的数组的指针的指针

    int *(a[2][2])[2] = {0};

    那么a这个数组的数组中存放的是什么呢?指针?指针的指针?我们把所有的修饰型指针全部取完,所以存放的是指针的指针:

    数组的指针的指针的数组的数组的指针的数组的指针的指针

    int *(**a[2][2])[2] = {0};

    那么现在a是一个什么样的指针呢?数组的指针:

    数组的指针的指针的数组的数组的指针的数组的指针的指针

    int *(**(a[2])[2][2])[2] = {0};

    好了,前半部分推完,还有后面一部分:

    现在我们知道a是一个数组,我们还要取它的指针的指针呢:

    数组的指针的指针的数组的数组的指针的数组的指针的指针

    int *(**((**a)[2])[2][2])[2] = NULL;

    完成!!!!

    好吧我没测试这个写到底对不对。

    这个已经够复杂了,但这还没在里面加入函数指针呢……

     

    好了,下面终于到引用了

    11、数组的指针的引用

    很显然,先写出数组的指针,于是

    int (*p)[2] = NULL;

    该指针的引用,参考指针的引用,于是

    int (*&r)[2] = p;

    12、指针的数组的引用

    很显然,先写出指针的数组,于是

    int *p[2] = {0};

    参考数组的引用,于是

    int *(&r)[2] = p;//这个括号不能省

    总结一下可用的三者组合的复合类型,共12种:

    数组

    指针

    引用

    数组的数组

    数组的数组的数组

    数组的数组的指针

    数组的数组的引用

    数组的指针

    数组的指针的数组

    数组的指针的指针

    数组的指针的引用

    数组的引用

    指针的数组

    指针的数组的数组

    指针的数组的指针

    指针的数组的引用

    指针的指针

    指针的指针的数组

    指针的指针的指针

    指针的指针的引用

    指针的引用

  • 相关阅读:
    各大代码托管服务器的分析比较
    《构建之法》读后
    【转】简单的程序诠释C++ STL算法系列之十五:swap
    【转】error while loading shared libraries: xxx.so.x" 错误的原因和解决办法
    C++大会感悟
    一次DDOS攻击引起的安全漫谈
    为npm设置代理,解决网络问题
    Rust 中的类型转换
    Rust 智能指针(二)
    软件设计原则
  • 原文地址:https://www.cnblogs.com/the-anxiety-of-bees/p/5349221.html
Copyright © 2011-2022 走看看