-2

I'm fairly new to C++ and coding in general, and I'm using Visual Studio 2013 Desktop to write a simple program to collect and perform some operations on data from a .CSV file. The program seems to compile and run fine, and asks me to type in a name for the file to be opened. Just like I intended, if I type an invalid file name, the program will display an error message and terminate, however if I enter the correct name I get a message that says

"Unhandled exception at 0x0F16A9E8 (msvcr120d.dll) in TestIO.exe: 0xC0000005: Access violation reading location 0xCCCCCCC0."

With the options to Break or Continue. If I press Continue, it displays the same message again, and goes on infinitely until I press "Break" and stop the debugging. I have absolutely no idea what's going on here, can anyone shed some light on this? It would be much appreciated.

Edit: Here is my main(). Hope this helps more, sorry for not including it before.

int main()
{
    int numDays = 0, streams;
    string* date;
    string line, filename;
    DailyData* days;
    cout << "Enter file name: ";
    getline(cin, filename);
    ifstream infile;
    infile.open(filename); 
    if (infile.fail())
    {
        cout << "Error opening input file" << endl;
        return 0;
    }
    while (getline(infile, line))
        numDays++;
    date = new string[numDays];
    for (int i = 0; i < numDays; i++)
        getline(infile, date[i]);
    days = new DailyData[numDays];
    for (int i = 0; i < numDays; i++)
    {
        getData(date[i], streams);
        days[i] = DailyData(date[i], streams);
    }
    cout << "Max Streams: " << maxStreams(days, numDays) << endl;
    cout << "Min Streams: " << minStreams(days, numDays) << endl;
    cout << "Avg Streams: " << average(days, numDays) << endl;
    cout << "Tot Streams: " << total(days, numDays) << endl;
    delete[] days;
    delete[] date;
    infile.close();
    return 0;
}

Edit 2: Here is some of the stuff you guys asked for

void getData(string& d, int& s)
{
    int start = 0, end = 0, i = 0;
    string p[14];
    while (start != string::npos)
    {
        end = d.find(",", start); 
        p[i] = d.substr(start, end - start);
        start = end + 1;
        i++;
    }
    d = p[0];
    s = atoi(p[5].c_str());
}

And here is DailyData with it's constructors

class DailyData
{
    public:
    DailyData() :date("NULL"), streams(0){}
    DailyData(string d, int s) :date(d), streams(s){}
    string getDate(){ return date; }
    int getStreams(){ return streams; }
    friend ostream& operator << (ostream&, DailyData&);
    private:
        string date;
        int streams;
};

Edit 3: I changed my code to use vectors instead of arrays. Along with changing int main(), I made sure to change the arguments in all the function definitions/declarations. I'm still getting the same Unhandled Exception error I originally got. Here's the new code snippet:

vector<string> date;
vector<DailyData> days;

//...

while (getline(infile, line))
{
    date.push_back(line);
    getData(date.back(), streams);
    days.push_back(DailyData(date.back(), streams));
}
numDays = days.size();
  • 4
    You would do well to include some relevant code in your question... – Sinkingpoint May 25 '14 at 23:55
  • Without a snippet we can only guess at where your code is failing, but usually an Access Violation occurs when you read from uninitialized memory. – Matt Coubrough May 26 '14 at 00:17
  • What part of the code should I include in this post? Also, if the code is failing, why does it compile? – ChilledGrease May 26 '14 at 01:11
  • 1
    It compiles because this is a run-time error, I.E. something that couldn't be determined by static analysis (such as trying to index past the end of an array via a runtime determined value). – aruisdante May 26 '14 at 01:20
  • I don't see anything that particularly jumps out at me as being wrong (although your use of ``new`` and arrays is bad practice, you should use ``vector``), so it may be helpful to put some print statements so you can narrow down what line exactly is failing. You should also, by convention, return a value of not zero when the application exits in an error state. – aruisdante May 26 '14 at 01:24
  • Nothing gets printed to the console though, as soon as I type in the name of the file and press enter, I get the error message I described above. – ChilledGrease May 26 '14 at 01:27
  • Show the code for `getData` and `DailyData` default constructor and copy-constructor (and any functions they call) – M.M May 26 '14 at 02:20
  • @Matt McNabb I included what you asked for in a second edit. – ChilledGrease May 26 '14 at 03:16
  • Looks like the problem is in the code in getData(), can you step through it with your debugger checking the values as you go? If not, please learn how to use the debugger. You cannot write code without using it. – Matt Coubrough May 26 '14 at 03:53
  • You need checks in your code to ensure that i never exceeds 13 and p[5] is valid before calling c_str(). Failure to do this is asking for Access Violations. – Matt Coubrough May 26 '14 at 03:57
  • Up to this point, the only coding I've done is for a C++ course at my university using GCC in linux, so I've never dealt with a debugger before. Do you know any resources to get me started? It's starting to seem like they didn't teach us any of the right stuff. – ChilledGrease May 26 '14 at 04:00
  • I've added a few more tips to my answer, but other than firing up my debugger and running your source with the same inputs, I don't think I can help much more. It's specific to what you're trying to accomplish and of little value to other users of StackOverflow I'm afraid. – Matt Coubrough May 26 '14 at 04:29
  • "if the code is failing, why does it compile?" -- That's a bit like asking why, if someone died of a heart attack, they looked healthy. – Jim Balter Jun 04 '14 at 13:41

