【C语言】指针和数组笔试题解析

各位读者好,我们现在来看几组指针和数组笔试题,小编才疏学浅,如有错误,恳请斧正! 

目录

1.一维数组

 1.printf("%d\n",sizeof(a));

2.printf("%d\n",sizeof(a+0));

3.printf("%d\n",sizeof(*a));

4.printf("%d\n",sizeof(a+1));

5.printf("%d\n",sizeof(a[1]);

6.printf("%d\n",sizeof(&a));

7.printf("%d\n",sizeof(*&a));

8.printf("%d\n",sizeof(&a+1));

9.printf("%d\n",sizeof(&a[0]));

10.printf("%d\n",sizeof(&a[0]+1));

运行结果如下:

2.字符数组 

第一组题目如下:

1.printf("%d\n",sizeof(arr)); 

2.printf("%d\n",sizeof(arr+0));

3.printf("%d\n",sizeof(*arr));

4.printf("%d\n",sizeof(arr[1]));

5.pritnf("%d\n",sizeof(&arr));

6.printf("%d\n",sizeof(&arr+1));

7.printf("%d\n",sizeof(&arr[0]+1));

运行结果如下:

第二组题目如下: 

1.printf("%zd\n",strlen(arr));

2.printf("%zd\n",strlen(arr+0));

3.printf("%zd\n",strlen(&arr[0]+1));

运行结果如下:

 第三组题目如下:

1.printf("%d\n",sizeof(arr)); 

2.printf("%d\n",sizeof(arr+0));

3.printf("%d\n",sizeof(*arr));

4.printf("%d\n",sizeof(arr[1]));

5.printf("%d\n",sizeof(&arr));

6.printf("%d\n",sizeof(&arr+1));

7.printf("%d\n",sizeof(&arr[0]+1));

运行结果如下:

第四组题目如下: 

1.printf("%zd\",strlen(arr)); 

2.printf("%zd\n",strlen(arr+0));

3.printf("%zd\n",strlen(&arr[0]+1));

运行结果如下:

第五组题目如下:

1.printf("%zd\n",sizeof(p)); 

2.printf("%zd\n",sizeof(p+1));

3.printf("%zd\n",sizeof(*p));

4.printf('%zd\n',sizeof(p[0]));

5.printf("%zd\n",sizeof(&p));

6.printf("%zd\n",sizeof(&p+1));

7.printf("%zd\n",sizeof(&p[0]+1));

运行结果如下:

第六组题目如下:

1.printf("%zd\n",strlen(p)); 

2.printf("%zd\n",strlen(p+1));

4.printf("%zd\n",strlen(&p+1));

5.printff("%zd\n",strlen(&p[0]+1));

运行结果如下:

 3.二维数组

1.printf("%d\n",sizeof(a));

2.printf("%d\n",sizeof(a[0][0]));

3.printf("%d\n",sizeof(a[0]));

4.printf("%d\n",sizeof(a[0]+1));

5.printf("%d\n",sizeof(*(a[0]+1)));

6.printf("%d\n",sizeof(a+1));

7.printf("%d\n",sizeof(*(a+1)));

8.printf("%d\n",sizeof(&a[0]+1));

9.printf("%d\n",sizeof(*(&a[0]+1)));

10.printf("%d\n",sizeof(*a));

11.printf("%d\n",sizeof(a[3]));

运行结果如下:

 ending:


既然是指针和数组相关的笔试题,我们可以先明确数组名的3种意义:

1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示数组首元素的地址。

指针变量的大小与指针变量类型无关,不管什么类型的指针变量,大小都是4/8个字节。注意为了避免歧义,我们以下代码的运行环境均处于32位(X86)系统下运行,以下指针变量大小均取4个字节。

strlen函数:求字符串长度,统计字符串种'\0'之前出现的字符的个数。

sizeof操作符:判断数据类型或者表达式长度,简单的说其作用就是返回一个对象或者类型所占的内存字节数。

好的,有以上铺垫,我们开始看题!

1.一维数组

题目如下:

#include<stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a + 0));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(a[1]));
	printf("%d\n", sizeof(&a));
	printf("%d\n", sizeof(*&a));
	printf("%d\n", sizeof(&a + 1));
	printf("%d\n", sizeof(&a[0]));
	printf("%d\n", sizeof(&a[0] + 1));
	return  0;
}

 1.printf("%d\n",sizeof(a));

这个情况数组名(a)属于数组名意义的第一种情况。sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。我们可以看到数组a有4个元素,元素类型为int(占4个字节),以下不在赘述这点。所以这里打印的的应该是16(单位:字节)。

2.printf("%d\n",sizeof(a+0));

这种情况数组名(a)属于数组名意义的第三种情况。因为数组名(a)没有单独放在sizeof()内部(即数组名意义的第一种情况:sizeof(数组名)),也没有取地址数组名(即数组名意义的第二种情况:&数组名)。既然数组名(a)属于第三种情况,数组名(a)表示数组首元素地址,a+0跳过0个字节还是指向了数组首元素,a+0还是表示数组首元素地址。所以这里打印的应该是4(单位:字节)。

3.printf("%d\n",sizeof(*a));

这种情况数组名(a)属于数组名意义的第三种情况。理由同上紫色字体所述。既然数组名(a)属于第三种情况,数组名(a)表示数组首元素地址,数组首元素地址(a)解引用(*a)访问数组首元素,即得到了数组首元素。所以这里打印的应该是4(单位:字节)。

4.printf("%d\n",sizeof(a+1));

这种情况数组名(a)属于数组名意义的第三种情况。理由如上紫色字体所述,以下不在赘述。既然数组名(a)表示数组首元素地址,a+1跳过4个字节(因为a的类型是int*)指向了数组第二个元素,a+1表示数组第二个元素的地址。所以这里打印的应该是4(单位:字节)。

5.printf("%d\n",sizeof(a[1]);

这种情况数组名(a)属于数组名意义的第三种情况。a[1]可以表示为*(a+1)。我们分析*(a+1),既然a表示数组首元素地址,a+1跳过4个字节(因为a的类型是int*)指向了数组第二个元素,a+1表示数组第二个元素的地址,解引用第二个元素地址*(a+1)访问数组第二个元素,即得到第二个元素。而且我们常规来看,a[1]亦是表示数组第二个元素。所以这里打印的应该是4(单位:字节)。

6.printf("%d\n",sizeof(&a));

这种情况数组名(a)属于数组名意义的第二种情况。&a表示的是整个数组的地址(&a类型是:int(*)[4]),既然是地址内存长度就是4个字节。所以这里打印的应该是4(单位:字节)。

7.printf("%d\n",sizeof(*&a));

这种情况数组名(a)属于数组名意义的第二种情况。&a表示的是整个数组的地址,解引用这个地址*&a访问整个数组,即得到整个数组。所以这里打印的应该是16(单位:字节)。

8.printf("%d\n",sizeof(&a+1));

这种情况数组名(a)属于数组名意义的的二种情况。&a表示的是整个数组的地址,&a+1跳过整个数组大小,即16个字节(因为&a的类型是int(*)[4]),&a+1还是表示一个地址。所以这里打印的应该是4(单位:字节)。

9.printf("%d\n",sizeof(&a[0]));

这种情况数组名(a)属于数组名意义的第三种情况。因为下标引用操作符([])的优先级高于取地址操作符(&),所以a先和[0]结合再取地址,即&a[0],所以数组名(a)并非属于数组名意义的第二种情况。a[0]可以表示为*(a+0),既然数组名(a)表示数组首元素地址,所以a+0跳过0个字节还是指向数组首元素,解引用*(a+0)访问数组首元素,即得到数组首元素,所以&a[0]表示数组首元素地址。而且常规来看,&a[0]也是表示数组首元素地址。所以这里打印的应该是4(单位:字节)。

10.printf("%d\n",sizeof(&a[0]+1));

这种情况数组名(a)属于数组名意义的第三种情况。&a[0]的分析同上,这里不在赘述。&a[0]表示数组首元素的地址,&a[0]+1跳过4个字节(因为&a[0]的类型是int*)指向数组第二个元素,所以&a[0]+1表示数组第二个元素的地址。所以这里打印的应该是4(单位:字节)。

运行结果如下:

2.字符数组 

第一组题目如下:

#include<stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr + 0));
	printf("%d\n", sizeof(*arr));
	printf("%d\n", sizeof(arr[1]));
	printf("%d\n", sizeof(&arr));
	printf("%d\n", sizeof(&arr + 1));
	printf("%d\n", sizeof(&arr[0] + 1));
	return 0;
}
1.printf("%d\n",sizeof(arr)); 

这种情况数组名(arr)属于数组名意义的第一种情况。我们可以看到数组arr有6个元素,元素类型为char(占1个字节),一下不在赘述这点。所以这里打印的应该是6(单位:字节)。

2.printf("%d\n",sizeof(arr+0));

这种情况数组名(arr)属于数组名意义的第三种情况。因为数组名(a)没有单独放在sizeof()内部(即数组名意义的第一种情况:sizeof(数组名)),也没有取地址数组名(即数组名意义的第二种情况:&数组名)。既然数组名(arr)属于第三种情况,数组名(arr)表示数组首元素地址,arr+0跳过0个字节还是指向了数组首元素,arr+0还是表示数组首元素地址。所以这里打印的应该是4(单位:字节)。

3.printf("%d\n",sizeof(*arr));

这种情况数组名(arr)属于数组名意义的第三种情况。理由同上紫色字体所述,以下不在赘述。数组名(arr)表示数组首元素的地址,解引用数组首元素地址*arr访问数组首元素,即得到数组首元素。所以这里打印的应该是1(单位:字节)。

4.printf("%d\n",sizeof(arr[1]));

这种情况数组名(arr)属于数组名意义的第三种情况。arr[1]可以表示为*(arr+1)。我们来分析*(arr+1),因为数组名(arr)表示数组首元素地址,所以arr+1跳过1个字节(因为arr类型是char*)指向数组第二个元素,arr+1表示数组第二个元素的地址,解引用第二个元素的地址*(arr+1)访问数组第二个元素,即得到数组第二个元素。而且,常规视角看来,arr[1]也表示数组第二个元素。所以这里打印的应该是1(单位:字节)。

5.pritnf("%d\n",sizeof(&arr));

这种情况数组名(arr)属于数组名意义的第二种情况。&arr表示的是整个数组的地址(类型是:char(*)[6]),既然是地址内存长度就是4个字节。所以这里打印的应该是4(单位:字节)。

6.printf("%d\n",sizeof(&arr+1));

这种情况数组名(arr)属于数组名意义的的二种情况。&arr表示的是整个数组的地址,&arr+1跳过整个数组大小,即6个字节(因为&arr的类型是char(*)[6]),&arr+1还是表示一个地址。所以这里打印的应该是4(单位:字节)。

7.printf("%d\n",sizeof(&arr[0]+1));

这种情况数组名(arr)属于数组名意义的第三种情况。我们来分析&arr[0]。因为下标引用操作符([])的优先级高于取地址操作符(&),所以arrr先和[0]结合再取地址,即&arr[0],所以数组名(arr)并非属于数组名意义的第二种情况。arr[0]可以表示为*(arr+0),既然数组名(arr)表示数组首元素地址,所以arr+0跳过0个字节还是指向数组首元素,解引用*(arr+0)访问数组首元素,即得到数组首元素,所以&arr[0]表示数组首元素地址。&arr[0]+1跳过1个字节(因为&arr[0]的类型是char*)指向数组第二个元素,所以&arr[0]+1表示数组第二个元素的地址。所以这里打印的应该是4(单位:字节)。

运行结果如下:

第二组题目如下: 

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%zd\n", strlen(arr));
	printf("%zd\n", strlen(arr + 0));
	printf("%zd\n", strlen(&arr[0] + 1));
	return 0;
}
1.printf("%zd\n",strlen(arr));

