1

Sucede que el programa que tengo se detiene.

Se supone que debe leer:

  • Nombre
  • Cédula
  • 5 lanzamientos
  • Lanzamiento mayor
  • Promedio de lanzamientos

Todo eso en un array/vector, eh abierto un for que recorre a los 10 atletas, el for hace 9 ciclos, en el 10mo lee el nombre y cédula del atleta numero 10 y justo despues de "leer" el primer lanzamiento el programa deja de funcionar.

"Proyecto.exe ha dejado de funcionar"

(esos lanzamientos están dentro de una matriz, por lo tanto uso un for para ahorrar lineas de código)

Todo eso sucedió luego que de cambiara todos los valores iniciales de cada for de 0 a 1

for (i=0 ; i<10 ; i++)  ------>>   for (i=1 ; i<11 ; i++)
#include <iomanip>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

using namespace std;

int main(int argc, char *argv[]) {
    struct atleta {
        char n[30];
        float lm,l[5],prom,pr;
        int ced,acc;
    };
    struct atleta at[10]; //Esta vaina es la estructura //

    int m,i,j,k,f1,f2,c1,c2,f3,c3,f4,c4,q,w,t,e;
    float lm2;
    int op;
    char resp='s';

    while (resp=='s' || resp=='S')
    {
    //menu <<abre//
    cout<<endl<<"Bienvenido al programa, escoga una de las siguientes opciones para continuar";
    cout<<endl;
    cout<<endl<<"ingresar datos de los atletas (recomendado)= 1";
    cout<<endl<<"Modificar los datos de un atleta= 2";
    cout<<endl<<"Mostrar un listado de todos los atletas= 3";
    cout<<endl<<"Mostar los datos de un atleta segun su cedula= 4";
    cout<<endl<<"Mostar los datos del ganador= 5";
    cout<<endl<<"Atletas cuyo promedio es supera los 70 metros=; 6";
    cout<<endl<<"Salir= 7";
    for (k=1;k<2;k++)
    {
        op=0;
        cout<<endl<<endl<<"Indique su opcion: ";    cin>>op;
        if(op<=0)
        {
            //system ("cls");
            cout<<endl<<"Indique una opcion valida1";
            k--;

        }
        else
        {

        }
    }

    //menu <<cierra//

    switch (op) 
    {
    case 1:
        system ("cls");
        for(i=1;i<11;i++) //leer datos de los 10 atletas <<abre// este es el original
        {
            cout<<endl<<"Indique el nombre del atleta Nº"<<i<<": ";
            fflush(stdin);
            gets (at[i].n);

            for (j=1;j<2;j++) //leer y validar la cedula <<abre//
            {
                cout<<endl<<"Indique la cedula del atleta: ";
                cin>>at[i].ced;
                if (at[i].ced>0 && at[i].ced<=99999999)
                {
                    //cout<<endl<<"Cedula Valida";
                }   
                else
                {
                cout<<endl<<"Ingrese una cedula valida";
                j--;
                }
            } //leer y validar la cedula <<cierra//

            cout<<endl<<"A continuacion indique los 5 lanzamientos del atleta";
            cout<<endl;
            at[i].acc=0;
            for (c1=1;c1<6;c1++) //leer y validar los 5 lanzamientos <<abre//
            {
                cout<<endl<<"ingrese el lanzamiento numero "<<c1<<": "; 
                cin>>at[i].l[c1]; //el for principal se ejecuta 10 veces a la 10ma vez el exe deja de funcionar justo aqui

                if (at[i].l[c1]<0)
                    c1--;
                else
                {

                }
                at[i].acc=at[i].acc+at[i].l[c1]; //promedio de lanzamientos del atleta de turno <<abre//

            } //leer y validar los 5 lanzamientos <<cierra//
            cout<<at[i].acc<<endl;
            at[i].prom=(at[i].acc)/5;       //promedio de lanzamientos del atleta de turno <<cierra//
            cout<<at[i].prom<<endl;
            //calcular el lanzamiento mayor del atleta <<abre//
            at[i].lm=0;

                for (c2=1;c2<6;c2++)
            {
                    if (at[i].l[c2]>at[i].lm)
                        at[i].lm=at[i].l[c2];
                    else
                        at[i].lm=at[i].lm;
            } //calcular el lanzamiento mayor del altleta <<cierra//

        } //ingresar los datos de los 10 atletas <<cierra//
        break;
    case 2: //modificar los datos de un atleta
        cout<<endl<<"indique el numero del altleta a modificar";
        cin>>m;
        for (e=1;e<2;e++)
        {
            if (m<0 && m>10)
            {
                cout<<endl<<"indique un numero valido";
                e--;
            }
            else{}
        }
        cout<<endl<<"indique el nombre";
        cin>>at[m].n;
        cout<<endl<<"indique la cedula";
        cin>>at[m].ced;
        for (t=1;t<2;t++)
        {
            if (at[t].ced>0 && at[t].ced<=99999999)
            {}  
            else
            {
                cout<<endl<<"Ingrese una cedula valida";
                t--;
            }
        };
        for (f1=1;f1<6;f1++)
        {
            cout<<endl<<"Indique el lanzamiento Nº"<<f1<<" :";
            cin>>at[m].l[f1];

            if(at[m].l[f1]<0)
            {
                cout<<endl<<"Indique una cantidad valida";
                f1--;
            }
            else {}
        }
        break;
    case 3: //mostrar los datos de todos los atletas
        system ("cls");
        cout<<endl<<"N"<<"==Ced"<<"==L1"<<"==L2"<<"==L3"<<"==L4"<<"==L5"<<"==LM"<<"==Prom"<<endl;
        for (f4=1;f4<11;f4++)
        {
            cout<<at[f4].n<<"=="<<at[f4].ced;
            for (c4=1;c4<6;c4++)
            {
                cout<<"=="<<at[f4].l[c4];
            }
            cout<<"=="<<at[f4].lm<<"=="<<at[f4].prom<<endl;
        }
        break;
    case 4: //datos de un atleta segun su cedula (utilizando una funcion)
        system ("cls");

        break;
    case 5: //atleta ganador y sus datos
        system ("cls");
        lm2=0;
        for (f3=1;f3<11;f3++)
        {
            if (at[f3].lm>lm2)
                lm2=at[f3].lm;
            else
                lm2=lm2; //lanzamiento mayor calculado//
        }
        for(f2=1;f2<11;f2++)
        {
            if(lm2==at[f2].lm)
            {
                cout<<endl<<"Atleta ganador";
                cout<<at[f2].n<<"="<<at[f2].ced;
                for (c3=1;c3<6;c3++)
                {
                    cout<<"="<<at[f2].l[c3];
                }
                cout<<"="<<at[f2].lm;
                cout<<"="<<at[f2].prom;
            }
            else {}
        }
        break;
    case 6: //atletas con un promedio mayor a 70
        system ("cls");
        for(q=1;q<11;q++)
        {
            at[q].pr=0;
            if(at[q].prom>70)
            {
                at[q].pr=at[q].prom;
            }
            else{}
        }
        for (w=1;w<11;w++)
        {
            if(at[w].pr>70)
            {
                cout<<at[w].n<<"="<<at[w].ced;
                for (c4=1;c4<6;c4++)
                {
                    cout<<"="<<at[w].l[c4];
                }
                cout<<"="<<at[w].lm;
                cout<<"="<<at[w].prom<<endl;
            }
            else{}
        }
        break; 
    case 7: //salir
        system ("cls");
        cout<<endl;
        break;
    default:
        system ("cls");
        cout<<endl<<"Indique una opcion valida"<<endl;
    } //switch case <<cierra//
    cout<<endl<<"para volver al menu presione 's', para salir del programa presione cualquier otra tecla"; cin>>resp;
    system ("cls");
    } //while <<cierra//
    return 0;
}
PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82

