Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Falha de Segmentação

Depois da aula "programando como um profissional" o programa parou de funcionar e fica dando "Falha de segmentação (imagem do núcleo gravada)". Então copiei o código do professor Maurício(https://gist.github.com/mauricioaniche/9edc5bdd8edacfbc2072) e deu o mesmo erro.

Usei o gdb para debugar e apareceu essa mensagem: Program received signal SIGSEGV, Segmentation fault. 0x0000000000401188 in andanomapa (m=0x6020c0 <m>, xorigem=9, yorigem=3, xdestino=3, ydestino=2) at mapa.c:105 105 char personagem = m->matriz[xorigem][yorigem];

Não sei como arrumar isso.

6 respostas

Oi, Fabio. Sei que você diz que copiou o código do maurício, mas é sempre bom ver exatamente o que você está rodando. Então, você pode colar aqui o código do mapa.c ? Além disso, sei que é meio óbvio, mas você lembrou de recompilar depois de modificar o código(o mesmo erro é um pouco suspeito)?

Compilei e recompilei durante uma semana e nada. O programa até começa a rodar mas quando entro com a direção do personagem acontece a falha de segmentação. Isso não pode ser problema do gcc? estou usando ubuntu 14.04.

código mapa.c abaixo.

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


int i,j;



void copiamapa(MAPA* destino, MAPA* origem){
    destino->linhas = origem->linhas;
    destino->colunas = origem->colunas;

    alocamapa(destino);
    for(i = 0; i < origem->linhas; i++){
        strcpy(destino->matriz[i], origem->matriz[i]);
    }
}


void andanomapa(MAPA* m, int xorigem, int yorigem, int xdestino, int ydestino){


    char personagem = m->matriz[xorigem][yorigem];
    m->matriz[xdestino][ydestino] = personagem;
    m->matriz[xorigem][yorigem] = VAZIO;
}


int ehvalida(MAPA* m, int x, int y){
    if(x >= m->linhas){
        return 0;
    }
    if(y >= m->colunas){
        return 0;
    }

    return 1;
}

int ehvazia(MAPA* m, int x, int y){
    return m->matriz[x][y] == VAZIO;
}

int encontramapa(MAPA* m, POSICAO* p, char c){
    for(i = 0; i < m->linhas; i++){
        for(j = 0; j < m->colunas; j++){
            if(m->matriz[i][j] == c){
                p->x = i;
                p->y = j;
                return 1;
            }
        }
    }
    return 0;

}

int podeandar(MAPA* m, char personagem, int x, int y){
    return
        ehvalida(m, x, y) &&
        !ehparede(m, x, y) &&
        !ehpersonagem(m, personagem, x, y);
}

int ehparede(MAPA* m, int x, int y){
    return
            m->matriz[x][y] == PAREDE_VERTICAL ||
            m->matriz[x][y] == PAREDE_HORIZONTAL;
}

int ehpersonagem(MAPA* m, char personagem, int x, int y){
    return m->matriz[x][y] == personagem;
}

void liberamapa(MAPA* m){
    for(i = 0; i < m->linhas; i++){
        free(m->matriz[i]);
    }
    free(m->matriz);
}

void alocamapa(MAPA* m){
    m->matriz = malloc(sizeof(char*) * m->linhas);
    for(i = 0; i < m->linhas; i++){
        m->matriz[i] = malloc(sizeof(char) * (m->colunas + 1));
    }
}

void lemapa(MAPA* m){
    FILE* f;
    f = fopen("mapa.txt", "r");
    if(f == 0){
        printf("Erro na leitura do mapa");
        exit(1);
    }

    fscanf(f, "%d %d", &(m->linhas), &(m->colunas));

    alocamapa(m);


    for(i = 0; i < m->linhas; i++){
        fscanf(f, "%s", m->matriz[i]);
    }

    fclose(f);
}

void imprimemapa(MAPA* m){
    for(i = 0; i < m->linhas; i++){
        printf("%s\n", m->matriz[i]);
    }
}

Esqueci de pedir para você postar o mapa que está usando também.

Eu abri o link do github com o código do maurício que você mandou mas ta bem diferente do seu. Parece que é de uma iteração anterior, não tem as funções pondera e copiamapa. Mesmo assim , eu copiei o código todo para testar e funcionou usando esse mapa:

5 10
##########
#..#.....#
#@..H....#
#..#.....#
##########

Só que como o seu está diferente poste o resto do código, ( os arquivos .h também. ) porque olhando para o que você colocou não ćonsigo ver nada importante, então vou testaqr aqui. Mas não acho que seja coisa do compilador não... não deveria ser tão fácil encontrar bugs no gcc. E quando for compilar utilize a flag -Wall também para mostrar todos os warnings.

apareceu esse warning:

fogefoge.c: In function ‘main’:
fogefoge.c:148:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

fogefoge.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "fogefoge.h"
#include "mapa.h"

MAPA m;
POSICAO heroi;
int tempilula = 0;
int i, j;


int acabou(){
    POSICAO pos;

    int fogefogenomapa = encontramapa(&m, &pos, HEROI);
    return !fogefogenomapa;
}


int ehdirecao(char direcao){
    return
        direcao == ESQUERDA
        || direcao == CIMA
        || direcao == DIREITA
        || direcao == BAIXO;
}


void move(char direcao){

     if(!ehdirecao(direcao)){
        return; //matar a função
}

    int proximox = heroi.x;
    int proximoy = heroi.y;

    switch(direcao){
        case ESQUERDA:
            proximoy--;
            break;
        case CIMA:
            proximox--;
            break;
        case DIREITA:
            proximoy++;
            break;
        case BAIXO:
            proximox++;
            break;
    }

    if(!podeandar(&m, HEROI, proximox, proximoy)){
        return;
    }

    andanomapa(&m, heroi.x, heroi.y, proximox, proximoy);
    heroi.x = proximox;
    heroi.y = proximoy;
}

int praondefantasmavai(int xatual, int yatual,
    int* xdestino, int* ydestino){

    int opcoes[4][2] = {
        { xatual   , yatual+1 },
        { xatual+1 , yatual   },
        { xatual   , yatual-1 },
        { xatual-1 , yatual   }
    };

    srand(time(0));
    for(i = 0; i < 10; i++){
        int posicao = rand() % 4;

        if(podeandar(&m, FANTASMA, opcoes[posicao][0], opcoes[posicao][1])){
            *xdestino = opcoes[posicao][0];
            *ydestino = opcoes[posicao][1];
            return 1;
        }
    }
    return 0;

}


void fantasmas(){
    MAPA copia;

    copiamapa(&copia, &m);

    for(i = 0; i < copia.linhas; i++){

        for(j = 0; j < copia.colunas; j++){

            if(copia.matriz[i][j] == FANTASMA){

                int xdestino;
                int ydestino;

                int encontrou = praondefantasmavai(i, j, &xdestino, &ydestino);

                if(encontrou){
                    andanomapa(&m, i, j, xdestino, ydestino);
                }
            }
        }
    }
    liberamapa(&copia);
}


int main(){


    lemapa(&m);
    encontramapa(&m, &heroi, HEROI);

    do{

        imprimemapa(&m);

    char comando;
        scanf(" %c", &comando);
        move(comando);
        fantasmas();


    }while(!acabou());


    liberamapa(&m);

}

fogefoge.h

#define CIMA 'w'
#define BAIXO 's'
#define ESQUERDA 'a'
#define DIREITA 'd'



int acabou();
void move(char direcao);

int ehdirecao(char direcao);

void fantasmas();

int praondefantasmavai(int xatual, int yatual,
    int* xdestino, int* ydestino);

mapa.h

#define HEROI '@'
#define FANTASMA 'F'
#define VAZIO '.'
#define PAREDE_VERTICAL '|'
#define PAREDE_HORIZONTAL '-'


struct mapa{
    char** matriz;
    int linhas;
    int colunas;
};

typedef struct mapa MAPA;

struct posicao {
    int x;
    int y;
};

typedef struct posicao POSICAO;

void liberamapa(MAPA* m);
void alocamapa(MAPA* m);
void lemapa(MAPA* m);
void imprimemapa(MAPA* m);
int encontramapa(MAPA* m, POSICAO* p, char c);
int ehvalida(MAPA* m, int x, int y);
int ehvazia(MAPA* m, int x, int y);
void andanomapa(MAPA* m, int xorigem, int yorigem, int xdestino, int ydestino);
void copiamapa(MAPA* destino, MAPA* origem);
int podeandar(MAPA* m, char personagem, int x, int y);
int ehparede(MAPA* m, int x, int y);
int ehpersonagem(MAPA* m, char personagem, int x, int y);

mapa.txt

5 10
|--------|
|.F.|..-.|
|..-|.@..|
|.F....-.|
|--------|

olha o que acontece:

|--------|
|.F.|..-.|
|..-|.@..|
|.F....-.|
|--------|
a

|-.------|
|F.-|..-.|
|.--|@...|
|.F....-.|
|-.------|
s
Falha de segmentação (imagem do núcleo gravada)

normalmente a falha de segmentação aparece logo quando entro com a primeira direção, as vezes acontece isso de os fantasmas andarem uma vez e aparece pontos aonde devia estar as paredes no mapa

solução!

Então, eu não encontrei nenhum erro, mas também não estava funcionando comigo. em vez de ter segmantation fault logo de cara o meu não andava com os comandos do teclado, mas eventualmente tive uns segfaults também. Por via das dúvidas resolvi mudar a declaração das variáveis int i, j para dentro dos loops (para compilar dessa forma tem que usar -std=C11) e funcionou. Abaixo eu colei os diffs dos quatro arquivos (dá para ver que só houve alterações no fogefoge.c). Enfim.. Tem muitas coisas que podem ser a causa. Compilei com o gcc-4.9.3 e gcc-5.3.0. Mas acho estranho ter alguma coisa a ver com isso. Mas também acho estranho ele ter funcionado com as alterações que eu fiz... hehehe aqui estão os diffs:

pingu@r2d2 ~/ffg2 $ diff fogefoge.c ../workspace/ffoge/fogefoge.c
10c10
< int i, j;
---
> 
74c74
<     for(i = 0; i < 10; i++){
---
>     for(int i = 0; i < 10; i++){
93c93
<     for(i = 0; i < copia.linhas; i++){
---
>     for(int i = 0; i < copia.linhas; i++){
95c95
<         for(j = 0; j < copia.colunas; j++){
---
>         for(int j = 0; j < copia.colunas; j++){
99,100c99,100
<                 int xdestino;
<                 int ydestino;
---
>                 int xdestino = 0;
>                 int ydestino = 0;
pingu@r2d2 ~/ffg2 $ diff mapa.c ../workspace/ffoge/mapa.c
pingu@r2d2 ~/ffg2 $ diff mapa.h ../workspace/ffoge/mapa.h
pingu@r2d2 ~/ffg2 $ diff fogefoge.h ../workspace/ffoge/fogefoge.h

e o arquivo que foi modificado:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "fogefoge.h"
#include "mapa.h"

MAPA m;
POSICAO heroi;
int tempilula = 0;



int acabou(){
    POSICAO pos;

    int fogefogenomapa = encontramapa(&m, &pos, HEROI);
    return !fogefogenomapa;
}


int ehdirecao(char direcao){
    return
        direcao == ESQUERDA
        || direcao == CIMA
        || direcao == DIREITA
        || direcao == BAIXO;
}


void move(char direcao){

     if(!ehdirecao(direcao)){
        return; //matar a função
}

    int proximox = heroi.x;
    int proximoy = heroi.y;

    switch(direcao){
        case ESQUERDA:
            proximoy--;
            break;
        case CIMA:
            proximox--;
            break;
        case DIREITA:
            proximoy++;
            break;
        case BAIXO:
            proximox++;
            break;
    }

    if(!podeandar(&m, HEROI, proximox, proximoy)){
        return;
    }

    andanomapa(&m, heroi.x, heroi.y, proximox, proximoy);
    heroi.x = proximox;
    heroi.y = proximoy;
}

int praondefantasmavai(int xatual, int yatual,
    int* xdestino, int* ydestino){

    int opcoes[4][2] = {
        { xatual   , yatual+1 },
        { xatual+1 , yatual   },
        { xatual   , yatual-1 },
        { xatual-1 , yatual   }
    };


    for(int i = 0; i < 10; i++){
        int posicao = rand() % 4;

        if(podeandar(&m, FANTASMA, opcoes[posicao][0], opcoes[posicao][1])){
            *xdestino = opcoes[posicao][0];
            *ydestino = opcoes[posicao][1];
            return 1;
        }
    }
    return 0;

}


void fantasmas(){
    MAPA copia;

    copiamapa(&copia, &m);

    for(int i = 0; i < copia.linhas; i++){

        for(int j = 0; j < copia.colunas; j++){

            if(copia.matriz[i][j] == FANTASMA){

                int xdestino = 0;
                int ydestino = 0;

                int encontrou = praondefantasmavai(i, j, &xdestino, &ydestino);

                if(encontrou){
                    andanomapa(&m, i, j, xdestino, ydestino);
                }
            }
        }
    }
    liberamapa(&copia);
}


int main(){
    srand(time(0));


    lemapa(&m);
    encontramapa(&m, &heroi, HEROI);

    do{

        imprimemapa(&m);

    char comando;
        scanf(" %c", &comando);
        move(comando);
        fantasmas();


    }while(!acabou());


    liberamapa(&m);

}

Ah, esqueci de falar que eu inicializei as variáveis xdestino e ydestino na declaração também (é sempre bom fazer isso em C).

`

Por último, logo antes de terminar de responder essa mensagem percebi que você botava o seed do rand dentro da função praondefantastmavai, mas isso é ruim. O seed só precisa/deve ser dado uma única vez no programa, então coloquei no main. Então se fizer um outro diff vai ver que isso também mudou. Mas foi só isso. Acho estranho que que o programa funcionou assim, e não funcionou como estava antes... hehe

`

Botei tudo no bpaste caso queria se certificar de que está com a mesma versão que eu usei; neste link: https://bpaste.net/show/0961e50f412a

Funcionou!! fiz todas as modificações e deu tudo certo, obrigado ai pela atenção.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software