这种情况数组名(arr)属于数组名意义的第三种情况。原因同上紫色字体所述。数组名(arr)表示数组首元素地址,将数组首元素地址传参给strlen函数。我们可以看到,数组arr有6个元素(没有字符'\0'),元素类型为char(占1个字节)。因为我们无法预料从数组首元素地址开始访问何时在内存中访问到字符'\0'。所以这里打印的应该是一个(>=6)随机值。

2.printf("%zd\n",strlen(arr+0));

这种情况数组名(arr)属于数组名意义的第三种情况。既然数组名(arr)属于第三种情况,数组名(arr)表示数组首元素地址,arr+0跳过0个字节还是指向了数组首元素,arr+0还是表示数组首元素地址。因为我们无法预料从数组首元素地址开始访问何时在内存中访问到字符'\0'。所以这里打印的也应该是一个同上一模一样的(>=6)随机值。

3.printf("%zd\n",strlen(&arr[0]+1));

这种情况数组名(arr)属于数组名意义的第三种情况。&arr[0]表示数组首元素的地址,原因同上澄色字体所述。&arr[0]+1跳过1个字节(因为&arr[0]类型是char*)指向数组第二个元素,所以&arr[0]+1表示数组第二个元素地址。因为我们无法预料从数组第二个元素开始访问何时在内存中访问到字符'\0'。所以这里打印的应该是一个(>=5且比上面两个数小1)的随机值。

