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é?

fgetslugar 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
getlinees 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? ¿Nofpes ya unaFILE *y tambiénfopen()devuelve unaFILE *?getlinees una buena alternativa. Estoy de acuerdo en que elFILE *reparto es innecesario.fpafilePointerpara mayor claridad.En su
readLinefunción, devuelve un puntero a lalinematriz (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 porqueprintfha 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):
readLinedevuelve 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 pasarfreecuando haya terminado de usar la memoria tomada por estos personajes. Así es como puede usar lareadLinefunción:fuente
fuente
fopen_shace que el código no sea portátil.printfbuscará 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()lineusarmalloc(), en este casolineserá 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 unintsochdebe declararse como unint. Esto es importante ya que la comparación conEOFse manejará correctamente. Algunos juegos de caracteres de 8 bits se usan0xFFcomo caracteres válidos (ISO-LATIN-1 sería un ejemplo) yEOFque es -1, se0xFFasignará a achar.Hay un potencial desbordamiento del búfer en la línea
Si la línea tiene exactamente 128 caracteres,
countes 128 en el punto que se ejecuta.Como otros han señalado,
linees una matriz declarada localmente. No puede devolverle un puntero.strncpy(count + 1)copiará a la mayoría de loscount + 1caracteres 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 sucharmatriz 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
fgetclugar 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
readLinefunció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 llamarmallocyfreeen 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() {codechar temp_str [20] = {'\ 0'};codec 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
fgetsque podría usarse.Proporcione una función portátil y genérica
getdelim, prueba aprobada a través de msvc, clang, gcc.fuente
fgetsexiste?getdelimpermite 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 )getdelimygetlinese estandarizó en POSIX.1-2008, alguien más lo menciona en esta página).fgetstambién es estándar c, y no es específico de Linux