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

时间:2022-12-28 20:44:42

What is the simplest way to read a full line in a C console program The text entered might have a variable length and we can't make any assumption about its content.

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

13 个解决方案

#1


69  

You need dynamic memory management, and use the fgets function to read your line. However, there seems to be no way to see how many characters it read. So you use fgetc:

您需要动态内存管理,并使用fgets函数来读取您的行。然而,似乎没有办法看到它读了多少字符。所以你使用获取:

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;
}

Note: Never use gets ! It does not do bounds checking and can overflow your buffer

注意:永远不要使用get !它不执行边界检查,并且可以溢出缓冲区

#2


23  

If you are using the GNU C library or another POSIX-compliant library, you can use getline() and pass stdin to it for the file stream.

如果您正在使用GNU C库或另一个与posix兼容的库,您可以使用getline()并将stdin传递给它作为文件流。

#3


11  

You might need to use a character by character (getc()) loop to ensure you have no buffer overflows and don't truncate the input.

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

#4


10  

A very simple but unsafe implementation to read line for static allocation:

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

char line[1024];

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

A safer implementation, without the possibility of buffer overflow, but with the possibility of not reading the whole line, is:

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

char line[1024];

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

Not the 'difference by one' between the length specified declaring the variable and the length specified in the format string. It is a historical artefact.

不是声明变量的长度和格式字符串中指定的长度之间的“差值为1”。这是一件历史文物。

#5


8  

getline runnable example

getline运行的例子

Mentioned on this answer but here is an example.

这里有一个例子。

It is POSIX 7, allocates memory for us, and reuses the allocated buffer on a loop nicely.

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

Pointer newbs, read this: Why is the first argument of getline a pointer to pointer "char**" instead of "char*"?

指针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 implementation

glibc实现

No POSIX? Maybe you want to look at the glibc 2.23 implementation.

没有POSIX ?也许你想看看glibc 2.23实现。

It resolves to getdelim, which is a simple POSIX superset of getline with an arbitrary line terminator.

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

It doubles the allocated memory whenever increase is needed, and looks thread-safe.

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

It requires some macro expansion, but you're unlikely to do much better.

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

#6


7  

So, if you were looking for command arguments, take a look at Tim's answer. If you just want to read a line from console:

因此,如果您正在寻找命令参数,请查看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;
}

Yes, it is not secure, you can do buffer overrun, it does not check for end of file, it does not support encodings and a lot of other stuff. Actually I didn't even think whether it did ANY of this stuff. I agree I kinda screwed up :) But...when I see a question like "How to read a line from the console in C?", I assume a person needs something simple, like gets() and not 100 lines of code like above. Actually, I think, if you try to write those 100 lines of code in reality, you would do many more mistakes, than you would have done had you chosen gets ;)

是的,它不安全,您可以执行缓冲区溢出,它不检查文件的末尾,它不支持编码和其他许多东西。事实上,我甚至都没想过它会不会有这些东西。我同意我有点搞砸了:)但是…当我看到像“如何用C语言从控制台读一行?”,我假设一个人需要一些简单的东西,比如get(),而不是像上面那样需要100行代码。实际上,我认为,如果你试着在现实中写这100行代码,你会犯更多的错误,比你选择得到的要多。

#7


4  

As suggested, you can use getchar() to read from the console until an end-of-line or an EOF is returned, building your own buffer. Growing buffer dynamically can occur if you are unable to set a reasonable maximum line size.

如建议的,您可以使用getchar()从控制台读取数据,直到返回行尾或EOF,构建您自己的缓冲区。如果无法设置合理的最大行大小,就会动态地增长缓冲区。

You can use also use fgets as a safe way to obtain a line as a C null-terminated string:

您也可以使用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);

If you have exhausted the console input or if the operation failed for some reason, eof == NULL is returned and the line buffer might be unchanged (which is why setting the first char to '\0' is handy).

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

fgets will not overfill line[] and it will ensure that there is a null after the last-accepted character on a successful return.

fgets不会重载行[],它将确保在成功返回的最后接受字符之后存在null。

If end-of-line was reached, the character preceding the terminating '\0' will be a '\n'.

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

If there is no terminating '\n' before the ending '\0' it may be that there is more data or that the next request will report end-of-file. You'll have to do another fgets to determine which is which. (In this regard, looping with getchar() is easier.)

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

In the (updated) example code above, if line[sizeof(line)-1] == '\0' after successful fgets, you know that the buffer was filled completely. If that position is proceeded by a '\n' you know you were lucky. Otherwise, there is either more data or an end-of-file up ahead in stdin. (When the buffer is not filled completely, you could still be at an end-of-file and there also might not be a '\n' at the end of the current line. Since you have to scan the string to find and/or eliminate any '\n' before the end of the string (the first '\0' in the buffer), I am inclined to prefer using getchar() in the first place.)

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

Do what you need to do to deal with there still being more line than the amount you read as the first chunk. The examples of dynamically-growing a buffer can be made to work with either getchar or fgets. There are some tricky edge cases to watch out for (like remembering to have the next input start storing at the position of the '\0' that ended the previous input before the buffer was extended).

做你需要做的,以处理仍然有更多的线比你读到的第一个块。动态扩展缓冲区的示例可以使用getchar或fgets。这里有一些需要注意的棘手的边缘情况(比如要记住在扩展缓冲区之前将下一个输入从'\0'的位置开始存储)。

#8


2  

Many people, like me, come to this post with the title matching what is searched for, though the description is saying about variable length. For most cases, we know the length beforehand.

许多人,像我,来到这篇文章的标题匹配搜索什么,尽管描述是关于可变长度。对于大多数情况,我们事先知道长度。

If you do know length before hand, try below:

如果你事先知道长度,试试下面的方法:

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

source: https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm

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

#9


1  

How to read a line from the console in C?

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

  • Building your own function, is one of the way that would help you to achieve reading a line from console in C.

    构建自己的函数,是帮助您在C语言中实现从控制台读取一行的方法之一。

  • I'm using dynamic memory allocation to allocate just the sufficient amount of memory required to hold all the characters of a line along with the '\0' character.

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

  • And here I'm using a loop to scan each character of the string one by one using the getchar() function untill the user enters '\n' or EOF character

    在这里,我使用一个循环来扫描字符串的每个字符,使用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;
    }  
    
  • Now you could read a full line this way :

    现在你可以用这种方式来阅读全文:

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

Here's an example program using the scan_line() function :

这里有一个使用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
}

sample input :

样例输入:

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

sample output :

样例输出:

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

#10


0  

I came across the same problem some time ago, this was my solutuion, hope it helps.

我以前遇到过同样的问题,这是我的解决方案,希望它能有所帮助。

/*
 * 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;
}

#11


0  

On BSD systems and Android you can also use fgetln:

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

#include <stdio.h>

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

Like so:

像这样:

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

The line is not null terminated and contains \n (or whatever your platform is using) in the end. It becomes invalid after the next I/O operation on stream.

行不是空终止的,最后包含\n(或您的平台正在使用的任何东西)。在流上的下一个I/O操作之后,它将变得无效。

#12


0  

Something like this:

是这样的:

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;
}

#13


-3  

This function should do what you want:

这个函数应该做你想做的:

char* readLine( FILE* file )
 {
 char buffer[1024];
 char* result = 0;
 int length = 0;

 while( !feof(file) )
  {
  fgets( buffer, sizeof(buffer), file );
  int len = strlen(buffer);
  buffer[len] = 0;

  length += len;
  char* tmp = (char*)malloc(length+1);
  tmp[0] = 0;

  if( result )
   {
   strcpy( tmp, result );
   free( result );
   result = tmp;
   }

  strcat( result, buffer );

  if( strstr( buffer, "\n" ) break;
  }

 return result;
 }

char* line = readLine( stdin );
/* Use it */
free( line );

I hope this helps.

我希望这可以帮助。

#1


69  

You need dynamic memory management, and use the fgets function to read your line. However, there seems to be no way to see how many characters it read. So you use fgetc:

您需要动态内存管理,并使用fgets函数来读取您的行。然而,似乎没有办法看到它读了多少字符。所以你使用获取:

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;
}

Note: Never use gets ! It does not do bounds checking and can overflow your buffer

注意:永远不要使用get !它不执行边界检查,并且可以溢出缓冲区

#2


23  

If you are using the GNU C library or another POSIX-compliant library, you can use getline() and pass stdin to it for the file stream.

如果您正在使用GNU C库或另一个与posix兼容的库,您可以使用getline()并将stdin传递给它作为文件流。

#3


11  

You might need to use a character by character (getc()) loop to ensure you have no buffer overflows and don't truncate the input.

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

#4


10  

A very simple but unsafe implementation to read line for static allocation:

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

char line[1024];

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

A safer implementation, without the possibility of buffer overflow, but with the possibility of not reading the whole line, is:

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

char line[1024];

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

Not the 'difference by one' between the length specified declaring the variable and the length specified in the format string. It is a historical artefact.

不是声明变量的长度和格式字符串中指定的长度之间的“差值为1”。这是一件历史文物。

#5


8  

getline runnable example

getline运行的例子

Mentioned on this answer but here is an example.

这里有一个例子。

It is POSIX 7, allocates memory for us, and reuses the allocated buffer on a loop nicely.

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

Pointer newbs, read this: Why is the first argument of getline a pointer to pointer "char**" instead of "char*"?

指针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 implementation

glibc实现

No POSIX? Maybe you want to look at the glibc 2.23 implementation.

没有POSIX ?也许你想看看glibc 2.23实现。

It resolves to getdelim, which is a simple POSIX superset of getline with an arbitrary line terminator.

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

It doubles the allocated memory whenever increase is needed, and looks thread-safe.

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

It requires some macro expansion, but you're unlikely to do much better.

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

#6


7  

So, if you were looking for command arguments, take a look at Tim's answer. If you just want to read a line from console:

因此,如果您正在寻找命令参数,请查看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;
}

Yes, it is not secure, you can do buffer overrun, it does not check for end of file, it does not support encodings and a lot of other stuff. Actually I didn't even think whether it did ANY of this stuff. I agree I kinda screwed up :) But...when I see a question like "How to read a line from the console in C?", I assume a person needs something simple, like gets() and not 100 lines of code like above. Actually, I think, if you try to write those 100 lines of code in reality, you would do many more mistakes, than you would have done had you chosen gets ;)

是的,它不安全,您可以执行缓冲区溢出,它不检查文件的末尾,它不支持编码和其他许多东西。事实上,我甚至都没想过它会不会有这些东西。我同意我有点搞砸了:)但是…当我看到像“如何用C语言从控制台读一行?”,我假设一个人需要一些简单的东西,比如get(),而不是像上面那样需要100行代码。实际上,我认为,如果你试着在现实中写这100行代码,你会犯更多的错误,比你选择得到的要多。

#7


4  

As suggested, you can use getchar() to read from the console until an end-of-line or an EOF is returned, building your own buffer. Growing buffer dynamically can occur if you are unable to set a reasonable maximum line size.

如建议的,您可以使用getchar()从控制台读取数据,直到返回行尾或EOF,构建您自己的缓冲区。如果无法设置合理的最大行大小,就会动态地增长缓冲区。

You can use also use fgets as a safe way to obtain a line as a C null-terminated string:

您也可以使用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);

If you have exhausted the console input or if the operation failed for some reason, eof == NULL is returned and the line buffer might be unchanged (which is why setting the first char to '\0' is handy).

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

fgets will not overfill line[] and it will ensure that there is a null after the last-accepted character on a successful return.

fgets不会重载行[],它将确保在成功返回的最后接受字符之后存在null。

If end-of-line was reached, the character preceding the terminating '\0' will be a '\n'.

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

If there is no terminating '\n' before the ending '\0' it may be that there is more data or that the next request will report end-of-file. You'll have to do another fgets to determine which is which. (In this regard, looping with getchar() is easier.)

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

In the (updated) example code above, if line[sizeof(line)-1] == '\0' after successful fgets, you know that the buffer was filled completely. If that position is proceeded by a '\n' you know you were lucky. Otherwise, there is either more data or an end-of-file up ahead in stdin. (When the buffer is not filled completely, you could still be at an end-of-file and there also might not be a '\n' at the end of the current line. Since you have to scan the string to find and/or eliminate any '\n' before the end of the string (the first '\0' in the buffer), I am inclined to prefer using getchar() in the first place.)

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

Do what you need to do to deal with there still being more line than the amount you read as the first chunk. The examples of dynamically-growing a buffer can be made to work with either getchar or fgets. There are some tricky edge cases to watch out for (like remembering to have the next input start storing at the position of the '\0' that ended the previous input before the buffer was extended).

做你需要做的,以处理仍然有更多的线比你读到的第一个块。动态扩展缓冲区的示例可以使用getchar或fgets。这里有一些需要注意的棘手的边缘情况(比如要记住在扩展缓冲区之前将下一个输入从'\0'的位置开始存储)。

#8


2  

Many people, like me, come to this post with the title matching what is searched for, though the description is saying about variable length. For most cases, we know the length beforehand.

许多人,像我,来到这篇文章的标题匹配搜索什么,尽管描述是关于可变长度。对于大多数情况,我们事先知道长度。

If you do know length before hand, try below:

如果你事先知道长度,试试下面的方法:

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

source: https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm

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

#9


1  

How to read a line from the console in C?

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

  • Building your own function, is one of the way that would help you to achieve reading a line from console in C.

    构建自己的函数,是帮助您在C语言中实现从控制台读取一行的方法之一。

  • I'm using dynamic memory allocation to allocate just the sufficient amount of memory required to hold all the characters of a line along with the '\0' character.

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

  • And here I'm using a loop to scan each character of the string one by one using the getchar() function untill the user enters '\n' or EOF character

    在这里,我使用一个循环来扫描字符串的每个字符,使用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;
    }  
    
  • Now you could read a full line this way :

    现在你可以用这种方式来阅读全文:

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

Here's an example program using the scan_line() function :

这里有一个使用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
}

sample input :

样例输入:

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

sample output :

样例输出:

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

#10


0  

I came across the same problem some time ago, this was my solutuion, hope it helps.

我以前遇到过同样的问题,这是我的解决方案,希望它能有所帮助。

/*
 * 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;
}

#11


0  

On BSD systems and Android you can also use fgetln:

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

#include <stdio.h>

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

Like so:

像这样:

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

The line is not null terminated and contains \n (or whatever your platform is using) in the end. It becomes invalid after the next I/O operation on stream.

行不是空终止的,最后包含\n(或您的平台正在使用的任何东西)。在流上的下一个I/O操作之后,它将变得无效。

#12


0  

Something like this:

是这样的:

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;
}

#13


-3  

This function should do what you want:

这个函数应该做你想做的:

char* readLine( FILE* file )
 {
 char buffer[1024];
 char* result = 0;
 int length = 0;

 while( !feof(file) )
  {
  fgets( buffer, sizeof(buffer), file );
  int len = strlen(buffer);
  buffer[len] = 0;

  length += len;
  char* tmp = (char*)malloc(length+1);
  tmp[0] = 0;

  if( result )
   {
   strcpy( tmp, result );
   free( result );
   result = tmp;
   }

  strcat( result, buffer );

  if( strstr( buffer, "\n" ) break;
  }

 return result;
 }

char* line = readLine( stdin );
/* Use it */
free( line );

I hope this helps.

我希望这可以帮助。