从stdin读取任意大小的字符串?

3

我想从控制台读取一个字符串。

使用scanf或fgets,似乎只能读取固定大小的字符串。更糟糕的是,如果用户输入了太多字符,似乎没有办法检查输入了多少个字符(在这种情况下,我可以简单地重新分配数组以使字符串适合数组)。

我在这个问题的答案中读到,应该一次读取一个字符,但我不知道如何在用户输入每个字符后不让其按回车键。

我该怎么做?


1
用户输入的字符会被缓存直到用户按下回车键,但是你仍然可以一个一个地读取它们。只是读取过程要等到用户按下回车键才开始。 - Vaughn Cato
如何读取未知长度的输入字符串? - jww
5个回答

4

GCC文档

标准C有一些函数可以实现这个功能,但它们并不是非常安全:空字符和(对于gets)甚至长行都会使它们混淆。因此,GNU库提供了非标准的getline函数,使得可靠地读取行变得容易。

并且

[getline]是GNU扩展,但它是从流中读取行的推荐方式。另外的标准函数是不可靠的。

因此,如果您正在使用GCC,则应使用getline。如果您没有使用GCC,则应查看您的编译器是否提供类似的功能。如果没有 - 或者如果您真的更喜欢使用某些标准功能 - 那么您需要逐个字符地读取。

我不知道如何在每个字符后不让用户按回车键。

是的,你需要。用户输入一系列字符,然后按Enter键。第一个fgetc调用将会阻塞,直到用户按下Enter键,但在此之后,随后的fgetc调用将立即返回,直到读取到换行符为止(然后它会再次阻塞,直到用户再次按下Enter键)。“逐个字符读取”并不意味着你必须在用户输入下一个字符之前读取每个字符;它只是意味着一旦用户完成输入一行,你就可以逐个字符地读取该行。


1
尝试运行这个:

...

#include <stdio.h>

int main(){
    char next;
    while((next=getchar())!=EOF)
        printf("%c\n",next);

}

那么请查看 getchar() 的手册以了解实际情况。


谢谢。这是最简单的答案,展示了我需要解决问题的内容。 - TravisG
1
应该是 int next,否则你无法区分 EOF 和 '\xff'(如果 char 是无符号的话,你会陷入无限循环). - zaphod

1

你可以在循环中使用 fgets(),并且如果最后一个字符不是 \n,则使用 realloc。

/* UNTESTED: MAY HAVE OFF-BY-ONE ERRORS */
char *buffer;
size_t bufsiz = 100;
size_t buflen = 100;
size_t bufcur = 0;
buffer = malloc(bufsiz);
for (;;) {
    fgets(buffer + bufcur, bufsiz, stdin);
    buflen = bufcur + strlen(buffer + bufcur);
    if (buffer[buflen - 1] == '\n') break;
    tmp = realloc(buffer, bufsiz * 2);
    if (tmp == NULL) /* deal with error */;
    buffer = tmp;
    bufcur = buflen - 1;
    bufsiz *= 2;
}
/* use buffer (and bufsiz and buflen) */
free(buffer);

1

被接受的答案应该注意到getchar()返回一个int。char数据类型不足以容纳EOF。

我们可以读取预定量的文本,然后丢弃其余的输入。这种方法有更多的批评者(我们怎么敢假设知道要丢弃什么)。另一个选择是使用getline或编写自定义函数。我想我会尝试后者。

这并不能防止用户用cat large_file填满内存。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define MAX 50
#define JUSTDO(a) if (!(a)) {perror(#a);exit(1);}
/** char *get_line  FILE *f
 * reads an arbitrarily long line of text or until EOF
 * caller must free the pointer returned after use
 */
char *get_line (FILE *f) {
    int len=MAX;
    char buf[MAX],*e=NULL,*ret;JUSTDO (ret=calloc(MAX,1));
    while (fgets (buf,MAX,f)) {
        if (len-strlen(ret)<MAX) JUSTDO (ret=realloc(ret,len*=2));
        strcat (ret,buf) ;if ((e=strrchr (ret,'\n'))) break;
    } if (e) *e='\0';
    return ret;
}
/* main */
int main (void) {
    char *s;
    printf ("enter a line of text:\n");
    printf ("line was '%s'\n",s=get_line(stdin)) ;free (s);
    return 0;
} 

只是...完全错误。 http://linux.die.net/man/3/getchar。手册明确说明fgetc()、getc()和getchar()返回读取的字符作为一个无符号字符强制转换为int或EOF在文件结束或出现错误时。EOF,虽然依赖于系统,通常是-1(或所有1位的字)。 - FrankieTheKneeMan

1
char c = NULL;
while (c != 0x0D)
{
    scanf("%c", &c);
    // do stuffs with c
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接