<笔试题>指针

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 目录1、笔试题1:2、笔试题2:3、笔试题3:4、笔试题4:5、笔试题5:6、笔试题6:7、笔试题7:8、笔试题8:

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;
}
//程序的结果是什么?

image.png

  • 解析:image.png*(ptr - 1) :

&a表示取出整个数组的地址,&a+1就跳过整个数组,&a的类型:int(*)[5],&a+1的类型还是int(*)[5],将&a+1强制类型转换为int*,赋给ptr,则ptr指向的就是&a+1的地址,ptr-1即为前一个元素的地址,再解引用*(ptr-1)拿到的就是5。


*(a + 1):

a表示数组名为首元素1的地址,+1表示元素2的地址,再解引用*(a+1)就是2。


2、笔试题2:

#include<stdio.h>
struct Test
{
  int Num;
  char* pcName;
  short sDate;
  char cha[2];
  short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
  printf("%p\n", p + 0x1);
  printf("%p\n", (unsigned long)p + 0x1);
  printf("%p\n", (unsigned int*)p + 0x1);
  printf("%x\n", p + 0x1);
  printf("%x\n", (unsigned long)p + 0x1);
  printf("%x\n", (unsigned int*)p + 0x1);
    //%p以地址的形式打印,不省略0
    //%x就是打印16进制,省略0
  return 0;
}

image.png解析:

p+0x1:

整形指针(int*)+1跳过4个字节,字符指针(char*)+1跳过1个字节,结构体指针p+1应该跳过一个结构体大小,也就是20字节,20的16进制是0x000014,加完后是0x100014。


(unsigned long)p + 0x1:

p本来是个结构体指针,把p强转成unsigned long类型,就是将变成无符号整型,就不再是指针了,既然是无符号整型,那就当成一个数字,加1后就直接加就行了,即0x100001


(unsigned int*)p + 0x1:

p被强制类型转换成整型指针,整型指针+1跳过4个字节,加4即为0x100004


3、笔试题3:

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

image.png

  • 解析:
  • ptr1[-1]:image.png&a取出的是数组的地址,&a+1跳过整个数组,将其强制类型转换为int*赋给ptr1,此时ptr1的地址就是&a+1,而ptr[-1]相当于*(ptr1-1),ptr1-1的地址如图所示,再解引用拿到的就是4。
  • *ptr2:image.png数组名a表示首元素地址,将其强制类型转化为整型,就是一个值,加1就是加了1个字节,需要将内存化为以字节为单位的数据,元素1就是4个字节,如果是小端,假设a的地址0x10,转成10进制就是16,加1就是17,16进制为0x11,找到ptr2的地址了,再解引用就只需再往后访问4个字节即可,打印出来即为2000000。过程如图所示


4、笔试题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;
}

image.png

  • 解析:image.png
  • 此题有坑,考到了逗号表达式,int a[3][2] = { (0, 1), (2, 3), (4, 5) };这句代码可以转化为int a[3][2] = { 1, 2, 5 };此数组为3行2列,a[0]是第一行的数组名,数组名表示首元素地址,a[0]代表第一行第一个元素的地址,也就是p指向的位置,p[0] = *(p+0) = *p,p解引用拿到的就是1。

5、笔试题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;
}

image.png

  • 解析:image.png &a[4][2]:

&a[4][2]表示第5行第3列的地址,如图所示。


&p[4][2]:

p是一个数组指针,p能够指向的数组是4个元素,p+1跳过4个整型,就是16个字节,p[4][2] --->*(*(p+4)+2),a是该数组数组名,即为首元素地址,将a赋给p,p也指向该地址,如图所示。p+1跳过4个元素的数组,+4的位置如图所示,*(p+4)向后找到4个元素,如黄色框框所示*(p+4),*(p+4)+2跳过2个元素指向的位置如图,再解引用,拿到的就是该元素。


&p[4][2] - &a[4][2]两个整型的地址相减拿到的就是中间的元素个数为4,因为小地址减大地址,所以%d的形式打印就是-4