运行结果如下:

第一次输入代码运行:

第二次输入代码运行:

 第三组题目如下:

#include<stdio.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr + 0));
	printf("%d\n", sizeof(*arr));
	printf("%d\n", sizeof(arr[1]));
	printf("%d\n", sizeof(&arr));
	printf("%d\n", sizeof(&arr + 1));
	printf("%d\n", sizeof(&arr[0] + 1));
	return 0;
}
1.printf("%d\n",sizeof(arr)); 

这个情况数组名(arr)属于数组名意义的第一种情况。我们可以看到数组arr有7个元素(结尾隐藏了字符'\0'),元素类型为char(占1个字节)。所以这里打印的应该是7(单位:字节)。

2.printf("%d\n",sizeof(arr+0));

这种情况数组名(arr)属于数组名意义的第三种情况。原因同上紫色字体所述。既然数组名(arr)属于第三种情况,数组名(arr)表示数组首元素地址,arr+0跳过0个字节还是指向了数组首元素,arr+0还是表示数组首元素地址。所以这里打印的应该是4(单位:字节)。

3.printf("%d\n",sizeof(*arr));

这种情况数组名(arr)属于数组名意义的第三种情况。理由同上紫色字体所述。既然数组名(arr)属于第三种情况,数组名(arr)表示数组首元素地址,数组首元素地址(arr)解引用(*arr)访问数组首元素,即得到了数组首元素。所以这里打印的应该是1(单位:字节)。

