使用二维数组创建矩阵

时间:2014-05-02 00:56:17

标签: c++ arrays matrix

我一直在编写一个程序,对两个方阵进行一些操作。目前我一直在想一个能读取固定矩阵(以前已知的大小)的代码,并且我将这些数据写入二维数组。但是,我遇到了一个问题,因为当我使用上瘾的输出消息调试我的代码时,一切似乎都很好,但是最终输出(for循环中的那个)我是遗漏了一些数字。这真的很奇怪,因为当我在处理过程中使用的所有变量时,它们的值看起来很好。

#include <iostream>
#include <stdio.h>

using namespace std;

int main () 
{
    int number = 0; 
    int index = 0;
    int v_ind = 0;  // vertical index
    int h_ind = 0;  // horizontal index
    char c;
    int size = 3;   // temporary fixed size
    int searched_number;
    int matrix1 [size-1][size-1];
    int matrix2 [size-1][size-1];

    //scanf("%i %i", &size, &searched_number);


    while (index < size)
    {
        c = getchar_unlocked();

        if ( (c >= '0') && (c <= '9') )
        {
            number = (number * 10) + (c - '0');
            continue;
        }

        if (c == ' ')
        {   
            cout << "number on a space: " << number << endl;
            matrix1[h_ind][v_ind] = number;
            cout << "1 ) matrix1[" << h_ind << "][" << v_ind << "] : " <<  matrix1[h_ind][v_ind]  << endl << endl;
            v_ind ++ ;
            number = 0;
            continue;
        }

        if (c == '\n')
        {   
            cout << "num on a newLine: " << number << endl;
            matrix1[h_ind][v_ind] = number;
            cout << "2) matrix1[" << h_ind << "][" << v_ind << "] : " << matrix1[h_ind][v_ind] << endl << endl;
            h_ind ++ ;
            v_ind = 0;
            number = 0;
            index ++ ;
            continue;
        }

    }



    for (int i = 0; i < size; i ++) {
        for (int j = 0; j < size; j ++) {
            int num = matrix1[i][j];
            cout << "mat[" <<i <<"][" << j << "] : " << num << " " << endl;
        }
    }
}

下面我贴了一个矩阵Ideone.com的示例输出,如下所示:
  | 1 2 3 |
  | 4 5 6 |
  | 7 8 9 |

Sukces   time: 0 memory: 3348 signal:0
number on space: 1
1 ) matrix1[0][0] : 1

number on space: 2
1 ) matrix1[0][1] : 2

num na newLine: 3
2) matrix1[0][2] : 3

number on space: 4
1 ) matrix1[1][0] : 4

number on space: 5
1 ) matrix1[1][1] : 5

num na newLine: 6
2) matrix1[1][2] : 6

number on space: 7
1 ) matrix1[2][0] : 7

number on space: 8
1 ) matrix1[2][1] : 8

num na newLine: 9
2) matrix1[2][2] : 9

mat[0][0] : 1 
mat[0][1] : 2 
mat[0][2] : 4 
mat[1][0] : 4 
mat[1][1] : 5 
mat[1][2] : 7 
mat[2][0] : 7 
mat[2][1] : 8 
mat[2][2] : 9 

问题看起来很简单 - 我错过了每一行的所有最后一个数字,除了最后一个。我怀疑在某处我覆盖了正确的值,但我不知道在哪里。

3 个答案:

答案 0 :(得分:1)

将矩阵创建为matrix1 [size-1] [size-1],其索引从0到size-2。然后,您尝试将索引o中的值打印到size-1。尝试将矩阵声明为

int matrix1 [size][size]

答案 1 :(得分:1)

让我们看看为matrix1分配的内存布局以及您如何使用它。

你有

int matrix1[size-1][size-1];

相当于:

int matrix1[2][2];

对于本讨论的其余部分,我可以使用m代替matrix1进行说明。

m分配的内存如下:

m[0][0]
|    m[0][1]
|    |    m[1][0]
|    |    |    m[1][1]
|    |    |    |
v    v    v    v     
+----+----+----+----+
|    |    |    |    |
+----+----+----+----+

现在让我们看看m[0]m[1]

的位置
m[0]
|         m[1]
|         |    
v         v  
+----+----+----+----+
|    |    |    |    |
+----+----+----+----+

m[0][0] = 1;m[0][1] = 2;之后,值如下所示:

+----+----+----+----+
| 1  | 2  |    |    |
+----+----+----+----+

设置m[0][2] = 3;时,事情会变得奇怪。

          m[0][2]  -- this is where the run time thinks m[0][2] points to.
          |
          v
