当前位置:  开发笔记 > 编程语言 > 正文

如何从C中的控制台读取一行?

如何解决《如何从C中的控制台读取一行?》经验,为你挑选了7个好方法。

在C控制台程序中读取完整行的最简单方法是什么?输入的文本可能具有可变长度,我们无法对其内容进行任何假设.



1> Johannes Sch..:

您需要动态内存管理,并使用该fgets功能读取您的行.但是,似乎没有办法看到它读取了多少个字符.所以你使用fgetc:

char * getline(void) {
    char * line = malloc(100), * linep = line;
    size_t lenmax = 100, len = lenmax;
    int c;

    if(line == NULL)
        return NULL;

    for(;;) {
        c = fgetc(stdin);
        if(c == EOF)
            break;

        if(--len == 0) {
            len = lenmax;
            char * linen = realloc(linep, lenmax *= 2);

            if(linen == NULL) {
                free(linep);
                return NULL;
            }
            line = linen + (line - linep);
            linep = linen;
        }

        if((*line++ = c) == '\n')
            break;
    }
    *line = '\0';
    return linep;
}

注意:永远不要使用获取!它不进行边界检查,可以溢出缓冲区


你可以通过使用缓冲区执行fgets并检查最后是否有换行符来提高效率.如果不这样做,请重新分配累积缓冲区,将其复制到fgets中,然后重新进行fgets.
此功能需要更正:行"len = lenmax;" realloc应该在realloc之前或者应该是"len = lenmax >> 1"; - 或其他一些等同于已经使用了一半长度的事实.
请注意,这个`getline()`与POSIX标准[`getline()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html)函数不同.

2> dmityugov..:

如果您使用的是GNU C库或其他符合POSIX的库,则可以使用getline()并传递stdin给它以获取文件流.



3> 小智..:

读取静态分配行的一个非常简单但不安全的实现:

char line[1024];

scanf("%[^\n]", line);

一个更安全的实现,没有缓冲区溢出的可能性,但有可能不读取整行,是:

char line[1024];

scanf("%1023[^\n]", line);

声明变量的指定长度与格式字符串中指定的长度之间不是"一个差异".这是一件历史人工制品.


**这根本不安全.它有完全相同的问题为什么`gets`被从标准中删除**
**主持人注意:**上面的评论指的是[答案的先前版本。](/sf/ask/17360801/)

4> Tim..:

您可能需要使用逐个字符(getc())循环来确保没有缓冲区溢出并且不截断输入.



5> Paul Kapusti..:

所以,如果您正在寻找命令参数,请看看Tim的答案.如果您只想从控制台读取一行:

#include 

int main()
{
  char string [256];
  printf ("Insert your full address: ");
  gets (string);
  printf ("Your address is: %s\n",string);
  return 0;
}

是的,它不安全,你可以做缓冲区溢出,它不检查文件的结尾,它不支持编码和许多其他的东西.实际上我甚至没想到它是否做了这些东西.我同意我有点搞砸了:)但是......当我看到一个问题如"如何从C中从控制台读取一行?"时,我认为一个人需要一些简单的东西,比如gets()而不是100行代码像上面一样.实际上,我认为,如果你试图在现实中编写这100行代码,你会犯更多错误,而不是你选择得到的错误;)


另一方面,如果您正在为自己编写程序并且只需要阅读输入,那么这非常好.程序需要多少安全性才符合规范 - 您不必每次都将其作为优先事项.
@Tim - 我想保留所有的历史:)
Downvoted.`gets`不再存在,因此这在C11中不起作用.
-1,不应使用gets(),因为它不进行边界检查.

6> Ciro Santill..:

getline 可运行的例子

提到这个答案,但这是一个例子.

它是POSIX 7,为我们分配内存,并在循环上很好地重用分配的缓冲区.

指针newbs,读取这个:为什么getline的第一个参数指向指针"char**"而不是"char*"?

#define _XOPEN_SOURCE 700

#include 
#include 

int main(void) {
    char *line = NULL;
    size_t len = 0;
    ssize_t read = 0;
    while (read != -1) {
        puts("enter a line");
        read = getline(&line, &len, stdin);
        printf("line = %s", line);
        printf("line length = %zu\n", read);
        puts("");
    }
    free(line);
    return 0;
}

glibc实现

没有POSIX?也许你想看一下glibc 2.23的实现.

它解析为getdelim,这是一个getline带有任意行终止符的简单POSIX超集.

每当需要增加时,它会将分配的内存加倍,并且看起来是线程安全的.

它需要一些宏观扩张,但你不太可能做得更好.



7> orcmid..:

如建议的那样,您可以使用getchar()从控制台读取,直到返回行尾或EOF,从而建立自己的缓冲区。如果您无法设置合理的最大行大小,则会动态增加缓冲区。

您还可以将fgets用作获取以C终止的字符串作为行的安全方法:

#include 

char line[1024];  /* Generously large value for most situations */

char *eof;

line[0] = '\0'; /* Ensure empty line if no input delivered */
line[sizeof(line)-1] = ~'\0';  /* Ensure no false-null at end of buffer */

eof = fgets(line, sizeof(line), stdin);

如果您用尽了控制台输入或由于某种原因操作失败,则返回eof == NULL,并且行缓冲区可能保持不变(这就是将第一个字符设置为'\ 0'的原因)。

fgets不会使line []溢出,并且将确保在成功返回时,最后一个可接受的字符之后为null。

如果到达了行尾,则终止符'\ 0'之前的字符将是'\ n'。

如果在结尾“ \ 0”之前没有终止符“ \ n”,则可能是有更多数据,或者下一个请求将报告文件结束。您必须做另一个fgets来确定哪个。(就此而言,使用getchar()循环更容易。)

在上面的(更新的)示例代码中,如果成功执行fget之后,如果line [sizeof(line)-1] =='\ 0',则说明缓冲区已完全填满。如果该职位以'\ n'开头,则说明您很幸运。否则,标准输入中可能有更多数据或文件末尾。(当缓冲区未完全填满时,您可能仍位于文件末尾,并且当前行的末尾也可能没有'\ n'。由于您必须扫描字符串才能查找和/或删除字符串末尾(缓冲区的第一个'\ 0')之前的任何'\ n',我倾向于首先使用getchar()。)

做您需要做的事情以处理仍然多于您作为第一块读取的行数的行。可以使动态增长缓冲区的示例与getchar或fgets一起使用。有一些棘手的边缘情况需要提防(例如,记住要在缓冲区扩展之前,将下一个输入开始存储在结束先前输入的'\ 0'位置)。

推荐阅读
大大炮
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有