Program crashes at substr (positions are in range, using string)

Hi, could someone tell me why this program crashes every time when it goes to substr()?

The crashing part is at line 70, it is really pissing me off. I've printed everything related to the substr, and they are all properly in place

Input:
1
2
3
4
5
6
7
2
World Cup
2
Brazil
Norway
1
BrazilH2H1HNorway


Output:
1
2
3
4
5
6
7
8
9
10
11
12
checkpoint1
B
r
a
z
i
l
HERE
BrazilH2H1HNorway
begCursor, subLength: 0,6
B r a z i l 
//crash 



crashing part:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
            getline(cin, workingString);
            if (workingString=="") getline(cin, workingString);
            endCursor=workingString.length();
            cout << "checkpoint1" << endl; 
            while (workingString[curCursor]!='H') {
                cout << workingString[curCursor] << endl; // recognize H as stopping point
                curCursor++;
                subLength++;
            }
            cout << "HERE" << endl;
            cout << workingString << endl; //checks if workingString was entered properly
            cout << "begCursor, subLength: " << begCursor << ", " << subLength << endl;
            for (int loopPrint=begCursor; loopPrint<begCursor+subLength; loopPrint++) {
                cout << workingString[loopPrint] << " ";   //prints each of the characters to be involved in the substring
            }
            workingSub=workingString.substr(begCursor,subLength); //crashes 


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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <sstream>
#include <string>

using namespace std;

struct team{
string name, lowerName;
int numPts=0, gPlayed=0, gWon=0, gTied=0, gLost=0, goScored=0, goAgainst=0;
int gDiff() {
return goScored-goAgainst;
}};

bool lastToFirst(team team1, team team2) {
if (team1.numPts<team2.numPts) return true;
else if (team1.numPts>team2.numPts) return false;
else {
    if (team1.gWon<team2.gWon) return true;
    else if (team1.gWon>team2.gWon) return false;
    else {
        if (team1.gDiff()<team2.gDiff()) return true;
        else if (team1.gDiff()>team2.gDiff())return false;
        else {
            if (team1.goScored<team2.goScored) return true;
            else if (team1.goScored>team2.goScored) return false;
            else {
                if (team1.gPlayed>team2.gPlayed) return true;
                else if (team1.gPlayed<team2.gPlayed) return false;
                else {
                    return (team1.lowerName<team2.lowerName);
                }
            }
        }
    }
}}

map <string, int> locTeam;
vector<team> allInfo;
int numTournaments, numTeams, numGames, curTeam1 , curTeam2, subLength, subBeg;
int begCursor, curCursor, endCursor, goal1, goal2;
string teamName, tourName, workingString, workingSub;
team input={};

int main()
{
    cin >> numTournaments;
    for (int loop=0; loop<numTournaments; loop++) {
        teamName=""; tourName=""; workingString=""; workingSub="";
        allInfo.clear();
        getline(cin, tourName, '\n');
        if (tourName=="") getline(cin, tourName, '\n');
        cin >> numTeams;
        string aa="abc";
        for (int inputT=0; inputT<numTeams; inputT++) {
            workingString="";
            getline(cin, teamName, '\n');
            if (teamName=="") getline(cin, teamName, '\n');
            input.name=teamName;
            transform(teamName.begin(), teamName.end(), workingString.begin(),::tolower);
            input.lowerName=workingString;
            allInfo.push_back(input);
            locTeam[teamName]= inputT;
        }
        cin >> numGames;
        cin.ignore();
        for (int loopp=0; loopp<numGames; loopp++) {
            workingString=""; workingSub=""; subBeg=0; subLength=0; curCursor=0; begCursor=0;
            getline(cin, workingString);
            if (workingString=="") getline(cin, workingString);
            endCursor=workingString.length();
            cout << "checkpoint1" << endl;
            while (workingString[curCursor]!='H') {
                cout << workingString[curCursor] << endl;
                curCursor++;
                subLength++;
            }
            cout << "HERE" << endl;
            cout << workingString << endl;
            cout << "begCursor, subLength: " << begCursor << ", " << subLength << endl;
            for (int loopPrint=begCursor; loopPrint<begCursor+subLength; loopPrint++) {
                cout << workingString[loopPrint] << " ";
            }
            workingSub=workingString.substr(begCursor,subLength);

            cout << workingSub << "chkpoint3" <<endl;
            curTeam1=locTeam[workingSub];
            begCursor=curCursor+1;
            curCursor++;
            subLength=0;
            while (workingString[curCursor]!='H') {
                curCursor++;
                subLength++;
            }
            cout << "b" << endl;
            workingSub=workingString.substr(begCursor,subLength);
            stringstream ss(workingSub);
            ss>>goal1;
            begCursor=curCursor+1;
            curCursor++;
            subLength=0;
            while (workingString[curCursor]!='H') {
                curCursor++;
                subLength++;
            }
            cout << "c" << endl;
            workingSub=workingString.substr(begCursor,subLength);
            stringstream sss(workingSub);
            ss>>goal2;
            begCursor=curCursor+1;
            curCursor++;
            subLength=0;
            while (curCursor<endCursor-1) {
                curCursor++;
                subLength++;
            }
            cout << "d" << endl;
            workingSub=workingString.substr(begCursor,subLength);
            curTeam2=locTeam[workingSub];
            allInfo[curTeam1].goScored+=goal1;
            allInfo[curTeam2].goScored+=goal2;
            allInfo[curTeam1].goAgainst+=goal2;
            allInfo[curTeam2].goAgainst+=goal1;
            if (goal1>goal2) {
                allInfo[curTeam1].gWon+=1;
                allInfo[curTeam1].gPlayed+=1;
                allInfo[curTeam1].numPts+=3;
                allInfo[curTeam2].gLost+=1;
                allInfo[curTeam2].gPlayed+=1;
            }
            else if (goal1==goal2) {
                allInfo[curTeam1].gTied+=1;
                allInfo[curTeam1].numPts+=1;
                allInfo[curTeam1].gPlayed+=1;
                allInfo[curTeam2].gTied+=1;
                allInfo[curTeam2].numPts+=1;
                allInfo[curTeam2].gPlayed+=1;
            }
            else {
                allInfo[curTeam2].gWon+=1;
                allInfo[curTeam2].numPts+=3;
                allInfo[curTeam2].gPlayed+=1;
                allInfo[curTeam1].gLost+=1;
                allInfo[curTeam1].gPlayed+=1;
            }
        }
        sort(allInfo.begin(),allInfo.end(), lastToFirst);
        cout << tourName << '\n';
        for (int loopOut=0; loopOut<numTeams; loopOut++) {
            cout <<loopOut+1<<") "<<allInfo[numTeams-loopOut-1].name<<" "<<
            allInfo[numTeams-loopOut-1].numPts<<"p, "<<allInfo[numTeams-loopOut-1].gPlayed<<
            " ("<<allInfo[numTeams-loopOut-1].gWon<<"-"<<allInfo[numTeams-loopOut-1].gTied<<"-"<<
            allInfo[numTeams-loopOut-1].gLost<<"), "<<allInfo[numTeams-loopOut-1].gDiff()<<"gd ("<<
            allInfo[numTeams-loopOut-1].goScored<<"-"<<allInfo[numTeams-loopOut-1].goAgainst<<")\n";
        }
        cout << "\n";

    }

    return 0;
}
Last edited on
Didn't read the code;

