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

E31.【C语言】练习:指针运算习题集(上)

Exercise 1

求下列代码的运行结果

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

答案速查:

分析:

Exercise 2

 求下列代码的运行结果

//在x86环境下
//假设结构体的大小是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;
}

答案速查:

分析:

☑ printf("%p\n", p + 0x1);

出现单个p,代表结构体中首元素的地址,类比&数组名,+0x1跳过整个结构体

十进制20=0x14

即0x100000+0x14==0x100014,x86环境下输出结果为00100014

☑ printf("%p\n", (unsigned long)p + 0x1);

 p被强制类型转换为unsigned long,p不再是struct Test*指针类型(不考虑+0x1跳过整个结构体)即0x100000+0x1=0x100001,x86环境下输出结果为00100011

☑ printf("%p\n", (unsigned int*)p + 0x1);

p被强制类型转换为unsigned long*指针类型,之前讲过,指针+1表示跳过4个字节,即

0x100000+4==0x100004,x86环境下输出结果为00100004

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

答案速查:

分析:

错误思路:

认为二维数组的元素排布是这样的:

在13.5.【C语言】二维数组里讲过:只有这样写int a[3][2] = { {0, 1}, {2, 3}, {4, 5} };内部是大括号不是圆括号)才是上方的排布!

写成这样int a[3][2] = { (0, 1), (2, 3), (4, 5) };内含逗号表达式

在15.【C语言】初识操作符 下里讲过

exp1,exp2,exp3,……,expn

程序从左向右依次执行exp

整个exp的结果是最后一个exp的结果

所以变成int a[3][2] = { 1, 3, 5 };

画成图是这样的:

回看代码:p[0]即a[0][0],所以输出1

Exercise 4

 求下列代码的运行结果

#include <stdio.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));return 0;
}

答案速查:

分析:

该数组元素排布图:

在内存中:

int* ptr1 = (int*)(&aa + 1);

\

"&数组名"取的是整个数组的地址,+1跳过整个数组,在*(ptr1-1)又往回4个字节,解引用是10

*(aa+1)相当于aa[1],二维数组的一行就是一维数组,aa代表第一行的地址,+1转到第二行的6,输出*(ptr2-1)解引用是5

结果为10,5

★Exercise 5:指针-指针

求下列代码的运行结果

//假设环境是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;
}

答案速查:

分析:

分析上方代码前先回顾下数组和指针

#include <stdio.h>
int main()
{int arr1[5] = { 1,2,3,4,5 };int* p1 = &arr1;int arr2[5]={ 0 };int *p2[5] = &arr2;int arr3[5]={ 0 };int (*p3)[5] = &arr3;int arr4[5]={ 0 };int* (*p4)[5] = &arr4;return 0;
}

上方代码运行是否有错误?写的是否规范呢?

逐条分析:

int arr1[5] = { 1,2,3,4,5 };定义了一个名为arr1的数组,其类型为int[5]

int* p1 = &arr1;&arr1的类型在int[5]的基础上加个*,即int[5]

这里int[5]int[5]类型不匹配

因此编译器会报警告:

必须强制让*与p1结合,建议改成:

int (*p1)[5] = &arr1;//p1是int(*)[5],指向含五个整型元素的数组

int arr2[5] = { 1,2,3,4,5 };定义了一个名为arr2的数组,其类型为int[5]

int *p2[5] = &arr2;出现了严重的问题!!

报错:

编译器认为p2是数组其包含5个元素(p2[5]),数组的类型为int*

&arr2的类型为int(*)[5]

这里int*int(*)[5]类型不匹配

必须强制让*与p2结合,建议改成:

int (*p2)[5] = &arr2;//p2是int(*)[5],指向含五个整型元素的数组

int arr3[5]={ 0 };int (*p3)[5] = &arr3;写法无误,解释同上


int arr4[5] = { 0 };定义了一个名为arr4的数组,其类型为int[5]

int* (*p4)[5] = &arr4;但p4类型有问题

arr4类型为int[5]

&arr4类型为int(*)[5]

但p4类型为int* (*)[5] 意思是p4是指向含5个int*类型指针元素的数组的指针

所以int(*)[5]int* (*)[5] 类型不匹配

因此编译器会报警告:

建议改成:

int* arr4[5] = { 0 };
int* (*p4)[5] = &arr4;

回到本练习:

a的类型为int[5][5],p的类型为int(*)[4],两者类型不一样,p=a;会发生类型的转换

因此会报警告

二维数组在内存中的排布(图中一个格子代表一个元素)可以按两种形式理解:p形式和a形式

对于p[4][2]:由于p是int(*)[4]类型,p+1代表跳过二维数组(这里p形式的二维数组是每4个元素一行因为int(*)[4])的第一行至第二行,因此p[4][2]即第4行(从第0行开始算)中的第2个元素

对于a[4][2]:由于a是int[5][5]类型,因此是第4行(从第0行开始算)中的第2个元素(这里a形式的二维数组是每5个元素一行)

指针-指针是两个指针之间的元素个数,%p以补码形式打印,%d以原码形式打印

&p[4][2] - &a[4][2]==小-大==负数,所以为-4(原码)-->FFFFFFFC(补码)

结果:FFFFFFFC,-4

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 深入RAG优化:BGE词嵌入全解析与Landmark Embedding新突破
  • C#线程同步
  • 大众(奥迪)汽车继电器编号对照表
  • uniapp+vue3实现双通道透明MP4播放支持小程序和h5
  • sicp每日一题[1.45]
  • LeetCode 热题100-17 缺失的第一个正数
  • nodejs笔记
  • 聚观早报 | 淘宝将支持微信支付;董明珠支持招35岁员工
  • AE调试一些记录(1)
  • 探索NVIDIA RTX 4060 8G与RTX 3060 12G:性能与适用场景的深度解析
  • 从零开始,认识游戏设计师(3)体验源于设计师①
  • 苹果手机怎么设置铃声?3个方法教你制定个性化铃声
  • 鲁大师8月新机性能/流畅/AI/久用榜:新机节奏放缓,但不乏小惊喜
  • Linux malloc内存分配实现原理
  • 828华为云征文 | Flexus X实例与Harbor私有镜像仓库的完美结合
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • 2019.2.20 c++ 知识梳理
  • Angular数据绑定机制
  • CentOS 7 修改主机名
  • ES6核心特性
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • MySQL主从复制读写分离及奇怪的问题
  • session共享问题解决方案
  • Spark RDD学习: aggregate函数
  • TCP拥塞控制
  • 仿天猫超市收藏抛物线动画工具库
  • 构造函数(constructor)与原型链(prototype)关系
  • 基于组件的设计工作流与界面抽象
  • 蓝海存储开关机注意事项总结
  • 如何使用 JavaScript 解析 URL
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 实现简单的正则表达式引擎
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • 以太坊客户端Geth命令参数详解
  • 在electron中实现跨域请求,无需更改服务器端设置
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​secrets --- 生成管理密码的安全随机数​
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (+4)2.2UML建模图
  • (4)logging(日志模块)
  • (Oracle)SQL优化技巧(一):分页查询
  • (附源码)springboot宠物管理系统 毕业设计 121654
  • (亲测有效)推荐2024最新的免费漫画软件app,无广告,聚合全网资源!
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (四十一)大数据实战——spark的yarn模式生产环境部署
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)LINQ之路
  • (转)linux下的时间函数使用
  • (转)VC++中ondraw在什么时候调用的
  • (最新)华为 2024 届秋招-硬件技术工程师-单板硬件开发—机试题—(共12套)(每套四十题)