我一直在编写一个程序,对两个方阵进行一些操作。目前我一直在想一个能读取固定矩阵(以前已知的大小)的代码,并且我将这些数据写入二维数组。但是,我遇到了一个问题,因为当我使用上瘾的输出消息调试我的代码时,一切似乎都很好,但是最终输出(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
问题看起来很简单 - 我错过了每一行的所有最后一个数字,除了最后一个。我怀疑在某处我覆盖了正确的值,但我不知道在哪里。
答案 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_stride
和y_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]
。
使用基于类的方法的另一个优点是,将调试断言放入访问器代码变得非常容易,以确保您永远不会访问矩阵边界之外。