0

I got a Segmentation fault in the following program.
Why is this happening and how can I fix it?

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

std::vector<std::string> split_words(std::string s) {
    std::vector<std::string> v(1, "");
    int i=0;
    int wortanzahl = 0;
    while(i<s.size()) {
        if (s[i]!=' ') {
            v.resize(wortanzahl + 1, "");
            for (int j=i; s[j]!=' '; ++j) {
                v[wortanzahl] += s[j];
                i=j;
            }
            ++wortanzahl;
        }
        ++i;
    }
}

int main() {
    std::string s = "Alpha beta! Gamma";
    split_words(s);
    return 0;
}
2
  • 3
    Use std::istringstream to split the words on a space. You don't need to write these types of loops to do this job. Commented Nov 29, 2016 at 17:49
  • 1
    Make sure you have a debug build, and run the program under your debugger. When the segmentation fault occurs, it will show you the line where it happened, and the program state. Or, you can examine an existing core file. PS, nothing stops j running off the end ... Commented Nov 29, 2016 at 17:57

4 Answers 4

2

I don't know the reason

You have several issues with your code. The one glaring one is that you failed to return the vector v in the split_words function. Not returning a value from a function that is defined to return a value is undefined behavior.

The second issue is that j falls off the end on the last word, since your loop only stops on s[j] being a blank. The string does not end on a blank character, thus your loop keeps going beyond the length of the string.

Having said this, if your goal is to split a string on the space character, there is no need to write code like this to do the job. Instead, simply use std::istringstream and operator >>:

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

std::vector<std::string> split_words(std::string s) 
{
    std::vector<std::string> v;
    std::istringstream iss(s);
    std::string temp;
    while (iss >> temp)
       v.push_back(temp);
    return v;
}
 
int main() 
{
   std::string s = "Alpha beta! Gamma";
   auto vect = split_words(s);
   for (auto& word : vect)
      std::cout << word << "\n";
   return 0;
} 

Live Example

The loop simply calls operator >> on the stream, and each iteration calls push_back for each parsed string encountered.

Sign up to request clarification or add additional context in comments.

Comments

0

I think, provided that you're using C++11 or higher, that you should go for regular expressions, and do something like this:

std::vector<std::string> split_words(std::string s) {
    std::vector<std::string> v;
    std::regex pattern("[!-~]+");
    std::cmatch result;

    while(regex_search(s.c_str(), result, pattern)) {
        for(auto it : result)
           v.push_back(it);
        s = result.suffix().str();
    }

    return v;
}

So that your search matches every single (non-extended) ASCII table character combination except non printable ones, including spaces, and you achieve your aim.

Comments

0

The bug is right here when you get to the last word you forget to check for \0 or the length of the string.

for (int j=i; s[j]!=' ' && j < s.size(); ++j) {
  v[wortanzahl] += s[j];
  i=j;
}

Ah forgot I had seen Alexsandrescu talk about sentinels, so you could actually have solved the problem if you had added a (space) after the input. As first line in your split_words add

s += ' ';

Comments

0

These changes are required. Also mentioned inline in code below.

// 0. can try using namespace std; to clean up code.

// 1. check for end of string in below loop.

// 2. return the vector of strings. (this fixes the crash).

// 3. output the split strings using vector.

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

// 0. can try using std to clean up code.
std::vector<std::string> split_words(std::string s)
{
    std::vector<std::string> v(1, "");
    int i=0;
    int wortanzahl = 0;
    while(i<s.size())
    {
        if (s[i]!=' ')
        {
            v.resize(wortanzahl+1, "");
            // 1. check for end of string in below loop
            for (int j=i; s[j] && s[j]!=' '; ++j)
            {
                v[wortanzahl] += s[j];
                i=j;
            }
            ++wortanzahl;
        }
        ++i;
    }

    // 2. return the vector of strings
    return v;
}

int main()
{
    std::string s = "Alpha beta! Gamma";
    std::vector<std::string> v = split_words(s);

    // 3. output the split strings using vector
    for (int i = 0; i < v.size(); ++i)
        std::cout << v[i] << std::endl;
    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.