c++ 对象起始地址 指针靠齐_你需要知道的各种指针运算

数组的某个成员可以用数组的基地址加上一个偏移量来表示。我们可以声明一个指针double *p;,把它作为基地址,然后就可以像数组一样在这个基地址上使用偏移量。在基地址上,我们可以找到第1个成员p[0]的内容,在基地址上前进一步可以找到第2个成员p[1]的内容,接下来以此类推。因此,只要提供一个指针以及两个相邻成员之间的距离,就可以把它作为数组使用了。

我们可以直接采用基地址加偏移量的书面形式,类似(p+1)。正如教科书所描述的那样,p[1]等同于 *(p+1),这就解释了为什么数组的第1个成员是p[0] == *(p+0)。

这个理论提示了一些规则,用于在实际应用中表述数组和它们的成员。

  • 可以通过显式的指针形式double *p,或静态/自动形式double p[100]来声明数组。
  • 不管是哪种情况,第n + 1个数组成员都是p[n]。不要忘了第一项是0而不是1,这样就可以采用特殊形式p[0] == *p。
  • 如果需要第n个成员的地址(而不是实际值),使用&符号:&p[n]。当然,第1个成员的地址就是&p[0] == p。

例1展示了这些规则的一些实际应用。

例1 一些简单的指针运算(arithmetic.c)

97f92f14cee622603a5a80d53dcb9a88.png

❶ 使用特殊形式*evens写入到evens[0]。

❷ 成员1的地址,赋值给一个新指针。

❸ 引用数组第1个成员的通常方式。

下面我再送你一个很好的技巧,这个技巧建立在指针运算规则“p+1表示数组中下一个成员的地址(&p[1])”的基础上。根据这个规则,我们不需要在遍历数组的循环中使用下标。在例2中我们就使用了一个备用指针来指向list的头部,然后用p++在数组中向前遍历,直到数组尾部的NULL标记,从而获得了整个数组值。如果你查看了接下来的指针声明的提示,会更容易理解这种用法。

例2我们可以利用p++表示“前进到下一个指针”实现循环的流水化

6c3f0b22ba933f9c40e44fa294b406be.png

自己动手

如果不了解p++,你打算怎样实现这个目标?

如果目标是为了实现简洁的语法表示形式,基地址加偏移量这个技巧并不能提供太多的帮助,但它确实解释了C的许多工作原理。事实上,我们可以考虑一下使用结构,例如:

4801eb909c1f900e5806542e45ffc841.png

作为一种智力模型来分析,我们可以把list看成是基地址,list[0].b与基地址的距离正好用来表示b。也就是说,假设list的位置是整数(size_t)&list,b位于(size_t)&list + sizeof(int);,这样list[2].d的位置将是(size_t)&list + 6*sizeof(int) + 5*sizeof(double)。根据这种思路,结构就与数组非常相似了,区别是结构的成员是用名称而不是序号表示的,并且它们具有不同的类型和长度。

这个思路并不是非常正确,因为存在对齐这个因素,系统可能会决定数据需要位于某个特定长度的内存块中,因此字段尾部可能会填充一些额外的空间,使下一个字符从正确的位置开始,并且结构的尾部可能也会进行填充,使结构列表中的每个结构能够大致对齐[C99和C11,§6.7.2.1(15)和(17)]。stddef.h头文件定义了offsetof宏,它精确地描述了基地址加领偏移量的思路:list[2].d的实际地址是(size_t)&list + 2*sizeof(abcd_s) + offsetof(abcd_s, d)。

顺便说一下,在结构的起始处不可能出现填充,因此list[2].a肯定等于(size_t)&list+ 2*sizeof(abcd_s)。

下面是个笨拙的函数,它以递归的方式对列表中的成员进行计数,直到遇到值为0的成员。假设我们想把这个函数用于零值为合理数据的任何类型的列表,因此我们让它接受一个void指针(当然这不是一种好的思路)。

0b1d84b50f555a6b98a7c87cfc3d6740.png

基地址加偏移量的规则解释了为什么这种做法是不行的。为了表示a_list[1],编译器需要知道a_list[0]的准确长度,这样才能知道应该从基地址偏移多少。但是,由于没有与之相关联的类型,它无法计算这个长度。

typedef作为一种教学工具

任何时候当我们遇到一种复杂的类型时,类似于指向某种类型的指针的指针的指针等情况,可以考虑用typedef进行简化。

例如,下面这个常见的定义:

bb169c12de3e3652b03f0a52410a7ea8.png

有效地减少了字符串数组的视觉混乱,使它们的意图变得清晰。

