List Iterator Not incrementable - Runtime Error - c++

I am getting a List Iterator Not incrementable on the code below after adding a stringstream for movieName and am unsure as how to go about solving the error. I am trying to read in from a file and add the items into a list then itterate through the list and add eash word from the title of the movie into another list. Any help would be appreciated!
#include <iostream>
#include <string>
#include <list>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
list <string> movieList;
list <string>::iterator iterMovie;
list <string> *titleWordList = new list <string>;
list <string>::iterator iterTitleWord;
ifstream inFile;
inFile.open("JamesBond.txt");
if (!inFile)
{
cout << "Could not find the specified file.";
}
else
{
movieList.clear();
string movieName;
while(getline(inFile,movieName))
{
movieList.push_back((movieName));
/*
for each(string movieName in movieList)
{
titleWordList->push_back(movieName);
}
*/
stringstream ss(movieName);
while (ss >> movieName)
{
titleWordList->push_back(movieName);
}
}
}
if (movieList.empty())
{
cout << "No Data Found!" << endl;
}
else
{
cout << "Writing Output: \n\n";
for (iterMovie=movieList.begin(); iterMovie !=movieList.end(); ++iterMovie)
{
cout << *iterMovie << endl;
}
for (iterTitleWord=movieList.begin(); iterTitleWord != movieList.end(); ++iterMovie)
{
cout << *iterTitleWord << endl;
cout << &titleWordList;
}
}
}

In the second for there is a copy paste error, it should be ++iterTitleWord instead of ++iterMovie.
Also, as #Greg suggested, iterTitleWord=movieList.begin() and iterTitleWord != movieList.end() should be iterTitleWord=titleWordList->begin() and iterTitleWord != titleWordList->end() respectively.

Related

strings in if statement

I am trying to write a code which lists all words used in a text file without repeating. I succeeded to list all the words but I always get repeating ,the if statement line 17 always gives the value of 0.I have no idea why , the words are listed properly in the vector. Any suggestion ?
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
class reading {
public:
string word;
vector<string> words;
};
int checkifexist(string word) {
reading readingobject;
bool exist = false;
for (int i = 0; i < readingobject.words.size(); i++) {
if (word == readingobject.words[i]) {
exist = true;
break;
}
}
return exist;
}
int main() {
reading readingobject;
ifstream inFile;
inFile.open("Book.txt");
if (inFile.fail()) {
cout << "file didn't open" << endl;
exit(1);
}
readingobject.word.resize(1);
while (!inFile.eof()) {
inFile >> readingobject.word;
if (checkifexist(readingobject.word) == 1)
continue;
cout << readingobject.word << endl;
readingobject.words.push_back(readingobject.word);
}
return 0;
}
Inside of checkifexist(), you are creating a new reading object, whose words vector is empty, so there is nothing for the loop to do, and the function returns 0.
You need to instead pass in the reading object from main() as an input parameter, eg:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
class reading {
public:
vector<string> words;
};
bool checkifexist(const reading &readingobject, const string &word)
{
for (size_t i = 0; i < readingobject.words.size(); ++i) {
if (word == readingobject.words[i]) {
return true;
}
}
return false;
/* alternatively:
return (std::find(readingobject.words.begin(), readingobject.words.end(), word) != readingobject.words.end());
*/
}
int main()
{
reading readingobject;
string word;
ifstream inFile;
inFile.open("Book.txt");
if (!inFile) {
cout << "file didn't open" << endl;
return 1;
}
while (inFile >> word) {
if (checkifexist(readingobject, word))
continue;
cout << word << endl;
readingobject.words.push_back(word);
}
return 0;
}
Alternatively, when it comes to tracking unique elements, you can use a std::set instead of a std::vector, eg:
#include <iostream>
#include <fstream>
#include <set>
using namespace std;
class reading {
public:
set<string> words;
};
int main()
{
reading readingobject;
string word;
ifstream inFile;
inFile.open("Book.txt");
if (!inFile) {
cout << "file didn't open" << endl;
return 1;
}
while (inFile >> word) {
if (readingobject.words.insert(word).second)
cout << word << endl;
}
return 0;
}

Sorting a textfile that contains player name and score in descending order

