Access Violation (Segmentation Fault) Error

I'm creating a program that will count and display total and unique words from user input. The program would have to display the unique words and their total counts in descending order. I have finished the majority of the program, but I keep getting an access violation (segmentation fault) error message. Since I'm not sure what's causing it and I'm fairly new to this forum, I've posted the code in its entirety.

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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Preprocessor directives
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <cctype>

// Avoid name conflicts.
using namespace std;

/*------------- FUNCTION DECLARATIONS/PROTOTYPES/GLOBAL VARIABLES ------------*/

const int maxUniqueWords = 200;
int totalWords=0, distinctWords=0;

class Word
{
    public:
         Word(): wordCount(0) {};
         void setName(string singleWord); // Change word.
         void setCount(int count); // Change count.
         string getName(); // Return word.
         int getCount(); // Return count.
    private:
         string uniqueWord;  
         int wordCount;         
};

Word wordDb[maxUniqueWords];

string fixString(const string& s);
void checkWord(string singleWord);
void sort();
int indexOfBiggest(int startIndex);
void swapValues(int index, int indexOfBiggest);

/*----------------------------- 'main' FUNCTION ------------------------------*/

int main()
{
    string inputString;
    string sentinel = "@@@";
    
    cout << "Please input your sentences, you can enter '@@@' to finish the input:\n";
    getline(cin,inputString); // Get user input
    inputString = fixString(inputString); // Remove punctuations and make it lower-cased.
    
    istringstream in(inputString);
    do {
      string singleWord;
      in >> singleWord;
      if(singleWord == sentinel) // Exit loop if sentinel is typed.
      {
         break;
      }
      if(singleWord.length()>0) // Check word if word length is greater than 0.
      {
        checkWord(singleWord);
        totalWords++;
      }
      else if (singleWord.length()==0) // Exit loop if word length if word length is 0.
      {
        break;
      }
    } while(in);
    
    cout << "\nTotal number of words: " << totalWords << endl;
    cout << "Total number of distinct words: " << distinctWords << endl << endl;
    
    sort();  // PROBLEM OCCURS HERE!
    
    for(int i=0;i<distinctWords;i++)
    {
      cout << setw(15) << left << wordDb[i].getName() << setw(3) << wordDb[i].getCount() << endl;
    }
    
    cout << endl;
    system("PAUSE");            
    return EXIT_SUCCESS; 
}

/*--------------------------- FUNCTION DEFINITIONS ---------------------------*/

void checkWord(string singleWord)
{
    bool isUnique;
    
    for(int i=0;i<maxUniqueWords;i++) // Check if word is already saved.
    {
      string dbWord = wordDb[i].getName();
      if(singleWord.compare(dbWord)==0)
        {
          wordDb[i].setCount(1);
          isUnique=1;
          break;
        }
      else
        {
          bool isUnique=0;
        }
    }
    if(isUnique==0) // Create a new word entry if unique.
    {     
      for(int i=0;i<maxUniqueWords;i++)
      {
        if(wordDb[i].getCount()==0)
          {
            wordDb[i].setName(singleWord);
            wordDb[i].setCount(1);
            break;
          }
        else
          {
            continue;
          }
      }
    }    
}

void Word::setName(string singleWord)
{
    uniqueWord = singleWord;
    distinctWords++;
}

void Word::setCount(int count)
{
    wordCount += count;
}

int Word::getCount()
{
    return wordCount;
}

string Word::getName()
{
    return uniqueWord;
}

string fixString(const string& s)
{
    const string punct(",;:.?!-\"");
    string noPunct; // initialized to empty string
    
    int sLength = s.length();
    int punctLength = punct.length();
    for (int i=0; i< sLength; i++) 
    {
         string aChar = s.substr(i,1);
         int location = punct.find(aChar,0);
         // Find location of successive characters
         // of src in punct.
         
         if (location<0||location>=punctLength)
              noPunct += aChar; // aChar is not in punct, so keep it
    }
    int fixedLength= noPunct.length();
    for (int i=0;i<fixedLength;i++)
    {
         noPunct[i]=tolower(noPunct[i]);
    }
    return (noPunct);     
}