在前面的指针运算p++例子中,char *list[]这样的声明是否很清楚地告诉你它表示一个字符串列表而*p是一个字符串?

例3对例2的for循环进行了重写,用string替换了char *。

例3 添加一个typedef声明使笨拙的代码稍稍变得清晰

fc3166a21bbd0293dc57dfd2a0e3558a.png

list的声明行现在变得简单,很清晰地表示它是个字符串列表,并且string *p也很清晰地表示p是个指向字符串的指针。因此,*p表示一个字符串。

最后,我们仍然需要记住字符串是个指向字符的指针。例如,NULL是个合法的字符串值。

我们甚至可以更进一步,例如使用上面的typedef加上typedef stringlist string*,声明一个字符串的二维数组。这种方法有时候非常实用,但有时候只会增加记忆的负担。

从概念上讲,函数类型的语法实际上是指向一个特定类型的函数的指针。如果我们有一个头部类似下面这样的函数:

22187f993d2e4161a7c3cc2e4dacfc48.png

然后只要添加一个星号(并加上括号以保证优先级),就可以描述一个指向这种类型的函数的指针:

a7c9795db0c2425a08001da60d004054.png

然后在前面加上typedef来定义一种类型:

3a8eb41609bfda955ae6a0f44ea44a97.png

现在我们可以把它当作一种类型使用,例如声明一个接受另一个函数作为其输入参数的函数,可以这样:

b05d01bbc1c41d2dd59cd5794cb76ca3.png

通过对函数指针类型的重新定义,那些接受其他函数作为输入的函数的表达—其中连环星号的书写曾是令人生畏的考验变得不再可怕。

最后需要说明的是,指针实际上要比教科书所描述的简单得多,因为它实际上只是一个位置或别名,根本不需要涉及不同类型的内存管理。像指向字符串的指针的指针这样的复杂构造总是会让人感到迷惑,但这只不过是因为我们以狩猎为生的祖先从来没有见到过这玩意而已。至少,C提供了typedef这个工具来处理它们。


本文节选自《C程序设计新思维》

8130c74fc2b3b3bbc08d7be39cf046b5.png

内容简介

C语言已经有40年的历史了。经过长时间的发展和普及,C语言的应用场景有了很大的变化,一些旧观念应该被淡化或者不再被推荐。

本书展现了传统C语言教科书所不具有的最新的相关技术。全书分为开发环境和语言两个部分,从编译、调试、测试、打包、版本控制等角度,以及指针、语法、文本、结构、面向对象编程、库等方面,对C程序设计的核心知识进行查缺补漏和反思。本书鼓励读者放弃那些对大型机才有意义的旧习惯,拿起新的工具来使用这门与时俱进的简洁语言。

本书适合有一定基础的C程序员或C语言学习者阅读,也适合想要深入理解C语言特性的读者参考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/291594.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2014,成为更好程序员的7个方法

2019独角兽企业重金招聘Python工程师标准>>> // 译注:英文原文发布今年年初,所以开头提到了”新年“,请不要惊讶~ 程序员总是有很多的决定,不是吗?如果你的新年待办事项还是空白的话,那么可以考…

.NET6之MiniAPI(十五):跨域CORS(下)

前一篇的跨域请求的方式是松宽的方式,毕竟跨域有安全风险,应尽量少的允许访问必要资源,本篇分别从请求方法,请求头和请求凭据方面了解跨域设置。请求方法:api项目,get,post是默认访问&#xff0…

游戏上线... 记录下...

转载于:https://www.cnblogs.com/porter/p/6339792.html

Beetlex服务网关1.8发布

在新的版本中网关添加了不少功能,分别有流量控制包括:会话、IP、域名和Url等流量控制配置;在插件上添加了Redis读取和ElasticSearch文档搜索功能。流量控制在新版本中网关添加了流量控制功能,通过这一功能可以控制会话、IP、域名和…

HDU 3487 Play with Chain | Splay

Play with Chain Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) 【Problem Description】YaoYao is fond of playing his chains. He has a chain containing n diamonds on it. Diamonds are numbered from 1 to n. At first, the d…

WIN32程序结构

windows程序基于消息驱动系统,用户的所有行为和事件都被windows转成消息。windows内部对消息的处理:消息生命周期:1.消息产生:windows监控所有具体输入事件硬件设备。当系统收到设备输入事件时。windows将对应事件转成消息。2.消息投递:每个消息都有一个目标窗体接收…

zsh

