肯尼斯·里科《C和指针》第13章 高级指针话题(3)命令行参数

处理命令行参数是指向指针的指针的另一个用武之地。有些操作系统,包括UNIX和MS-DOS,让用户在命令行中编写参数来启动一个程序的执行。这些参数被传递给程序,程序按照它认为合适的任何方式对它们进行处理。

13.4.1 传递命令行参数

这些参数如何传递给程序呢?C程序的main函数具有两个形参。第1个通常称为argc,它表示命令行参数的数目。第2个通常称为argv,它指向一组参数值。由于参数的数目并没有内在的限制,因此argv指向这组参数值(从本质上说是一个数组)的第1个元素。这些元素的每一个都是指向一个参数文本的指针。如果程序需要访问命令行参数,main函数在声明时就要加上这些参数:

int main(int argc, char **argv)

注意,这两个参数通常取名为argc和argv,但它们并无神奇之处。如果你喜欢,也可以把它们称为fred和ginger,只不过程序的可读性会差一点。

下图显示了下面这条命令行是如何进行传递的。

$ cc –c –o main.c insert.c –o test

注意指针数组:这个数组的每个元素都是一个字符指针,数组的末尾是一个NULL指针。argc的值和这个NULL值都用于确定实际传递了多少个参数。argv指向数组的第1个元素,这就是它被声明为一个指向字符的指针的指针的原因。

最后一个需要注意的地方是第1个参数就是程序的名称。把程序名作为参数传递有什么用意呢?程序显然知道自己的名字,通常这个参数是被忽略的。不过,如果程序通常采用几组不同的选项进行启动,此时这个参数就有用武之地了。UNIX中用于列出一个目录中所有文件的ls命令就是一个这样的程序。在许多UNIX系统中,这个命令具有几个不同的名字。当它以名字ls启动时,它将产生一个文件的简单列表;如果它以名字l启动,就产生一个多列的简单列表;如果它以名字ll启动,就产生一个文件的详细列表。程序对第1个参数进行检查,确定它是由哪个名字启动的,从而根据这个名字选择启动选项。

在有些系统中,参数字符串是挨个存储的。这样当把指向第1个参数的指针向后移动,越过第一个参数的尾部时,就到达了第2个参数的起始位置。但是,这种排列方式是由编译器定义的,所以不能依赖它。为了寻找一个参数的起始位置,应该使用数组中合适的指针。

程序是如何访问这些参数的呢?程序13.2是一个非常简单的例子,它简单地打印出它的所有参数(除了程序名)——非常像UNIX的echo命令。

/*
** 一个打印其命令行参数的程序。
*/
#include <stdio.h>
#include <stdlib.h>
int
main( int argc, char **argv )
{/*** 打印参数,直到遇到NULL指针(未使用argc)。程序名被跳过。*/while( *++argv != NULL )printf( "%s\n", *argv );return EXIT_SUCCESS;
}

程序13.2 打印命令行参数 echo.c

while循环增加argc的值,然后检查*argv,看看是否到达了参数列表的尾部,方法是把每个参数都与表示列表末尾的NULL指针进行比较。如果还存在另外的参数,循环体就执行,打印出这个参数。在循环一开始就增加argc的值,程序名就被自动跳过了。

printf函数的格式字符串中的%s格式码要求参数是一个指向字符的指针。printf假定该字符是一个以NUL字节结尾的字符串的第一个字符。对argv参数使用间接访问操作产生它所指向的值,也就是一个指向字符的指针——这正是格式所要求的。

13.4.2 处理命令行参数

让我们编写一个程序,用一种更加现实的方式处理命令行参数。这个程序将处理一种非常常见的形式——文件名参数前面的选项参数。在程序名的后面,可能有零个或多个选项,后面跟随零个或多个文件名,像下面这样:

prog –a –b –c name1 name2 name3

每个选项都以一条横杠开头,后面是一个字母,用于在几个可能的选项中标明程序所需的一个。每个文件名以某种方式进行处理。如果命令行中没有文件名,就对标准输入进行处理。

为了让这些例子更为通用,我们的程序设置了一些变量,记录程序所找到的选项。一个现实程序的其他部分可能会测试这些变量,用于确定命令所请求的处理方式。在一个现实的程序中,如果程序发现它的命令行参数有一个选项,其对应的处理过程可能也会执行。

下面的程序13.3和程序13.2颇为相似,因为它包含了一个循环,用于检查所有的参数。它们的主要区别在于我们现在必须区分选项参数和文件名参数。当循环到达并非以横杠开头的参数时就结束。第2个循环用于处理文件名。

/*
** 处理命令行参数。
*/
#include <stdio.h>
#define   TRUE 1
/*
** 执行实际任务的函数的原型。
*/
void    process_standard_input( void );
void    process_file( char *file_name );
/*
** 选项标志,缺省初始化为FALSE。
*/
int    option_a, option_b  /* etc. */ ;
void
main( int argc, char **argv )
{/*** 处理选项参数:跳到下一个参数,并检查它是否以一个横杠开头。*/while( *++argv != NULL && **argv == '-' ){/*** 检查横杠后面的字母。*/switch( *++*argv ){case 'a':option_a = TRUE;break;case 'b':option_b = TRUE;break;/* etc. */}}/*** 处理文件名参数。*/if( *argv == NULL )process_standard_input();else {do {process_file( *argv );} while( *++argv != NULL );}
}

