1

El programa consiste en crear un programa que tome datos de un archivo .data y realizar operaciones como:

  1. El monto promedio de todas las operaciones.
  2. El total del monto de todas las operaciones.
  3. El producto que más veces aparece en las ventas.

El formato de los datos del archivo son lineales de esta forma:

Nombre;Producto;Monto;Fecha;dd-mm-aaaa

Si me pudieran ayudar en como puedo hacer estas operaciones o darme una guía de como realizarlas, he intentado hacerlas pero ya la cabeza no me da para más, por favor si me pudieran ayudar que ya tengo poco tiempo para presentar el programa en la escuela. Aquí esta lo que he hecho hasta ahora:

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

typedef struct {
    char *nombre;
    int   codProducto;
    int   monto;
    int   dia;
    int   mes;
    int   year;
} personas;

personas *per;

void vaciar(char tenm[]);
void copiaNom(char temp[], int i);
void copiaPro(char temp[], int i);
void copiaMot(char temp[], int i);
void copiaDia(char temp[], int i);
void copiaMes(char temp[], int i);
void montoPromedio(char temp[]);

int main() {
    char temp[50];
    char aux;
    int  cont = 0;
    int  a, b, c, d, e, g, i;
    int  n3 = 0;

    FILE *f;
    f = fopen("prueba_test.data", "r");
    if (f == NULL) {
        printf("No se pudo encontrar el fichero.\n");
        exit(1);
    }

    while (!feof(f)) {
        fgets(temp, 50, f);
        cont++;
    }
    rewind(f);

    per = (personas *)malloc(cont * sizeof(personas));
    if (per == NULL) {
        printf("No se pudo resrvar memoria");
        exit(1);
    }

    for (i = 0; !feof(f); i++) {
        vaciar(temp);
        aux = 'j';

        // nombre
        for (a = 0; aux != ';'; a++) {
            aux = fgetc(f);
            if (aux != ';') {
                temp[a] = aux;
            }
        }
        copiaNom(temp, i);

        // producto
        vaciar(temp);
        aux = '0';
        for (b = 0; aux != ';'; b++) {
            aux = fgetc(f);
            if (aux != ';') {
                temp[b] = aux;
            }
        }
        copiaPro(temp, i);

        // monto
        vaciar(temp);
        aux = '0';
        for (c = 0; aux != ';'; c++) {
            aux = fgetc(f);
            if (aux != ';') {
                temp[c] = aux;
            }
        }
        copiaMot(temp, i);

        // dia
        vaciar(temp);
        aux = '0';
        for (d = 0; aux != '-'; d++) {
            aux = fgetc(f);
            if (aux != ';') {
                temp[d] = aux;
            }
        }
        copiaDia(temp, i);

        // mes
        vaciar(temp);
        aux = '0';
        for (e = 0; aux != '-'; e++) {
            aux = fgetc(f);
            if (aux != '-') {
                temp[e] = aux;
            }
        }
        copiaMes(temp, i);

        // year
        fgets(temp, 6, f);
        per[i].year = atoi(temp);

        printf("Nombre: %s Producto: %i Monto: %i Fecha: %i-%i-%i \n",
               per[i].nombre,
               per[i].codProducto,
               per[i].monto,
               per[i].dia,
               per[i].mes,
               per[i].year);
    }

    system("pause");
    return 0;
}

void vaciar(char temp[]) {
    int i;
    for (i = 0; i < 50; i++) {
        temp[i] = '\0';
    }
}

