数组指针和指针数组

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

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

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

先来看一段代码:

void main()
{
	int a[2][2]={1,2,3,4};//这是一个2*2的二维数组
    int (*p)[2];//数组指针
    p=a;//令p指向数组a
}


注意到代码中这句话: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)指针是数组的迭代器

#include<stdio.h>
#define M 2
#define N 3

int main()
{
	int a[M][N]={1,2,3,4,5,6};
	int *start=&a[0][0];
	int * const end=start+M*N;
	for(;start!=end;start++)
		printf("%-5d",*start);
	putchar('\n');
	return 0;
}


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

 

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

 

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

 

看看这个代码:

#include<stdio.h>
void main()
{
	int a[2][2]={1,2,3,4};//这是一个2*2的二维数组
    int (*p)[2];//数组指针
    p=a;//令p指向数组a
	printf("%d\n%d\n",sizeof a,sizeof p);
}

猜一猜输出是什么?


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

 



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

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

#include<stdio.h>

void main()
{
	int a[2][2]={1,2,3,4};//这是一个2*2的二维数组
    int (*p)[2];//数组指针
    p=a;//令p指向数组a
    printf("%d\n%d\n",sizeof(a+1),sizeof(p+1));
    printf("%d\n%d\n",sizeof(a+0),sizeof(p+0));
}


运行结果:

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

 

现在再来看一段代码:

#include<stdio.h>

void f(int a[][2])
{
	printf("%d\n",sizeof a);
}
void main()
{
	int a[2][2]={1,2,3,4};//这是一个2*2的二维数组
	printf("%d\n",sizeof a);
	f(a);
}

再猜一下输出是什么?

是不是又有点困惑呢?

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

 

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

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

(1)认识指针数组

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

#include<stdio.h>

void main()
{
	int i=1,j=2;
	//p先跟[]结合,然后再跟*结合
    int *p[2];//指针数组,存放指针的数组
	p[0]=&i;
	p[1]=&j;
	printf("%d",sizeof(p));
}

 断点调试分析:

 

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

 

(2)指针数组用法举例

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

 

 

 3、深入思考

数组名a、a[0]、a[1],数组指针p到底在内存中是怎么存储的呢?存放在内存中的哪里呢?是在代码段吗?求解惑!

 

 4、参考资料

《c和指针》 《the c programming language》 等

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页