Consulta con archivos en C y un arreglo

Iniciado por palacio29, 21 Mayo 2020, 07:01 AM

0 Miembros y 1 Visitante están viendo este tema.

palacio29

Tengo un problema con el siguiente codigo.
Basicamente.
1) Leo desde un archivo cierta información y la guardo en un arreglo de char.
2) Lo imprimo en pantalla (Hasta aca todo joya)
3) Cuando llamo a la funcion auxiliares lo que hace es abrir otro archivo y guardar esa informacion en otro arreglo de char.
4) No se porque cuando llamo a esta ultima funcion (auxiliares), al hacer un printf del contenido en la posicion 0 del primer arreglo, se borra.
Adjunto informacion de los 2 archivos al final
Espero que alguien pueda ayudarme porque no encuentro el error.

#include <stdio.h>
#include <stdlib.h>
#define F 10
#define C 50
void lectura(char arreglo[F][C]);
void imprimir(char arreglo[F][C]);
void auxiliares(char arreglo[2][C]);
int main()
{
    char arreglo[F][C];
    char aux[2][C];
    lectura(arreglo);
    printf("Imprimir:\n \n");
    imprimir(arreglo);
    printf("El valor 0 del arreglo es: %s\n",arreglo[0]);  ///Aca imprime perfecto el contenido
    auxiliares(aux);
    printf("El valor 0 del arreglo es: %s\n",arreglo[0]);  ///Aca el mismo contenido ya no lo imprime, aparece vacio
    printf("El valor 0 del arreglo es: %s",arreglo[1]);    ///Aca los demas elementos si los tiene, pero no el de la posicion 0
    return 0;
}
void lectura(char arreglo[F][C])
{
    int i=0,j=0,r;
    char letra;

    FILE*arch=NULL;
    arch=fopen("nomina.txt","r");
    letra=fgetc(arch);
    while(letra!=EOF && i<F)
    {
        while(letra!='\n' && j<C)
        {
            arreglo[i][j]=letra;
            j++;
            letra=fgetc(arch);
        }
        arreglo[i][j]='\0';
        j=0;
        i++;
        letra=fgetc(arch);
    }
    arreglo[i][0]=0;
}

void imprimir(char arreglo[F][C])
{
    int i=0;
    while(arreglo[i][0]!=0)
    {
        printf("%s\n",arreglo[i]);
        i++;
    }
}
void auxiliares(char aux[2][C])
{
    int i=0,j=0;
    char letra;
    FILE*arch=NULL;
    arch=fopen("actualizaciones.txt","r");
    letra=fgetc(arch);
    while(letra!=EOF)
    {
        while(letra!='\n' && j<C)
        {
            aux[i][j]=letra;
            j++;
            letra=fgetc(arch);
        }
        aux[i][j]='\0';
        i++;
        j=0;
        letra=fgetc(arch);
    }
    aux[i][j]='\0';
}



Archivo "nomina.txt" --->Contenido:
Juan Perez
Marta Saldiva
Juana Dorrego
Juan Perez
Susana Rodriguez
Pilar Santoro   
Juan Perez

Archivo "actualizaciones.txt" --->Contenido:
Juan Perez
Graciela Arpe

K-YreX

Lo que veo son varios problemas de acceso y eso es lo que está generando tu problema.

Función lectura():
  • Si el bucle de la línea 31 sale porque j == C, en la línea 37 tienes un acceso a memoria fuera de los límites del array.
  • Si el bucle de la línea 29 sale porque i == F, en la línea 42 tienes otro acceso fuera del array.

    Además no sé si es obligatorio que hagas así la lectura pero sino es mucho mejor que uses la función fgets():

    // Guarda el contenido de un archivo en un array bidimensional por lineas y devuelve el numero de lineas leidas
    int lectura(char array[][C]){
      FILE *archivo = fopen("loquesea.txt", "r");
      int fila = 0;
      // fgets guarda C-1 caracteres de una linea del archivo y pone '\0' al final
      while(fila < F && fgets(array[fila], C, archivo)) ++fila;
      return fila;
    }


    Y en la función auxiliares() tienes los mismos problemas que en lectura() además de que no controlas el límite de líneas leídas. Si el array tiene 2 filas y el fichero tiene n filas estás realizando n-2+1 accesos a memoria fuera del array.
    Al ejecutarse la línea 74, el programa se detendría si intenta acceder a memoria fuera del ámbito de tu ejecutable. Si no se detiene está modificando algo y en tu caso ese algo es el elemento arreglo[0][0].
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