4 Answers4

5

Todo eso sucedió luego que de cambiara todos los valores iniciales de cada for de 0 a 1

Los índices empiezan siempre en 0... ¿Por qué empeñarse entonces en reinventar la rueda y hacer que empiecen en 1?

Si haces ese cambio tienes que cambiar todos los accesos al vector:

at[i]   // MAL!!!!!
at[i-1] // BIEN

Si no haces esto suceden dos cosas:

  1. En la primera iteración (i==1), estás accediendo directamente al segundo elemento, luego estarás ignorando el primer elmento siempre. Esto no causa errores de ejecución pero no es un comportamiento deseado.
  2. En la última iteración (i==10), estarás accediendo a un elemento que no pertenece al vector. Lo que sucede aquí es que accedes a memoria que no pertenece a tu vector... si la memoria a la que accedes pertenece a tu programa pisarás memoria y el programa se volverá errático... si la memoria no te pertenece el Sistema Operativo matará tu proceso para evitar que corrompas memoria de otros procesos.

Así pues, te sugiero que te hagas un favor y te acostumbres a recorrer los vectores en el rango (0..n-1) en vez de en el rango (1..n). Conseguirás que tu código esa compatible con el del 100% de los programadores que saben hacer las cosas.

Y ya hablando que hablamos de tu código:

