Escribí esta función para leer una línea de un archivo:
const char *readLine(FILE *file) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
const char *constLine = line;
return constLine;
}
La función lee el archivo correctamente, y usando printf veo que la cadena constLine también se leyó correctamente.
Sin embargo, si uso la función, por ejemplo, así:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
printf produce galimatías. ¿Por qué?
fgets
lugar defgetc
. Estás leyendo carácter por carácter en lugar de línea por línea.getline()
es parte de POSIX 2008. Puede haber plataformas similares a POSIX sin él, especialmente si no son compatibles con el resto de POSIX 2008, pero dentro del mundo de los sistemas POSIX,getline()
es bastante portátil en estos días.Respuestas:
Si su tarea no es inventar la función de lectura línea por línea, sino solo leer el archivo línea por línea, puede usar un fragmento de código típico que involucre la
getline()
función (consulte la página del manual aquí ):fuente
getline
es específico de GNU libc, es decir, de Linux. Sin embargo, si la intención es tener una función de lectura de línea (en lugar de aprender C), hay varias funciones de lectura de línea de dominio público disponibles en la web.if(line)
cheque es superfluo. Llamarfree(NULL)
es esencialmente un no-op.fuente
(FILE*) fp
? ¿Nofp
es ya unaFILE *
y tambiénfopen()
devuelve unaFILE *
?getline
es una buena alternativa. Estoy de acuerdo en que elFILE *
reparto es innecesario.fp
afilePointer
para mayor claridad.En su
readLine
función, devuelve un puntero a laline
matriz (en sentido estricto, un puntero a su primer carácter, pero la diferencia es irrelevante aquí). Como es una variable automática (es decir, está "en la pila"), la memoria se recupera cuando la función regresa. Ves galimatías porqueprintf
ha puesto sus propias cosas en la pila.Debe devolver un búfer asignado dinámicamente desde la función. Ya tienes uno, es
lineBuffer
; todo lo que tiene que hacer es truncarlo a la longitud deseada.AGREGADO (respuesta a la pregunta de seguimiento en el comentario):
readLine
devuelve un puntero a los caracteres que forman la línea. Este puntero es lo que necesita para trabajar con el contenido de la línea. También es a lo que debe pasarfree
cuando haya terminado de usar la memoria tomada por estos personajes. Así es como puede usar lareadLine
función:fuente
fuente
fopen_s
hace que el código no sea portátil.printf
buscará especificadores de formato y no imprimirá signos de porcentaje y los siguientes caracteres como son . Los bytes nulos harán que todos los caracteres del resto de la línea desaparezcan. (¡No me digas que no pueden ocurrir bytes nulos!)readLine()
devuelve el puntero a la variable local, lo que provoca un comportamiento indefinido.Para moverte puedes:
readLine()
line
usarmalloc()
, en este casoline
será persistentefuente
Se usa
fgets()
para leer una línea desde un identificador de archivo.fuente
Algunas cosas están mal con el ejemplo:
fprintf(stderr, ....
fgetc()
lugar degetc()
.getc()
es una macrofgetc()
es una función adecuadagetc()
devuelve unint
soch
debe declararse como unint
. Esto es importante ya que la comparación conEOF
se manejará correctamente. Algunos juegos de caracteres de 8 bits se usan0xFF
como caracteres válidos (ISO-LATIN-1 sería un ejemplo) yEOF
que es -1, se0xFF
asignará a achar
.Hay un potencial desbordamiento del búfer en la línea
Si la línea tiene exactamente 128 caracteres,
count
es 128 en el punto que se ejecuta.Como otros han señalado,
line
es una matriz declarada localmente. No puede devolverle un puntero.strncpy(count + 1)
copiará a la mayoría de loscount + 1
caracteres pero terminará si golpea'\0'
Debido configuralineBuffer[count]
a'\0'
que sabe que nunca va a llegar acount + 1
. Sin embargo, si lo hiciera, no pondría una terminación'\0'
, por lo que debe hacerlo. A menudo ves algo como lo siguiente:si tiene
malloc()
una línea para devolver (en lugar de suchar
matriz local ), su tipo de retorno debería serchar*
: suelte elconst
.fuente
¿Qué hay de este?
fuente
Aquí están mis varias horas ... Leyendo todo el archivo línea por línea.
fuente
fgetc
lugar defgets
?tenga en cuenta que la variable 'línea' se declara en la función de llamada y luego se pasa, por lo que su
readLine
función llena el búfer predefinido y simplemente lo devuelve. Esta es la forma en que funcionan la mayoría de las bibliotecas de C.Hay otras formas, de las cuales soy consciente:
char line[]
como estático (static char line[MAX_LINE_LENGTH]
-> mantendrá su valor DESPUÉS de regresar de la función). -> mal, la función no es reentrante y puede producirse una condición de carrera -> si lo llama dos veces desde dos hilos, sobrescribirá sus resultadosmalloc()
ing la línea char [], y liberándola en funciones de llamada -> demasiados correos carosmalloc
, y delegando la responsabilidad de liberar el buffer a otra función (la solución más elegante es llamarmalloc
yfree
en cualquier buffer en la misma función)por cierto, la conversión 'explícita' de
char*
aconst char*
es redundante.por cierto, no hay necesidad de
malloc()
lineBuffer, solo defínalo, porchar lineBuffer[128]
lo que no es necesario liberarlopor cierto, no use 'matrices de pila de tamaño dinámico' (definiendo la matriz como
char arrayName[some_nonconstant_variable]
), si no sabe exactamente qué está haciendo, solo funciona en C99.fuente
Debe usar las funciones ANSI para leer una línea, por ejemplo. Fgets. Después de llamar, necesita free () en el contexto de la llamada, por ejemplo:
fuente
Implemente un método para leer y obtener contenido de un archivo (input1.txt)
Espero que esto ayude. ¡Feliz codificación!
fuente
Comete el error de devolver un puntero a una variable automática. La línea variable se asigna en la pila y solo vive mientras viva la función. No está permitido devolverle un puntero, porque tan pronto como regrese, la memoria se dará en otro lugar.
Para evitar esto, puede devolver un puntero a la memoria que reside en el montón, por ejemplo. lineBuffer y debería ser responsabilidad del usuario llamar a free () cuando haya terminado con él. Alternativamente, puede pedirle al usuario que le pase como argumento una dirección de memoria en la que escribir el contenido de la línea.
fuente
Quiero un código de la base 0, así que hice esto para leer el contenido de la palabra del diccionario línea por línea.
char temp_str [20]; // puede cambiar el tamaño del búfer de acuerdo con sus requisitos y la longitud de una sola línea en un archivo.
Tenga en cuenta que he inicializado el búfer con carácter nulo cada vez que leo la línea. Esta función se puede automatizar pero ya que necesito una prueba de concepto y quiero diseñar un programa Byte By Byte
fuente
int main() {
code
char temp_str [20] = {'\ 0'};code
c llenará automáticamente cada ranura con un terminador nulo, ya que la forma en que funcionan las declaraciones de matriz es que si una matriz se inicializa con menos elementos que contiene, el último elemento completará los elementos restantes.char temp_str[20] = {0}
también llena toda la matriz de caracteres con terminadores nulos.Mi implemento desde cero:
fuente
fgets
que podría usarse.Proporcione una función portátil y genérica
getdelim
, prueba aprobada a través de msvc, clang, gcc.fuente
fgets
existe?getdelim
permite delimitadores personalizados. También noto que no tengo un límite de longitud de línea, en este caso puedes usar la pila congetline
. (Ambos descritos aquí: man7.org/linux/man-pages/man3/getline.3.html )getdelim
ygetline
se estandarizó en POSIX.1-2008, alguien más lo menciona en esta página).fgets
también es estándar c, y no es específico de Linux