C++ getline segmentation fault, std::vector<custom class> - c++

I've been looking at this for a while in the debugger while Googling around, but I think I've stumbled upon some C++ behavior that I'm not familiar with. I'm going to give a quick outline on what I'm doing and what/where the problem is. I'll put code block below.
The rough outline of what's happening is:
Created a custom class (LogReader) to handle a single log file.
LogReader contains a pointer to an ifstream (ifstream *log_file)
The ifstream is used with getline() in the constructor, this works fine.
The LogReader is placed in a vector.
The code below for main.cpp is using the LogReader directly (without the vector). The segfault occurs in both cases.
LogReader.advance() is called. getline() is used in this function. The segfault occurs here (commented in LogReader.cpp).
Thanks for any help on what C++ behaviors I'm missing that might be causing this!
EDIT: Not placing the LogReader into a vector removes the segfault (failing elsewhere now, but not a problem). The change is commenting the following line out in main.cpp
readers.push_back(&label_reader);
I guess now the question is why using std::vector is causing this problem.
LogReader.h
#ifndef LOGREADER
#define LOGREADER
using namespace std;
class LogReader {
private:
LogReader(){} // private default constructor
public:
ifstream *log_file; // file the log is read from
vector<int> val_locations; // offsets in line for values
string next_line; // next line from the file
int current_time; // time for most recent reading
string current_line;
int next_time; // what is the next time in the file
vector<string> current_vals; // what the current vals are
LogReader(string log_loc, vector<int> offsets); // given a file to start on
bool advance(int new_time); // advance the log reader, return true if advanced
bool has_more(); // is there more in the log
};
#endif
LogReader.cpp
// c++ imports
#include <boost/algorithm/string.hpp>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
// my imports
#include "LogReader.h"
#include "functions.h"
using namespace std;
LogReader::LogReader(string log_loc, vector<int> offsets){
// make the file reader
ifstream lf(log_loc);
log_file = &lf;
// pull out the first line
getline(*log_file, current_line);
cout << current_line << endl;
// get the set of current values
val_locations = offsets;
for(int i = 0; i < val_locations.size(); i++) {
current_vals.push_back(get_line_part(current_line,
val_locations.at(i)));
}
// get the current time
current_time = stoi(get_line_part(current_line, 0));
// pull down the next line
getline(*log_file, next_line);
cout << next_line << endl;
// get the next time
next_time = stoi(get_line_part(next_line, 0));
}
bool LogReader::advance(int new_time){
if(new_time < next_time)
return false; // nothing to do, current still good
cout << "can check time" << endl;
// update the time and values
current_time = next_time;
current_line = next_line;
current_vals.clear();
cout << "can do housekeeping" << endl;
for(int i = 0; i < val_locations.size(); i++) {
current_vals.push_back(get_line_part(next_line,
val_locations.at(i)));
}
cout << "can push in new values" << endl;
// move the line
next_line.clear();
if(!getline(*log_file, next_line)) { // **SEGFAULT**
// no more lines
cout << "no more lines" << endl;
next_line.clear();
next_time = -1;
return true;
}
cout << "got the line" << endl;
// update the time as well
next_time = stoi(get_line_part(next_line, 0));
return true;
}
bool LogReader::has_more(){
return next_time != -1;
}
main.cpp
// c imports
#include <time.h>
// c++ imports
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/date_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
// my imports
#include "LogReader.h"
#include "functions.h"
// custom shorter namespaces
namespace bfs = boost::filesystem;
// used namespaces
using namespace std;
void update_line(int *current_time, string *current_line,
ifstream *current_file){
if(!getline(*current_file, *current_line)){
*current_time = -1;
current_line->clear();
return;
}
try {
*current_time = stoi(get_line_part(*current_line, 0));
} catch (int e) {
cout << "update line, bad stoi on time" << endl;
cout << *current_line << endl;
throw e;
}
}
void update_vals(vector<float*> vals, string line) {
for(int i = 0; i < vals.size(); i++) {
// offset for fact that first two are time and sensor
try {
*(vals.at(i)) = stof(get_line_part(line, 2 + i));
} catch (int e) {
cout << "update_vals, bad stof for " << i << endl;
cout << line << endl;
throw e;
}
}
}
string get_correct_file(string name, vector<string> options) {
for(int i =0; i < options.size(); i++) {
string option = options.at(i);
if(boost::algorithm::contains(option, name)){
return option;
}
}
return string("");
}
int main(int argc, char* argv[]) {
// open the base dir
bfs::path base_dir("log/");
if(!bfs::exists(base_dir) && !bfs::is_directory(base_dir)){
cout << "Bad base directory" << endl;
return 1;
}
// create a vector of the possible traces
vector<string> traces;
for(bfs::directory_iterator iter(base_dir);
iter != bfs::directory_iterator(); iter++) {
stringstream trace_path;
trace_path << iter->path().string();
traces.push_back(trace_path.str());
}
int trace_index = user_choose_option(traces);
// load that directory
bfs::path trace_dir(traces.at(trace_index));
if(!bfs::exists(base_dir) && !bfs::is_directory(base_dir)){
cout << "Selected a bad trace directory" << endl;
return 1;
}
// get the image directory
cout << "loading image directory" << endl;
string img_path_string = trace_dir.string();
stringstream img_path_stream;
img_path_stream << img_path_string << "/img/";
bfs::path img_dir(img_path_stream.str());
if(!bfs::exists(img_dir) && !bfs::is_directory(img_dir)){
cout << "no image directory" << endl;
return 1;
}
// get image list, ends up in sorted order from naming conventions
cout << "getting image paths" << endl;
vector<string> image_paths;
for(bfs::directory_iterator iter(img_dir);
iter != bfs::directory_iterator(); iter++) {
stringstream image_path;
image_path << iter->path().string();
image_paths.push_back(image_path.str());
}
// get the data traces
cout << "loading data traces" << endl;
vector<string> log_paths;
vector<string> label_paths;
string trace_path_string = trace_dir.string();
for(bfs::directory_iterator iter(trace_path_string);
iter != bfs::directory_iterator(); iter++) {
string cur_file = iter->path().string();
cout << cur_file << endl;
if(boost::algorithm::contains(cur_file, "label-")) {
label_paths.push_back(cur_file);
} else if(boost::algorithm::contains(cur_file, "log-")) {
log_paths.push_back(cur_file);
}
}
cout << endl;
// temp for reading in line parts
// istringstream temp;
cout << "getting log readers" << endl;
// choose the label file to use, get first line
int label_index = user_choose_option(label_paths);
vector<int> label_offsets;
label_offsets.push_back(1);
LogReader label_reader(label_paths.at(label_index), label_offsets);
/*
ifstream label_file(label_paths.at(label_index));
string label_line;
getline(label_file, label_line);
int label_time;
temp.clear();
temp.str(get_line_part(label_line, 0));
temp >> label_time;
string label_current = get_line_part(label_line, 1);
*/
/*
// get the accel
string accel_path = get_correct_file("accel", log_paths);
vector<int> accel_offsets;
accel_offsets.push_back(2);
accel_offsets.push_back(3);
accel_offsets.push_back(4);
LogReader accel_reader(accel_path, accel_offsets);
*/
vector<LogReader*> readers;
vector<bool> updated;
readers.push_back(&label_reader);
updated.push_back(true);
// readers.push_back(&accel_reader);
// updated.push_back(true);
int l_time = current_time_min(readers);
while(label_reader.has_more() ){ // || accel_reader.has_more()) {
// figure out what time to advance to
int n_time;
cout << label_reader.has_more() << endl;
if(same_current_time(readers)) {
n_time = next_time_min(readers);
} else {
n_time = current_time_nextmin(readers);
}
cout << n_time << endl;
label_reader.advance(n_time);
cout << label_reader.current_line << endl;
/*
// advance all the readers
for(int i = 0; i < readers.size(); i++) {
cout << "loop " << i << endl;
// keep track of which values updated
readers.at(i);
cout << "can get from vector" << endl;
bool advanced = readers.at(i)->advance(n_time);
cout << advanced << endl;
if(advanced) {
updated.at(i) = true;
} else {
updated.at(i) = false;
}
}
// sanity check printing
for(int i = 0; i < readers.size(); i++) {
cout << readers.at(i)->current_line << endl;
}
*/
// deal with statistics here
}
/*
ifstream accel_file(accel_path);
string accel_line;
getline(accel_file, accel_line);
int accel_time;
temp.clear();
temp.str(get_line_part(accel_line, 0));
temp >> accel_time;
float accel_current_x = stof(get_line_part(accel_line, 2));
float accel_current_y = stof(get_line_part(accel_line, 3));
float accel_current_z = stof(get_line_part(accel_line, 4));
vector<float*> accel_vals;
accel_vals.push_back(&accel_current_x);
accel_vals.push_back(&accel_current_y);
accel_vals.push_back(&accel_current_z);
// get the sprox
string sprox_path = get_correct_file("sprox", log_paths);
ifstream sprox_file(sprox_path);
string sprox_line;
getline(sprox_file, sprox_line);
int sprox_time;
temp.clear();
temp.str(get_line_part(sprox_line, 0));
temp >> sprox_time;
float sprox_current = stof(get_line_part(sprox_line, 2));
vector<float*> sprox_vals;
sprox_vals.push_back(&sprox_current);
// get the lprox
string lprox_path = get_correct_file("lprox", log_paths);
ifstream lprox_file(lprox_path);
string lprox_line;
getline(lprox_file, lprox_line);
int lprox_time;
temp.clear();
temp.str(get_line_part(lprox_line, 0));
temp >> lprox_time;
float lprox_current = stof(get_line_part(lprox_line, 2));
vector<float*> lprox_vals;
lprox_vals.push_back(&lprox_current);
// get the light
string light_path = get_correct_file("light", log_paths);
ifstream light_file(light_path);
string light_line;
getline(light_file, light_line);
int light_time;
temp.clear();
temp.str(get_line_part(light_line, 0));
temp >> light_time;
float light_current = stof(get_line_part(light_line, 2));
vector<float*> light_vals;
light_vals.push_back(&light_current);
*/
// int time_current = min(label_time, min(sprox_time,
// min(lprox_time, min(accel_time,
// light_time))));
/*
// variables for processing here
int total_time = 0;
map<string, int> label_counts;
while(label_time != -1 || accel_time != -1 || sprox_time != -1
|| lprox_time != -1 || light_time != -1) {
time_current++;
if(label_time != -1 && time_current > label_time) {
update_line(&label_time, &label_line, &label_file);
if(label_line.size() > 0) // if last label, don't overwrite
label_current = get_line_part(label_line, 1);
}
if(accel_time != -1 && time_current > accel_time) {
update_line(&accel_time, &accel_line, &accel_file);
if(accel_line.size() > 0) // if last line, don't overwrite
update_vals(accel_vals, accel_line);
}
if(sprox_time != -1 && time_current > sprox_time) {
update_line(&sprox_time, &sprox_line, &sprox_file);
if(sprox_line.size() > 0) // if last line, don't overwrite
update_vals(sprox_vals, sprox_line);
}
if(lprox_time != -1 && time_current > lprox_time) {
update_line(&lprox_time, &lprox_line, &lprox_file);
if(lprox_line.size() > 0) // if last line, don't overwrite
update_vals(lprox_vals, lprox_line);
}
if(light_time != -1 && time_current > light_time) {
update_line(&light_time, &light_line, &light_file);
if(light_line.size() > 0) // if last line, don't overwrite
update_vals(light_vals, light_line);
}
// Processing happens here
total_time++;
if(label_counts.count(label_current) == 0)
// not in map
label_counts[label_current] = 0;
label_counts[label_current]++;
}
// post processing happens here
cout << "Labels Counts:" << endl;
for(map<string, int>::iterator it = label_counts.begin();
it != label_counts.end(); it++) {
cout << it->first << " -> " << it->second << " -> ";
cout << 1.0 * it->second / total_time << endl;
}
*/
}

