指针面试笔试题练习

简介: 指针面试笔试题练习

笔试题1


题目1:


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


答案:


运行结果:


2,5


文字解释1:


a是数组名,类型为int[5],则&a类型为int(*)[5],当&a+1时,一次会跳过5个整形数据,则指向a数组的最后一个元素的后一个位置,ptr - 1刚好指向a数组的最后一个元素,解引用(星号)就会得到整形数字5.


a+1表示数组的第二个元素,所以解引用得到整形数字2.


图解1:



笔试题2


不了解指针运算的可以点击这里哦!


[传送门]


考点:指针+1,跳过的步长


题目2:


#include <stdio.h>
//已知结构体Test的大小是20字节
struct Test
{
  int Num;
  char* pcName;
  short sDate;
  char cha[2];
  short sBa[4];
}*p;
int main()
{
  p = (struct Test*)0x100000;//假设p 的值为0x100000。
  printf("%p\n", p + 0x1);//0x100020
  printf("%p\n", (unsigned long)p + 0x1);//0x10
  printf("%p\n", (unsigned int*)p + 0x1);
  return 0;
}


运行结果:


00100014


00100001


00100004


文字解释2:


p + 0x1:


因为p是一个结构体指针,结构体的大小是20个字节,所以p+0x1会跳过20个字节,20转化为16进制表示是14.


(unsigned long)p + 0x1:


这里需要注意的是,这里将p强制转化为无符号长整形,并不是无符号长整形指针,所以,+0x1只是正常的+1,就好比1+1=2,就只是变量之间的正常+1.


(unsigned int*)p + 0x1


将p指针强制转化为无符号整形指针,因为无符号整形是四个字节,则+0x1会跳过四个字节,转化为16进制4.


笔试题3


题目3:


环境:x86 小端环境


#include <stdio.h>
int main()
{
  int a[4] = { 1, 2, 3, 4 };
  int* ptr1 = (int*)(&a + 1);
  int* ptr2 = (int*)((int)a + 1);
  printf("%x,%x", ptr1[-1], *ptr2);
  return 0;
}


运行结果:


4,2000000


文字解释3:


ptr1


因为&a + 1表示跳过a数组,指向a数组最后一个元素的后一个位置.


ptr1[-1]等价于 *(ptr-1),即解引用得到数组的最后一个元素4.


ptr2:需要注意的是,向后偏移了一个字节.


(int)a + 1,表示将a强制转化为int整形,整形+1就是正常的+1,则会向后偏移一个字节,


(int*)((int)a + 1)再强制转化为整形指针,在小端存储模式下,会从首元素1(占四个字节)的第二个字节开始,向后读取四个字节(红色框框).这时按16进制打印出来就是2000000了.


图解3:



笔试题4


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


运行结果:


1


文字解释4:


是不是感觉很奇怪,不应该是0吗?


a[0]表示二维数组的第一行的数组名,那么p[0]就等价于a[0][0],就是0呀.


实际本题考察重点是在逗号表达式.


? ? ?


这才是二维数组的初始化:用的是{}


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


而上面用的是(),则编译器会认为是逗号表达式,只保留后面的结果.


等价于:


int a[3][2] = { (0, 1), (2, 3), (4, 5) }; ====== int a[3][2] = { 1, 3, 5 };


故二维数组的初始化结果是


1 3


5 0


0 0


第一行第一个元素是1.做题要仔细哦,掉坑里了.


笔试题5


题目:


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


运行结果:


FFFFFFFC,-4


文字解释5:


a是二维数组的数组名,类型是int ()[5],一次跳过五个整形


p是一个数组指针,类型是int()[4],一次跳过四个整形,


a[4][2]与p[4][2]之间差了4个字节,即&p[4][2] - &a[4][2]=-4;


-4按"%p"形式打印.会认为内存中的数据是内存.-4在内存中是按补码存的.


-4


1000 0000 0000 0000 0000 0000 0000 0100原码


1111 1111 1111 1111 1111 1111 1111 1011反码


1111 1111 1111 1111 1111 1111 1111 1100补码


转化为16进制表示地址后:F F F F F F F C


图解5:



笔试题6


题目:


#include <stdio.h>
int main()
{
  int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  int* ptr1 = (int*)(&aa + 1);
  int* ptr2 = (int*)(*(aa + 1));
  printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
  return 0;
}


