数组
先讲讲数组名:一维数组数组名可以代表一个指针常量(注意它是一个指针常量,不是指针变量),指向数组的第一个元素,她的类型取决于数组元素的类型:如果是int型,那么数组就是指向int的常量指针。
多维数组跟一维数组差不多,只是多维数组的第一个元素时是另外一个数组。
然后讲讲数组和指针吧,虽然数组名是一个指针常量但是它还是和指针有区别的:
如:
int a[10];/*声明数组是编译先为数组保留指定元素数量的内存空间,然后创建数组名,它是一个常量,指向这段内存空间的起始位置。*/ int *b; /*声明指针变量的时候,只会为指针变量预留内存空间,而不会为任何其他类型预留内存,这个指针并未初始化,没有指向任何内存。*/
所有根据上面的我们可以得出:
1,*a的调用是合法的,因为a是一个指针常量,对它间接访问是正确的取值方法,但是*b就是不合法的,因为指针b并未进行初始化,对它进行间接访问是不合理的,它会访问内存空间中一个不确定的位置。
2,b++可以通过编译,他是指针变量的正常变化,但是a++就不能通过编译,因为a是一个指针常量,你不能对它进行改变。
数组名只有在另种情况下不用常量指针来表示:
1,当数组名作为sizeof()操作符的操作数时,它返回的是整个数组的长度,而不是常量指针的长度。(当数组名作为函数参数传递是情况有所不同。我们下面再讲)
2,对数组名取地址是(&)所产生的是一个指向数组的指针,而不是指向某个指针常量的指针。
二,C中的下标引用和间接访问。我们直接看代码。
#include<stdio.h> /* **C的下标引用和间接访问除了优先级不一样,其他都是一样的 */ int main(){ int array[10]={0,1,2,3,4,5,6,7,8,9}; int *p=array+2; /* **下面的很好理解也就是 **array+2=array[2] */ printf("%d ",*p); printf("%d ",array[2]); /* **下面三个是同一个东西所以我们在指针就行下标引用也就是间接访问。 */ printf("%d ",*(p+6)); printf("%d ",array[8]); printf("%d ",p[6]); /* **只要是在范围之类的,不管下标为多少,正数还是负数都可以转换为间接访问来处理 */ printf("%d ",p[-1]); /* **正确的表达式,我们可以把下标表达式转换为间接访问的表达式:*(2+(array)) -> *(array+2) 加法运算的两个操作数可以交换位置 **下面的例子更加说明了在c中下标引用和间接访问时同一个概念 */ printf("%d\n",2[array]); return 0; }
三,数组名作为函数参数:这时数组名进行sizeof()操作是情况有所不同,我们看例子。
#include<stdio.h> void Func(int str[]){ printf("%d\n",sizeof(str)); } int main(){ int array[10]={0,1,2,3,4,5,6,7,8,9}; Func(array); printf("%d\n",sizeof(array)); return 0; }
数组名作为参数传递时,它已经把自己弱化为指针了,此时对数组名进行sizeof()操作是,时间返回的是指针的字节大小。而不是整个数组的字节大小。
我们数组名作为函数参数时,情况有所不同,它传递的是一个该指针的拷贝,对他进行下标引用就是进行间接访问,可以对数组值进行修改。我们通常所理解的是传值方式不能修改实参好像跟我们这边讲的起矛盾了。其实并不然,我们这边也是传值的方式,复制了一个指针,我们并不对实参指针进行修改,但是我们可以通过拷贝的指针的间接访问来改变数组的值,并不违反传值的方式。如果不想修改数组值乐意用const关键字来进行修饰。
四,字符数组的初始化:
char message1[]="Hello"; char *message[]="Hello";
第一个是字符数组的初始化,第二个是一个字符串常量,平时写的时候我们应该记住他们并不一样:当用于初始化一个字符数组是,他就是一个初始化列表。在其他任何情况下,他表示一个字符串常量。
五,多维数组,
1,存储方式:多维数组数据的存储方式是根据右边的下标率先变化的。看例子就知道。
#include<stdio.h> int main(){ int array[2][10]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; int *p; p=&array[0][8]; printf("The first value is %d\n",*p); printf("The second value is %d\n",*++p); printf("The third value is %d\n",*++p); return 0; }
2,多维数组名,跟一维数组差不多指向数组的第一个元素,但是这里有不同的是多维数组的第一个元素是另外一个数组,如下图。即:多维数组名代表指向数组的指针。
3,下标,这个要结合间接访问来一起解释,举例:
#include<stdio.h> int main(){ int i; int array[2][10]={0,1,2,3,4,5,6,7,8,9, 10,11,12,13,14,15,16,17,18,19}; int (*p)[10]=array; /*指向数组的指针,记住中括号里面数组的长度必须存在,不然p+1就不知道指的是那个数组了*/ int *q=array[1] ; /* **下面两个输出代表同一位置的同一个值的不同方法,便是*(array+1)+1指向array[1][1], array数组名代表指向第一个一维数组的常量指针,所以array+1代表指向第二个一维数组的指针,*(array+1)+1 **代表指向第二个一维数组的第一个元素的指针。 所以所对他进行间接访问就是下标操作的array[1][1] */ printf("%d ",*(array+1)+1); printf("%d\n",&array[1][1]); printf("%d ",*(*(array+1)+1)); printf("%d ",array[1][1]); /* **这里的array[1]就代表*(array+1),指向第二个一维数组的第一个元素的指针也就是指向array[1][0], array[1]+1就是指向array[1][1],间接访问就是array[1][1]的值。 */ printf("%d\n",*(array[1]+1)); /* **下面是指向数组的指针p,p是指向array第一个一维数组的指针,*p就是指向第一个一维数组第一个元素的指针,利用这个我们就可以把array第一个一维数组给全部打印出来 */ for(i=0;i<10;++i) printf("%d ",*(*p+i)) ; /* **利用上面的array[1] 代表指向第二个一维数组的第一个元素的指针,我们也可以用指针来打印 */ printf("\n"); for(i=0;i<10;++i) printf("%d ",*(q+i)) ; return 0; }
4,多维数组作为函数参数,多维数组名其实传递的是一个指向数组的指针。
所以当我们f(array);调用函数的时候,函数的声明就需要这样
1)void f(int (*p)[10]);
2)void f(int p[][10]);
记住不要把他们和**p弄混了,指向数组的指针和指向指针的指针并不是一回事。
5,指针数组和指向数组的指针。
int (*p)[10] /*指向数组的指针,p是指针,指向数组*/
int *p[10] /*指针数组,p是数组。里面存的都是指针*/
2015.12.22
http://blog.csdn.net/code_crash/article/details/4855036
数组名不是指针:
首先,在C/C++中,数组类型跟指针类型是两种不同的派生类型,数组名跟指针是两种不同类型的实体,把数组类型的实体说成“是”另一个类型的实体,本身就是荒谬的;
其次,a + 1在效果上之所以等同于p + 1,是因为a进行了数组到指针的隐式转换,这是一个转换的过程,是converted to而不是is a的过程。如果是两个相同的事物,又怎会有转换的过程呢?当把a放在a + 1表达式中时,a已经从一个数组名转换为一个指针,a是作为指针而不是数组名参与运算的。
第三,a + 1与p + 1是等效关系,不是等价关系。等价是相同事物的不同表现形式,而等效是不同事物的相同效果。把数组名说成是指针实际上把等效关系误解为等价关系。
因此,数组名不是指针,永远也不是,但在一定条件下,数组名可以转换为指针。