Leyendo una línea de longitud desconocida de stdin en c con fgets

Estoy tratando de leer una línea de longitud desconocida desde stdin usando el lenguaje C.

He visto esto cuando miro en la red:

char** str; gets(&str); 

Pero parece que me causa algunos problemas y realmente no entiendo cómo es posible hacerlo de esta manera.

¿Puede explicarme por qué este ejemplo funciona / no funciona y cuál será la forma correcta de implementarlo (con malloc?)

No desea un puntero para apuntar a char , use una matriz de caracteres

 char str[128]; 

o un puntero a char

 char *str; 

Si elige un puntero, necesita reservar espacio usando malloc

 str = malloc(128); 

Entonces puedes usar fgets

 fgets(str, 128, stdin); 

y eliminar la nueva línea de entrenamiento

 char *ptr = strchr(str, '\n'); if (ptr != NULL) *ptr = '\0'; 

Para leer una línea larga arbitraria, puede usar getline (una función agregada a la versión GNU de libc):

 #define _GNU_SOURCE #include  char *foo(FILE * f) { int n = 0, result; char *buf; result = getline(&buf, &n, f); if (result < 0) return NULL; return buf; } 

o su propia implementación usando fgets y realloc :

 char *getline(FILE * f) { size_t size = 0; size_t len = 0; size_t last = 0; char *buf = NULL; do { size += BUFSIZ; /* BUFSIZ is defined as "the optimal read size for this platform" */ buf = realloc(buf, size); /* realloc(NULL,n) is the same as malloc(n) */ /* Actually do the read. Note that fgets puts a terminal '\0' on the end of the string, so we make sure we overwrite this */ if (buf == NULL) return NULL; fgets(buf + last, size, f); len = strlen(buf); last = len - 1; } while (!feof(f) && buf[last] != '\n'); return buf; } 

Llamalo usando

 char *str = getline(stdin); if (str == NULL) { perror("getline"); exit(EXIT_FAILURE); } ... free(str); 

Más información

En primer lugar, gets() no proporciona ninguna forma de evitar un desbordamiento del búfer. Eso lo hace tan peligroso que se ha eliminado del último estándar C. No debería ser usado. Sin embargo, el uso habitual es algo así como

 char buffer[20]; gets(buffer); /* pray that user enters no more than 19 characters in a line */ 

Su uso es pasar gets() un puntero a un puntero a un puntero a char. Eso no es lo que gets() , por lo que su código ni siquiera se comstackría.

Ese elemento de oración reflejado en el comentario es por qué gets() es tan peligroso. Si el usuario ingresa 20 (o más) caracteres, gets() escribirá felizmente los datos más allá del final del buffer . No hay forma de que un progtwigdor pueda evitarlo en el código (aparte de acceder al hardware para electrocutar al usuario que ingresa demasiados datos, lo que está fuera del ámbito del estándar C).

Sin embargo, para responder a su pregunta, las únicas formas consisten en asignar un búfer de algún tamaño, leer los datos de forma controlada hasta que se alcanza ese tamaño, reasignarlo si es necesario para obtener un tamaño mayor y continuar hasta una nueva línea (o fin de línea). archivo, o alguna otra condición de error en la entrada) se encuentra.

Se puede usar malloc() para la asignación inicial. malloc() o realloc() se pueden usar para la reasignación (si es necesario). Tenga en cuenta que un búfer asignado de esta manera debe liberarse (usando free() ) cuando los datos ya no son necesarios; de lo contrario, el resultado es una pérdida de memoria.

use la función getline (), esto devolverá la longitud de la línea y un puntero al contenido de la línea en un área de memoria asignada. (asegúrese de pasar el puntero de línea a free () cuando haya terminado con él)

Si desea ingresar una longitud de cadena o entrada desconocida, intente con el siguiente código.

 #include  #include  #include  int main() { char *m; clrscr(); printf("please input a string\n"); scanf("%ms",&m); if (m == NULL) fprintf(stderr, "That string was too long!\n"); else { printf("this is the string %s\n",m); /* ... any other use of m */ free(m); } getch(); return 0; } 

Tenga en cuenta que% ms,% as son extensiones GNU ..