肯尼斯·里科《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://xiahunao.cn/news/2776310.html

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

相关文章

在计算机/移动设备上恢复已删除视频的 10 个数据恢复工具

视频在网上疯传&#xff0c;我们都观看或创建视频&#xff0c;并将我们最喜欢的视频保存在硬盘上。如果我们丢失了一些重要的视频&#xff0c;那将是非常令人心碎的。但是今天&#xff0c;恢复已删除的视频变得更加容易。删除的视频在被新数据覆盖之前并没有真正从您的存储驱动…

OpenSSL 创建自签名证书

前言 Openssl 是一个方便的实用程序,用于创建自签名证书。您可以在所有操作系统(如 Windows、MAC 和 Linux 版本)上使用 OpenSSL。 自签名证书 创建我们自己的根 CA 证书和 CA 私钥(我们自己充当 CA)创建服务器私钥以生成 CSR使用我们的根 CA 和 CA 私钥创建具有 CSR 的…

Redis 单线程

文章目录 Redis单线程架构Redis 单线程访问速度IO多路复用原理 Redis单线程架构 Redis的单线程架构的效果为&#xff1a;Redis的单线程是对于服务端而言的&#xff0c;Redis允许多个Redis用户端同时在线操作&#xff0c;但同时只有一个用户端在和服务端交互。多个用户同时发送…

centos7的git使用方法

下载git yum install git git克隆 git clone https...(图片中复制的内容) git提交到远程仓库 git add filename git commit -m "提交日志" git push git首次使用要配置邮箱和用户名 查看提交日志 git log 查看当前提交状态 git status

人力资源智能化管理项目(day04:组织架构)

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/humanResourceIntelligentManagementProject 觉得有帮助的同学&#xff0c;可以点心心支持一下哈 树组件应用 <!-- 展示树形结构 --><!-- default-expand-all默认展开所有节点 --><el-tree default-ex…

黄金交易策略(EA):三个仓位的设计是确保可以不停息做单

完整EA&#xff1a;Nerve Knife.ex4黄金交易策略_黄金趋势ea-CSDN博客

c++ 类的第二章,对象的创建和使用

新年快乐&#xff01;&#xff01;&#xff01;&#xff01; 定义了类&#xff0c;相当于定义了一个数据类型。使用方法和int double是一样的,可以定义变量&#xff0c;数组&#xff0c;指针&#xff0c;而定以后的变量&#xff0c;我们把它叫做这个类的对象。 定义如下&#…

猫头虎分享已解决Bug || 未定义的变量(Undefined Variable):ReferenceError: x is not defined

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

AI创作2024科幻大片《沙丘2》高清宣传片

AI创作2024科幻大片《沙丘2》高清宣传片 "Beyond the vast deserts of Dune, a new threat looms." "The war for control of the universe has just begun." "In the shadows of the great sand dunes, danger waits." "The power of t…

排序算法---快速排序

原创不易&#xff0c;转载请注明出处。欢迎点赞收藏~ 快速排序是一种常用的排序算法&#xff0c;采用分治的策略来进行排序。它的基本思想是选取一个元素作为基准&#xff08;通常是数组中的第一个元素&#xff09;&#xff0c;然后将数组分割成两部分&#xff0c;其中一部分的…

MySQL篇之索引

一、定义 索引&#xff08;index&#xff09;是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff08;B树&#xff09;&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0…

Linux 命令基础

Shell概述 Linux操作系统的Shell作为操作系统的外壳&#xff0c;为用户提供使用操作系统的接口。它是命令语言、命令解释程序及程序设计语言的统称。 Shell是用户和Linux内核之间的接口程序&#xff0c;如果把硬件想象成一个球体的中心&#xff0c;内核围绕在硬件的外层管理着…

【Java八股面试系列】并发编程-并发关键字,线程池

目录 并发关键字 Synchronized synchronized最主要的三种使用方式&#xff1a; 具体使用&#xff1a;双重校验锁单例模式 synchronized 底层实现原理&#xff1f; synchronized锁的优化 偏向锁 轻量级锁 重量级锁 Mark Word 与 Monitor 之间的关系 总结 偏向锁、轻量…

数字IC实践项目(9)— Tang Nano 20K: I2C OLED Driver

Tang Nano 20K: I2C OLED Driver 写在前面的话硬件模块RTL电路和相关资源报告SSD1306 OLED 驱动芯片SSD1306 I2C协议接口OLED 驱动模块RTL综合实现 总结 写在前面的话 之前在逛淘宝的时候偶然发现了Tang Nano 20K&#xff0c;十分感慨国产FPGA替代方案的进步之快&#xff1b;被…

算法------(11)并查集

例题&#xff1a; &#xff08;1&#xff09;Acwing 836.合并集合 并查集就是把每一个集合看成一棵树&#xff0c;记录每个节点的父节点。合并集合就是把一棵树变成另一棵树的子树&#xff0c;即把一棵树的父节点变为另一棵树的父节点的儿子。查询是否在同一集合就是看他们的根…

【 buuctf snake 】

需要用到 Serpent 加密&#xff0c;蛇也不一定是 snake&#xff0c;serpent 也是蛇的意思。 binwalk -e /Users/xxx/Downloads/snake/snake.jpgbinwalk 提取 key 中有 base64 编码&#xff0c;解密 图源自BUUCTF:snake_buuctf snake-CSDN博客 结果是 anaconda&#xff0c;还有…

GC调优工具

1、jstat 2、VisualVM GC tool插件 插件下载地址&#xff1a;https://blog.csdn.net/jushisi/article/details/109655175 3、Prometheus和Grafana监控

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 2月9日,星期五

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年2月9日 星期五 农历腊月三十 除夕 1、 三部门&#xff1a;各地不得挤占、挪用、截留、滞留优抚对象补助经费。 2、 校外培训《条例》出炉&#xff1a;明确在职教师、教研人员不得从事校外培训活动。 3、 2024年“全面降…

(十六)springboot实战——spring securtity的认证流程源码解析

前言 本节内容是关于spring security安全框架认证流程的源码分析&#xff0c;spring security的认证流程主要是在UsernamePasswordAuthenticationFilter过滤器中实现的。我们会通过源码层级的分析&#xff0c;了解清楚spring security的底层是如何实现用户的认证的。 正文 1…

放飞梦想,扬帆起航——1888粉丝福利总结

目录 1.祝福 2.准备 3.抽奖 4.制作 5.添加 6.成果 7.感谢 8.福利 9.祝福 1.祝福 马上就是除夕了&#xff0c;在这里提前预祝大家春节快乐&#xff0c;小芒果在这里给大家拜年了&#xff01; 2.准备 其实很早之前我就在幻想着哪一天我的粉丝量能突破1888&#xff0c;…