指针面试题详解

简介: 指针面试题详解

前言(数组名的总结):

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

  • &数组名,这里的数组名就表示整个数组的地址
  • 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

相关文章
|
7月前
|
C++
C/C++工程师面试题(指针篇)
C/C++工程师面试题(指针篇)
106 0
|
7月前
|
算法 程序员 索引
【Leetcode 程序员面试金典 02.08】 —— 环路检测 |双指针
我们可以使用双指针解决本题,由数学推导可知:a 的距离为(环长度的倍数 - b),即 tmp 指针从头节点走到环开头节点等于 slow 指针走到环开头节点的距离
|
2月前
|
编译器 C语言
经典左旋,指针面试题
文章介绍了两种C语言实现字符串左旋的方法,以及如何使用C语言对整数数组进行奇偶数排序。通过实例演示了如何使用函数reverse_part和leftRound,以及在swap_arr中实现数组元素的重新排列。
30 0
|
2月前
|
Serverless 编译器 C语言
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
|
7月前
|
Java Go
Golang深入浅出之-Go语言指针面试必知:理解与使用指针
【4月更文挑战第21天】Go语言中的指针允许直接操作内存,常用于高效数据共享和传递。本文介绍了指针的基础知识,如声明、初始化和解引用,以及作为函数参数使用。此外,讨论了`new()`与`make()`的区别和内存逃逸分析。在结构体上下文中,指针用于减少复制开销和直接修改对象。理解指针与内存管理、结构体的关系及常见易错点,对于面试和编写高性能Go代码至关重要。
106 2
|
7月前
|
编解码 缓存 安全
【C/C++ 泡沫精选面试题03】谈谈C/C++ 智能指针?
【C/C++ 泡沫精选面试题03】谈谈C/C++ 智能指针?
89 1
|
7月前
|
存储 C语言
c语言中strlen与sizeof的区别(指针面试题详解帮你深度区分!)
c语言中strlen与sizeof的区别(指针面试题详解帮你深度区分!)
|
7月前
|
安全 IDE Java
【2024java面试题无需C币下载】终结空指针异常:Java开发者的生存指南
【2024java面试题无需C币下载】终结空指针异常:Java开发者的生存指南
90 1
|
7月前
|
C++
面试题:常量指针和指针常量?
面试题:常量指针和指针常量?
50 0
|
7月前
|
C++
面试题:如何避免野指针?
面试题:如何避免野指针?
93 0