Your program exhibits undefined behavior since you are using a pointer to an object that has been deleted.
ifstream lf(log_loc);
log_file = &lf;
if gets deleted when the constructor returns and you are still holding on to a pointer to the object.
Change log_file to an object instead of a pointer.

Related

unable to get return data from class in .hpp file

I have 2 files: main.cpp and parser.hpp
I am returning vector<vector> from a member function in class in parser.hpp. However it seems I am not getting anything in my main.cpp from the return value because when I print its size I get 0.
This is my main.cpp:
#include <vector>
#include <cstring>
#include <fstream>
#include <iostream>
#include "parser.hpp"
using namespace std;
int main()
{
ifstream file;
file.open("test.csv");
csv obj;
obj.parse(file);
obj.print_parsed_csv(file);
vector<vector<string>> parsed_csv_data = obj.parse(file);
cout << parsed_csv_data.();
cout << parsed_csv_data.size();
for (int i = 0; i < parsed_csv_data.size(); i++)
{
for (int j = 0; j < parsed_csv_data[i].size(); j++)
cout << parsed_csv_data[i][j] << '\t';
cout << endl;
}
}
This is my parser.hpp
using namespace std;
class csv
{
public:
vector<vector<string>> parse(ifstream &file)
{
string str;
vector<vector<string>> parsed_data;
while (getline(file, str))
{
vector<string> parsed_line;
while (!str.empty())
{
int delimiter_pos = str.find(',');
string word = str.substr(0, delimiter_pos);
// cout << word << " ";
if (delimiter_pos == -1)
{
parsed_line.push_back(word);
break;
}
else
{
str = str.substr(delimiter_pos + 1);
// cout << str << endl;
parsed_line.push_back(word);
}
}
parsed_data.push_back(parsed_line);
}
return parsed_data;
}
void print_parsed_csv(ifstream &file)
{
vector<vector<string>> parsed_csv_data = parse(file);
cout << parsed_csv_data.size();
for (int i = 0; i < parsed_csv_data.size(); i++)
{
for (int j = 0; j < parsed_csv_data[i].size(); j++)
cout << parsed_csv_data[i][j] << '\t';
cout << endl;
}
}
};
I am getting correct cout output in parse() only. print_parsed_csv() in parser.hpp and the cout in main.cpp both are giving 0 as the variable's size.
How do I resolve this?
The first time you call obj.parse the stream object is read from until you get to the end of the file. You need to either reopen the file or reset file to point back to the beginning of the file after reading from it.
You pass the same file variable to each of the three functions below but only the first one works. The first call to obj.parse moves where file is pointing in the input file. When obj.parse exits the first time, file is pointing to the end of the file so when it's used in the subsequent 2 calls, there's nothing to read.
obj.parse(file); // <-- this works fine
obj.print_parsed_csv(file); // <-- this fails
vector<vector<string>> parsed_csv_data = obj.parse(file);fails
// ^^^^^^^^^- this fails
See this question for answers on how to reset the ifstream to the beginning of the file.

