复制矩阵时出现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(),这是没有问题的
它看起来像operator=
开始通过释放当前内存(OK),分配内存(但多少的原因应分配?)并复制。
如果源大小大于目标大小,您将覆盖未分配的内存。
在调用内存分配器之前,应该先将a_f
和a_n
设置为正确的值。
因为我必须复制当前的矩阵,这是你的意思吗? 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
@ p.bosch:不,完全相反:在调用'reservarMemoria'之前,在体内你应该做'a_f = y.a_f;'和'a_n = y.a_n;'。你没有制作'* this'的副本;你正在复制'y'。 – 6502 2013-05-02 12:42:23
我不能这样做,它说:'分配成员'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)。也许如果你很幸运,失败很简单,你可以通过前提条件断言来获得,比如我建议的断言。
对不起,但我不明白你想要什么我用'assert'做。我以前从未使用过,因此我认为我不应该在这里使用它。这是大学中一门学科的最后一个项目,他们从来没有说过有关断言的任何事情。有没有其他方法?如果我使用你的第一条建议,它会在第二行崩溃:'a_mp [i] [j] = valorAAssignar;' – 2013-05-02 12:40:47
(1)C++是一种语言,assert在C++中有意义。尽管它是一个宏而不是一个函数,但它是一个重要的工具。我告诉你检查数组边界。如果你不知道断言你可以用“if”指令来做。这是一个劣质的解决方案,但它是调查为什么代码崩溃的另一种方法。用一个简单的“if”你可以检查你的数组索引是否有效。我想他们会让你在大学里这样做。 – 2013-05-02 12:43:58
(2)“如果我使用你的第一条建议,它会在第二行崩溃:a_mp [i] [j] = valorAAssignar;”太棒了,你现在已经简化了50%的问题。你知道阅读部分没有崩溃,写作失败。划分问题是找到其根源的另一种方法。 – 2013-05-02 12:44:48
该代码是一个阅读的痛苦,但你是否确保a_mp被初始化为适当的大小?如果您最小化重现问题所需的代码,您可以让人们更容易阅读代码。 – SinisterMJ 2013-05-02 12:09:26
'Tauler :: iniciar'在哪里? – john 2013-05-02 12:10:59
此代码Tauler&Tauler :: operator =(const Tauler&y){... y.iniciar(); ...}不应该编译。 – john 2013-05-02 12:12:00