Count and display number of rows and columns of file input

Hi all, I am trying the output the number of rows and columns of a matrix text file.
For example, if the matrix text file is
2 10 5
-7 8 9

in its terminal console, it will output as it is from the file it read and also output the number of rows and column.
Currently I am having the issue, in which I am able to get the number of rows. Can anyone kindly point to me how to get the number of columns?

The following is my code, please pardon me if the formatting used is wrong etc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main(){

    ifstream fin;  //file input stream
    ofstream fout; //file output stream

    fin.open("/Desktop/matrix_f.txt");
    fout.open("/Desktop/matrix_f.out");
    string msg;
    
    int countRows = 0;
    
    if (fin.is_open())
    {
        while (getline(fin,msg))
        {
            //read until eof
            cout << msg << '\n';
            countRows++;
        }
        
        cout << "No. of rows : " << countRows << endl;
        
        fin.close();
        fout.close();
    }
    else
    {
        cout << "File is unable to be opened";
    }
}
Last edited on
What is the problem? What behaviour are you seeing, and how is it different from the behaviour you expect?
closed account (D80DSL3A)
He's asking for an idea on how to find the number of elements in a row from the given file data.
Here's a way that is working for me, so long as the data is formatted well in the file.
Read values from the 1st row until a '\n' is encountered. Continue reading to find the number of total items then calculate the rows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void readFile()
{
    std::ifstream fin("arrData.txt");
    int val=0, rows=0, cols=0, numItems=0;

    while( fin.peek() != '\n' && fin >> val )
    {
        cout << val << ' ';
        ++numItems;
    }
    cols = numItems;// # of columns found

    cout << '\n';
    while( fin >> val )
    {
        ++numItems;
        cout << val << ' ';
        if( numItems%cols == 0 ) cout << '\n';
    }
    rows = numItems/cols;
    cout << "rows = " << rows << ", cols = " << cols << '\n';
}

From your data
2 10 5
-7 8 9
I get this output:
2 10 5
-7 8 9
rows = 2, cols = 3

However, if a space follows the 5 on the 1st line, the '\n' gets missed and I get:
2 10 5 -7 8 9
rows = 1, cols = 6

so this method is a bit sensitive to file formatting.
A more bulletproof method probably involves using a stringstream to stream the 1st row entries and count the values.

edit: code clarity
Last edited on
>> MilkeyBoy : I am having issues getting the number of columns/ need directions to get the number of columns...

>> fun2code : Thanks mate, your code works exactly to my needs! However can I ask if there is a need for ofstream fout and fin.close() or fout.close()? I asked because I derived them from http://www.cplusplus.com/doc/tutorial/files/ as part of my reference
closed account (D80DSL3A)
Hi. No need to call open() or close(). The file will be opened (or not) where declared.
The file will be closed automatically (by fin destructor) when fin goes out of scope at function end.

In the event the file fails to open I think the while loops are safe (iteration will just fail to occur at all in both cases), but I do see a disaster at line 20 where cols would still = 0.
Correcting for this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void readFile()
{
    std::ifstream fin("arrData.txt");
    int val=0, rows=0, cols=0, numItems=0;

    while( fin.peek() != '\n' && fin >> val )
    {
        cout << val << ' ';
        ++numItems;
    }
    cols = numItems;// # of columns found

    cout << '\n';
    while( fin >> val )
    {
        ++numItems;
        cout << val << ' ';
        if( numItems%cols == 0 ) cout << '\n';
    }

    if( numItems > 0 )// got data!
    {
        rows = numItems/cols;
        cout << "rows = " << rows << ", cols = " << cols << '\n';
    }
    else// didn't get any data
        cout << "data reading failed\n";
}

Thank you!
Thanks mate! It works! :D

I have another question though, I apologize if it is off topic, while using your code, I am trying to get use the number of rows and columns found to allocate them into a 1-d array.

