Search code examples
cfilestructfgetstxt

Problem with duplicate data in fgets with structs


I have a program that seems to have a problem displaying the data received from a .txt file with fgets Basically the program is something similar to a CRUD or ABM (in Spanish). The problem is that when I show the structs from the file, it shows me a duplicate of the last struct.

The code is the following:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>

// ==== Estructura Empleado ====
typedef struct
{
  int legajo; // Numero de 6 digitos
  char nombreApellido[30];
  float sueldo; // Aleatorio entre 80k-200k
} Empleado;

// Carga un empleado por teclado; Devuelve un struct Empleado
Empleado cargarEmpleadoPorTeclado();

// Carga un vector de Empleado
void cargarEmpleadosPorTeclado(Empleado empleados[], int cantidadEmpleados);

// Recibe un vector de chars y devuelve un struct Empleado
Empleado parsearEmpleado(char datosSinParsear[50], int largoDatos);

// Carga los empleados desde el archivo al vector empleados[]
void cargarEmpleadosEnVector(Empleado empleados[], int cantidadEmpleados);

// Guarda los empleados en el archivo 'empleados.txt'
void guardarEmpleados(Empleado empleados[], int cantidadEmpleados);

// Muestra los empleados cargados en el vector empleados[]
void mostrarEmpleadosDesdeArchivo(int cantidadEmpleados, int eliminados);

// Busca un empleado por legajo en el archivo 'empleados.txt' y lo 'elimina'
void eliminarEmpleadoPorLegajo(Empleado empleados[], int legajo, int cantidadEmpleados, int * eliminados);

void eliminarEmpleadoVectorPorLegajo(Empleado empleados[], int legajo, int cantidadEmpleados, int *eliminados);

void menu(Empleado empleados[], int cantidadEmpleados);

/* ==== Funcion main ==== */
int main()
{
  int cantidadEmpleados = 100;
  Empleado empleados[cantidadEmpleados];

  menu(empleados, cantidadEmpleados);

  return 0;
}

/* ==== Implementaciones ==== */

Empleado cargarEmpleadoPorTeclado()
{
  Empleado empleado;

  printf("\nIngrese el Nombre y Apellido del empleado: ");
  fflush(stdin);
  gets(empleado.nombreApellido);

  printf("\nIngrese el numero de Legajo del empleado: ");
  fflush(stdin);
  scanf("%d", &empleado.legajo);

  empleado.sueldo = 80000 + rand() % (200000-80000);

  return empleado;
}

void cargarEmpleadosPorTeclado(Empleado empleados[], int cantidadEmpleados)
{
  for (int i = 0; i < cantidadEmpleados; i++)
  {
    empleados[i] = cargarEmpleadoPorTeclado();
  }
  guardarEmpleados(empleados, cantidadEmpleados);
}

Empleado parsearEmpleado(char datosSinParsear[], int largoDatos)
{
  Empleado empleado;

  int delimitador1 = -1;
  int delimitador2 = -1;

  char auxiliarLegajo[10] = " ";
  char auxiliarNombreApellido[30] = " "; 
  char auxiliarSueldo[10] = " ";

  for(int i = 0; i < largoDatos; i++)
  {
    // Recorro el string hasta encontrar la primera ocurrencia
    // Notese que i = largoDatos es para forzar la salida del for y no sobreescribir el valor de delimitador1
    // con la segunda ocurrencia
    if(datosSinParsear[i] == ';')
    {
      delimitador1 = i;
      i = largoDatos;
    }
  }
  // Recorro el string a partir de la posicion siguiente de la primera ocurrencia
  for (int i = delimitador1 + 1; i < largoDatos; i++)
  {
    if (datosSinParsear[i] == ';')
    {
      delimitador2 = i;
    }
  }

  if ((delimitador1 != -1) && (delimitador2 != -1))
  {
    // Desde 0 hasta delimitador1 tenemos el legajo
    for (int i = 0; i < delimitador1; i++)
    {
      auxiliarLegajo[i] = datosSinParsear[i];
    }

    // Desde delimitador1+1 hasta delimitador2 tenemos el nombre y apellido
    for (int i = delimitador1 + 1; i < delimitador2; i++)
    {
      auxiliarNombreApellido[i - delimitador1 - 1] = datosSinParsear[i];
    }

    // Desde delimitador2+1 hasta largoDatos tenemos el sueldo en float
    for (int i = delimitador2 + 1; i < strlen(datosSinParsear); i++)
    {
      auxiliarSueldo[i - delimitador2 - 1] = datosSinParsear[i];
    }

    empleado.legajo = atoi(auxiliarLegajo);
    strcpy(empleado.nombreApellido, auxiliarNombreApellido);
    empleado.sueldo = atof(auxiliarSueldo);

    return empleado;
  }
}

