1

I've been struggling on this for about an hour now so I'm turning to the almighty entity that is the internet for assistance.

I'm trying to write a program that will A) read a matrix from a txt file in the following format where the first number is the columns (4) and the second number is the rows(3) in the matrix. And each row of numbers corresponds to a row in the matrix.

4 3
1 2 3 4
0 1 2 7
4 1 9 2

and B) calculate the number of ones in the matrix. So the above example would return 3. My code is below.

#include <iostream>
#include <fstream>
#include <string>


using namespace std;

void count_ones(int matrix[][], int rows, int columns)
{

int count = 0;

for(int i = 0; i < rows; i++)
{
        for( int j = 0; j < columns; j++)
        {
                if( matrix[i][j] == 1)
                { count++;}
        }
}

cout << "There are " << count << " ones in this matrix.";
}

int main(int argc, char* argv[])
{

int rows, columns;
string file_name = argv[1];

ifstream reader("m1.txt");

reader >> columns;
reader >> rows;

int matrix[rows][columns];

for(int i = 0; i < rows; i++)
{
        for(int j = 0; j < columns; j++)
        {
          reader >>  matrix[i][j];
        }
}


cout << columns << " " << rows;
cout << endl;
for( int k = 0; k < rows; k++) {
      for( int l = 0; l < columns; l++)
         cout << matrix[k][l] << " ";
      cout << endl;

reader.close();

count_ones(matrix, rows,columns);
return 0;
}
}

Right now I have two issues. The code i'm using to print the matrix I'm reading from the "m1.txt" file is only printing the first two lines and I have absolutely no clue what could be causing this but I'm guessing it has something to do with my ifstream reader.

4 3
1 2 3 4

Secondly, I'm getting a bunch of errors I don't understand when I try to pass my matrix to my count_ones function. I'm not very good with C++ so I would appreciate all the help I can get.

Caladin00
  • 356
  • 1
  • 3
  • 11
  • 1
    I don't think you can accept arrays like that (`matrix[][]`) in C++. If I remember correctly (which I might not) C++ only allows 1 dimension to be passed like that i. e. `matrix[]`. It could have changed, though. –  Feb 26 '19 at 19:22
  • 3
    "*I'm getting a bunch of errors*", please always include the errors so others don't need to guess what they are. Also indent your code properly, you might notice what the problem with the output is after that. Or you can debug the code line by line to see what's going on. – Sami Kuhmonen Feb 26 '19 at 19:22
  • 3
    `return` is inside the loop, meaning that the function would theoretically return after only 1 iteration. –  Feb 26 '19 at 19:26
  • 1
    You have the closing `}` of the first `for` statement of the printing code in the wrong place. – R Sahu Feb 26 '19 at 19:26
  • Thank you Chipster! That solved one issue.Does anyone have a better way to pass the matrix to the count_ones method? I heard something about using pointers but I absolutely suck with them. – Caladin00 Feb 26 '19 at 19:29
  • Be careful with `int matrix[rows][columns];`. It's a Variable Length Array and not supported under Standard C++. The g++ compiler allows it via extension, but it comes at a bit of a cost. `sizeof` behaviour is a bit different and it is really easy to run the program out of Automatic storage, resulting in inexplicable program behaviour.. – user4581301 Feb 26 '19 at 19:31
  • Suggestion: Write less code before compiling and testing. It keeps bugs from accumulating and ganging up on you. One bug is usually fairly easy to pick off and fix, but two bugs often hide one another. It's not uncommon to find the time spent debugging goes exponential. If you only added a line or two,and find a bug, you don't have to search as much code; the bug is usually in the couple line you just added. You are also less likely to repeat the same mistake if you catch it early. – user4581301 Feb 26 '19 at 19:38
  • I'm probably wrong about the whole `matrix[][]` thing. However, if you do want another way, you try `int** matrix` –  Feb 26 '19 at 19:41
  • [Link to a good trick that keeps most of the speed of the variable length array, but makes it easy to pass around and use.](https://stackoverflow.com/a/2076668/4581301) – user4581301 Feb 26 '19 at 20:36

3 Answers3

3

In a comment, you asked

Does anyone have a better way to pass the matrix to the count_ones method?

  1. Don't use

    int matrix[rows][columns];
    

    This is not standard C++. It is supported by some compilers as an extension.

  2. Use

    std::vector<std::vector<int>> matrix;
    

    You can initialize it with the correct sizes for rows and columns using

    std::vector<std::vector<int>> matrix(rows, std::vector<int>(columns));
    
  3. Change the declaration of count_ones to accept a std::vector<std::vector<in>>.

    int count_ones(std::vector<std::vector<in>> const& matrix);
    

    Update its implementation accordingly.


Suggestion for improvement

You can avoid the error of putting the closing } in the wrong place by using helper functions to write the matrix to cout.