void sort()
{
    int indexOfNextBiggest;
    for(int index=0;index<distinctWords;index++)
    {
      indexOfNextBiggest=indexOfBiggest(index);
      swapValues(index,indexOfNextBiggest); 
    }
}

int indexOfBiggest(int startIndex)
{
    int max = wordDb[startIndex].getCount();
    int indexOfMax = startIndex;
    
    for (int index = startIndex+1;index<distinctWords;index++)
    {
      if(wordDb[index].getCount()>max)
        {
          max = wordDb[index].getCount();
          indexOfMax=index;
        }
    }
    return indexOfMax;
}

void swapValues(int index, int indexOfBiggest)
{
    Word temp;
    
    temp.setName(wordDb[index].getName());
    temp.setCount(wordDb[index].getCount());
    
    wordDb[index].setName(wordDb[indexOfBiggest].getName());
    wordDb[index].setCount(wordDb[indexOfBiggest].getCount());
    
    wordDb[indexOfBiggest].setName(temp.getName());
    wordDb[indexOfBiggest].setCount(temp.getCount());
}
Last edited on
Run it in the debugger and post the line that causes the segmentation fault.
I reviewed the code -- here's my notes.

I bolded the part that's causing the access violation .. but I recommend you read all of it:


Your checkWord function has a few problems:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    for(int i=0;i<maxUniqueWords;i++)
    {
      string dbWord = wordDb[i].getName();
      if(singleWord.compare(dbWord)==0)  // if this word matches the word in the DB
        {
          //  this code runs if the word is NOT unique (Because it matched a word in the DB)
          wordDb[i].setCount(1);    // therefore this makes no sense
          isUnique=1;  // and this is backwards
          break;
        }
      else
        {
          bool isUnique=0;  // get rid of this 'bool'.  You're creating a second isUnique var and not
           //   changing the var you mean to.
        }
    }


Although personally I would get rid of the else condition entirely. Initialize isUnique to true and then search for a matching word and set it to false if you find one. If you get through the loop without finding any matches, isUnique is left to it's initialized value of 'true' and you know the word is unique.

 
if(isUnique==0) // Create a new word entry if unique. 


If isUnique is false... doesn't that mean the word isn't unique?

Or is your variable just named backwards? ... actually now that I see that, it looks like what you're doing is ALMOST right -- except isUnique is backwards and you're never setting it to false.


more from checkWord:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    if(isUnique==0)
    {     
      for(int i=0;i<maxUniqueWords;i++)  // why do you need to look for the next available word?
      {    // doesn't 'distinctWords' already keep track of that?  You can just use it to know where
            //  to put this word
        if(wordDb[i].getCount()==0)
          {
            wordDb[i].setName(singleWord);
            wordDb[i].setCount(1);
            break;
          }
//        else  // these lines are all redundant, I'd get rid of them
//          {
//            continue;
//          }
      }
    }   




- Word::setName seems like an inappropriate place to increment distinctWords. I would move that to checkWord.

... and actually that is your problem, because setName is called a bunch when you swapValues. This corrupts distinctWords and makes the loop in sort() and indexOfBiggest() run too long.

- Word::setCount is strange:
1
2
3
4
5
6
void Word::setCount(int count)
{
    wordCount += count;  // this is not setting the count, it's adding to it.
    // either this function doesn't do what you expect, or it's named
    //   inappropriately
}



- In fix string... this isn't a bug, but it seems wasteful:
1
2
         string aChar = s.substr(i,1);
         int location = punct.find(aChar,0);


There's no need to make a separate substr, here. find() works with an individual character. You can just take the character out of the string with the [] operator:

 
    int location = punct.find( s[i] );  // much better 


likewise, line 157 can be changed to noPunct += s[i];




EDIT:

I also want to say "good work". You're doing a very decent job of organizing your code and splitting it up into manageable tasks. And while it's not perfect, and there are things I would want to change, it's certainly tons better than most of the stuff we get in here -- which is why I was willing to go over it with a fine tooth comb.

Keep up the good work.


EDIT2:

I also thought this was ironic:


1
2
// Avoid name conflicts.
using namespace std;


'using namespace std;' causes name conflicts... it doesn't avoid them. XD
Last edited on
Okay. I've ran the debugger and whenever it gets to the sort() function on main() it gives the segmentation fault. I'm not so sure what to do next. I've tried setting breakpoints on every line on the sort function definition. I don't know, but I'm going in circles trying to figure out what's wrong...
Okay, let me try your suggestions. I'll let you know if it works shortly...
Wow, thanks Disch for all of your suggestions; it helped me fix the erred logic in the checkWord function. I've also implemented all of your other suggestions as well. However, after moving out the distinctWords increment, I still get the access violation message. Here is the revised code:

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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Preprocessor directives
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <cctype>

// Avoid name conflicts.
using namespace std;

/*------------- FUNCTION DECLARATIONS/PROTOTYPES/GLOBAL VARIABLES ------------*/

const int maxUniqueWords = 200;
int totalWords=0, distinctWords=0;

class Word
{
    public:
         Word(): wordCount(0) {};
         void setName(string singleWord); // Change word.
         void setCount(int count); // Change count.
         string getName(); // Return word.
         int getCount(); // Return count.
    private:
         string uniqueWord;  
         int wordCount;         
};

Word wordDb[maxUniqueWords];

string fixString(const string& s);
void checkWord(string singleWord);
void sort();
int indexOfBiggest(int startIndex);
void swapValues(int index, int indexOfBiggest);

/*----------------------------- 'main' FUNCTION ------------------------------*/

int main()
{
    string inputString;
    string sentinel = "@@@";
    
    cout << "Please input your sentences, you can enter '@@@' to finish the input:\n";
    getline(cin,inputString); // Get user input
    inputString = fixString(inputString); // Remove punctuations and make it lower-cased.
    
    istringstream in(inputString);
    do {
      string singleWord;
      in >> singleWord;
      if(singleWord == sentinel) // Exit loop if sentinel is typed.
      {
         break;
      }
      if(singleWord.length()>0) // Check word if word length is greater than 0.
      {
        checkWord(singleWord);
        totalWords++;
      }
      else if (singleWord.length()==0) // Exit loop if word length if word length is 0.
      {
        break;
      }
    } while(in);
    
    cout << "\nTotal number of words: " << totalWords << endl;
    cout << "Total number of distinct words: " << distinctWords << endl << endl;
    
    sort();
    
    for(int i=0;i<distinctWords;i++)
    {
      cout << setw(15) << left << wordDb[i].getName() << setw(3) << wordDb[i].getCount() << endl;
    }
    
    cout << endl;
    system("PAUSE");            
    return EXIT_SUCCESS; 
}

/*--------------------------- FUNCTION DEFINITIONS ---------------------------*/

void checkWord(string singleWord)
{
    bool isUnique=1;
    
    for(int i=0;i<maxUniqueWords;i++) // Check if word is already saved.
    {
      string dbWord = wordDb[i].getName();
      if(singleWord.compare(dbWord)==0)
        {
          wordDb[i].setCount(1); // Still need this to increase count.
          isUnique=0;  // I fixed the logic I wrote when I was sleepy. :]
          break;
        }
    }
    if(isUnique==1) // Create a new word entry if unique.
    {     
      wordDb[distinctWords].setName(singleWord);
      wordDb[distinctWords].setCount(1);
      distinctWords++; // Correct placement to increase distinct words count.
    }    
}

void Word::setName(string singleWord)
{
    uniqueWord = singleWord;
}

void Word::setCount(int count)
{
    wordCount += count;
}

int Word::getCount()
{
    return wordCount;
}

string Word::getName()
{
    return uniqueWord;
}