4.printf("%d\n",sizeof(arr[1]));

这种情况数组名(arr)属于数组名意义的第三种情况。arr[1]可以表示为*(arr+1)。我们分析*(arr+1),既然arr表示数组首元素地址,arr+1跳过1个字节(因为arr的类型是char*)指向了数组第二个元素,arr+1表示数组第二个元素的地址,解引用第二个元素地址*(arr+1)访问数组第二个元素,即得到第二个元素。而且我们常规来看,arr[1]亦是表示数组第二个元素。所以这里打印的应该是1(单位:字节)。

5.printf("%d\n",sizeof(&arr));

这种情况数组名(arr)属于数组名意义的第二种情况。&arr表示的是整个数组的地址(&arr类型是:char(*)[7]),既然是地址内存长度就是4个字节。所以这里打印的应该是4(单位:字节)。

6.printf("%d\n",sizeof(&arr+1));

这种情况数组名(a)属于数组名意义的的二种情况。&arr表示的是整个数组的地址,&arr+1跳过整个数组大小,即7个字节(因为&a的类型是char(*)[7]),&arr+1还是表示一个地址。所以这里打印的应该是4(单位:字节)。

7.printf("%d\n",sizeof(&arr[0]+1));

这种情况数组名(a)属于数组名意义的第三种情况。&arr[0]的分析同上橙色字体所述,这里不在赘述。&arr[0]表示数组首元素的地址,&arr[0]+1跳过1个字节(因为&arr[0]的类型是char*)指向数组第二个元素,所以&arr[0]+1表示数组第二个元素的地址。所以这里打印的应该是4(单位:字节)。

运行结果如下:

