«Поврежден стек вокруг переменной’b'». (Нет выделения кучи)

#c #matrix

#c #матрица

Вопрос:

Итак, у меня есть простой класс matrix, и когда я регистрирую его на консоли, все в порядке, но проблема возникает при завершении программы.

Я не выделял никакой памяти кучи, это просто простой шаблонный класс, который может записывать матрицу в консоль. (Я планирую добавить сложение, вычитание и умножение.)

 #include <iostream>

using std::cout, std::cin, std::ostream;

template<typename T = float, int R = 4, int C = R>
class Matrix {
public:
    Matrix(T identity = T{}) {
        for (int i = 0; i < R;   i)
            for (int j = 0; j < C;   j)
                matrix[i][j] = T{};

        for (int i = 0; i < R;   i)
            matrix[i][i] = identity;
    }

    Tamp; operator()(int row, int column = 0) {
        if (C == 1)
            return matrix[(row < Ramp;amp; row > -1 ? row : 0)][0];
        else
            return matrix[(row < Ramp;amp; row > -1 ? row : 0)][(column < Ramp;amp; column > -1 ? column : 0)];
    }

    const Tamp; operator()(int row, int column = 0) const {
        if (C == 1)
            return matrix[(row < Ramp;amp; row > -1 ? row : 0)][0];
        else
            return matrix[(row < Ramp;amp; row > -1 ? row : 0)][(column < Ramp;amp; column > -1 ? column : 0)];
    }

    T* ToArray() {
        return reinterpret_cast<T*>(matrix);
    }

    const T* ToArray() const {
        return reinterpret_cast<const T* const>(matrix);
    }
private:
    T matrix[R][C];
};

template<typename T, int R = 4, int C = 0>
ostreamamp; operator<<(ostreamamp; stream, const Matrix<T, R, C>amp; matrix) {

    const T* matrixArray = matrix.ToArray();
    
    for (int i = 0; i < R;   i) {
        for (int j = 0; j < C;   j) {
            stream << (j == 0 ? '[' : ' ');
            stream << matrix(i, j);
            stream << (j == C - 1 ? ']' : ' ');
        }
        stream << (i == R - 1 ? '' : 'n');
    }

    return stream;
}

int main() {

    Matrix a(1.0f);
    Matrix<float, 4, 1> b(1.0f);

    cout << a << 'n';
    // no error occurs when I do this
    //cout << b(1, 0) << 'n';
    cout << b << 'n';

    /* OUTPUT
    [1  0  0  0]
    [0  1  0  0]
    [0  0  1  0]
    [0  0  0  1]
    [1]
    [0]
    [1]
    [0]
    */

    cin.get();
    // when the error occurs
}
 

Комментарии:

1. matrix[i][i] = identity; Что, если матрица не квадратная?

2. @dxiv Матрица 4 x 1 дает мне этот результат. /* [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] [1] [0] [1] [0] */ По-моему, все в порядке.

3. column < Ramp;amp; column > -1 ? column : 0) это должно быть column < C

4. @xKaihatsu В матрице 4×1 нет элемента matrix[1][1] , но код записывается в нее независимо. Это переполнение буфера.

5. @dxiv хороший улов, я добавлю это в ответ, если вы не возражаете

Ответ №1:

Проблема в этом цикле (благодаря dxiv)

     for (int i = 0; i < R;   i)
        matrix[i][i] = identity;
 

доступ к массиву выходит за пределы, когда R> C, вы должны исключить этот цикл и изменить предыдущий (при условии, что логика всегда заполнять diagonal идентификатором в вашем коде верна):

     for (int i = 0; i < R;   i)
        for (int j = 0; j < C;   j)
            matrix[i][j] = i == j ? identity : T{};
 

также в этом коде:

  return matrix[(row < Ramp;amp; row > -1 ? row : 0)][(column < Ramp;amp; column > -1 ? column : 0)];
 

вы сравниваете column с R , но вы должны сравнивать с C и, похоже, именно по этой причине вы обрабатываете регистр C==1 отдельно. Просто исправьте это, и вам больше не нужно это условие.

Примечание: я не вижу использования методов при reinterpret_cast преобразовании массива в указатель, но, скорее всего, вы делаете что-то не так здесь.