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

news2025/1/20 11:01:22

处理命令行参数是指向指针的指针的另一个用武之地。有些操作系统,包括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.coloradmin.cn/o/1441607.html

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

相关文章

BestEdrOfTheMarket:一个针对AVEDR绕过的训练学习环境

关于BestEdrOfTheMarket BestEdrOfTheMarket是一个针对AV/EDR绕过的训练学习环境&#xff0c;广大研究人员和信息安全爱好者可以使用该项目研究和学习跟AV和EDR绕过相关的技术知识。 支持绕过的防御技术 1、多层API钩子&#xff1b; 2、SSH钩子&#xff1b; 3、IAT钩子&#x…

比较6*6范围内7个点182个结构的顺序

( A, B )---6*30*2---( 1, 0 )( 0, 1 ) 让网络的输入有6个节点&#xff0c;训练集AB各由6张二值化的图片组成&#xff0c;让A中有7个点&#xff0c;让B全是0&#xff0c;收敛误差7e-4&#xff0c;收敛199次&#xff0c;统计迭代次数平均值并排序。 得到顺序为 用6个点的结构标…

【开源】JAVA+Vue.js实现在线课程教学系统

目录 一、摘要1.1 系统介绍1.2 项目录屏 二、研究内容2.1 课程类型管理模块2.2 课程管理模块2.3 课时管理模块2.4 课程交互模块2.5 系统基础模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示4.1 管理后台4.2 用户网页 五、样例代码5.1 新增课程类型5.2 网站登录5.3 课…

初识NodeJS

本文主要基于极客时间《Nodejs开发实战》课程。 本篇&#xff08;一&#xff09;为课程的第二篇——技术预研篇。 什么是Nodejs? 来源官网&#xff1a; Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型&#x…

备战蓝桥杯---动态规划(基础1)

先看几道比较简单的题&#xff1a; 直接f[i][j]f[i-1][j]f[i][j-1]即可&#xff08;注意有马的地方赋值为0&#xff09; 下面是递推循环方式实现的AC代码&#xff1a; #include<bits/stdc.h> using namespace std; #define int long long int a[30][30]; int n,m,x,y; …

HTTP2:netty http2 StreamChannel多流实现与Http2StreamFrame解码器的源码分析

netty http2 server侧的核心逻辑个人认为&#xff0c;主要在编解码处理器和Stream Transform Channel这块&#xff0c;分别处理Http2 消息帧的编解码&#xff0c;以及连接的多流处理机制。对应用的处理类分别&#xff1a; ChannelHandlerDescio.netty.handler.codec.http2.Htt…

vue 引入 百度地图API 和 路书

公司项目中&#xff0c;偶尔都会涉及到地图的使用&#xff0c;这里以百度地图为例&#xff0c;我们梳理一下引用流程及注意点 账号和获取密钥 百度地图示例 百度地图 类参考 1、账号和获取密钥 // api.map.baidu.com/api?typewebgl&v3.0&ak您的密钥<script type…

宋小黑原创高清壁纸分享之蓝白云海

大家好&#xff0c;我是小黑&#xff0c;最近迷上了制作壁纸&#xff0c;哈哈&#xff0c;给大家分享一波&#xff0c;小黑做的美图~ 本期给大家分享的是&#xff0c;小黑原创的蓝白云海主题系统壁纸~ 厌倦了一成不变的壁纸吗&#xff1f; 感到学习负担过重吗&#xff1f; …

肯尼斯·里科《C和指针》第13章 高级指针话题(1)进一步探讨指向指针的指针变量的高级声明

13.1 进一步探讨指向指针的指针 上一章使用了指向指针的指针&#xff0c;用于简化向单链表插入新值的函数。另外还存在许多领域&#xff0c;指向指针的指针可以在其中发挥重要的作用。这里有一个通用的例子&#xff1a; 这些声明在内存中创建了下列变量。如果它们是自动变量&am…

6.0 Zookeeper session 基本原理详解教程

