指针试题合集

指针试题合集



前言

关于一部分指针的笔试题;向着星辰与深渊!


一、题目

题目一:

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int *ptr = (int *)(&a + 1);
    printf( "%d,%d", *(a + 1), *(ptr - 1));
    return 0;
}
//程序的结果是什么?

数组名:表示首元素地址;但有两种例外;
sizeof(数组名):这里表示计算整个数组的大小,数组名表示整个数组地址;
&数组名:取出整个数组的地址

首先*(a + 1)a是首元素地址,a+1是第二个元素地址解引用后是2;
题目中&a,取出整个数组的地址,加1跳过一个数组的大小,
&a+1的地址放入int* ptr,指针类型决定了操作权限,-1只能减一个int类型,所以指向5;

在这里插入图片描述

答案

2 5

题目二:

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);
 printf("%p\n", (unsigned long)p + 0x1);
 printf("%p\n", (unsigned int*)p + 0x1);
 return 0;
}

p是变量,类型是结构体指针;
已知结构体类型变量类型是20字节;
p = 0x100000;
加1为跳过20字节,16进制20为14;
p + 0x1 = 0x100014;
unsigned long 无符号整形 p是0x100000,看做无符号整形加1后0x100001;
unsigned int* 是四个字节 0x100004

答案

0x100014
0x100001
0x100004

题目三:

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

(&a+1)跳过一个数组大小,操作权限是int ,*(ptr1+(-1))所以000004,前面0不会打印;
a是首元素地址,把首元素地址看为int,+1就是原值+1,在看做int*时,便是增加一个字节大小,又因为小端存储0x02000000,但是02前面的0不会显示;
在这里插入图片描述

答案

42000000

题目四:

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

这里看似和前几题相似,实则不然,如果把这个数组看成了

                              0 1
                              2 3 
                              4 5

那就大错特错了

int a[3][2] = { {0, 1}, {2, 3}, {4, 5} };//这样初始化才这样
int a[3][2] = { (0, 1), (2, 3), (4, 5) };//看清楚这是小括号,是逗号表达式

实际上的初始化

                              1 3
                              4 0
                              0 0

a[0]是第一行元素, p[0] = 1

答案

1

题目五:

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

我们先来分析一下下面代码是什么类型?

int(*p)[4]

首先,p先和*相结合,所以这是个指针,是指向存放int型的有四个元素的数组的指针;
二维数组在内存中存放的其实是连续的,a是首元素地址;
指针的元素的类型,及确定了操作权限;
指针减指针代表的是元数个数;
在这里插入图片描述
如图显示,我们可以看到相差4个元素;
%p打印地址,%d按十进制输出
按%d打印-4;
在内存中存储的是补码,
原码:0000 0000 0000 0000 0000 0000 0000 0100
反码:1111 1111 1111 1111 1111 1111 1111 1011
补码:1111 1111 1111 1111 1111 1111 1111 1100
当地址打印时将补码看做地址输出,以16进制输出
FFFF FFFC

答案

FFFFFFFC,-4

题目六:

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

&aa的取出的是整个数组的地址,跳过整个二维数组;

*(ptr1-1) = 10

aa是首元素地址,而二维数组的首元素是第一行元素,加1,跳过一行,ptr1操作一个整形。

*(ptr2-1) = 5;

答案

10,5

题目七:

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

char* a[]是数组,存放的是char*类型
在这里插入图片描述
所以,at

答案

at

题目八:

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

先分析内存中布局是如何的?
在这里插入图片描述
首先:*++cppcpp+1后解引用
在这里插入图片描述
结果为POINT

*--*++cpp+3

先自增,解引用后–,在解引用后+3

在这里插入图片描述
找到ER

*cpp[-2]+3

等价于*(cpp+(-2))+3
在这里插入图片描述
找到ST

cpp[-1][-1]+1

等价于*(*(cpp+(-1))+(-1))+1
在这里插入图片描述
找到EW

答案

POINT
ER
ST
EW

总结

指针的坑,非常多,有限令人意想不到,就拿题目四来说,数组初始化用了逗号表达式,如果想都没想,那必然……;所以仔细分析,画图是个好方法。向着星辰与深渊!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值