I have an error "crosses initialization of 'player p3' when using the switch in C ++

2
#include<iostream>
#include<string.h>
using namespace std;
class jugador{
    char *nombre;
    float arg;
    char *equipo;
    int aux;

    public:
        jugador(char *, char *, float);
       ~jugador();
        jugador(jugador &j);
        char *getnombre();
        char *getequipo();
        float getarg();
        void setnombre(char *n);
        void setequipo(char *e);
        void setarg(float a);
        void operator=(jugador &p)
        {
            cout<<endl;
            cout<<"sobrecarga del operador"<<endl;
            aux=p.aux;
            nombre=new char[aux+1];
            strcpy(nombre,p.nombre);
            aux=p.aux;
            equipo=new char[aux+1];
            strcpy(equipo,p.equipo);
            arg=p.arg;
            }
            void mostrar_jugador();
};
jugador::jugador(char *n,char *e, float a){
    aux= ::strlen(n);
    nombre=new char[aux+1];
    strcpy(nombre, n);
    aux= ::strlen(n);
    equipo=new char[aux+1];
    strcpy( equipo, e);
    arg=a;
}
jugador::jugador(jugador &j){
    cout<<endl;
    cout<<"constructor copia"<<endl;
    aux=j.aux;
    nombre=new char[aux+1];
    strcpy(nombre,j.nombre);
    cout<<"se creo la copia de la clase para "<<nombre<<endl;
    aux=j.aux;
    equipo=new char[aux+1];
    strcpy(equipo,j.equipo);
    cout<<"se creo la copia de la clase para "<<equipo<<endl;
    arg=j.arg;
}
void jugador::mostrar_jugador(){
    cout<<endl;
    cout<<"Nombre: "<<nombre<<endl;
    cout<<"Equipo: "<<equipo<<endl;
    cout<<"Arg: "<<arg<<endl;
    }
jugador::~jugador(){
}
main(){ 
    int op;
    cout<<"1.Ingreso de 3 jugadores"<<endl;
    cout<<"2.Crear copia de los 3 jugadores"<<endl;
    cout<<"3.Mostrar a los jugadores"<<endl;
    cout<<"4.Mostrar mejor jugador"<<endl;
    cout<<"5.salir"<<endl;
    cout<<"----Elija una opcion----"<<endl;
    cin>>op;
switch(op){
    case 1:
    jugador p((char*)"Edwin", (char*)"Tigres", 20 );
    jugador p2((char*)"Maria", (char*)"Rapidos", 21 );
    jugador p3((char*)"Julio", (char*)"Triunfadores", 30 );
        break;
    case 2://aquí empieza el problema no se porque
    jugador x1(p);
        x1.mostrar_jugador();
    jugador x2(p2);
        x2.mostrar_jugador();
    jugador x3(p3);
        x3.mostrar_jugador();
        break;
    case 3:
        break;
    case 4:
        break;
    default:
        cout<<"Opcion invalida"<<endl;
}   
    return 0;
}
    
asked by Edwin Casco 21.09.2017 в 03:57
source

1 answer

3

switch blocks are different from if-else blocks for several reasons:

  • The compiler has more freedom to apply optimizations.
  • case tags have no scope of their own.

To avoid the appearance of inconsistencies and errors difficult to find due to the second characteristic, within each case they should not declare variables. These could collide with the variables of other case and their life cycle is not easy to limit.

In order to declare variables within a case it is necessary to create a scope, which is achieved with the { } keys. Now, if we review your code:

switch(op){
  case 1:
    jugador p((char*)"Edwin", (char*)"Tigres", 20 );
    jugador p2((char*)"Maria", (char*)"Rapidos", 21 );
    jugador p3((char*)"Julio", (char*)"Triunfadores", 30 );
    break;
  case 2://aquí empieza el problema no se porque
    jugador x1(p);
    x1.mostrar_jugador();
    jugador x2(p2);
    x2.mostrar_jugador();
    jugador x3(p3);
    x3.mostrar_jugador();
    break;

We see that you are declaring variables in case 1 that you then try to reuse in case 2 ... but of course if op==2 it is impossible that op==1 . In other words: if the case 2 is executed the case 1 is not executed, then the variables p , p2 and p3 are not going to be declared or initialized and that is not fixed nor even with the keys.

To see it better we will refactor the code slightly:

void func1()
{
  // variables locales
  jugador p((char*)"Edwin", (char*)"Tigres", 20 );
  jugador p2((char*)"Maria", (char*)"Rapidos", 21 );
  jugador p3((char*)"Julio", (char*)"Triunfadores", 30 );
}

void func2()
{
  jugador x1(p); // ¿Que es p?
  x1.mostrar_jugador();
  jugador x2(p2); // ¿Que es p2?
  x2.mostrar_jugador();
  jugador x3(p3); // ¿Que es p3?
  x3.mostrar_jugador();
}

// ...

if( op == 1 )
  func1();
else if( op == 2 )
  func2();

Your program has to request the data of 3 players in option 1 ... and that data must remain alive in successive options, then you should move your declaration to the level of main .

At this point you have a problem and that is that the default constructor is not implemented. This prevents you from creating objects without specific values. You can solve it using pointers or by enabling the default constructor. The easiest way is to enable the default constructor (consider using std::string instead of char* when programming in C ++).

class jugador
{
  std::string nombre;

public:
  // C++11 en adelante
  jugador() = default; 

  // Standares antiguos C++
  jugador()
  { }
};

int main(){ // <-- el tipo de retorno es obligatorio en C++
  jugador p, p2, p3;

Although, as we said, you can also use pointers and ignore the default constructor:

  • option C ++ 11, C ++ 14, C ++ 17

    int main() {
    
      std::unique_ptr<jugador> p, p1, p2;
    
      // ...
      switch(op)
      {
        case 1:
          // C++11 en adelante
          p.reset(new jugador("Edwin","Tigres",20));
          p2.reset(new jugador("Maria","Rapidos",21));
          p2.reset(new jugador("Julio","Triunfadores",30));
    
          // C++14 o C++17
          p = std::make_unique<jugador>("Edwin","Tigres",20);
          p2 = std::make_unique<jugador>("Maria","Rapidos",21);
          p2 = std::make_unique<jugador>("Julio","Triunfadores",30);
    
          break;
    
        case 2:
        { // iniciamos ambito para declarar variables
          // Hay que comprobar que los punteros estan inicializados
          if( p && p2 && p3 )
          {
            jugador x1(*p); // p es un puntero
            jugador x2(*p2);
            jugador x3(*p3);
    
            x1.mostrar_jugador();
            x2.mostrar_jugador();
            x3.mostrar_jugador();
          }
          else
            std::cout << "No se han introducido datos\n";
    
          break;
        }
      }
    
      // ...
      // No es necesario borrar los punteros, se borran solos
    }
    
  • option C ++ 98, C ++ 03 (old versions)

    int main() {
    
      jugador *p = 0, *p1 = 0, *p2 = 0;
    
      // ...
      switch(op)
      {
        case 1:
          p = new jugador("Edwin","Tigres",20);
          p2 = new jugador("Maria","Rapidos",21);
          p2 = new jugador("Julio","Triunfadores",30);
    
          break;
    
        case 2:
        {
          // Hay que comprobar que los punteros estan inicializados
          if( p && p2 && p3 )
          {
            jugador x1(*p);
            jugador x2(*p2);
            jugador x3(*p3);
    
            x1.mostrar_jugador();
            x2.mostrar_jugador();
            x3.mostrar_jugador();
          }
          else
            std::cout << "No se han introducido datos\n";
    
          break;
        }
      }
    
      // ...
    
      delete p;
      delete p2;
      delete p3;
    }
    

Final note

I have commented to you that it is preferable to replace char* with std::string . I'm telling you because the use you make of the pointers in C ++ is incorrect:

jugador p((char*)"Edwin", (char*)"Tigres", 20 );
//        ^^^^^^^         ^^^^^^^

Those two conversions are telling you that you're trying to do something dangerous in C ++. Written strings bareback are, by definition, constants. Modifying one of these chains can result in an undefined behavior of the application (nothing may happen or the chains may be stored in read-only memory and the Operating System will kill your application), not to mention that you may end up treading memory of other variables:

char* cad = (char*)"a"; // cad apunta a un array de 2 bytes
strcpy(cad,"ABCDE");    // ¿Donde metemos los 3 bytes de mas?

C-style solutions would then use dynamic memory to manage the strings or use a fixed-size array ( nombre[100] ) and stick with pointer management and hand string with strcpy and company.

However, the C ++ solution requires using the class std::string :

std::string cadena = "a"; // ok
cadena = "ABCDE"; // ok, la clase se encarga de gestionar la memoria del 
    
answered by 21.09.2017 в 08:44