C语言篇 + 指针笔试题

C语言篇 + 指针笔试题_第1张图片

目录

  • 前言
  • 进入主题

前言

学过了指针相关的知识就得再加以巩固基础,今天分享的几道题希望对你能有所帮助,觉得有所收获的话也可以点个小爱心

进入主题

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
分析:(int *)(&a + 1); 可以拆解为 &a + 1,取出的是整个数组的地址 + 1跳过的是一个数组,&a + 1的类型是 int( * )[4],为了赋值给ptr1从而进行了一个强制类型转换,将int( * )[4]类型强转为 int *,最后再赋值给ptr1,此时的ptr1指向的是&a + 1处的地址,ptr1是一个指针,指针变量的步长取决于它的实际类型,int *步长是4字节,ptr1[-1]可以看成 *(ptr1 + (-1)),指针向前跳过4字节,从原来的&a + 1地址处跳到了ptr[-1]地址处,指向的是04这个字节,以%x的形式打印打印的就是4
C语言篇 + 指针笔试题_第2张图片
再看看 int *ptr2 = (int *)((int)a + 1);,数组名是首元素的地址假设地址是0x00d5fbcc,而这个地址只负责管理一个字节,将地址强制型转换为一个整形,对应的10进制数:14023628,14023628 + 1 = 14023629 ,再将这个+ 1后的结果数强制类型转换为一个指针 ( 指针地址:0x00d5fbcd) 得到的是一个新的地址也是管理一个字节(有没有发现这个地址只是0x00d5fbcc + 1后得到的结果),最后将他赋值给int * ptr2,这个指针的类型是int *它能够访问四个字节的空间 00 00 00 02 ,当然在内存中是以小端存储的,当把数据还原出来的时候(低位放在低地址处,高位放在高地址处)就是02 00 00 00,以%x的形式打印出来的时候就是2000000C语言篇 + 指针笔试题_第3张图片

#include 
int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    int *p;
    p = a[0];
    printf( "%d", p[0]);
 return 0; }

答案:1
分析:
这是一个三行二列的二维数组在内存中的存储顺序是这样子的,
(0,1),(2,3)(4,5),并不是将这6个数全部都存储进去,注意看,()里的是一个逗号表达式,在数组初始化的时候也要记住这点,逗号表达式的优先级是最低的所以只会存放逗号表达式之后的数字,当1 、3、5被存放在数组中后其他的位置都被默认初始化为0,而指针指向的是数组首元素的地址 p[0] == >*(p + 0),访问的是数组首元素 1
C语言篇 + 指针笔试题_第4张图片
C语言篇 + 指针笔试题_第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
分析:p是一个数组指针类型是int( * )[4],p + 1会跳过四个整形(指针的步长跟指针的类型有关),p[4][2] 等价于 ==> * ( * (p + 4) + 2),从内存图中可以看出它们之间是差了四个字节的,
C语言篇 + 指针笔试题_第6张图片
低地址减高地址得到的结果是一个-4,以%p 和 %d的形式打印结果截然不同,%d打印有符号的整数,会通过补码计算出原码最后将结果打印,而%p是以地址的形式打印出来的结果,将-4的补码以16进制的形式显示出来,所以打印的结果是 :FFFFFFFC -4
C语言篇 + 指针笔试题_第7张图片
在这里插入图片描述

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、(int )((aa + 1));,aa+1是跳过二维数组的一行,来到第二行的地址处,
2、(&aa + 1);是跳过整个二维数组
相对简单的一题,一图胜过千言万语,就不过多解释了C语言篇 + 指针笔试题_第8张图片

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

答案:atC语言篇 + 指针笔试题_第9张图片> 从图中可以看到数组a是一个指针数组,那么指针数组中的每一个元素类型都是char*,他都指向着字符串的起始地址,而将a赋值给pa是将数组首元素的地址(char * )存放到一个二级指针(char** )中去,pa++等价于a[1]等价于*(a + 1),而此时的指针指向的是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; }

先来看一下它们之间的存放关系,脑海里先有个印象,不至于被绕晕
C语言篇 + 指针笔试题_第10张图片
C语言篇 + 指针笔试题_第11张图片

这两张图的指针间的关系都是一样的,读者觉得哪个适合自己就看哪个

梳理一下它们之间的关系:
1、c和cp是一个指针数组,数组c中的每一个元素都是char*,而数组cp的每一个元素都是char**,
2、在图中我们可以看出数组cp中存放了数组c的元素(二级指针存放一级指针),
3、而cpp指针变量又指向了数组cp注意cpp是一个三级指针变量,(三级指针变量存放二级指针),存放的是数组名为cp的首元素的指针(char**)

printf("%s\n", **++cpp);

首先来拆解这句代码,**++cpp可以看作*(*(++cpp))
cpp这个三级指针自增跳过一个char * *类型的步长,指向的是数组cp下标为1的位置,解引用找到了p[1]里面存放的二级指针变量,对二级指针变量解引用找到的是一级指针,这个指针变量指向的是字符串POINT的地址,%s打印就是POINT

 printf("%s\n", *--*++cpp+3);

这句代码也可以拆解,* (–(* (++cpp))) + 3,先看括号最里面的同样的++cpp跳个一个类型为char**的元素,此时的指针变量指向的是数组名为cp下标为2的位置,对指针解引用找到了cp[2]位置的二级指针,而这个指针指向的是数组名为C下标为1位置的指针变量,对一级指针变量–,此时的指针变量指向了C[0]的位置处,也就是ENTER字符串的首字符地址,再+3,char*类型的指针变量就指向了E这个字符,%s打印就是ER

 printf("%s\n", *cpp[-2]+3);

cpp[-2]+3 同样也可以拆解成 * ( * ( cpp + (-2))) + 3
等价于 * ( * ( cpp - 2) ) + 3,
cpp-2,char
**类型的指针变量指向了数组名为cp下标为0的位置,对指针解引用找到了char **类型的指针变量,而这个指针变量指向了数组名为c下标为3位置的一级指针,再对char *指针解引用找到了FIRST字符串的首地址,地址+3,指针指向了S字符的位置,打印出来就是ST

printf("%s\n", cpp[-1][-1]+1);

分析最后一组cpp[-1][-1]+1,依然可以继续拆分成
*( *(cpp - 1) - 1) + 1,cpp-1后指针变量指向的是数组名为CP下标位置为1的元素地址,对这个二级指针解引用后找到的是char *类型的指针变量,而这个指针变量,它指向的是数组名为c下标为2的位置处,再对指针变量-1,此时指向的时数组名为c下标为1位置的元素,在对指针解引用后取出来的时NEW字符串的首字符地址,最后+1指针指向了E这个字符,%s打印出来就是EW
C语言篇 + 指针笔试题_第12张图片

本次的讲解就到这里了,希望分享的题目能够加深你对指针变量的理解,谢谢大家
C语言篇 + 指针笔试题_第13张图片

你可能感兴趣的:(c语言,c语言,c#)