0

I'm trying to convert an old program I wrote in C to C++. One of the parts requires reading in a dictionary file, and putting each word into a vector that only contains words of that length. All the smaller vectors will be put in a bigger, outer vector. In this basic example, I'm trying to just read in a few words and print out words of a given size. When I try to test it, no words are printed out even though words of that size exist in the file. What is wrong with this code?

#include <iostream>
#include <fstream>
#include <vector>
#include <stdlib.h>  
using namespace std;

vector< vector<string> >readDictionary(void)
{
    vector< vector<string> > outer;
    vector<string>::iterator iterator;
    int letters;
    ifstream dict;
    for(int i = 0; i < 29; i++)
    {
        vector<string> inner;
        outer.push_back(inner);
    }
    dict.open("dictionary.txt");
    if(!dict.is_open())
    {
        cout << "Error opening the dictionary. Exiting" << endl;
        exit(1);
    }
    while(!dict.eof())
    {
        string word;
        getline(dict,word);
        if(word.size() > 0)
        {
            vector<string> inner = outer.at(word.size() - 1);
            inner.push_back(word);
        }
    }
    cout << "Letters: ";

    cin >> letters;

    vector<string> inner = outer.at(letters - 1);
    for(iterator = inner.begin(); iterator != inner.end(); iterator++)
    {
        cout << *iterator << endl;
    }
    return outer;
}
Sam Hanley
  • 4,707
  • 7
  • 35
  • 63
sarnex
  • 3
  • 4
  • What is the error you're getting? – vsoftco May 19 '14 at 21:09
  • Not getting an error, it compiles fine. It just isn't printing out the words. For example, if my dictionary file has the words "test" and "nest" on seperate lines, and I type 4 for letters, nothing is printed. When I check the size of the vector that's supposed to have size 4 words, it's zero. – sarnex May 19 '14 at 21:11
  • @samex: :_'Not getting an error ...'_ http://stackoverflow.com/posts/23747234/edit – πάντα ῥεῖ May 19 '14 at 21:15
  • `while(!dict.eof())` no no no no no – Lightness Races in Orbit May 19 '14 at 21:23
  • I changed it to while(dict.good()), is that how to handle it in C++. Again, I'm used to C file io. – sarnex May 19 '14 at 21:24
  • 2
    @sarnex: No, and it would be wrong in C, too. Testing for EOF _before_ you attempt a read is pointless. – Lightness Races in Orbit May 19 '14 at 21:25
  • In C, you check if the object is NULL first. Then, you continue to read until EOF. At least that's how I did it. What is the equivalent in C++? – sarnex May 19 '14 at 21:27
  • @sarnex: Yes, you continue to read until EOF. But you check for EOF _after_ attempting to read a value. Here, you're doing the opposite. Stop blaming C++, as this is no different in C! In C++ you'd write `string word; while (getline(dict, word)) { ... }` – Lightness Races in Orbit May 19 '14 at 21:27
  • I'm not blaming C++ at all, I'm saying I don't know the language.Thanks for the help. – sarnex May 19 '14 at 21:28
  • @sarnex: One final time, _the problem is the same in C_. You not knowing C++ is not relevant to what I am saying. If you've been checking for EOF in a manner similar to this in your C code, then your C code is broken. Anyway, good luck =) – Lightness Races in Orbit May 19 '14 at 21:31
  • In C, i would check if the object is NULL, then check the return value of fscanf. Pretty sure that isn't wrong. Either way, thanks. Try to bring down the hostility. – sarnex May 19 '14 at 21:32
  • Did you try to run it with a debugger ? Also please show an extract of the `dictionary.txt` file. – Jabberwocky May 20 '14 at 12:27
  • Thanks Michael. I've already solved the problem, I needed to pass by reference. – sarnex May 20 '14 at 16:06

3 Answers3

2

The main problem is that vector::at() returns a reference to whatever kind of object it stores. But you are not using a reference inside the 'if' statement. Your line:

vector<string> inner = outer.at(word.size() - 1);

is making a copy of the vector you want, and then that copy is destroyed when it goes out of scope.

Try replacing that with:

vector<string>& inner = outer.at(word.size() - 1);

And do the same with the line just above the 'for' loop.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Jason
  • 121
  • 3
1

Simple typo. You forgot to use a reference in this line:

            vector<string> inner = outer.at(word.size() - 1);

With the code as it is, it copies the vector, adds to it, then destroys it.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
  • I don't actually know anything about C++ references, I'm used to C-style pass-by-value. How can I use the references? Thanks – sarnex May 19 '14 at 21:17
  • @sarnex: You're writing C++ but don't know the language? Okay; stop! Time to read through a book on C++. http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – Lightness Races in Orbit May 19 '14 at 21:24
  • I learn more from trying things than reading books. – sarnex May 19 '14 at 21:26
0

Just a suggestion, you could use a map with key the size of the words and value a vector of strings, see code below:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <map>

std::map<int, std::vector<std::string>> readDictionary(char const *filename)
{
  std::map<int, std::vector<std::string>> out;
  std::ifstream dict(filename);
  if (!dict.is_open()) throw std::runtime_error("Error opening the dictionary.");
  while (!dict.eof()) {
    std::string word;
    std::getline(dict, word, ' ');
    if (!word.empty()) out[word.size()].push_back(word);
  }

  return out;
}

int main()
{
  auto v = readDictionary("dictionary.txt");
  for (auto i : v) {
    std::cout << "Length " << i.first << ":" << std::endl;
    for (auto j : i.second) std::cout << "    " << j << std::endl;
  }
  return 0;
}
101010
  • 41,839
  • 11
  • 94
  • 168
  • Thanks alot. I'm trying to a direct conversion of an old program I wrote, so I'm using vectors as I wrote a vector object in the old one. I don't even know what a map is. Thanks a lot for the code. – sarnex May 19 '14 at 21:35