substr() will throw if you try to index characters beyond the ends of the string. Figure out how you are doing that and fix it.

Hope this helps.
Update:
It now throws SIGTRAP at line 71 when I use getline
Any reason?
An unexplained SIGTRAP very often indicates that there was some (earlier) invalid access to dynamically allocated memory.

Verify that there is no out of bounds access to the strings; this can be done by replacing the [] operator with the at() member function.
http://en.cppreference.com/w/cpp/string/basic_string/at
There doesn't seem to be enough input?

Apparently there are 2 tournaments. The first is the World Cup. What is the second?

Somewhere, the input is not being correctly entered or validated.

I tested with the following input and the program finished without crashing. That suggests when the input fails somewhere, it is not being validated. You may need to test cin.fail() after each input.

2
World Cup
2
Brazil
Norway
1
BrazilH2H1HNorway
FA Cup
2
Liverpool
Everton
1
LiverpoolH2H1HEverton

A few problem areas. Mixing of formatted input cin >> with getline()
Suggested solution. Extract trailing whitespace. Example:
 
    cin >> numTournaments >> ws;


No validation of success or failure of input.
Suggested solution (example):
1
2
3
4
5
    if (!cin)
    {
        cout << "cin fail 01 numTournaments\n";
        return 1;
    }


Also another example:
1
2
3
4
5
6
7
8
9
10
11
12
        getline(cin, tourName);
        if (!cin)
        {
            cout << "cin fail 02 tourName\n";
            return 1;            
        }
        
        if (!tourName.size())
        {
            cout << "tourName empty 02\n";
            return 1;                           
        }



Some of the above is rather a brute-force approach, however it seems the input may be coming from a file since there are no console prompts. If something goes wrong with either file or program at the input stage, there's no point attempting to continue. But do report as much detail as possible so the problem can be resolved.


Out of range subscripts in string parsing code.
Possible solution, add extra range checking
 
    while (curCursor < workingString.size() && workingString[curCursor] != 'H') {


However. There is a lot of code in main(). It is a good idea to move some of the more complex code into a separate function. Parsing a line of input like this
 
BrazilH2H1HNorway
can be done in its own function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool parseScore(string score, string & hometeam, string & awayteam, int & home, int & away)
{
    if (score.size() < 4)
        return false;
                    
    for (size_t i=1, count = 0; i < score.size() && count < 3; ++i)
    {
        if (score[i] == 'H')
        {
            score[i] = '\n';
            ++count;
        }
    }
    
    istringstream ss(score);
    getline(ss, hometeam);
    ss >> home >> away >> ws;
    getline(ss, awayteam);
    
    if (ss)
        return true;
    return false;        
}


The related code (including the problem area) inside main() then becomes:
1
2
3
4
5
6
7
8
9
10
11
12
13
    string hometeam, awayteam;
    int goal1, goal2;
    
    bool ok =  parseScore(workingString, hometeam, awayteam, goal1, goal2);
    if (!ok)
    {
        cout << "parseScore failed: [" << workingString << "]\n";
        return 1;
    }
    cout <<  hometeam << " vs " << awayteam << "  " << goal1 << " " <<  goal2 << '\n';

    int curTeam1 = locTeam[hometeam];
    int curTeam2 = locTeam[awayteam];


The above would replace lines 73 to 121 in the original code.


One more comment. It does not seem a good idea to use an alphabetic character as a delimiter. The code may just work with input such as "HollandH2H1HHungary" but there may be cases where a team name has two words starting with 'H' which would cause a parsing error.
Last edited on
Topic archived. No new replies allowed.