Debug Assertion Failed! String subscript out of range

Hello, I'm trying to read a file and store information into struct array. Now, I've done this before, and even this code works great on Code::Blocks, but I get this error when trying to test on Visual Studio 2010.

 
Debug assertion failed! string subscript out of range.


Again, all this code is good, and proven to work on code blocks, I just can't figure out why VS2010 is not letting me run it.

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  #include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

/*
*   Definition of Patient structure
*/
struct patient
{
    string date;
    string name;
    string ic;
    string type;
    string therapist;
    int charge;
};

//so we don't have to write 'struct patient' every time, this way
//we can only write 'Patient'
typedef struct patient Patient;

/*
*    Functions we'll use
*/
Patient* parse_file(string, int*);
Patient parse_line(string);
Patient* expand_array(Patient*, int*);
void print_patient(Patient&);

int main()
{
    Patient* patients;
    int numPatients = 0;

    //read patients from file
    patients = parse_file("input.txt", &numPatients);

    for(int i = 0; i < numPatients; i++)
        print_patient(patients[i]);

    //free memory allocated for patients
    delete[] patients;

	system("pause");

    return 0;
}

/*
*   input: filename to be opened, pointer to integer
*   output: array of Patients read from file
*   summary: this function reads data from file and saves it into structure array
*/
Patient* parse_file(string filename, int* num)
{
    //declare patients array
    Patient* ret = new Patient[10];

    string line;
    *num = 0;  //at first total number of patients is zero

    ifstream input(filename.c_str(), ios::in);

    if(!input.is_open())
    {
        cout << "Couldn't open file. Exiting..." << endl;
        return NULL;
    }

    //waste first two lines
    getline(input, line);
    getline(input, line);

    while(getline(input, line))
    {
        ret[*num] = parse_line(line);

        *num += 1;

        if(*num % 10 == 0)
        {
            ret = expand_array(ret, num);
        }

        line.clear();
    }

    input.close();
    return ret;
}

Patient parse_line(string line)
{
    Patient ret;
    int phase = 0;

    istringstream iss(line);
    string token;
    while (getline(iss, token, '\t'))
    {
        if(token[0] != 0)
        {
            //std::cout << token << std::endl;

            switch(phase)
            {
            case 0:
                ret.date = token;
                break;
            case 1:
                ret.name = token;
                break;
            case 2:
                ret.ic = token;
                break;
            case 3:
                ret.type = token;
                break;
            case 4:
                ret.therapist = token;
                break;
            case 5:
                istringstream(token) >> ret.charge;
                break;
            }

            phase++;
        }
    }

    return ret;
}

Patient* expand_array(Patient* smaller, int* s)
{
    Patient* ret = new Patient[*s + 10];

    for(int i = 0; i < *s; i++)
        ret[i] = smaller[i];

    delete[] smaller;

    return ret;
}
Visual Studio (in debug mode) will give you an error on line 104 if token is empty. This line of code should work fine since C++11 but VS2010 has not been updated to allow the use of indices equal to the size of the string (not sure about later versions).

If you want to check if the string is empty you could use the empty() function instead.
http://www.cplusplus.com/reference/string/string/empty/
Correct. I added
 
  if(!token.empty())

Before that 'if' and right after 'while'. And it works great now. Thanks a lot!
Also it looks to me like you have a possible memory leak in your expand_array() function. You've passed the pointer by value into the function, therefore the function is operating on a copy of the pointer.
Also it looks to me like you have a possible memory leak in your expand_array() function. You've passed the pointer by value into the function, therefore the function is operating on a copy of the pointer.


Since the function does not modify the pointer passed in and returns the newly expanded array, this seems like a baseless concern.
Except that the OP overwrites the memory location with that return value.

1
2
3
        if(*num % 10 == 0)
        {
            ret = expand_array(ret, num);
Except that the OP overwrites the memory location with that return value.

... which is exactly what should happen.
which is exactly what should happen.

But because the memory was never deleted you create a memory leak of the previous allocated block. You need to delete the memory before you reassign that pointer.
But because the memory was never deleted you create a memory leak of the previous allocated block.

The old array is deleted inside expand_array, on line 144.

 
delete[] smaller;
But because the memory was never deleted you create a memory leak of the previous allocated block. You need to delete the memory before you reassign that pointer.


137
138
139
140
141
142
143
144
145
146
147
Patient* expand_array(Patient* smaller, int* s)
{
    Patient* ret = new Patient[*s + 10];

    for(int i = 0; i < *s; i++)
        ret[i] = smaller[i];

    delete[] smaller;   // <----

    return ret;
}


What does line 144 do exactly?

Topic archived. No new replies allowed.