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

肯尼斯·里科《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.mzph.cn/news/624039.shtml

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

相关文章

leetcode 349 两个数组的集合

题目 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例 2&#xff1a; 输入&#xff1a…

【playwright】新一代自动化测试神器playwright+python系列课程00——playwright安装

playwright安装 本文主要分享由微软开发的实现Web UI自动化测试工具Playwright库&#xff0c;相比于之前学习过selenium库&#xff0c;playwright对于编写自动化代码绝对是更轻松了&#xff0c;因为它支持脚本录制&#xff0c;如果只求简单点可以不用写一行代码就能够实现自动…

网络安全|GitHub 已成为恶意软件传播的严重污染源

Recorded Future 凸显了全球合法平台威胁的上升。 根据 Recorded Future最近 的一份报告&#xff0c;开发者平台GitHub最近已成为黑客用来托管和传播恶意软件的流行工具。 该平台为攻击者提供了将其行为伪装成合法网络流量的能力&#xff0c;这使得跟踪和确定攻击者的身份变得…

ubuntu20.04 deepstream 6.3安装

1.基础环境gstreamer sudo apt install \ libssl-dev \ libgstreamer1.0-0 \ gstreamer1.0-tools \ gstreamer1.0-plugins-good \ gstreamer1.0-plugins-bad \ gstreamer1.0-plugins-ugly \ gstreamer1.0-libav \ libgstreamer-plugins-base1.0-dev \ libgstrtspserver-1.0-0 …

C练习——模拟投掷6000次骰子

题目&#xff1a; 模拟骰子投6000次&#xff0c;并计算每一面出现的概率 解析&#xff1a; 6000次&#xff0c;首先想到用数组记录六个面各出现次数 其次&#xff0c;使用随机数&#xff08;1~6的数&#xff09;模拟骰子 然后统计1~6每个数出现的几次&#xff0c;最后除以6…

倒F天线设计经验分享

一、IFA天线理论分析 为了改善&#xff29;&#xff2c;&#xff21;天线难以使用的缺点&#xff0c;在&#xff29;&#xff2c;&#xff21;天线的基础上再增加一个倒L结构&#xff0c;形成IFA天线&#xff0c;此种天线体积小、易于匹配并具有双极化的特点&#xff0c;而在蓝…

基于springboot的二手车交易系统的设计与实现

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一 、设计说明 1.1 课题背景 二…

交换机批量巡检、配置软件

使用Python3.8实现&#xff0c;支持huawei\h3c\cisco三种交换机批量巡检或者批量配置。 要求&#xff1a;同一种类型的交换机有相同的登录账号和密码&#xff0c;开启ssh服务。 可以查看mac地址是否漂移或者欺骗、ip地址与MAC对应关系&#xff0c;可以查看是否有环路&#xf…

AI 图像自动补全 Uncrop 工具介绍

ClipDrop Uncrop是一款基于AI的图像自动补全工具&#xff0c;由StabilityAI旗下的Clipdrop开发。通过利用StableDiffusionXL开发的算法和深度学习技术&#xff0c;Uncrop可以对用户上传的图片进行自动扩展和补全&#xff0c;改变图片尺寸&#xff0c;使得图像内容得到更完整的呈…

互联网上门洗衣洗鞋工厂系统搭建;

随着移动互联网的普及&#xff0c;人们越来越依赖手机应用程序来解决生活中的各种问题。通过手机预约服务、购买商品、获取信息已经成为一种生活习惯。因此&#xff0c;开发一款上门洗鞋小程序&#xff0c;可以满足消费者对于方便、快捷、专业的洗鞋服务的需求&#xff0c;同时…

MYSQL第三次作业--单表查询

第三次作业 一、创建worker表 mysql> create table worker(-> 部门号 int(11) not null,-> 职工号 int(11) not null,-> 工作时间 date not null,-> 工资 float(8,2) not null,-> 政治面貌 varchar(10) not null default群众,-> 姓名 varchar(20) not n…

【无主之地3】最详细的补丁教程(酸奶公园)

【无主之地3】最详细的补丁教程&#xff08;酸奶公园&#xff09; steam已有游戏 1.迅雷种子下载文件&#xff0c;只用下载AddtionalContent这一个&#xff0c;放在文件夹OakGame下 2.将文件夹Engine&#xff1e;Binaries&#xff1e;ThirdParty&#xff1e;steamworks&a…

人脸识别(Java实现的)

虹软人脸识别&#xff1a; 虹软人脸识别的地址&#xff1a;虹软视觉开放平台—以免费人脸识别技术为核心的人脸识别算法开放平台 依赖包&#xff1a; 依赖包是从虹软开发平台下载的 在项目中引入这个依赖包 pom.xml <!-- 人脸识别 --><dependency><gr…

DeepFloyd IF:由文本生成图像的强大模型,能够绘制文字的 AI 图像工具

文章目录 一、DeepFloyd IF 简介二、DeepFloyd IF模型架构三、DeepFloyd IF模型生成流程四、DeepFloyd IF 模型定义 一、DeepFloyd IF 简介 DeepFloyd IF&#xff1a;能够绘制文字的 AI 图像工具 之前的 Stable Diffusion 和 Midjourney 都无法生成带有文字的图片&#xff0c;…

YOLOv8改进 | 细节涨点篇 | UNetv2提出的一种SDI多层次特征融合模块(分割高效涨点)

一、本文介绍 本问给大家带来的改进机制是UNetv2提出的一种多层次特征融合模块(SDI)其是一种用于替换Concat操作的模块,SDI模块的主要思想是通过整合编码器生成的层级特征图来增强图像中的语义信息和细节信息。该方法已在多个公开的医学图像分割数据集上进行了验证,包括皮…

【数据库原理】(27)数据库恢复

在数据库系统中&#xff0c;恢复是指在发生某种故障导致数据库数据不再正确时&#xff0c;将数据库恢复到已知正确的某一状态的过程。数据库故障可能由多种原因引起&#xff0c;包括硬件故障、软件错误、操作员失误以及恶意破坏。为了确保数据库的安全性和完整性&#xff0c;数…

多合一小程序商城系统源码:支持全平台端口 附带完整的搭建教程

现如今&#xff0c;随着移动互联网的飞速发展&#xff0c;小程序已经成为电商行业的新宠。罗峰给大家分享一款多合一小程序商城系统源码。该系统旨在为商家提供一个功能强大、易于搭建和管理的电商平台&#xff0c;帮助商家快速占领市场&#xff0c;提高品牌影响力。 以下是部…

day08

回顾 1.选择排序原理: 找到最小值的下标&#xff0c;交换 2.冒泡排序原理: 比较相邻的两个元素&#xff0c;把最小值放到左边。第一次比较的时候最大值放到最右边了&#xff0c;以此类推今天的内容 1类和对象 2.类和对象内存 3.构造方法 1.从生活的角度区理解面向对象开发 有两…

C program to check little vs. big endian

void main() {int n 1;// little endian if trueif(*(char *)&n 1)printf("This is little endian\n");elseprintf("This is big endian\n"); }Suppose we are on a 32-bit machine. And char type is 8 bits

如何配置mybatisplus基础环境?

1.在pom文件&#xff08;都加上吧&#xff0c;以防万一&#xff09; 2.若当初有mybatis的依赖&#xff0c;要删除 3.在Mapper接口加上"extends BaseMapper<实体类型>" 4.更改yml文件内容 别名扫描包&#xff1a;是指实体类型 5.添加"extends ServiceIm…