【问题标题】:C: keyboard and terminal inputC:键盘和终端输入
【发布时间】:2015-03-29 16:54:08
【问题描述】:

我只知道如何用getchar() 读取C 上的字符,并且 到目前为止,我试图不比 K&R 教给我的更进一步。所以 我想知道是否有任何方法可以使我的程序更通用,qsking 用户输入一个或多个值,但仍然 能够阅读非常有用的

c = getchar ()) != EOF 

当我做 1-20 、 1-21 和 1-22 练习时,我意识到我总是 赋予用户无法更改的值,例如:

#define BIG_LINE 16
#define BUFF_SIZE BIG_LINE+2
#define TAB_SIZE 4

等等

有什么方法可以使用

$ ./myprogram < file 

$ cat file | ./myprogram

仍然要求用户输入一个或多个值 getchar() 在这两种情况下?

【问题讨论】:

  • 对不起,这个问题似乎不清楚。请总结并突出显示您要提出的实际问题。
  • 是的,有办法。多做练习,你会发现的。

标签: c input


【解决方案1】:

没有。您给出的两个示例命令(./myprogram &lt; filecat file | ./myprogram)都指定程序的标准输入管道将用于读取文件,因此 getchar() 将仅从该文件中检索字符,它不能用于从用户那里获取交互式输入。

也许您应该问一个更一般的问题,例如“是否可以编写一个 C 程序来从文件中读取数据并提供一个交互式命令行用户界面,包括提示用户和获取响应?”如果这是您想要做的,您可以使用 C 函数 open()fopen() 打开输入文件的句柄,同时仍然使用标准输入管道和 getchar() 从用户获取交互式输入.

您需要告诉您的程序要打开的文件的路径。该路径可以在程序中进行硬编码,也可以来自环境变量,或者可以作为命令行参数提供(例如,您可以使用 ./myprogram file 运行它)。

【讨论】:

    【解决方案2】:

    由于您似乎使用的是 UNIX-y 系统,您通常可以这样做,而不是直接使用 getchar() 和朋友,而是使用其他带有文件指针的 stdio 函数(例如 fgets()getc() ,等等),如果你创建这样一个指向你的终端的指针。

    例如,下面的程序:

    #define _POSIX_C_SOURCE 200809L
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #define BUFSIZE 1024
    
    /*  Returns a file pointer to the terminal, exits on failure  */
    
    FILE * get_terminal(void)
    {
        char * tname = ctermid(NULL);
    
        int fd = open(tname, O_RDWR);
        if ( fd == -1 ) {
            perror("couldn't open terminal");
            exit(EXIT_FAILURE);
        }
    
        FILE * fp = fdopen(fd, "r+");
        if ( !fp ) {
            fprintf(stderr, "couldn't make file pointer\n");
            exit(EXIT_FAILURE);
        }
    
        return fp;
    }
    
    /*  Closes a file pointer to the terminal  */
    
    void close_terminal(FILE * fp)
    {
        if ( fclose(fp) == EOF ) {
            perror("couldn't close terminal");
            exit(EXIT_FAILURE);
        }
    }
    
    /*  Main function  */
    
    int main(void)
    {
        FILE * fp = get_terminal();
    
        char buffer[BUFSIZE];
    
        /*  Get line from stdin and print to stdout  */
    
        fgets(buffer, BUFSIZE, stdin);
        fprintf(stdout, "Line 1: %s", buffer, stdout);
    
        /*  Get string from terminal and print to terminal  */
    
        fputs("Enter a string: ", fp);
        fflush(fp);
        fgets(buffer, BUFSIZE, fp);
        fprintf(fp, "You entered: %s", buffer);
    
        /*  Get another line from stdin and print to stdout  */
    
        fgets(buffer, BUFSIZE, stdin);
        fprintf(stdout, "Line 2: %s", buffer, stdout);
    
        close_terminal(fp);
    
        return 0;
    }
    

    即使您的 shell 重定向程序的标准输入和标准输出,也会提供以下输出:

    paul@thoth:~/src/sandbox$ cat input.txt
    This is the first line of the file.
    This is the second line of the file.
    
    paul@thoth:~/src/sandbox$ ./prog < input.txt > output.txt
    Enter a string: This is my string.
    You entered: This is my string.
    paul@thoth:~/src/sandbox$ cat output.txt
    Line 1: This is the first line of the file.
    Line 2: This is the second line of the file.
    paul@thoth:~/src/sandbox$ 
    

    请注意,ctermid() 生成的内容不能保证唯一标识终端(事实上,在大多数系统上不会 - 它通常是 /dev/tty)并且不能保证您能够打开它.但它可能会在现代 UNIX-y 个人计算机上运行。

    您是否应该这样做完全是另一个问题。在绝大多数情况下,这将是非常不寻常和意想不到的行为。如果您希望用户能够指定诸如制表位大小之类的选项,则使用命令行参数将是比交互式获取更好的解决方案,例如:

    ./prog --tabstop=4 < input.txt > output.txt
    

    K&R 在 5.10 节中介绍了命令行参数,getopt 库是使用它们的一种常见且简单的方法。

    对于更持久的选项,使用配置文件甚至读取环境变量是其他潜在的解决方案。

    显然以上所有内容都比 K&R 的第 1 章要先进得多,但是既然你说“我尽量不走得比 K&R 迄今为止教给我的更远”,然后立即问如何比 K&R 走得更远教你到目前为止,这就是即将发生的事情。就您而言,目前最好的选择就是完成其余章节,并且在您读完之前,您将回答大部分问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 2015-02-10
      • 2021-10-18
      • 2017-12-04
      • 2013-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多