第四组题目如下: 

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdef";
	printf("%zd\n", strlen(arr));
	printf("%zd\n", strlen(arr + 0));
	printf("%zd\n", strlen(&arr[0] + 1));
	return 0;
}
1.printf("%zd\",strlen(arr)); 

这种情况数组名(arr)属于数组名意义的第三种情况。原因同上紫色字体所述。数组名(arr)表示数组首元素地址,将数组首元素地址传参给strlen函数。我们可以看到数组arr有7个元素(结尾隐藏了字符'\0'),元素类型为char(占1个字节)。所以这里打印的应该是6(单位:字节)。

2.printf("%zd\n",strlen(arr+0));

 这种情况数组名(arr)属于数组名意义的第三种情况。既然数组名(arr)属于第三种情况,数组名(arr)表示数组首元素地址,arr+0跳过0个字节还是指向了数组首元素,arr+0还是表示数组首元素地址。所以这里打印的应该也是6(单位:字节)。

3.printf("%zd\n",strlen(&arr[0]+1));

 这种情况数组名(arr)属于数组名意义的第三种情况。&arr[0]表示数组首元素的地址,原因同上澄色字体所述。&arr[0]+1跳过1个字节(因为&arr[0]类型是char*)指向数组第二个元素,所以&arr[0]+1表示数组第二个元素地址。所以这里打印的应该是一个(>=5且比上面两个数小1)的随机值。所以这里打印的应该是5(单位:字节)。

运行结果如下:

第五组题目如下:

#include<stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%zd\n", sizeof(p));
	printf("%zd\n", sizeof(p + 1));
	printf("%zd\n", sizeof(*p));
	printf("%zd\n", sizeof(p[0]));
	printf("%zd\n", sizeof(&p));
	printf("%zd\n", sizeof(&p + 1));
	printf("%zd\n", sizeof(&p[0] + 1));
	return 0;
}

这组题目与上面的题目有所不同。这组题目的意思是:内存中存储这一个常量字符串“abcdef\0”('\0'被隐藏了)。 这个常量字符串是不能被更改的。将这个常量字符串的首元素('a')地址赋给一个类型为char*的指针变量p。

1.printf("%zd\n",sizeof(p)); 

由上分析,我们可知指针变量p指向了常量字符串首元素('a'),即p存放着'a'的地址。所以这里应该打印4(单位:字节)。

2.printf("%zd\n",sizeof(p+1));

由上可知,指针变量p存放着'a'的地址,p+1跳过1个字节(因为p的类型是char*)指向了常量字符串第二个元素('b'),即p+1表示第二个元素的地址。所以这里应该打印4(单位:字节)。

3.printf("%zd\n",sizeof(*p));

由上分析,我们可知指针变量p指向了字符串首元素('a'),即p存放着'a'的地址。解引用该地址*p访问常量字符串首元素'a',所以的*p得到常量字符串首元素'a'。所以这里应该打印1(单位:字节)。

4.printf('%zd\n',sizeof(p[0]));

我们知道p[0]可以表示成*(p+0),并且知道p存放着'a'的地址。我们分析*(p+0):p+0跳过0个字节还是指向常量字符串首元素'a',解引用该地址*(p+0)访问常量字符串首元素'a',即p[0]得到常量字符串首元素'a'。所欲这里应该打印1(单位:字节)。

5.printf("%zd\n",sizeof(&p));

我们知道p是一个类型为char*的指针变量,存放着'a'的地址。&p就得到指针变量p的地址,所以&p是一个二级指针(&p的类型是**char)。所以这里应该打印4(单位:字节)。

6.printf("%zd\n",sizeof(&p+1));

由上分析可知&p就得到指针变量p的地址,所以&p是一个二级指针(&p的类型是**char)。&p+1跳过4个字节(因为&p的类型是char**,而char*类型占4个字节,所以char**+1的权限就是跳过4个字节),仍然是一个地址。所以这里应该打印4(单位:字节)。

7.printf("%zd\n",sizeof(&p[0]+1));

由上分析可知p[0]得到常量字符串首元素'a',&p[0]即表示常量字符串首元素'a'的地址。&p[0]+1跳过1个字节(因为&p[0]的类型是char*)指向常量字符串第二个元素'b',所以&p[0]+1表示'b'的地址。所以这里应该打印4(单位:字节)。

