C语言基础(2)—小工具


C语言小工具可以实现控制命令行选项、操纵信息流、重定向,可以根据自己的需求来创建自己的小工具,如果想要完成更复杂的任务,可以把多个工具链接在一起。

重定向

一般情况下,我们可以在某些特定的情境下,使用重定向这一小技巧,比如我们想用文件内容来代替键盘显示器的输入输出,在用scanf()从键盘读取数据、printf()向显示器写数据时,这两个函数其实并没有直接使用键盘、显示器,而是用了标准输入和标准输出。程序运行时,操作系统会创建标准输入和标准输出。操作系统之所以要使用标准输入、标准输出与程序交互是因为这么一来,就可以重定向标准输入、标准输出,让程序从键盘以外的地方读数据、往显示器以外的地方写数据,例如文件。

在这里插入图片描述

重定向标准输入的方法

可以用<来重定向标准输入,不必再使用键盘了,而是可以直接用<从文件中读取数据,如> ./geo2json < gpsdata.csv<操作符告诉操作系统,程序的标准输入应该与gpsdata.csv文件相连,而不是键盘,所以可以把数据从文件发送到程序。

重定向标准输出的方法

可以用>来重定向标准输出,如> ./geo2json < gpsdata.csv > output.json此时运行该代码,屏幕上没有出现任何数据,程序现在创建了一个叫output.json的文件。

fprintf()和fscanf()

我们都知道printf()函数可以将数据发送到标准输出,但printf()其实只是一个函数的特例,而这个函数叫fprintf(),从下面几个方面来简单谈一下,为接下来的内容做铺垫:

  • 基本用法:fprintf 的基本作用是将格式化的数据输出到指定的文件流。它的原型为 int fprintf(FILE *stream, const char *format, …), 其中 stream 是指向 FILE 类型的指针,表示输出的目标文件,format 是格式化字符串,后面跟随的是可变参数列​​​​​​。

  • 格式化输出:fprintf 使用与 printf 相同的格式化字符串规则。这意味着你可以使用 %d、%s、%f 等格式化占位符来指定输出数据的格​​​​​​。

  • 返回值:成功时,fprintf 返回写入的字符数,失败时返回负​​。

  • 文件指针:fprintf 需要一个文件指针 FILE* 作为其第一个参数,这个文件指针指向要写入数据的文件。你可以使用 fopen 函数获取这个文件指​​​​。

  • 错误处理:在使用 fprintf 时,应检查其返回值以确认数据是否正确写入。如果返回值是负数,则表明写入过程中出现了错​​。

  • 应用场景:fprintf 通常用于将数据保存到文件中,例如保存程序的日志、输出程序结果​​。

在这里插入图片描述

fscanf()和fprintf()相似,fscanf与scanf的区别在于打印到数据流的部分,换句话说scanf()就是用fscanf(stdin, …)标准输入实现的。

标准错误

标准输出是程序输出数据的默认方式,他无法区分错误消息和普通输出,这时就需要标准错误来加以区分,标准错误就是用来发送错误消息的二号输出,他的优点在于不论标准输入、标准输出定位到屏幕还是文件,他都会将错误数据发送到屏幕上;
在了解了fprintf()之后,我们就可以开始实现标准错误了,

if ((latitude < -90.0) || (latitude > 90.0)) {
 printf("Invalid latitude: %f\n", latitude);
 return 2;
 }

上面这样的代码我们就可以修改成,从而就可以实现分流了

if ((latitude < -90.0) || (latitude > 90.0)) {
fprintf(stderr, "Invalid latitude: %f\n", latitude);
return 2;
}

同样的,可以用2>来重定向标准错误,实现对标准错误的按要求更改;

工具的并用

当我们需要同时使用多个工具时,就需要一个纽带将他们连接起来,这个纽带就是管道,符号 | 表示管道(pipe),它能连接一个进程的标准输出与另一个进程的标准输入。两个独立的程序用管道连接以后就可以看成一个程序,可以重定向它的标准输入和标准输出,> (./bermuda | ./geo2json) < spooky.csv > output.json

输出多个文件

假设你需要创建另一个工具,它从文件中读取一批数据,然后将数据分类,写到多个文件,但不能写多个文件。使用重定向最多也只能写两个文件,一个标准输出,一个标准错误,这个时候就需要创建自己的数据流每条数据流用一个指向文件的指针来表示,可以用fopen()函数创建新数据流。
在这里插入图片描述
fopen()函数接收两个参数:文件名和模式。共有三种模式,分别是w(写文件)、r(读文件)与a(在文件末尾追加数据)。创建数据流后,可以用fprintf()往数据流中打印数据。如果想要从文件中读取数据,则可以用fscanf()函数:

fprintf(out_file, "不要穿 %s 色的衣服和 %s 色的裤子 ”, ”红 ”, ”绿 ”);
fscanf(in_file, "%79[^\n]\n", sentence);

最后,当用完数据流,别忘了关闭它。虽然所有的数据流在程
序结束后都会自动关闭,但你仍应该自己关闭它们:

fclose(in_file);
fclose(out_file);

tips: 你在程序中打开
文件准备读写时,最好检查一下有没有错误发生。好在如果数据流打开失败,fopen()函数会返回0,也就是说如果想检查错误,可以将下面这段代码:
FILE *in = fopen("我不存在.txt", "r");
改成这样:

FILE *in;
 if (!(in = fopen("我不存在.txt", "r"))) {
fprintf(stderr, "无法打开文件.\n");
 return 1;
 }

命令行选项

命令行选项是一些小开关,它们经常出现在命令行工具中:

ps -ae
tail -f logfile.out

很多程序都会使用命令行选项,因此有一个专门的库函数,可以用它来简化处理过程。这个库函数叫getopt(),每一次调用都会返回命令行中下一个参数。

getopt() 方法是用来分析命令行参数的,该方法由 Unix 标准库提供,包含在<unistd.h> 头文件中。

基本结构

int getopt(int argc, char * const argv[]);
 
extern char *optarg;
extern int optind, opterr, optopt;

getopt 参数说明:

argc:通常由 main 函数直接传入,表示参数的数量
argv:通常也由 main 函数直接传入,表示参数的字符串变量数组

外部变量说明:

optarg:如果某个选项有参数,这包含当前选项的参数字符串
optind:argv 的当前索引值
opterr:正常运行状态下为 0。非零时表示存在无效选项或者缺少选项参数,并输出其错误信息
optopt:当发现无效选项字符时,即 getopt() 方法返回 ? 字符,optopt 中包含的就是发现的无效选项字符

详细剖析

假如我们写了个C语言程序,name.c,内容如下:

#include <stdio.h>
#include <unistd.h>
 
int main(int argc, char *argv[]) {
    int o;
    const char *optstring = "abc:"; // 有三个选项-abc,其中c选项后有冒号,所以后面必须有参数
    while ((o = getopt(argc, argv, optstring)) != -1) {
        switch (o) {
            case 'a':
                printf("opt is a, oprarg is: %s\n", optarg);
                break;
            case 'b':
                printf("opt is b, oprarg is: %s\n", optarg);
                break;
            case 'c':
                printf("opt is c, oprarg is: %s\n", optarg);
                break;
            case '?':
                printf("error optopt: %c\n", optopt);
                printf("error opterr: %d\n", opterr);
                break;
        }
    }
    return 0;
}

编译运行后

gcc name.c -o name
./name -a -b -c afei
opt is a, oprarg is:(null)
opt is b, oprarg is:(null)
opt is c, oprarg is: afei
./name -abc
opt is a, oprarg is:(null)
opt is b, oprarg is:(null)
./name: option requires an argument --'c'
error optopt:c
error opterr: 1
./name -d/name:invalid option--d
error optopt:d
error opterr:1

命令 gcc OptDemo.c -o OptDemo 是使用 gcc 把 OptDemo.c 编译成可执行程序,命名为 OptDemo

第一次运行 ./name -a -b -c afei 正常执行和输出

第二次运行 ./name -abc 由于选项 c 后没有输入参数,于是报错

第三次运行 ./name -d 由于选项 d 不是我们在 optstring 中预定义的选项,于是报错



看完上面的内容后我们知道,一个冒号代表后面必须跟上参数,就是得加内容不论是啥,但必须得有,没有参数就会报错。如果有两个冒号的话,那么这个参数就是可选参数了,即可有可没有。

#include <stdio.h>
#include <unistd.h>
 
void usage() {
    printf("Usage:\n");
    printf("\tOptDemo [-a] [-b] [-c message]");
}
 
int main(int argc, char *argv[]) {
    int o;
    const char *optstring = "abc::"; // 有三个选项-abc,其中c选项后有两个冒号,表示后面可选参数
    while ((o = getopt(argc, argv, optstring)) != -1) {
        switch (o) {
            case 'a':
                printf("opt is a, oprarg is: %s\n", optarg);
                break;
            case 'b':
                printf("opt is b, oprarg is: %s\n", optarg);
                break;
            case 'c':
                printf("opt is c, oprarg is: %s\n", optarg);
                break;
            case '?':
                printf("发生错误时提示用户正确的使用方式\n");
                usage(); // 提示使用说明
                break;
        }
    }
    return 0;
}

编译运行后

gcc name.c -o name
./name -d
/name invalid option--'d发生错误时提示用户正确的使用方式Usage:
name [-a][-b] [-c message]%name
./name-ac哼哼哈嘿opt is a, oprarg is:(null)opt is c, oprarg is:[哼哼哈嘿有空格就不行了呢
 ./name -copt is c,oprarg is:(null)

注意这里 可选参数 选项 -c 后面跟参数的时候,一定不能有空格。

但是如果是 必选参数,即选项后面只有一个冒号,则是有没有空格都可以。

  • 29
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值