目录
回顾:
我们在之前的blog中有涉及到关于数组名和实现冒泡排序的讲解。
我们这里简单的进行回顾一下:
1.sizeof(数组名)---表示的是整个数组的大小。
2.&(数组名)---表示的是取出整个数组的地址。
3.除以上两种情况外,其余的数组名都表示数组首元素的地址!!!
以上三点我们需要牢记,并且要记住一句话:
“不要在门缝里看指针,把指针看扁了!”
关于数组名的知识点可以参考一下blog:
数组面试题:
一维数组:
题型一:
我们可以先尝试自己做一下一下代码,看看自己想的是否与待会讲解内容一致。
int main()
{
//T1
int a[] = { 1, 2, 3, 4 };
printf("%d\n", sizeof(a)); //1
printf("%d\n", sizeof(a + 0)); //2
printf("%d\n", sizeof(*a)); //3
printf("%d\n", sizeof(a + 1)); //4
printf("%d\n", sizeof(a[1])); //5
printf("%d\n", sizeof(&a)); //6
printf("%d\n", sizeof(*&a)); //7
printf("%d\n", sizeof(&a + 1)); //8
printf("%d\n", sizeof(&a[0])); //9
printf("%d\n", sizeof(&a[0] + 1)); //10
}
1.
printf("%d\n", sizeof(a));
对于这一行代码我们可以知道,sizeof内部是字母‘a’,那么‘a’是什么呢?
答案显而易见,‘a’是数组名,所以在这里sizeof(a)计算的就是整个数组的大小!
由于该数组的返回值为int,即数组中每个元素都为整形,已知一个整形占4个字节,
所以我们不难算出最后的结果为4 * 4 = 16。
一共是
16字节。
2.
printf("%d\n", sizeof(a + 0));
对于这一行的代码来说呢,我们先判断sizeof内部是什么?
在这里,sizeof内部是“a + 0”,所以它不满足sizeof(数组名)这种例子。
正因如此,这里的“a + 0”表示的就是数组首元素的地址。
既然是地址,那么它的大小
在32位的机器上就是4个字节。
在64位的机器上就是8个字节。
所以该题的答案就是
4或者8字节。
3.
printf("%d\n", sizeof(*a));
对于这道题,第一步就是判断sizeof内部,内部不是只有数组名,所以不满足数组名的个例。
那么*a表示什么呢?
我们其实可以换一种表示方式,即
*a == *(a + 0)== a[0]
a[0]表示的意思就是数组的第一个元素。
那么既然是元素,又因为它是整形变量,所以它占4个字节。
因此结果为
4字节。
6.
printf("%d\n", sizeof(&a));
对于这道题来说,我们不仅仅要注意sizeof内部的值。
确实,sizeof
内部现在不是仅为数组名a了,是&a,那么肯定会有人觉得&a表示的就是整个数组的地址,所以答案是16字节。
这种想法大错特错!
既然我们已经知道,&数组名表示的是“取出整个数组的地址”,那么既然是地址,
地址肯定仅仅占4或8个字节。
所以这道题的答案为:
4或8字节。
根据以上内容,我们可以了解到“数组的地址”和“数组首元素的地址”,他们的本质区别是类型的区别。
即:
数组名a --- int*
&数组名a --- int(*)[4]
前者表示整形指针变量。
后者表示数组指针变量
剩下的内容可以参考上述讲解,
答案即输出内容如下:
题型二:
char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
printf("%d\n", sizeof(arr)); //1
printf("%d\n", sizeof(arr + 0)); //2
printf("%d\n", sizeof(*arr)); //3
printf("%d\n", sizeof(arr[1])); //4
printf("%d\n", sizeof(&arr)); //5
printf("%d\n", sizeof(arr + 1)); //6
printf("%d\n", sizeof(&arr[0] + 1)); //7
printf("%d\n", strlen(arr)); //8
printf("%d\n", strlen(arr + 0)); //9
printf("%d\n", strlen(*arr)); //10
printf("%d\n", strlen(arr[1])); //11
printf("%d\n", strlen(&arr)); //12
printf("%d\n", strlen(&arr + 1)); //13
printf("%d\n", strlen(&arr[0] + 1)); //14
2.
printf("%d\n", sizeof(arr + 0));
对于该题目,先判断sizeof内部是否只有数组名arr。
对于“arr + 0”,
要注意的是,这里表示的是首元素的地址,与指针变量是int*还是char*无关!!!
要记住,
指针变量大小和类型无关!!!
不管什么类型的指针变量,大小都是4或者8个字节。
指针变量是用来存放地址的,
地址存放需要多大空间,指针变量大小就是多少字节!!
既然是地址,那么它都占4字节或者8字节。所以答案为:
4或8字节
8.
printf("%d\n", strlen(arr));
strlen(const char* str)
对于strlen的题目,我们要时时刻刻注意的是——'\0',作为一个字符串元素个数统计的函数,他的结束标志是当它访问到‘\0’时,就结束遍历并返回统计到的个数。
那么对于该题,arr表示的数组首元素的地址,意思就是说strlen会找到数组首元素的地址,再从首元素往后进行遍历统计,直到访问到‘\0’。
但是该数组不存在'\0',那么strlen就会继续在内存中寻找‘\0’。
由于‘\0’的地址会随着每次编译发生变化,所以每次打印出来的值都不一样,
所以strlen会统计出随机值。
所以该题答案为:
随机值。
10.
printf("%d\n", strlen(*arr));
对于此题目,*arr就是首元素,站在strlen的角度上,strlen会认为传参进去的arr - ‘97’该ASCll码值就是地址,当97作为地址,就相当于strlen对内存直接进行访问,那么就是非法访问,程序会崩掉。
因此程序会崩掉。
11题同理。
补充一下,&arr——char(*)[6]
如果是strlen(&arr)则会报告错误:“简介级别不同”
因此该题型中strlen部分的答案为:
sizeof部分的答案为:
题型三:
char arr1[] = "abcdef";
printf("%d\n", sizeof(arr1)); //1
printf("%d\n", sizeof(arr1 + 0)); //2
printf("%d\n", sizeof(*arr1)); //3
printf("%d\n", sizeof(arr1[1])); //4
printf("%d\n", sizeof(&arr1)); //5
printf("%d\n", sizeof(&arr1 + 1)); //6
printf("%d\n", sizeof(&arr1[0] + 1)); //7
printf("%d\n", strlen(arr1)); //8
printf("%d\n", strlen(arr1 + 0)); //9
printf("%d\n", strlen(*arr1)); //10
printf("%d\n", strlen(arr1[1])); //11
printf("%d\n", strlen(&arr1)); //12
printf("%d\n", strlen(&arr1 + 1)); //13
printf("%d\n", strlen(&arr1[0] + 1)); //14
1.
printf("%d\n", sizeof(arr1));
对于该题目来说,先判断sizeof内部,由题可知sizeof(arr1),内部数据为数组名arr1,所以arr1表示去出整个数组的大小,又该数组的返回值为char类型,所以该数组的每个元素为char类型,char类型在内存中占1个字节。
在这里要注意的是,该数组里存放的是一个字符串,因此不可以漏掉‘\0’。
所以答案为 7 * 1
7字节。
13.
对于strlen(&arr1 + 1),画图则会好理解些,图如下:
蓝色箭头所指向的就不是数组中的内容了,所以最后答案就是
随机值。
其它提醒均与上述两种题型相似,在这里不进行过多的赘述。
答案如下:
sizeof部分:
strlen部分为:
题型四:
char* p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p + 1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
对于这道题,利用画图可以很好的解释以上全部代码。
要注意的是,该题型为常量字符串,利用指针来表示字符串。
sizeof部分答案:
strlen部分答案:
二维数组:
int b[3][4] = { 0 };
printf("%d\n", sizeof(b)); //1
printf("%d\n", sizeof(b[0][0])); //2
printf("%d\n", sizeof(b[0])); //3
printf("%zd\n", sizeof(b[0] + 1)); //4
printf("%d\n", sizeof(*(b[0] + 1))); //5
printf("%d\n", sizeof(b + 1)); //6
printf("%d\n", sizeof(*(b+1))); //7
printf("%d\n", sizeof(&b[0] + 1)); //8
printf("%d\n", sizeof(*(&b[0] + 1))); //9
printf("%d\n", sizeof(*b)); //10
printf("%d\n", sizeof(b[3])); //11
对于二维数组,其实二维数组就是一维数组的数组。
我们可以理解为如图排列的:
但是二维数组在内存中实际上是连续排序的:
1.
printf("%d\n", sizeof(b));
所以对于第一行代码来说,sizeof内部是数组名b,所以b此时代表的是整个数组,所以b占4 * 4 *4个字节,即答案为:
48字节。
3.
printf("%d\n", sizeof(b[0]));
b[0]是第一行一位数组的数组名,计算的是整个第一行数组的大小。
所以答案为:
4 * 4 = 16字节。
4.
printf("%zd\n", sizeof(b[0] + 1));
b[0]此时并非单独存放在sizeof内部,因此b[0]表示表示第一行数组首元素的地址,也就是第一行第一个元素的地址,即&b[0][0]
所以当b[0] + 1 <——>&b[0][1]
所以既然是地址,答案就是
4或8个字节。
6.
printf("%d\n", sizeof(b + 1));
b作为二维数组的数组名,并没有单独存放在sizeof内部,所以b就是数组首元素的地址,即第一行的地址,所以b的类型为——int(*)[4]
故b + 1是第二行的地址
既然是地址所以答案为:
4或8字节。
8.
printf("%d\n", sizeof(&b[0] + 1));
b[0]是第一行的数组名,&b[0]取出的是数组的地址,取出的是第一行这个一维数组的地址,类型就是int(*)[4],那么&b[0] + 1就是第二行的地址。
既然是地址,所以答案为:
4或8字节。
10.
printf("%d\n", sizeof(*b));
b并非单独存放在sizeof内部,b表示首元素的地址,也就是第一行的地址。
*b代表的就是第一行,也就是相当于是第一行的数组名。
*b——>*(b + 0)——>b[0]。
补充:
*(b + 1) == b[1] 即第二行的数组名。
总结:
以上的代码就是笔试面试题中关于数组的命题提醒,下去应当及时复习这一部分,并对其中的题型熟烂于心,在每一次看答案甚至解析之前动手做一做。
记住:
“坐而言不如起而行!”
“Actions speak louder than words!”
点击下面链接,即可访问“攻破《数组与指针》相关面试题(二)”