运行结果如下:

第六组题目如下:

#include<stdio.h>
#include<string.h>
int main()
{
	char* p = "abcdef";
	printf("%zd\n", strlen(p));
	printf("%zd\n", strlen(p + 1));
	printf("%zd\n", strlen(&p));
	printf("%zd\n", strlen(&p + 1));
	printf("%zd\n", strlen(&p[0] + 1));
	return 0;
}
1.printf("%zd\n",strlen(p)); 

由上分析,我们可知指针变量p指向了常量字符串首元素('a'),即p存放着'a'的地址。将该地址传参给strlen函数。我们可以看到这个常量字符串有7个元素(结尾隐藏'\0'),每个元素类型为char(占1个字节)。所以这里应该打印6(单位:字节)。

2.printf("%zd\n",strlen(p+1));

由上可知,指针变量p存放着'a'的地址,p+1跳过1个字节(因为p的类型是char*)指向了常量字符串第二个元素('b'),即p+1表示第二个元素的地址。将第二个元素的地址传参给strlen函数。所以这里应该打印5(单位:字节)。

3.printf("%zd\n",strlen(&p));

 我们知道p是一个类型为char*的指针变量,存放着'a'的地址。&p就得到指针变量p的地址,所以&p是一个二级指针(&p的类型是**char)。将&p传参给strlen函数。我们无法预料从&p这个地址开始访问何时在内存中访问到'\0'。所以这里应该打印一个随机值(单位:字节)。

4.printf("%zd\n",strlen(&p+1));

由上分析可知&p就得到指针变量p的地址,所以&p是一个二级指针(&p的类型是**char)。&p+1跳过4个字节(因为&p的类型是char**,而char*类型占4个字节,所以char**+1的权限就是跳过4个字节),仍然是一个地址。将&p+1传参给strlen函数。我们也无法预料从&p+1这个地址开始访问何时在内存中访问到'\0'。所以这里应该打印的也是一个随机值(单位:字节)。

5.printff("%zd\n",strlen(&p[0]+1));

由上分析可知p[0]得到常量字符串首元素'a',&p[0]即表示常量字符串首元素'a'的地址。&p[0]+1跳过1个字节(因为&p[0]的类型是char*)指向常量字符串第二个元素'b',所以&p[0]+1表示'b'的地址。将&p[0]+1传参给strlen函数,即将第二个元素的地址传参给strlen函数。所以这里应该打印5(单位:字节)。

运行结果如下:

 3.二维数组

题目如下:

#include<stdio.h>
int main()
{
	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]));
	return 0;
}

在做这道题之前,我们需要明白: 二维数组可以理解成:

角度1:数组的数组,就是一维数组的数组。一维数组是二维数组的元素。如题中二维数组为例:这个二维数组可以理解为:有三个元素,分别是a[0],a[1],a[2]。这三个元素类型均为int(*)[4],这三个元素又分别为一个有4个元素(类型为int)的一维数组。

角度2:常规理解,如题中这个二维数组为例:这个二维数组可以理解为:有12个元素,每个元素类型为int。

小编个人理解:

1.printf("%d\n",sizeof(a));

这个情况二维数组数组名(a)属于数组名意义的第一种情况。sizeof(数组名),这里的数组名表示整个二维数组,计算的是整个二维数组的大小。我们可以看到二维数组a有12个元素,元素类型为int(占4个字节)。所以这里打印的的应该是48(单位:字节)。

2.printf("%d\n",sizeof(a[0][0]));

角度1看来:这种情况二维数组数组名(a)属于数组名意义的第三种情况。二维数组数组名a表示二维数组首元素a[0]的地址。a[0]可以表示为*(a+0),我们来分析*(a+0):二维数组数组名a代表二维数组首元素a[0]地址,a+0表示跳过0个字节还是指向首元素a[0],再解引用就得到二维数组首元素a[0],即a[0]表示二维数组首元素(这个首元素是一个一维数组,类型为int(*)[4])。a[0][0]又可以表示为*(a[0]+0),我们来分析*(a[0]+0):二维数组首元素a[0]是一个一维数组,这个一维数组的数组名为a[0],所以这种情况一维数组数组名(a[0])属于数组名意义的第三种情况。那么a[0]代表一维数组a[0]首元素地址,a[0]+0跳过0个字节还是指向一维数组首元素,所以一维数组首元素地址解引用*(a[0]+0)访问一维数组首元素,可以知道*(a[0]+0)就代表二维数组首元素a[0]的首元素a[0][0]。所以这里应该打印的是4(单位:字节)。

