I'm just a young computer science student, and currently I'm a bit confused about what is the best practice to read a string from stdin. I know that there are a lot of ways to do that, some safer than other, and so on... I'm currently in need of a function that prevents buffer overflow and appends a null terminator character (\0) to the end of the string. I found fgets really useful for that, but ... It stops reading with \n or EOF! What if I want the user to input more than one line at time? Are there some other function that can help me doing that? I'm sorry if this question can seem silly to some of you, but please, understand me! Any help would be appreciated.
-
[Similar question](http://stackoverflow.com/questions/3068198/how-to-read-a-multiple-line-input-from-command-line-in-c-or-c) using `getline` – KarelG Jan 09 '16 at 15:38
-
1Input would always need to end at EOF, which is when the user types CTRL + Z on Windows or CTRL + D on Linux. – lost_in_the_source Jan 09 '16 at 15:41
-
This [similar question](http://stackoverflow.com/questions/314401/how-to-read-a-line-from-the-console-in-c) has an answer explaining how to do it with `fgetc` – arainone Jan 09 '16 at 15:42
-
1I can see why `fgets` stopping at `\n` could be a problem (although, honestly, I do *not* see *why* it is a problem - you can just run it again to fetch the next line!) but what do you imagine it to do when it encounters `EOF`? – Jongware Jan 09 '16 at 15:47
-
@arainone I'm aware of fgetc, getc and getchar(void), very similar function to each other. What I'm looking for is a function just like fgets, because it's safer (it doesnt allow buffer overflow) and it appends a null terminator character. – Claudio Cortese Jan 09 '16 at 16:14
-
@Jongware Is there a way to let fgets not stop reading with \n but only with EOF? – Claudio Cortese Jan 09 '16 at 16:18
-
@ClaudioCortese `fgetc` is safe against buffer overflows as it is not dealing with buffers. I don't think the function you are looking for exists in C, you would have to write it. The [SO thread](http://stackoverflow.com/questions/314401/how-to-read-a-line-from-the-console-in-c) I indicated to you is a way of doing it – arainone Jan 09 '16 at 16:33
-
@ClaudioCortese - the faster alternative to read an entire file is `fread`. Since you do *Not* want to stop reading on `'\n'`, you can use `fread` to read the entire file into an adequately allocated buffer in a single call. This can provide significant I/O improvement over a *character-oriented* read. – David C. Rankin Jan 09 '16 at 23:24
3 Answers
#define INITALLOC 16 /* #chars initally alloced */
#define STEP 8 /* #chars to realloc by */
#define END (-1) /* returned by getline to indicate EOF */
#define ALLOCFAIL 0 /* returned by getline to indicate allocation failure */
int getline(char **dynline)
{
int i, c;
size_t nalloced; /* #chars currently alloced */
if ((*dynline = malloc(INITALLOC)) == NULL)
return ALLOCFAIL;
nalloced = INITALLOC;
for (i = 0; (c = getchar()) != EOF; ++i) {
/* buffer is full, request more memory */
if (i == nalloced)
if ((*dynline = realloc(*dynline, nalloced += STEP)) == NULL)
return ALLOCFAIL;
/* store the newly read character */
(*dynline)[i] = c;
}
/* zero terminate the string */
(*dynline)[i] = '\0';
if (c == EOF)
return END;
return i+1; /* on success, return #chars read successfully
(i is an index, so add 1 to make it a count */
}
This function allocates memory dynamically, so the caller needs to free
the memory.
This code is not perfect. If, on reallocation, there is a failure, NULL
overwrites the previous, perfectly-good data causing a memory leak and loss of data.

- 10,998
- 9
- 46
- 75
-
-
2Too bad you use the `getline` name which has a different meaning on POSIX – Basile Starynkevitch Jan 09 '16 at 16:11
-
*Why the downvote?* I'd think you'd need something more like `int getline(char **dynline)` so the caller would have a pointer that you could modify the value of. Right now, you're modifying the value of a `char` in an undefined way. I'd actually return the pointer and pass the address of `int` for a return status: `char *myGetline( int *retStatus );` – Andrew Henle Jan 09 '16 at 16:16
-
already pointed out [comment](http://stackoverflow.com/questions/34694547/memory-at-runtime/34694875#comment57138529_34694875) – BLUEPIXY Jan 09 '16 at 17:05
-
2You are wasting the return value; you should use it to indicate how many characters were read. You have a memory leak on allocation failure; you've just overwritten `*dynline` with a null pointer; sad there's no other way to free what was previously allocated. Study the design of POSIX [`getline()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html); it has quite a lot of merits. – Jonathan Leffler Jan 25 '16 at 03:39
If a newline is encountered and fgets
returns, you can run it again as many times as necessary to read as many lines as you want. A loop is useful for this.
If EOF is encountered, you have reached the end of the file(/stream) and there is no point in running it again, because there is nothing left to read.
An example showing the logic to read an entire string to EOF from stdin follows.
There are many ways to do this, and this is just one, but it shows the general logic.
The result buffer grows as the input is read, and there are no bounds on this – so if EOF is never reached you will eventually run out of memory and the program will exit. A simple check could avoid this, or depending on your application you could process the data as it comes in and not need to store it all.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LINE_BUFFER_SIZE 256
// Each time this is exhausted, the buffer will be increased in size by this amount again.
#define INITIAL_BUFFER_SIZE 2048
int main (int argc, char **argv) {
char *result = malloc(INITIAL_BUFFER_SIZE);
if (!result) {
// Out of memory.
return 1;
}
size_t totalBytesRead = 0;
size_t bytesAllocated = INITIAL_BUFFER_SIZE;
char buf[LINE_BUFFER_SIZE];
while (fgets(buf, LINE_BUFFER_SIZE, stdin)) {
size_t bytesRead = strlen(buf);
size_t bytesNeeded = totalBytesRead + bytesRead + 1;
if (bytesAllocated < bytesNeeded) {
char *newPtr = realloc(result, bytesAllocated + INITIAL_BUFFER_SIZE);
if (newPtr) {
result = newPtr;
bytesAllocated += INITIAL_BUFFER_SIZE;
}
else {
// Out of memory.
free(result);
return 1;
}
}
memcpy(result + totalBytesRead, buf, bytesRead);
totalBytesRead += bytesRead;
}
result[totalBytesRead] = '\0';
// result contains the entire contents from stdin until EOF.
printf("%s", result);
free(result);
return 0;
}

- 4,903
- 1
- 27
- 30
-
Ok, but how I'm supposed to do that? while(what?) fgets(sentence,33,stdin); – Claudio Cortese Jan 09 '16 at 16:10
-
From `man fgets`: "If end-of-file occurs before any characters are read, they return NULL and the buffer contents remain unchanged." So, for example you could do `while (fgets(buffer, BUFLEN, stdin) != NULL) { ... }`. Another common pattern would be a `while (1)` loop with a test for EOF inside which `break`s out of the loop. – jbg Jan 09 '16 at 16:36
-
I noticed that if the user inputs a sentence of 32 or more character, fgets doesn't stop. Moreover its overriding the string every time it runs. I'm looking for a way to store sentences composed of more lines than just one... – Claudio Cortese Jan 09 '16 at 17:14
-
I’ve added an example showing the logic to read an entire file, line-by-line, from stdin storing the lines into a buffer which grows as you read. – jbg Jan 09 '16 at 17:27
On POSIX systems, you have getline. It is able to read an arbitrarily wide line (till exhausting resources) in heap allocated memory.
You can also repeatedly call fgetc ... (BTW, you should define exactly what is a string for you)
On Linux, you can read an editable line from the terminal (that is, stdin
when it is a tty) using GNU readline.
To read some kind of strings, you might use fscanf with e.g. %50s
or %[A-Z]
etc...
And you can read an array (of bytes, or some other binary data) using fread
You might read an entire line and parse it later (perhaps using sscanf
). You could read several lines and build some strings in heap memory (e.g. using asprintf or strdup on systems having it) from them.

- 223,805
- 18
- 296
- 547