当前位置: 首页 > article >正文

数组,指针 易混题解析(二)

目录

一.基础

1.

2.

二.中等

1. 坑

2.

3.指针+1到底加什么

三.偏难

1.(小端   x86)

2.通过数组指针进行偏移的时候怎么偏移

3. 大BOSS

(1)**++cpp

(2)*-- * ++cpp + 3

(3)*cpp[-2] + 3

(4)cpp[-1][-1] + 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;
}

&a 是整个数组的地址,类型:int (*)[5]     &a+1 的类型还是 int (*)[5]

存到 int * 类型的指针 ptr 中,要强制类型转换。

   答案:2 5

2.

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  是整个数组的地址

*(aa+1) 等价于 aa[1] 是第二行的数组名,是第二行第一个元素的地址。

   答案:5 10

二.中等

1. 坑

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

坑:二维数组内部分行的时候,要用 {  } 。  这里的 ( )是3个逗号表达式。

所以题目等价于:

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

a[0] 是第一行的数组名,是第一行首元素的地址。     p[0] 等价于 * (p + 0)

   答案:1

2.

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

这里的 char* * pa  ,第二个 * 告诉我 pa 是指针 ,指向的是 char* 类型的元素 

这里的 a 是数组名,首元素的地址,传给 pa 。pa++ 后, pa 指向 a 第二个空间的地址。

*pa 解引用,a 第二个空间放的是  (char * 类型)'a' 的地址。从这里开始打印,直至 \0

   答案:at

3.指针+1到底加什么

指针+1,+的是指针指向对象的大小。

//由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设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;
}

1. p 是结构体指针,+1,+的就是一个结构体大小。+20 之后为 0x00100014

2. p 被强制转换为整型,p 里面的值被强制转换为整数。+1 结果为 0x00100001

3. p 是整型指针,整型指针+1,跳过1个整型。整型4字节。 结果为:0x00100004

三.偏难

1.(小端   x86)

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);
    // %x :以16进制打印
	return 0;
}

ptr1[-1] 是 *(ptr1 - 1)

注意:指针+1,+的是指针指向对象的大小。

a 是数组首元素的地址,假设为 0x0012ff40  被强制转换为 int (不是指针)。+1后为:0x0012ff41

再被转换为 int * 整型指针 ptr2。

但是,一个整型是4个字节,0x0012ff41 之加了一个字节,ptr2 并不指向 2 所在的地址

找到 ptr2 所指向的位置,再向后访问4个字节

答案:4 ,2000000

2.通过数组指针进行偏移的时候怎么偏移

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

p是指向4个整型的数组指针。对 指针 p+1,跳过4个整型

p 的类型:int (*)[4]         a 的类型:int (*)[5]

p[4][2]  ---  *(*(p+4)+2)

指针-指针,结果是中间元素个数。大-小为正,小-大为负。所以题目中相减结果为 -4

-4 用 %d 打印还是 -4              用 %p 打印:

-4
原码:10000000000000000000000000000100
反码:11111111111111111111111111111011
补码:11111111111111111111111111111100

-4 在内存中以补码形式存放,用 %p 打印时,就认为11111111111111111111111111111100是地址。

地址不存在什么原反补。类似于16进制打印:0x ff ff ff fc

3. 大BOSS

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

(1)**++cpp

cpp 里面存放的是 char** 的地址。++跳过一个 char** 的数据

**++cpp 最终拿到 POINT 里面 P 的地址

结果:POINT

(2)*-- * ++cpp + 3

先 ++cpp ,解引用。--  给里面的值自减1,修改了这块地址。再解引用。+3 后,指向 E 的地址。

结果:ER

(3)*cpp[-2] + 3

cpp[-2]  ----  * (cpp - 2)                   整个表达式转换:** (cpp - 2) + 3

结果:ST

(4)cpp[-1][-1] + 1

转换:* (* (cpp - 1) - 1) + 1

* (cpp - 1) - 1  这个表达式拿到的值是 c + 1  。不改变里面的值

结果:EW

本篇的分享就到这里了,感谢观看,如果对你有帮助,别忘了点赞+收藏+关注

小编会以自己学习过程中遇到的问题为素材,持续为您推送文章。


http://www.kler.cn/a/598018.html

相关文章:

  • golang Error的一些坑
  • 唯品会商品详情页架构设计与实现:高并发场景下的技术实践‌
  • 乘法逆元(快速幂,费马小定理)
  • 常见前端安全问题及解决方案
  • PyJSON5:高效、安全的JSON5处理库
  • Linux-数据结构-哈夫曼树-哈希表-内核链表
  • 【STL】string类
  • 死锁:当程序 “卡住“ 时,发生了什么?
  • wordpress主题使用中常见错误汇总
  • OpenGL实现摄像机(根据鼠标位置放大缩小视图)
  • How to install visual studio code on Linux mint 22
  • 详解内联容器标签<span>的用法
  • 幻影星空亮相CAAPA北京展 引领文旅产业升级转型
  • uniapp从 vue2 项目迁移到 vue3流程
  • 【网络层协议】NAT技术内网穿透
  • 【实战】deepseek数据分类用户评论数据
  • ADC噪声全面分析 -04- 有效噪声带宽简介
  • Tomcat常见漏洞攻略
  • 分布式系统设计陷阱,白话CAP理论
  • 【嵌入式学习2】位运算 - 控制语句