por - Cómo leer una línea desde la consola en C?
leer palabras de un archivo en c (13)
¿Cuál es la forma más sencilla de leer una línea completa en un programa de consola en C? El texto ingresado puede tener una longitud variable y no podemos hacer ninguna suposición sobre su contenido.
Cómo leer una línea desde la consola en C?
Construir su propia función , es una de las maneras que lo ayudaría a lograr leer una línea desde la consola en C.
Estoy usando la asignación de memoria dinámica para asignar solo la cantidad de memoria necesaria para contener todos los caracteres de una línea junto con el carácter
''/0''
.Y aquí estoy usando un bucle para escanear cada carácter de la cadena uno por uno usando la función
getchar()
hasta que el usuario ingrese''/n''
o el carácterEOF
//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; }
Ahora puedes leer una línea completa de esta manera:
char *line = NULL; line = scan_line(line);
Aquí hay un programa de ejemplo que usa la función 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
}
muestra de entrada:
Twinkle Twinkle little star.... in the sky!
muestra de salida:
Twinkle Twinkle little star.... in the sky!
Algo como esto:
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;
}
Como se sugiere, puede usar getchar () para leer desde la consola hasta que se devuelva un final de línea o un EOF, creando su propio búfer. El búfer en crecimiento puede ocurrir dinámicamente si no puede establecer un tamaño de línea máximo razonable.
También puede utilizar fgets como una forma segura de obtener una línea como una cadena con terminación nula 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);
Si ha agotado la entrada de la consola o si la operación ha fallado por algún motivo, se devuelve eof == NULL y el buffer de línea podría no haber cambiado (por eso es útil configurar el primer carácter en ''/ 0'').
fgets no sobrecargará la línea [] y garantizará que haya un valor nulo después del último carácter aceptado en un retorno exitoso.
Si se llegó al final de la línea, el carácter que precede a la terminación ''/ 0'' será ''/ n''.
Si no hay una terminación ''/ n'' antes de la terminación ''/ 0'', es posible que haya más datos o que la próxima solicitud informe de fin de archivo. Tendrás que hacer otros errores para determinar cuál es cuál. (En este sentido, bucle con getchar () es más fácil.)
En el código de ejemplo (actualizado) anterior, si la línea [sizeof (línea) -1] == ''/ 0'' después de los cambios exitosos, sabrá que el buffer se ha llenado por completo. Si esa posición es procesada por un ''/ n'', sabrá que tuvo suerte. De lo contrario, hay más datos o un final de archivo por delante en stdin. (Cuando el búfer no se llena por completo, aún podría estar en un final de archivo y también podría no haber un ''/ n'' al final de la línea actual. Ya que debe escanear la cadena para encontrar y / o eliminar cualquier ''/ n'' antes del final de la cadena (la primera ''/ 0'' en el buffer), estoy inclinado a preferir usar getchar () en primer lugar.)
Haga lo que tenga que hacer para lidiar con que haya más líneas que la cantidad que lee como primer trozo. Los ejemplos de un buffer de crecimiento dinámico se pueden hacer para trabajar con getchar o con fgets. Hay algunos casos de bordes complicados a tener en cuenta (como recordar que el siguiente inicio de entrada se almacena en la posición del ''/ 0'' que finalizó la entrada anterior antes de que se ampliara el búfer).
En sistemas BSD y Android también puedes usar fgetln
:
#include <stdio.h>
char *
fgetln(FILE *stream, size_t *len);
Al igual que:
size_t line_len;
const char *line = fgetln(stdin, &line_len);
La line
no tiene terminación nula y contiene /n
(o lo que sea que use su plataforma) al final. Se vuelve inválido después de la siguiente operación de E / S en la transmisión.
Entonces, si buscaba argumentos de comando, eche un vistazo a la respuesta de Tim. Si solo quieres leer una línea desde la consola:
#include <stdio.h>
int main()
{
char string [256];
printf ("Insert your full address: ");
gets (string);
printf ("Your address is: %s/n",string);
return 0;
}
Sí, no es seguro, puedes sobrepasar el búfer, no verifica el final del archivo, no admite codificaciones y muchas otras cosas. En realidad, ni siquiera pensé si esto CUALQUIERA de estas cosas. Estoy de acuerdo, me equivoqué :) Pero ... cuando veo una pregunta como "¿Cómo leer una línea desde la consola en C?", Supongo que una persona necesita algo simple, como get () y no 100 líneas de código como arriba. En realidad, creo que si tratas de escribir esas 100 líneas de código en realidad, cometerías muchos más errores de los que hubieras hecho si hubieras elegido;)
Es posible que necesite utilizar un bucle de carácter por carácter (getc ()) para asegurarse de que no tiene desbordamientos de búfer y no trunca la entrada.
Esta función debe hacer lo que quieras:
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 );
Espero que esto ayude.
Me encontré con el mismo problema hace un tiempo, esta fue mi solución, espero que ayude.
/*
* 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;
}
Muchas personas, como yo, llegan a este post con el título que coincide con lo que se busca, aunque la descripción se refiere a la longitud variable. Para la mayoría de los casos, sabemos la longitud de antemano.
Si conoces la longitud antes de la mano, prueba a continuación:
char str1[1001] = { 0 };
fgets(str1, 1001, stdin); // 1000 chars may be read
fuente: https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
Si está utilizando la biblioteca C de GNU u otra biblioteca compatible con POSIX, puede usar getline()
y pasarle stdin
para la secuencia de archivos.
Una implementación muy simple pero insegura para leer líneas para la asignación estática:
char line[1024];
scanf("%[^/n]", line);
Una implementación más segura, sin la posibilidad de desbordamiento de búfer, pero con la posibilidad de no leer toda la línea, es:
char line[1024];
scanf("%1023[^/n]", line);
No es la ''diferencia en uno'' entre la longitud especificada que declara la variable y la longitud especificada en la cadena de formato. Es un artefacto histórico.
getline
runnable example
Mencionado en esta respuesta, pero aquí hay un ejemplo.
Es POSIX 7 , asigna memoria para nosotros y reutiliza el búfer asignado en un bucle muy bien.
Pointer newbs, lea esto: ¿Por qué el primer argumento de getline es un puntero al puntero "char **" en lugar de "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;
}
implementación glibc
¿No hay POSIX? Quizás quieras ver la implementación de glibc 2.23 .
Se resuelve con getdelim
, que es un superconjunto POSIX simple de getline
con un terminador de línea arbitrario.
Dobla la memoria asignada cada vez que se necesita aumentar, y parece seguro para subprocesos.
Requiere una expansión macro, pero es poco probable que lo haga mucho mejor.
Necesita gestión dinámica de la memoria y utilizar la función fgets
para leer su línea. Sin embargo, parece que no hay forma de ver cuántos caracteres lee. Entonces usas 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;
}
Nota : ¡Nunca use gets! No hace controles de límites y puede desbordar tu memoria intermedia