C++ debug assertion 질문
조회수 1692회
#include <iostream>
#include <fstream>
#define FILENAME "data.txt"
#define MAXSIZE 60
using namespace std;
ifstream fin;
ofstream fout;
class Matrix {
private:
int size;
int numOfElements;
int* row;
int* col;
int* value;
public:
void sort();
Matrix(); // constructor
Matrix(int, int, int*, int*, int*);
Matrix(const Matrix&); // copy constructor
~Matrix();
void display() const;
void getData();
void printData();
Matrix operator*(const Matrix&);
};
void Matrix::printData() {
fout.open("resultMatrix.txt");
fout << size << endl << numOfElements << endl;
for (int i = 0; i < numOfElements; i++) {
fout << row[i] << " " << col[i] << " " << value[i] << endl;
}
fout.close();
}
void Matrix::sort() {
int tempRow, tempCol, tempValue;
for (int i = 0; i < numOfElements; i++)
for (int j = i + 1; j < numOfElements; j++) {
if (row[i] > row[j]) {
tempRow = row[i]; row[i] = row[j]; row[j] = tempRow;
tempCol = col[i]; col[i] = col[j]; col[j] = tempCol;
tempValue = value[i]; value[i] = value[j]; value[j] = tempValue;
}
else if (row[i] == row[j]) {
if (col[i] > col[j]) {
tempRow = row[i]; row[i] = row[j]; row[j] = tempRow;
tempCol = col[i]; col[i] = col[j]; col[j] = tempCol;
tempValue = value[i]; value[i] = value[j]; value[j] = tempValue;
}
}
}
}
Matrix::Matrix(int _size, int _numOfElements, int* _row, int* _col, int* _value) {
this->size = _size;
this->numOfElements = _numOfElements;
row = new int[_numOfElements];
col = new int[_numOfElements];
value = new int[_numOfElements];
for (int i = 0; i < _numOfElements; i++) {
this->row[i] = _row[i];
this->col[i] = _col[i];
this->value[i] = _value[i];
}
}
Matrix::Matrix() {
size = 0;
numOfElements = 0;
row = nullptr;
col = nullptr;
value = nullptr;
}
void Matrix::getData() {
fin >> this->size;
fin >> this->numOfElements;
row = new int[numOfElements];
col = new int[numOfElements];
value = new int[numOfElements];
for (int i = 0; i < numOfElements; i++) {
fin >> row[i] >> col[i] >> value[i];
}
this->sort();
}
Matrix Matrix::operator*(const Matrix& B) {
int newNumOfElements = 0, notAdded = 1;
int* tempRow, *tempCol, *tempValue;
tempRow = new int[this->size * this->size];
tempValue = new int[this->size * this->size];
tempCol = new int[this->size * this->size];
Matrix rhs((const Matrix&)B);
int* temp; // transpose
temp = rhs.row;
rhs.row = rhs.col;
rhs.col = temp;
for (int i = 0; i < this->numOfElements; i++) { // multiply
for (int j = 0; j < rhs.numOfElements; j++) {
notAdded = 1;
if (col[i] == rhs.col[j]) {
for (int k = 0; k <= numOfElements - 1; k++) {
if (tempRow[k] == row[i] && tempCol[k] == rhs.row[j]) {
tempValue[k] += value[i] * rhs.value[j];
notAdded = 0;
}
}
if (notAdded) {
tempRow[newNumOfElements] = row[i];
tempCol[newNumOfElements] = rhs.row[j];
tempValue[newNumOfElements] = value[i] * rhs.value[j];
newNumOfElements++;
}
}
}
}
Matrix ans(rhs.size, newNumOfElements, tempRow, tempCol, tempValue);
//ans.display();
delete[] tempRow;
delete[] tempCol;
delete[] tempValue;
return ans;
}
void Matrix::display()const {
cout << "The Matrix is : " << endl;
for (int i = 0; i < this->numOfElements; i++) {
cout << row[i] << " " << col[i] << " " << value[i] << endl;
}
}
Matrix::~Matrix() {
if (this->row != nullptr) {
delete(this->row);
delete(this->col);
delete(this->value);
}
}
Matrix::Matrix(const Matrix& rhs) {
this->size = rhs.size;
this->numOfElements = rhs.numOfElements;
if (rhs.row != nullptr) {
this->row = new int(numOfElements);
this->col = new int(numOfElements);
this->value = new int(numOfElements);
for (int i = 0; i < rhs.numOfElements; i++) {
this->row[i] = rhs.row[i];
this->col[i] = rhs.col[i];
this->value[i] = rhs.value[i];
}
}
else {
this->row = nullptr;
this->col = nullptr;
this->value = nullptr;
}
}
int main() {
fin.open(FILENAME);
Matrix A, B, C;
A.getData();
B.getData();
C = A * B;
A.display(); B.display(); C.display();
C.printData();
cout << "Done !!" << endl;
return 0;
}
코딩중에 질문이 생겨 질문드려요 (Sparse Matrix Multiplication 에 관한 소스입니다.)
내용이해를 위해 잠깐 설명해드리면, getData()함수로 파일입력을 통해 Sparse Matrix Data를 받아와서, 두 Matrix간의 곱셈을 하는 코드입니다.
Visual Studio에서만 자꾸 에러가 나서 질문드려요.. 저번에 isValidHeapPointer(Block) 에러에 관한 질문을 드렸었고, 답변을 받았었습니다.(감사합니다♥♥)
그래서 그 때 실수한점 생각하면서 코딩 했는데, 이번에도 오류가납니다. 이번에는 좀 이상한게.. 실행시키면 오류가 안나고 제가 예상하는 지점 이후로 아무런 실행이 되지않거나, 계속 다른 오류가 납니다. 위에쓴 오류 isValidHeapPointer(Block)가 날때도 있습니다
디버깅을 해보면 오류명이 안뜨고 '중단점을 트리거 했습니다' 가 뜨거나 다른 오류들이 뜹니다.
같은 실수 반복안하려 아무리 찾아봤는데 잘못한점이 제겐 보이지 않네요ㅠㅠ 한번 찾아봐주시면 감사하겠습니다
-
(•́ ✖ •̀)
알 수 없는 사용자
1 답변
-
일단 각각의 문제를 나눠서 코멘트 쓰기보단 한번에 쓰는 게 좋을 듯 하여, 전체적으로 코드를 수정하고, 주석으로 코멘트를 달았습니다.
그리고 사실 new int[]를 통한 배열 할당보다는 std::vector 등의 STL을 이용하는 것이 좋지만, 거기까지 수정해버리면 원래 코드와 너무 달라질 듯 하여 알려만 드립니다.
#include <iostream> #include <fstream> #define FILENAME "data.txt" #define MAXSIZE 60 using namespace std; // 전역변수는 왠만하면 쓰지 않는 게 좋습니다. // ifstream fin; // ofstream fout; class Matrix { public: Matrix(); ~Matrix(); // 함수 선언시 매개변수의 이름을 생략하는 건 좋지 않습니다. // 그리고 변수명은 일관성 있게 짓는 게 좋습니다. // 어떤 함수는 매개변수에 접두사(_)를 붙이고 어떤 함수는 안 붙이면, 헷갈리게 됩니다. Matrix(int _size, int _numOfElements, int* _row, int* _col, int* _value); Matrix(const Matrix& _rhs); Matrix& operator=(const Matrix& _rhs); void init(const Matrix& _rhs); void release(); void getData(ifstream& _fin); void printData() const; void display() const; void sort(); Matrix operator*(const Matrix& _rhs); private: // 멤버 변수에는 적당한 접두사나 접미사를 붙이는 것이 좋습니다. // 함수 내에서 보기도 편하고, 지역변수와 이름이 겹치는 것을 피할 수 있습니다. int mSize; int mNumOfElements; int* mRow; int* mCol; int* mValue; }; // 메인 함수는 최대한 위쪽에 위치시키는 것이 // 전체코드 가독성에 있어서 좋다고 생각합니다. int main() { Matrix A, B, C; ifstream fin(FILENAME); A.getData(fin); B.getData(fin); fin.close(); C = A * B; // 함수 호출을 한 줄에 여러번 쓰는 것은 좋지 않습니다. A.display(); B.display(); C.display(); C.printData(); cout << "Done !!" << endl; return 0; } // 함수 정의 순서는 선언 순서와 동일하게 유지하는 것이 좋습니다. Matrix::Matrix() : mSize(0) , mNumOfElements(0) , mRow(nullptr) , mCol(nullptr) , mValue(nullptr) { // 기본적인 멤버 변수의 초기화는 // 생성자 초기화 리스트를 이용하는 게 좋습니다. } Matrix::~Matrix() { // 문제1. 널체크를 변수 하나에 대해서만 했네요. // 문제2. 할당은 배열로 하고, 해제는 그냥 delete를 썼네요. // PS1. this->는 굳이 쓸 필요가 없습니다. // PS2. 널체크는 if(변수) 이런 식으로도 가능합니다. release(); } Matrix::Matrix(int _size, int _numOfElements, int* _row, int* _col, int* _value) : mSize(_size) , mNumOfElements(_numOfElements) , mRow(_row) , mCol(_col) , mValue(_value) { // 이 생성자가 호출되는 쪽을 보니, temp변수에 new를 해서 이걸 호출하고, // 여기서 또 new 해서 복사한다음에 temp변수를 delete하던데, // 굳이 그럴필요 없이 포인터를 그대로 옮겨주면 될 듯합니다. } Matrix::Matrix(const Matrix& _rhs) : mSize(0) , mNumOfElements(0) , mRow(nullptr) , mCol(nullptr) , mValue(nullptr) { // 문제3. 여기도 널체크가 변수 하나에만 되어있었습니다. // 문제4. new int()는 배열 할당이 아닙니다. // 문제5. _rhs.mNumOfElements의 값이 0이하 라면 문제가 생깁니다. // 따라서, 그때는 빈 객체로 남도록 해야합니다. init(_rhs); } Matrix& Matrix::operator=(const Matrix& _rhs) { // PS3. 복사 생성자와 복사 대입 연산자를 구현할 때는, // 중복되는 코드를 사용하게 되니, 초기화와 메모리 해제를 함수로 추출하여 // 해당 함수들을 호출하도록 해주는 것이 좋습니다. release(); init(_rhs); return *this; } void Matrix::init(const Matrix& _rhs) { if (_rhs.mNumOfElements > 0 && _rhs.mRow != nullptr && _rhs.mCol != nullptr && _rhs.mValue != nullptr) { mSize = _rhs.mSize; mNumOfElements = _rhs.mNumOfElements; mRow = new int[mNumOfElements]; mCol = new int[mNumOfElements]; mValue = new int[mNumOfElements]; for (int i = 0; i < mNumOfElements; i++) { mRow[i] = _rhs.mRow[i]; mCol[i] = _rhs.mCol[i]; mValue[i] = _rhs.mValue[i]; } } } void Matrix::release() { if (mRow) delete[] mRow; if (mCol) delete[] mCol; if (mValue) delete[] mValue; } void Matrix::getData(ifstream& _fin) { _fin >> mSize; _fin >> mNumOfElements; // 어차피 이 변수는 size * size 인듯 하니, 따로 읽을 필요는 없어 보입니다. // 위의 데이터 읽기에 실패한다면, 아래 코드들을 실행하면 안 되기 때문에 // 예외처리를 추가했습니다. if (mSize < 1 || mNumOfElements < 1) return; mRow = new int[mNumOfElements]; mCol = new int[mNumOfElements]; mValue = new int[mNumOfElements]; for (int i = 0; i < mNumOfElements; i++) { _fin >> mRow[i] >> mCol[i] >> mValue[i]; } // 여기서 sort 함수를 호출하는 의미는 잘 모르겠습니다.. sort(); } void Matrix::printData() const { // 파일 오픈시 ios::ate 플래그를 주면, // 파일에 이미 있는 데이터에 이어서 쓰기 작업을 진행할 수 있습니다. ofstream fout("resultMatrix.txt", ios::ate); fout << mSize << endl; fout << mNumOfElements << endl; for (int i = 0; i < mNumOfElements; i++) { fout << mRow[i] << " " << mCol[i] << " " << mValue[i] << endl; } fout.close(); } void Matrix::display() const { cout << "The Matrix is : " << endl; for (int i = 0; i < mNumOfElements; i++) { cout << mRow[i] << " " << mCol[i] << " " << mValue[i] << endl; } } void Matrix::sort() { // 문제6. 가장 바깥의 for문에 스코프({})가 없습니다. // 문제7. 한 줄에 여러 코드가 들어가 있어서 가독성이 떨어집니다. // PS4. 중복되는 패턴의 코드들은 함수로 추출하는 게 좋지만, // 추가적인 함수를 만들어드리면, 원래코드랑 너무 차이가 생길 듯 하여 주석만 남깁니다. int tempRow, tempCol, tempValue; for (int i = 0; i < mNumOfElements; i++) { for (int j = i + 1; j < mNumOfElements; j++) { if (mRow[i] > mRow[j]) { // swap(mRow[i], mRow[j]); 이런 식의 코드로 변경하는 것이 좋을 듯 합니다. tempRow = mRow[i]; mRow[i] = mRow[j]; mRow[j] = tempRow; tempCol = mCol[i]; mCol[i] = mCol[j]; mCol[j] = tempCol; tempValue = mValue[i]; mValue[i] = mValue[j]; mValue[j] = tempValue; } else if (mRow[i] == mRow[j]) { if (mCol[i] > mCol[j]) { tempRow = mRow[i]; mRow[i] = mRow[j]; mRow[j] = tempRow; tempCol = mCol[i]; mCol[i] = mCol[j]; mCol[j] = tempCol; tempValue = mValue[i]; mValue[i] = mValue[j]; mValue[j] = tempValue; } } } } } Matrix Matrix::operator*(const Matrix& _rhs) { int newNumOfElements = 0; int notAdded = 1; // 변수 선언과 동시에 값을 대입하는 것이 좋습니다. int* tempRow = new int[mSize * mSize]; int* tempValue = new int[mSize * mSize]; int* tempCol = new int[mSize * mSize]; // (const Matrix&) 캐스팅은 필요 없는 코드입니다. Matrix rhs(_rhs); // 여기도 swap함수를 쓰는 게 좋을 듯 합니다. // transpose int* temp = rhs.mRow; rhs.mRow = rhs.mCol; rhs.mCol = temp; // 아래 알고리즘이 제대로 동작하는 지까지는 검증하지 않았습니다. // 제대로 작성하셨다고 가정하고 넘어가겠습니다. // multiply for (int i = 0; i < mNumOfElements; i++) { for (int j = 0; j < rhs.mNumOfElements; j++) { notAdded = 1; if (mCol[i] == rhs.mCol[j]) { for (int k = 0; k <= mNumOfElements - 1; k++) { if (tempRow[k] == mRow[i] && tempCol[k] == rhs.mRow[j]) { tempValue[k] += mValue[i] * rhs.mValue[j]; notAdded = 0; } } if (notAdded) { tempRow[newNumOfElements] = mRow[i]; tempCol[newNumOfElements] = rhs.mRow[j]; tempValue[newNumOfElements] = mValue[i] * rhs.mValue[j]; newNumOfElements++; } } } } // temp 변수들은 그대로 새 객체에게 넘겨줬기 때문에 // 여기서 delete[] 해줄 필요가 없습니다. // 하지만, 1,2번째 인자가 문제가 없는지는 애매합니다. // 위의 알고리즘과 함께 다시 한번 검증해보셔야 할 듯 합니다. Matrix ans(_rhs.mSize, newNumOfElements, tempRow, tempCol, tempValue); //ans.display(); return ans; }
- 헐.. 감사합니다ㅠㅠㅠ 정말 많이배워가네요.. 선물이라도 드리고싶네요ㅠㅠㅠ 이렇게까지 해주실줄은.. 알 수 없는 사용자 2016.10.2 14:31
- 하나만 더 여쭤볼게요!! Matrix::Matrix(const Matrix& _rhs)에서, 생성자 초기화 리스트를 사용하셨는데, 이 부분은 if문의 조건이 해당하지 않을 때 작동하는 건가요? 알 수 없는 사용자 2016.10.2 14:36
- 생성자 초기화 리스트는 생성자 본문에 진입하기 전에 시행됩니다. 즉, Matrix::Matrix(const Matrix& _rhs)에서 초기화 리스트를 통해 전부 기본값(0 or nullptr)으로 초기화를 먼저 진행한 후, if문의 조건이 해당될 때 추가적으로 값을 할당하는 작업이 이루어집니다. Subin Park 2016.10.2 15:52
- 흐음.. 감사합니다!! 습관이나 코딩스타일에관해서도 고칠게많군요 알려주신대로 수정하면서 해보니 main에서 C = A * B;를 수행할 때 대입연산자를 구현 안했더군요.. 그래서 메인에서 C의 데이터를 보면 쓰레기값이 나왔었네요 감사합니다!! 알 수 없는 사용자 2016.10.3 01:08
- 죄송합니다 하나만더 여쭤봐도될까요..? 전역변수를 안쓸려고 수정중인데, txt파일에서 두 개의 매트릭스의 데이터를 읽어오려고 합니다. getData의 함수는 한 개의 매트릭스만 읽어오는 함수입니다. getData함수를 호출 할 때 마다 파일을 오픈하니, A매트릭스 B매트릭스 가 같은 데이터를 읽어오더라구요.. (txt파일에 보면 A매트릭스 데이터 밑에 B매트릭스 데이터가 있습니다) 그래서 다른 방법으로 메인에서 ifstream을 선언하고, getData의 parameter로 ifstream을 넘겨주려고 하니 삭제된함수? 라고하면서 컴파일에러가 뜨네요.. getData함수 자체를 두 개 매트릭스를 읽어 오는것 밖에 방법이 없을까요? 알 수 없는 사용자 2016.10.3 01:47
- 아마 컴파일 에러가 뜬 이유는, 함수의 정의부분만 수정하고 선언부분을 수정하지 않은 게 아닐 까 싶습니다. 일단 위 코드에서 생성자부분과 파일 입출력 부분을 수정하였으니, 한번 비교해보세요. Subin Park 2016.10.3 17:40
댓글 입력