C语言之指针笔试题解析(上)

160 阅读6分钟

指针对于不少人来说:是多么一个难的代名词呀!!当然这个里面也包括笔者!所以……笔者对于指针满满的后怕!但是也有着更多的期待!毕竟阴影是用来打破的!后怕打破了,也就是龙腾虎跃的时候了!!下面进入正题:

笔者将用代码+解析的方式来带领大家走进:指针!!

解析题1.

#include <stdio.h>
int main()
{
	int a[5] = { 1,2,3,4,5 };
	int* ptr = (int*)(&a + 1);
	printf("%d %d\n", *(a + 1), *(ptr - 1));   //2   5
	return 0;
}

注意,笔者的代码是在vs2022 的x86环境下进行演示的!请注意细节,若是在vs2022的x64环境下,将会出现不一样的结果!但那个结果也是正确的!

181be3a2d6e1495e97389c909d3cea7f.png 若是有老铁能直接看懂,并且能够跟答案对上号,那么这篇博客,这位老铁就没有看的必要了,下面内容主要是对上面的代码的讲解!并不做其他的内容!但若是有兴趣,可以进一步欣赏! 下面进入讲解部分:

1.由上述的代码,我们可以知道: int (p)[5]=&a; 指针类型为: int ()[5] 是一个数组指针!!

即 &a+1的类型仍为:int (*)[5] ;所以进行(int *)强制类型转化,若不进行强制类型转化,则会出现警告!即ptr指向:数组后面的第一个元素!对于ptr-1则指向元素5的位置!

cabec78354cb4daca088adb3bc7fe1c7.png 2。在a+1中:数组名,是数组的首元素的地址!即元素1的地址,数组名a+1,跳过一个元素,即:指向元素2的地址!在进行解引用(*)得到元素2!

c5dd358a7fbf471991e6bf62b3afadd6.png 因此,代码的运行结果为:

7d46f0f11f934defb922c05c4218bcaa.png 解析题2. (考察的为指针(+ -)加减整数的问题!)

struct test
{
	int num;
	char* pcname;
	short spate;
	char ch[2];
	short sba[5];
}*p;
 
int main()
{
	p = (struct test*)0x100000;
	printf("%p\n", p + 0x1);   //0x1就是十六进制下的1    //00100018
 
	printf("%p\n", (unsigned long)p + 0x1);           //00100001
 
	printf("%p\n", (unsigned int*)p + 0x1);            //00100004
 
	return 0;
}

对于上述的结构体!由于不少人目前,没有接触到结构体大小的计算方法,所以,笔者人为的提供该结构体的大小:20个字节!!(对于结构体大小略微感兴趣的老铁,敬请关注笔者博客,将会更新!)

1.在结构体中,定义的全局变量*p,因此,p是一个结构体指针变量!在x86的环境下进行演示!

2.p的值为0x100000 为十六进制int类型!赋值给结构体,则需要强制类型转化即: p = (struct test*)0x100000;

3.p+0x1 :—》p+1 ;指针+1,到底加的是几??这个就是要取决于指针的类型!!

p为结构体指针,则p+1需要跳过一个结构体(20个字节)!即 0x100000 (十六进制)+20(十进制),再将所得的结果,转化为:十六进制!!即结果为:0x100014!

4.(unsigned long)p + 0x1 : p是一个结构体指针类型!(unsigned long)p 将p强制类型转化为:unsigned long型,p里面本来放一个数值,而将p强制类型转化为:(unsigned long)整型,整型+1 :即:0x100001

5.(unsigned int*)p + 0x1 : 不管p是什么类型,现在将p强制类型转化为:unsigned int* 类型的指针类型,即:p转化完成后,指向一个无符号的整型(4个字节)!整型指针+1,跳过4个字节!即:0x100004

因此,代码的运行结果为:

ad39aa7be3484684851fc5add867e96b.png 此题到此结束,那么,跟着笔者步伐走进接下来的题目吧!!!

#include <stdio.h>
int main()
{
	int a[4] = { 1,2,3,4 };
	int* ptr = (int*)(&a + 1);
	int* ptr2 = (int*)(int)(a + 1);
	printf("%x %x\n", ptr[-1], *ptr2);  //4    2
	return 0;
}

注意,笔者的代码是在vs2022 的x86环境下进行演示的!请注意细节,若是在vs2022的x64环境下,将会出现不一样的结果!但那个结果也是正确的!

06fd2e9dd4f94021981c8bf92975a4ad.png 若是有老铁能直接看懂,并且能够跟答案对上号,那么这篇博客,这位老铁就没有看的必要了,下面内容主要是对上面的代码的讲解!并不做其他的内容!但若是有兴趣,可以进一步欣赏! 下面进入讲解部分:

对于:%p :打印地址!

%x : 以十六进制形式进行打印! 1.(int*)(&a + 1) : &a取出的是这个数组的地址,&a+1,跳过整个数组,通过int* ptr = (int*)(&a + 1); 赋值给ptr1; 即ptr1 yu &a+1指向同一位置!

608091f982c94128b758acc83edf203e.png 2. (int*)(int)(a + 1) : a是这个数组的数组名,数组名表示首元素的地址!(int)a 是指,a被强制类型转化为:int(整型)!!假设:起始地址为:0x00000015(方便计算),将其转化为整型:116的一次幂+516的零次幂=21;(int)a+1—》21+1=22;(int*)(int)(a + 1) 再将22认为是一个地址,转化为(int*)类型,地址22为:0x00000016;而0x00000015与0x00000016之间相差一个字节!一个字节一个地址!

a5a59f798b3043dcbdbbab37a530940c.png 3. 假设在VS中是小端存储模式(其实在vs2022中是小端存储)!

数组元素随着下标的变化,由地址到高地址变化!

1的十六进制为:0x00000001;

2的十六进制为:0x00000002;

小端存储模式,(倒着存):低地址放在低地址处!高地址放在高地址处!

int 类型占4个字节!对于数组:int a[4] = { 1,2,3,4 };

6592a2d1c9cc47cfa72b44843c0f0b00.png 对于:int* ptr = (int*)(&a + 1) : &a+1之后,强制类型转换为:(int *)整型指针!

对于:int* ptr2 = (int*)(int)(a + 1) : a是一个数组名,表示首元素的地址!

a的类型为:本来应该为:int *类型,而通过 :(int)(a + 1) 跳过一个字节!即00000002!从而打印出来!!

从而代码的运行结果为:

8397456e048e4a69ad8409ffb040f0e9.png 由于笔者最近精神不佳!简简单单的一道题!目前已经讲解完毕!接下来,笔者将会给大家,讲解一些 :指针笔试题解析!来供大家参考!!!