肯尼斯·里科《C和指针》第6章 指针(4)实例

news2024/10/7 6:38:34

肯尼斯·里科《C和指针》第6章 指针(1)-CSDN博客

肯尼斯·里科《C和指针》第6章 指针(2)-CSDN博客

肯尼斯·里科《C和指针》第6章 指针(3)-CSDN博客

6.12 实例

/*
** 计算一个字符串的长度。
*/
#include <stdlib.h>
size_t
strlen( char *string )
{
         int     length = 0;
         /*
         ** 依次访问字符串的内容,计数字符数,直到遇见NUL终止符。
         */
         while( *string++ != '\0' )
               length += 1;
         return length;
}

在指针到达字符串末尾的NUL字节之前,while语句中*string++表达式的值一直为真。它同时增加指针的值,用于下一次测试。这个表达式甚至可以正确地处理空字符串。

如果这个函数调用时传递给它的是一个NULL指针,那么while语句中的间接访问将会失败。函数是不是应该在解引用指针前检查这个条件?从绝对安全的角度讲,应该如此。但是,这个函数并不负责创建字符串。如果它发现参数为NULL,它肯定发现了一个出现在程序其他地方的错误。当指针创建时检查它是否有效是合乎逻辑的,因为这样只需检查一次。这个函数采用的就是这种方法。如果函数失败是因为粗心大意的调用者懒得检查参数的有效性而引起的,那是他活该如此。

程序6.2和程序6.3增加了一层间接访问。它们在一些字符串中搜索某个特定的字符值,但我们使用指针数组来表示这些字符串,如图6.1所示。函数的参数是strings和value,strings是一个指向指针数组的指针,value是我们所查找的字符值。注意,指针数组以一个NULL指针结束。函数将检查这个值以判断循环何时结束。下面这行表达式

