0

我遇到了矩阵问题,问题是当我尝试复制它时,它给了我错误“分段错误”。这是涉及的代码:

主文件

void principal(Tauler &tauler) {
    GeneradorPuzzle puzzle;
    pilaMoviments pilaMovs;
    int nPuzzle, cont=0;
    bool valid;

    cout << "JOC DEL RUSH HOUR" << endl;
    cout << "ENTRA EL PUZZLE A JUGAR:" << endl;
    cin >> nPuzzle;
    valid=puzzle.esPuzzleValid(nPuzzle);
    if(!valid) {
        do {
            cout << "PUZZLE NO VALID. ENTRA EL PUZZLE A JUGAR:" << endl;
            cin >> nPuzzle;
            valid=puzzle.esPuzzleValid(nPuzzle);
        }while(!valid);
    }
    puzzle.posarPuzzleActiu(nPuzzle);
    tauler=Tauler(puzzle.midaPuzzle(),puzzle.totalVehicles());

    for(int i=0;i<puzzle.totalVehicles();i++) {
        Vehicle v(cont, puzzle.midaVehicle(i),puzzle.filaVehicle(i),puzzle.columnaVehicle(i),puzzle.direccioVehicle(i));
        valid=tauler.esValid(v);
        if(valid) {
            tauler.processar(v,cont);
            cont++;
        }
    }
}
int main() {
    pilaMoviments pilaMovs;
    Tauler tauler;
    char opcio;

    principal(tauler);
    tauler.mostrar();
    mostrarMenu();
    do {
        cout << "ENTRA OPCIO:" << endl;
        cin >> opcio;
        tractarOpcio(tauler,pilaMovs,opcio);
    }while(opcio!='X');
    return 0;
}

陶勒.cpp

Tauler::Tauler() {
    a_f=a_surt=a_n=a_valids=0;
    a_mp=NULL;
}
Tauler::Tauler(const Tauler &t) {
    a_f=t.a_f;
    a_n=t.a_n;
    a_surt=t.a_surt;
    a_valids=t.a_valids;
    reservarMemoria();
    copiar(t);
}
Tauler::Tauler(int nf, int nv) {
    a_f=nf;
    a_n=nv;
    a_v=new Vehicle[a_n];
    reservarMemoria();
    for(int j=0;j<a_f;j++)
        for(int i=0;i<a_f;i++)
            a_mp[i][j]='-';
}

Tauler::~Tauler() {
    alliberarMemoria();
}

// OPERADORS

Tauler& Tauler::operator=(const Tauler& y) {
    if (this!=&y) {
        alliberarMemoria();
        reservarMemoria();
        copiar(y);
    }
    return *this;
}

// METODES PRIVATS

void Tauler::copiar(const Tauler &t) {
    a_f=t.a_f;
    a_n=t.a_n;
    a_surt=t.a_surt;
    a_valids=t.a_valids;
    for(int i=0;i<a_f;i++) {
        for(int j=0;j<a_f;j++)
            a_mp[i][j]=t.a_mp[i][j];
    }
}
void Tauler::alliberarMemoria() {
    for(int i=0;i<a_f;i++)
        delete [] a_mp[i];  // s'alliberen les taules horitzontals
    delete [] a_mp;
}
void Tauler::reservarMemoria() {
    a_mp=new char*[a_f];
    for(int i=0;i<a_f;i++)
        a_mp[i]=new char[a_f];
}

陶勒.h

#ifndef TAULER_H
#define TAULER_H
#include "Vehicle.h"
#include "pilaMoviments.h"

class Tauler {
    // La classe que guardara la informacio del Tauler
    public:
        // CONSTRUCTORS I DESTRUCTOR
        Tauler();
        //Pre: --; Post: Posa Tauler per defecte.
        Tauler(int nf, int nv);
        //Pre: nf i nv entrats correctament. Post: Posa Tauler amb les files i el nombre de vehicles que li hem entrat.
        Tauler(const Tauler &t);
        //Pre: Tauler correcte. Post: Fa una copia de Tauler i li diu t.
        ~Tauler();
        //Pre: --; Post: Memoria alliberada.

        // OPERADOR
        Tauler &operator=(const Tauler &e);

