【指针笔试题上】你知道大厂面试题的指针题是什么样的吗?快来通过这些面试题目检测一下自己吧!

简介: 【指针笔试题上】你知道大厂面试题的指针题是什么样的吗?快来通过这些面试题目检测一下自己吧!

目录

前言:

一.strlen和sizeof的区别

二.一维数组笔试题解析

三.二维数组笔试题解析

四.总结:

博客主页:张栩睿的博客主页

欢迎关注:点赞+收藏+留言

系列专栏:c语言学习

       家人们写博客真的很花时间的,你们的点赞和关注对我真的很重要,希望各位路过的朋友们能多多点赞并关注我,我会随时互关的,欢迎你们的私信提问,也期待你们的转发!

       希望大家关注我,你们将会看到更多精彩的内容!!!

前言:

       相信大家在之前的学习对于指针这一块的知识是比较头疼的,通过下面的题目,我相信你会真正检测出自己的指针是否真的学的扎实了!

在开始之前,我们来看看数值名意义的总结,这个是本篇文章的重中之重!

1. sizeof(数组名),数组名表示整个数组。计算的是整个数组的大小,单位是字节

2. &数组名,数组名表示整个数组。取出的是整个数组的地址.

3.其他所有的数组名都是数组首元素的地址.

一.strlen和sizeof的区别

sizeof()

是一个操作符,

只关注占用内存空间的大小,单位是字节,不关心内存中存放的是什么,'\0'会被包含在内

注:

       sizeof只关注占用空间的大小,放在()内的表达式是不会参与运算的。

解析:

sizeof(s=s+3)的值为:2;表示 sizeof只看它的类型大小,short类型大小为2,而不会具体去看表达式的值;

printf(“%d\n”,s)的值还是3,表示sizeof并不计算表达式的值;

     

       表达式最终的类型是short,cpu只知道两个整形相加,保存在short类型里面,所以sizeof计算的是short的内存大小。实际上,我们sizeof的使用是在编译期间使用的,而表达式的运算在运行期间执行,时间不一样。c语言程序的实现顺序如下:

实际上,c语言的表达式有两个属性,

比如2+3

1.值属性:5

2.类型属性:int

strlen

是一个库函数,

是求字符串长度的,统计的是\0之前(\0不算在内)出现的字符个数,一定要找到\0才算结束,所以可能存在越界访问的

关于库函数strlen()的定义:

       是用来求字符串长度的,形参设置为一个char类型的指针,所以我们传参的时候都是传的都是地址,而srtrlen()收到一个地址后,将会从这个地址以每次访问一个字节的空间大小,开始一直扫描,直到扫描到\0后停止;

二.一维数组笔试题解析

sizeof的一维数组:

      整形数组:

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));
}

结果:

                               

解析:

int a[]={1,2,3,4};

printf(“%d\n”,sizeof(a));

解:sizeof(数组名),计算的是整个数组的大小:4x4=16

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

解:a+0表示首元素的地址,不属于sizeof(数组名)类型,所以sizeof(a+0)表示计算的是首元素地址的大小;地址大小在32位操作系统是4字节,64位操作系统是8字节;

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

解:a表示数组首元素的地址,*a表示对这个地址解引用,就是数组第一个元素的值。sizeod(*a)表示计算第一个数组元素值的大小,而数组是整型数组,其中每个元素都是int类型,在内存中占4个字节;

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

解:a+1表示数组第二个元素的地址,sizeof(a+1)表示计算地址大小,4/8;

printf(“%d\n”,sizeof(a[1]));

解:a[1]表示第二个元素,sizeof(a[1])表示计算第二个元素的大小,结果为4字节;

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

解:&a表示整个数组的地址,sizeof(&a)表示计算整个数组地址大小,为4/8;

&a---> 类型:int(*)[4]

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

解:&a是数组的地址,*&a就是拿到了数组,*&a--> a,a就是数组名,sizeof(*&a)-->sizeof(a),sizeof(*&a)表示计算整个数组大小,为16字节;

