从 C 中的 stdin 识别空行

问题描述 投票:0回答:2

我在尝试识别 C 中标准输入上的空行时遇到了一些困难。我有以下代码:

char *line = NULL;
int done = 0;
while (!done) {
   scanf("%m[^\n]", &line);
   if (line != NULL)
      //do something with line
   else
      done = 1;
scanf("\n");
free(line);

这些行应该是用户的命令。假设他只允许打电话

insert something
delete something

exit

在任何其他情况下,程序都应该输出,比如说“命令不允许”。在每种情况下我都可以做到这一点,除了一种情况 - 当输入上有空行时 - 我不知道如何识别它。我希望能得到一些帮助。

c parsing input
2个回答
3
投票

不要使用

scanf()
,而是使用
fgets()
或 *nix
getline()

scanf()
旨在读取格式化数据 - 它与 lines 配合使用效果稍好。
fgets()
旨在读取 line(0 个或更多字符,直至并包括最后的
'\n'
),并通过将空字符
'\0'
附加到目标缓冲区将其转换为 C 字符串。

char line[100];
while (!done) {
  // scanf("%m[^\n]", &line);
  if (fgets(line, sizeof line, stdin) == NULL) {
    // EOF or input error occurred, for now let us just clear line
    line[0] = 0; 
  }
  // get rid of potential trailing \n
  line[strcspn(line, "\n")] = 0;
  if (line[0]) 
    //do something with line
  else
    done = 1;
} 

m
中的
"%m[^\n]"
在C规范中没有指定。它是一些 C 库使用的扩展。


2
投票

此答案中的所有信息均摘自

man scanf

%[
格式代码不会匹配空字符串:

[
匹配指定接受字符集中的非空序列字符

记住

scanf
有一个非常有用的返回值:

这些函数返回成功匹配和分配的输入项的数量,该数量可能少于提供的数量,如果早期匹配失败,甚至为零。

您应该始终检查 scanf 的返回值,因为如果无法成功匹配相应的输入项,则输出参数具有未指定的值。

在这种情况下,返回值将告诉您换行符前面是否有非空字符串。


如所示,您的代码存在内存泄漏(假设读取了不止一行),因为

m
修饰符会导致分配内存,而不会查看最初存储在相应参数中的值。因此,如果参数保存了先前分配的存储的地址,它将被新分配的存储的地址覆盖,并且先前的分配将会泄漏。

循环应该是:

while (!done) {
  line = NULL; /* Not strictly necessary */
  if (scanf("%m[^\n]", &line) == 1) {
    /* Do something with line */
    free(line);
  } else {
    /* Handle an empty line */
  }
  /* skip trailing newline. See below. */
  getchar();
}

scanf("\n")
不仅仅跳过单个换行符。与
scanf(" ")
没有什么不同; scanf 格式中的任何空格:

匹配输入中任意数量的空格,包括无空格。

如果您只想跳过单个换行符,请使用

getchar()

© www.soinside.com 2019 - 2024. All rights reserved.