解释:


看图理解方便(偷个懒)


图解6:



笔试题7


题目:


#include <stdio.h>
int main()
{
  char* a[] = { "work","at","alibaba" };
  char** pa = a;
  pa++;
  printf("%s\n", *pa);
  return 0;
}


运行结果:


at


解释:


a是一个字符指针,类型是char*,a+1会跳过一个char类型.


pa是一个二级指针,类型是char**,pa+1会跳过一个char*.即指向数组的第二行,%s从该地址处向后打印直到遇到’\0’.


动图解析:



笔试题8(难度提升)


#include <stdio.h>
int main()
{
  char* c[] = { "ENTER","NEW","POINT","FIRST" };
  char** cp[] = { c + 3,c + 2,c + 1,c };
  char*** cpp = cp;
  printf("%s\n", **++cpp);      //1
  printf("%s\n", *-- * ++cpp + 3);  //2
  printf("%s\n", *cpp[-2] + 3);   //3
  printf("%s\n", cpp[-1][-1] + 1);  //4
  return 0;
}


运行结果:


POINT


ER


ST


EW


解释分析:


需要注意的是,当进行自增(++)或者自减(–)时,会真正改变指针的值,从而影响后面的语句.而加减整数或者访问元素([ ])并不会改变指针本身.并不会对后面的语句造成影响.


c是一个字符指针,+1会跳过一个字符(1字节).


cp是一个指向一级字符指针的二级指针,+1可以跳过一个char*类型指针.


cpp是一个指向cp的三级指针,+1会跳过一个二级指针.


分析1: ** ++cpp


原始状态图:



++cpp会跳过一个二级指针,并且是真正改变cpp指针的内容,


即cpp会指向cp的第二个元素,c+2


*++cpp表示得到c+2的地址


**++cpp表示得到c+2的值,即P的地址,按%s打印会得到,POINT.


分步动态图解1:



分析2:*-- * ++cpp + 3


注意!!!


cpp由于1的改变,现在指向的是c+2.


原始图2:



++cpp会使cpp指向c+1(cp的第二个元素).


*++cpp得到c+1的地址


- - *++cpp表示c+1的地址–,会会指向c


*-- * ++cpp 会得到c的地址


*-- * ++cpp + 3表示指向E


按%s打印会打印ER.


分步动态图解2:



分析3:*cpp[-2] + 3


注意!!!


因为2的改变,此时cpp指向的是c+1.


图三原始图:



cpp[-2]等价于*(cpp-2),表示访问cpp指向的元素,往前找两个位置,即cp的第一个元素,c+3,


*cpp[-2]解引用得到c+3的地址.


*cpp[-2] + 3,表示指向c+3的第3个字符.


按%s打印,结果为ST


分步动态图解3:



分析4:cpp[-1][-1] + 1


注意!!!


3只是[-2]访问,并没有改变cpp本身.


原始图四:(与图三一样)



cpp[-1]等价于*(cpp-1),表示访问cpp指向的内容的前一个,即c+2(cp的第二个元素).


cpp[-1][-1]表示访问c+2地址的前一个,即N地址处.


cpp[-1][-1] + 1表示从N地址的下一个地址,E开始.


按%s打印是EW


分步动态图解4:



目录
相关文章
|
6月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
7月前
|
C语言
C语言指针——练习
C语言指针——练习
|
2月前
|
编译器 C语言
经典左旋,指针面试题
文章介绍了两种C语言实现字符串左旋的方法,以及如何使用C语言对整数数组进行奇偶数排序。通过实例演示了如何使用函数reverse_part和leftRound,以及在swap_arr中实现数组元素的重新排列。
32 0
|
2月前
|
Serverless 编译器 C语言
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
|
6月前
|
存储 C++
有关【指针运算】的经典笔试题
有关【指针运算】的经典笔试题
38 4
指针与数组笔试题解析
指针与数组笔试题解析
|
6月前
|
C++
指针习题练习
指针习题练习
27 0
|
7月前
指针笔试题模拟
指针笔试题模拟
34 0
|
7月前
进阶指针笔试题
进阶指针笔试题
37 0
|
7月前
|
编译器 程序员 C语言
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题(下)
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题
54 0

热门文章

最新文章