I am trying to open a text file and then rearrange it in descending order, to show who has the highest score. In the text file there's the player name and their score.
I've managed to print out the textfile in c++, but I cannot find a way to sort it since the variables are in the text file.
#include <string>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
using namespace std;
struct player {
string name;
int score;
int position;
};
int main()
{
string line;
ifstream inFile;
inFile.open("C:/Users/kkpet/Desktop/highscore.txt");
if (inFile.is_open()) {
while (getline(inFile, line)) {
player x;
ifstream inFile;
inFile.open("C:/Users/kkpet/Desktop/highscore.txt");
cout << line << '\n';
}
inFile.close();
}
else
cout << "Unable to open text";
}
Assuming your text file looks like this:
Name1 1
Name2 1
Name4 5
Name3 6
you could do something like this:
#include <string>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
#include <vector>
int main()
{
std::string line;
std::ifstream inFile;
inFile.open("/C:/Users/kkpet/Desktop/highscore.txt");
if (inFile.is_open()) {
std::vector<std::pair<int, std::string> > score_vector;
std::string name;
int score;
while (inFile >> name >> score) {
score_vector.push_back(std::make_pair(score, name));
std::cout << line << '\n';
}
inFile.close();
std::sort(score_vector.begin(), score_vector.end());
std::reverse(score_vector.begin(), score_vector.end());
for(auto it = score_vector.begin(); it != score_vector.end(); ++it){
std::cout << "Name: " << it->second << " Score: " << it->first << std::endl;
}
}
else
std::cout << "Unable to open text";
}
You first read the file line by line using inFile << name << score directly gives you the name and score of the player. You then create a pair out of them with score as first, which just makes it easier to sort, you could also sort by the second element of a pair using your own compare function, but for simplicity I put it this way around. Then you can easily sort the vector with the std::sort method. Afterwards it needs to be reverted.
Full code with custom compare function:
#include <string.h>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
#include <vector>
// This is a compare funciton for the sort algorithm of std::sort. See [1]
bool compareScorePair(std::pair<std::string, int>&a, std::pair<std::string, int>&b){
if(a.second > b.second){return true;}
if(a.second == b.second){return a.first.compare(b.first) > 0;}
return false;
}
int main()
{
std::ifstream inFile;
inFile.open("C:/Users/kkpet/Desktop/highscore.txt");
if (inFile.is_open()) {
std::vector<std::pair<std::string, int> > score_vector;
std::string name;
int score;
while (inFile >> name >> score) { // Can be used to directly assign istream data to variables. See [2]
score_vector.push_back(std::make_pair(name, score)); // Storing data as pair, to keep relationships between score and name.
}
inFile.close();
std::sort(score_vector.begin(), score_vector.end(), compareScorePair); // Sort the vector with the custom compare function, See top of code.
int place = 1;
//auto is used purely for convenience. auto represents std::vector<std::pair<std::string, int> >::iterator here.
for(auto it = score_vector.begin(); it != score_vector.end(); ++it){
std::cout << "Place: " << place << " Name: " << it->first << " Score: " << it->second << std::endl;
++place;
}
// The whole for loop could look like this:
/*
for(uint i = 0; i < score_vector.size(); ++i){
std::string name_out = score_vector[i].first;
int score_out = score_vector[i].second;
std::cout << "Place: " << i << " Name: " << name_out << " Score: " << score_out << std::endl;
}
*/
}
else
std::cout << "Unable to open text";
}
Output:
Place: 1 Name: Name3 Score: 6
Place: 2 Name: Name4 Score: 5
Place: 3 Name: Name2 Score: 1
Place: 4 Name: Name1 Score: 1
Links:
[1]: https://en.cppreference.com/w/cpp/named_req/Compare
[2]: http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
Information on pair:
https://en.cppreference.com/w/cpp/utility/pair
Information on iterators (see auto keyword):
https://www.geeksforgeeks.org/iterators-c-stl/
No need to use C++ for this problem! Just enter this in the shell prompt.
sort -rk 2 highscore.txt > sorted_scores.txt
Explanation:
'sort' sorts a file, typically by the first letter.
The -k 2 option means to sort by the second column.
The -r option means to reverse (so highest score is on top).

Inputting values into an array from a file with C++

