C语言标准输入标准输出

标准输入

将键盘或终端其他设备的输入存储的位置(自己理解瞎定义的),一般使用'<'操作符告诉操作系统,标准输入的来源,默认情况下从键盘和终端读取数据
eg:./demo < input.txt 表示运行demo程序的数据来源是input.txt文件

标准输出

将显示在屏幕的输出存储的位置(自己理解瞎定义的),一般使用'>'操作符告诉操作系统,标准输出的位置,默认情况下会发送到显示器
eg:./demo > output.txt 表示运行demo程序产生的结果输出到output.txt文件

为什么要使用标准输入,标准输出?

因为一旦有了标准输入,标准输出,就可以重定向标准输入,标准输出,让程序从键盘以外的地方读取数据,往显示器以外的地方写数据

标准输入与标准输出的实例

#include <stdio.h>

int main()
{
    float latitude;
    float longitude;
    char info[80];

    int started=0;
    puts("data=[");
    while (scanf("%f,%f,%79[^\n]", &latitude, &longitude, info) == 3) {
        if (started) {
            printf(",\n");
        } else {
            started = 1;
        }
        printf("{latitude:%f, longitude:%f, info:'%s'}", latitude, longitude, info);
    }
    puts("\n]");

    return 0;
}

input.txt内容为:
    12.12,22.33,speed=21
    33.33,45.21,speed=24
    12.44,55.32,seppd=44
    11.55,44.33,speed=22
    423.63182,-71.095833,speed=22
    28.345,-74.232,speed=44

以上程序在tool.c的文件中,gcc tool.c -o tool && ./tool < input.txt > output.txt
程序的标准输入是input.txt文件,标准输出到了output.txt文件

如果程序出错了如何看到结果?

程序执行完之后再终端输入:echo $?
如果返回结果是0代表正常执行,如果返回结果是其他值,就是程序中报错的值(main函数正常返回0)

如果其中一条数据出错了怎么办?终止程序的运行,错误的信息也写入到了output.txt?

我们需要将正常输出和异常输出分开来

标准错误

将错误的信息输出的位置,一般使用fprintf(stderr,msg)进行输出
例子:
    #include <stdio.h>

    int main()
    {
        float latitude;
        float longitude;
        char info[80];
        int started = 0;

        puts("data=[");
        while (scanf("%f,%f,%79[^\n]", &latitude, &longitude, info) == 3) {
            if (started) {
                printf(",\n");
            } else {
                started = 1;
            }

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

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

            printf("{latitude:%f, longitude:%f, info:'%s'}", latitude, longitude, info);
        }
        puts("\n]");
        return 0;
    }

    以上程序在tool.c的文件中,gcc tool.c -o tool && ./tool < input.txt > output.txt
    程序的标准输入是input.txt文件,标准输出到了output.txt文件,标准错误输出到了终端的显示界面上

管道

将一个进程的标准输出与另一个进程的标准输入连接起来。用符号'|'表示

一个例子:
    #include <stdio.h>

    int main()
    {
        float latitude;
        float longitude;
        char info[80];
        while(scanf("%f, %f, %79[^\n]", &latitude, &longitude, info) == 3) {
            if ((latitude > 26) && (latitude < 34)) {
                if ((longitude > -76) && (longitude < -64)) {
                    printf("%f, %f, %s\n", latitude, longitude, info);
                }
            }
        }

        return 0;
    }

    以上程序在filter.c的文件中,gcc filter.c -o filter && (./filter | ./tool < input.txt > output.txt
    程序的标准输入是input.txt文件,标准输出到了output.txt文件,标准错误输出到了终端的显示界面上

如果我需要把数据进行分类输出到多个文件中呢?标准输出和标准错误输出只有两种形式,满足不了需求怎么办?

需要在程序运行时创建自己的数据流

读取数据

FILE *in_file = fopen("input.txt", "r");
fscanf(in_file, "%79[^\n]\n", demo);

写入数据

FILE *out_file = fopen("output.txt", "w");
fprintf(out_file, "this is %s", "demo");

关闭数据流

fclose(in_file);
fclose(out_file);

创建数据流例子

以下是file.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
    argc代表传入函数main的参数的个数
    argv表示实际的参数数组
*/
int main(int argc, char *argv[])
{
    char line[80];

    /*
        argc第0个参数是函数名,所以一共有6个参数
    */
    if (argc != 6) {
        fprintf(stderr, "you need to give 5 arguments\n");
        return 1;
    }

    /*
        注意:一定要是双引号,写别的语言惹的祸
    */
    FILE *in = fopen("spooky.csv", "r");
    FILE *file1 = fopen(argv[2], "w");
    FILE *file2 = fopen(argv[4], "w");
    FILE *file3 = fopen(argv[5], "w");
    /*
        用fscanf读取自定义数据流
    */
    while(fscanf(in, "%79[^\n]\n", line) == 1) {
        if (strstr(line, argv[1])) {
            /*
                用fprintf输出自定义数据流
            */
            fprintf(file1, "%s\n", line);
        } else if (strstr(line, argv[3])) {
            fprintf(file2, "%s\n", line);
        } else {
            fprintf(file3, "%s\n", line);
        }
    }

    fclose(file1);
    fclose(file2);
    fclose(file3);
    return 0;
}

以下是spooky.csv

30.453,-68.1212,Type=Yeti
28.2342,-74.1212,Type=UFO
29.303.-71.1323,Type=Ship
28.1212,-62.2342,Type=Elvis
27.1313,-68.1212,Type=Goatsucker
30.12123,-73.12132,Type=Disappearance
26.121,-71.123213,Type=UFO
29.12,-66.1212,Type=Ship
37.234,-69.23424,Type=Elvis
22.234,-68.23424,Type=Elvis
27.234,-87.23424,Type=Elvis

运行:gcc file.c -o file && ./file UFO aliens.txt Elvis elviss.txt the_rest.txt
会得到多个自定义的输出流:aliens.txt,elviss.txt


# 函数参数的传入太过复杂,该如何处理呢?
    使用unistd.h替代函数参数的处理

# 函数参数处理的例子
    #include <stdio.h>
    #include <unistd.h>

    /*
        argc代表传入函数main的参数的个数
        argv表示实际的参数数组
    */
    int main(int argc, char *argv[])
    {
        char *delivery = "";
        int thick = 0;
        int count = 0;
        char ch;

        while((ch = getopt(argc, argv, "d:t")) != EOF) {
            switch(ch) {
                case 'd':
                    delivery = optarg;
                    break;
                case 't':
                    thick = 1;
                    break;
                default:
                    fprintf(stderr, "Unknow option: '%s'\n", optarg);
                    return 1;
            }
        }

        argc -= optind;
        argv += optind;

        if (thick) {
            puts("thick crust");
        }

        if (delivery[0]) {
            printf("to be delivered %s.\n", delivery);
        }

        puts("Ingredients:");
        for(count = 0; count<argc;count++) {
            puts(argv[count]);
        }
        return 0;
    }

    gcc unistd.c -o unistd
    ./unistd Anchovies Pineapple
    ./unistd -d now Anchovies Pineapple
    ./unistd -d now -t Anchovies Pineapple
    ./unistd -f
坚持原创技术分享,您的支持将鼓励我继续创作!