复制矩阵时出现C++分段错误

问题描述:

我遇到了矩阵问题,问题是当我尝试复制它时,它给了我'错误分割错误'的错误。这是所涉及的代码:复制矩阵时出现C++分段错误

的main.cpp

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; 
} 

Tauler.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]; 
} 

Tauler.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]; 

在'copiar'方法中。我所承认的是,我给a_mp [i] [j]一个我不知道的价值,但我不知道如何解决它,有什么想法? 我知道名字不是英文的,但我希望这不是问题。

非常感谢 编辑:删除iniciar(),这是没有问题的

+2

该代码是一个阅读的痛苦,但你是否确保a_mp被初始化为适当的大小?如果您最小化重现问题所需的代码,您可以让人们更容易阅读代码。 – SinisterMJ 2013-05-02 12:09:26

+0

'Tauler :: iniciar'在哪里? – john 2013-05-02 12:10:59

+0

此代码Tauler&Tauler :: operator =(const Tauler&y){... y.iniciar(); ...}不应该编译。 – john 2013-05-02 12:12:00

它看起来像operator=开始通过释放当前内存(OK),分配内存(但多少的原因应分配?)并复制。

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

在调用内存分配器之前,应该先将a_fa_n设置为正确的值。

+0

因为我必须复制当前的矩阵,这是你的意思吗? Tauler&Tauler :: operator =(const Tauler&y)if(this!=&y)alliberarMemoria(); y.a_f = a_f; y.a_n = a_n; reservarMemoria(); copiar(y); } return * this;}' – 2013-05-02 12:23:55

+0

@ p.bosch:不,完全相反:在调用'reservarMemoria'之前,在体内你应该做'a_f = y.a_f;'和'a_n = y.a_n;'。你没有制作'* this'的副本;你正在复制'y'。 – 6502 2013-05-02 12:42:23

+0

我不能这样做,它说:'分配成员'Tauler :: a_f'在只读对象' – 2013-05-02 12:50:36

我觉得你在这里做了一个错误:

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()源代码。

不是答案,而是几个建议来找到它。

首先,隔离你的代码读取值并写入另一个矩阵,即隔离查询和命令。

而不是

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,或在加泰罗尼亚语中LlegeixValor

LlegeixValor(a_mp, i, j); 

这基本上做什么,我上面建议:检查限制和返回值。

如果您在调试模式下运行它,并检查断言,您应该会发现哪里出了问题。通过编写assert(false);并确定它失败,马雷肯定了最后一点。然后删除这一行。

此代码呼吁要添加前置条件,后置条件和类不变量(请参阅Design by Contract)。也许如果你很幸运,失败很简单,你可以通过前提条件断言来获得,比如我建议的断言。

+0

对不起,但我不明白你想要什么我用'assert'做。我以前从未使用过,因此我认为我不应该在这里使用它。这是大学中一门学科的最后一个项目,他们从来没有说过有关断言的任何事情。有没有其他方法?如果我使用你的第一条建议,它会在第二行崩溃:'a_mp [i] [j] = valorAAssignar;' – 2013-05-02 12:40:47

+0

(1)C++是一种语言,assert在C++中有意义。尽管它是一个宏而不是一个函数,但它是一个重要的工具。我告诉你检查数组边界。如果你不知道断言你可以用“if”指令来做。这是一个劣质的解决方案,但它是调查为什么代码崩溃的另一种方法。用一个简单的“if”你可以检查你的数组索引是否有效。我想他们会让你在大学里这样做。 – 2013-05-02 12:43:58

+0

(2)“如果我使用你的第一条建议,它会在第二行崩溃:a_mp [i] [j] = valorAAssignar;”太棒了,你现在已经简化了50%的问题。你知道阅读部分没有崩溃,写作失败。划分问题是找到其根源的另一种方法。 – 2013-05-02 12:44:48