2

I've been writing a program conducting some operations on two square matrixes. For the time being I've been thinking of a code which will read a matrix of a fixed (previously known size) and I'm writing these data into a 2-D array. However, I've got a problem, because when I'm debugging my code with addictional output messages everything seems fine, but the final output (the one in the for loop) I'm missing some numbers. It is really strange because when I'm prining all variables used in the process their values look fine.

#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;
        }
    }
}

Below I've pasted an exemplary output from Ideone.com of a matrix like this:
| 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 

The problem looks simple - I'm missing all last numbers from every row, except from the last one. I suspect that somewhere I overwrite proper values but I've got no clue where.

3 Answers 3

1

you create the matrix as matrix1[size-1][size-1] which will have indices from 0 to size-2. Then you attempt to print the values from indices o to size-1. Try declaring the matrix as

int matrix1 [size][size]
Sign up to request clarification or add additional context in comments.

2 Comments

You're right! I forgot that size is one thing and indexing array from 0 is another thing. Thank U very much!
Also , arrays with runtime size are illegal in standard C++; be aware that in doing this you are relying on a compiler extension
1

Let's see the layout of the memory allocated for matrix1 and how you are using it.

You have

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

Which is equivalent to:

int matrix1[2][2];

For rest of this discussion let me use m instead of matrix1 for illustration.

Memory allocated for m looks like:

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

Now let's see where m[0] and m[1] point

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

After m[0][0] = 1; and m[0][1] = 2;, the values look like:

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

Things get strange when you set m[0][2] = 3;.

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

and you get:

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

Now, you execute m[1][0] = 4; If you recall where m[1][0] points to, you will see that the values now become (4 overwrites 3 in the location):

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

After you execute m[1][1] = 5;, you get:

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

When you execute m[1][2] = 6;, you are reaching the memory past what was allocated for m.

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

Normally, you'd enter undefined behavior at this point. However, due to lucky (or unlucky depending your point of view) circumstances, your program does not crash but lets you use that memory. So, you get:

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

Now, you try to access memory by using m[2][0], m[2][2], and m[2][2]. Once again, the run time lets you use the memory after m[1][1] without crashing. By following pointer arithmetic, m[2] points to 2 addresses past 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  |    |    |
+----+----+----+----+----+----+----+

After you execute, m[2][0] = 7;, m[2][1] = 8;, and m[2][2] = 9;, the values in memory look like:

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

Now you can see why you are getting the output. m[0][2] and m[1][0] point to the same address that holds the value 4. m[1][2] and m[2][0] point to the same address that holds the value 7.

My guess is that you are using the memory allocated for matrix2 when you are reaching beyond the memory allocated for matrix1 and the program does not crash. In other circumstances, the program might behave in unpredictable ways.

1 Comment

@R Sahu Thank U for this comprehensive reply. I've already managed to fix my problem which was really trivial but so damn difficult to discover.
0

If you're doing anything interesting with your matrices, you should probably consider grabbing an existing library. Many of these will provide a heap of utilities for you, and they will still use either a 2D or 1D array for backing the data. the particular one you should choose will depend on what you're trying to use it for.

If you're determined to roll your own matrices I'd consider using a class with a 1D array. I've used something like this before

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...
};

Why use both x_stride and y_stride, when one will be 1 and the other nx? It allows you to do some nice tricks like copyless submatrix and copyless transpose on large matrices.

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;
}

Why should you care about these? Well maybe you don't, but it can make the implementation of a lot of numerical algorithms neater without compromising speed. (E.g. I've used them to get neat versions of Gaussian elimination, Inverse, Determinant, least squares etc.)

One difference is that you need to use matrix(i,j) rather than matrix[i][j], but if you really care about that (and I've had to care about it before...) you can create a MatrixRow class that backs onto the same data, and is returned by a MatrixRow Matrix::operator[](int), which can also provide a int& MatrixRow::operator[](int), If you do this (and provide the const versions too) you'll be able to do matrix[i][j] as you might expect.

Another advantage of using a class based approach is that it becomes really easy to put debugging assertions into your accessor code, to ensure that you never access outside the matrix bounds.

2 Comments

Thank U very much for this reply! My task is to multiply two square matrices and to find a number in the product matrix. So the only 'typical' mathematical operation on them is to multiply them. And on the top of that the program sadly has to be more structural because it's for my algorithm design class so I reeeally care about speed. One of the things I was told that to get a greater performance I've got to avoid bouilt-in libraries and to try to write my own optimized functions... So this is what I've got to do, though what You've posted seems much more neat and simple...
The "avoid third party libraries for performance" line seems like a bad move to me. You just need to pick one that correctly addresses your need. For example some of these will use clever tricks to get more than one calculation occuring at once, or some calculations occuring at compile time. Getting that kind of optimisation working yourself is hard.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.