*指针笔试题*带你进一步了解指针的使用

总结一部分指针面试题,让我们一起看看指针的使用细节。
运行环境VS2013 32位下测试

1.

源代码:

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

运行结果:
在这里插入图片描述
讲解:

首先我们回顾下数组名的概念:
数组名是数组首元素的地址。(有两个例外)

  1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数 组。

  2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。

(1)*(a + 1) :数组名表示数组的首元素地址,+1表示数组的第二个元素即地址,再对其解引用得到数组的第二个元素2
等价于a【1】。
(2)int *ptr = (int *)(&a + 1); //&a表示整个数组,数组+1表示越过整个数组
如图:在这里插入图片描述
*(ptr - 1) : (ptr-1)即指针向后移动四个字节,再对其解引用得到数组的第4个元素5

2.

#include<stdio.h>
#include<windows.h>
struct Test
{
    
    
	int Num;
	char *pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//由于部分未学习结构体,这里我们告知结构体大小为20字节。
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
    
    
	p = (struct Test*)0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
讲解:

注意:%p的意思为读取地址
(1)p + 0x1 :p表示整个结构体,0x1=1,即p+1,表示越过整个结构体,结构体大小为20个字节,转换为十六进制为0x00000014,p=0x001000000
p+0x1=0x00100014 以%p读取结果为00100014
(2)(unsigned long)p + 0x1 :unsigned long表示强转为整数
在这里插入图片描述
+1即加上数字1为0x00100001再以%p读取为00100001
(3)(unsigned int*)p + 0x1:unsigned int*表示强转为无符号整形
+1即跳过一个无符号整形大小为4,运行结果为00100004

3.

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<windows.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);
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
讲解:

(1)ptr1[-1]:容易理解,&a+1相当于跨过整个数组,-1回到第4个元素的首地址,再以十六进制数打印结果为4
(2)重点来看看*ptr2
int *ptr2 = (int *)((int)a + 1);
我们先了解下数组a在内存中是如何存储的:

在这里插入图片描述
(int *)((int)a + 1)即表示越过一个字节
在这里插入图片描述
再以%x读取即向后读取四个字节结果为20 00 00
(涉及大小端问题)

4.

#include<stdio.h>
#include<windows.h>
int main()
{
    
    
	int a[3][2] = {
    
     (0, 1), (2, 3), (4, 5) };
	int *p;
	p = a[0];
	printf("%d\n", p[0]);
	system("pause");
	return 0;
}

运行结果:

在这里插入图片描述
讲解:

有一个坑:{}和()的不同
这里用的()里面是逗号表达式,逗号表达式的结果为最后一个值,故首元素为1 数组实际的初始化内容为{1,3,5,0,0,0}
我们将()改为{}
数组实际存储的内容是{0,1,2,3,4,5}在这里插入图片描述可以看到首元素的值变为了0。

5.

#include<stdio.h>
#include<windows.h>
int main()
{
    
    
	int a[5][5];
	int(*p)[4];
	p = (int(*)[4])a;
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	system("pause");
	return 0;
}

运行结果:

讲解:

在这里插入图片描述
为了便于理解 我们用画图的方式
可以看到a【4】【2】的位置我们很好找如图 红色 所示
但由于p是一个数组指针,p【4】相当于p+4且每次跳过4个整形,+4即跳过16个整形,得到了一个指向4个int型的数组指针,p【4】【2】即指针向后偏移两个int类型如图 绿色 所示
接下来就好办了 指针相减得到是指针之间的元素个数
以"%d打印得到-4
以"%p打印得到-4的补码FFFFFFFC

6.

#include<stdio.h>
#include<windows.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));
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
讲解:

概念同一维数组
(1)(&aa + 1)表示跨过整个数组,(ptr1 - 1)的输出结果为10。
(2)
(*(aa + 1))表示得到第二个元素的首地址,对于二维数组来说第二个元素即aa【1】【0】, *(ptr2 - 1)得到的是a【0】【4】即5。

7.

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

运行结果:

讲解:

这里是引用
a是一个指针数组,里面存放了三个char※的指针分别指向三个字符串的首地址。 char**pa = a;
定义了一个二级指针pa,将a的首地址放进去,即pa指向上图第一个char*的首地址pa++得到第二个char※的首地址。
再对其解引用得到其里面的内容即字符串“at”中a的地址 再以%s的方式读取得到at

8.

#include<stdio.h>
#include<windows.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);
	system("pause");
	return 0;
}

** 有没有很懵,不要着急,做会这道题,你会对指针有一个更全面的认识**

讲解:

这里是引用

运行结果:
在这里插入图片描述
关于指针的学习到这里就结束了,感觉如何?如果对于指针的指针还有不懂,希望浏览下发博文关于指针的详解~~~大家一起学指针呀!

最全指针讲解及使用你比昨天更懂指针了吗?

猜你喜欢

转载自blog.csdn.net/m0_58103115/article/details/120918812