C语言学习之指针和数组
前面我们看了如何去使用数组,在这里我们要关心更深层次的问题,它和更前面的指针是何种关系。
1. 一维数组和指针
前面我们操作数组都是通过数组名加下标的方式,那么这个数组名到底代表什么含义?其实数组名它是一个指针常量,它是一个地址,这个地址是数组的首地址,也就是数组第一个元素的地址。例如:
int a[10];
你可以去看一下,a, &a, &a[0]它都是同一个值,都是数组的首地址。
那么这个指针常量它的类型的是什么呢,如果数组元素的类型是int类型的,那么这个指针常量的类型就是int*,像这里就是int*类型。还有要注意的是这个指针是一个常量,不能修改这个值,但是有两种情况下数组名不被当作一个指针常量看待,一个是&运算,另一个是sizeof,一个常量肯定是没有地址的,所以&运算是取得数组的首地址,而sizeof是返回整个数组的长度,而不是返回的指针长度。
所以数组和指针是如此的相似,以至于它们可以互换使用。例如,数组元素除了使用下标方式操作外,还可以使用指针的方式:
*(a + 1)代表第二个元素,*(a + 2)代表第三个元素。
数组可以当作指针来使用,指针同样也可以当作数组来使用。
虽然数组和指针有如此相似地方,但是它们还是有区别的。
(1) 数组名这个指针它是一个指针常量,也就是你不能对它进行算数运算,例如a++这是错误的操作。但是我们定义的指针它却是一个变量。
(2) 我们定义一个数组,它就分配了相应大小的空间,但是定义指针,它只是分配4字节大小空间,它只能指向其它存储空间,否则,它没有任何意义。
既然数组和指针有如此多的相似之处,那我们到底是使用数组还是指针呢,这要看具体的上下环境,如果是数组,那么使用数组的下标形式更让人理解,让人一看就知道这是一个数组,如果是指针,那就直接使用指针的方式操作,这样也不会混淆程序的其它阅读者。
2. 一维数组作为函数参数
当我们将一个数组作为参数传递给函数时,实际上是将数组的首地址传给了子函数。那么这个函数参数该怎么去定义呢,有两种写法,例如:
int strlen(char string[]);
int strlen(char* string);
这两种写法都是正确的,但是哪种写法更好呢,当然是使用指针的写法更好,因为我们的的确确是传递的一个指针给函数。
3. 二维数组和指针
int a[10][10];
a它是一个二维数组,通过前面我们知道,数组名它是一个指针常量,那么这里的a也不例外,它肯定也是一个指针常量,但是这个指针常量的类型是什么呢?在前面看数组时我们说二维数组可以看作是数组的数组,从前面来看,数组名它是一个指向数组的第一个元素的指针常量,所以这里的a也是指向数组的第一个元素的指针常量,不过它的元素类型又是一个数组,所以这里的指针常量的类型是指向数组的指针,如果我们要定义指针来保存这个值,我们需要这样定义:
int (*b)[10];
注意,需要加上括号才表示它只是一个指针,一个指向数组的指针,如果你定义成了这样int *b[10];意义完全不一样了,后者表示定义了一个含有10个元素的数组,只不过这个数组里面的元素它的类型是一个指针。
所以如果我们要使用指针的方式来访问数组,需要注意了,这里的a + 1后,实际上指向了数组的第二行。
4. 二维数组作为函数参数
二维数组作为函数参数最常见的写法就是main函数的命令参数,和前面一维数组的参数写法一样,它也有两种写法:
void func2(int (*mat)[10]);
void func2(int mat[][10]);
同样的,个人认为还是使用指针的方式好一点,更能表达出数组名它是一个指针。