1 Answers1

2

It appears your code is calling getline on the inputfile after you've already read to the end of the file

while (getline(infile, line))
    numDays++;

// above reads every line in the file,
// then you call this, even though while(getline) has returned false:

for (int i = 0; i < numDays; i++)
    getline(infile, date[i]);

If you're new to programming always use curly braces to show the body of a loop so you can see where the loop block execution begins and ends.

Also, in practice, its best to learn to use a debugger. It will be the most valuable thing you ever do as a programmer.

Edit:

here's how you could use a dynamically resizable vector instead of a fixed size array:

std::vector<string> dates;

//...

while( getline(infile, line) )
{
    dates.push_back(line);
}

If you need more info, search for C++ vector.

Edit2:

Now that the code to getData has been posted I think the problem is in there. For a start this code:

while (start != string::npos)
{
    end = d.find(",", start); 
    p[i] = d.substr(start, end - start);
    start = end + 1;
    i++;
}

looks very dangerous.

p[i] = d.substr(start, end - start); 

will result in weird behaviour if end == string::npos which will occur whenever d.find does not find a comma.

similarly start = end + 1 will not do what you expect if end == string::npos

further p[i] = ... will only work for values of i less than 13. I see no checks to guarantee this.

My first suggestion would be to check if end == string::npos and only perform other the operations if it isn't.

Hope that helps, the behaviour of this code depends heavily on what your input data looks like, which is why its best to use a debugger.

Matt Coubrough
  • 3,739
  • 2
  • 26
  • 40
  • What's the best way to fix this? Should I put the while loop in a separate function that returns the number of lines? – ChilledGrease May 26 '14 at 01:51
  • @ChilledGrease Is there any reason you need to know the number of lines apriori? Could you not do all your processing as you iterate across the file? Presuming of course you switch your containers to ``vectors`` instead of bare ``arrays``. – aruisdante May 26 '14 at 01:54
  • I have never used vectors before, I will look up how to do that. Thanks for your help! – ChilledGrease May 26 '14 at 01:55
  • Well, the best way would probably to use a dynamically resizable data structure such as a vector instead of an array. The simplest thing to do would be to reset the file pointer back to the beginning of the file using infile.clear(); and infile.seekg(0, std::ios::beg); – Matt Coubrough May 26 '14 at 01:58
  • I've edited my answer to provide you with a minimal vector example – Matt Coubrough May 26 '14 at 02:04
  • While this is true, it wouldn't cause an access violation. The later getlines would just fail, leaving `date[i]` being an empty string. Perhaps `getData()` or `DailyData()` cause undefined behaviour when called on an empty string; OP didn't show the code for those. – M.M May 26 '14 at 02:19
  • I wonder how robust the DailyData constructor when an empty string is passed in? – Matt Coubrough May 26 '14 at 02:21
  • @MattCoubrough I edited the code to use vectors and I'm getting the same runtime error I originally got. The edit is posted above along with the getData() definition and the DailyData class. – ChilledGrease May 26 '14 at 03:43