printf(“%d\n”,sizeof(&a+1));

解:&a+1表示整个数组+1之后的地址,sizeof(&a+1)表示对数组后面的地址进行计算,地址的大小为4/8;

printf(“%d\n”,sizeof(&a[0]));

解:&a[0]是首元素的地址,计算的是首元素地址的大小,4/8字节

printf(“%d\n”,sizeof(&a[0]+1));

解:表示计算第二个元素的地址,4/8;其实这里是指:&*(a+0),等价于a+0,我们要知道这个+0非常重要,真的不能省略!省略就变成sizeof(数组名)了

字符数组:  

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));

                                   

解析:

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

printf(“%d\n”,sizeof(arr);

解:arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节,6;

printf(“%d\n”,sizeof(arr+0);

解:计算的是数组第首元素地址的大小,4/8;

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

解:计算的是数组首元素大小,为1字节;

printf(“%d\n”,sizeof(arr[1]);

解:计算数组第二个元素大小,1字节;

printf(“%d\n”,sizeof(&arr);

解:取出的数组的地址,数组的地址也是地址,是地址大小就是4/8

printf(“%d\n”,sizeof(&arr+1);

解:&arr + 1是跳过整个数组的地址,是4/8字节

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

解:计算的是第二个元素地址大小,4/8;

char arr[] = { 'a','b','c','d','e','f' };
  printf("① %d\n", strlen(arr));
  printf("② %d\n", strlen(arr + 0));
  printf("③ %d\n", strlen(*arr));
  printf("④ %d\n", strlen(arr[1]));
  printf("⑥ %d\n", strlen(&arr));
  printf("⑦ %d\n", strlen(&arr + 1));
  printf("⑧ %d\n", strlen(&arr[0] + 1));

解析:

printf(“%d\n”,strlen(arr));

解:随机值,因为我们知道strlen()函数根据首元素地址,计算字符串,是以\0结束;如果扫描不到\0,它就会一直在内存中扫描下去,直到遇见\0为止;

printf(“%d\n”,strlen(arr+0));

解:随机值,同上;

printf(“%d\n”,strlen(*arr));

解:我们知道,库函数strlen()它的参数是一个字符指针,如int strlen(const char *str);而*arr表示对字符数组首元素解引用,即是访问’a’字符,而我们又知道’a’字符在内存中表示为ASCLL码,为97,而97这个数组传给strlen()函数时,它会把它当成一个地址来访问,我们也不知道地址97里放的啥,会报错。strlen('a')->strlen(97),非法访问。

printf(“%d\n”,strlen(arr[1]));

解:arr[1]表示字符’b’,分析同上,报错;

printf(“%d\n”,strlen(&arr));

解:&arr虽然是数组的地址,但是也是从数组起始位置开始的,计算的还是随机值

这个时候类型不统一,&arr类型为char (*)[6],但不会报错。

printf(“%d\n”,strlen(&arr+1));

解:随机值;&arr是数组的地址,&arr+1是跳过整个数组的地址,求字符串长度也是随机值。但是这个随机值和strlen(&arr)的随机值是相差6字节的;

printf(“%d\n”,strlen(&arr[0]+1));

解:&arr[0] + 1是第二个元素的地址,是'b'的地址,求字符串长度也是随机值

字符串数组:

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));
  printf("⑧ %d\n", strlen(arr));
  printf("⑨ %d\n", strlen(arr + 0));
  printf("⑩ %d\n", strlen(*arr));
  printf("11  %d\n", strlen(arr[1]));
  printf("12  %d\n", strlen(&arr));
  printf("13  %d\n", strlen(&arr + 1));
  printf("14  %d\n", strlen(&arr[0] + 1));

结果:

解析:

[a b c d e f \0]

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

解:sizeof()计算字符串长度时会把字符串后面自带的\0计算进去,所以为7字节;

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

解:计算首元素地址,4/8字节

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

解:*arr是数组首元素,大小是1字节

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

解:计算第二个元素大小,1字节;

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

解:计算整个数组的地址,4/8;

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

解:&arr + 1是跳过整个数组的地址,是4/8字节

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

解:计算第二个元素的地址大小,4/8

8.printf(“%d\n”,strlen(arr))

解:strlen计算字符串长度,遇到字符串后\0,停止;字符数组arr大小为6字节;

9.printf(“%d\n”,strlen(arr+0))

解:arr+0表示首元素地址,但我们知道strlen要遇到\0才停止,所以会扫描完整个字符数组,结果为6字节;

10.printf(“%d\n”,strlen(*arr))

解:*arr是'a',是97,传给strlen是一个非法的地址,造成非法访问

11.printf(“%d\n”,strlen(arr[1]))

解:报错;

 

12.printf(“%d\n”,strlen(&arr))

解:6字节,我们知道strlen的形参为char*类型,即字符指针,每次访问一个字节,当我们传&arr整个字符数组的地址给strlen时,它会从这个地址开始,一个字节一个字节的往后访问,直到遇到\0为止,它不会以整个字符数组的大小来访问;

13.printf(“%d\n”,strlen(&arr+1))

解:随机值;字符数组后的内存空间我们不知道具体存放内容

14.printf(“%d\n”,strlen(&arr[0]+1))

解:&arr[0]+1是b的地址,从第二个字符往后统计字符串的长度,大小是5

如果换成指针形式呢?

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("11  %d\n", strlen(p[0]));
  printf("12  %d\n", strlen(&p));
  printf("13  %d\n", strlen(&p + 1));
  printf("14  %d\n", sizeof(&p[0] + 1));

                                       

解析:

char *p = “abcdef”//把字符串首地址放到指针p里;

 

1.printf(“%d\n”,sizeof(p));

解:p是指针变量,大小就是4/8字节

2.printf(“%d\n”,sizeof(p+1));

解:计算第二个元素地址大小,4/8

3.printf(“%d\n”,sizeof(*p));

解:计算第一个元素大小,1

4.printf(“%d\n”,sizeof(p[0]));

解:计算第一个元素大小,1

5.printf(“%d\n”,sizeof(&p));

解:&p是二级指针,是指针大小就是4/8

6.printf(“%d\n”,sizeof(&p+1));

解:计算二级指针+1后的地址大小,4/8

7.printf(“%d\n”,sizeof(&p[0]+1));

解:计算第二个元素地址大小,4/8

8.printf(“%d\n”,strlen(p));

解:大小为6;p是指针,存放的是字符串首元素的地址,传参给strlen的是首元素的地址,strlen函数就会找到第一个元素,并从第一个元素向后扫描,直到遇到\0后结束;

9.printf(“%d\n”,strlen(p+1));

解:大小为5;p+1表示的是字符串第二个元素的地址,strlen会找到第二个元素,并从第二个元素开始扫描,直到遇见\0为止;

10.printf(“%d\n”,strlen(*p));

解:报错;*p表示对指针解引用,就是访问地址里所指向的数值,即此时的值是字符’a’,,而a字符在内存中是以ASCLL码存放,为数值97 ,而strlen接收到这个数值“97”后,会把它当初一个地址,去访问内存中97处的数值,此时编译器就会报错,我们也不知道97地址处存放的是啥;

11.printf("%d\n", strlen(p[0]));err - 同上一个

12.printf("%d\n", strlen(&p));//&p拿到的是p这个指针变量的起始地址,从这里开始求字符串长度完全是随机值

13.printf("%d\n", strlen(&p + 1));//&p+1是跳过p变量的地址,从这里开始求字符串长度也是随机值

14.printf("%d\n", strlen(&p[0] + 1));//&p[0] + 1是b的地址,从b的地址向后数字符串的长度是5

三.二维数组笔试题解析

首先我们来复习一下二维数组:

a数组名除了那两种情况,都表示第一行的地址,类型为数组指针类型,所以a+1表示第二行的地址,如果我们对他解引用(或者[]),此时的*a(a[0])就是指针指向的数组的首元素地址,类型为int类型,所以我们所说的a[0]+1指的是第一行第二列的地址。

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));  
  a - int (*)[4]
  a+1--> int(*)[4]
  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));
  *a -- *(a+0)--a[0]
  printf("%d\n", sizeof(a[3]));//16字节 int[4]

