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》)是:引用不是对象。我自己的想法是:引用传递的不仅仅是值,还有变量的地址信息,多个引用指向的变量内存上不一定是连续的(如上例中的h和a[1]),不一定是不同的地址(如上例中的引用d和e指向同一个变量);但是数组的元素地址必须是连续的。
太好了,下面就不会有由“引用的数组”组成的麻烦的复合类型了!!
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是一个指针,指向一个2行3列元素为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种:
数组 |
指针 |
引用 |
|
数组的数组 |
数组的数组的数组 |
数组的数组的指针 |
数组的数组的引用 |
数组的指针 |
数组的指针的数组 |
数组的指针的指针 |
数组的指针的引用 |
数组的引用 |
|||
指针的数组 |
指针的数组的数组 |
指针的数组的指针 |
指针的数组的引用 |
指针的指针 |
指针的指针的数组 |
指针的指针的指针 |
指针的指针的引用 |
指针的引用 |