数组指针和指针数组
1.数组指针
即数组的指针
1 2 3 4 5 6
| int c[3]; int a[3] = {4, 5, 6}; int b[3] = {1, 6, 10}; int (*p)[3];
p = &a;
|
1 2 3 4 5 6
| cout << "数组a的起始地址:" << a << "\n" << "数组b的起始地址:" << b << endl; ----------- 数组a的起始地址:0x61fdfc 数组b的起始地址:0x61fdf0
|
可以看到数组a和数组b位于栈空间上,a的起始地址大于b
1 2 3 4 5 6 7 8
| cout << "sizeof(a)=" << sizeof(a) << "\n" << "sizeof(p)=" << sizeof(p) << "\n" << "sizeof(*p)=" << sizeof(*p) << endl; ------------ sizeof(a)=12 sizeof(p)=8 sizeof(*p)=12
|
1 2 3 4 5 6 7 8 9 10 11
| #include<typeinfo> #include<cxxabi.h> cout << "p type:"<<abi::__cxa_demangle(typeid(p).name(), 0, 0, 0) << endl; cout << "*p type:"<<abi::__cxa_demangle(typeid(*p).name(), 0, 0, 0) << endl; cout << "a type:"<<abi::__cxa_demangle(typeid(a).name(), 0, 0, 0) << endl;
------------ p type:int (*) [3] *p type:int [3] a type:int [3]
|
p
表示指向包含三个int
型变量数组的指针,其存放的是==地址==,因此其占用空间大小根据机器是32
位还是64
位有所不同,我电脑是64
位的,因此其占用空间为8
字节。
*p
可以认为表示的是包含三个int
型变量的数组,因此其占用空间为3*4=12
字节,表示的就是整型数组a
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| cout << "数组a地址:" << a << "\n" << "a[0]地址:" << &a[0] << "\n" << "a[1]地址:" << &a[1] << "\n" << "a[2]地址:" << &a[2] << endl; cout << "*p =" << *p << "\n" << "*p + 1 =" << *p + 1 << "\n" << "*p + 2 =" << *p + 2 << endl; cout << "*(*p)=" << *(*p) << "\n" << "*(*p + 1)=" << *(*p + 1) << "\n" << "*(*p + 2)=" << *(*p + 2) << endl;
cout << "p =" << p << "\n" << "p + 1 =" << p + 1 << "\n" << "p + 1 =" << p + 2 << endl; cout << "*p =" << *p << "\n" << "*(p + 1)=" << *(p + 1) << "\n" << "*(p + 2)=" << *(p + 2) << endl; cout << "**p =" << **p << "\n" << "**(p + 1)=" << **(p + 1) << "\n" << "**(p + 2)=" << **(p + 2) << endl; cout << "p[0]=" << p[0] << "\n" << "p[1]=" << p[1] << "\n" << "p[2]=" << p[2] << endl;
sizeof(int)=4
数组a地址:0x61fdf0 a[0]地址:0x61fdf0 a[1]地址:0x61fdf4 a[2]地址:0x61fdf8 *p =0x61fdf0 *p + 1 =0x61fdf4 *p + 2 =0x61fdf8 *(*p)=4 *(*p + 1)=5 *(*p + 2)=6
p =0x61fdf0 p + 1 =0x61fdfc p + 1 =0x61fe08 *p =0x61fdf0 *(p + 1)=0x61fdfc *(p + 2)=0x61fe08 **p =4 **(p + 1)=0 **(p + 2)=6422000 p[0]=0x61fdf0 p[1]=0x61fdfc p[2]=0x61fe08
|
个人理解:
p
指向数组a
的地址(首地址)即a[0]
也即4
的地址,p+1
指向数组c
的地址(首地址)即将该指针往后移动length
字节,length
为p
指向数组的所有元素的字节数;这里我先定义数组c
,再定义数组a
使得p+1
指向数组c
(理论上可用p+1
指针访问数组c
,但实践中不能这样访问)
p
指向数组a
的地址(p
可以理解为指向二维数组的指针,但这里实际上指向一维数组),*p
指向数组a
第一个元素的地址,*p+1
指向数组a
第二个元素的地址,**p
则表示提领*p
地址的元素值。
对于二维数组arr
来说,p
指向数组arr[0]
即{1,6,9,4}
的地址,p+1
指向数组arr[1]
即{5,6,7,8}
的地址,以此类推。
*p
表示长度为4的整型数组,直接输出*p
即相当于输出其地址,使用**p
提领该*p
地址的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| int arr[3][4] = {{1, 6, 9, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; int(*p)[4]; p=arr; cout << &arr[0] << " " << &arr[1] << " " << &arr[2] << endl; cout << arr[0] << " " << arr[1] << " " << arr[2] << endl; ------------ 0x7ffc3814ec30 0x7ffc3814ec40 0x7ffc3814ec50 0x7ffc3814ec30 0x7ffc3814ec40 0x7ffc3814ec50 ------------ arr type:int [3][4] arr[0] type:int [4] &arr[0] type:int (*) [4] p type:int (*) [4] *p type:int [4] **p type:int
|
- 对于
arr[0]
和&arr[0]
来说,其类似于*p
和p
,因此直接输出两者值一样
- 由于
*p+n
可以代表数组a
的元素的地址,n从0开始,因此使用*p+1
和*p+2
依次访问a[1]
和a[2]
的地址,使用*(*p+1)即a[1]
和*(*p+2)即a[2]
访问对应的数据。若此时p
指向二维数组arr
,则p+1
指向数组arr
第二行的首地址即arr[1]
也即&arr[1]
,*(p+1)
表示该数组第二行第一个元素地址,*(p+1)+1
表示该数组第二行第二个元素地址,依次类推。
对于二维整型数组array[i][j]
来说,定义数组指针int (*p)[j]
来指向该数组array
即p=array
,则有如下结论:
p
指向该数组第一行,p+1
指向数组第二行,…,p+k
指向数组第k+1
行,依此类推;
*p
指向该数组第一行第一列元素,*p+1
指向该数组第一行第二列元素,…,*(p+k)+m
指向该数组第k+1
行第m+1
列元素
*p
表示该数组第一行第一列的元素即array[0][0]
,*(*p+1)
指向该数组第一行第二列的元素即array[0][1]
,…,*(*(p+k)+m)
表示该数组第k+1
行第m+1
列的元素即array[k][m]
数组指针指向一/二维数组
1 2 3 4 5 6 7 8 9
| int a[3]={4,5,6}; int (*p)[3]; p=&a; p=a;
----- a type:int [3] &a type:int (*) [3] p type:int (*) [3]
|
错误原因
1 2 3
| test.cpp:66:6: error: cannot convert 'int [3]' to 'int (*)[3]' in assignment p = a; ^
|
这是因为&a
是指整个数组的首地址,而a
是指数组首元素的首地址,虽然二者值相同的,但表示的意义不同。这里p
是数组指针,指向整个数组。p=&a
等号两边的数据类型完全一致,而p=a
等号两边的数据类型不一致,因此会提示错误信息。
==补充:a
表示数组名称,&a
表示整个数组的首地址,类型为int (*) [3]
,a+1
表示数组的第二个元素地址,类型为int*
,&a[0]
表示数组首元素地址,类型为int*
,a[0]
表示数组首元素值,类型为int
==
1 2 3 4 5 6 7 8 9
| int arr[3][4] = {{1, 6, 9, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; int(*p)[4]; p = arr; p = &arr;
------- arr type:int [3][4] &arr type:int (*) [3][4] p type:int (*) [4]
|
错误原因
1 2 3 4 5
| array2.cpp:10:6: error: cannot convert ‘int (*)[3][4]’ to ‘int (*)[4]’ in assignment 10 | p = &arr; | ^~~~ | | | int (*)[3][4]
|
这里错误的原因同一维数组
2.指针数组
1 2 3 4 5 6 7 8 9 10 11
| int *p[4]; int a[4] = {1, 2, 3, 4};
*p = &a[0]; *(p + 1) = &a[1]; *(p + 2) = &a[2]; *(p + 3) = &a[3];
|
这里给指针数组赋值不能只写*p=&a[0]
,否则后面利用它来访问数组的时候会出问题,因为没有把数组a
的其他元素地址赋值给指针数组p
的其他元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| cout << "&a[0]=" << &a[0] << endl; cout << "&a[1]=" << &a[1] << endl; cout << "&a[2]=" << &a[2] << endl; cout << "&a[3]=" << &a[3] << endl;
cout << "&p[0]=" << &p[0] << endl; cout << "&p[1]=" << &p[1] << endl; cout << "&p[2]=" << &p[2] << endl; cout << "&p[3]=" << &p[3] << endl; cout << "p[0]=" << p[0] << endl; cout << "p[1]=" << p[1] << endl; cout << "p[2]=" << p[2] << endl; cout << "p[3]=" << p[3] << endl;
cout << "*p=" << *p << endl; cout << "*(p+1)=" << *(p+1) << endl; cout << "*(p+2)=" << *(p+2) << endl; cout << "*(p+3)=" << *(p+3) << endl;
cout << "p=" << p << endl; cout << "p+1=" << p+1 << endl; cout << "p+2=" << p+2 << endl; cout << "p+3=" << p+3 << endl;
---------------
&a[0]=0x61fdd0 &a[1]=0x61fdd4 &a[2]=0x61fdd8 &a[3]=0x61fddc
&p[0]=0x61fde0 &p[1]=0x61fde8 &p[2]=0x61fdf0 &p[3]=0x61fdf8 p[0]=0x61fdd0 p[1]=0x61fdd4 p[2]=0x61fdd8 p[3]=0x61fddc
*p=0x61fdd0 *(p+1)=0x61fdd4 *(p+2)=0x61fdd8 *(p+3)=0x61fddc
p=0x61fde0 p+1=0x61fde8 p+2=0x61fdf0 p+3=0x61fdf8
|
这里p
是指针数组,类型为int* [4]
,其中存放的是一维数组a
的各个元素的地址,*p
是指针数组中的指针,类型为int*
,其存放的是一维数组a
中一个元素的地址。
对于指针数组p
,&p[0]、&p[1]、&p[2]、&p[3]
是指针数组p
自身的地址,用于存放数组a
的地址;p[0]、p[1]、p[2]、p[3]
存放的是数组a
的{1,2,3,4}
对应元素的地址。
使用指针数组p
来访问数组a
时,p[i]
和*(p+i)
都是取数组a
某个元素的地址,*p[i]
和*(*p+i)
都是取数组a
某个元素的值。
1 2 3 4 5 6 7 8 9 10 11 12
| int i; int *p[4]; int b[4][2] = {{1, 3}, {2, 4}, {5, 7}, {6, 8}};
*p = b[0]; *(p + 1) = b[1]; *(p + 2) = b[2]; *(p + 3) = b[3];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| cout << &b[0] << " " << &b[1] << " " << &b[2] << " " << &b[3] << endl; cout << b[0] << " " << b[1] << " " << b[2] << " " << b[3] << endl; cout << b << " " << b+1 << " " << b+2 << " " << b+3 << endl; cout << "&b[1] type:"<<abi::__cxa_demangle(typeid(&b[1]).name(), 0, 0, 0) << endl; cout << "b[1] type:"<<abi::__cxa_demangle(typeid(b[1]).name(), 0, 0, 0) << endl; cout << "b+1 type:"<<abi::__cxa_demangle(typeid(b+1).name(), 0, 0, 0) << endl; cout << "p type:"<<abi::__cxa_demangle(typeid(p).name(), 0, 0, 0) << endl; cout << "*p type:"<<abi::__cxa_demangle(typeid(*p).name(), 0, 0, 0) << endl; cout << "**p type:"<<abi::__cxa_demangle(typeid(**p).name(), 0, 0, 0) << endl; cout << "p[0] type:"<<abi::__cxa_demangle(typeid(p[0]).name(), 0, 0, 0) << endl;
---------------- 0x61fdd0 0x61fdd8 0x61fde0 0x61fde8 0x61fdd0 0x61fdd8 0x61fde0 0x61fde8 0x61fdd0 0x61fdd8 0x61fde0 0x61fde8 &b[1] type:int (*) [2] b[1] type:int [2] b+1 type:int (*) [2] p type:int* [4] *p type:int* **p type:int p[0] type:int*
|
对于二维数组b
,b+1、b[1]、&b[1]
的值都相同,但是其表示的意义不同;b+i
和&b[i]
表示二维数组第i+1
行数组(这里是一维数组)的首地址,b[i]
表示二维数组第i+1
行数组(一维数组)的第一个元素的首地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| cout << "&p[0]=" << &p[0] << endl; cout << "&p[1]=" << &p[1] << endl; cout << "&p[2]=" << &p[2] << endl; cout << "&p[3]=" << &p[3] << endl; cout << "p=" << p << endl; cout << "p+1=" << p+1 << endl; cout << "p+2=" << p+2 << endl; cout << "p+3=" << p+3 << endl;
cout << "*p=" << *p << endl; cout << "*(p+1)=" << *(p+1) << endl; cout << "*(p+2)=" << *(p+2) << endl; cout << "*(p+3)=" << *(p+3) << endl;
cout << "*(*p)=" << *(*p) << " " << "*(*p+1)=" << *(*p + 1) << endl; cout << "*(*(p+1))=" << *(*(p + 1)) << " " << "*(*(p+1)+1)=" << *(*(p + 1) + 1) << endl; cout << "*(*(p+2))=" << *(*(p + 2)) << " " << "*(*(p+2)+1)=" << *(*(p + 2) + 1) << endl; cout << "*(*(p+3))=" << *(*(p + 3)) << " " << "*(*(p+3)+1)=" << *(*(p + 3) + 1) << endl;
-------- &p[0]=0x61fe00 &p[1]=0x61fe08 &p[2]=0x61fe10 &p[3]=0x61fe18 p=0x61fe00 p+1=0x61fe08 p+2=0x61fe10 p+3=0x61fe18 *p=0x61fde0 *(p+1)=0x61fde8 *(p+2)=0x61fdf0 *(p+3)=0x61fdf8 *(*p)=1 *(*p+1)=3 *(*(p+1))=2 *(*(p+1)+1)=4 *(*(p+2))=5 *(*(p+2)+1)=7 *(*(p+3))=6 *(*(p+3)+1)=8
|
这里和数组指针访问二维数组基本一致
值得注意的是,用数组指针和指针数组同时指向二维数组时,其引用和使用数组名引用都是一样的
表示数组中i
行j
列的一个元素,下面的表示都是等价的:
*(*(p+i)+j)、*(p[i]+j)、(*(p+i))[j]和p[i][j]
3.二维数组相关
总结指针在数组中的一些应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| int array[3][3]={{1,3,6},{2,5,8},{5,10,100}};
cout << "array type:"<<abi::__cxa_demangle(typeid(array).name(), 0, 0, 0) << endl; cout << "array[0] type:"<<abi::__cxa_demangle(typeid(array[0]).name(), 0, 0, 0) << endl; cout << "&array[0] type:"<<abi::__cxa_demangle(typeid(&array[0]).name(), 0, 0, 0) << endl; cout << "&array[0][0] type:"<<abi::__cxa_demangle(typeid(&array[0][0]).name(), 0, 0, 0) << endl; cout << "array+1 type:"<<abi::__cxa_demangle(typeid(array+1).name(), 0, 0, 0) << endl; cout << "*array type:"<<abi::__cxa_demangle(typeid(*array).name(), 0, 0, 0) << endl; cout << "&(*array) type:"<<abi::__cxa_demangle(typeid(&(*array)).name(), 0, 0, 0) << endl; cout << "*&(*array) type:"<<abi::__cxa_demangle(typeid(*&(*array)).name(), 0, 0, 0) << endl;
---------------------- array type:int [3][3] array[0] type:int [3] &array[0] type:int (*) [3] &array[0][0] type:int* array+1 type:int (*) [3] *array type:int [3] &(*array) type:int (*) [3] *&(*array) type:int [3]
|
从上面的输出可以看出,array
是数组名,同时也可以说成是指向array[0][0]
地址的指针,此时,array
/array[0]
/&array[0]
/&array[0][0]
的值是一样的,都是指向数组最开始的地址,但它们表示的含义是不同的。
从类型结果来看,array
/array+1
/array+2
分别是该数组每一行整个一维数组的地址,等同于&array[0]
/&array[1]
/&array[2]
;*array
/*(array+1)
/*(array+2)
分别是该数组每一行的首地址,等同于array[0]
/array[1]
/array[2]
;
==相当于C语言直接将相邻的方括号[]
使用*
来表示,比如说a[1]和1[a],最后展开后是*(a+1)
和*(1+a)
,本质上都是相同的==;
还有值得注意的就是,&
和*
的操作是互逆的,这里&
是取地址操作符,这里*
是指针运算符,也能说是取内容运算符,相当于找到该指针指向变量的值。
参考链接:
数组指针和指针数组
数组指针和指针数组的区别