How to fix my topological.cpp outputting error?

i have been provided middleearth.h/cpp and was asked to make a makefile, doxyfile (which i did correctly) and a topological.cpp that works but has a small mistake in the output and i need help with that please.ill provide all three files and the text we use to test and the error.
cs2110 cs2150
cs2102 cs2150
cs1110 cs2110
cs3330 cs4414
cs2150 cs4414
cs2110 cs3330
cs1110 cs2102
0 0
middleearth.h
#ifndef MIDDLEEARTH_H
#define MIDDLEEARTH_H
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <random>
using namespace std;
// see the comments in the lab11 write-up, or in middleearth.cpp
class MiddleEarth {
public:
MiddleEarth(int xsize, int ysize, int num_cities, int seed);
void print();
void printTable();
float getDistance(const string& city1, const string& city2);
vector<string> getItinerary(unsigned int length);
private:
int num_city_names, xsize, ysize;
unordered_map<string, float> xpos, ypos;
vector<string> cities;
unordered_map<string, unordered_map<string, float>> distances;
mt19937 gen; // Mersenne-Twister random number engine
};
#endif
middleearth.cpp
#include "middleearth.h"
#include <algorithm>
#include <array>
#include <cstdlib>
#include <cmath>
// New shuffle method that uses the Mersenne Twister engine
void shuffle (vector<string>::iterator first, vector<string>::iterator last, mt19937& g) {
for (auto i=(last-first)-1; i>0; --i) {
unsigned int n = (g() / (double) g.max())*distance(first,last);
swap (first[i], first[n]);
}
}
// The list of all the place names that we'll be using
const array<string, 40> all_city_names{
// human towns, cities and strongholds
"Bree", // a human and hobbit town between the Shire and Rivendell
"Isengard", // the tower fortress where Saruman resided; Gandalf was imprisoned there.
"Minas Tirith", // capital of Gondor, the "white city"; home to Boromir, Denethor, and later, Aragorn
"Osgiliath", // city on the river Anduin; is at the other end of Pelennor Fields from M. Tirith
"Edoras", // the capital city of Rohan, where King Theoden resides
"Helm's Deep", // fortress of Rohan, it is where the people of Edoras fled to from the orc invasion
"Dunharrow", // a refuge of Rohan, it is where Elrond presents the sword to Aragorn in the movie
// dwarf cities
"Moria", // the enormous dwarven underground complex that the Fellowship traveled through
// elvish cities
"Lothlorien", // the elvish tree-city, home of Lady Galadriel and Lord Celeborn
"Rivendell", // the elvish city that is home to Lord Elrond
"The Grey Havens", // the port city on the western coast from which the elves travel westward
// hobbit villages
"Bucklebury", // a Shire village, it has a ferry across the Brandywine River that the Hobbits use
"Bywater", // a Shire village, it is the site of the Battle of Bywater (removed from the movie)
"Hobbiton", // a Shire village, it is home to Bilbo and, later, Frodo
"Michel Delving", // a Shire village, it is the chief town of the Shire
// Mordor places
"Orodruin", // Mount Doom in Mordor, it is where the Ring was made, and later, unmade
"Barad-Dur", // Sauron's fortress that was part castle, part mountain
"Minas Morgul", // formerly the Gondorian city of Minas Ithil; renamed when Sauron took it over
"Cirith Ungol", // the mountianous pass that Sam & Frodo went through; home of Shelob
"Gorgoroth", // the plains in Mordor that Frodo & Sam had to cross to reach Mount Doom
// places that are not cities
"Emyn Muil", // the rocky region that Sam & Frodo climb through after leaving the Fellowship
"Fangorn Forest", // the forest where Treebeard (and the other Ents) live
"Dagorlad", // great plain/swamp between Emyn Muil & Mordor where a great battle was fought long ago
"Weathertop", // the tower between Bree and Rivendell where Aragorn and the Hobbits take refuge
"Gladden Fields", // this is where the Ring is lost in the River Anduin, after Isildur is ambushed and killed by Orcs
"Entwash River", // a river through Rohan, which flows through Fangorn Forest
"River Isen", // river through the Gap of Rohan; Theoden's son was slain in a battle here.
"The Black Gate", // huge gate to Mordor that Aragorn and company attack as the ring is destroyed
"The Old Forest", // a forest to the west of the Shire (adventures there were removed from the movie)
"Trollshaws", // area to the west of Rivendell that was home to the trolls that Bilbo met
"Pelennor Fields", // great plain between M. Tirith and Osgiliath; site of the Battle of M. Tirith
"Hollin", // the empty plains that the Fellowship crosses between Rivendell and Moria
"Mirkwood", // Legolas' forest home; Bilbo travels there in 'The Hobbit'.
"Misty Mountains", // the north-south moutain range that runs through Middle-earth
"Prancing Pony", // an inn in Bree where the hobbits tried to meet Gandalf, but meet Aragorn instead
// places from the Hobbit book and movies
"Laketown", // also called Esgaorth, it is the town of men on the Long Lake near Erebor
"Dale", // the town of men outside Erebor, destroyed by Smaug long before the Hobbit story
"Erebor", // the Elvish name for the Lonely Mountain, where the dwarves had their fortress
"Beorn's House", // Beorn is the shape-shifter who shelters the dwarf party
"Dol Guldur", // fortress in Mirkwood where Sauron, as the Necromancer, hid during most of the Hobbit
};
// Iluvatar, the creator of Middle-Earth
MiddleEarth::MiddleEarth(int xsize, int ysize, int num_cities, int seed) {
this->xsize = xsize;
this->ysize = ysize;
// set up the random number generator
gen.seed(seed == -1 ? random_device{}() : seed);
// count the number of cities in the array
this->num_city_names = all_city_names.size();
if (num_cities > num_city_names) {
cout << "There are only " << num_city_names << " city names, so "
<< num_cities << " cities cannot be created." << endl;
cout << "Exiting." << endl;
exit(0);
}
if (num_cities < 5) {
num_cities = 5;
}
// copy all the cities into a mutable vector
this->cities = vector<string>(all_city_names.begin(), all_city_names.end());
shuffle(cities.begin(), cities.end(), gen); // shuffle all the cities
cities.erase(cities.begin() + num_cities, cities.end()); // then remove the ones we won't be using
// compute random city positions
for (auto city : cities) {
xpos.emplace(city, (gen() / (double) gen.max()) * xsize);
ypos.emplace(city, (gen() / (double) gen.max()) * ysize);
}
// compute the 2-d distance array
// we assume that num_cities < xsize * ysize
for (auto city1 : cities) {
for (auto city2 : cities) {
distances[city1].emplace(city2, sqrt((xpos[city2] - xpos[city1]) * (xpos[city2] - xpos[city1]) +
(ypos[city2] - ypos[city1]) * (ypos[city2] - ypos[city1])));
}
}
}
// The Mouth of Sauron!
// Prints out info on the created 'world'
void MiddleEarth::print() {
cout << "there are " << num_city_names
<< " locations to choose from; we are using " << cities.size() << endl;
cout << "they are: " << endl;
for (auto city : cities) {
cout << "\t" << city << " # (" << xpos[city] << ", " << ypos[city]
<< ")" << endl;
}
}
// Prints a tab-separated table of the distances,
// which can be loaded into Excel or similar
void MiddleEarth::printTable() {
cout << "Table: " << endl << endl << "Location\txpos\typos\t";
for (auto city : cities) {
cout << city << "\t";
}
cout << endl;
for (auto city1 : cities) {
cout << city1 << "\t" << xpos[city1] << "\t" << ypos[city1] << "\t";
for (auto city2 : cities) {
cout << distances[city1][city2] << "\t";
}
cout << endl;
}
}
// This method returns the distance between the two passed cities.
// If we assume that the hash table (i.e. the map) is O(1),
// then this method call is also O(1)
float MiddleEarth::getDistance(const string& city1, const string& city2) {
return distances[city1][city2];
}
// Returns the list of cities to travel to.
// The first city is the original start point as well as the end point.
// The number of cities passed in does not include this start/end point
// (so there will be length+1 entries in the returned vector).
vector<string> MiddleEarth::getItinerary(unsigned int length) {
// check parameter
if (length >= cities.size()) {
cout << "You have requested an itinerary of " << length
<< " cities; you cannot ask for an itinerary of more than length "
<< cities.size() - 1 << endl;
exit(0);
}
length++; // to account for the start point
// we need to make a deep copy of the cities vector
vector<string> itinerary(cities.begin(), cities.end());
// shuffle, erase unneeded ones, and return the itinerary
shuffle(itinerary.begin(), itinerary.end(), gen);
itinerary.erase(itinerary.begin() + length, itinerary.end());
return itinerary;
}
topological.cpp
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <list>
#include <stack>
#include <string>
#include <map>
using namespace std;
/**
#date 11/16/2020
*/
/** #brief
*/
class Graph
{
public:
Graph(int vert);
/** #brief adds an edge to the list
* #param string v
* #param string w
* #param map<string, int> m
*
*/
void addEdge(string v, string w, map<string, int> m);
void printSort();
private:
int vertices;
list<int> *myList;
void sort(int v, stack<int> &myStack, bool visited[]);
map<int, string> myMap;
};
Graph::Graph(int vert) {
vertices = vert;
myList = new list<int>[vertices];
}
void Graph::addEdge(string v, string w, map<string, int> m) {
int loc1 = m[v];
int loc2 = m[w];
myMap[loc1] = v;
myMap[loc2] = w;
myList[loc1].push_back(loc2);
}
void Graph::sort(int v, stack<int> &myStack, bool visited[]) {
visited[v] = true;
list<int>::iterator i;
for(i = myList[v].begin(); i != myList[v].end(); ++i) {
if(!visited[*i]) {
sort(*i, myStack, visited);
}
}
myStack.push(v);
}
void Graph::printSort() {
stack<int> myStack;
bool *visited = new bool[vertices];
for(int i = 0; i < vertices; i++) {
visited[i] = false;
}
for(int i = 0; i < vertices; i++) {
if(visited[i] == false)
sort(i, myStack, visited);
}
while(myStack.empty() == false) {
int x = myStack.top();
string output = myMap[x];
cout << output << " ";
myStack.pop();
}
}
int main (int argc, char **argv) {
if ( argc != 2 ) {
cout << "Must supply the input file name as the one and only parameter" << endl;
return 1;
}
ifstream file(argv[1], ifstream::binary);
ifstream file1(argv[1], ifstream::binary);
if ( !file.is_open() ) {
cout << "Unable to open file '" << argv[1] << "'." << endl;
return 1;
}
string s1, s2;
int count = 0;
list <string> edges;
while(!file.eof()) {
file >> s1;
file >> s2;
if(s1 == "0" && s2 == "0") {
break;
}
edges.push_back(s1);
edges.push_back(s2);
}
file.close();
edges.sort();
edges.unique();
int size = edges.size();
map<string, int> myMap;
Graph myGraph(size);
list<string>::iterator i;
for(i = edges.begin(); i != edges.end(); i++) {
string s = *i;
myMap[s] = count;
count++;
}
while(!file1.eof()) {
file1 >> s1;
file1 >> s2;
if(s1 == "0" && s2 == "0") {
break;
}
myGraph.addEdge(s1, s2, myMap);
}
myGraph.printSort();
cout<<endl;
file1.close();
return 0;
}
You are confusing yourself. You have your solution in edges. There isn't a reason to read the data a second time. For example, you can simply output sorted/unique elements of edges, e.g. the modifications to your code are:
int main (int argc, char **argv) {
if ( argc != 2 ) {
cout << "Must supply the input file name as the one and only parameter" << endl;
return 1;
}
ifstream file(argv[1], ifstream::binary);
// ifstream file1(argv[1], ifstream::binary);
if ( !file.is_open() ) {
cout << "Unable to open file '" << argv[1] << "'." << endl;
return 1;
}
string s1, s2;
// int count = 0;
list <string> edges;
while(file >> s1 && file >> s2) {
if(s1 == "0" && s2 == "0") {
break;
}
edges.push_back(s1);
edges.push_back(s2);
}
file.close();
edges.sort();
edges.unique();
// int size = edges.size();
// map<string, int> myMap;
bool first = true;
for (const auto& n : edges) {
if (!first)
cout.put(' ');
cout << n;
first = false;
}
cout.put('\n');
// Graph myGraph(size);
// list<string>::iterator i;
// for(i = edges.begin(); i != edges.end(); i++) {
// string s = *i;
// myMap[s] = count;
// count++;
// }
//
// while(file1 >> s1 && file1 >> s2) {
// if(s1 == "0" && s2 == "0") {
// break;
// }
// myGraph.addEdge(s1, s2, myMap);
// }
//
// myGraph.printSort();
// cout<<endl;
// file1.close();
return 0;
}
(note: how while (!file.eof())) was replaced with while(file >> s1 && file >> s2))
Example Use/Output
With your sample data in dat/topological.txt, you would receive:
$ ./bin/topological dat/topological.txt
cs1110 cs2102 cs2110 cs2150 cs3330 cs4414
If you are having problems editing your code, then you can do things much easier with a std::set, e.g.
#include <iostream>
#include <fstream>
#include <string>
#include <set>
int main (int argc, char **argv) {
if ( argc != 2 ) {
std::cerr << "Must supply the input file name as the one and only parameter\n";
return 1;
}
std::set<std::string> strset {};
std::string s {};
std::ifstream f (argv[1]);
if (!f.good()) {
std::cerr << "file open failed.\n";
return 1;
}
while (f >> s && s != "0")
strset.insert(s);
bool first = true;
for (const auto& unique : strset) {
if (!first)
std::cout.put(' ');
std::cout << unique;
first = false;
}
std::cout.put('\n');
}
(same answer)
This is when i used the main you gave me:
enter image description here
This is when i added (Yes. after edges.unique(); you can simply do. bool first = true; for (const auto& n : edges) { if (!first) cout.put(' '); cout << n; first = false; } cout.put('\n');):
enter image description here
the first line on output is correct, i dont want the line under it

