Lucas
Lucas

Reputation: 43

Segmentation Fault Before main()

I'm having a problem with this code. After compiling with g++, I run a.out and I get a segmentation fault and no "here" displayed. The code is pretty short:

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

bool inWords(vector<string> words, string str);

int main()
{
  cout << "here";

  vector<string> words;
  string str;
  istringstream iss;
  ifstream file("data.txt", ifstream::in);

  // read in words
  for(int i = 0; file >> str; /*no i++*/)
  {
    if(str[str.length() - 1] == '.')
      str.erase( str.length()-1);
      // if word has a period at the end, erase it

    if(!inWords(words, str))
    {
      // if word is not in vector words, add it
      words.push_back(str);
      i++;
    }
  }

  // output each word
  for (vector<string>::size_type i = 0; i < words.size(); i++)
    cout << words[i];

  // return to beginning of file
  file.clear();
  file.seekg(0, ios::beg);

  // read in sentences
  // to be implemented

  file.close();

  return 0;
}

bool inWords(vector<string> words, string str)
{
  for(int i = 0; !words[i].empty(); i++)
    if(words[i] == str) { return true; }
  return false;
}

As far as I know, nothing should be a problem. data.txt is definitely in the same directory as the file and I receive no arguments from the command line. Can anyone help?

Upvotes: 1

Views: 2680

Answers (2)

Wyck
Wyck

Reputation: 11750

The technique for iterating the vector in inWords is wrong and interacts with elements past the end of the vector causing the segmentation fault.

This program immediately accesses words[0] in inWords when the words vector is empty and words[0] (the first element of the vector) does not exist yet because the size of the vector is still zero but the loop does not do anything to avoid this condition.

I think inWords could be better implemented with std::find, perhaps like this:

bool inWords(const vector<string>& words, const string& str)
{
  return std::find(words.begin(), words.end(), str) != words.end();
}

Remember to #include <algorithm> to make use of std::find. I also changed the parameters to pass by const reference, so you'll need to change the forward declaration of that function. I also added an endl to the output to make it readable.

Full text of repair:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;

bool inWords(const vector<string>& words, const string& str);

int main()
{
  vector<string> words;
  string str;
  istringstream iss;
  ifstream file("data.txt", ifstream::in);

  // read in words
  for(int i = 0; file >> str; /*no i++*/)
  {
    if(str[str.length() - 1] == '.')
      str.erase( str.length()-1);
      // if word has a period at the end, erase it

    if(!inWords(words, str))
    {
      // if word is not in vector words, add it
      words.push_back(str);
      i++;
    }
  }

  // output each word
  for (vector<string>::size_type i = 0; i < words.size(); i++)
    cout << words[i] << std::endl;

  // return to beginning of file
  file.clear();
  file.seekg(0, ios::beg);

  // read in sentences
  // to be implemented

  file.close();

  return 0;
}

bool inWords(const vector<string>& words, const string& str)
{
  return std::find(words.begin(), words.end(), str) != words.end();
}

Upvotes: 0

Cramer
Cramer

Reputation: 1795

It won't be before main. Try using a debugger to see where it happens (eg GDB) which are incredibly handy tool. The reason you don't see "here" is because the buffer isn't flushed. Put a << std::endl after it so that it forces output at that point.

A technicality: You can segfault before main but that will happen in a constructor. I see you have no custom objects defined/instantiated in global scope.

Upvotes: 2

Related Questions