数组与指针

来源:互联网 发布:37周胎儿b超数据标准 编辑:程序博客网 时间:2024/05/26 17:44

数组使用实践简析

主旨

讨论在实践用使用数组的时候,对于数组和指针的实践和自己的分析。
写这篇文章主要是因为看到一个C语言的面试题。

(33)若有定义:int a[4][10];,则以下选项中对数组元素a[i][j]引用错误的是________。(0<=i<40<=j<10)A)*(&a[0][0]+10*i+j)     B)*(a+i)+jC)*(*(a+i)+j)             D)*(a[i]+j)

因为上述指针和引用的表达方式让我很是迷惑,于是我想实际使用visual studio分析下以上四个选项的情况。

代码

话不多说,先贴代码。

#include<stdio.h>#include<stdlib.h>#include<string.h>int main(){    int i = 1, j = 5;    int a[2][10] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};}

分析

本段代码,我定义了一个数组a。并且在执行阶段使用F11一个一个执行句子,使用VS中的监视窗口来查看各种上述选项的内容。

变量 值 类型 *(&a[0][0]+10*i+j) 16 int。。。。 *(a+i)+j 0x0115f6ec {16} int * *(*(a+i)+j) 16 int *(a[i]+j) 16 int *(a+1) 0x0115f6d8 {11, 12, 13, 14, 15, 16, 17, 18, 19, 20} int[10] a+1 0x0115f6d8 {11, 12, 13, 14, 15, 16, 17, 18, 19, 20} int[10] * (a+i)+j 0x0115f7a0 {1965974212, 14913536, 1965974176, 25994783, 18216952, 2006978521, 14913536, 52403305, 0, …} int[10] * *(a+i)+j 0x0115f6ec {16} int * **(a+1) 11 int &a[0][1] 0x0115f6b4 {2} int * &a[0][9] 0x0115f6d4 {10} int * &a[1][0] 0x0115f6d8 {11} int * *(&a[1][0]) 11 int **a 1 int *a 0x0115f6b0 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} int[10] a 0x0115f6b0 {0x0115f6b0 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0x0115f6d8 {11, 12, 13, 14, 15, 16, 17, 18, …}} int[2][10] &a 0x0115f6b0 {0x0115f6b0 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0x0115f6d8 {11, 12, 13, 14, 15, 16, 17, 18, …}} int[2][10] *

结果分析

根据上述的表格,我们简单分析下指针与数组之间的对应关系。
首先看一组表格

变量 值 类型 &a 0x004ffa30 {0x004ffa30 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0x004ffa58 {11, 12, 13, 14, 15, 16, 17, 18, …}} int[2][10] * a 0x004ffa30 {0x004ffa30 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0x004ffa58 {11, 12, 13, 14, 15, 16, 17, 18, …}} int[2][10] *a 0x004ffa30 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} int[10] **a 1 int

从上述的表格中,可以看出:
1.首先a的值是一个地址,是一个二维数组变量。而&a、*a的值也是一个地址,不过虽然值都是地址,但是表示的变量类型不同,这个直接影响到它们与int整数相加的代表意义,这一点后面会讲。
2.通过分析,可以将多维数组理解为多层地址的嵌套,而*号的作用是不断的挖去这个地址对应的更小维度的数组直到最后取这个数组中的一个元素值。如**a是一个int型的整数,表示数组中的一个元素;如果a是一个4四维或者5维的数组,那么,它的首元素的值应该是****a或者*****a。
3.在数组的情况下,*与[]符号对于数组来说效果类似,例如,*a=a[0]是一个int型的一维数组,**a=a[0][0]。都是为了确定最后值。

接下来我们来看下对于寻址来说,不同数量的**有什么作用
首先我们定义了一个三维数组b[2][3][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 },通过以下的表格做一下分析。

变量 值 类型 b+1 0x004ff9f8 {0x004ff9f8 {13, 14, 15, 16}, 0x004ffa08 {17, 18, 19, 20}, 0x004ffa18 {21, 22, 23, 24}} int[3][4] * *b+1 0x004ff9d8 {5, 6, 7, 8} int[4] * **b+1 0x004ff9cc {2} int * ***b+1 2 int

首先b+1是一个二维数组地址,表示b[1]这个二维数组,但是二维数地址类型,通过取值操作*(b+1)可以得到二维数组类b[1]一样的值和一样的数据类型:int[3][4];如果*b+1则表示一维数组b[0][1]的首地址,通过*(*b+1)取值成为b[0][1];通过**b+1取到b[0][0][1]的元素地址,同理,通过*(**b+1)得到b[0][0][1]的值2。而***b+1代表的意义是b[0][0][0] + int值1,1+1=2。
以上的例子也解释了,为何*a和**a的值相同,但是表示的意义不同。

面试题选项分析

经过以上的分析,对比后,我们回到引出这个问题本身的面试题选项分析。

A)*(&a[0][0]+10*i+j)     B)*(a+i)+jC)*(*(a+i)+j)             D)*(a[i]+j)

首先A项,先通过&a[0][0]取了a[0][0]的元素地址,接着这里面的10*i和j就都是以元素为单位的偏移操作了,+10i相当于向下偏移了10个元素,即偏移了一个int[10]的一维数组,也就是地址偏移到了a[i][0],再+j,就在a[i][0]的基础上偏移了j个单位,即最后得到a[i][j]的地址,最后通过*取值,得到int a[i][j]元素的值。
C项,a+i,即选择了a[i]这个一维数组,值为a[i]的首地址,然后通过*(a+i)+j取到a[i][j]的元素地址,最后通过取值操作*((a+i)+j)
操作取到元素值。
D项,a[i]即是数组的首地址,相当于*(a+i),再+j就是在a[i]数组上偏移j个单位,得到a[i][j]地址,最后取值操作得出a[i][j]的值。

对于B项,是一个地址,还没取值,属于指针类型,所以错误。

0 0
原创粉丝点击