指针面试题详解

目录

前言(数组名的总结):

一、int 型数组和 sizeof 的组合

sizeof计算原理

 二、char类型和strlen()组合

三、char*类型和sizeof()组合(有 '\0' 版本)

四、char*类型和strlen()组合(有 '\0' 版本)

五、二维数组和sizeof()组合


前言(数组名的总结):

因为本文章大部分与数组名有关,我们首先温习一下数组名的知识,数组名通常都表示数组的首元素地址,但是有两个例外:

  • &数组名,这里的数组名就表示整个数组的地址
  • sizeof(数组名),这里的数组名也表示整个数组的地址

除上述两种特殊情况外,其余我们见到的数组名都表示数组的首元素地址。

一、int 型数组和 sizeof 的组合

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

此时的数组名就是表示整个数组的地址,所以计算结果就是4*4=16

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

此时的数组名不是两种特殊情况,因此就表示数组的首元素地址,+0无效果,所以最终还是数组的首元素地址,因此答案4/8个字节(指针的大小)

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

此时数组名也表示数组的首元素地址,然后解引用*就是数组的第一个元素,也就是4个字节

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

 这个数组名也表示数组的首元素地址,然后+1,因为a是int *类型,+1就跳过一个int类型的大小,所以a+1就表示数组的第二个元素的地址,答案是4/8(指针大小)

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

 此时的数组名确实表示整个数组的地址,但他本质上还是一个指针,不能在门缝里看指针,把指针看扁了,无论什么类型的指针,他的大小都是4/8个字节!

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

* 和 & 是两个相逆的运算,相当于求导和求微分的意思,所以这两个在一起,就可以抵消。

因此*&a==a

而我们上面已经讲过,答案就是4*4

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

&a+1 相较于 &a 跳过了整个数组,但本质上还是地址,所以结果是4/8

sizeof计算原理

sizeof只需要知道数据类型是什么,不需要访问内存去计算,甚至sizeof(int),这样的表达式也是可以的 

 二、char类型和strlen()组合

首先我们明确,strlen计算字符串的长度,计算的是\0之前出现的字符的个数

	char arr[] = { 'a','b','c','d','e','f' };

注意这一种初始化方式,内存中存储的是

a b c d e f

后面内容未知,前面内容也未知。

	strlen(arr);

因为arr里面没有存放\0,所以strlen会一直向后寻找,直到找到为止,而后面存储的内容我们是未知的,因此最后结果就是随机值。

	strlen(arr + 0);

表示的仍然是首元素的地址,跟第一个一样,因此结果也是随机值

	strlen(*arr);

这样写是非法的!

因为strlen()需要的参数是字符指针类型,而我们将*arr也就是数组的第一个元素 'a' 作为参数传递进去,转换为97,而strlen会将97作为地址访问,而97并不是我们的地址,所以就造成了非法访问内存了。

	strlen(arr[1]);

这一题跟上一题一样,都是非法访问内存,是错误的。

	strlen(&arr);

我们首先需要明确&arr,和数组的首元素的地址值是一样的。

但是类型不一样,前者是 char (*) [ ],后者是 char* 。

但是我们将地址传到strlen之后,函数会将地址自动转换为想要的const char* 

因此,还是会从数组的首元素开始访问,答案也就是随机值

	strlen(&arr + 1);

这题表示跳过了整个数组,答案也就是随机值,并且跟上一题的结果有联系,相差6,因为跳过整个数组,数组的6个字符元素。

三、char*类型和sizeof()组合(有 '\0' 版本)

	char* p[] = { "abcdef" };//字符串已经含有'\0'

把字符串首元素a的地址赋给arr。 

	printf("%d\n", sizeof(p)); 

注意这里的p不是数组名,他本质上就是一个指针变量,所以结果就是4/8个字节

	printf("%d\n", sizeof(p+1)); 

首先表示字符串第二个元素的地址,因为 p是char* 类型,所以p+1就跳过一个字符的大小,所以就是b的地址。是地址就是4/8个字节

	printf("%d\n", sizeof(*p));

因为p存储的是字符串首元素的地址,所以解引用就是字符串的首元素,因此结果就是一个字符的大小——1

	printf("%d\n", &p + 1);

答案是显而易见的,仍然是地址(4/8),但这题的关键在于&p+1到底指向哪里?

我们首先明确&p的类型是char **,p的类型是char*。

+1就跳过char*的内容,而char*的内容指向的是p,所以+1就跳过p,最终指向的是p后面

注意字符串首元素的地址和p的地址是两码事,是两块不同的内存空间

四、char*类型和strlen()组合(有 '\0' 版本)

	char* p[] = { "abcdef" };//字符串已经含有'\0'
	printf("%d\n", strlen(p));

到\0前面停止,就是6个字符

	printf("%d\n", strlen(p + 1));

p是a的地址,+1就是b的地址,所以结果就是6-1=5

	printf("%d\n", strlen(*p));

此时输入是非法的,因为*p就是把a传进去,而strlen需要一个字符指针。

	printf("%d\n", strlen(&p));

p的地址和字符串存的地址没有任何关系,也是随机值

	printf("%d\n", strlen(&p + 1));

也是随机值,但与&p有没有关系呢?

其实并没有关系,因为p是一个地址,4/8个字节,我们并不能确定这4~8个字节里面是否含有\0,如果有,那这两者无任何关系

五、二维数组和sizeof()组合

	int arr[3][4] = { 0 };

 

二维数组在内存中的存储方式就是这样的。

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

注意此时的数组名直接放在了sizeof里面,所以就是表示整个数组3*4*4=48

	printf("%d\n", sizeof(arr[0]));

 TIP:

在二维数组中,我们认为第一行就是第一个元素

arr[0]:二维数组第一行这个一维数组的数组名

arr[1]:二维数组第二行这个一维数组的数组名

arr[2]:二维数组第三行这个一维数组的数组名

以此类推……

所以此时的arr[0]就是二维数组第一行的数组名,既然又是数组名,那么就仍表示整个数组

4*4=16

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

首先arr[0]并没有单独放在sizeof()内部,也没有&arr,所以此时的arr[0]就表示数组第一行的首元素地址,也就是arr[0][0]的地址,再+1就表示arr[0][1]的地址,结果是4/8个字节

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

arr是表示数组的首元素地址,但这是二维数组,所以首元素也就是二维数组的第一行的地址

再+1就表示第二行整体的地址,是地址就是4/8个字节、

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

第一种思路:

*(arr+1)==arr[1],这两者互相转换,所以我们把arr[1]单独放在sizeof()内部就表示整个第二行的数组,所以就是4*4

第二种思路:

上一题我们讲过arr+1就是数组的第二行元素的地址,类型是int (*) []是数组指针,而我们对数组指针解引用,访问的就是整个数组。4*4

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

&arr[0]表示的二维数组第一行的地址,再+1就表示第二行的地址。4/8

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

我们由上一题已经直到&arr[0]+1就表示数组的第二行地址,再解引用就是整个第二行元素的大小4*4

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

因为数组名没有单独放在sizeof(),也没有&,所以就表示数组的首元素地址,在二维数组中也就是第一行的地址,然后解引用,计算整个第一行,4*4

猜你喜欢

转载自blog.csdn.net/hanwangyyds/article/details/131682234
今日推荐