void cargarEmpleadosEnVector(Empleado empleados[], int cantidadEmpleados)
{
  // Intentamos abrir el archivo y verificamos si no es un puntero nulo
  FILE * archivoEmpleados = fopen("empleados.txt", "r");

  if(archivoEmpleados != NULL)
  {
    int i = 0;

    while (!feof(archivoEmpleados) && (i < cantidadEmpleados))
    {
      char datosSinParsear[50] = "";
      Empleado empleadoActual;

      // Leemos los datos y lo parseamos
      fgets(datosSinParsear, 50, archivoEmpleados);
      empleadoActual = parsearEmpleado(datosSinParsear, 50);

      // Lo asignamos a la posicion actual del vector 'empleados[]'
      empleados[i] = empleadoActual;

      i++;
    }
    fclose(archivoEmpleados);
  }

  // Si el archivo no existe o no lo encuentra
  else 
  {
    printf("\nImposible leer los empleados\nEl archivo \"empleados.txt\" no existe o no se encuentra en la ruta actual");
    exit(-1);
  }
}

void guardarEmpleados(Empleado empleados[], int cantidadEmpleados)
{
    // Intentamos abrir el archivo y verificamos si no es un puntero nulo
  FILE * archivoEmpleados = fopen("empleados.txt", "w");

  if(archivoEmpleados != NULL)
  {
    for (int i = 0; i < cantidadEmpleados; i++)
    {
      // Grabamos los datos linea por linea con el formato 'legajo;nombreapellido;sueldo'
      fprintf(archivoEmpleados, "%d;%s;%.2f\n", empleados[i].legajo, empleados[i].nombreApellido, empleados[i].sueldo);
    }
    printf("\nEmpleados guardados exitosamente en \"empleados.txt\"");
    fclose(archivoEmpleados);
  }

  // Si el archivo no existe o no lo encuentra
  else 
  {
    printf("\nImposible guardar los empleados\nEl archivo \"empleados.txt\" no existe o no se encuentra en la ruta actual");
    exit(-1);
  }
}

void mostrarEmpleadosDesdeArchivo(int cantidadEmpleados, int eliminados)
{
  FILE * archivoEmpleados = fopen("empleados.txt", "r");

  int i = 0;

  while(!feof(archivoEmpleados) && i < (cantidadEmpleados-eliminados))
  {
    char datosSinParsear[50] = "";
    fgets(datosSinParsear, 50, archivoEmpleados);

    Empleado empleadoActual;

    empleadoActual = parsearEmpleado(datosSinParsear, 50);
    
    printf("\nEmpleado");
    printf("\n\t* Numero de legajo: %d", empleadoActual.legajo);
    printf("\n\t* Nombre y Apellido: %s", empleadoActual.nombreApellido);
    printf("\n\t* Sueldo (en pesos): %.2f", empleadoActual.sueldo);
    
    i++;
  }
  fclose(archivoEmpleados);
}