// copiando nombre
void copiaNom(char temp[], int i) {
    int N = strlen(temp) + 1;
    per[i].nombre = (char *)malloc(N * sizeof(char));
    if (per[i].nombre == NULL) {
        printf("No se pudo reservar memoria");
        exit(1);
    }

    strcpy(per[i].nombre, temp);
}
// copiando producto
void copiaPro(char temp[], int i) {
    int N = strlen(temp) + 1;

    per[i].codProducto = atoi(temp);
}
// copiando monto
void copiaMot(char temp[], int i) {
    int N = strlen(temp) + 1;

    per[i].monto = atoi(temp);
}
// copiando dia
void copiaDia(char temp[], int i) {
    int N = strlen(temp) + 1;

    per[i].dia = atoi(temp);
}
// copiando mes
void copiaMes(char temp[], int i) {
    int N = strlen(temp) + 1;

    per[i].mes = atoi(temp);
}
Pablochaches
  • 2,505
  • 1
  • 5
  • 21
  • Si estás usando C++ como lo sugieren los tags que agregaste a la pregunta, podrías considerar usar `new` y `delete`. Son las formas concisas que tiene C++ de asignar y liberar memoria dinámicamente. – Mateo Jul 20 '21 at 04:01
  • Por favor, _reescribe el título de tu pregunta_. Como está actualmente, las respuestas serán útiles solo para ti (ya que otros usuarios más adelante que tengan un problema similar no podrían llegar a esta pregunta). Lee [ask]. – padaleiana Jul 20 '21 at 12:19
  • Eso no es C++ es C. Te recomendiria que cambies los tags para que las respuestas esten mas centradas a lo que necesitas. – Pablochaches Jul 20 '21 at 15:03

2 Answers2

3

En el título de tu pregunta, pides ayuda para un programa C++. Te seré sincero, si estás trabajando con C++ lo primero que debes hacer es seleccionar todo tu código y borrarlo, pues ni una línea de las que has redactado es C++:

  • Las cabeceras <stdlib.h>, <string.h> y <stdio.h> son de , existen versiones adaptadas a que son <cstdlib>, <cstring> y <cstdio> y son las que deberías usar en caso de necesitarlas. Pero no es tu caso, no las necesitas.
  • En C++ las estructuras (struct) son tipos, así que no necesitan una definición de tipos (type definition) para ser tratadas como tal.
  • En C++ las cadenas de caracteres se manejan con el objeto std::string de la cabecera <string>, no se manejan como punteros a carácter.
  • En C++ la lectura de archivos se hace mediante un objeto de flujo de archivo de entrada o salida (std::ifstream y std::ofstream respectivamente), no se hace con FILE*.
  • En C++ se escribe en consola con el flujo de datos de salida a consola std::cout, no se hace con la función printf.
  • En C++ la memoria se pide con el operador new y se libera con el operador delete, no se pide con las función malloc ni se libera con la función free.

Esos son sólo los errores de confundir C con C++, pero tu código tiene malas prácticas:

  • La estructura personas (plural) almacena una sola persona, su nombre debería ser persona (singular).
  • Las variables deben tener un nombre que nos ayude a entender cuál es su misión, nombres como temp, aux, cont, a, b, c, d, e, g, i, n3 y f no aportan ninguna información de para qué se van a usar.
  • Las variables deben declararse cerca de donde se van a usar, esto ayuda a comprender mejor el código, puedes declarar las variables de indizado de tus bucles for en el propio bucle.
  • Tu indentación es una pesadilla.

Si programas en C++ tu código podría parecerse a:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <numeric>

struct persona{
    std::string nombre;
    int codProducto;
    int monto;
    int dia;
    int mes;
    int year;
};

template <auto separador>
auto split(const std::basic_string<decltype(separador)> &text)
{
    using string = std::basic_string<decltype(separador)>;

    std::basic_stringstream<decltype(separador)> reader(text);
    std::vector<string> result;
    string token;

    while (std::getline(reader, token, separador))
        result.push_back(token);

    return result;
}

int main()
{
    std::vector<persona> personas;

    if (std::ifstream datos{"prueba_test.data"})
    {
        std::string linea;
        while (std::getline(datos, linea))
        {
            const auto &registro = split<';'>(linea);
            const auto &fecha = split<'-'>(registro[3]);

            persona p
            {
                registro[0],
                std::stoi(registro[1]),
                std::stoi(registro[2]),
                std::stoi(fecha[0]),
                std::stoi(fecha[1]),
                std::stoi(fecha[2])
            };

            personas.push_back(p);

        }

        auto total = std::accumulate(personas.begin(), personas.end(), 0, [](int i, const persona &p) { return i + p.monto; });

        std::cout << "Total: " << total << '\n'
            << "Media: " << (total / personas.size());
    }
    else
        std::cout << "No se pudo abrir el fichero.\n";

    return 0;
}

