C++ program stops responding when calling a function a second time

Asked

Viewed 130 times

0

I’m doing a simplified game in the style of Pokémon, but is stopping to answer when calling Bootpokemon for the second time, I’m not finding the problem because it works normally with the first and hangs on the second.

Print mostrando que o jogo parou de funcionar

The values print is just to test if everything is being passed correctly.

Excerpts from the code:

Main:

int main(int argc, char** argv){
    TipoMove flamethrower; 
    TipoMove fire_blast; 
    TipoMove fly; 
    TipoMove earthquake;

    TipoMove quick_attack;
    TipoMove thunderbolt;
    TipoMove thunder;
    TipoMove skull_bash;

    InicializaMove(&flamethrower, "Flamethrower", 1, 'e', 95); 
    InicializaMove(&fire_blast, "Fire Blast", 2, 'e', 120);
    InicializaMove(&fly, "Fly", 3, 'f', 70);
    InicializaMove(&earthquake, "Earthquake", 4, 'f', 100);

    InicializaMove(&quick_attack, "Quick Attack", 5, 'f', 40);
    InicializaMove(&thunderbolt, "Thunderbolt", 6, 'e', 95);
    InicializaMove(&thunder, "Thunder", 7, 'e', 120);
    InicializaMove(&skull_bash, "Skull Bash", 8, 'f', 100);

    TipoPokemon charizard;
    TipoPokemon pikachu;

    InicializaPokemon(&charizard, 2, "Charizard", 293, 280, 360, 328, 348, 295, flamethrower, fire_blast, fly, earthquake);

    ImprimePokemon(&charizard);

    InicializaPokemon(&pikachu, 1, "pikachu", 229, 196, 274, 306, 218, 218, quick_attack, thunderbolt, thunder, skull_bash);

    ImprimePokemon(&pikachu);


    return 0;
}

Bootpokemon:

void InicializaPokemon(TipoPokemon *poke, int id, string nome, float ataque, float defesa, float vida, float velocidade, float spAtk, float spDef, TipoMove mov0, TipoMove mov1, TipoMove mov2, TipoMove mov3){         

    poke->id = id;
    poke->nome = nome;
    poke->atk = ataque;
    poke->def = defesa;
    poke->hp = vida;
    poke->speed = velocidade;
    poke->sp_atk = spAtk;
    poke->sp_def = spDef;
    poke->moves[0]= mov0;
    poke->moves[1] = mov1;
    poke->moves[2] = mov2;
    poke->moves[3] = mov3;                                                                              
}

Initialize:

void InicializaMove(TipoMove *mov, string n, int id, char t, float pw){
    mov->nome = n;
    mov->id = id;
    mov->tipo = t;
    mov->power = pw;

    cout << "move " << mov->nome << " inicializado " << endl;
}

Full code on Github

  • 2

    In the structure has TipoMove moves[3];, when it should be such 4, because you use 4 moves

  • @Isac but in C vectors start at position 0... C++ is not so either?

  • 2

    Exact. In a size 3 vector, there are only positions 0, 1 and 2. There is no position 3. Hence the segmentation failure in your program.

  • Wow, I changed here and it really worked, I ended up getting confused with this, thank you :D

  • By the way so I can know how to solve in the future, what I did was paste the code in the codeblocks I ran and saw where crashed, which was on the line poke->moves[3] = mov3;, and by deduction if crasha ai is because the size does not play with the assigned values.

  • 1

    It would also be a good idea to start objects only in constructors, because there you guarantee that you are assigning values in objects that actually exist.

Show 1 more comment

1 answer

2


The question has already been answered in the comments, but only to contextualize a little:

Behavior Indefinite

You just came across a Behavior Indefinite. This type of behavior occurs when the programmer (nodes) makes a mistake that the compiler is not required to diagnose.

In its specific case, the error was an attempt to access outside the limits of an array. Note that an error will not necessarily occur, and if one occurs (such as a segmentation failure), a debugger will not necessarily point to the correct cause.

How to protect yourself from this kind of mistake?

First, by linking the compiler warnings (and taking them seriously!). In the case of gcc, you must set the flag -Wall.

Second, using safer interfaces. In your specific case, it would be more interesting to use a Std::array instead of a simple list, and use the member function at() instead of operator[] to retrieve/modify the elements, as this function performs limit checking, preventing its program from causing undefined behavior.

  • Membership functions at() add an overhead on any index access (the check of the index being within the limits is a conditional code), then it is more interesting to use iterators, which guarantee the limit and the overhead of the check is better learned by the CPU.

  • @Márioferoldi Thanks for the comment! In her case, iterators do not help, because each element is accessed directly. Also, the member function overhead at() is minimal: It is not worth trying to optimize a program in this way without measuring performance and detecting that such a function is a significant Bottleneck. Finally, in most cases (When the compiler can prove that an illegal access does not happen) this check is removed by the optimizer. That test shows this. Check that there are no conditional jumps in the compiled program.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.