how to push and pop elements read from a textfile to an array in c++ and output the stack in revserse order?

Hi I am new to c++ and am having trouble understanding on how I would push and pop elements read from a text file to an array and displaying those elements in reverse order for example if i have a text file called hero.txt with elements Goku Luffy Naruto I would like the output to be Naruto Luffy Goku
this is what I have so far
string hero[100]; // array to store elements
int count=0;
int main()
{
fstream myfile;
string nameOffile;
string text;
string mytext;
cout << "Enter name of file" << endl;
cin >> nameOffile
myfile.open(nameOffile.c_str());
if (!myfile)
{
cerr << "error abort" << endl;
exit(1);
}
while (myfile >> text )
{
Push(mytext); //Note I know this is wrong I just don't know how to write it in a manner that will push the first element of the textfile to the top
}
myfile.close();
while(hero[count]=="")
{
//Again I know these two lines are incorrect just don't know how to implement in correct manner
cout <<hero[0] << " " <<endl;
Pop(mytext);
}
}
// Function for push
void Push(string mytext)
{
count = count + 1;
hero[count] = mytext;
}
void Pop(string mytext)
{
if(count=0)
{
mytext = " ";
}
else
{
mytext = hero[count];
count = count - 1;
}
}
Normally, a stack will begin with index = -1 to indicate that the stack is empty. So you need to replace
int count = 0
with
int count = -1
After you do all the pushing, your stack will look like this:
hero[0] = "Goku"
hero[1] = "Luffy"
hero[2] = "Naruto"
Now, to print it out in reverse order, you can just loop from the last index to the first. After pushing all the heroes string, count is now equal to 2. The last heroes will be at index = 0. So you can rewrite the loop as
while(count >= 0)
{
cout << hero[count] << " " <<endl;
Pop();
}
Your Pop function is also incorrect. In the if statement, you will replace the value of count to 0. What you need to do in Pop is just to decrement the value of count.
So you can rewrite it as
void Pop()
{
count = count - 1;
}
The vector class defined in the standard library acts like a stack.
For example:
// include the library headers
#include <vector>
#include <string>
#include <iostream>
// use the namespace to make the code less verbose
using namespace std;
int main()
{
// declare the stack
vector<string> heroStack;
// insert the elements
heroStack.push_back("Goku");
heroStack.push_back("Luffy");
heroStack.push_back("Naruto");
// print elements in reverse order
while(!heroStack.empty())
{
// get the top of the stack
string hero = heroStack.back();
// remove the top of the stack
heroStack.pop_back();
cout << hero << endl;
}
}
ok let's tart by improving your functions
push function works good but just change the order of it to be like this
void Push(string mytext)
{
hero[count] = mytext; //now you will start at index 0
count = count + 1;
}
pop function should be like this
you need to return a string value and you don't need to pass a parameter
string Pop()
{
if(count == 0)
{
return "";
}
else
{
count = count - 1;
mytext = hero[count];
return mytext;
}
}
now you are functions are ready let's use them
you are using the push function correctly in your main
we need to change the while which displays the output
it should be like this
while(true)
{
tempText = pop(); // this function will get you the last element and then remove it
if ( tempText == "" ) // now we are on top of the stack
break;
cout <<tempText << " " <<endl;
}
#include "stdafx.h"
#include <fstream>
#include <stack>
#include <string>
#include <iostream>
class ReadAndReversePrint
{
std::stack<std::string> st;
std::ifstream file;
public:
ReadAndReversePrint(std::string path)
{
file.open(path);
if (file.fail())
{
std::cout << "File Open Failed" << std::endl;
return;
}
std::string line;
while (!file.eof())
{
file >> line;
st.push(line);
}
file.close();
std::cout << "Reverse printing : " << std::endl;
while (!st.empty())
{
std::cout << st.top().c_str() << "\t";
st.pop();
}
std::cout << std::endl;
}
};
int main()
{
ReadAndReversePrint rrp("C:\\awesomeWorks\\input\\reverseprint.txt");
return 0;
}