客户端与服务端之间的连接是基于 TCP 长连接&#xff0c;client 端连接 server 端默认的 2181 端口&#xff0c;也就 是 session 会话。 从第一次连接建立开始&#xff0c;客户端开始会话的生命周期&#xff0c;客户端向服务端的ping包请求&#xff0c;每个会话都可以设置一个…

python列表推导式(List Comprehension)

目录 1. 介绍&#xff1a;2. 示例3. 过滤功能4. 多重循环小结&#xff1a; 1. 介绍&#xff1a; 列表推导式是 Python 中一种简洁的语法形式&#xff0c;用于从一个可迭代对象中生成新的列表。它的语法形式为 [expression for item in iterable]&#xff0c;其中expression是一…

【Larry】英语学习笔记语法篇——从句=连词+简单句

目录 三、从句连词简单句 1、必须有连词 主从结构 疑问词的词性 2、名词性从句 同位语从句 形式主语 形式宾语 that的省略 3、形容词性从句&#xff08;上&#xff09; 关系代词 关系词的作用 介词前置问题 4、形容词性从句&#xff08;中&#xff09; 定语关系…

(十四)springboot实战——spring securtity安全框架原理之启动流程

前言 本节内容主要介绍spring securtity的初始化启动流程&#xff0c;spring security是通过EnableWebSecurity注解来启用的&#xff0c;在EnableWebSecurity注解中主要引入了WebSecurityConfiguration、SpringWebMvcImportSelector、OAuth2ImportSelector、HttpSecurityConfi…

光耦固态继电器:2024年发展之路

随着科技的迅猛发展&#xff0c;光耦固态继电器在2024年面临着独特的机遇与挑战。本文将深入分析光耦固态继电器行业的现状&#xff0c;探讨其在技术创新、市场需求等方面的机遇和挑战。 光耦固态继电器技术创新的机遇&#xff1a; 光耦固态继电器作为电气控制领域的关键元件&…

leetcode(哈希表)49.字母异位词分组(C++详细解释)DAY5

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 示例 1: 输入: strs [“eat”, “tea”…

请手写几种js排序算法

什么是排序算法 冒泡排序选择排序插入排序快速排序归并排序&#xff08;Merge Sort&#xff09; 思想实现测试分析动画 快速排序 &#xff08;Quick Sort&#xff09; 思想实现测试分析动画 思考&#xff1a;快排和归并用的都是分治思想&#xff0c;递推公式和递归代码也非常相…

RCE(命令执行)知识点总结最详细

description: 这里是CTF做题时常见的会遇见的RCE的漏洞知识点总结。 如果你觉得写得好并且想看更多web知识的话可以去gitbook.22kaka.fun去看&#xff0c;上面是我写的一本关于web学习的一个gitbook&#xff0c;当然如果你能去我的github为我的这个项目点亮星星我会感激不尽htt…

MaxKey 单点登录认证系统——前端后端合并步骤

开发指南 | MaxKey单点登录认证系统 该项目前端是Angular项目&#xff0c;后端是springboot项目 以maxkey-web-app前后端合并为例 构建MaxKey统一认证前端 maxkey-web-frontend/maxkey-web-app ng build --prod --base-href /sign/static/以上sign由以下得来&#xff1a; 根…

Ubuntu22.04 gnome-builder gnome C 应用程序习练笔记(一)

一、序言 gnome-builder构建器是gnome程序开发的集成环境&#xff0c;支持主力语言C, C, Vala, jscript, python等&#xff0c;界面以最新的 gtk 4.12 为主力&#xff0c;将其下版本的gtk直接压入了depreciated&#xff0c;但gtk4.12与普遍使用的gtk3有很大区别&#xff0c;原…

问题:银行账号建立以后,一般需要维护哪些设置,不包括() #学习方法#经验分享

问题&#xff1a;银行账号建立以后&#xff0c;一般需要维护哪些设置&#xff0c;不包括&#xff08;&#xff09; A&#xff0e;维护结算科目对照 B&#xff0e;期初余额初始化刷 C&#xff0e;自定义转账定义 D&#xff0e;对账单初始化 参考答案如图所示