The file does open and I get the message "File opened successfully". However I can't input data from the array in file "random.csv" into my inputFile object.
The data in random.csv is:
Boston,94,-15,65
Chicago,92,-21,72
Atlanta,101,10,80
Austin,107,19,81
Phoenix,112,23,88
Washington,88,-10,68
Here is my code:
#include "main.h"
int main() {
string item; //To hold file input
int i = 0;
char array[6];
ifstream inputFile;
inputFile.open ("random.csv",ios::in);
//Check for error
if (inputFile.fail()) {
cout << "There was an error opening your file" << endl;
exit(1);
} else {
cout << "File opened successfully!" << endl;
}
while (i < 6) {
inputFile >> array[i];
i++;
}
for (int y = 0; y < 6; y++) {
cout << array[y] << endl;
}
inputFile.close();
return 0;
}
Hello and welcome to Stack Overflow (SO). You can use std::getline() to read each line from the file, and then use boost::split() to split each line into words. Once you have an array of strings for each line, you can use a container of your liking to store the data.
In the example below I've used an std::map that stores strings and a vector of ints. Using a map will also sort the entrances using the key values, which means that the final container would be in alphabetical order. The implementation is very basic.
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <ctype.h>
typedef std::map<std::string,std::vector<int>> ContainerType;
void extract(ContainerType &map_, const std::string &line_)
{
std::vector<std::string> data;
boost::split(data, line_, boost::is_any_of(","));
// This is not the best way - but it works for this demo.
map_[data[0]] = {std::stoi(data[1]),std::stoi(data[2]),std::stoi(data[3])};
}
int main()
{
ContainerType map;
std::ifstream inputFile;
inputFile.open("random.csv");
if(inputFile.is_open())
{
std::string line;
while( std::getline(inputFile,line))
{
if (line.empty())
continue;
else
extract(map,line);
}
inputFile.close();
}
for (auto &&i : map)
{
std::cout<< i.first << " : ";
for (auto &&j : i.second)
std::cout<< j << " ";
std::cout<<std::endl;
}
}
Hope this helps.

Variable inside for loop

I am frustrated. I am trying to find a way to get the variable called 'line' to be accessed inside of the for loop that is at the bottom of the code.
#include <ctime>
#include <iostream>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <vector>
#include <string>
#include <iostream>
#include <Lmcons.h>
#include <fstream>
#include <windows.h>
using namespace std;
string currentmonth;
string earlydays;
//**************************************
string a3;
string a1;
int getdir (string dir, vector<string> &files)
{
DIR *dp;
struct dirent *dirp;
if((dp = opendir(dir.c_str())) == NULL)
{
cout << "Error(" << errno << ") opening " << dir << endl;
return errno;
}
while ((dirp = readdir(dp)) != NULL) {
std::string fname = dirp->d_name;
if(fname.find("FIN804") != std::string::npos)
files.push_back(fname);
}
}
//***************************************
int main() {
//Copy New date to be used from date database
ifstream dailyfiledate;
dailyfiledate.open("Databasedate.txt");
string line;
if (!dailyfiledate) //checks to see if file opens properly
{
cerr << "Error: Failed to copy the first string from Date Database.";
}
else
{
if (getline(dailyfiledate, line)) // Get line
cout << line; // print the line.
dailyfiledate.close(); // Remember to close the file.
}
string dir = string(a1);
vector<string> files = vector<string>();
getdir(dir,files);
for (unsigned int i = 0; i < files.size();)
{
//cout << files[i] << endl;
a3 = files[i];
cout << a3 << endl;
string b1 = a3 + line;
cout << b1 << endl;
remove(b1.c_str());
i++;
}
}
Actually, the variable was successfully being reached inside the for loop. I guess it was an oversight on my path.
And there is absolutely no error in the code above when it's compiled.
You mo'effers really need to be more humble. Give the answer, give guidance, or don't comment at all.

Using the find() function with sets

I have just encountered this chapter in my book and I dont really understand how find() works. I tried to create a simple function to check how the find() function works, but I am getting a multitude of errors in my code.
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> setA(1,2);
int item;
cout << "Enter a number: ";
cin >> item;
int setIter;
setIter = setA.find(item);
if (setIter != setA.end())
{
cout << "It's in the list." << endl;
}
return 0;
}
Here is the correct implementation of your program...
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> setA;
setA.insert(1); // use insert function
setA.insert(2);
set<int>::iterator setIter; // take set iterator
int item;
cout << "Enter a number: ";
cin >> item;
setIter = setA.find(item);
if (setIter != setA.end())
{
cout << "It's in the list." << endl;
}
return 0;
}
You are making two mistakes in your program. First you are initializing set using constructor which does not work so you have to use insert function of set. Secondly you are taking iterator as an int which is not correct. Iterator is basically a pointer of set type. So you have to take the iterator of set
Your code has two issues- first is the usage of constructor and the other is assigning set iterator returned by set.find() to an int. Here is the corrected code:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> setA({1,2});
int item;
cout << "Enter a number: ";
cin >> item;
set<int>::iterator setIter = setA.find(item);
if (setIter != setA.end())
{
cout << "It's in the list." << endl;
}
return 0;
}