面试题之数组指针和指针数组的区别

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sum_TW/article/details/53540866

1、数组指针(指向数组的指针)

(1)数组在内存中的表示

创建一个数组就是在内存里面开辟一块连续的空间,比如int a[4];就是在内存里面开辟了一个大小为4*sizeof(int)字节的内存空间。二维数组是特殊的一维数组。

先来看一段代码:

[cpp] view plain copy
  1. <strong><span style="font-size:16px;">void main()  
  2. {  
  3.     int a[2][2]={1,2,3,4};//这是一个2*2的二维数组  
  4.     int (*p)[2];//数组指针  
  5.     p=a;//令p指向数组a  
  6. }</span></strong>  


注意到代码中这句话:int (*p)[2];这里的p是一个数组指针变量。

a中各个元素在内存中是这样存放的:

 

(2)理解数组名和数组指针变量

OK,现在我们思考a,a[0],a[1],p,a+1,a[0]+1,p+1到底是什么,思考3秒钟:

分析:

a是一个数组名,类型是指向一维数组的指针,不是变量,a的值是指针常量,即不能有a++或者a=p这些操作。a指向这块连续空间的首地址,是&a[0][0]。

a[0]是一维数组名,类型是指向整型的指针,是&a[0][0],这个值是一个常量。

a[1]是一维数组名,类型是指向整型的指针,是&a[1][0],这个值是一个常量。

p是一个数组指针变量,指向一维数组的指针变量是&a[0][0]。可以执行p++;p=a等操作。

a+1表示指向下一行元素,也可以理解为指向下一个一维数组。

*(a+1)是取出第一行的首地址。

a[0]+1是指向第0行第1个元素,也可以理解为指向一维数组a[0]的第一个元素。

p+1同a+1

*(p+1)同*(a+1)

虽然a跟a[0]值是一样,但类型不一样,表示的意义不一样。通过分析就不难理解为什么*(*(a+i)+j)和a[i][j]等效了。

 

(3)指针是数组的迭代器

[cpp] view plain copy
  1. <span style="font-size:16px;">#include<stdio.h>  
  2. #define M 2  
  3. #define N 3  
  4.   
  5. int main()  
  6. {  
  7.     int a[M][N]={1,2,3,4,5,6};  
  8.     int *start=&a[0][0];  
  9.     int * const end=start+M*N;  
  10.     for(;start!=end;start++)  
  11.         printf("%-5d",*start);  
  12.     putchar('\n');  
  13.     return 0;  
  14. }</span>  


理解这段代码,用指针遍历一个二维数组,是不是很像C++标准库里面vector的迭代器。注意这里只用了一个for循环,这也可以说明二维数组其实就是特殊的一维数组。

 

(4)数组名与数组指针变量的区别

 

从(2)中的分析中得出数组名是指针,类型是指向元素类型的指针,但值是指针常量,声明数组时编译器会为声明所指定的元素数量保留内存空间。数组指针是指向数组的指针,声明指针变量时编译器只为指针本身保留内存空间。

 

看看这个代码:

[cpp] view plain copy
  1. <strong><span style="font-size:16px;">#include<stdio.h>  
  2. void main()  
  3. {  
  4.     int a[2][2]={1,2,3,4};//这是一个2*2的二维数组  
  5.     int (*p)[2];//数组指针  
  6.     p=a;//令p指向数组a  
  7.     printf("%d\n%d\n",sizeof a,sizeof p);  
  8. }</span></strong>  

猜一猜输出是什么?


困惑了吗?为什么结果会是这样的呢,让我们先初步了解一下sizeof关键字吧,下面是MSDN上sizeof的说明:

 



注意到说明中的红色字体,当sizeof用于变量时返回这个变量占用的实际空间的大小。当sizeof用于数组名时,返回整个数组的大小(这里的大小指占用的字节数)。p是一个指针变量,这个变量占用四个字节。而a是数组名,所以sizeof a返回数组a中的全部元素占用的字节数。

 了解了sizeof,猜猜下面这段代码输出什么

[cpp] view plain copy
  1. <span style="font-size:16px;"><strong>#include<stdio.h>  
  2.   
  3. void main()  
  4. {  
  5.     int a[2][2]={1,2,3,4};//这是一个2*2的二维数组  
  6.     int (*p)[2];//数组指针  
  7.     p=a;//令p指向数组a  
  8.     printf("%d\n%d\n",sizeof(a+1),sizeof(p+1));  
  9.     printf("%d\n%d\n",sizeof(a+0),sizeof(p+0));  
  10. }</strong></span>  


运行结果:

从结果中看出,a在做+运算时是转化成了指针变量,此时a+i的类型是一个指针变量,而不是一个数组名。但a[i]是一个一维数组的数组名,sizeof(a[0])的值是8

 

现在再来看一段代码:

[cpp] view plain copy
  1. <strong><span style="font-size:16px;">#include<stdio.h>  
  2.   
  3. void f(int a[][2])  
  4. {  
  5.     printf("%d\n",sizeof a);  
  6. }  
  7. void main()  
  8. {  
  9.     int a[2][2]={1,2,3,4};//这是一个2*2的二维数组  
  10.     printf("%d\n",sizeof a);  
  11.     f(a);  
  12. }</span></strong>  

再猜一下输出是什么?

是不是又有点困惑呢?

解释:这是因为传参的时候数组名转化成指针变量,注意到函数f中f(int a[][2])这里并不需要指定二维数组的长度,此处可以改为int (*a)[2]。所以传过来的就是一个数组指针变量。这样明白了吧!

 

总结:数组名的类型是指向元素类型的指针,值是指针常量。(a+1)的类型是一个指针变量。把数组名作为参数传递的时候实际上传递的是一个指针变量。sizeof对变量和数组名操作时返回的结果会不一样。数组指针是指向数组的指针,其值可以是变量。

2、指针数组(存放指针的数组)

(1)认识指针数组

一个存放int类型的数组称为整型数组,那么存放指针的数组就叫指针数组。

[cpp] view plain copy
  1. <strong><span style="font-size:16px;">#include<stdio.h>  
  2.   
  3. void main()  
  4. {  
  5.     int i=1,j=2;  
  6.     //p先跟[]结合,然后再跟*结合  
  7.     int *p[2];//指针数组,存放指针的数组  
  8.     p[0]=&i;  
  9.     p[1]=&j;  
  10.     printf("%d",sizeof(p));  
  11. }</span></strong>  

 断点调试分析:

 

此例数组p就两个元素,p[0]是指向i的指针,p[1]是指向j的指针。这两个指针都是int型指针,所以p是存放int型指针的数组。sizeof(p)返回数组占用的总空间,所以程序输出是8

 

(2)指针数组用法举例

来自《the c programming language》的一个例子,对字符串进行排序,看了下面这个例子,相信你就体会到了指针数组的好处了。

 

展开阅读全文

没有更多推荐了,返回首页