std::ostream& operator<<(std::ostream& out, std::vector<int> const& row)
{
   for ( int item : row )
      out << item << " ";
   return out;
}

std::ostream& operator<<(std::ostream& out, std::vector<std::vector<int>> const& matrix)
{
   for ( auto const& row : matrix )
      out << row << std::endl;
   return out;
}

and then use

std::cout << matrix;

in main.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    I ended up turning my 2D array into a 1D array but I solved my issue. Thanks for the input. – Caladin00 Feb 26 '19 at 20:19
  • 1
    @Caladin00, I hope you decided to use `std::vecot matrix(rows*columns);` instead of `int matrix[rows*columns];`. – R Sahu Feb 26 '19 at 20:21
3

You have done a mistake in the last for loop.

for( int k = 0; k < rows; k++) {
      for( int l = 0; l < columns; l++)
         cout << matrix[k][l] << " ";
      cout << endl;

reader.close();

count_ones(matrix, rows,columns);
return 0;
}
}

It should be like this

for( int k = 0; k < rows; k++) {
      for( int l = 0; l < columns; l++)
         cout << matrix[k][l] << " ";
      cout << endl;
}

reader.close();

count_ones(matrix, rows,columns);
return 0;
}

Because of this the outer for loop in your code runs only once and prints only first row of matrix.

Edit: Some more things to correct. You can not use matix[][] as a function parameter, it will through the error multidimensional array must have bounds for all dimensions except the first

You can use double pointer for this work. Change the check ones function declaration to this

void count_ones(int **matrix, int rows, int columns)

replace

int matrix[rows][columns];

with

int **matrix = (int **)malloc(sizeof(int *)*columns);
for(int i=0; i < columns; i++)
    *(matrix + i) = (int *)malloc(sizeof(int)*rows);

and the code should work like a charm. And also remove this line, its redundant as file_name is not being used.

string file_name = argv[1];
Rajnesh
  • 798
  • 5
  • 22
0

So, I don't know what the errors are until you post them, but I have an idea why your output is cut off prematurely.

So, to recap, let's look at your code again (the relevant part":

cout << columns << " " << rows;
cout << endl;
for( int k = 0; k < rows; k++) {
    for( int l = 0; l < columns; l++) /* { */
        cout << matrix[k][l] << " ";
    /* } */
    cout << endl;

    reader.close();

    count_ones(matrix, rows,columns);
    return 0;
}

I've indented it so it's easier to read as well as added the comment braces, just so it's clearer what is getting executed by what.

And now, the output:

4 3
1 2 3 4

Okay, now let's break down what's happening.

cout << columns << " " << rows;
cout << endl;

This is creating the line:

4 3

So far so good, right?

Now, we enter the lop:

for( int k = 0; k < rows; k++) {
    for( int l = 0; l < columns; l++) /* { */
        cout << matrix[k][l] << " ";
    /* } */
    cout << endl;

and get this:

1 2 3 4

This must be the first line of the matrix.

More code executes:

reader.close();

count_ones(matrix, rows,columns);

which isn't relevant to your problem.

And now this:

    return 0;
}

Whoops! We've just left the function by calling return.

The loop will no longer execute because we've terminated it prematurely by returning, only outputting the first line of the matrix.

Solution: Just move the return statement outside the loop like so:

cout << columns << " " << rows;
cout << endl;
for( int k = 0; k < rows; k++) {
    for( int l = 0; l < columns; l++) /* { */
        cout << matrix[k][l] << " ";
    /* } */
    cout << endl;

    reader.close();

    count_ones(matrix, rows,columns);
}
return 0;

And that should fix the problem.

Finally, some friendly advice, take Sami Kuhmonen's advice and indent your code. It makes it easier to read and catch things like this.

EDIT: One more point, as R.k. Lohana mentioned, you probably want to pull these lines out of the loop too:

    reader.close();

    count_ones(matrix, rows,columns);

Like so:

for( int k = 0; k < rows; k++) {
    for( int l = 0; l < columns; l++) /* { */
        cout << matrix[k][l] << " ";
    /* } */
    cout << endl;

}

reader.close();

count_ones(matrix, rows,columns);

return 0;

Since you probably only want to do them once and not multiple times.