palacio29

Modifique esta funcion y le agregue en la linea 8 el i<2.
Lo que no entiendo es porque funciona mal si en el while en la linea 10, como los nombres no son tan largos, lo primero que va a encontrar es el \n y la linea 21 por mas que la saque queda igual.
Es re loco esto, nunca me paso
Por cierto, lo del fgets funciona perfecto en el ejercicio, pero como que me hinchan mucho que use el fgetc lo tengo que hacer asi.
O que forma de hacer el fgetc recomendas para que no me pase esto?


auxiliares(char aux[2][C])
{
    int i=0,j=0;
    char letra;
    FILE*arch=NULL;
    arch=fopen("actualizaciones.txt","r");
    letra=fgetc(arch);
    while(letra!=EOF && i<2)
    {
        while(letra!='\n' && j<C)
        {
            aux[i][j]=letra;
            j++;
            letra=fgetc(arch);
        }
        aux[i][j]='\0';
        i++;
        j=0;
        letra=fgetc(arch);
    }
    aux[i][j]='\0';
}

K-YreX

#3
Cita de: palacio29 en 21 Mayo 2020, 08:17 AM
Modifique esta funcion y le agregue en la linea 8 el i<2.
Lo que no entiendo es porque funciona mal si en el while en la linea 10, como los nombres no son tan largos, lo primero que va a encontrar es el \n y la linea 21 por mas que la saque queda igual.
Aunque añadas la segunda condición en la línea 8 sigues teniendo el problema que tienes en la función lectura().
Te lo muestro por pasos (función auxiliares()):

1. i = 0 -> i < 2?? Sí -> Entra a los dos bucles -> Guarda "Juan Perez" -> Sale -> i++
2. i = 1 -> i < 2?? Sí -> Entra a los dos bucles -> Guarda "Graciela Arpe" -> Sale -> i++
3. i = 2 -> i < 2?? No -> Va a la línea 21 -> aux[2][0] = '\0'

Al final accedes a aux[2][0] y tu array es de 2 dimensiones por lo que solo tiene las filas {0,1}. Esto es un acceso fuera de la memoria permitida. Coincide que justo donde acaba tu array aux, empieza el espacio de memoria de arreglo. Entonces el programa accede sin querer a arreglo[0][0] (que repito, el programa calcula la posición de memoria en la que tendría que estar aux[2][0] pero se encuentra con que esa posición es la de arreglo[0][0]) y cambia su valor.

La forma de hacerlo con fgetc para que no pase esto es... haciéndolo bien  :xD. Es decir, tratando correctamente cada posible situación:

i = 0
letra = fgetc(fichero)
while(i < F && letra != NULL){
 j = 0
 // La ultima columna siempre va a tener \0 entonces no hace falta guardar nada del fichero ahi
 while (j < C-1 AND letra != NULL AND letra != '\n'){
   arreglo[i][j] = letra
   ++j
   letra = fgetc(fichero)
 }
 // Una vez salimos, siempre podemos poner el \0 sin miedo a salirnos porque solo hemos ido hasta C-1
 arreglo[i][j] = '\0'
  if(letra != NULL) letra = fgetc(fichero);
 ++i
}
return i


Igual que antes, en vez de poner un 0 en la primera línea vacía, es mejor que devuelvas el número de filas útiles que tiene tu array. Luego guarda dicho valor en una variable y úsalo cuando quieras mostrar el array. Así no malgastas una fila entera para nada.

Si sigo sin convencerte y quieres poner un 0 al final, recorre el bucle de fuera para i < F-1. Así siempre dejarás la última fila libre para poder guardar ese 0.


EDIT: En el código anterior me he dejado el leer otro carácter al salir del bucle interno. Ahora lo corrijo... :rolleyes:
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

palacio29

Muchisimas gracias, al final entendi ;-),
Tremenda suerte la mia que con tantas direcciones de memoria justo tienen que salir todas juntitas.
Lo que yo estaba haciendo era poner una linea de mas para que en la impresion lea hasta que encuentre un /0 en el primer elemento,pero mi arreglo no tenia 3 posiciones, sino 2, y ahi era el problema.
Te copio el ultimo codigo para hacerlo mejor.
Sos un crack! ;-)