1

I'm trying to read a CSV file with entries like this:

//2009-12-31 21:00:00, COUNTRY ,1.84296,350.947,60.72

This is what I did

#include <iostream>
#include <fstream>
#include <sstream>

int main()
{
    using namespace std;
    ifstream read("data.csv");

    string line;

    //I want to use this to hold the data temporarily
    string temp[5];

    while (std::getline(read, line))
    {
        int i=0;
        std::istringstream iss(line); // string stream
        while(std::getline(iss, temp[i], ','))
        {
            cout << i << ": " << temp[i] << endl;
            ++i;
        };
    }
}

But it didn't do what I wanted the code to do. In particular, the code stopped after the integer i hit 21. Here's the output

0: 2009-12-31 21:00:00
1: GRID_A
2: 1.84296
3: 350.947
4: 60.72
2010-01-01 00:00:00
5: GRID_A
6: 1.93569
7: 348.98
8: 60.64
2010-01-01 03:00:00
9: GRID_A
10: 2.30688
11: 339.444
12: 247.6
2010-01-01 06:00:00
13: GRID_A
14: 1.74453
15: 326.219
16: 587.92
2010-01-01 09:00:00
17: GRID_A
18: 2.16002
19: 289.19
20: 180.72
2010-01-01 12:00:00
21: GRID_A

Then I got an error like this

_LIBCPP_INLINE_VISIBILITY
    static void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT
        {__c1 = __c2;}
Thread 1: EXC_BAD_ACCESS...

Can you please tell me what's wrong? Many thanks!

PS: It turns out that the problem had to do with the CSV file that I saved using Excel on my Mac. The newline character was missing.

Dinosaur
  • 645
  • 4
  • 10
  • 14

1 Answers1

2

Your code works if there are only 5 columns in each line. If i is greaten than 4 you will get problems. As you said your i is 21! Your array can't take this much elements. You should leave the loop at the end if i is outside your array range.

You try to access temp[21] which is somewhere beyond the rainbow. No wonder you get BAD ACCESS.

Just use temp as a single string. No need for an array if you only want to output the value. Just use string temp; and remove [i] down there.

Robert S.
  • 1,942
  • 16
  • 22
  • Thanks, what I wanted to do was to use temp[5] to hold the five elements in each line. I didn't expect the integer i to go beyond 4. – Dinosaur May 20 '15 at 14:52
  • If your csv file contains a line with more commas this will happen. – Robert S. May 20 '15 at 14:53
  • The lines in my CSV file look like this: 2009-12-31 21:00:00,GRID_A,1.84296,350.947,60.72 – Dinosaur May 20 '15 at 14:54
  • Maybe your `std::getline(read, line)` extracts one single line? Can you test this by outputting `line` before `int i ...`? Maybe your line endings of your CSV file are not compatible to the default line delimiter of `std::getline`. – Robert S. May 20 '15 at 14:58
  • Thanks! However, if I remove the [i], I would be reading the whole line into temp, which isn't what I wanted. I need to have each attribute put into temp[i] for i=0,1,2,...,4 for practical reasons. Can you tell me how I can achieve that? – Dinosaur May 20 '15 at 14:59
  • First try out my last comment. I guess the first `std::getline` is your problem, considering your output. It seems your variable `line` contains the whole file content instead of a single line. – Robert S. May 20 '15 at 15:00
  • @Dinosaur Are you **sure** the lines are separated by newline? It looks like you're reading just a looooong line. Did you use a Windows file into a Unix environment or the other way around? The code itself is perfectly fine otherwise. – vsoftco May 20 '15 at 15:01
  • @vsoftco. I'm on a mac. The file I'm reading is just an ordinary CSV file. If I take the more tedious route like read >> temp[0] >> read.get() >> temp[1].... then the program has no problem going from one line to another. – Dinosaur May 20 '15 at 15:04
  • @Dinosaur try opening your file in a text editor. The lines should be separated. If not, then you have a problem, since you read only one long line as the whole file, and you should change the code accordingly. AFAIK, CSV uses a line separator for each record. If you read only one line, and you know your records contain 5 fields, then you can simply do `temp[i % 5]` so `i` stays in the range `[0..5)` – vsoftco May 20 '15 at 15:05
  • @vsoftco. I opened it using TexEdit (plain text editor) and the file wasn't a long line. Any thoughts? – Dinosaur May 20 '15 at 15:06
  • This might help you: http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf See accepted answer there. I guess your problem are the line endings. `std::getline` uses the delimiter that matches your OS default line ending. But if you exchange files from OS to another (e.g. from Windows to Mac) this might be a problem. – Robert S. May 20 '15 at 15:07
  • @Dinosaur as Robert said, your file was probably written by Windows. Convert it to UNIX format, http://stackoverflow.com/questions/6373888/converting-newline-formatting-from-mac-to-windows – vsoftco May 20 '15 at 15:09
  • @Dinosaur also try `wc -l data.csv` in a terminal to see exactly how many lines you have. My guess is that your text editor wrap the lines around and you falsely believe there are multiple lines. – vsoftco May 20 '15 at 15:29
  • @vsoftco. Wow, you got it! Upon adding some *'s to show the end of line I realized the line in the file was horrendously long. Many thanks for providing the solution. – Dinosaur May 21 '15 at 01:55