程序13.3 处理命令行参数 cmd_line.c

注意,在程序13.3的while循环中,增加了下面这个测试:

**argv == '-'

双重间接访问操作访问参数的第1个字符,如图13.2所示。如果这个字符不是一个横杠,那就表示不再有其他的选项,循环终止。注意,在测试**argv之前先测试*argv是非常重要的。如果*argv为NULL,那么**argv中的第2个间接访问就是非法的。

switch语句中的*++*argv表达式以前曾见到过。第1个间接访问操作访问argv所指的位置,然后这个位置执行自增操作。最后1个间接访问操作根据自增后的指针进行访问,如图13.3所示。switch语句根据找到的选项字母设置一个变量,while循环中的++操作符使argv指向下一个参数,用于循环的下一次迭代。

当不再存在其他选项时,程序就处理文件名。如果argv指向NULL指针,命令行参数中就没有其他内容了,程序就处理标准输入;否则,程序就逐个处理文件名。这个程序的函数调用较为通用,它们并未显示一个现实程序可能执行的任何实际工作。然而,这个设计方式是非常好的。main程序处理参数,这样执行处理过程的函数就无须担心怎样对选项进行解析或者怎样挨个访问文件名。

有些程序允许用户在一个参数中放入多个选项字母,像下面这样:

prog –abc name1 name2 name3

一开始我们可能会觉得这个改动会使程序变得复杂,但实际上它很容易进行处理。每个参数都可能包含多个选项,所以我们使用另一个循环来处理它们。这个循环在遇到参数末尾的NUL字节时应该结束。

程序13.3中的switch语句由下面的代码段代替:

while((opt= *++*argv) != '\0'){switch(opt){case 'a':option_a = TRUE;break;/*etc*/}}

循环中的测试使参数指针移动到横杠后的那个位置,并复制一份位于那里的字符。如果这个字符并非NUL字节,那么就像前面一样使用switch语句来设置合适的变量。注意,选项字符被保存到局部变量opt中,这可以避免在switch语句中对**argv进行求值。

注意,使用这种方式时,命令行参数可能只能处理一次,因为指向参数的指针在内层的循环中被破坏。如果必须多次处理参数,则当挨个访问列表时,对每个需要增值的指针都复制一份。在处理选项时还存在其他的可能性。例如,选项可能是一个单词而不是单个字母,或者可能有一些值与某些选项联系在一起,如下面的例子所示:

cc -o prog prog.c

本章的其中一个问题就是对这个思路的扩展。

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

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

相关文章

html5 audio video

DOMException: play() failed because the user didn‘t interact with the document first.-CSDN博客 不可用&#xff1a; 可用&#xff1a; Google Chrome Close AutoUpdate-CSDN博客

用HTML5实现灯笼效果

本文介绍了两种实现效果&#xff1a;一种使用画布&#xff08;canvas&#xff09;标签/元素&#xff0c;另一种不用画布&#xff08;canvas&#xff09;标签/元素主要使用CSS实现。 使用画布&#xff08;canvas&#xff09;标签/元素实现&#xff0c;下面&#xff0c;在画布上…

Compose | UI组件(十四) | Navigation-Data - 页面导航传递数据

文章目录 前言传参流程实例说明普通方式传值定义接受参数格式定义接受参数类型获取参数传入参数传参和接受参数效果图 结合 ViewModel 传递参数定义ViewModel在 navigation 定义 ViewModel 实例&#xff0c;并且传入 LoginScreen传入输入框中的值&#xff0c;并且跳转传值获取值…

Spring Authorization Server Spring Security密码加密

