0


八道C语言指针笔试题——拿捏指针

第一题

//请问输出什么?
#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;
    return 0;
}

分析:

我们有必要搞清楚整形指针 ptr 是什么来头。

这个图我们可以明显看到 &a+1 之后指向哪个位置。我们要注意的是,我们有 & 这个取地址符号,即代表我们取出的是整个数组的地址,所以是一个数组指针类型的地址。再通过强制类型转换得到整型指针 ptr 。

*(a+1),不难理解得到数组的第二个元素,即 2 。

***(ptr-1),同样也不难理解,得到数组的第五个元素,即 5 。**


**故本题输出为: 2,5 **

第二题

#include <stdio.h>

//这里告知结构体大小为20个字节
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;
}

分析:

注意我们的程序,定义了一个全局结构体指针变量 p ,那么这个指针变量的值默认初始化为0。

** 那么 p+0x1 就可以理解为:指向结构体指针 p 向后移动一个结构体大小的地址。**


那就应该得到答案: p+0x1 = 20 ,需要注意的是,打印格式为 %p 。

这里普及一下:%p 是以地址的形式来打印数字的。

那么 (unsigned long)p+0x1 更简单了,即把结构体指针变量转化为无符号长整型数字了,数学上如何计算加法,那么这里就怎么计算加法,所以这里输出 1 。

对于(unsigned int)p+0x1 ,就是把结构体指针变量强制类型转换为了无符号整型指针了,那么整型指针+1,无非就是向后跨越4(整型大小)个字节。故答案为 4 。*

一定要注意是以 %p 形式打印的。

第三题

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

分析:

*整型指针 ptr1 与第一题类似,只不过输出的时候 将 (a-1) 写为了 a[-1] 。

重点是如何理解整型指针 ptr2 ,假设我们的机器是小端存储模式,那么数组在内存中的存储形式应该是这样:

题目将数组首元素地址强转为了整型变量并+1,即指针变成了数字+1,再将其强转为整型指针。现在我们假设数组首元素的地址为 0 ,即a的地址为0,那么有:

通过这个图,就可以明显看出 ptr2 内存放的是 a+1 的地址,但因其是整型指针,所以它会包括四个字节:

** **

那么输出结果为:

需要注意,本题若是使用比较高版本的VS编译器,需要再x86环境下才能正常输出结果。

第四题

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

分析:

这个题的重点在于逗号表达式。

一定要注意,数组中经过逗号表达式运算后,存储的应该是:

内存布局应该是:

整型指针 p 等于 a[0] ,a[0] 是指针操作的简写,那么完整的指针形式为:*(*(a+0)+0) ,即二维数组的第一个数组元素的第一个元素 ,即 1 。

第五题

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

分析:

这个题乍一看是又一些难度的,那我们仔细分析:

二维数组的大小为 55 ,但数组指针指向的数组大小为 n4 ,并且把二维数组的数组名赋给了指针p,这就导致了指针 p 与数组 a 的类型不同,但数据的存放顺序都是一样的。

我们来看图:

明显直观地看到 p[4][2] 与 a[4][2] 之间相差四个元素,正巧的是,指针相减得到的正是两个指针中间的元素个数。那么 p[4][2] - a[4][2] 得到的就是 -4 。

但是,-4 是个负数,而%p是一个无符号的格式,所以-4的原反补为:

-4存储在内存中的是补码,那么以 %d 形式打印的话,会将补码翻译成原码,打印:-4

以 %p 打印的话,是以无符号形式打印的,所以会直接以无符号十六进制打印补码。

故输出为:

第六题

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

分析:

整型指针变量 ptr1 想必不用多说,打印的结果也就为 10 。

对于整型指针变量 ptr2 ,(aa+1),找到的也就是二维数组的第二个数组元素的首元素地址,所以前面的强制类型转换是为了混淆我们的。*

那么 ptr2 也就保存元素 6 的地址,这个地址 -1 得到 5 的地址,所以输出5。

第七题

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

分析:

这段代码非常简单。

首先是一个指针数组,指针数组里面放的是三个字符串常量(字符串常量不做介绍了),二级指针 pa 放的是数组名,即首元素地址,通过 pa++ 得到了第二个元素的地址,故打印 at 。

第八题

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

分析:

我们先看一副关系图

** 那么 ++cpp ,我们按照运算符优先级来分析:

++cpp:

****++cpp:**

** **

所以这里输出:POINT ,并且要注意,++cpp 可以表示为 cpp=cpp+1,也就是说,cpp的值是改变了的。

*我们来看 --++cpp+3 如何分析:*

++cpp:

** ++cpp得到 c+1 ,--++cpp 得到 c**


** --++cpp得到:**

即得到 ENTER 的首元素地址。

***--*cpp+3得到 E 的地址,往后打印即为 ER**。

*我们再看如何理解 cpp[-2]+3 ,这个表达式可以化为: ((cpp-2))+3

*那么 (cpp-2) 得到 c+3:

((cpp-2))为:

** 即得到 F的地址。**

((cpp-2))+3即为 S 的地址,故打印 ST。

** 对于cpp[-1][-1]+1 这个表达式可以化为 ((cpp-1)-1)+1**

则*(*(cpp-1)-1)表示为:

** 即得到 N 的地址,那么 ((cpp-1)-1)+1 得到 E的地址 ,向后打印得 EW 。**

标签: c语言 蓝桥杯 c++

本文转载自: https://blog.csdn.net/weixin_59913110/article/details/125278431
版权归原作者 龙兆万 所有, 如有侵权,请联系我们删除。

“八道C语言指针笔试题&mdash;&mdash;拿捏指针”的评论:

还没有评论