So instead of seeing my output for column 1 as -5, column 2 as 18 and column 3 as 14, I am getting werid values such as -13582, 38679, 5255432

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int arr[rows * cols];
 
    // read each value into the array
    for(int i = 0; i < rows; i++)
    {
        for(int j = 0; j < cols; j++)
        {
            fin >> arr[i * cols + j];
        }
    }
 
    int sum = 0;
    for(int j = 0; j < cols; j++)
    {
        for(int i = 0; i < rows; i++)
        {
            sum += arr[i * cols + j];
        }
        cout << "Sum for column " << j << " = " << sum << endl;
    }


Any ideas?
Last edited on
closed account (D80DSL3A)
I assume you're reading from the file a 2nd time. Have you checked if data is being extracted as expected? Use debugger or a cout statement after line 8 to find out.
Or, assign fixed values instead, eg. arr[i * cols + j] = i * cols + j;

I'm guessing the problem is with the declaration of arr on line 1.
An array declared at compile time (like arr here) must have the # of elements known. rows and cols can't be variables with values determined at run time.
Suggest you use std::vector<int> arr(rows*cols); instead.
While using a cout at line 8, I got the weird values all over again. However, when I did using the fixed values as you mentioned, it works.

And there I thought by using the integer values I got from rows and cols, and then int arr[rows*cols] equates as giving the number of elements to the array..

Can I also check with you by writing arr[i * cols + j] = i * cols + j;, this means that the array arr will be set to the size as determined by i * cols + j?
closed account (D80DSL3A)
Here's some complete code for all this.
It's hard to troubleshoot your code by just seeing fragments. Was that last code in the readFile() function? Did you rewind the input file to beginning?

There are 2 readFile() functions. The new one allocates memory for an array, copies values to that array from the file and returns a pointer + dimensions to main().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <iostream>
#include <fstream>
using std::cout;

void readFile();// just looking
int* readFile( const char* fname, int& rows, int& cols );// copies file data to array
void print( int* A, int rows, int cols );
void showColSums( int* A, int rows, int cols );

int main()
{
   int Arows=0, Acols=0;
   int* A = readFile( "arrData.txt", Arows, Acols );

   if( A )
   {
       print( A, Arows, Acols );
       showColSums( A, Arows, Acols );
        // cleanup
       delete [] A;
   }
   else cout << "Could not get array data\n";

    return 0;
}

// definitions
void readFile()// just looking
{
    std::ifstream fin("arrData.txt");
    int val=0, rows=0, cols=0, numItems=0;

    while( fin.peek() != '\n' && fin >> val )
    {
        cout << val << ' ';
        ++numItems;
    }
    cols = numItems;// # of columns found

    cout << '\n';
    while( fin >> val )
    {
        ++numItems;
        cout << val << ' ';
        if( numItems%cols == 0 ) cout << '\n';
    }
    rows = numItems/cols;
    cout << "rows = " << rows << ", cols = " << cols << '\n';
}

// copies file data to array
int* readFile( const char* fname, int& rows, int& cols )// copies file data to array
{
    std::ifstream fin( fname );
    int val=0, numItems=0;

    while( fin.peek() != '\n' && fin >> val ) ++numItems;
    cols = numItems;// # of columns found
    while( fin >> val ) ++numItems;// keep counting

    // got data!
    if( numItems > 0 )
    {
        rows = numItems/cols;
        int *A = new int[rows*cols];
        fin.close();
        fin.open( fname );
    //    fin.seekg( 0, fin.beg );// I can't get the "right way" to work
        int i=0;
        while( i < numItems && fin >> A[i] )++i;
        return A;
    }
    else// didn't get any data
        cout << "data reading failed\n";

    return nullptr;
}

void print( int* A, int rows, int cols )
{
    if( !A ) return;
    for( int r=0; r<rows; ++r )
   {
        cout << '\n';
        for( int c=0; c<cols; ++c )
            cout << A[r*cols + c] << ' ';
   }
   cout << '\n';
}

