0
#include <iostream>
#include <vector>
#include <string>
using namespace std;

vector<string> separate(string str){
   string build = "";
   vector<string> temp;
   
   for(int i = 0;i < str.size(); i++){
      if(str[i] != ' '){
         
         build += str[i];
         
      } else if(str[i] == ' '){
         
         temp.push_back(build);
         build = "";
      }
   }
      
      return temp;
}

int main() {
   
   int count;
   string sentence;
   vector<int> numTimes;
   
   getline(cin, sentence);
   
   vector<string> words = separate(sentence);
   
   for(int i = 0; i < words.size(); i++){
      for(int j = 0; j < words.size(); i++){
         if(words[i] == words[j]){
            count++;
         }
      }
      numTimes.push_back(count);
   }
   
   for(int k = 0; k < words.size(); k++){
      cout << words[k] << " - " << numTimes[k] << endl;
   }

   return 0;
}

The code is supposed to receive a string, separate it into the individual words, place those words into a vector and finally output the number of times the word occurs in the sentence. However when running my code, I get a message saying that the program was exited with code -11. I have looked a bit online but do not fully understand what this means or where it is occurring in my code.

  • It means there is a fatal bug in your code. Your only hope is to find and fix that bug. Your best tool for finding it is the Mark 1 brain, but the brain can be assisted by the debugging utility that came with your development tools. – user4581301 Sep 22 '21 at 00:25
  • Build your program with debug (gcc would -g3) then run your program via debugger which will tell you where it's crashing. You should also compile it with -Wall or whatever which would tell you that count is uninitialized. – Allan Wind Sep 22 '21 at 00:26
  • Typo: `for(int j = 0; j < words.size(); i++)` `j` is initialized. `j` is tested `i` is incremented. – user4581301 Sep 22 '21 at 00:29
  • In separate, either first or 2nd part match so you just need an if-else (not if-else-if) – Allan Wind Sep 22 '21 at 00:30
  • Does this answer your question? [What is a segmentation fault?](https://stackoverflow.com/questions/2346806/what-is-a-segmentation-fault) – Nate Eldredge Sep 22 '21 at 00:36

2 Answers2

2

Changed signed counter variables (i, j) to unsigned (size_t) as you compare the two. In separate(..) changed if-else-if to just if-else, and fixed the loop per @user4581301 to use the right loop variable. Also fixed last word not being added. Minor reformat to use tab/8 space for indent.

#include <iostream>
#include <vector>
#include <string>
using namespace std;

vector<string> separate(string str) {
    string build = "";
    vector<string> temp;

    for(size_t i = 0; i < str.size(); i++) {
        if(str[i] == ' ') {
            temp.push_back(build);
            build = "";
        } else {
            build += str[i];
        }
    }
    if(build.size()) {
        temp.push_back(build);        
    }       
 
    return temp;
}

int main() {
    int count = 0;
    string sentence;
    vector<int> numTimes;

    getline(cin, sentence);

    vector<string> words = separate(sentence);

    for(size_t i = 0; i < words.size(); i++) {
        for(size_t j = 0; j < words.size(); j++) {
            if(words[i] == words[j]) {
                count++;
            }
        }
        numTimes.push_back(count);
    }

    for(size_t k = 0; k < words.size(); k++) {
        cout << words[k] << " - " << numTimes[k] << endl;
    }

    return 0;
}

This seems to fix the segfault which answers question posed.

You haven't provided sample input and output but the counts clearly seems wrong. What do you mean with sentence? There is no notion of English sentences ending with '.' or whatever:

./a.out
a bc d
a - 1
bc - 2
d - 3
./a.out 
a a b
a - 2
a - 4
b - 5

Suggest you work on that and open new question if you need further help.

Allan Wind
  • 23,068
  • 5
  • 28
  • 38
  • Additional recommendation: replace the traditional, index-based for loops like `for(size_t i = 0; i < str.size(); i++)` and friends with range-based loops like `for (const auto & value: str)` because they have so few "moving parts" that they're next to impossible to get wrong. – user4581301 Sep 22 '21 at 00:53
  • Very good point, but it makes my answer more of a rewrite then a fix. Do you think that is in the best interest of op? – Allan Wind Sep 22 '21 at 00:54
  • At this point, no. I dropped that as a suggestion the asker or those who follow can experiment with at their leisure after they get a working program. – user4581301 Sep 22 '21 at 00:55
1

@Allan Wind is right, but to offer an alternate solution using the C++17 standard.

Iterating

Rather than use indexes, let's use a more modern for loop.

for (const char &ch : s)

Rather than:

for (size_t i = 0; i < str.size(); i++)

After all, the index is not important in this situation.

Dealing with multiple spaces

Right now, both the OP's code and Allan's will push an empty string onto the output vector whenever they encounter more than one contiguous space. We can correct that by resetting the string to empty when a space is encountered, but when a space is encountered and the string is empty, don't take any action.

We also need to check if the string is non-empty when the loop is finished. If so, we need to push that onto the output vector. We may not get a trailing space to trigger pushing that last word.

vector<string> separate(string s) {
    vector<string> output;
    string current = "";

    for (const char &ch : s) {
        if (current != "" && ch == ' ') {
            output.push_back(current);
            current = "";
        }
        else if (ch == ' ') {
            // Do nothing!
        }
        else {
            current += ch;
        }
    }

    if (current != "") {
        output.push_back(current);
    }

    return output;
}

Putting it together so far

#include <string>
#include <vector>
#include <iostream>

using namespace std;

vector<string> separate(string s);

int main() {
    auto v = separate("hello world   foo"); 

    for (auto i : v) {
        cout << i << endl;
    }
}

vector<string> separate(string s) {
    vector<string> output;
    string current = "";

    for (const char &ch : s) {
        if (current != "" && ch == ' ') {
            output.push_back(current);
            current = "";
        }
        else if (ch == ' ') {
            // Do nothing!
        }
        else {
            current += ch;
        }
    }

    if (current != "") {
        output.push_back(current);
    }

    return output;
}

Counting words

We can use a map to count the occurrences of words. We use a map<string, int> where each word is the key, and the val is the occurrences. As we iterate over the words, if the word already exists as a key in the map, we increment it by `. If not, we set it to 1.

int main() {
    auto v = separate("hello    world   hello world   foo");    

    map<string, int> m;

    for (auto i : v) {
        if (m[i]) {
            m[i] += 1;
        }
        else {
            m[i] = 1;
        }
    }

    for (auto const& [key, val] : m) {
        cout << "The word \"" << key << "\" occurs " 
             << val << " times." << endl;
    }    
}
Chris
  • 26,361
  • 5
  • 21
  • 42
  • Your answer is a bigger (and better) step so maybe rejiggle `separate()` to use a standard solution like strtok(), getline(), find() or substr()? Although you are almost certainly right re empty string, question (specification) doesn't really say. – Allan Wind Sep 22 '21 at 01:03
  • 1
    I felt with everything else I'd eliminated in terms of the iteration logic, the actual parsing logic was better left a bit manual. Hopefully I made it easier to see the algorithm by getting rid of some of the boilerplate. – Chris Sep 22 '21 at 01:05