您的位置:首页 > 编程语言 > C语言/C++

C语言指针和数组详解

2012-11-16 00:38 267 查看
常常在BBS上看到有人问指针和数组的问题。我曾经也很迷惑,现在,我谈谈我对指针和数组的理解。欢迎批评指正讨论。

1:定义数组

int a[5];

上一句定义了一个数组,名字叫a,它有5个元素,每个元素是int类型。换句话说,a是一个int [5]型的数组。int [5]表示的是类型,只不过是个复合类型,本质上,和int, float,double没有区别,都是类型。

2:数组的操作。

2.1:sizeof操作。

像1中的数组a,sizeof(a)的值也就是sizeof(int [5])的值,也就是5*sizeof(int)的值。

2.2:加、减、赋值。

当一个数组参与加、减和赋值运算的时候,它首先被转换(converted to)成指向首元素的指针。

a+0是什么?这里数组a要做加法,所以,它首先被转换成指向首元素的指针。然后再加0。

同理,a-0的操作过程是:a首先转换成指向首元素的指针,再减0。

int *p = a;合法吗?合法。数组a在赋值运算的时候,首先a转换成指向首元素的指针,然后再赋值给p。

a+0,a-0和a,这三者有什么区别?a+0的类型是int *,a-0的类型是int *,a的类型是int [5],也就是说类型有同。但它们的值是相同的,都是数组a首元素的地址。

2.3 下标运算符[]

大家都知道,要访问数组a的首元素,用a[0]就可以了。访问第二个元素,用a[1]就可以了。

那么,[]究竟是什么?表达式 E1[E2] 等同于表达式 *((E1)+(E2)),等同于*((E2)+(E1)),等同于E2[E1].

所以a[0]等同于*((a)+(0))即*(a+0)。a+0是指向首元素的指针,那么*(a+0)就是首元素了。同理 a+1是指向第二个元素的指针,*(a+1)也就是第二个元素了。

2.4 取地址运算符&。

&a是什么?很明显,&a是指向a的指针,a的类型是int [5],&a的类型就是int (*)[5]。&a的数值是数组a的首地址。

3:所谓的多维数组。

3.1 二维数组。

首先要明确,C语言中没有真正的多维数组。C语言中的多维数组本质上是一维数组。

3.1.1 定义

int b[3][5];

看上面的数组b的定义,b是一个一维数组,有3个元素,每个元素都像数组a一样,也就是说,b的每个元素是int [5]。

既然所谓的二维数组还是一维数组,那么我们所讲述的一组数组的东西都可以用到所谓的二维数组上。

b是什么?b是int [3][5]类型的变量。只不过这个变量不可被改变。

3.1.2 加、减、赋值。

b+0是什么?b要做加法了,所以它首先被转换为指向首元素的指针,然后再加0。b的元素的类型是int [5],所以b+0的类型就是int (*)[5]。

b-0呢?同上。

int (*p1)[5] = b;是什么意思?p1是一个指针,指向int [5]。把b赋值给它时候,b首先转换成指向b的首元素的指针,再赋值。

*(b+0)的类型是什么?b+0的类型是int (*)[5],那么*(b+0)的类型就是int [5]。*(b+0)也就是数组b的第一个元素。*(b+1) 也就是数组b的第二个元素。

*(b+0)+0的类型是什么?*(b+0)的类型就是int [5],那么*(b+0)+0也就是指向这个整形数组的首元素的指针。也就是说*(b+0)+0的类型是int *型。

*(*(b+0)+0)的类型是什么?*(b+0)+0是int *, *(*(b+0)+0)就是int。

3.1.3 下标运算符[]

E1[E2]不是和*((E1)+(E2))完全等同吗,那么*(*(b+0)+0)也就是*(b[0]+0)也就是b[0][0]。

3.1.4取地址运算符&

&b是什么?很明显,&b是指向b的指针,b的类型是int [3][5] ,&b的类型就是int (*)[3][5]。&b的数值是数组b的首地址。

3.2 三维数组

int c[2][3][5]。c是个一维数组,有2个元素,每个元素都像b那样,也就是说,每个元素都是个int [3][5]。

c+0是指针,类型是int (*)[3][5],指向c的第一个元素。

*(c+0)是第一个元素,也就是第一个int [3][5]。

*(c+0)+0是什么?*(c+0)是int [3][5],*(c+0)+0就是指向*(c+0)中第一个int[5]的指针。

*(*(c+0)+0)是什么?是个int [5]。

*(*(c+0)+0)+0是什么?是指向上面的int [5]的第一个元素的指针。它的类型是int *。

*(*(*(c+0)+0)+0)是什么?是第一个int。

4:把数组传给一个函数。

把数组赋值给一个函数的参数,我们已经知道,赋值的时候数组首先转换成指向首元素的指针。

数组a可以传给 void f1(int *arr)

数组b可以传给 void f2(int (*arr)[5])

数组c可以传给 void f3(int (*arr)[3][5])

在上面三个函数里,参数arr都是指针了,不再是数组了。所以,数组传给函数的时候,会丢失维度的信息,所以,很多时候,把一个数组传给函数时,还要用另一个参数指明数组是几维的

PS:

数组名是指针?错。

数组名在+,-,赋值运算时被转换为指向数组首元素的指针?对。

二维数组是二级指针?大错特错。数组就是数组。所谓的二维数组就是一维数组的数组。

*(a+0)与a[0]完全一样?对。不信就去查C99标准中的[]运算符。

*(0+a)与0[a]完全一样?对。不信去查标准。但写成这样蛋疼。

a+0和a有什么区别?区别大了。a是数组,a+0运算时,首先a被转化成指向首元素的指针,然后再做指针加法。也就是说,a+0和a的数值一样,类型不一样。

int *p=a;赋值运算时,a也被转化为指向首元素的指针?对。

当数组a做为参数传给函数void foo(int a[])也被转化为指向首元素的指针?对。

把b传给函数,参数怎么写?void foo(int (*b)[5]),一个指向一组数组的指针。

&a的类型是什么?是int (*)[5]也就是指向一维数组的指针。但它的值还是a的首地址。

如果你不太清楚int (*)[3][5]和int *[3][5]的区别,请google “右左原则”或访问此网页,然后在下载下来的东西里找“右左原则”四个字,读过之后,对于声明定义,都看得懂了。

本文来源:http://wildpointer.net/2010/06/10/c_pointer_array/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: