How to read input of unknown length using fgets

As I should read long input using fgets() , I do not quite understand it.

I wrote this

 #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char buffer[10]; char *input; while (fgets(buffer,10,stdin)){ input = malloc(strlen(buffer)*sizeof(char)); strcpy(input,buffer); } printf("%s [%d]",input, (int)strlen(input)); free(input); return 0; } 
+6
source share
2 answers
 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char buffer[10]; char *input = 0; size_t cur_len = 0; while (fgets(buffer, sizeof(buffer), stdin) != 0) { size_t buf_len = strlen(buffer); char *extra = realloc(input, buf_len + cur_len + 1); if (extra == 0) break; input = extra; strcpy(input + cur_len, buffer); cur_len += buf_len; } printf("%s [%d]", input, (int)strlen(input)); free(input); return 0; } 

It's about a minimal set of changes that will give you a complete line of input. This increases the space to 9 bytes at a time; this is not the best way to do this, but there additional accounting includes performing the best methods (doubling the allocated space and keeping a record of how much money has been allocated versus how much is used). Note that cur_len writes the length of the string in the space pointed to by input , with the exception of the null terminal. Also note that using extra avoids memory leaks when you are unable to allocate.

The strcpy() operation can be legally replaced with memmove(input + cur_len, buffer, buf_len + 1) (and in this context you can use memcpy() instead of memmove() , but it does not always work while memmove() always works, therefore, it is more reliable to use memmove() ).


With doubling the length - the cur_max variable records how much space is allocated, and cur_len records how much space is used.

 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char buffer[10]; char *input = 0; size_t cur_len = 0; size_t cur_max = 0; while (fgets(buffer, sizeof(buffer), stdin) != 0) { size_t buf_len = strlen(buffer); if (cur_len + buf_len + 1 > cur_max) { size_t new_len = cur_max * 2 + 1; if (buf_len + 1 > new_len) new_len = buf_len + 1; char *extra = realloc(input, new_len); if (extra == 0) break; input = extra; cur_max = new_len; } strcpy(input + cur_len, buffer); cur_len += buf_len; } printf("%s [%d]", input, (int)strlen(input)); free(input); return 0; } 
+5
source

A better approach is to use an input mechanism that will stand out for you, such as getline (or even scanf ). ( Note: scanf does not stand out in all compilers. It works on gcc/Linux , but not on Windows/Codeblocks/gcc )

 #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char *input; scanf ("%m[^\n]%*c", &input); printf("\n %s [%d]\n\n",input, (int)strlen(input)); free(input); return 0; } 

output:

 $ ./bin/scanfinput This is my longer string. This is my longer string. [25] 

getline example

 #include <stdio.h> #include <stdlib.h> int main() { char *input = NULL; /* input buffer, NULL forces getline to allocate */ size_t n = 0; /* maximum characters to read (0 - no limit */ ssize_t nchr = 0; /* number of characters actually read */ if ((nchr = getline (&input, &n, stdin)) != -1) input[--nchr] = 0; /* strip newline */ printf ("\n %s [%zd]\n\n", input, nchr); free(input); return 0; } 
+3
source

Source: https://habr.com/ru/post/979202/


All Articles