2013-05-02 96 views
0

我遇到了矩陣問題,問題是當我嘗試複製它時,它給了我'錯誤分割錯誤'的錯誤。這是所涉及的代碼:複製矩陣時出現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

回答

2

它看起來像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

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

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,或在加泰羅尼亞語中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