Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read a line from the console in C?

Tags:

c

io

stdin

console

People also ask

How do you read a line of text in C?

The standard way of reading a line of text in C is to use the fgets function, which is fine if you know in advance how long a line of text could be. You can find all the code examples and the input file at the GitHub repo for this article.

How strings are read from terminal in C?

Read String from the user You can use the scanf() function to read a string. The scanf() function reads the sequence of characters until it encounters whitespace (space, newline, tab, etc.).

Which function is used to read data from the console in C?

In C, the scanf() function is used to read formatted data from the console.


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:

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


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.


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.


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:

#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 ;)


getline runnable example

getline was 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.

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

main.c

#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 (1) {
        puts("enter a line");
        read = getline(&line, &len, stdin);
        if (read == -1)
            break;
        printf("line = %s", line);
        printf("line length = %zu\n", read);
        puts("");
    }
    free(line);
    return 0;
}

Compile and run:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

Outcome: this shows on therminal:

enter a line

Then if you type:

asdf

and press enter, this shows up:

line = asdf
line length = 5

followed by another:

enter a line

Or from a pipe to stdin:

printf 'asdf\nqwer\n' | ./main.out

gives:

enter a line
line = asdf
line length = 5

enter a line
line = qwer
line length = 5

enter a line

Tested on Ubuntu 20.04.

glibc implementation

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

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

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.


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


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.

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

#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).

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

If end-of-line was reached, the character preceding the terminating '\0' will be a '\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.)

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.)

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).