string fixString(const string& s)
{
    const string punct(",;:.?!-\"");
    string noPunct; // initialized to empty string
    
    int sLength = s.length();
    int punctLength = punct.length();
    for (int i=0; i< sLength; i++) 
    {
         int location = punct.find(s[i]);
         // Find location of successive characters
         // of src in punct.
         
         if (location<0||location>=punctLength)
              noPunct += s[i]; // s[i] is not in punct, so keep it
    }
    int fixedLength= noPunct.length();
    for (int i=0;i<fixedLength;i++)
    {
         noPunct[i]=tolower(noPunct[i]);
    }
    return (noPunct);     
}

void sort()
{
    int indexOfNextBiggest;
    for(int index=0;index<distinctWords;index++)
    {
      indexOfNextBiggest=indexOfBiggest(index);
      swapValues(index,indexOfNextBiggest); 
    }
}

int indexOfBiggest(int startIndex)
{
    int max = wordDb[startIndex].getCount();
    int indexOfMax = startIndex;
    
    for (int index = startIndex+1;index<distinctWords;index++)
    {
      if(wordDb[index].getCount()>max)
        {
          max = wordDb[index].getCount();
          indexOfMax=index;
        }
    }
    return indexOfMax;
}

void swapValues(int index, int indexOfBiggest)
{
    Word temp;
    
    temp.setName(wordDb[index].getName());
    temp.setCount(wordDb[index].getCount());
    
    wordDb[index].setName(wordDb[indexOfBiggest].getName());
    wordDb[index].setCount(wordDb[indexOfBiggest].getCount());
    
    wordDb[indexOfBiggest].setName(temp.getName());
    wordDb[indexOfBiggest].setCount(temp.getCount());
}
Works fine for me, here. I also don't see anything else that could be causing the problem. =x

Although the count is still wrong. setCount isn't setting the count, it's incrementing it, which is not what setCount should do.
Yay, it does execute; just had to delete the old executables files. Now, one little kink left. In the program when I type in, for example, "one two two", it lists the word in descending order, but the number of times is wrong; it gives:

two      3
one      9
Right. This is because setCount is incrementing instead of setting.
Disch, thanks so much for your help! I've finally got the code working and I've "re-fixed" the setCount as you've said. Kudos to you! Now, is there a way to get '@@@' as a sentinel in a new line instead of the same line as the input; everytime I input and press Enter it sends it straight to processing and I was wondering if I could continue typing onto a new line and enter the sentinel.
getline(cin,inputString); // Get user input


This only gets 1 line from the user. If you want the user to be able to enter multiple lines, you could loop on that.

OR

what you're doing now is getline, then putting it in an istringstream, then using >> to extract it. Instead... you could just extract with >> directly from cin and forget about making a separate stream.
Okay, I'm trying your second suggestion, but I'm not sure what you mean by getting it directly from cin. Would that mean I wouldn't have to use istringstream to split the strings into words?
Gotcha Disch! I removed getline , as you've said, and instead set the istringstream to get direct input from cin into singleWord, then finally "fix" the string! Wow, you have been much help tonight my bud! Thank YOU so, so much! :]
To everyone else, here is the working code for your convenience:

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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Preprocessor directives
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <cctype>

// Avoid name conflicts.
using namespace std;

/*------------- FUNCTION DECLARATIONS/PROTOTYPES/GLOBAL VARIABLES ------------*/

const int maxUniqueWords = 200;
int totalWords=0, distinctWords=0;

class Word
{
    public:
         Word(): wordCount(0) {};
         void setName(string singleWord); // Change word.
         void setCount(int count); // Change count.
         string getName(); // Return word.
         int getCount(); // Return count.
    private:
         string uniqueWord;  
         int wordCount;         
};

Word wordDb[maxUniqueWords];

string fixString(const string& s);
void checkWord(string singleWord);
void sort();
int indexOfBiggest(int startIndex);
void swapValues(int index, int indexOfBiggest);

/*----------------------------- 'main' FUNCTION ------------------------------*/

