学C的第二十七天【指针的进阶(三)】-2

简介: 10. 指针笔试题(1). 笔试题一:

10. 指针笔试题

(1). 笔试题一:

838e2a54edb942c892c02ad861c12c37.png

对应代码:

#include <stdio.h>
int main()
{
  int a[5] = { 1, 2, 3, 4, 5 };
  int* ptr = (int*)(&a + 1);
  //&a+1: 跳过该数组后的地址,再强制转化成int*类型,方便后面移动时是4个字节
  printf("%d,%d", *(a + 1), *(ptr - 1));
  //*(a+1): 是数组的第二个元素 -- 2
  //*(ptr-1): ptr刚好在整个数组后,ptr-1后指针在 5 的地址位置,所以解引用后是5
  return 0;
}

(2). 笔试题二:


image.png

对应代码:

#include <stdio.h>
//结构体的大小是20个字节(x86)
struct Test
{
  int Num;
  char* pcName;
  short sDate;
  char cha[2];
  short sBa[4];
}* p = (struct Test*)0x100000;//结构体指针变量
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
  printf("%p\n", p + 0x1); 
  //结构体指针 +1 跳过一个结构体(20个字节)
  //所以 结果 == 0x100000 + 0x14(20的十六进制数)
  //         == 0x100014
  printf("%p\n", (unsigned long)p + 0x1);
  //把原来的结构体指针的类型强制转化为(unsigned long)整数,
  //相当于普通的数值计算,+1 就是 +1
  // 结果 == 0x100000 + 0x1 == 0x100001
  printf("%p\n", (unsigned int*)p + 0x1);
  //转化为无符号整型指针,所以每次跳过4个字节(x86)
  // 结果 == 0x100000 + 0x4 == 0x100004
  return 0;
}

(3). 笔试题三:

image.png

对应代码:

#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);
  //ptr1[-1] 等价于 *(ptr1-1)
  //%x : 以十六进制打印
  return 0;
}

(4). 笔试题四:

image.png

对应代码:

#include <stdio.h>
#include <stdio.h>
int main()
{
  int a[3][2] = { (0, 1), (2, 3), (4, 5) };
  //注:这里用的是(),而不是{},()表达式的结果是最后一个
  //所以a的实际情况是:{1,3,5,0,0,0}
  int* p;
  p = a[0];
  //a[0]是二维数组的第一行第一列的地址,相当于a[0][0]
  printf("%d", p[0]); 
  //p[0] 相当于 *(p+0),即*p -- *a[0][0],解引用后为 1
  return 0;
}

(5). 笔试题五:

image.png

对应代码:

#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]);
  //%d:
  //这里是小地址-大地址,两个相差4,又因为以%d打印
  //所以是 -4 (把补码转换为原码后打印)
  //%p:
  //以 %p 打印的话,就不考虑无符号和有符号了,直接以补码打印:
  //-4是负数,内存中存的是补码:
  //原码:10000000000000000000000000000100
  //反码:11111111111111111111111111111011
  //补码:1111 1111 1111 1111 1111 1111 1111 1100 -- 内存中存储的-4
  //      F  F    F    F    F    F    F    C
  return 0;
}

(6). 笔试题六:

image.png

对应代码:

#include <stdio.h>
int main()
{
  //二维数组:
  int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  //第一行: 1 2 3 4 5      第二行: 6 7 8 9 10
  int* ptr1 = (int*)(&aa + 1);
  //&aa+1:跳过整个二维数组后的当前位置的地址(10后面的位置)
  int* ptr2 = (int*)(*(aa + 1));
  //aa+1:跳过二维数组的首元素(第一行),指向第二行首元素地址
  //*(aa+1) 相当于 *aa[1][0],解引用后拿到第二行的首元素地址(6的位置)
  printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
  //ptr1-1:“10”后面的地址-1,指向了10的地址
  //ptr2-1:“6”的前一个地址,指向5的地址
  return 0;
}

(7). 笔试题七:

image.png

               

对应代码:

#include <stdio.h>
#include <stdio.h>
int main()
{
  char* a[] = { "work","at","alibaba" };
  //相当于用三个字符指针分别存放三个字符串:
  //char* p1 = "work" -- 存放w的地址
  //char* p2 = "at" -- 存放a的地址
  //char* p3 = "alibaba" -- 存放a的地址
  char** pa = a; //存放a的首元素"p1"的地址
  pa++;//指向"p2"的地址
  printf("%s\n", *pa);
  //*pa:解引用指针p2的地址,p2指向"a"的地址,以%s打印为 at
  return 0;
}

(8). 笔试题八:

image.png

网络异常,图片无法展示
|

对应代码:

#include <stdio.h>
int main()
{
  char* c[] = { "ENTER","NEW","POINT","FIRST" };
  //相当于用四个字符指针分别存放四个字符串:
  //(下标为0)char* p1 = "ENTER" -- 存放“E”的地址
  //(下标为1)char* p2 = "NEW" -- 存放“N”的地址
  //(下标为2)char* p3 = "POINT" -- 存放“P”的地址
  //(下标为3)char* p4 = "FIRST" -- 存放“F”的地址
  char** cp[] = { c + 3,c + 2,c + 1,c };
  //相当于用四个二级字符指针分别存放四个一级指针:
  //(下标为0)char** pp1 = c+3 = &p4 -- 存放一级指针p4的地址
  //(下标为1)char** pp2 = c+2 = &p3 -- 存放一级指针p3的地址
  //(下标为2)char** pp3 = c+1 = &p2 -- 存放一级指针p2的地址
  //(下标为3)char** pp4 = c = &p1 -- 存放一级指针p1的地址
  char*** cpp = cp;
  //三级指针存放二级指针cp首元素的地址,即pp1地址
  printf("%s\n", **++cpp);
  //cpp指向pp1地址,++后指向pp2地址,
  //第一次*得到pp2内容:p3的指针(地址)
  //第二次*得到p3内容:“P”的地址
  //所以打印 "POINT"
  //因为++,此时cpp已经指向了pp2,不是pp1
  printf("%s\n", *-- * ++cpp + 3);
  //先进行++,cpp指向pp3
  //再进行第一次*:得到pp3内容 -- p2的指针(地址)
  //再--:p2-1 ,指向p1
  //再进行第二次*:得到p1内容 -- “E”的地址("ENTER")
  //最后进行+3:“E”的地址+3,指向“ENTER”第二个“E”
  //所以打印"ER"
  //因为++,此时cpp已经指向了pp3,不是pp2
  printf("%s\n", *cpp[-2] + 3);
  //cpp[-2] 相当于 *(cpp-2)
  //所以题目可以写成:**(cpp-2)+3
  //先进行 cpp-2 : 从指向pp3转为指向pp1
  //再进行第一次*:得到pp1内容 -- p4的指针(地址)
  //再进行第二次*:得到p4的内容 -- “F”的地址(“FIRST”)
  //最后+3:指向“FIRST”的“S”的地址
  //所以打印“ST”
  //此时cpp还是指向pp3
  printf("%s\n", cpp[-1][-1] + 1);
  //cpp[-1] 相当于 *(cpp-1)
  //所以题目可以转化为:*(cpp-1)[-1]+1
  //再转化:*(*(cpp-1)-1)+1
  //先进行cpp-1:cpp从pp3转为指向pp2
  //再进行*:得到pp2内容 -- p3的指针(地址)
  //再进行-1:p3-1 -- 得到p2的地址
  //再进行*:得到p2的内容 -- “N”的地址(“NEW”)
  //最后+1:指向“NEW”的"E"
  //所以打印“EW”
  return 0;
}

相关文章
|
5月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
5月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
5月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
5月前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
5月前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
5月前
|
搜索推荐
指针进阶(2)
指针进阶(2)
47 4
|
5月前
指针进阶(3)
指针进阶(3)
41 1
|
5月前
|
C++
指针进阶(1)
指针进阶(1)
43 1
|
5月前
|
存储 安全 编译器
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
42 2
|
5月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
49 0