C++ accessing vector of vector got segmentation fault

I created a vector of vector (10*10000) and try to access this vector through member function. but I got a segmentation fault. I don't know what's wrong here...
Here is Simple.h
class Simple
{
private:
std::vector<double> data_row;
std::vector<std::vector<double> > data;
public:
Simple():data_row(10000), data(10, data_row){};
/*initialize data vector*/
int getSampleCounts(std::istream &File);
/*return number of packet samples in this file*/
Result getModel(std::istream &File);
/*return average and variance of simple delta time*/
void splitData (std::istream &File, const int & sample_in_fold);
};
#endif /* SIMPLE_H */
here is Simple.cpp
void Simple::splitData(std::istream& File, const int & sample_in_fold) {
double value = 0.0;
bool isFailed = true;
int label = 0;
while (File >> value) {
// for each value, generate a label
srand(time(NULL));
label = rand() % 10; // generate label between 0 to 9
while (isFailed) {
// segmentation fault in the next line!
std::cout << "current data size is: " << this->data.size() <<endl;
std::vector<double>::size_type sz = this->data[label].size();
if (sz <= sample_in_fold) {
std::cout << "current size is " << sz << "< samples in fold: " << sample_in_fold << endl;
this->data[label].push_back(value);
std::cout << "push_back succeed!" << endl;
isFailed = false;
} else {
std::cout << "label " << label << "if full. Next label. \n";
srand(time(NULL));
label = rand() % 10;
sz = this->data[label].size();
}
}
}
}
and I'm attaching the main file here.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib> // for system())
#include <sys/types.h>
#include <dirent.h>
#include <vector>
#include <limits.h> // for PATH_MAX
#include "Complex.h"
#include "Result.h"
#include "Simple.h"
#include <math.h>
using namespace std;
int main(int argc, char ** argv) {
struct dirent *pDirent;
DIR *pDir;
std::string line;
// check for args
if (argc == 1) {
printf("Usage: ./main + folder name. \n");
return 1;
}
pDir = opendir(argv[1]);
if (pDir == NULL) {
printf("Cannot open directory '%s' \n", argv[1]);
return 1;
}
// readdir returns a pointer to the next direcctory entry dirent structure
while ((pDirent = readdir(pDir)) != NULL) {
// get file name and absolute path
char *name = pDirent->d_name;
char buf[PATH_MAX + 1];
realpath(name, buf);
// std::cout << "Current file is: " << (pDirent->d_name) << endl;
if (has_suffix(pDirent->d_name, ".txt")) {
printf("[%s]\n", pDirent->d_name);
//printf("absolute path is %s. \n", buf);
ifstream infile;
// open file with absolute path
infile.open(buf, ios::in);
if (!infile) {
cerr << "Can't open input file " << buf << endl;
exit(1);
}
//processing for simple pattern
if (has_suffix(name, "testfile.txt")) {
Simple* simple_obj;
int number = simple_obj->getSampleCounts(infile);
Result simplerst = simple_obj->getModel(infile);
std::cout << "Number of delta time is " << number << endl;
infile.clear();
infile.seekg(0);
write_to_file(pDirent->d_name, simplerst);
// divide data into k = 10 folds, get number of data in each fold
int sample_in_fold = floor(number / 10);
std::cout << sample_in_fold << std::endl;
simple_obj->splitData(infile, sample_in_fold);
}
} else {
// printf("This is not a txt file. Continue\n");
}
}
closedir(pDir);
return 0;
}
And here is a sample testfile.txt. I only copied part of the original file, for illustration.
10.145906000
10.151063000
10.131083000
10.143461000
10.131745000
10.151285000
10.147493000
10.123198000
10.144975000
10.144484000
10.138129000
10.131634000
10.144311000
10.157710000
10.138047000
10.122754000
10.137675000
10.204973000
10.140399000
10.142194000
10.138388000
10.141669000
10.138056000
10.138679000
10.141415000
10.154170000
10.139574000
10.140207000
10.149151000
10.164629000
10.106818000
10.142431000
10.137675000
10.204973000
10.140399000
10.142194000
10.138388000
10.141669000
10.138056000
10.138679000
10.141415000
Here is Result.h
#ifndef RESULT_H
#define RESULT_H
typedef struct Result {
double average;
double sigma;
}Result;
and getModel function in Simple.cpp:
Result Simple::getModel(std::istream &File) {
double value = 0.0;
double average = 0.0;
double sum = 0.0;
double counter = 0.0;
double sumsqr = 0.0;
double var = 0.0;
double sigma = 0.0;
while (File >> value) {
++counter;
sum += value;
sumsqr += value * value;
}
average = sum / counter;
var = sumsqr / counter - average * average; //E(x^2) - (E(x))^2
sigma = sqrt(var);
std::cout << "average is " << average << std::endl;
std::cout << "std deviation is " << sigma << std::endl;
File.clear();
File.seekg(0);
Result result = {average, sigma};
return result;
}
One issue right away:
Simple* simple_obj;
int number = simple_obj->getSampleCounts(infile);
simple_obj is an uninitialized pointer, thus your program exhibits undefined behavior at this point.
Why use a pointer anyway? You could have simply done this to avoid the issue:
Simple simple_obj;
simple_obj.getSampleCounts(infile);
Also, this line may not be an issue, but I'll mention it anyway:
Result simplerst = simple_obj->getModel(infile);
We already know that in your original code, simple_obj is bogus, but that's not the issue here. If Result is an object, and that object does not have correct copy semantics, then that assignment will also cause undefined behavior.
You've got a couple of uses of endl without specifying std::endl (they're not the same thing - you always have to type the std:: ). Is endl silently referring to another variable somewhere else?