解析:

二维数组

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

1.printf("%d\n", sizeof(a));a为数组名,表示整个数组,48 = 3*4*4

2.printf("%d\n", sizeof(a[0][0]));第一个元素,四个字节

3.printf("%d\n", sizeof(a[0]));//a[0]是第一行的数组名,数组名单独放在sizeof内部,计算的就是数组(第一行)的大小,16个字节

4.printf("%d\n", sizeof(a[0] + 1));//a[0]作为第一行的数组名,没有单独放在sizeof内部,没有取地址,表示的就是数组首元素的地址,那就是a[0][0]的地址,a[0]+1就是第一行第二个元素的地址,是地址就是4/8个字节

5.printf("%d\n", sizeof(*(a[0] + 1)));//*(a[0] + 1)是第一行第2个元素,计算的是元素的大小-4个字节

6.printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,数组名表示首元素的地址,就是第一行的地址,a+1就是第二行的地址,第二行的地址也是地址,是地址就是4/8    

   a - int (*)[4]

   a+1--> int(*)[4]

7.printf("%d\n", sizeof(*(a + 1)));//a+1是第二行的地址,*(a+1)表示的就是第二行,*(a+1)--a[1]  //16

8.printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址,&a[0]+1是第二行的地址,地址的大小就是4/8

