如何输入未知大小的字符串

时间:2018-11-02 09:54:44

标签: c visual-studio-2017 scanf

我对C中的字符串有些困惑。我知道声明缓冲区大小很重要,因为否则会导致缓冲区溢出。但是我需要知道如何获取我不知道大小的字符串输入。例如,如果我想从用户那里获取一行文本作为输入,而我却无法知道他们的文本会持续多久,该怎么办?

我已经尝试在用户提供输入时动态分配内存。这是代码-

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

int main()
{
    char *str, ch;
    int size = 10, len = 0;
    str = realloc(NULL, sizeof(char)*size);
    if (!str)return str;
    while (EOF != scanf_s("%c", &ch) && ch != '\n')
    {
        str[len++] = ch;
        if (len == size)
        {
            str = realloc(str, sizeof(char)*(size += 10));
            if (!str)return str;
        }
    }
    str[len] = '\0';
    printf("%s\n", str);
    free(str);
}

问题是,当我使用VS-2017进行编译时,出现这些错误-

  

source.c(10):警告C4473:'scanf_s':传递的参数不足   用于格式字符串

     

source.c(10):注意:占位符及其参数应为2   可变参数,但提供了1个

     

source.c(10):注意:缺少必需的可变参数2   格式字符串'%c'

     

source.c(10):注意:此参数用作缓冲区大小

我认为在继续操作时动态分配内存(就像上面的代码一样)应该可以,但是我可能做错了。有办法使这项工作吗?

编辑:Word。

5 个答案:

答案 0 :(得分:4)

  1. 您应该使用getchar而不是scanf_s
  2. 对于int ch;,您应该使用char ch;而不是EOF

以下code可以工作:

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

int main() {
    char *str = NULL;
    int ch;
    size_t size = 0, len = 0;

    while ((ch=getchar()) != EOF && ch != '\n') {
        if (len + 1 >= size)
        {
            size = size * 2 + 1;
            str = realloc(str, sizeof(char)*size);
        }
        str[len++] = ch;
    }
    if (str != NULL) {
        str[len] = '\0';
        printf("%s\n", str);
        free(str);
    }

    return 0;
}

答案 1 :(得分:2)

  • scanf_s需要缓冲区大小作为参数,而您不希望如此
  • 通常scanf都会被stdin读取。
  • 在此处使用\n是一种更好的方法

以下是使用getchar的版本:

getchar

答案 2 :(得分:1)

scanf_s对于每个格式化的输入占位符都需要一个附加的“ buffer-size”参数。那就是您的编译器所抱怨的。因此,在使用scanf_s时,您必须编写scanf_s("%c", &ch, 1)。但是,您也可以简单地使用scanf,因为可以保证缓冲区ch足够大,可以在任何情况下采用字符值。因此scanf("%c",&ch)也将安全地工作。

请进一步注意,scanf(和scanf_s)返回正确读取的值的数量;返回值0也将是可能的,这也表明未读入任何内容。

所以我将其测试为...

while (scanf("%c", &ch)==1 && ch != '\n') 

答案 3 :(得分:1)

您的代码几乎没问题。

应更改两件事:

  1. 不要使用scanf,而要使用getc
  2. ch应该为int,否则与EOF的比较会引起麻烦。
  3. 细心的细节:main在成功的情况下应返回0,在失败的情况下应返回不同于0的值。

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

int main()
{
  char *str;
  int ch;
  int size = 10, len = 0;

  str = realloc(NULL, sizeof(char)*size);
  if (str == NULL)
    return 1;

  while ( (ch = getc(stdin)) && ch != EOF && ch != '\n')
  {
    str[len++] = (char)ch;

    if (len == size)
    {
      str = realloc(str, sizeof(char)*(size += 10));

      if (str == NULL)
        return 1;
    }
  }

  str[len] = '\0';
  printf("%s\n", str);
  free(str);
}

答案 4 :(得分:1)

  

问题是,当我使用VS-2017进行编译时,出现这些错误-

source.c(10): warning C4473: 'scanf_s' : not enough arguments passed for format string

source.c(10): note: placeholders and their parameters expect 2 variadic arguments, but 1 were provided

source.c(10): note: the missing variadic argument 2 is required by format string '%c'

source.c(10): note: this argument is used as a buffer size

警告和注释很明确,不是吗?

查找the related documentation会在“备注”部分显示:

  

scanf wscanf 不同, scanf_s wscanf_s 要求为所有输入参数指定缓冲区大小类型为 c C s S [ ] 。缓冲区大小(以字符为单位)将作为附加参数传递到指向缓冲区或变量的指针之后。

所以您想更改

  while (EOF != scanf_s("%c", &ch) && ch != '\n')

至少看起来像这样:

  while (EOF != scanf_s("%c", &ch, sizeof ch) && ch != '\n')

更好的办法是提供像这样的完整错误检查:

  {
    int result;
    while (1 == (result = scanf_s("%c", &ch, sizeof ch)) 
           && ch != '\n')
    {
      ...
    }

    if (EOF == result && ferror(stdin)) /* As scanf'ing uses stdin, 
                                           test its error status. */
    {
      fprintf(stderr, "scanf_s() failed.\n")
    }
  }