void showColSums( int* A, int rows, int cols )
{
    if( !A ) return;

    cout << "column sums\n";
    for( int c=0; c<cols; ++c )
   {
        int colSum = 0;
        for( int r=0; r<rows; ++r )
            colSum += A[r*cols + c];
        cout << colSum << ' ';
   }
   cout << '\n';
}
closed account (D80DSL3A)
I felt bad about promoting such hackish methods in that last code.
Here's a version which uses std::vector for the dynamically sized array, and a std::stringstream object for parsing the 1st line of the file reliably. eg, a space may now follow the last number in a line and we get the same result.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>

using std::cout;
using std::vector;


void readFile( const char* fname );// just looking
bool readFile( const char* fname, vector<int>& A, int& rows, int& cols );// copies file data to array
void print( const vector<int>& A, int cols );
void showColSums( const vector<int>& A, int cols );

int main()
{
   int Arows=0, Acols=0;
   vector<int> A;

   readFile("arrData.txt");

   if( readFile( "arrData.txt", A, Arows, Acols ) )
   {
       print( A, Acols );
       showColSums( A, Acols );
   }
   else cout << "Could not get array data\n";

    return 0;
}

void readFile( const char* fname )// just looking
{
    std::ifstream fin( fname );
    int val=0, rows=0, cols=0, numItems=0;

    std::stringstream ss;
    std::string temp;
    getline( fin, temp );
    ss << temp;

    while( ss >> val )
    {
        cout << val << ' ';
        ++numItems;
    }
    cols = numItems;// # of columns found

    cout << '\n';
    while( fin >> val )
    {
        ++numItems;
        cout << val << ' ';
        if( numItems%cols == 0 ) cout << '\n';
    }
    rows = numItems/cols;
    cout << "rows = " << rows << ", cols = " << cols << '\n';
}

// copies file data to vector
bool readFile( const char* fname, vector<int>& A, int& rows, int& cols )// copies file data to array
{
    std::ifstream fin( fname );
    int val=0, numItems=0;
    A.clear();

    std::stringstream ss;
    std::string temp;
    getline( fin, temp );
    ss << temp;

    while( ss >> val ){ ++numItems; A.push_back(val); }
    cols = numItems;// # of columns found
    while( fin >> val ){ ++numItems; A.push_back(val); }// keep counting

    // got data!
    if( A.size() > 0 )
    {
        rows = numItems/cols;
        return true;
    }
    else// didn't get any data
        cout << "data reading failed\n";

    return false;
}

void print( const vector<int>& A, int cols )
{
    if( A.size() < (unsigned int)cols ) return;
    cout << '\n';
    for( size_t i=0; i<A.size(); ++i )
   {
            cout << A[i] << ' ';
            if( (i+1)%cols == 0 ) cout << '\n';
   }
   cout << '\n';
}

void showColSums( const vector<int>& A, int cols )
{
    if( A.size() < (unsigned int)cols ) return;

    cout << "column sums\n";
    int rows = A.size()/cols;
    for( int c=0; c<cols; ++c )
   {
        int colSum = 0;
        for( int r=0; r<rows; ++r )
            colSum += A[r*cols + c];
        cout << colSum << ' ';
   }
   cout << '\n';
}

edit: better code.
Last edited on
I will try out your code and digest the info. But in the end, I ended up using that hackish code that you did previously..

Nevertheless thanks again for your help and the code. Greatly appreciate it :)
Hi there, I am trying to do similar but upon using the code, it seems that it is unable to take in decimal numbers.

Regardless of the index/place that the decimal number is in, it will return as 1 row and 1 column.
closed account (D80DSL3A)
@salik89. You're welcome. Glad it worked for you.

@zacdare I would expect the code to fail if any decimal numbers are encountered. Data is streaming into a variable of type int: int val=0;.
Try changing the type of val to double in whatever version of readFile() you're trying to use.
Last edited on
Ah.. Okay.
Upon changing from int to float, the program run perfectly as long as the file input contains any decimal number.

Interestingly, while using the same code and still using the float, this time round, I am getting output such as -1.70457e+33 if my file inputs, both do not contains any decimal numbers. (I am doing some matrix multiplication)
Topic archived. No new replies allowed.