【C语言】指针笔试题2
C语言学习
指针基础
友情链接:C语言专栏
文章目录
- C语言学习
- 前言:
- 指针笔试题
- 笔试题1
- 笔试题2
- 笔试题3
- 笔试题4
- 笔试题5
- 笔试题6
- 笔试题7
- 笔试题8
- 总结:
- 附录
- 上文链接
- 专栏
前言:
继上文【C语言】指针笔试题1,此篇文章是指针学习的最终章,笔试题详解。建议对指针有了深入理解再来食用。
指针笔试题
笔试题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;
}
输出
解析:
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int* ptr = (int*)(&a + 1); //&a为数组指针,&a + 1则跳过整个数组,//即此时指向数组最后一个元素(5)的后面//(int*)(&a + 1)又将它强制类型转化为int*的指针printf("%d,%d", *(a + 1), *(ptr - 1));//a数组名首元素地址,a + 1则为的第二个元素地址,// *(a + 1)解引用则为2;//ptr为int*的指针,指向数组最后一个元素(5)的后面,//ptr - 1则指针向后退4个字节(因为指针为int*),指向数组最后一个元素,//*解引用则为5;return 0;
}
笔试题2
代码:
//这里直接告诉大家结构体Test类型的变量大小是20个字节
struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p;
//假设p 的值为0x0。 如下表表达式的值分别为多少?
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}
输出(都为16进制):
解释:
int main()
{printf("%p\n", p + 0x1);//p + 0x1,跳过一个结构体大小,故为0x14(16进制);printf("%p\n", (unsigned long)p + 0x1);//(unsigned long)p,将p强制类型转化为无符号长整形,//(unsigned long)p + 0x1则为0x1;printf("%p\n", (unsigned int*)p + 0x1);//(unsigned int*)p将结构体指针强制类型转换为无符号整型指针,//且unsigned int为4个字节,整数运算://所以(unsigned int*)p + 0x1则跳过四个字节,故为0x4return 0;
}
笔试题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;
}
输出:
解释:
int main()
{int a[4] = { 1, 2, 3, 4 };int* ptr1 = (int*)(&a + 1); //&a数组地址,//&a + 1数组指针跳过整个数组,即指向数组最后一个元素的后面//(int*)(&a + 1)强制类型转换,将数组指针转化为(int*)类型的指针;//即ptr1为指向数组最后一个元素后面int*指针int* ptr2 = (int*)((int)a + 1);//下面画图解释printf("%x\n", ptr1[-1]);printf("%x\n", *ptr2); //下面画图解释//ptr1[-1]可以转换为*(ptr-1),//ptr - 1,ptr为int*指针,-1则为向后退4个字节,指向数组最后一个元素;//故输出为4;return 0;
}
咱们主要来分析一下这两行代码(干货哦!!!):
int* ptr2 = (int*)((int)a + 1);printf("%x\n", *ptr2);
在此之前,咱们要对大小端字节序了解,可以看我关于【数据的存储】(由于数据的存储是在此篇博客后面的,所以未附上链接)的介绍。
假设咱们是小端字节序,则数组中元素存储是这样的:
了解了这个,来分析一下代码:
(int)a
:a是数组首元素地址,(int)a是将a强制类型转化为int型的数据;
((int)a + 1)
:假设a是0x1000,(int)a + 1此时为整数运算则为0x1001,
(int*)((int)a + 1)
:又将(int)a + 1强制类型转化为int型的指针,那它此时指向哪里呢,看图
a指针指向示意图:
(int)((int)a + 1)指针指向示意图:
那对于*ptr2
怎么理解呢?
因为ptr2是int型的指针,所以解引用访问四个字节,有因为咱们是小端字节序,所以它是从从ptr2指针指向的位置起(0x1001)向后访问4个字节(int)内容,即为*ptr2
图示:
16进制则为0x02000000;
当然,咱们也可以试试大端字节序的情况下是什么样的。
笔试题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;
}
输出:
解释:
#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };//重点在这://(0, 1)逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。//即数组可写为int a[3][2] = { 1, 3, 5 };后面默认为0;int* p;p = a[0];//a[0]为第一行的数组名//数组名为首元素地址//即p=&a[0][0]printf("%d", p[0]);//p[0]可以这样看*(p+0);//故为1;return 0;
}
笔试题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;
}
输出:
解释:
int main()
{int a[5][5];int(*p)[4];//一维数组指针p = a;//首先,咱们先对p与a的类型进行分析:// p是int(*)[4];a是int(*p)[5];这个是要明白的,然后分析代码;// 对于a与p他俩的区别是什么呢://a + 1 会跳过 5 * sizeof(int) 字节(通常 20 字节)//p + 1 会跳过 4 * sizeof(int) 字节(通常 16 字节)printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;
}
首先,先来看数组a的示意图:
咱们先来看a[4][2]
所在的位置,很简单:
那来看看p[4][2]
:
将两者放一起:
那么对于&p[4][2] - &a[4][2]
,即指针相减,得到的是两个指针之间的元素,为-4;
对于%d
形式的输出,就为-4;
但对于%p形式的输出呢?
解释:
- %p 用于打印指针(内存地址),而内存地址本质上是无符号整数。
- -4 的二进制补码:0xFFFFFFFC(即 11111111 11111111 11111111 11111100)。
- 当 -4 被当作指针(无符号数)时,它会被解释为 0xFFFFFFFC。也可以说,%p不管内存中存储的是什么,它只会原样输出存储的二进制(因为无符号数“补码”的概念)。
笔试题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;
}
输出:
解释:
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int* ptr1 = (int*)(&aa + 1);//&aa取出整个数组的地址//&aa+1跳过整个数组,指向数组最后一个元素的后面//(int*)(&aa + 1)将数组指针强制类型转化为int*类型的//即ptr1是一个int*的指针,且指向数组最后一个元素的后面int* ptr2 = (int*)(*(aa + 1));//aa二维数组的数组名是第一行的地址,类型为int(*)[5]//aa + 1第二行地址,类型为int(*)[5]//*(aa + 1),可以这样写aa[1]//即数组第二行元素,为一维数组//一维数组数组名是首元素地址//首元素地址类型为int*//(int*)(),多余//即ptr2指向数组第二行第一个元素printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//*(ptr1 - 1)数组最后一个元素10;//*(ptr2 - 1)数组第一行最后一个元素5return 0;
}
笔试题7
看代码:
#include <stdio.h>
int main()
{char* a[] = { "work","at","alibaba" };char** pa = a;pa++;printf("%s\n", *pa);return 0;
}
输出:
解释:
#include <stdio.h>
int main()
{char* a[] = { "work","at","alibaba" };//对字符指针数组进行解释://它是将三个字符串的首元素地址存储在数组中char** pa = a;//a 是数组名,在大多数表达式中会退化为指向首元素的指针,即 pa 为 &a[0](类型是 char**)。//pa 存储的是 a[0] 的地址(即 &a[0])pa++;//pa 原本指向 a[0],pa++ 后指向 a[1](即 &a[1])printf("%s\n", *pa);//*pa 得到 a[1],即 'at' 的首地址,printf 打印这个字符串";return 0;
}
笔试题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;
}
输出:
解释:
int main()
{char* c[] = { "ENTER","NEW","POINT","FIRST" };//数组 c 的每个元素(c[0]、c[1] 等)存储的是指向对应字符串常量的指针://c[0] → 指向 "ENTER" 的首地址(即字符 'E' 的地址)。//c[1] → 指向 "NEW" 的首地址。//c[2] → 指向 "POINT" 的首地址。//c[3] → 指向 "FIRST" 的首地址。char** cp[] = { c + 3,c + 2,c + 1,c };//c数组名为首元素地址,即&c[0];//c + 3 → 指向c[3] cp[0]//c + 2 → 指向c[2] cp[1]//c + 1 → 指向c[1] cp[2]//c → 指向c[0] cp[3]char*** cpp = cp;//cp数组名为首元素地址,即&cp[0];//cpp → 指向cp[0]//搞清楚上面这部分,就很简单了//注意:++cpp会产生副作用,会使得cpp改变printf("%s\n", **++cpp);//++cpp → 指向cp[1];//*++cpp 为cp[1]是c + 2 → 指向c[2];//**++cpp 为c[2];//则输出为"POINT"printf("%s\n", *-- * ++cpp + 3);//注意操作符优先级//++cpp → 指向cp[2];//* ++cpp为cp[2] → 指向c[1]//-- * ++cpp → 指向c[0]//*-- * ++cpp 为c[0] → 指向 "ENTER" 的首地址//*-- * ++cpp + 3 → 指向 "ENTER" 的'E'的地址//则输出为"ER"printf("%s\n", *cpp[-2] + 3);//由于此时cpp → 指向cp[2]//cpp[-2]等效为*(cpp-2)//cpp-2 → 指向cp[0]//*(cpp-2)即为cp[0];//*(cp[0])即为c[3] → 指向 "FIRST" 的首地址。//+ 3 → 指向 "FIRST" 的'S'的地址//则输出为"ST"printf("%s\n", cpp[-1][-1] + 1);//cpp[-1][-1]+1等效为*(*(cpp-1)-1)+1;//先看cpp-1 → 指向cp[1];//*(cpp-1)则为cp[1] → 指向c[2];//*(cpp-1)-1 → 指向c[1];//*(*(cpp-1)-1)则为c[1] → 指向 "NEW" 的首地址。//+1 → 指向 "NEW" 的'E'的地址;//则输出为"EW"return 0;
}
总结:
指针到这就结束了,但我们的学习尚未结束,希望大家对指针都有各自的理解。
谢谢学习至此!!!
附录
上文链接
【C语言】指针基础:为什么说指针是C语言的灵魂?
【C语言】指针进阶1:数组与指针
【C语言】指针进阶2:数组、指针、函数
【C语言】指针笔试题1
专栏
C语言专栏