C++ debug assertion 질문


#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)가 날때도 있습니다

디버깅을 해보면 오류명이 안뜨고 '중단점을 트리거 했습니다' 가 뜨거나 다른 오류들이 뜹니다.

같은 실수 반복안하려 아무리 찾아봤는데 잘못한점이 제겐 보이지 않네요ㅠㅠ 한번 찾아봐주시면 감사하겠습니다

  • 2016년 10월 02일에 작성됨
    컴퓨터공학과 재학중인 학생입니다.

조회수 144


1 답변


좋아요
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월 02일에 작성됨
    C++, C# 좋아합니다.

  • 헐.. 감사합니다ㅠㅠㅠ 정말 많이배워가네요.. 선물이라도 드리고싶네요ㅠㅠㅠ 이렇게까지 해주실줄은..    이혁준   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     

로그인이 필요한 기능입니다.

Hashcode는 개발자들을 위한 무료 QnA사이트 입니다. 작성한 답변에 다른 개발자들이 댓글을 작성하거나 좋아요/싫어요를 할 수 있기 때문에 계정을 필요로 합니다.
► 로그인
► 계정만들기
Close