/*
Esta funcion no elimina en si la linea que pertenezca al empleado
Sino mas bien, la omitiria cuando la lea, escribiendo un archivo nuevo con el mismo nombre
De esa forma, estariamos haciendo lo mismo
*/
void eliminarEmpleadoPorLegajo(Empleado empleados[], int legajo, int cantidadEmpleados, int *eliminados)
{
  // Intentamos abrir el archivo y verificamos si no es un puntero nulo
  FILE * archivoEmpleados = fopen("empleados.txt", "r");

  // Creamos un nuevo archivo para escribir los datos
  FILE * nuevoArchivoEmpleados = fopen("empleados2.txt", "w");

  if(archivoEmpleados != NULL)
  {
    int i = 0;
    while (!feof(archivoEmpleados) && i < cantidadEmpleados)
    {
      char datosSinParsear[50] = "";
      Empleado empleadoActual;

      // Recibimos los datos y los parseamos
      fgets(datosSinParsear, 50, archivoEmpleados);
      empleadoActual = parsearEmpleado(datosSinParsear, 50);

      /*
      Cuando no coincida el legajo, escribe
      Si es que llega a coincidir (justamente ese debemos eliminar), no lo escribimos,
      simplemente, hacemos una iteración y continuamos el bucle
      */      
      if (empleadoActual.legajo != legajo)
      {
        fprintf(nuevoArchivoEmpleados, "%d;%s;%.2f\n", empleadoActual.legajo, empleadoActual.nombreApellido, empleadoActual.sueldo);
        i++;
      }
      else
      {
        i++;
        continue;
      };
    }
    fclose(archivoEmpleados);
    fclose(nuevoArchivoEmpleados);

    remove("empleados.txt");
    rename("empleados2.txt", "empleados.txt");

    eliminarEmpleadoVectorPorLegajo(empleados, legajo, cantidadEmpleados, &eliminados);

    *eliminados = *eliminados + 1;

    printf("\nEmpleado con legajo numero %d eliminado exitosamente", legajo);
  }

  // Si el archivo no existe o no lo encuentra
  else 
  {
    printf("\nImposible eliminar al empleado\nEl archivo \"empleados.txt\" no existe o no se encuentra en la ruta actual");
    exit(-1);
  }
}

void eliminarEmpleadoVectorPorLegajo(Empleado empleados[], int legajo, int cantidadEmpleados, int *eliminados)
{
  int posicionDelElemento = -1;

  for (int i = 0; i < cantidadEmpleados; i++)
  {
    if(empleados[i].legajo == legajo)
    {
      posicionDelElemento = i;
      i = cantidadEmpleados;
    }
  }

  for(int i = posicionDelElemento - 1; i<cantidadEmpleados-1; i++)
  {
    empleados[i] = empleados[i + 1];
  }
  cantidadEmpleados--;
}

void menu(Empleado empleados[], int cantidadEmpleados)
{
  int sigue = 1;
  int eliminados = 0;
  int cantidadEmpleadosVar = 0;

  printf("\nMenu Empleados\n");
  printf("\nOpciones:\n");
  printf("\n\t1. Listar los empleados");
  printf("\n\t2. Agregar un empleado");
  printf("\n\t3. Eliminar un empleado");
  printf("\n\t4. Salir");

  do
  {
    int opcion;
    int legajo;

    printf("\nIngrese opcion > ");
    scanf("%d", &opcion);

    switch (opcion)
    {
    case 1:
      printf("\nMostrando empleados cargados");
      mostrarEmpleadosDesdeArchivo(cantidadEmpleados, eliminados);
      break;

    case 2:
      printf("\nAgregar un empleado:");
      printf("\nCuantos empleados desea cargar? > ");
      
      scanf("%d", &cantidadEmpleadosVar);
      cargarEmpleadosPorTeclado(empleados, cantidadEmpleadosVar);
      break;
    
    case 3:
      printf("\nEliminando un empleado:");
      printf("\nIngrese el numero de legajo del empleado a eliminar > ");
      scanf("%d", &legajo);
      eliminarEmpleadoPorLegajo(empleados, legajo, cantidadEmpleados, &eliminados);
      break;

    case 4:
      sigue = 0;
      break;

    default:
      printf("\nLa opcion \"%d\" no es valida, ingrese otra vez\n\n", opcion);
      continue;
      break;
    }
  } while (sigue);
}

And the empleados.txt file is the following:

555666;Leandro;80041.00
232433;Juan;80945.00
234443;Antonio;90485.00
119304;Manuel;102943.00

The output is: Code output linked on imgur

Does anyone know what this error could be?


Solution

  • There are many issues in your code, here are some important ones:

    Also use more spaces for indentation, 4 is recommended for readability.