¿¿??

Este código no tiene ningún sentido:

for (k=1;k<2;k++)
{
    op=0;
    cout<<endl<<endl<<"Indique su opcion: ";    cin>>op;
    if(op<=0)
    {
        //system ("cls");
        cout<<endl<<"Indique una opcion valida1";
        k--;

    }
    else
    {

    }
}

Tu idea es iterar hasta que el usuario introduzca una opción válida... para eso existe while cuya traducción mientras es más adecuada a este contexto. En beneficio de tu propia salud, procura que el código sea lo más legible posible:

do
{
  cout<<endl<<endl<<"Indique su opcion: ";
  cin>>op;
  if(op<=0)
    cout<<endl<<"Indique una opcion valida\n";
} while( op <= 0 );

No mezcles buffers

En tu programa estás usando las librerías iostream y stdio.h. La primera es propia de C++ y la segunda una reminiscencia para mantener cierta compatibilidad con C... pero no deberías usarla.

Uno de los motivos que esgrimen muchos gurús que está aprendiendo para justificar que C es mucho más rápido que C++ es que la lectura de datos en C++ es lentísima... bien esto es así porque, justamente por mantener stdio.h, se fuerza a que ambos sistemas estén sincronizados... lo que crea un sobreesfuerzo en la capa de C++... sin embargo lo que estos gurús no saben es que esta sincronización se puede deshabilitar... permitiendo que las lecturas en C++ sean más rápidas que las de C.

std::ios_base::sync_with_stdio(false); // Para desincronizar los streams

Las lecturas con iostream son mucho más seguras porque tienen la ventaja de estar tipadas... cosa que no sucede con las funciones propias de C. Esta característica hace que el compilador te pueda avisar ante determinadas aberraciones o despistes... las funciones de C no mostrarán avisos y el error te lo encontrarás al ejecutar la aplicación

Ahora bien, como existe esta opción y alguien la puede activar en cualquier momento, no parece buena idea basar el buen hacer de tu programa en la asunción de que esto no existe o no se va a hacer nunca.

Para leer una línea desde la consola plantéate algo así:

std::string s;
std::getline(std::cin, s);

En vez de

gets (at[i].n);

Así mismo, considera usar std::string en vez de char[].

fflush no es para streams de entrada

fflush está pensado para ejecutarse en dispositivos de salida y así se indica en la documentación:

In all other cases, the behavior depends on the specific library implementation. In some implementations, flushing a stream open for reading causes its input buffer to be cleared (but this is not portable expected behavior).

Es decir:

En el resto de casos, el comportamiento dependerá de la implementación de la librería. En algunas implementaciones, llamar a fflush para un stream de lectura provoca el vaciado del mismo (pero no es un comportamiento portable).

Así pues, evita esto:

fflush(stdin);

Para limpiar el buffer de entrada en C++ usa esto:

#include <limits>

std::cin.ignore(std::numeric_limits<int>::max(),'\n');

Esta función elimina todos hasta que se encuentre un salto de línea ('\n'), que también se eliminará... o se vacíe completamente el buffer de entrada.

Y bueno, habría más cosas pero lo dejamos para otro día que si no no va a haber quien se lea esta respuesta.

eferion
  • 49,291
  • 5
  • 30
  • 72
