【朝花夕拾】C语言指针定义和数组定义的歧义问题-指针和数组疑难辩证-终极解答2

=

=

=

朝花夕拾-C语言指针定义和数组定义的歧义问题-指针和数组疑难辩证-终极解答2

这一篇主要目标讲多维数组和指针类型。

原理1:C语言中只有一维数组。2维数组可以看成是一维数组的一维数组。多维数组以此类推。

原理1:C语言中只有一维数组,:数组名称后面跟着的第一个数字维度就是数组的真实维度。除此之外,其他的参数则是数组元素的信息描述。

C语言中只有一维数组,而且数组的大小必须在编译时期就确定下来(旧标准)。然而,C语言数组的元素可以是任意对象,包括数组。这样就给多维数组的实现或者仿真提供了可能。

2维数组: int a[2][3];

分解为一维数组的代数法为:

扫描二维码关注公众号,回复: 2756460 查看本文章

a的1维类型为:int a[];

a[i]的类型为 int B[];

结合起来看,a的类型为:a[][3]。【从高级语言来看,a的类型为a[][],但是c语言要求写类型的时候,后面维数写确定。】

 原理2:不同的指针类型也是不同类型,也是不能互用的,切记别以为都是指针,就属于一个类型了:

一定要重视指针类型,这一点往往刚学的时候容易忽略。

不同的类型是不能互用的(强制转换不算)。例如int和float是不能互用的。

同理,不同的指针类型也是不同类型,也是不能互用的,切记别以为都是指针,就属于一个类型了

不同的指针类型,其指针使用方法遵从指针原理(比如:指针加法减法),其取值使用方法遵从指针类型(比如int **p类型的指针,**p取到int值,遵从int的操作)。

类型有强制转换的需求,指针类型,应该也可以强制转换,比如可以把p强转为:float *p8 = (int *) p;

原理3:指针和数组的关系,在多为数组上的应用,以2维数组为例:int a[m][n],a的类型为int (*)[n],a的类型不是int *。

int a[2];

//a是指向a[0]的地址,指针类型为 int *;

//a等价于指针 int *

int a[2][3];

//等价于int A[2];

//a是指向A[0]的地址,指针类型为int A[]等价于int *A,

//而A[0]的类型为int[3]等价于int *,所以a等价于类型:int (*)[3];【注意不是(int *)[3]】。

//根据括号左移法则(见上一篇),a的类型是int[][3], 等价于指针类型是int[3] *,因为c语言要求[3]在后面,所以只能写为 int (*)[3]   【注意不是(int *)[3]】。

//如果全用指针来看,a的类型应该是int * *。推理:a的类型是int *A,A的类型是int *,所以合并为 int *(int *)==int **。

知晓了上面的原理,我们来看看容易混淆的地方。

int a[m][n];

a永远是指向a[0]的地址。//不是a[0][0]的地址。原理是C语言本质只有一维数组。

a+i,指向了第i行的(首)地址。//不是a数组中第i个元素。

*(a+i)==a[i]//为什么a[i]不是(a+i)而是*(a+i)?因为a的类型和a[i]的类型是不同的。a+i的类型依然和a的类型一样是int (*)[n],而a[i]的类型确实int *。

这里的核心是a的类型和a[i]的类型是不同的。

a[i][j]的不同表示法:

(*(a+i))[j];

*(      (*(a+i))+j    )

*(a[i] + j)

*的作用:

*定义指针。在定义时,用来定义某个类型的指针。

*指针取值。在使用时,用来取值指针指向类型的值。

为什么可以把二维数组当成一维数组?以及为什么a指向了a[0][0]的地址?

虽然指针类型是不同的,不能混用。但地址值却只是一串数字,是可以根据情况使用的。

int a[m][n];

a指向的是a[0]的地址,而a[0]指向的是a[0][0]的地址。

问题就出在a[0]并不真实的存在,不存在a[0]这个中间变量,只是编译器根据指针类型编译的时候使用的。

所以在c中,a存储的就是a[0][0]的地址,如果a[0]这个中间变量存在,就不是这样的结果了。这就是c中很麻烦的地方。

比如a[0]真实存在,那么就成了下面的形式:

a = &a[0];

a[0] = &a[0][0];

这完全不是一回事。

可以说,c和指针,确实存在设计问题。这就导致c语言很多混淆难懂不好用。高级语言之所以高级,就在于对人友好。

好了,既然a真实存储了a[0]的地址,那么这个地址值是怎么用都可以的。

比如定义一个一维指针:int *p = a; 等价于int *p = &a[0];等价于int *p = &a[0][0];

因为p是一维指针,那么就可以完全把p当成一维指针用,因为p就是这么用的。

而c内存分配,以连续分配,则可以把p移动完所有的数组值。

具体见下面的代码:

  printf("把二维数组当成一维数组使用的原理:\n");
  int *p = a;
  for(i = 0; i < 2; i++){
    for(j = 0; j < 3; j++){
      printf("%d, ", *(p++) );
    }
  }

例子代码:

复制代码
#include <stdio.h>

int main(void){
  int a[2][3];

  //init
  int i = 0, j = 0;
  for(i = 0; i < 2; i++){
    for(j = 0; j < 3; j++){
      a[i][j] = i + j;
    }
  }

  //traverse
  for(i = 0; i < 2; i++){
    for(j = 0; j < 3; j++){
      printf("%d, ", a[i][j]);
    }
  }

  printf("\n");

  printf("把二维数组当成一维数组使用的原理:\n");
  int *p = a;
  for(i = 0; i < 2; i++){
    for(j = 0; j < 3; j++){
      printf("%d, ", *(p++) );
    }
  }

  printf("\n");

  printf("取值的不同方法:\n");
  printf("%d \n", a[1][2]);
  printf("%d \n", *(*(a+1) + 2)  );
  printf("%d \n", (*(a+1))[2] );
  printf("%d \n", *(a[1]+2) );

  printf("\n");

}
复制代码

=

=

=

猜你喜欢

转载自www.cnblogs.com/fantaxy025025/p/9473024.html