而%p的形式打印就是打印地址,只是打印补码即可

-4的补码:1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1100


换成16进制打印就是FFFF FFFF FFFF FFFC

6、笔试题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;
}

image.png

  • 解析:
  • *(ptr1 - 1):image.png&aa表示二维数组的地址,&aa+1表示跳过整个二维数组到如图所示的位置,强转成整型指针赋给ptr1,ptr1-1的地址即如图所示,再解引用拿到的就是数字10。


*(ptr2 - 1):

aa为数组名表示二维数组首元素第一行的地址,aa+1跳过第一行来到第二行如图所示,再解引用*(aa+1)拿到第二行数组名首元素地址,即元素6的地址,强转赋给ptr2,ptr2-1向前移动再解引用拿到的就是5。

7、笔试题7:

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

image.png

  • 解析:image.png pa的类型是char*,加1表示跳过了一个char*的元素,指向如图所示位置,再解引用*pa拿到a的地址,再%s向后访问到\0停止。即为at。

8、笔试题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);
  printf("%s\n", *-- * ++cpp + 3);
  printf("%s\n", *cpp[-2] + 3);
  printf("%s\n", cpp[-1][-1] + 1);
  return 0;
}

image.png

  • 解析:
  • **++cpp:image.png ++cpp跳过了一个char**元素的地址到如图所示位置,解引用*++cpp拿到了c+2这个元素,c+2又是c里第3个元素的地址,再解引用拿到了p的地址,以%s的形式打印直到\0为止,即POINT。
  • *-- * ++cpp + 3:image.png++cpp再跳过一个char*的元素到图示位置,再解引用 * ++cpp拿到c+1,-- * ++cpp让c+1-1=c,此时c就是c数组名第一个元素地址,再解引用*-- * ++cpp拿到E的地址,再+3指向第二个E,再%s打印处ER。
  • *cpp[-2] + 3:image.png  *cpp[-2]就是**(cpp-2)+3。cpp-2指向的位置如图所示,解引用*(cpp-2)拿到c+3,再解引用**(cpp-2)拿到F的地址,再+3指向S,再%s打印出ST。
  • cpp[-1][-1] + 1:image.png cpp[-1][-1] + 1就是*(*(cpp-1)-1)+1,cpp-1的位置如图,解引用拿到c+2,减1就是c+1,再解引用*(*(cpp-1)-1)拿到的就是N的地址,再加1指向E,%s打印出EW。
相关文章
|
5月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
6月前
|
存储 编译器 C语言
C语言初阶⑦(指针初阶)知识点+笔试题(上)
C语言初阶⑦(指针初阶)知识点+笔试题
39 0
|
5月前
|
存储 C++
有关【指针运算】的经典笔试题
有关【指针运算】的经典笔试题
31 4
指针与数组笔试题解析
指针与数组笔试题解析
|
6月前
|
C语言
C语言进阶⑫(指针下)(指针和数组笔试题解析)(杨氏矩阵)(上)
C语言进阶⑫(指针下)(指针和数组笔试题解析)(杨氏矩阵)
41 0
|
6月前
指针笔试题模拟
指针笔试题模拟
30 0
|
6月前
进阶指针笔试题
进阶指针笔试题
34 0
|
6月前
|
算法 C语言
C语言进阶⑫(指针下)(指针和数组笔试题解析)(杨氏矩阵)(下)
C语言进阶⑫(指针下)(指针和数组笔试题解析)(杨氏矩阵)
27 0
|
6月前
|
C语言
C语言进阶⑫(指针下)(指针和数组笔试题解析)(杨氏矩阵)(中)
C语言进阶⑫(指针下)(指针和数组笔试题解析)(杨氏矩阵)
36 0
|
6月前
|
存储 编译器 C语言
C语言初阶⑦(指针初阶)知识点+笔试题(下)
C语言初阶⑦(指针初阶)知识点+笔试题
44 0