4

Si depuras tu programa paso por paso el problema te resultaría evidente. Te aconsejo hacerlo como ejercicio didáctico. Mientras tanto te explico el problema:

Arreglos.

  • Los arreglos son un espacio de memoria que almacena objetos de un mismo tipo. Se definen de esta manera: tipo nombre[tamaño], tú tienes un arreglo de tipo atleta declarado así:

    atleta at[10];
    
  • Los arreglos en C++ se indexan desde 0, así que at[0] corresponde a la primera posición, at[1] a la segunda, at[2] a la tercera, y así sucesivamente.
  • Los arreglos en C++ se almacenan en memoria contigua, esto implica que entre el inicio de at[0] y el inicio de at[1] habrá una cantidad de bits equivalente a sizeof(atleta) ya que atleta es el tipo de los datos almacenados en el arreglo at.
  • C++ no realiza comprobación de límites den los arreglos, por ello es posible acceder a elementos que no se corresponden con los que gestiona el arreglo.
  • Aunque en C++ es posible acceder a elementos fuera de los límites del arreglo, hacerlo puede provocar que el programa lance errores en tiempo de ejecución.

Tu arreglo.

Tienes un arreglo de 10 atleta:

atleta at[10];

Que en memoria tendrá un aspecto parecido a esto:

Como puedes ver, tienes una variable llamada at que apunta al principio de 10 elementos contiguos (cuentalos, son exáctamente 10 aunque empiecen en 0 y acaben en 9).

Tu código.

Todo eso sucedió luego que de cambiara todos los valores iniciales de cada for de 0 a 1

for (i=0 ; i<10 ; i++)  ------>>   for (i=1 ; i<11 ; i++)

Originalmente recorrías el arreglo de la posición 0 a la posición 9 (ya que el valor 10 incumple la condición <10) y como esas son exactamente las posiciones de las que dispone tu arreglo at todo funcionaba correctamente.

Con el nuevo cambio recorres el arreglo de la posición 1 (que es la segunda posición del arreglo) a la posición 10 (que no existe ya que las posiciones llegan hasta 9).

Al intentar trabajar con la posición 10 (que no está asignada al arreglo at) provoca que el programa falle en tiempo de ejecución.

Otras cosas a tener en cuenta.

  • Tienes faltas de ortografía.
  • En C++ la palabra clave struct no forma parte del tipo, así pues no es necesaria para definir variables de tipo struct:

       /*struct*/ atleta at[10];
    // ~~~~~~~~~~ <-- innecesario!
    
  • Las cabeceras de C adaptadas a C++ carecen de extensión y tienen el prefijo "c", así que <stdio.h>, <stdlib.h> y <math.h> serían <cstdio>, <cstdlib> y <cmath> (consulta esta pregunta para más detalles).
  • No necesitas las cabeceras de C que estás incluyendo, aunque las hubieras incluido bien (que no ha sido el caso, ver punto anterior).
PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
0

Cundo tienes un menú de opciones lo más recomendable es usar un do { menú de opciones }while( condición aquí );

Y si antes te funcionaba porque no lo dejaste como estaba ¿?, te recomiendo que valides errores con try catch si es posible en c porque por lo general yo solo sé de Java.Recuerda que cuando algo funciona no lo toques. y es posible que tu problema se base en que como son 10 ,tú empiezas de 1 y no de 0 a 10, tal vez tengas que poner for(int i=1,i<=10;i++){ tus códigos aquí } Etc.. prueba así el problema entre contadores y acumuladores siempre suele ser la inicialización.

MBS.corp
  • 1
  • 1
0

Despues de la linea que dice cout<<endl<<"A continuacion indique los 5 lanzamientos del atleta";, haces un for donde c1 va desde 1 hasta 5, pero estas intentando recorrer el arreglo l el cual tiene 5 elementos, pero los elementos de un arreglo no comienzan a enumerarse desde 1 sino desde cero. Debes ser cuidadoso con esas cosas. Parece que las excepciones que eso causa por intentar acceder a un registro de la RAM invalido es lo que detiene tu programa.

Isaac Vega
  • 709
  • 3
  • 11