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

指针运算典型例题解析

1.题目1

该代码运行的结果是什么?

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

解析:

运行结果:

2.题目2

在X86(32位)环境下,假设结构体的大小是20个字节,程序输出的结构是啥?

struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}

解析:

考察的是“指针+-整数”的问题

+0x1就是结构体指针+1,要跳过一个结构体,结构体的大小是20个字节,所以就是+20字节 —— 如果是10进制则是:0x100020,但是现在是16进制,所以是0x100014

p 强制转换为 unsigned long,不是指针类型了,整型值+1,就是+1,所以是0x100001

unsigned int* 强制转换为,无符号整型的指针,+1是跳过一个整型的4个字节,所以是0x100004

运行结果:

3.题目3

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

解析:

调试一下,观察一下a中的内容:

不是:

01
23
45

的原因是因为:

int a[3][2] = { (0, 1), (2, 3), (4, 5) };

不是:

int a[3][2] = { {0, 1}, {2, 3}, {4, 5} };

所以,按照逗号表达式计算括号中保留了:1,3,5. 又因为是3行两列的,所以用 0 补位。

a[0] 是第一行的数组名,数组名表示首元素的地址,其实就是&a[0][0]

p[0] —— *(p + 0)——*p ——  1

运行结果:

4.题目4

假设环境是x86环境,程序输出的结果是啥?

#include <stdio.h>
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;
}

解析:

考察的是指针 - 指针,其结果的绝对值是指针和指针之间的元素个数。

a 是二维数组

p 是数组指针,p 指向的数组是 4 个整型元素的

分析如下:

%d 是打印有符号的整数

%p 是打印地址的

  1. 数组和指针的类型差异

    • a 是一个 int[5][5] 类型的二维数组。
    • p 是一个指向 int[4] 的指针,即每次移动会跳过 4 个 int
  2. 指针运算规则

    • 指针相减的结果是两个地址之间的元素个数,而非字节数。
    • &p[4][2] 相当于 p + 4*4 + 2 = p + 18(跳过 18 个 int)。
    • &a[4][2] 相当于 a + 4*5 + 2 = a + 22(跳过 22 个 int)。
  3. 地址计算

    • 假设 a 的起始地址为 0x0,则:
      • &p[4][2] 的地址为 0x0 + 18*4 = 0x48(每个 int 占 4 字节)。
      • &a[4][2] 的地址为 0x0 + 22*4 = 0x58
    • 地址差值为 0x48 - 0x58 = -0x10(即 - 16 字节),但指针相减结果为 -16 / 4 = -4

运行结果:

5.题目5

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

解析:

12345
678910

*(aa+1)—— aa[1]

aa[1] 是第二行的数组名

数组名表示首元素地址

aa[1] 也是 &aa[1][0]

&aa[1] 第二行的地址

sizeof(aa[1])计算的是第二行的大小

运行结果:

6.题目6

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

解析:

a 是指针数组

a 是 char* 型的

pa 是 char** 型的

*pa 就是解引用是 at

运行结果:

7.题目7

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 是一个字符指针数组,包含 4 个字符串常量的地址。

  • cp 是一个二级指针数组,初始化为 {c+3, c+2, c+1, c}

  • cpp 是一个三级指针,初始指向 cp 的起始位置。

第一次 printf**++cpp

  1. ++cpp 使 cpp 指向 cp[1](即 c+2)。

  2. *cpp 解引用得到 c+2

  3. **cpp 进一步解引用得到 c[2],即字符串 "POINT"

输出POINT

第二次 printf*--*++cpp+3

  1. ++cpp 使 cpp 指向 cp[2](即 c+1)。

  2. *cpp 得到 c+1

  3. --*cpp 将 c+1 减 1,变为 c(即 cp[3] 的原始值)。

  4. *--*cpp 解引用得到 c[0](字符串 "ENTER")。

  5. +3 跳过前 3 个字符,指向 "ER"

输出ER

第三次 printf*cpp[-2]+3

  1. cpp[-2] 等价于 *(cpp-2),指向 cp[0](即 c+3)。

  2. *cpp[-2] 解引用得到 c[3](字符串 "FIRST")。

  3. +3 跳过前 3 个字符,指向 "ST"

输出ST

第四次 printfcpp[-1][-1]+1

  1. cpp[-1] 指向 cp[1](即 c+2)。

  2. cpp[-1][-1] 等价于 *((c+2)-1),即 c[1](字符串 "NEW")。

  3. +1 跳过首字符,指向 "EW"

输出EW

关键注意点:

  • 指针运算直接修改了 cpp 和 cp 中的值(如 --*cpp)。

  • 下标访问(如 cpp[-2])基于当前 cpp 的位置计算。

  • 字符串偏移(如 +3)从字符串起始位置向后跳过指定字符数。

运行结果:

http://www.xdnf.cn/news/5234.html

相关文章:

  • IOC和Bean
  • 【读书笔记】《编码:隐匿在计算机软硬件背后的语言》01 逻辑与开关
  • Android方法耗时监控插件开发
  • Java 基础面试题
  • 自定义类型-结构体(一)
  • 【Rust】枚举和模式匹配
  • 2025年数维杯赛题C题专家 组委会C题专家疑集锦
  • 5.8线性动态规划2
  • SpringMVC-执行流程
  • 40、C# 数组、链表、哈希、队列、栈数据结构的特点、优点和缺点
  • AI:生成对抗网络(GAN)
  • 【Vue】vuex的getters mapState mapGetters mapMutations mapActions的使用
  • yocto的大致工作流程
  • CSS渲染性能优化
  • MySQL进阶篇2_SQL优化、锁
  • 探索 JWT(JSON Web Token):原理、结构与实践应用对比
  • RK3568-OpenHarmony(1) : OpenHarmony 5.1的编译
  • C# 使用 WinUI 3 项目模板创建桌面应用程序
  • 在 Kubernetes 中使用 Docker 实现 GPU 支持的完整方案
  • Ubuntu 与 Windows 双系统环境下 NTFS 分区挂载教程
  • 添加物体.
  • 2025年5月15日前 免费考试了! Oracle AI 矢量搜索专业​​认证
  • 用jsp简单实现C语言标准化测试系统
  • (2025)图文解锁RAG从原理到实操
  • DeepSeek:开启物流行业创新变革新时代
  • 高效Python开发:uv包管理器全面解析
  • LeetCode热题100 两数之和
  • SAN 对抗网络搜索,搜索—智能编程—仙盟创梦IDE
  • 手机银行怎么打印流水账单(已解决)
  • vue访问后端接口,实现用户注册