Reading multiple files one by one

I am almost done with my project, but I still have one small thing that needs to be done...I need to run the entire program for each file in the directory. There are about 200 files in total. Below is the main class of the program that needs to run. I'm thinking I will put the entire thing in a do-while loop and run it until there are no more .dat files in the directory, but I'm not sure if that will work. Obviously, I'd like to replace the hard-coded file names with variables...I'm just not sure how to do that, either. Please let me know if you need clarification. I've been working on this project for a while and I'm getting kind of brain-numb. Thanks in advance for your help!
Edit My test directory is on a Windows machine, but it will be uploaded to a linux machine at school.
int main() {
NearestNeighbor face;
//string path = "C:\Users\Documents\NetBeansProjects\CSCE350";
//string searchPattern = "*dat";
// string fullSearchPath = path + searchPattern;
/*TEMPLATE DATA*/
/***********************************************************************************/
fstream templateData;
double data = 0.0;
templateData.open("003_template.dat", std::ios::in);
//check that the file is opened
if (!templateData.is_open()) {
std::cerr << "Template: Nooooooo!\n";
exit(0);
}
/*************************************************************************************/
//fill the templateVector with the values from templateData
std::vector<std::vector<double> > templateVector;
std::string line;
while (getline(templateData, line, '\n'))
templateVector.push_back(face.splitData(line));
//testing the contents of the templateVector
// cout << "TemplateVector: ";
// for (unsigned i = 0u; i != templateVector.size(); ++i) {
//
// std::cout << "Index[" << i << "] ";
// for(double value : templateVector[i])
// std::cout << value << " ";
// std::cout << "\n";
// }
/*QUERY DATA*/
/************************************************************************************/
std::ifstream inFile("003_AU01_query.dat", std::ios::in);
std::vector<double> queryVector;
double pixel = 0.0;
// Check that the file opened
if (!inFile.is_open()) {
std::cerr << "Query: Nooooooo!\n";
exit(1);
}
// fill the queryVector with the query data
while (inFile >> pixel) {
queryVector.push_back(pixel);
}
inFile.close();
// testing the content of the query vector
// for (unsigned i =0u; i < pixels.size(); i++){
// std::cout << "Index["<< i << "] " << pixels[i];
// }
// std::cout << "\n";
/*OUTPUT SCALAR PRODUCT*/
/****************************************************************************************/
vector<double> theList;
/*break out each of the vectors from the templateVector and compute the scalar product*/
for (auto& vec : templateVector) {
int i;
cout << "\nscalar_product: Index[" << i << "] " << face.scalar_product(vec, queryVector);
theList.push_back(face.scalar_product(vec, queryVector));//fill theList vector with the computations
i++;
std::cout << "\n";
}
//make sure that the sorted products are output with their original index numbers
vector<pair<int, double> > sorted;
sorted.reserve(theList.size());
for(size_t i = 0.00; i != theList.size(); i++){
sorted.push_back(make_pair(theList[i], i));
}
//sort the scalar products and print out the 10 closest neighbors
face.quickSort(sorted);
cout << "\nVector after sort:\n";
for(size_t i = 0; i < 10; i++){
cout << "idx: " << sorted[i].second << " " << "val: " << sorted[i].first << endl;
}
}
A solution in bash:
#!/bin/bash
for file in `ls`
do
./program $file
done
Of course you'd have to modify your main function to take an argument to pass to the fstream constructor:
int main(int argc, char **argv)
{
if (argc != 2)
{
// some error handling code
}
ifstream templateData(argv[1]);
if (!templateData)
{
// more error handling
}
// process the file
}
From your code it is windows.
This code will print all the *.dat file names in your folder:
Instead of printing do whatever you like.
first You'll need to include:
#include <windows.h>
Now to the code:
const wstring dir = L"C:\\Users\\Documents\\NetBeansProjects\\CSCE350";
const wstring ext = L"dat";
wstring findstr = dir;
findstr += L"\\*.";
findstr += ext;
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(findstr.c_str(),&ffd);
do{
if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
wstring path = dir;
path += L"\\";
path += ffd.cFileName;
wcout<< path<<endl;
}
} while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
EDIT:
On linux you can give your program a parameter path/to/dir/*.dat and you'll get the parameters trough argv, maybe its the better solution.
But if you insist to do it with code it is like this:
includes:
#include <sys/types.h>
#include <dirent.h>
Now the code:
const string dirname = "path/to/dir";
const string ext = ".dat";
DIR *dir;
struct dirent *de;
if((dir = opendir(dirname.c_str())) == NULL) {
//error... check errno and so on
cerr<<"Error..."<<endl;
}else{
while ((de = readdir(dir)) != NULL) {
//you can use stat to check if is is file or dir...
string filename(de->d_name);
if(ext = filename.substr(filename.size()-ext.size())){
cout<<dirname<<"/"<<filename<<endl;
}
}
closedir(dp);
}
Good luck