+----+----+----+----+
| 1  | 2  |    |    |
+----+----+----+----+

你得到:

+----+----+----+----+
| 1  | 2  | 3  |    |
+----+----+----+----+

现在,您执行m[1][0] = 4;如果您回想m[1][0]指向的位置,您会看到现在的值变为(4在该位置覆盖3):

+----+----+----+----+
| 1  | 2  | 4  |    |
+----+----+----+----+

执行m[1][1] = 5;后,您会得到:

+----+----+----+----+
| 1  | 2  | 4  | 5  |
+----+----+----+----+

当您执行m[1][2] = 6;时,您将获得的内存超过为m分配的内存。

                    m[1][2] -- this is where the run time thinks m[1][2] points to.
                    |
                    v
+----+----+----+----+----+
| 1  | 2  | 4  | 5  |    |
+----+----+----+----+----+

通常,此时您将输入未定义的行为。但是,由于幸运(或根据您的观点不幸)情况,您的程序不会崩溃,但允许您使用该内存。所以,你得到:

+----+----+----+----+----+
| 1  | 2  | 4  | 5  | 6  |
+----+----+----+----+----+

现在,您尝试使用m[2][0]m[2][2]m[2][2]来访问内存。再一次,运行时间允许您在m[1][1]之后使用内存而不会崩溃。通过遵循指针算术,m[2]指向过去2

m[1]地址
                    m[2]
                    |
                    v
+----+----+----+----+----+
| 1  | 2  | 4  | 5  | 6  |
+----+----+----+----+----+

                    m[2][0]
                    |    m[2][0]
                    |    |    m[2][2]
                    |    |    |
                    v    v    v
+----+----+----+----+----+----+----+
| 1  | 2  | 4  | 5  | 6  |    |    |
+----+----+----+----+----+----+----+

执行m[2][0] = 7;m[2][1] = 8;m[2][2] = 9;后,内存中的值如下所示:

+----+----+----+----+----+----+----+
| 1  | 2  | 4  | 5  | 7  | 8  | 9  |
+----+----+----+----+----+----+----+

现在您可以看到为什么要获得输出。 m[0][2]m[1][0]指向包含值4的同一地址。 m[1][2]m[2][0]指向包含值7的同一地址。

我的猜测是,当你超出为matrix2分配的内存并且程序没有崩溃时,你正在使用为matrix1分配的内存。在其他情况下,程序可能会以不可预测的方式运行。

答案 2 :(得分:0)

如果你正在对你的矩阵做任何有趣的事情,你应该考虑抓住现有的库。其中许多将为您提供一堆实用程序,它们仍将使用2D或1D阵列来备份数据。您应该选择的具体项目将取决于您尝试使用它的目的。

如果您决定滚动自己的矩阵,我会考虑使用带有一维数组的类。

之前我曾经使用过这样的东西
class Matrix {
   int * values;
   unsigned int nx;
   unsigned int ny;
   unsigned int x_stride;
   unsigned int y_stride;

   int& operator(int x, int y) {
     return values[nx*x_stride+ny*y_stride];
   }
   ... constructors etc...
};

为什么同时使用x_stridey_stride,其中一个1而另一个nx?它允许你做一些漂亮的技巧,如无副本子矩阵和大型矩阵上的无副本转置。

void transpose(Matrix &m) {
  std::swap(m.nx, m.ny);
  std::swap(m.x_stride, m.y_stride);
}

Matrix submatrix_slice(const Matrix &m, int start_x, int step_x, int start_y, int step_y) {
   Matrix retval(m, Matrix::SharedData());
   retval.start_x += start_x;
   retval.x_stride *= step_x;
   retval.start_y += start_y;
   retval.y_stride *= step_y;
}

你为什么要关心这些?好吧,也许你没有,但它可以使许多数值算法的实现更整洁,而不会影响速度。 (例如,我用它们得到了高斯消元,逆,行列式,最小二乘等的整齐版本。)

一个区别是你需要使用matrix(i,j)而不是matrix[i][j],但如果你真的关心它(我之前不得不关心它)。 ..)你可以创建一个支持相同数据的MatrixRow类,并由MatrixRow Matrix::operator[](int)返回,它也可以提供int& MatrixRow::operator[](int),如果你这样做(并提供const版本)你将能够像你期望的那样matrix[i][j]

使用基于类的方法的另一个优点是,将调试断言放入访问器代码变得非常容易,以确保您永远不会访问矩阵边界之外。