9.printf("%d\n", sizeof(*(&a[0] + 1)));//*(&a[0] + 1) 是对第二行的地址解引用,得到的就是第二行,计算的就是第二行的大小4/8

10.printf("%d\n", sizeof(*a));//a表示首元素的地址,就是第一行的地址,*a就是第一行,计算的就是第一行的大小

   *a -- *(a+0)--a[0]

11.printf("%d\n", sizeof(a[3]));//16字节 int[4]

   16;a[3]其实是第四行的地址(如果存在的话),其实在内存中并不存在a[3],但是sizeof并不会计算表达式的值,它也会通过表达的类型计算它所占空间大小;我们知道,一个表达式:int a= 3+5;a有两个属性,一个值属性:8,一个类型属性:int,而size of()是计算变量所占空间大小,即表达式的类型所占空间大小,它并不会计算表达式的值。

四.总结:

       通过这些题目,我们对数组和指针有了更深入的了解,其实说白了就是理解清楚变量的类型,然后知道数组名在不同情况下的区别就可以轻松做出。

       辛苦各位小伙伴们动动小手,三连走一波 最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

目录
相关文章
|
4天前
|
存储 NoSQL Java
【面试宝藏】Redis 常见面试题解析
Redis 是内存数据结构存储系统,用作数据库、缓存和消息中间件,支持字符串、哈希、列表等数据类型。它的优点包括高性能、原子操作、持久化和复制。相比 Memcached,Redis 提供数据持久化、丰富数据结构和发布/订阅功能。Redis 采用单线程模型,但通过 I/O 多路复用处理高并发。常见的面试问题涉及持久化机制、过期键删除、回收策略、集群和客户端等。
23 4
|
4天前
|
存储 关系型数据库 MySQL
【面试宝藏】MySQL 面试题解析
MySQL面试题解析涵盖数据库范式、权限系统、Binlog格式、存储引擎对比、索引原理及优缺点、锁类型、事务隔离级别等。重点讨论了InnoDB与MyISAM的区别,如事务支持、外键和锁机制。此外,还提到了Unix时间戳与MySQL日期时间的转换,以及创建索引的策略。
17 4
|
13天前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
4天前
|
存储 异构计算 内存技术
【硬件工程师面试宝典】常见面试题其一
- Setup时间:时钟前数据需稳定的最小时间。 - Hold时间:时钟后数据需保持稳定的时间。 - 竞争现象:不同路径信号汇合导致输出不稳定。 - 冒险现象:竞争引起的短暂错误状态。 - D触发器实现2倍分频电路。
19 5
|
4天前
【硬件工程师面试宝典】常见面试题其二
检查单片机上电不运行:电源电压、时钟信号、复位电路、程序烧录。三极管特性:输出特性曲线和转移特性曲线。频率响应指系统对不同频率信号的响应,稳定要求幅度和相位不变。改变响应曲线方法:调整反馈、使用滤波器、改变元件参数。差分运放相位补偿通过在反馈回路加电容,波特图显示补偿效果。基本放大电路类型有共射、共集、共基,差分结构用于抗干扰和提高共模抑制比。电阻电容串联,电容电压为低通滤波,电阻电压为高通滤波。选择电阻考虑阻值、功率、温度系数、精度和尺寸。CMOS电路传递低电平用N管。电流偏置电路通过R1、Q1产生稳定电流。施密特电路回差电压由R1、R2决定。LC振荡器的哈特莱、科尔皮兹、克拉
10 0
|
4天前
|
存储 缓存 NoSQL
【面试宝藏】Redis 常见面试题解析其二
Redis 高级面试题涵盖了哈希槽机制、集群的主从复制、数据丢失可能性、复制机制、最大节点数、数据库选择、连通性测试、事务操作、过期时间和内存优化等。Redis 使用哈希槽实现数据分布,主从复制保障高可用,异步复制可能导致写操作丢失。集群最大支持1000个节点,仅允许单数据库。可通过 `ping` 命令测试连接,使用 `EXPIRE` 设置过期时间,`MULTI/EXEC` 等进行事务处理。内存优化包括合理数据类型、设置过期时间及淘汰策略。Redis 可用作缓存、会话存储、排行榜等场景,使用 `SCAN` 查找特定前缀键,列表实现异步队列,分布式锁则通过 `SET` 命令和 Lua 脚本实现。
19 5
|
4天前
|
负载均衡 算法 Java
【面试宝藏】Go语言运行时机制面试题
探索Go语言运行时,了解goroutine的轻量级并发及GMP模型,包括G(协程)、M(线程)和P(处理器)。GMP调度涉及Work Stealing和Hand Off机制,实现负载均衡。文章还讨论了从协作到基于信号的抢占式调度,以及GC的三色标记算法和写屏障技术。理解这些概念有助于优化Go程序性能。
23 4
|
5天前
|
存储 安全 Java
【面试宝藏】Go基础面试题其一
Go语言(Golang)结合C的性能和Python的易用性,具有简单语法、高效并发、自动垃圾回收等优点。它支持基本和派生数据类型,通过包进行代码管理。类型转换需显式进行,如将整数转为浮点数。Goroutine是轻量级线程,通过channel进行并发同步。Go接口可嵌套,同步锁用于控制并发访问。Channel提供类型安全的通信,注意避免死锁。Go Convey用于测试,`new`和`make`分别用于值类型和引用类型的初始化。了解这些,有助于更好地掌握Go语言。
12 2
|
5天前
|
存储 缓存 算法
【面试宝藏】Go并发编程面试题
探索Go语言并发编程,涉及Mutex、RWMutex、Cond、WaitGroup和原子操作。Mutex有正常和饥饿模式,允许可选自旋优化。RWMutex支持多个读取者并发,写入者独占。Cond提供goroutine间的同步,WaitGroup等待任务完成。原子操作保证多线程环境中的数据完整性,sync.Pool优化对象复用。了解这些,能提升并发性能。
11 2
|
6天前
|
数据采集 算法 数据挖掘
LeetCode 题目 80:删除排序数组中的重复项 II【算法面试高频题】
LeetCode 题目 80:删除排序数组中的重复项 II【算法面试高频题】