int main()
{
    string inputString;
    string sentinel = "@@@";
    
    cout << "Please input your sentences, you can enter '@@@' by a new line to\nfinish the input:\n";

    istringstream in(inputString); // Feeds input strings word-by-word
    do {
      string singleWord;
      cin >> singleWord; // Singled-string input
      singleWord = fixString(singleWord); // Removes punctuations and makes string lower-cased.
      if(singleWord == sentinel) // Exit loop if sentinel is typed.
      {
         break;
      }
      if(singleWord.length()>0) // Check word if word length is greater than 0.
      {
        checkWord(singleWord);
        totalWords++;
      }
      else if (singleWord.length()==0) // Exit loop if word length if word length is 0.
      {
        break;
      }
    } while(in);
    
    cout << "\nTotal number of words: " << totalWords << endl;
    cout << "Total number of distinct words: " << distinctWords << endl << endl;
    
    sort(); // Sorts array by descending order by word frequency.
    
    for(int i=0;i<distinctWords;i++) // Display distinct word list.
    {
      cout << setw(15) << left << wordDb[i].getName() << setw(3) << wordDb[i].getCount() << endl;
    }
    
    cout << endl;
    system("PAUSE");            
    return EXIT_SUCCESS; 
}

/*--------------------------- FUNCTION DEFINITIONS ---------------------------*/

void checkWord(string singleWord)
{
    bool isUnique=1;
        
    for(int i=0;i<maxUniqueWords;i++) // Check if word is already saved.
    {
      string dbWord = wordDb[i].getName();
      if(singleWord.compare(dbWord)==0)
        {
          wordDb[i].setCount(wordDb[i].getCount()+1); // Increase its count if word is already saved.
          isUnique=0;  
          break;
        }
    }
    if(isUnique==1) // Create a new word entry if unique.
    {     
      wordDb[distinctWords].setName(singleWord);
      wordDb[distinctWords].setCount(1);
      distinctWords++; // Increase distinct word count.
    }    
}

void Word::setName(string singleWord)
{
    uniqueWord = singleWord;
}

void Word::setCount(int count)
{
    wordCount = count;
}

int Word::getCount()
{
    return wordCount;
}

string Word::getName()
{
    return uniqueWord;
}

string fixString(const string& s)
{
    const string punct(",;:.?!-\"");
    string noPunct; // initialized to empty string
    
    int sLength = s.length();
    int punctLength = punct.length();
    for (int i=0; i< sLength; i++) 
    {
         int location = punct.find(s[i]);
         // Find location of successive characters
         // of src in punct.
         
         if (location<0||location>=punctLength)
              noPunct += s[i]; // s[i] is not in punct, so keep it
    }
    int fixedLength= noPunct.length();
    for (int i=0;i<fixedLength;i++)
    {
         noPunct[i]=tolower(noPunct[i]); // Lower-cases the noPunct string.
    }
    return (noPunct);     
}

void sort()
{
    int indexOfNextBiggest;
    
    for(int index=0;index<distinctWords;index++)
    {
      indexOfNextBiggest=indexOfBiggest(index);
      swapValues(index,indexOfNextBiggest); 
    }
}

int indexOfBiggest(int startIndex)
{
    int max = wordDb[startIndex].getCount();
    int indexOfMax = startIndex;
    
    for (int index = startIndex+1;index<distinctWords;index++)
    {
      if(wordDb[index].getCount()>max)
        {
          max = wordDb[index].getCount();
          indexOfMax=index;
        }
    }
    return indexOfMax;
}

void swapValues(int index, int indexOfBiggest)
{
    Word temp;
    
    temp.setName(wordDb[index].getName());
    temp.setCount(wordDb[index].getCount());
    
    wordDb[index].setName(wordDb[indexOfBiggest].getName());
    wordDb[index].setCount(wordDb[indexOfBiggest].getCount());
    
    wordDb[indexOfBiggest].setName(temp.getName());
    wordDb[indexOfBiggest].setCount(temp.getCount());
}
Topic archived. No new replies allowed.