如何读取未知长度的输入字符串?

it_*_*ure 57 c scanf

如果我不知道这个词有多长,我就不会写char m[6];,
这个词的长度可能是十到二十个.如何使用scanf键盘输入?

#include <stdio.h>
int main(void)
{
    char  m[6];
    printf("please input a string with length=5\n");
    scanf("%s",&m);
    printf("this is the string: %s\n", m);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

请输入一个lenght = 5 的字符串
你好
这是字符串:hello

BLU*_*IXY 86

在动态保护区域时输入

例如

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

char *inputString(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
    char *str;
    int ch;
    size_t len = 0;
    str = realloc(NULL, sizeof(char)*size);//size is start size
    if(!str)return str;
    while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
        str[len++]=ch;
        if(len==size){
            str = realloc(str, sizeof(char)*(size+=16));
            if(!str)return str;
        }
    }
    str[len++]='\0';

    return realloc(str, sizeof(char)*len);
}

int main(void){
    char *m;

    printf("input string : ");
    m = inputString(stdin, 10);
    printf("%s\n", m);

    free(m);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 乘以`sizeof(char)`?啊. (10认同)
  • @MrLister这就是为什么正确的方法,如果有的话,乘以`sizeof(*str)`,这样你甚至不必在类型改变时*编辑*乘法. (10认同)
  • @Jens Pfff,可能会被优化掉.没问题.但是如果你要使用`wchar_t`对`char`进行全局查找和替换,那么这个解决方案仍然有效,与其他解决方案不同,需要更多的修改! (7认同)
  • @germanfr 不。我说的是`realloc(NULL, sizeof(char)*size); 与 malloc(sizeof(char) * size)` 相同。我对 `malloc` 和 `realloc` 的说法不同。 (2认同)

Mr *_*ter 15

使用今天的计算机,您可以放弃分配非常大的字符串(数十万个字符),同时几乎不会削弱计算机的RAM使用率.所以我不会太担心.

然而,在过去,当内存非常宝贵时,通常的做法是以块的形式读取字符串.fgets从输入读取最大数量的字符,但保留输入缓冲区的其余部分,因此您可以随意读取其余部分.

在这个例子中,我读了200个字符的块,但你可以使用你想要的任何块大小.

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

char* readinput()
{
#define CHUNK 200
   char* input = NULL;
   char tempbuf[CHUNK];
   size_t inputlen = 0, templen = 0;
   do {
       fgets(tempbuf, CHUNK, stdin);
       templen = strlen(tempbuf);
       input = realloc(input, inputlen+templen+1);
       strcpy(input+inputlen, tempbuf);
       inputlen += templen;
    } while (templen==CHUNK-1 && tempbuf[CHUNK-2]!='\n');
    return input;
}

int main()
{
    char* result = readinput();
    printf("And the result is [%s]\n", result);
    free(result);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这是一个简单的示例,没有错误检查; 在现实生活中,你必须通过验证返回值来确保输入正常fgets.

另请注意,如果是readinput例程,最后没有浪费字节; 字符串具有它需要的确切内存大小.

  • 我认为第一次重新分配(输入为空时重新分配)存在问题。这可能指向任意内存,因此 strcat 可能没有预期的结果(即输入应该只是缓冲区的内容)。相反,它不会尝试存储已分配的长度为 Templen 的字符串,而是尝试存储 strlen(任意数据)+ Templen 的字符串,并给出“malloc() 内存损坏”错误。 (3认同)
  • @BrendanHart 噢,六年来没有人看到这一点。通过执行 strcpy 而不是 strcat 来修复。 (3认同)

sh1*_*sh1 9

我只看过一种读取任意长字符串的简单方法,但我从未使用它.我认为它是这样的:

char *m = NULL;
printf("please input a string\n");
scanf("%ms",&m);
if (m == NULL)
    fprintf(stderr, "That string was too long!\n");
else
{
    printf("this is the string %s\n",m);
    /* ... any other use of m */
    free(m);
}
Run Code Online (Sandbox Code Playgroud)

m之间%s告诉scanf()衡量字符串,并为它分配内存和字符串复制到这一点,该分配内存的地址存储在相应参数.一旦你完成它,你必须这样free()做.

scanf()但是,每次实现都不支持此功能.

正如其他人所指出的,最简单的解决方案是设置输入长度的限制.如果您仍想使用,scanf()那么您可以这样做:

char m[100];
scanf("%99s",&m);
Run Code Online (Sandbox Code Playgroud)

需要注意的是的大小m[]必须至少一个字节比之间的数量多%s.

如果输入的字符串长于99,则剩余的字符将等待另一个调用或传递给的格式字符串的其余部分读取scanf().

通常scanf()不建议用于处理用户输入.它最适用于由其他应用程序创建的基本结构化文本文件.即便如此,你必须意识到输入可能没有按照你的预期格式化,因为有人可能会干扰它以试图破坏你的程序.

  • @TimČas:这是Posix 2008的一部分,这是一个标准。之前有一个类似的GNU扩展和一个类似的BSD扩展。Posix标准旨在统一各种实现。它很有可能会进入未来的C标准。 (3认同)

Par*_*ani 6

C 标准中有一个新函数可以在不指定大小的情况下获取一行。getline函数自动分配所需大小的字符串,因此无需猜测字符串的大小。以下代码演示了用法:

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


int main(void)
{
    char *line = NULL;
    size_t len = 0;
    ssize_t read;

    while ((read = getline(&line, &len, stdin)) != -1) {
        printf("Retrieved line of length %zu :\n", read);
        printf("%s", line);
    }

    if (ferror(stdin)) {
        /* handle error */
    }

    free(line);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,它不在 C 标准中,但它确实存在于 POSIX 中,因此它的应用相当广泛 (6认同)

Nob*_*lis 5

如果我可以建议更安全的方法:

声明一个足以容纳字符串的缓冲区:

char user_input[255];

安全的方式获取用户输入:

fgets(user_input, 255, stdin);

获取输入的安全方法,第一个参数是指向将存储输入的缓冲区的指针,第二个参数是函数应该读取的最大输入,第三个是指向标准输入的指针 - 即用户输入到达的位置从.

安全性尤其来自第二个参数,它限制了将要读取多少以防止缓冲区溢出.此外,fgets负责处理null终止已处理的字符串.

这里有关于该功能的更多信息.

编辑:如果您需要进行任何格式化(例如将字符串转换为数字),您可以在输入后使用atoi.

  • 但OP要求他不知道如果他随机想要输入> 255,他会输入多少 (2认同)
  • @chux-ReinstateMonica 直到您使用指针而不是数组;) (2认同)