C语言指针与数组(C专家编程)

1.区别(主要的):指针需要增加一次额外的提取操作

     编译器为每个变量分配一个地址(左值)。这个地址编译时可知,而且该变量在运行时一直保存于这个地址。相反,存储于变量中的值(它的右值)只有在运行时才可知。如果需要用到变量中存储的值,编译器就发出指令从地址读入变量值并将它存于寄存器中。
     对于数组,如果编译器需要一个地址(可能还需要加上偏移)来执行某种操作,它可以直接进行操作,不需要增加指令取得具体地址(把数组名直接看成地址)。对于指针,必须首先在运行时取得它的当前值(即所需要的地址)。
     定义一个指针:char *p = "helloworld";
     在这里p是一个变量,其类型为指针类型,并且指向一个字符串,字符串内容为"helloworld",如果要访问p[2]的话需要3步:
1) 取p的值,该值即为字符串的首地址。
2) 该地址加上偏移量,得到所要取的字符的地址。
3) 从这个地址中取得值。
    此处p是一个变量,它自己本身是存放在一个地址中的,而这个地址的内容则是"helloworld"这个字符串的地址。p与字符串是分开的。同时,该指针的值是动态确定的,必须在运行的时候才能确定其值,并通过该值访问到字符串。
    定义一个数组: char a[20] = "helloworld";
    此时的a这个地址的内容就为'h'这个字符,其类型为字符型而不是一个指针类型。此时a的地址与a[0]的地址是相同的。
    每个变量的地址在编译时就确定了,所以这里a的地址就已经确定了,如果需要访问a[2],需要2步:
1) 直接使用该地址加上2这个偏移量,得到所要取的字符的地址
2) 从这个地址中取得值。
    注:当定义为数组,在其它文件声明是指针时,编译器会把它当作一个指针,取地址时实际取到的只是字符,会造成严重错误!
    只有字符串常量才能初始化指针(并且该字符串常量不能再修改,而数组可以),其它常量不能初始化指针。

2.相同的情况(统一是为了编译器效率)

1) 表达式中的数组名(与声明不同)被编译器当作一个指向该数组第一个元素的指针(即在表达式中的最终形式是指针:a[i]总是被编译器解释为像*(a+1)这样的指针访问)与34.1矛盾?。
2) 下标总是与指针的偏移量相同。
3) 在参数声明中,数组名被编译器当作指向该数组第一个元素的指针。
“数组名被改写成一个指针参数”规则并不是递归定义的。数组的数组会被改写为“数组的指针”,而不是“指针的指针”。
     实参                                     所匹配的形式参数
char c[8][10] (数组的数组)     char (*) [10] (数组的指针)
char *c[10] (指针的数组)        char**c (指针的指针)
char (c*) [10] (数组的指针)    char (c*) [10](不变)
char**c (指针的指针)              char**c (不变)
  
main()中的char *argv[]与char**argv等价

3.二维数组(转别人的blog)

int a[10][20];
int **p;
p = a;    //这种方式是错误的!!
      a是一个数组类型,而p是一个指向指针的指针类型,此时p里面是一个地址,通过该地址所得到的值还是一个整型指针的类型。即*p也是一个整型指针。而此处a为数组,其里面的内容为整型,让p指向这个数组的首地址,而该首地址里面的内容又为一个整型,不是一个指针类型。所以会出现错误。
      因此, 只能采取指向数组的指针类型才能够完成这个功能,即
      int (*q)[20];
      q = a;
      此时q是一个指针,其指向的是一个具有20个整型变量的一维数组。这样, 就可以使用q[i][j]或者*(*(q+i)+j)的方式来访问这个二维数组了。
       另外, 对于一维数组。
       int a[10];
       int (*q)[10] = &a;
      也可以进行访问, 但是此时q[i][j]中的i值就只能是为0了。
      在这个地方,也可以说明为什么a+1与&a+1不相同了。 a表示的是一个元素, 所以a+1也只是地址增加一个整型的长度,而&a+1则是以整个数组为角度来看的,相当于q+1,所以其地址增加的是10*sizeof(int)这么长。
      同理,对于二维数组, int a[10][20]; a+1地址增加的为20个整型的长度。 因为其是以一个一维数组的角度来看的,此时相当于是int (*q)[20] = a;这种形式。
     对于二维数组,a+1与*(a+1)都是同一个地址,但是角度不相同,前一个是以一个20长度的一维数组来看的,即a[1]的地址,而后面一个则是 a[1]的值, 因为a[1]为a[1][0]的首地址,而该首地址又与a[1]的首地址相同, 所以此时a+1与*(a+1)是相同的。 *(a+1)+2就是a[1][2]的首地址了,即相当于是a[1]+2了,此时是以单个元素来看的。

你可能感兴趣的:(编程,c,Blog,存储,语言,编译器)