Reading csv into 2d arrays properly

I've been looking into many I/O questions I have, and one in particular is how to read values in from a txt or csv file to alter 2d array values. I've already mastered how to output values to the csv or txt file, now I need to do the reverse. In perusing, I came across similar topics and older threads and managed to get a halfway working program together. My test input file involves 8 fields and looks like this:
1,2,3,4
5,6,7,8

The code I've developed is mostly taken from the previously mentioned threads, although it has been altered a bit. I've also added a portion that confirms if the array now holds the correct values, and this is where I hit a snag.
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
  #include <iostream>
#include <fstream>
#include <sstream>
#include<string>
#include <iomanip>
using namespace std;
int main()
{
    int array[3][4]={};
    ifstream file("test (2).csv");

    for(int row = 0; row < 3; ++row)
    {
        string line;
        getline(file, line);
        if ( !file.good() )
            break;

        stringstream iss(line);

        for (int col = 0; col < 4; ++col)
        {
            string val;
            getline(iss, val, ',');
            if ( !iss.good() )
                break;
            stringstream convertor(val);
            convertor >> array[row][col];
        }
    }

    //check array values
    for (int y=0; y<3; y++)
    {
        for (int x=0; x<4; x++)
        {
            cout<<array[y][x];
            if (x!=3)//add commas when not at end of row
                cout<<", ";
        }
        cout<<endl;
    }
}

1, 2, 3, 0
0, 0, 0, 0
0, 0, 0, 0

Where is the rest of my array? Playing with the values within the loops has not seemed to impact this, and only the last line should be zeroes. It may be something simple, but I'm having difficulty pinpointing it. In this case, simply working with integer values and confirming correct output would be acceptable, as I can reason out how to work with floats, or expand the size of the array from there.
Last edited on
Does your file end with a new line? If it doesn't, I think line 16 will end the loop. Similar problems for line 25.

Checking if something is "good" can be problematic, check out getline:
http://www.cplusplus.com/reference/string/string/getline/

Reading to the end of the stream will trigger the eof flag, which will cause good() to return false.
Honestly, I had taken that code from another thread and didn't entirely understand how it operated. A bit further experimentation confirms that you are correct, it is breaking out of the loop after parsing the first three values. I've also confirmed that it is grabbing the fourth value, but apparently not applying it.

Oddly, adding a newline character to the end of the first row solves everything, but I can't understand why. Shouldn't the same issue apply on the second or third row?
My newly edited input file:
1,2,3,4,\n
5,6,7,8
9,10,11,12

My actual output after editing:
1, 2, 3, 4
5, 6, 7, 8
9, 10, 11, 12

If possible, I'd like a way to address this issue that does not require garbage characters within the input file.

EDIT: Apparently putting anything, whether a numeric value, a symbol, or newline character following the 4th field (4) in the first row solves the problem. The question is why?

Also, while it typically would not be a big deal to include an additional unused numerical value (or symbol) within an input file, the way I intend to use this is to have the file created by another program. I suppose that program could add garbage to the end of the first row to solve the problem, but shouldn't there be a better and more practical solution?

I would much rather have it parse a row until it comes to a blank value, before going to the next line, and have it terminate upon reaching a line that begins with a blank value. Is there any simple way to accomplish this?
Last edited on
You should end every file that you make with a new line character. Many programs do this by default, and I image the editor you are using has this option. It's just a thing, text files should end with a new line.

( You don't add \n to your file, just hit enter ).

For your edit, I'm not getting the same results as you. All of my lines have to end in junk to get the last number printed.
1
2
3
getline(iss, val, ',');
if ( !iss.good() )
   break;


The getline says "read the contents of iss into val until a comma or the end of the stream is found. If you do find a comma, remove it from the stream."
So, for the last number in the stream "1,2,3,4", you don't find a comma, you read to the end of the stream. This will trigger the eof bit on the stream, which makes good() return false. Thus, your loop breaks even though it was successful at reading a number.

Same thing when you don't have a newline at the end of your file. You set the EOF bit, instead of stopping at the last newline.

I suppose that program could add garbage to the end of the first row, but shouldn't there be a better answer?

You don't want your other program to output junk, but it should output a newline at the end of the file.

The quickest thing to do is to remove the good() clause, so you have this:
 
if ( !iss ) break;


Streams can be converted to bool, in which case they check against the fail bit rather than the eof bit. Trying to extract from a stream that is at EOF does trigger the fail bit though.
Last edited on
Thanks alot, LowestOne. That quick change to if (!iss) break; on line 25 did the trick, and it now works properly when only including the values intended for the array. This clears up many of the problems and much of the confusion I was experiencing, and your explanation of how the code works helped as well. I see now that adding an additional field after the four element resulted in another comma, which allowed it to apply the fourth character to the array. It IS strange that we had differing results on the subsequent lines, but the logic seems solid now for that first line, and I suppose differences in OS's or compilers could account for it.

There may be some other handy things I can do with input files like this, and over the break I'll take the time to experiment further.

Last edited on
Topic archived. No new replies allowed.