角度2看来:常规看来,a[0][0]就是二维数组的首元素,这个首元素的类型是int。所以这里应该打印的是4(单位:字节)。

3.printf("%d\n",sizeof(a[0]));

这种情况一维数组数组名(a[0])属于数组名意义的第一种情况。a[0]是二维数组a的首元素(这个首元素是一个一维数组),同时又是一维数组的数组名。数组名单独放在sizeof内部计算的是整个(一维)数组的大小。所以这里应该打印的是16(单位:字节)。

4.printf("%d\n",sizeof(a[0]+1));

这种情况一维数组数组名(a[0])属于数组名意义的第三种情况。所以数组名a[0]是一维数组首元素的地址,a[0]+1跳过4个字节(因为a[0]类型为int*)指向一维数组第二个元素,即a[0]+1得到二维数组首元素a[0]的第二个元素a[0][1]的地址。所以这里打印的应该是4(单位:字节)。

5.printf("%d\n",sizeof(*(a[0]+1)));

这种情况一维数组数组名(a[0])属于数组名意义的第三种情况。由上分析可知,a[0]+1代表二维数组首元素a[0]的第二个元素a[0][1]的地址,解引用该地址*(a[0]+1)访问a[0][1],所以得到元素a[0][1]。所以这里打印的应该是4(单位:字节)。

6.printf("%d\n",sizeof(a+1));

这种情况二维数组数组名(a)属于数组名意义的第三种情况。a代表二维数组首元素(一维数组a[0])地址,a+1跳过16个字节(因为a的类型是int(*)[4])指向二维数组第二个元素(一维数组a[1]),所以a+1代表a[1]的地址。所以这里打印的应该是4(单位:字节)。

7.printf("%d\n",sizeof(*(a+1)));

由上可知,a+1代表a[1]的地址,解引用该地址*(a+1)访问a[1]整个一维数组,即得到整个一维数组a[1]。所以这里计算的应该是整个一维数组的大小。另一种视角看:访问整个一维数组a[1],得到整个一维数组a[1],所以a[1]可以代表*(a+1),这样的话a[1]就单独放在sizeof内部了,计算的也是整个一维数组的大小。所以这里打印的应该是16(单位:字节)。

8.printf("%d\n",sizeof(&a[0]+1));

这种情况一维数组数组名(a[0])属于数组名意义的第二种情况。&a[0]代表整个一维数组a[0]的地址,&a[0]+1跳过16个字节(&a[0]类型为int(*)[4])指向二维数组第二个元素a[1],即&a[0]+1代表二维数组第二个元素a[1]的地址。所以这里打印的应该是4(单位:字节)。

9.printf("%d\n",sizeof(*(&a[0]+1)));

由上可知,&a[0]+1代表二维数组第二个元素a[1]的地址,解引用该地址*(&a[0]+1)访问整个二维数组a[1],即*(&a[0]+1)代表了整个二维数组的第二个元素a[1]。所以这里打印的应该是16(单位:字节)。

10.printf("%d\n",sizeof(*a));

这种情况二维数组数组名(a)属于数组名意义的第三种情况。a代表了二维数组的首元素a[0]地址,解引用该地址*a访问整个二维数组首元素a[0]。所以这里打印的应该是16(单位:字节)。

11.printf("%d\n",sizeof(a[3]));

 sizeof是一个编译时刻就起效果的运算符,在其内的任何运算都没有意义,所以不存在越界访问的问题。sizeof(a[3])的大小与sizeof(a[0])的大小一样。所以这里打印的应该是16(单位:字节)。

运行结果如下:

 ending:

感谢阅读,跪求点赞,如有不足,恳请斧正!

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X_chengonly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值