文章目录 一、修改密码编码器二、效果三、注意点1. RegisteredClient2. UserDetailsService 一、修改密码编码器 以BCryptPasswordEncoder举例。 直接将其注册成PasswordEncoder 的Bean即可。 Beanpublic PasswordEncoder passwordEncoder() {// 密码为明文方式 // ret…

“智能检测,精准把控。温湿度检测系统,为您的生活带来全方位的健康保障。”#非标协议项目【下】(分文件编程)

“智能检测&#xff0c;精准把控。温湿度检测系统&#xff0c;为您的生活带来全方位的健康保障。”#非标协议项目【下】&#xff08;分文件编程&#xff09; 前言预备知识1温湿度检测系统需求2.分文件编程核心思路3.分文件编程操作4利用分文件操作建立uart.c、lcd1602.c、dht11…

【图形图像的C++ 实现 01/20】 2D 和 3D 贝塞尔曲线

目录 一、说明二、贝塞尔曲线特征三、模拟四、全部代码如下​五、资源和下载 一、说明 以下文章介绍了用 C 计算和绘制的贝塞尔曲线&#xff08;2D 和 3D&#xff09;。    贝塞尔曲线具有出色的数学能力来计算路径&#xff08;从起点到目的地点的曲线&#xff09;。曲线的形…

YOLOv8改进 | 检测头篇 | 独创RFAHead检测头超分辨率重构检测头(适用Pose、分割、目标检测)

一、本文介绍 本文给大家带来的改进机制是RFAHead,该检测头为我独家全网首发,本文主要利用将空间注意力机制与卷积操作相结合的卷积RFAConv来优化检测头,其核心在于优化卷积核的工作方式,特别是在处理感受野内的空间特征时。RFAConv主要的优点就是增加模型的特征提取能力,…

HiveSQL——sum(if()) 条件累加

注&#xff1a;参考文章&#xff1a; HiveSql面试题10--sum(if)统计问题_hive sum if-CSDN博客文章浏览阅读5.8k次&#xff0c;点赞6次&#xff0c;收藏19次。0 需求分析t_order表结构字段名含义oid订单编号uid用户idotime订单时间&#xff08;yyyy-MM-dd&#xff09;oamount订…

ChatGPT高效提问—prompt常见用法(续篇七)

ChatGPT高效提问—prompt常见用法&#xff08;续篇七&#xff09; 1.1 零样本、单样本和多样本 ​ ChatGPT拥有令人惊叹的功能和能力&#xff0c;允许用户自由向其提问&#xff0c;无须提供任何具体的示例样本&#xff0c;就可以获得精准的回答。这种特性被称为零样本&#x…

PWM输入输出

PWM&#xff08;Pulse Width Modulation&#xff09;即脉冲宽度调制&#xff0c;在具有惯性的系统中&#xff0c;可以通过对一系列脉冲的宽度进行制&#xff0c;来等效地获得所需要的模拟参量&#xff0c;常应用于电机控速、开关电源等领域。 PWM参数 PWM 中有三个重要参数&…

如何开始深度学习,从实践开始

将“如何开始深度学习”这个问题喂给ChatGPT和文心一言&#xff0c;会给出很有专业水准的答案&#xff0c;比如&#xff1a; 要开始深度学习&#xff0c;你可以遵循以下步骤&#xff1a; 学习Python编程语言的基础知识&#xff0c;因为它在深度学习框架中经常被使用。 熟悉线性…

基于tomcat运行jenkins常见的报错处理

目录 1.jenkins.util.SystemProperties$Listener错误 升级jdk11可能遇到的坑 2.java.lang.RuntimeException: Fontconfig head is null, check your fonts or fonts configuration 3.There were errors checking the update sites: UnknownHostException:updates.jenkins.i…

03 动力云客项目之登录功能后端实现

1 准备工作 1.1 创建项目 使用Spring initializr初始化项目 老师讲的是3.2.0, 但小版本之间问题应该不大. 1.2 项目结构 根据阿里巴巴Java开发手册确定项目结构 1.3 分层领域模型 【参考】分层领域模型规约&#xff1a; • DO&#xff08;Data Object&#xff09;&am…

(四)elasticsearch 源码之索引流程分析

https://www.cnblogs.com/darcy-yuan/p/17024341.html 1.概览 前面我们讨论了es是如何启动&#xff0c;本文研究下es是如何索引文档的。 下面是启动流程图&#xff0c;我们按照流程图的顺序依次描述。 其中主要类的关系如下: 2. 索引流程 (primary) 我们用postman发送请求&…

【正式】今年第一篇CSDN(纯技术教学)

一、文件上传简介 文件上传漏洞是指用户上传了一个可执行的脚本文件&#xff08;木马、病毒、恶意脚本、webshell等&#xff09;&#xff0c;并通过此脚本文件获得了执行服务器端命令的能力。上传点一般出现在头像、导入数据、上传压缩包等地方&#xff0c;由于程序对用户上传…

Vue2中v-for 与 v-if 的优先级

在Vue2中&#xff0c;v-for 和 v-if 是常用的指令&#xff0c;它们在前端开发中非常有用。但是&#xff0c;当我们在同一个元素上同时使用这两个指令时&#xff0c;就需要注意它们的优先级关系了。 首先&#xff0c;让我们了解一下v-for和v-if的基本用法。 v-for 是Vue的内置…

Leetcode 213 打家劫舍 II

题意理解&#xff1a; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房屋是紧挨着的。同时&#xff0c;相邻的房屋装有相互连通的防盗系统&#xff0c;如果…

three.js 向量方向(归一化.normalize)

效果&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><div><p><el-button type"primary…

Web后端开发:事务与AOP

事务管理 在学习数据库时&#xff0c;讲到&#xff1a;事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位。事务会把所有的操作作为一个整体&#xff0c;一起向数据库提交或者是撤销操作请求&#xff0c;要么同时成功&#xff0c;要么同时失败。 事务的操作主要有三…

传输频宽是啥?对网速影响有多大?

频宽&#xff0c;即WIFI频道宽度&#xff0c;又称为WIFI信道宽度&#xff0c;是WiFi Channel width的缩写。从科学的定义来说&#xff0c;Wi-Fi频道宽度&#xff0c;是指Wi-Fi无线信号在频谱上所占用的带宽大小。它决定了Wi-Fi网络的数据传输速率和稳定性&#xff0c;一般有20M…