1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > C语言一维/二维数组解引用难理解点以及一道难题

C语言一维/二维数组解引用难理解点以及一道难题

时间:2020-07-02 01:48:14

相关推荐

C语言一维/二维数组解引用难理解点以及一道难题

C语言指针相关的坑爹题


先来一点简单的

求下面各代码打印结果(32位环境):

int a[3][4] = {0};printf("%d\n",sizeof(a));printf("%d\n",sizeof(a[0][0]));printf("%d\n",sizeof(a[0]));printf("%d\n",sizeof(a[0]+1));printf("%d\n",sizeof(*(a[0]+1)));printf("%d\n",sizeof(a+1));printf("%d\n",sizeof(*(a+1)));printf("%d\n",sizeof(&a[0]+1));printf("%d\n",sizeof(*(&a[0]+1)));printf("%d\n",sizeof(*a));printf("%d\n",sizeof(a[3]));

我们首先要明白

数组名单独放在sizeof()内部,计算的是整个数组大小。如果&数组名放在里面就是求指针大小二维数组中,数组名是首元素地址,二维数组的首元素是第一行的地址,对它解引用就是第一行第一个元素的地址,再解引用一次就是第一行第一个元素的值。


我们再用一维数组仔细解释一下第三条的原因:

给定一个一维数组a[4]={1,2,3,4}

那么数组名a就代表该一维数组的首元素地址,即1的地址,对它解引用就是1;

但我们再看二维数组

给定一个二维数组a[2][2]={1,2,3,4}

在这,数组名也是首元素地址

但二维数组的首元素地址代表着第一行整体的地址,a+1就是第二行的地址。

如果对a解引用*a,*a就是第一行第一个元素的地址,*a+1就是第一行第二个元素的地址

如果再解引用一次,**a就是第一行第个元素的值。


可见,二维数组解引用一次,就变成了一维数组,再用一维数组的思维去理解是不是就更容易了一点。

接下来对上面的题解析:

int a[3][4] = {0};printf("%d\n",sizeof(a));/数组名单独防在sizeof里面,求长度,所以结果是3*4*4=48printf("%d\n",sizeof(a[0][0]));/a的第一行第一个元素是0,类型为int,结果就为4printf("%d\n",sizeof(a[0]));/a[0]代表二维数组第一个元素,第一个元素是它的第一行整个数组的地址,也就相当于一个一维数组的数组名,单独放在sizeof里为求它大小,为16printf("%d\n",sizeof(a[0]+1));a[0]作为第一行数组名,没有单独放在sizeof内部,a表示第一行地址那么a+1就是第二行地址,是地址,所以大小为4printf("%d\n",sizeof(*(a[0]+1)));/a[0]+1是第二行数组首元素的地址,对它解引用就是0,类型为int大小为4printf("%d\n",sizeof(a+1));/a数组名没有单独放在sizeof内部,没有&,所以a为第一行整体的地址,a+1就是第二行整体的地址,类型为int(*)[4]的数组指针,32位环境下结果为4。printf("%d\n",sizeof(*(a+1)));/同上,对数组指针解引用,a+1是整个第二行数组的整体地址,对它进行第一次解引用就是第二行首元素的地址,又因为数组名等于首元素地址,所以在这*(a+1)相当于一维数组的数组名,所以为求整个第二行数组的大小,结果为16printf("%d\n",sizeof(&a[0]+1));/a[0]为第一行首元素的地址,对它取地址就相当于二维数组a首元素的地址,二维数组首元素地址是第一行整体的地址,加一就是第二行整体的地址,所以&a[0]+1 -> a+1 ,是地址,所以大小为4printf("%d\n",sizeof(*(&a[0]+1)));/同上,对a+1解引用就是第二行第一个元素的地址,相当于一维数组的数组名单独放在sizeof里,求第二行数组的大小,为16printf("%d\n",sizeof(*a));/a是二维数组的数组名,也就是首元素的地址,,就是第一行第一个元素的地址相当于一维数组名单独放在sizeof里,求第一行数组的大小,为16printf("%d\n",sizeof(a[3]));/a[3]确实越界了,但是sizeof里面的表达式不进行实际运算,所以还是直接看着第四行的数组名,求数组大小,为16


接下来是一道难题:

int main() {int a[4] = {1, 2, 3, 4 };int *ptr1 = (int *)(&a + 1);int *ptr2 = (int *)((int)a + 1); printf( "%x,%x", ptr1[-1], *ptr2); return 0;}

求结果

解析:ptr1很简单:&a是整个一维数组的地址,加一就跳过了整个a数组,指向4后面的一个地址。

打印的时候ptr1[-1]相当于*(ptr1-1),结果就是4。

再来看ptr2:a是数组a的首元素地址,强制转化为int类型,就变成了普通的整型,整型加一就直接看成一个数加一,就相当于只跳过一个字节,不管是跳过一个int还是一个char。

a数组在内存中以2进制方式存储,并且,我们在这默认为小段存储。

10 00 00 00 20 00 00 00 30 00 00 00 40 00 00 00

一开始a指向数组首元素,ptr2变成整型加一后,再强制类型转换为int*,就相当于只跳过一个字节,指向了二进制位01后面一个地址,再以十六进制形式打印,从00往后找四个字节,这时找到的就是00 00 00 02,打印出来的是2。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。