Puedes ver el código funcionando en Try it online!, he usado una función split basada en la de este hilo.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
1

Las estructuras en C++ no necesitan typedef

Y ya de paso quita el plural al nombre, esa estructura solo almacena los datos de una persona, no de varias, luego el uso del plural complica la lectura del código

struct Persona { 
    char *nombre;
    int codProducto;
    int monto;
    int dia;
    int mes;
    int year;
};

Usa std::string en vez de array de chars

Ya es C++ bastante complejo de por sí como para que te vayas complicando la vida de forma totalmente gratuita:

struct Persona { 
    std::string nombre;
    int codProducto;
    int monto;
    int dia;
    int mes;
    int year;
};

En C++ las reservas de memoria se suelen gestionar con new y con delete

per = new Persona[cont];

// ...

delete[] per;

Mejor que new y delete, usa contenedores

La memoria dinámica es complicada de gestionar, si puedes evitar el lidiar con ella todo el rato, mejor.

std::vector<Persona> per; // Yo a esta variable la llamaria "personas"

Usa clases propias de C++ para leer del fichero (y para interactuar con el usuario)

std::ifstream fichero("prueba_test.data");
if (!fichero.is_open())
{
    std::cout << "No se pudo abrir el fichero\n";
    exit(1);
}

// Contar el número de líneas
// (con los contenedores ya no es necesario hacer esto)
int cont = std::count(std::istreambuf_iterator<char>(fichero), 
                           std::istreambuf_iterator<char>(),
                           '\n');

// Reseteamos el puntero interno del archivo
fichero.seekg(0);

Usar lógica propia de C++ en vez de la heredada de C te permite conseguir código más legible:

Persona persona;
std::getline(fichero, persona.nombre, ';');

if (!fichero.good()) break;

fichero >> persona.codProducto;
fichero.ignore(1);
fichero >> persona.monto;
fichero.ignore(1);
fichero >> persona.dia;
fichero.ignore(1);
fichero >> persona.mes;
fichero.ignore(1);
fichero >> persona.year;
fichero.ignore(1); // Descartamos el salto de línea (si lo hubiera)

personas.push_back(persona);

Como ves, ya no te hacen falta todas esas funciones de lectura

No uses variables globales

Las variables globales pueden ser bastante complicadas de gestionar. Evitar su uso te permitirá librarte de bastantes dolores de cabeza.

Tu programa en C++

Lo que llevas hecho, escrito en C++ de verdad, se parece más a esto:

#include <string>
#include <fstream>
#include <iostream>
#include <vector>

struct Persona { 
    std::string nombre;
    int codProducto;
    int monto;
    int dia;
    int mes;
    int year;
};

int main()
{
    std::vector<Persona> personas;
    
    std::ifstream fichero("prueba_test.data");
    
    while(fichero.good())
    {
        Persona persona;
        std::getline(fichero, persona.nombre, ';');
    
        if (!fichero.good()) break;
    
        fichero >> persona.codProducto;
        fichero.ignore(1);
        fichero >> persona.monto;
        fichero.ignore(1);
        fichero >> persona.dia;
        fichero.ignore(1);
        fichero >> persona.mes;
        fichero.ignore(1);
        fichero >> persona.year;
        fichero.ignore(1);
        
        personas.push_back(persona);
    }

    for (auto const& persona : personas)
    {
        std::cout << "Nombre: " << persona.nombre << '\n'
                  << "Producto: " << persona.codProducto << '\n'
                  << "Monto: " << persona.monto << '\n'
                  << "Fecha: " << persona.dia << '-' << persona.mes << '-' << persona.year << '\n'
                  << '\n';
    }
}

No voy a decirte cómo hacer las partes que te faltan ya que la idea de estos ejercicios es que aprendas, no que te lo den todo hecho.

Mucho ánimo y suerte.

eferion
  • 49,291
  • 5
  • 30
  • 72