        // CONSULTORS
        int Files() const;
        //Pre: Files del Tauler correctes. Post: Retorna les files i columnes del Tauler.
        int filaSurtida() const;
        //Pre: Files del Tauler correctes. Post: Retorna la fila de surtida del Tauler.
        int Vehicles() const;
        //Pre: a_valids del Tauler correctes. Post: Retorna el nombre de Vehicles valids del tauler.
        bool fiPartida() const;
        //Pre: Vehicle 'A' al tauler. Post: Retorna true si el Vehicle 'A' esta a la ultima columa de la fila de surtida, altrament retorna false.
        bool esValid(Vehicle v) const;
        //Pre: Parametres del Vehicle v entrats correctament. Post: Retorna true si el vehicle es pot posar correctament dins el tauler. False si no es pot posar.
        bool xoquen(Vehicle v, Moviment m) const;
        //Pre: Parametres del Vehicle v, files i cols entrats correctament. Post: Retorna true si no hi ha cap altre vehicle bloquegi el desplaçament. Si n'hi ha algun retorna false.
        void mostrar() const;
        //Pre: Tauler ple. Post: Mostra per pantalla totes les posicions del tauler amb els vehicles.

        // MODIFICADORS
        void posarVehicle(char a, Vehicle v);
        //Pre: a correcte i Vehicle v valid. Post: Coloca el vehicle del puzzle al Tauler al lloc que li toca.
        void processar(Vehicle v, int cont);
        //Pre: Vehicle v valid i cont>=0. Post: Assigna una lletra al vehicle i si es el primer horitzontal guarda la fila com a fila de surtida.
        bool validarMov(Moviment m);
        //Pre: --; Post: Retorna false si la lletra no es de cap Vehicle del taulell, o si el moviment no es pot fer, altrament retorna true.
        void ferMov(pilaMoviments pilaMovs, Moviment m);
        //Pre: Parametres lletra, files i cols correctes. Post: Mou el vehicle que tingui la lletra entrada les files i columnes que ens entren i empila el moviment a la pila.
        void desferMov(pilaMoviments pilaMovs);
        //Pre: Movimetns de la pila >0. (No es pot desfer moviments si no n'hi ha cap). Post: Desfa l'ultim moviment i el desempila de la Pila de moviments.
        bool movPossible(Vehicle v, int files, int cols);

    private:
        // TAULA DE VEHICLES
        Vehicle * a_v;
        int a_valids;

        // ATRIBUTS
        pilaMoviments a_pila;
        int a_f;
        int a_n;
        int a_surt;
        char ** a_mp;

        // METODES
        void alliberarMemoria();
        void reservarMemoria();
        void copiar(const Tauler &t);
};

#endif // TAULER_H

当我启动它时,它会要求一个谜题,但它会在这一行崩溃:

a_mp[i][j]=t.a_mp[i][j];

在“复印”方法中。我所理解的是,我正在给 a_mp[i][j] 一个我不知道的值,但我不知道如何解决它,有什么想法吗?我知道名字不是英文的,但我希望这不是问题。

非常感谢编辑:删除 iniciar(),这不是问题的原因

4

3 回答 3

3

我认为你在这里犯了一个错误:

Tauler& Tauler::operator=(const Tauler& y) {
if (this!=&y) {
    alliberarMemoria();
    reservarMemoria();
>>     y.iniciar();
    copiar(y);
}

如果您的对象实例的 a_f 小于 y.a_f ,那么当您复制 y 时,您将写入未分配的位置。你可能想做 iniciar(),而不是 y.iniciar()。

我可能错了,因为您还没有发布 iniciar() 源代码。

于 2013-05-02T12:19:08.647 回答
2

看起来是operator=从释放当前内存(好的)开始,分配内存(但应该分配多少?)和复制。

如果源大小大于目标大小,您将覆盖未分配的内存。

在调用内存分配器之前,您应该首先将a_f和设置a_n为正确的值。

于 2013-05-02T12:14:27.350 回答
1

不是答案,而是一些找到它的建议。

首先,在您的代码中隔离读取值并写入另一个矩阵,即将查询与命令隔离。

代替

a_mp[i][j]=t.a_mp[i][j];

写:

int valorAAssignar = t.a_mp[i][j];
a_mp[i][j] = valorAAssignar;

其次,assert你所有的数组间接都在它们的限制之间。

assert(0 <= i);
assert(i <= SOME_MAXIMUM_VALUE_FOR_I);
assert(0 <= j);
assert(j <= SOME_MAXIMUM_VALUE_FOR_J);
int valorAAssignar = t.a_mp[i][j];
a_mp[i][j] = valorAAssignar;

在存在数组间接的所有其他点上执行相同的操作。实际上,您最好编写一个方法,例如ReadCellValue, 或 Catalan LlegeixValor

   LlegeixValor(a_mp, i, j);

这基本上符合我上面的建议:检查限制并返回值。

如果您在调试模式下运行它,您应该会发现出了什么问题,在该模式下会检查断言。通过写作assert(false);并看到它失败来确定最后一点。然后删除此行。

此代码要求添加前置条件、后置条件和类不变量(请参阅按合同设计)。也许如果你很幸运并且失败很简单,你可以通过前置条件断言来解决,比如我建议的那些。

于 2013-05-02T12:20:04.470 回答