while( ( string = *strings++ ) != NULL ) {

完成3项任务:把strings当前所指向的指针复制到变量string中;增加strings的值,使它指向下一个值;测试string是否为NULL。当string指向当前字符串中作为终止标志的NUL字节时,内层的while循环就终止。

程序6.2 在一组字符串中查找:版本1 s_srch1.c

/*
** 给定一个指向以NULL结尾的指针列表的指针,在列表中的字符串中查找一个特定的字符。
*/
#include <stdio.h>
#define    TRUE        1
#define    FALSE    0
int
find_char( char **strings, char value )
{
            char*string;      /* 我们当前正在查找的字符串 */
            /*
            ** 对于列表中的每个字符串 ...
            */
            while( ( string = *strings++ ) != NULL ){
                  /*
                  ** 观察字符串中的每个字符,看看它是不是我们需要查找的那个。
                  */
                  while( *string != '\0' ){
                      if( *string++ == value )
                                return TRUE;
                  }
            }
            return FALSE;
}
if( *string++ == value )

如果string尚未到达其结尾的NUL字节,就执行上面这条语句,它测试当前的字符是否与需要查找的字符匹配,然后增加指针的值,使它指向下一个字符。

后增加指针的值,使它指向下一个字符。程序6.3实现相同的功能,但它不需要对指向每个字符串的指针进行复制。但是,由于存在副作用,这个程序将破坏这个指针数组。这个副作用使该函数不如前面那个版本有用,因为它只适用于字符串只需要查找一次的情况。

程序6.3 在一组字符串中查找:版本2 s_srch2.c

/*
** 给定一个指向以NULL结尾的指针列表的指针,在列表中的字符串中查找一个特定的字符。这个函数将破坏这些指针,所以它只适用于这组字符串只使用一次的情况。
*/
#include <stdio.h>
#include <assert.h>
#define   TRUE       1
#define   FALSE   0
int
find_char( char **strings, int value )
{
         assert( strings != NULL );
         /*
         ** 对于列表中的每个字符串 ...
         */
        while( *strings != NULL ){
                 /*
                 ** 观察字符串中的每个字符,看看它是否是我们查找的那个。
                 */
                 while( **strings != '\0' ){
                       if( *(*strings)++ == value )
                           return TRUE;
                 }
                 strings++;
        }
           return FALSE;
}

但是,在程序6.3中存在两个有趣的表达式。第1个是**strings。第1个间接访问操作访问指针数组中的当前指针,第2个间接访问操作随该指针访问字符串中的当前字符。内层的while语句测试这个字符的值并观察是否到达了字符串的末尾。

第2个有趣的表达式是*(*strings)++。这里需要括号,这样才能使表达式以正确的顺序进行求值。第1个间接访问操作访问列表中的当前指针。增值操作把该指针所指向的那个位置的值加1,但第2个间接访问操作作用于原先那个值的副本。这个表达式的直接作用是对当前字符串中的当前字符进行测试,看看是否到达了字符串的末尾。它的副作用是指向当前字符串字符的指针值将增加1。

6.13 指针的运算

实际的过程

指针加上一个整数的结果是另一个指针。问题是,它指向哪里?如果将一个字符指针加1,运算结果产生的指针指向内存中的下一个字符。float占据的内存空间不止1字节,如果将一个指向float的指针加1,将会发生什么呢?它会不会指向该float值内部的某个字节呢?

幸运的是,答案是否定的。当一个指针和一个整数量执行算术运算时,整数在执行加法运算前始终会根据合适的大小进行调整。这个“合适的大小”就是指针所指向类型的大小,“调整”就是把整数值和“合适的大小”相乘。为了更好地说明,试想在某台机器上,float占据4字节。在计算float型指针加3的表达式时,这个3将根据float类型的大小(此例中为4)进行调整(相乘)。这样,实际加到指针上的整型值为12。

把3与指针相加使指针的值增加3个float的大小,而不是3字节。这个行为较之获得一个指向一个float值内部某个位置的指针更为合理。表6.5包含了一些加法运算的例子。调整的美感在于指针算法并不依赖于指针的类型。换句话说,如果p是一个指向char的指针,那么表达式p+1就指向下一个char。如果p是个指向float的指针,那么p+1就指向下一个float,其他类型也是如此。

表6.5 指针运算结果

 算数运算

C的指针算术运算只限于两种形式。

第1种形式是:指针±整数

标准定义这种形式只能用于指向数组中某个元素的指针,如下图所示。

第2种类型的指针运算具有如下形式:指针-指针

只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去另一个指针,如下所示。

两个指针相减的结果的类型是ptrdiff_t,这是一种有符号整数类型。减法运算的值是两个指针在内存中的距离(以数组元素的长度为单位,而不是以字节为单位),因为减法运算的结果将除以数组元素类型的长度。例如,如果p1指向array[i]而p2指向array[j],那么p2-p1的值就是j-i的值。

让我们看一下它是如何作用于某个特定类型的。假定上图中数组元素的类型为float,每个元素占据4字节的内存空间。如果数组的起始位置为1000,p1的值是1004,p2的值是1024,但表达式p2-p1的结果值将是5,因为两个指针的差值(20)将除以每个元素的长度(4)。

同样,这种对差值的调整使指针的运算结果与数据的类型无关。不论数组包含的元素类型如何,这个指针减法运算的值总是5。

那么,表达式p1-p2是否合法呢?是的,如果两个指针都指向同一个数组中的元素,这个表达式就是合法的。在前一个例子中,这个值将是-5。

如果两个指针所指向的不是同一个数组中的元素,那么它们之间相减的结果是未定义的。就像如果你把两个位于不同街道的房子的门牌号码相减,不可能获得这两所房子间的房子数一样。程序员无从知道两个数组在内存中的相对位置,如果不知道这一点,两个指针之间的距离就毫无意义。

关系运算

对指针执行关系运算也是有限制的。可以用下列关系操作符对两个指针值进行比较:

<  <=  >  >=

不过前提是它们都指向同一个数组中的元素。根据所使用的操作符,比较表达式将告诉你哪个指针指向数组中更前或更后的元素。标准并未定义如果两个任意的指针进行比较时会产生什么结果。

不过,可以在两个任意的指针间执行相等或不相等测试,因为这类比较的结果和编译器选择在何处存储数据并无关系——指针要么指向同一个地址,要么指向不同的地址。

让我们再观察一个循环,它用于清除一个数组中的所有元素

for语句使用了一个关系测试来决定是否结束循环。这个测试是合法的,因为vp和指针常量都指向同一数组中的元素(事实上,这个指针常量所指向的是数组最后一个元素后面的那个内存位置,虽然在最后一次比较时,vp也指向了这个位置,但由于此时未对vp执行间接访问操作,因此它是安全的)。使用!=操作符代替<操作符也是可行的,因为如果vp未到达它的最后一个值,这个表达式的结果将总是假的。

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

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

相关文章

SSL证书怎么选?

首先&#xff0c;我们需要理解不同类型的SSL证书及其费用差异。通常情况下&#xff0c;SSL证书分为域名验证型&#xff08;DV&#xff09;、组织验证型&#xff08;OV&#xff09;和企业验证型&#xff08;EV&#xff09;三种。其中&#xff0c;DV证书是最常见的类型&#xff0…

入驻商城小程序系统源码:众多自定义组件以及营销插件随心搭,独立部署,带完整的搭建教程

现如今&#xff0c;互联网在不断的发展&#xff0c;小程序已成为电商行业的重要战场。入驻商城小程序系统源码正是基于这一背景&#xff0c;为用户提供了一套功能强大、易于定制的电商解决方案。该源码拥有众多自定义组件和营销插件&#xff0c;支持独立部署&#xff0c;并附带…

芯课堂 | 华芯微特MCU在PCB板级设计中对ISP引脚的应用

1.应用描述 ISP&#xff08;In System Programming&#xff09;&#xff0c;在系统编程&#xff0c;使用片内驻留出厂引导程序&#xff08;BootROM&#xff09;配合UART / SPI等外设进行烧录。 华芯微特全系MCU的ISP操作说明&#xff1a;当芯片上电后检测到 ISP 引脚持续 5ms…

聚甲基丙烯酸甲酯PMMA的特性有哪些?UV胶水能够粘接聚甲基丙烯酸甲酯PMMA吗?又有哪些优势呢?

聚甲基丙烯酸甲酯&#xff08;Polymethyl Methacrylate&#xff0c;PMMA&#xff09;&#xff0c;又称丙烯酸甲酯&#xff0c;是一种常见的透明塑料&#xff0c;具有许多特性&#xff0c;使其在各种应用领域中广泛使用。以下是PMMA的一些主要特性&#xff1a; 1. 优异的透明性&…

【极光系列】springBoot集成Hibernate

【极光系列】springboot集成hibernate gitee地址 直接下载可用 https://gitee.com/shawsongyue/aurora.git 模块&#xff1a;aurora_hibernate mysql安装教程 参考我另外一篇文章&#xff0c;直接下载安装 https://blog.csdn.net/weixin_40736233/article/details/1355829…

入站请求负载均衡解决方案 LVS 的介绍

概述 LVS 简介 LVS&#xff08;Linux Virtual Server&#xff09;即 Linux 虚拟服务器&#xff0c;是一个虚拟的服务器集群系统。 通过 LVS 的负载均衡技术和 LINUX 操作系统可以实现一个高性能、高可用的 LINUX 服务器集群&#xff0c;它具有良好的可靠性、可扩展性和可操作性…

PVE虚拟机安装qemu guest agent

pve虚拟机安装guest agent&#xff0c;使web平台可以直接显示虚拟机的ip&#xff0c;方便管理。 一、虚拟机需开启Qemu代理 首先&#xff0c;虚拟机需开启Qemu代理&#xff0c;需要关闭虚拟机再启动虚拟机并安装agent。网上有些文章说要把网卡配置为virtio&#xff0c;经测试是…

MATLAB - 计算关节扭矩以平衡端点力和力矩

系列文章目录 前言 产生力矩以平衡作用在平面机器人末端执行器体上的端点力。要使用各种方法计算关节力矩&#xff0c;请使用刚体树机器人模型的几何雅各比&#xff08;geometricJacobian&#xff09;和反动力学&#xff08;inverseDynamics&#xff09;对象函数。 一、初始化…

在IntelliJ IDEA上使用通义灵码(TONGYI Lingma)

参考链接&#xff1a; 通义灵码产品介绍_智能编码助手_AI编程_云效(Apsara Devops)-阿里云帮助中心 【IDEA如何使用通义灵码&#xff1f;】_idea 通义灵码-CSDN博客 1. 简介 1.1 定义 通义灵码&#xff0c;是阿里云出品的一款基于通义大模型的智能编码辅助工具&#xff0c;提…

单细胞转录组学对代谢功能障碍相关脂肪变性肝病的类器官模型进行分析

前言 最近接触比较多肝纤维化项目&#xff0c;包括空转、单细胞和普通的BULK转录组&#xff0c;本文是肝脏疾病类器官构建&#xff0c;所以结果是比较确定的&#xff0c;只是对比不同处理和培养哪种效果更好&#xff0c;适合了解纤维化进展和哪些分子和细胞参与&#xff0c;以…

基于协方差矩阵自适应演化策略(CMA-ES)的高效特征选择

特征选择是指从原始特征集中选择一部分特征&#xff0c;以提高模型性能、减少计算开销或改善模型的解释性。特征选择的目标是找到对目标变量预测最具信息量的特征&#xff0c;同时减少不必要的特征。这有助于防止过拟合、提高模型的泛化能力&#xff0c;并且可以减少训练和推理…

CANFD数据记录仪在新能源汽车复杂路测下的应用

CANFD数据记录仪在新能源汽车复杂路测下的应用 汽车制造商在生产预批量阶段的耐久性测试中,为了检测潜在故障,必须让车辆在严酷的路况和环境下接受测试。为确保能回溯故障发生的现场情况,我们需要对测试数据精准记录与储存。这些数据是新车型优化迭代的关键,也是确保产品质量的…

【优选算法】滑动窗口 {何时使用滑动窗口?如何使用滑动窗口?如何确定更新结果的时机?滑动窗口是如何提高效率的?相关编程题解析}

一、经验总结 何时使用滑动窗口&#xff1f; 在使用暴力解法解题时&#xff0c;发现可以将其优化为同向双指针&#xff0c;既可以使用滑动窗口。 如何使用滑动窗口&#xff1f; 1. 定义窗口控制变量n&#xff0c;进窗口&#xff0c;判断&#xff0c;出窗口都需要操作窗口控制…

天软特色因子看板 (2024.01 第7期)

该因子看板跟踪天软特色因子A04001(当日趋势强度)&#xff0c;该因子为反映股价走势趋势强弱&#xff0c;用以反映股价走势趋势强弱&#xff0c;abs(值)越接近1&#xff0c;趋势 性越强&#xff0c;符号代表涨跌方向。 今日为该因子跟踪第7期&#xff0c;跟踪其在SW801050 (申万…

Open CV 图像处理基础:(六)在Java中使用 Open CV进行图片翻转和图片旋转

在Java中使用 Open CV进行图片翻转和图片旋转 目录 在Java中使用 Open CV进行图片翻转和图片旋转前言图片翻转函数代码示例其它翻转方向垂直翻转两轴翻转 图片旋转函数代码示例 Open CV 专栏导航 前言 在Java中使用OpenCV进行图片翻转和旋转是一种基本的图像处理技术&#xff0…

机器学习根据金标准标记数据-九五小庞

根据金标准标记数据是一种在机器学习和数据科学中常见的操作&#xff0c;主要用于评估分类模型的性能。其基本步骤如下&#xff1a; 收集数据&#xff1a;首先需要收集相关领域的原始数据&#xff0c;这些数据通常来自不同的来源和渠道。数据清洗和预处理&#xff1a;在这一步…

常见的限流算法

本文已收录至我的个人网站&#xff1a;程序员波特&#xff0c;主要记录Java相关技术系列教程&#xff0c;共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源&#xff0c;让想要学习的你&#xff0c;不再迷茫。 天下武学出同源 正所谓天下武学殊途同归&#xff…

怎么批量重命名图片?分享3个高效方法!

怎么批量重命名图片&#xff1f;在日常生活中&#xff0c;将图片批量重命名是一项非常实用的操作。有时候我们拍摄或收集了很多图片&#xff0c;需要对其进行整理和归类。通过批量重命名&#xff0c;我们可以快速为图片添加序号、日期或其他标识&#xff0c;使其更有条理。此外…

new mars3d.layer.GeoJsonLayer({实现图标点billboard贴模型聚合效果

说明&#xff1a; 1.【mars3d】的依赖库cesium本身是不支持贴地/贴模型操作的 2.sdk内部异步计算了数据的贴地/高度值之后&#xff0c;更新到图层上实现贴地/贴模型效果的 3.相关的示例链接&#xff1a; 1.功能示例(Vue版) | Mars3D三维可视化平台 | 火星科技 4.相关的计算…

Java基础 - 黑马

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 知…