2019独角兽企业重金招聘Python工程师标准>>> 1. MAC安装zsh后,部分bash 指令失效conda, list, pip, list失效,怎么解决? step1:vim ~/.bash_profile 记录Anaconda的路径地址: export PATH"/Users/XXX/anaconda/bin:$PAT…

导出jar插件_Fluttify输出的Flutter插件工程详解

系列文章:yohom:Fluttify输出的Flutter插件工程详解​zhuanlan.zhihu.comyohom:开发Flutter插件必备原生SDK->Dart接口生成引擎Fluttify介绍​zhuanlan.zhihu.comyohom:如何使用Fluttify开发一个新的Flutter插件​zhuanlan.zhi…

[免费下载应用]iNeuKernel.Ocr 图像数据识别与采集原理和产品化应用

目 录1..... 应用概述... 22..... 免费下载试用... 23..... 视频介绍... 24..... iNeuLink.Ocr图像数据采集应用... 25..... 数据上传到iNeuOS工业互联网操作系统... 46..... Ocr基本概念... 71. 应用概述在工业、军工或航天等领域,有些设备及软件系统比较陈…

hdu 1848(Fibonacci again and again)(SG博弈)

Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8380 Accepted Submission(s): 3462 Problem Description任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生&#xff…

linux c之gcc编译出现error:lvalue required as unary ‘‘ operand解决办法

1、问题 今天搞epoll实现io复用的时候gcc编译出现这个错误lvalue required as unary & operand,如下图 2、解决办法 accept函数参数如下 int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen); 在第三个参数为了少些代码我是这样写成这样&size…

生成arff文件,csv转为arff

一、什么是arff格式文件 1、arff是Attribute-Relation File Format缩写,从英文字面也能大概看出什么意思。它是weka数据挖掘开源程序使用的一种文件模式。由于weka是个很出色的数据挖掘开源项目,所以使用的比较广,这也无形中推广了它的数据存…

C#中的类

前言今天咱们简单复习下C#中类的相关知识。在刚开始学习编程的时候,都是从面向过程的C语言开始的,它有个特征就是有其执行顺序,先干这,再干那,很直接,也很好理解。但现在学习C#或者JAVA等面向对象的语言&am…

Stopwatch类学习

1、概述:给一条大MSDN的链接关于Stopwatch类最详细的教程 ,然后看着教程自己手动敲一边,加深映象,好记性不如烂键盘,哈哈,开个玩笑! 2、类位置:这个类在哪里,这个是重点,虽然C#IDE很强大,但是我们还是得简单的了解下。通过一段代码来说明: using System; namespace …

看看这套WPF开源基础控件库:WPFDevelopers

此项目包含了 微信公众号 《 WPF开发者》 日常开发分享,欢迎Star。运行环境 Visual Studio 2019,dotNet Framework 4.0 SDK欢迎关注微信公众号支持贡献者DrawPrize(WPF 实现大转盘抽奖)GIF帧数太多,无法上传&#xff0…

如何将EDM营销与多渠道推广方式相结合

目前,消费者每天都会从各种渠道收到信息,如果仅用单一渠道的营销会影响整体营销。多渠道推广方式是所有渠道都要兼顾到从而接触用户,让他接收到他想接收的信息,多渠道的过程中邮件还是非常好的营销方式。你要想让你的EDM营销获得成…

Cannot resolve the collation conflict between SQL_Latin1_General_CP1_CI_AS and Latin1_General_100...

ErrorMessage Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_100_CI_AS" in the equal to operation. 查看SQL Server的Collation SELECT SERVERPROPERTY (Collation) Solution 1. 在安装SQL Server…

语言 ota_荣威RX5 PLUS使用最新的家族设计语言,给人更年轻时尚的感觉

如果要用一个词来形容 荣威RX5 PLUS,我第一个能想到的便是“诚意”。斑马最新VENUS系统、米其林PS4轮胎、双层隔音玻璃、终身原厂质保、终身免费基础保养……从产品到政策,荣威RX5 PLUS的方方面面都显示出了上汽荣威的诚意。从上市到现在,荣威…

C# 制作指示灯(经典)

群友提问:C#中的指示灯怎么做,改变状态有什么好的方法吗?制作指示灯的方法有很多中:比如:通过GDI绘制自定义LED指示灯控件;调用现成的第三方控件库;采用label标签,通过改变背景色实现…

结合ChatGPT和MINDSHOW自动生成PPT

总结/朱季谦 一、首先,通过chatGPT说明你的需求,学会提问是Ai时代最关键的一步。你需要提供一些关键信息,如果没有关键信息,就按照大纲方式让它设计,例如,我让它帮我写一份《2023年年中述职报告》的模版—…