【C进阶】指针笔试题解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【C进阶】指针笔试题解析

做题之前我们再来回顾一下

对于数组名的理解:除了以下两种情况,数组名表示的都是数组首元素的地址

(1)sizeof(数组名):这里的数组名表示整个数组

(2)&(数组名) :这里的数组名也表示整个数组

1.程序的结果是什么?

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

【解析】:

难点:&a+1的含义

&a,数组名和&单独结合,此时的a代表整个数组的地址

+1也就跳过整个数组的地址(&a的类型为数组指针:int (*)【5】)

a指向的是数组首元素

+1也就是指向第二个元素

【图解】:


2.假设p 的值为0x100000。 如下表表达式的值分别为多少?

//已知,结构体Test类型的变量大小是20个字节(32位环境下)

struct Test
{
  int Num;
  char* pcName;
  short sDate;
  char cha[2];
  short sBa[4];
}*p;
int main()
{
  printf("%p\n", p + 0x1);
  printf("%p\n", (unsigned long)p + 0x1);
  printf("%p\n", (unsigned int*)p + 0x1);
  return 0;
}

【答案】:

10000014

10000001

10000004

【解析】:

结构体的最后*p表示:定义了一个struct类型的指针变量p

%p表示:以地址的形式打印

eg:32位打印出来也就是00 00 00 00(前面的0不会省,就是打印出8位

%x表示:以十六进制的形式打印(和%p不一样,最前面的0会省略

(1)结构体指针+1,表示跳过整个结构体,因为结构体的大小为20个字节,那么就是地址+20

,0x十六进制表示0x10000014(14表示的十六进制也就是十进制的20)

%p形式打印也就是10 00 00 14

(2)指针类型变为unsigned long正常数值类型(要注意这里不再是指针类型)

正常数值+1也就是10 00 00 01

%p形式打印也就是10 00 00 01

(3)struct类型的指针变为unsigned int*类型的指针

int类型指针+1,表示跳过一个int类型,也就是跳过4个字节

%p形式打印也就是10 00 00 04


3.程序的结果是什么?

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

【解析】:

(1)&a,数组名和&单独结合,此时的a代表整个数组的地址

+1也就跳过整个数组的地址(&a的类型为数组指针:int (*)【4】)

再强转为int *类型,ptr1[-1]==*(ptr1-1),也就是4

(2)难点:怎么理解(int*)((int)a + 1) (简单来说就是数值+1转为地址+1个字节)

a单独代表数组首元素,强转为int类型,再+1也就是数值+1

eg:假设a的地址是0x0012ff40(十进制也就是1244992)

那么a+1也就是0x0012ff41(十进制1244993)

我们发现就是多了一个字节(内存中一个地址对应一个字节)

在vs编译器中,数值在内存中是小端存储,那么a数组从低地址到高地址存储就是

01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00(注意不要写成了10 00 00 00)

a变为数值+1也就是+一个字节,再把加一个字节后的a当作一个地址,那么a也就是跳过了一个字节,指向了01后面的00位置,即ptr2指向了01后面的00位置

int *ptr2解引用也就访问4个字节,也就是00 00 00 02这4个字节

转化为数值也就是0x02 00 00 00,那么以%x打印也就是2000000


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

【解析】:

难点:数组定义的括号不是{ },而是()

{   {   }, {  }  }中里面的{  }表示:数组初始化的行列元素

{   (  ), (  )}中的( )表示:逗号表示式

第一行逗号表达式计算完也就是int a[3][2] = { 1, 3, 5 };

那么p【0】==*(p+0)也就是数组的第一个元素1


5.程序的结果是什么?

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

【解析】:

一个元素为4的数组指针指向一个5行5列的二维数组,也就是将这个数组每4个元素放一块,看图解(实际上二维数组也是连续存放的,但是为了便于理解,还是画成了行和列)

指针-指针得到的是两个指针之间的元素个数

&p[4][2] - &a[4][2]也就是-4

&d打印就直接打印数值-4

对于%p打印地址,在内存中存储的补码就是地址(fffc)

原码:1000 0000 0000 0000 0000 0000 0000 0100

反码:1111 1111 1111 1111 1111 1111 1111 1011

补码:1111 1111 1111 1111 1111 1111 1111 1100

转为十六进制也就是F F F F F F C


6.程序的结果是什么?

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

【答案】:

10,5

【解析】:

(1)&aa是二维数组地址,&aa+1跳过整个二维数组,元素10后面的地址

ptr1-1是元素10的地址,*(ptr1-1)是元素10

(2)aa是二维数组名,是第一行一维数组地址

aa+1跳过第一行数组,到第二行数组地址

*(aa + 1)是第二行的首元素地址

ptr2 - 1是元素5的地址,*(ptr2 - 1)是元素5


7.程序的结果是什么?

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

【答案】:

at

【解析】:

a是一个指针数组,里面存放了元素的地址

pa指针变量指向了a数组的第一个元素(第一个字符串)

二级指针pa++也就是跳过一个a【0】

那么pa就指向了a【1】(也就是第二个字符串)

二级指针char **pa怎么理解:

*pa这里的*表示pa为指针

char *代表pa指向的对象类型为char *类型


8.程序的结果是什么?

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

【答案】:

POINT

ER

ST

EW

【解析】:

(1)cpp+1指向cp的第二个元素,

一次解引用找到c+2

两次解引用找到的就是POINT

(2)cpp再次++指向cp的第三个元素

注意:这里cpp++是接着上次的位置继续++

一次解引用找到c+1

c+1再--得到c(数值--)

c再第二次解引用找到ENTER的首地址

再+3跳过3个字节指向E的地址

最后从这个地址开始打印

(3)*cpp[-2] ==**(cpp-2) (这里是相当于,但是cpp并没有-2)

cpp-2指向cp的第一个元素,

一次解引用找到c+3

两次解引用找到的就是FIRST

再+3,跳过3个字节指针指向S的地址

最后从这个地址开始打印

(4)cpp[-1][-1]==*(*(cpp-1)-1)

cpp-1指向cp的第二个元素

一次解引用找到c+2

(c+2)-1得到c+1

第二次解引用找到的就是NEW中N的地址

再+1跳过一个字节,指向E

最后从这个地址开始打印


本次内容就到此啦,欢迎评论区或者私信交流,觉得笔者写的还可以,或者自己有些许收获的,麻烦铁汁们动动小手,给俺来个一键三连,万分感谢 !


目录
相关文章
|
6月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
2月前
|
Serverless 编译器 C语言
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
|
4月前
|
SQL 存储 算法
【数据挖掘】恒生金融有限公司2023届秋招数据ETL工程师笔试题解析
恒生科技2022年9月24号数据ETL工程师岗位的笔试题目及答案汇总,包括了SQL选择题、SQL编程题和业务应用SQL编程题,涵盖了数据库基础知识、SQL语句编写以及数据仓库概念等多个方面。
63 2
【数据挖掘】恒生金融有限公司2023届秋招数据ETL工程师笔试题解析
|
4月前
|
机器学习/深度学习 自然语言处理 算法
【数据挖掘】2020奇安信秋招算法方向试卷1 笔试题解析
2020年奇安信秋招算法方向试卷1的题目解析,覆盖了数据结构、机器学习、深度学习、自然语言处理、排序算法、激活函数、主题模型、采样方法、图像处理等多个领域的知识点。
53 1
【数据挖掘】2020奇安信秋招算法方向试卷1 笔试题解析
|
4月前
|
机器学习/深度学习 存储 算法
【数据挖掘】2020奇安信秋招算法方向试卷3 笔试题解析
2020年奇安信秋招算法方向试卷3的题目解析,涵盖了数据结构、机器学习、深度学习、自然语言处理、排序算法、激活函数、PCA、词嵌入库等多个领域的知识点。
63 1
【数据挖掘】2020奇安信秋招算法方向试卷3 笔试题解析
|
6月前
|
存储 C++
有关【指针运算】的经典笔试题
有关【指针运算】的经典笔试题
34 4
|
6月前
|
C++ 存储 Java
C++ 引用和指针:内存地址、创建方法及应用解析
'markdown'C++ 中的引用是现有变量的别名,用 `&` 创建。例如:`string &meal = food;`。指针通过 `&` 获取变量内存地址,用 `*` 创建。指针变量存储地址,如 `string *ptr = &food;`。引用不可为空且不可变,指针可为空且可变,适用于动态内存和复杂数据结构。两者在函数参数传递和效率提升方面各有优势。 ```
|
2月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
32 0
|
3月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
106 4

推荐镜像

更多