IT-Swarm.Net

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

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

97
pbreault

您需要动态内存管理,并使用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;
}

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

75
Johannes Schaub - litb

快速,可靠且价格合理的云托管

注册并在30天内获得$50奖金!

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

27
dmityugov

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

char line[1024];

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

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

char line[1024];

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

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

15
Anish Jhaveri

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

11
Tim

getline runnable example

提到 关于这个答案 但这是一个例子。.

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

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

#define _XOPEN_SOURCE 700

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

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超集,带有任意行终止符。.

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

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

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

#include <stdio.h>

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行代码,那么你会犯很多错误,而不是你选择得到的错误;)

7
badbadboy

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

您还可以使用fgets作为一种安全的方式来获取一行作为C空终止字符串:

#include <stdio.h>

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并且行缓冲区可能保持不变(这就是为什么将第一个char设置为'\ 0'的方便)。.

fgets不会溢出line []并且它将确保在成功返回的最后接受的字符之后存在null。.

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

如果在结束'\ 0'之前没有终止'\ n',则可能是有更多数据或下一个请求将报告文件结束。你将不得不做另一个fgets来确定哪个是哪个。 (在这方面,使用getchar()循环更容易。)

在上面的(更新的)示例代码中,如果在成功fgets之后行[sizeof(line)-1] =='\ 0',则表示缓冲区已完全填充。如果该位置以'\ n'开头,你知道你很幸运。否则,stdin中会有更多数据或文件结束。 (当缓冲区未完全填满时,您仍然可能位于文件末尾,并且当前行的末尾也可能没有'\ n'。因为您必须扫描字符串以查找和/或者在字符串结尾之前消除任何'\ n'(缓冲区中的第一个'\ n'),我倾向于首先使用getchar()。)

做你需要做的事情来处理仍然比你读作第一个块的数量更多的线。动态增长缓冲区的示例可以与getchar或fgets一起使用。有一些棘手的Edge情况要注意(比如记住下一个输入开始存储在'\ 0'的位置,在缓冲区扩展之前结束前一个输入)。.

4
orcmid

许多人,像我一样,来到这个帖子,标题与搜索的内容相匹配,尽管描述的是关于可变长度的说法。对于大多数情况,我们事先知道长度。.

如果您事先知道长度,请尝试以下方法:

char str1[1001] = { 0 };
fgets(str1, 1001, stdin); // 1000 chars may be read

来源: https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm

2
Manohar Reddy Poreddy

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

  • 构建自己的函数 ,是帮助您在 _ c _ 中从控制台读取一行的方法之一。.

  • 我正在使用 动态内存分配 分配只需要足够的内存量来保存一行的所有字符以及'\0'字符。.

  • 在这里,我使用一个循环使用getchar()函数逐个扫描字符串的每个字符,直到用户输入'\n'EOF字符

    //the function to read lines of variable length
    
    char* scan_line(char *line)
    {
        int ch; //as getchar() returns `int`
    
        if( (line = malloc(sizeof(char))) == NULL) //allocating memory
        {
            //checking if allocation was successful or not
            printf("unsuccessful allocation");
            exit(1);
        }
    
        line[0]='\0';
    
        for(int index = 0; ( (ch = getchar())!='\n' ) && (ch != EOF) ; index++)
        {
            if( (line = realloc(line, (index + 2)*sizeof(char))) == NULL )
            {
                //checking if reallocation was successful or not
                printf("unsuccessful reallocation");
                exit(1);
            }
    
            line[index] = (char) ch; //type casting `int` to `char`
            line[index + 1] = '\0'; //inserting null character at the end
        }
    
        return line;
    }  
    
  • 现在你可以这样读完整行:

    char *line = NULL;
    line = scan_line(line);
    

这是一个 示例程序 使用scan_line()函数:

#include <stdio.h>
#include <stdlib.h> //for dynamic allocation functions

char* scan_line(char *line)
{
    ..........
}

int main(void)
{
    char *a = NULL;

    a = scan_line(a); //function call to scan the line

    printf("%s\n",a); //printing the scanned line

    free(a); //don't forget to free the malloc'd pointer
}

样本输入:

Twinkle Twinkle little star.... in the sky!

样本输出:

Twinkle Twinkle little star.... in the sky!
1
Cherubim

像这样的东西:

unsigned int getConsoleInput(char **pStrBfr) //pass in pointer to char pointer, returns size of buffer
{
    char * strbfr;
    int c;
    unsigned int i;
    i = 0;
    strbfr = (char*)malloc(sizeof(char));
    if(strbfr==NULL) goto error;
    while( (c = getchar()) != '\n' && c != EOF )
    {
        strbfr[i] = (char)c;
        i++;
        strbfr = (void*)realloc((void*)strbfr,sizeof(char)*(i+1));
        //on realloc error, NULL is returned but original buffer is unchanged
        //NOTE: the buffer WILL NOT be NULL terminated since last
        //chracter came from console
        if(strbfr==NULL) goto error;
    }
    strbfr[i] = '\0';
    *pStrBfr = strbfr; //successfully returns pointer to NULL terminated buffer
    return i + 1; 
    error:
    *pStrBfr = strbfr;
    return i + 1;
}
0
user2074102

我前段时间遇到同样的问题,这是我的解决方案,希望它有所帮助。.

/*
 * Initial size of the read buffer
 */
#define DEFAULT_BUFFER 1024

/*
 * Standard boolean type definition
 */
typedef enum{ false = 0, true = 1 }bool;

/*
 * Flags errors in pointer returning functions
 */
bool has_err = false;

/*
 * Reads the next line of text from file and returns it.
 * The line must be free()d afterwards.
 *
 * This function will segfault on binary data.
 */
char *readLine(FILE *file){
    char *buffer   = NULL;
    char *tmp_buf  = NULL;
    bool line_read = false;
    int  iteration = 0;
    int  offset    = 0;

    if(file == NULL){
        fprintf(stderr, "readLine: NULL file pointer passed!\n");
        has_err = true;

        return NULL;
    }

    while(!line_read){
        if((tmp_buf = malloc(DEFAULT_BUFFER)) == NULL){
            fprintf(stderr, "readLine: Unable to allocate temporary buffer!\n");
            if(buffer != NULL)
                free(buffer);
            has_err = true;

            return NULL;
        }

        if(fgets(tmp_buf, DEFAULT_BUFFER, file) == NULL){
            free(tmp_buf);

            break;
        }

        if(tmp_buf[strlen(tmp_buf) - 1] == '\n') /* we have an end of line */
            line_read = true;

        offset = DEFAULT_BUFFER * (iteration + 1);

        if((buffer = realloc(buffer, offset)) == NULL){
            fprintf(stderr, "readLine: Unable to reallocate buffer!\n");
            free(tmp_buf);
            has_err = true;

            return NULL;
        }

        offset = DEFAULT_BUFFER * iteration - iteration;

        if(memcpy(buffer + offset, tmp_buf, DEFAULT_BUFFER) == NULL){
            fprintf(stderr, "readLine: Cannot copy to buffer\n");
            free(tmp_buf);
            if(buffer != NULL)
                free(buffer);
            has_err = true;

            return NULL;
        }

        free(tmp_buf);
        iteration++;
    }

    return buffer;
}
0
dsm

在BSD系统和Android上你也可以使用fgetln

#include <stdio.h>

char *
fgetln(FILE *stream, size_t *len);

像这样:

size_t line_len;
const char *line = fgetln(stdin, &line_len);

line不是以null结尾并且最终包含\n(或您的平台正在使用的任何内容)。在流上的下一个I/O操作后它变为无效。.

0
wonder.mice