0

I'm pretty new to C++, and working through a book called "Accelerated C++." In one of the chapters you are suppose to make a program that, given a string of text, tells you what line(s) each word appears on. To break up all of the words in the string, i used a function called 'split' from a different source file, but included its header file so I could use it. It didn't work though. For the life of me I can't figure out why the linker tells me "undefined reference to 'split(std::string const&)'

split.cpp:

#include <string>
#include <cctype>
#include <vector>
#include "split.h"

using namespace std;

bool space(char c) {
    return isspace(c);
}

bool not_space(char c) {
    return !isspace(c);
}

vector<string> split(const string& s) {
    vector<string> ret;
    string::const_iterator i = s.begin();

    while (i != s.end()) {

        i = find_if(it, s.end(), not_space);

        string::const_iterator j = i;
        j = find_if(j, s.end(), space);
        if (i != s.end())
            ret.push_back(string(i, j));

        i = j;
    }
    return ret;
}

split.h:

#ifndef GUARD_split_h
#define GUARD_split_h

#include <string>
#include <vector>

bool space(char);
bool not_space(char);
std::vector<std::string> split(const std::string&);

#endif

Word_Counter.cpp:

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include "split.h"

using namespace std;

map<string, vector<int> > xref(istream& in, vector<string>
        find_words(const string&) = split) {

    string line;
    int line_number = 0;
    map<string, vector<int> > ret;

    while (getline(in, line)) {
        ++line_number;

        vector<string> words = find_words(line);

        for (vector<string>::const_iterator it = words.begin();
                it != words.end(); it++)
            ret[*it].push_back(line_number);
    }
    return ret;
}

int main() {

map<string, vector<int> > ret = xref(cin);

for(map<string, vector<int> >::const_iterator it = ret.begin();
    it != ret.end(); it++) {

    cout << it->first << "occurs on line(s): ";

    vector<int>::const_iterator line_it = it->second.begin();
    cout << *line_it;

    line_it++;

    while(line_it != it->second.end()) {
        cout << ", " << *line_it;
        line_it++;
    }
    cout << endl;
}
return 0;

}

I've been having a tough time with headers in general lately. Any help is greatly appreciated!

Liam Tyler
  • 33
  • 7
  • How do you build your program? Can you edit to the question the exact build line? Do you include _both_ `.o` (or, well, `.cpp`) files? – Petr Sep 29 '15 at 06:49
  • All I type is: "g++ Word_Counter.cpp -o Word_Counter." All three files are in the same directory. – Liam Tyler Sep 29 '15 at 06:56
  • Oh what the heck. I just typed "g++ Word_Counter.cpp split.cpp" and (after i fixed one typo) it worked. Why is that? – Liam Tyler Sep 29 '15 at 06:58

1 Answers1

1

If you have sources split in several files, you need to make the compiler aware of all them. The simplest way is to list all .cpp files (not .h files!) on the command line:

g++ Word_Counter.cpp split.cpp -o Word_Counter
Petr
  • 9,812
  • 1
  • 28
  • 52
  • So even though Word_Counter.cpp includes split.h, the compiler won't grab split.cpp automatically? Was there actually anything wrong with my header file? – Liam Tyler Sep 29 '15 at 07:02
  • @LiamTyler, I see no problems with your header. However, just `#include`'ing a header does not make the compiler aware of the corresponding source. It works on a simpler level: `#include`ing a file simply inserts its text in the position of `#include`, and nothing more. – Petr Sep 29 '15 at 07:04
  • Oh, i never knew it literally just inserted the text where the #include is. Thank you so much – Liam Tyler Sep 29 '15 at 07:06
  • And if you have to deal with a large project that deals with CMakeLists.txt, those files are listed in `add_library`. – Martin Braun Aug 12 '23 at 21:25