【问题标题】:How to create an input loop?如何创建输入循环?
【发布时间】:2015-05-15 01:04:35
【问题描述】:

我正在寻找一种方法来编写一个输入循环,该循环继续打印提示,直到用户输入一个空行。

这就是我想做的:

循环开始,将提示符> 打印到命令行。用户输入以 '\n' 结尾的行,我的程序对该行执行任何操作,然后再次打印 >。这一直持续到用户输入一个空行 (\n),此时循环终止。

【问题讨论】:

  • 使用递归更好,因为它使代码更简单。但是,它也使代码更难读。
  • @QuipYowert 不,不是。如果用户输入 100,000 行怎么办?一个简单的while 循环可以轻松处理这种情况,而递归程序可能会因为递归太深(导致堆栈溢出和分段错误)而崩溃。
  • @QuipYowert:当一个简单的循环就可以了,为什么要递归?
  • 这样的话,我还不如写一个贝叶斯静态分析程序来捕捉segfaults。 (在 Haskell 中)

标签: c loops input


【解决方案1】:

这些方面的东西会满足您的需求吗?

int ret;
// Basically, in order, 1 to indicate the file descriptor of the standard output
// ">" as the string you want to print
// 1 as the number of characters you want printed.
write(1, ">", 1);
while ((ret = read(0, buff, SizeBuff)) > 0) {
    buff[ret] = 0;
    if (buff[0] == '\n' && strlen(buff) == 1)
        return (0);
    /*Do your stuff*/
    write(1, ">", 1);
} 

【讨论】:

  • 您能解释一下这是如何工作的吗?我认为 write() 用于文件,而不是命令行打印。
  • @PythonNewb 注释在代码中,简单解释写入参数。如果还有其他问题,尽管问。
  • 既然有printf,为什么还要write? (在这种情况下,后跟fflush 以确保出现提示。或者write 不需要刷新?)
  • @Jongware 为什么要写作?因为我们想要一个角色。算了。为什么调用 printf 然后为 one 字符调用 flush ?写会写任何发生的事情。我通常发现它比 printf 更可靠。除非您正在格式化。 :-) 哦,我也更喜欢尽可能使用基本调用。 Printf 甚至在开始考虑它必须打印什么之前就初始化了 va-args。
  • @Jongware 实际上......现在我刚刚写了那个,你到底为什么要使用 printf? O_o
【解决方案2】:

也可以使用很简单的scanf版本:

#include <stdio.h>

#define MAXL 64

int main (void) {

    char str[MAXL] = {0};

    printf ("\n Enter a string ([enter] alone to quit)\n");

    while (printf (" > ") && scanf ("%63[^\n]%*c", str) == 1)
    {
        /* do whatever in your code */
        printf ("   result: %s\n", str);
    }

    return 0;
}

使用/输出

$ ./bin/scanf_enter_quits

 Enter a string ([enter] alone to quit)
 > string
   result: string
 > another
   result: another
 >

注意: MAXL-1 添加为 scanf 的最大宽度说明符,以防止写入超出数组末尾。


getline 示例

getline 通过动态分配行缓冲区允许你接受一行,只要你想给它。它可以是数十亿个字符(取决于您的记忆范围)。这是一个优势和一个弱点。如果您需要限制您接受的数据量,则由您来检查/验证/等....

#include <stdio.h>
#include <stdlib.h>

int main (void) {

    char *str = NULL;
    size_t n = 0;
    ssize_t nchr = 0;

    printf ("\n Enter a string ([enter] alone to quit)\n");

    while (printf (" > ") && (nchr = getline (&str, &n, stdin)) > 1)
    {
        str[--nchr] = 0;                /* strip newline from input */
        printf ("   (str: %s)\n", str); /* do whatever in your code */
    }

    if (str) free (str);

    return 0;
}

使用/输出

$ ./bin/getline_enter_quits

 Enter a string ([enter] alone to quit)
 > string one as long as you want
   (str: string one as long as you want)
 > string 2 make it 1000 chars.........................................
   (str: string 2 make it 1000 chars.........................................)
 >

scanf动态分配

您还可以让scanf 使用m 转换说明符为您动态分配空间(scanf 的旧版本为此使用a 转换说明符)。在这种情况下,您还必须提供 pointer-to-pointer 以接受该地址。 (例如scanf ("%m[^\n]%*c", &amp;str))。

#包括 #包括

int main (void) {

    char *str = NULL;

    printf ("\n Enter a string ([enter] alone to quit)\n");

    while (printf (" > ") && scanf ("%m[^\n]%*c", &str) == 1)
    {
        printf ("   (str: %s)\n", str); /* do whatever in your code */
        if (str) free (str);            /* you must free each loop  */
        str = NULL;
    }

    if (str) free (str);

    return 0;
}

使用/输出

$ ./bin/scanf_dyn_enter_quits

 Enter a string ([enter] alone to quit)
 > some string as long as you want
   (str: some string as long as you want)
 > another string any length .......... ............. .............
   (str: another string any length .......... ............. .............)
 >

【讨论】:

  • 也许使用fgets 而不是scanf?这样您就不必担心缓冲区溢出,也不必将长度硬编码到格式字符串中。
  • 是的,但是我需要包含代码以从行缓冲区中删除换行符。这是一个权衡。我用scanffgetsgetline 来做。都有优点和缺点...scanf 是迄今为止最简单的一次性提示情况。
  • @DavidC.Rankin 如果我不知道用户输入的字符串有多长,我该如何更改您的代码来解决这个问题?我会在用户输入他们的输入后简单地mallocstr 吗?
  • 简单,使用getline。您可以给它数十亿个字符(直到内存不足)。我将添加一个示例。
  • @PythonNewb 我添加了 both 一个getline 示例和一个使用scanf 显示动态分配的示例。您会发现关于哪个更好的竞争观点。 scanf 的实现可能会有所不同,但在过去合理的范围内,任何一个都应该适合您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-03
  • 2017-11-30
  • 1970-01-01
  • 1970-01-01
  • 2017-12-15
  • 2013-10-23
  • 1970-01-01
相关资源
最近更新 更多