I was trying to put this code into a class but I couldn't manage to do it. The job of the function is pulling team names from a .txt file and putting them in a vector. I think the main problem is I couldn't select the right function return type.
This is the teams.txt: (The names before the "-" symbol are teams. Other names are unrelated with my question but they are coachs of the teams.)
Trabzonspor-Abdullah Avcı+
Fenerbahçe-Vítor Pereira+
Beşiktaş-Sergen Yalçın+
Galatasaray-Fatih Terim+
İstanbul Başakşehir-Emre Belözeoğlu+
Alanyaspor-Bülent Korkmaz+
Fatih Karagümrük-Francesco Farioli+
Gaziantep-Erol Bulut+
Adana Demirspor-Vincenzo Montella+
Ankara Dinc-Nestor El Maestro+
Antalyaspor-Nuri Şahin+
Kayserispor-Hikmet Karaman+
Yeni Malatyaspor-Marius Sumudica+
Konyaspor-İlhan Palut+
Sivasspor-Rıza Çalımbay+
Hatayspor-Ömer Erdoğan+
Giresunspor-Hakan Keleş+
Kasımpaşa-Hakan Kutlu+
And this is the my code who does the putting them in a vector:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std; //I know that's a bad practice but i just need to do this for while
std::string process(std::string const& s) //A function to seperate teams from the coaches
{
string::size_type pos = s.find('-');
if (pos != string::npos)
{
return s.substr(0, pos);
}
else
{
return s;
}
}
int main() {
ifstream readTeam("teams.txt");
if (!readTeam) { //checking that successfully opened the file.
std::cerr << "Error while opening the file.\n";
return 1;
}
vector<std::string> teams;
string team;
while (getline(readTeam, team)) {
teams.push_back(process(team));
}
readTeam.close();
int g = 1;//for printing the teams, just for displaying it. doesn't have to in a class.
for (const auto& i : teams) {
cout << g;
cout << i << endl;
g++;
}
return 0;
}
And that's what i did(tried) to make it a class:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
std::string process(std::string const& s)
{
string::size_type pos = s.find('-');
if (pos != string::npos)
{
return s.substr(0, pos);
}
else
{
return s;
}
}
class readFile {
public:
void setTxtName(string);
vector<unsigned char> const& getTeam() const{
}
vector<string> teams;
private:
string fileName;
};
int main() {
readFile pullTeams;
pullTeams.setTxtName("teams.txt");
return 0;
}
void readFile::setTxtName(string txtName) {
fileName = txtName;
}
vector<string> const& readFile::getTeam { //problem is defining it(I think). So I couldn't add my main code int it..
return teams;
}
Anything helps, thank you!
I did a little different research based on the Botje's comment. And I manage to create an answer based on here. Thanks.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
std::string process(std::string const& s){
string::size_type pos = s.find('-');
if (pos != string::npos){
return s.substr(0, pos);
}
else{
return s;
}
}
class readFile {
public:
vector<string> getTxt();
bool read(string);
private:
vector<string> teams;
string team;
ifstream txt;
};
int main() {
vector<string> teams;
readFile team;
if (team.read("teaams.txt") == true)
teams = team.getTxt();
int g = 1;//for printing the teams, just for displaying it. doesn't have to in a class.
for (const auto& i : teams) {
cout << g;
cout << i << endl;
g++;
}
return 0;
}
bool readFile::read(string txtName) {
ifstream txt;
string team;
txt.open(txtName.c_str());
if (!txt.is_open())
return false;
while (getline(txt, team))
teams.push_back(process(team));
return true;
}
vector<string> readFile::getTxt() {
return teams;
}
Related
#include <iostream>
#include <fstream>
using namespace std;
struct review {
string text;
string date;
};
void getRegistry(int i) {
review* reg = new review;
ifstream file;
file.open("test.txt", ios::binary);
if (file) {
file.seekg(i * sizeof(review), ios::beg);
file.read(reinterpret_cast<char*>(reg), sizeof(review));
cout << reg->text;
file.close();
}
delete reg;
}
void generateBinary()
{
ofstream arq("test.txt", ios::binary);
review x;
x.text = "asdasdasd";
x.date = "qweqweqwe";
for (int i = 1; i <= 1000000; i++)
{
arq.write(reinterpret_cast<const char*>(&x), sizeof(review));
}
arq.close();
}
int main() {
generateBinary();
getRegistry(2);
return 0;
}
Hello, I'm trying to make a program which writes several "reviews" to a binary file, then reads a certain registry. The program seems to work, but, in the end, it always throws an exception: "Exception thrown at 0x00007FF628E58C95 in trabalho.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF." How can I solve this? Thank you!
The problem is that you can't read/write std::string objects they way you are. std::string holds a pointer to variable-length character data that is stored elsewhere in memory. Your code is not accounting for that fact.
To be able to seek to a specific object in a file of objects the way you are attempting, you have to use fixed-sized objects, eg:
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
struct review {
char text[12];
char date[12];
};
void getRegistry(int i) {
ifstream file("test.txt", ios::binary);
if (file) {
if (!file.seekg(i * sizeof(review), ios::beg)) throw ...;
review reg;
if (!file.read(reinterpret_cast<char*>(®), sizeof(reg))) throw ...;
cout << reg.text;
}
}
void generateBinary()
{
ofstream arq("test.txt", ios::binary);
review x = {};
strncpy(x.text, "asdasdasd", sizeof(x.text)-1);
strncpy(x.date, "qweqweqwe", sizeof(x.date)-1);
for (int i = 1; i <= 1000000; ++i) {
if (!arq.write(reinterpret_cast<char*>(&x), sizeof(x))) throw ...;
}
}
int main() {
generateBinary();
getRegistry(2);
return 0;
}
Otherwise, to deal with variable-length data, you need to (de)serialize each object instead, eg:
#include <iostream>
#include <fstream>
#include <cstdint>
using namespace std;
struct review {
string text;
string date;
};
string readStr(istream &is) {
string s;
uint32_t len;
if (!is.read(reinterpret_cast<char*>(&len), sizeof(len))) throw ...;
if (len > 0) {
s.resize(len);
if (!is.read(s.data(), len)) throw ...;
}
return s;
}
void skipStr(istream &is) {
uint32_t len;
if (!is.read(reinterpret_cast<char*>(&len), sizeof(len))) throw ...;
if (len > 0) {
if (!is.ignore(len)) throw ...;
}
}
void writeStr(ostream &os, const string &s) {
uint32_t len = s.size();
if (!os.write(reinterpret_cast<char*>(&len), sizeof(len)) throw ...;
if (!os.write(s.c_str(), len)) throw ...;
}
review readReview(istream &is) {
review r;
r.text = readStr(is);
r.date = readStr(is);
return r;
}
void skipReview(istream &is) {
skipStr(is);
skipStr(is);
}
void writeReview(ostream &os, const review &r) {
writeStr(is, r.text);
writeStr(is, r.date);
}
void getRegistry(int i) {
ifstream file("test.txt", ios::binary);
if (file) {
while (i--) skipReview(file);
review reg = readReview(file);
cout << reg.text;
}
}
void generateBinary()
{
ofstream arq("test.txt", ios::binary);
review x;
x.text = "asdasdasd";
x.date = "qweqweqwe";
for (int i = 1; i <= 1000000; ++i) {
writeReview(arq, x);
}
}
int main() {
generateBinary();
getRegistry(2);
return 0;
}
The operator sizeof (review) does not return the length of containing strings. This is due to the fact that string class contain pointers to real strings, which are located in a separated location of the memory, allocated dynamically. You should use explicitly the length of strings, and write explicitly the strings instead of the class. Same thing with reading from file. Read strings first, then attribute to review.
I have a homework task where I should complete the body of a function located in a separate file Find.h which should be completed in such a way that the code written below should compile successfully:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include "Find.h"
using namespace std;
class Company {
std::string name;
int id;
public:
std::string getName() const {
return this->name;
}
int getId() const {
return this->id;
}
friend std::istream& operator>>(std::istream& stream, Company& company);
};
std::istream& operator>>(std::istream& stream, Company& company) {
return stream >> company.name >> company.id;
}
std::ostream& operator<<(std::ostream& stream, const Company& company) {
return stream << company.getName() << " " << company.getId();
}
int main() {
using namespace std;
vector<Company*> companies;
string line;
while (getline(cin, line) && line != "end") {
istringstream lineIn(line);
Company* c = new Company();
lineIn >> *c;
companies.push_back(c);
}
string searchIdLine;
getline(cin, searchIdLine);
int searchId = stoi(searchIdLine);
Company* companyWithSearchedId = find(companies, searchId);
if (companyWithSearchedId != nullptr) {
cout << *companyWithSearchedId << endl;
}
else {
cout << "[not found]" << endl;
}
for (auto companyPtr : companies) {
delete companyPtr;
}
return 0;
}
And here is my incomplete attempt for completion of the Find.h file (the program should output the id and the name of the company that matches the given id):
#ifndef FIND_H
#define FIND_H
#include "Company.h"
#include <vector>
using namespace std;
Company* find(vector<Company*> vc, int id) {
for (int i = 0; i < vc.size(); i++) {
if (vc[i]->getId() == id) {
//I do not know what to write here as to return a pointer
//to the required element so as to fulfil the requirement?
}
}
return nullptr;
}
#endif // !FIND_H
One alternative is to define a functor or function object and use the std::find algorithm:
struct Find_By_ID
{
int id_to_find;
bool operator==(const Company& a)
{
return a->getId() == id_to_find;
}
}
//...
std::vector<Company> database; // Note, not a vector of pointers
//...
Find_By_ID functor;
functor.id_to_find = searchId;
std::vector<Company>::iterator iter = std::find(database.begin(), database.end(),
functor);
Edit 1: No new necessary
You don't need to use new when building your database:
Company c;
std::vector<Company> database;
while (std::cin >> c)
{
database.push_back(c);
}
The std::vector::push_back() method will make a copy and append it to the vector. The vector will allocate memory for the item as necessary.
Edit 2: Brute force
You could use a custom brute force method instead of a functor:
const std::vector<Company>::const_iterator iter_begin(database.begin());
const std::vector<Company>::const_iterator iter_end(database.end());
std::vector<Company>::const_iterator iter;
for (iter = iter_begin; iter != iter_end; ++iter)
{
if (iter->getId() == searchId)
{
break;
}
}
if (iter != iter_end)
{
std::cout << "Customer found by ID.\n";
}
If you want to modify the found Customer, change the iterator types to:
std::vector<Customer>::iterator
as appropriate.
For the specific issue in the .h file for loop try:
return vc[i]; //vc is a vector of Company pointers, this returns the pointer at vc index i
For the output part consider:
cout << companyWithSearchedId->getId() << " " << companyWithSearchId->getName() << endl;
There are more issues here at as a whole, take your time and work through it.
My program uses ifstream() and getline() to parse a text file in to objects that are two vectors deep. i.e vector inside vector. The inner vector contains over 250000 string objects once the text file is finished loading.
this is painfully slow. Is there an STD alternative that is more efficient than using ifstream() and getline() ?
Thanks
UPDATE:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>
using namespace std;
class Word
{
private:
string moniker = "";
vector <string> definition;
string type = "";
public:
void setMoniker(string m) { this->moniker = m; }
void setDefinition(string d) { this->definition.push_back(d); }
void setType(string t) { this->type = t; }
int getDefinitionSize() { return this->definition.size(); }
string getMoniker() { return this->moniker; }
void printDefinition()
{
for (int i = 0; i < definition.size(); i++)
{
cout << definition[i] << endl;
}
}
string getType() { return this->type; }
};
class Dictionary
{
private:
vector<Word> Words;
public:
void addWord(Word w) { this->Words.push_back(w); }
Word getWord(int i) { return this->Words[i]; }
int getTotalNumberOfWords() { return this->Words.size(); }
void loadDictionary(string f)
{
const regex _IS_DEF("[\.]|[\ ]"),
_IS_TYPE("^misc$|^n$|^adj$|^v$|^adv$|^prep$|^pn$|^n_and_v$"),
_IS_NEWLINE("\n");
string line;
ifstream dict(f);
string m, t, d = "";
while (dict.is_open())
{
while (getline(dict, line))
{
if (regex_search(line, _IS_DEF))
{
d = line;
}
else if (regex_search(line, _IS_TYPE))
{
t = line;
}
else if (!(line == ""))
{
m = line;
}
else
{
Word w;
w.setMoniker(m);
w.setType(t);
w.setDefinition(d);
this->addWord(w);
}
}
dict.close();
}
}
};
int main()
{
Dictionary dictionary;
dictionary.loadDictionary("dictionary.txt");
return 0;
}
You should reduce your memory allocations. Having a vector of vectors is usually not a good idea, because every inner vector does its own new and delete.
You should reserve() the approximate number of elements you need in the vector at the start.
You should use fgets() if you don't actually need to extract std::string to get your work done. For example if the objects can be parsed from char arrays, do that. Make sure to read into the same string buffer every time, rather than creating new buffers.
And most important of all, use a profiler.
i have been stuck on this for awhile now no matter how i compile it on cygwin i still can't get through it
Main.cpp
#include <iostream>
#include <istream>
#include <fstream>
#include <string>
#include <sstream>
#include <ctype.h>
#include <cstring>
#include <cstdlib>
#include "Message.h"
#include "Packet.h"
#include "main.h"
using namespace std;
void fillList(list<Message> messages, char *argv[]);
void printList(const list<Message> &messages);
int getMID(list<Message> &messages, stringstream &lines);
void create(list<Message> &messages, stringstream &lines);
bool exist(list<Message> &messages, stringstream &lines);
Message getMessage(int ID, list<Message> &messages);
void printList(const list<Message> &messages);
void fillList(list<Message> messages, char *argv[])
{
string lines;
ifstream files(argv[1]);
if(files.is_open())
{
int delimc = 0;
string line;
stringstream file;
while(getline(files,lines))
{
file << lines;
if(!exist(messages, file))
create(messages, file);
int ID = getMID(messages, file);
string fields[3];
while(getline(file, line, ':'), delimc != 3)
{
if(delimc != 0)
{
fields[delimc] = line;
}
delimc++;
}
getMessage(ID, messages).add(atoi(fields[1].c_str()), fields[2]);
delimc = 0;
}
files.close();
}
}
int getMID(list<Message> &messages, stringstream &lines)
{
std::string line;
getline(lines, line, ':'); //followed standard procedure for defining string (line)
return atoi(line.c_str());
}
void create(list<Message> &messages, stringstream &lines)
{
messages.push_back(getMessage(getMID(messages, lines), messages)); //getID takes 2 arguments
}
bool exist(list<Message> &messages, stringstream &lines)
{
list<Message>::iterator itr;
for(itr = messages.begin(); itr != messages.end(); itr++)
{
if(itr->Message::getID() == getMID(messages, lines)) //itr is not a pointer and if you want to point it use the correct way
return true;
}
return false;
}
Message getMessage(int ID, list<Message> &messages)
{
list<Message>::iterator itr;
for(itr = messages.begin(); itr != messages.end(); itr++)
{
if(itr->Message::getID() == ID) //itr is not a pointer and if you want to point it use the correct way
return *itr;
}
//return ; //no need to return null, even if you want to return still you have to assign memebers of messages as null seperately
}
void printList(list<Message> &messages)
{
list<Message>::iterator itr;
for(itr = messages.begin(); itr != messages.end(); itr++)
{
cout << itr->Message::toString(); //was stucked at it, you have to redesgn it in a way that you will first use add() and then packect.tostring() in order to print
}
cout << '\n';
}
int main(int argc, char *argv[])
{
cout << "The Program: " << argv[0] << " was created by Newbie";
list<Message> messages;
fillList(messages, argv);
printList(messages);
return 0;
}
//input argument for the text file
//read the file with limit of 2 splitter
//split it up and create the Message with packets
//display the msg
Message.cpp
#include <iostream>
#include <list>
#include <ctype.h>
#include <sstream>
#include "Packet.h"
using namespace std;
class Message
{
private:
int ID;
list<Packet> packets;
public:
Messages(int newID, list<Packet> newPackets)
{
ID = newID;
packets = newPackets;
}
int getID()
{
return ID;
}
void setID(const int &newID)
{
ID = newID;
}
list<Packet> getPackets()
{
return packets;
}
void add(int SQN, string text)
{
packets.push_back(Packet(SQN, text));
}
string toString()
{
ostringstream oss;
oss << "Message " << ID;
list<Packet>::iterator itr;
for(itr = packets.begin(); itr != packets.end(); itr++)
{
oss << itr->toString();
}
return oss.str();
}
};
Message.h
#ifndef Message_H
#define Message_H
#include <iostream>
#include <list>
#include <ctype.h>
#include <sstream>
#include "Packet.h"
using namespace std;
class Message
{
int ID;
list<Packet> packets;
public:
Message(int ID, list<Packet> packets);
int getID();
list<Packet> getPackets();
void setID(const int newID);
void setPackets(list<Packet> newPackets);
void add(int SQN, string text);
string toString();
};
#endif
i've tried to compile it but i keep getting the same error each time
/tmp/ccDZ0PKH.o:main.cpp:(.text+0x1f3): undefined reference to `Message::add(int, std::string)'
/tmp/ccDZ0PKH.o:main.cpp:(.text+0x1f3): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Message::add(int, std::string)'
/tmp/ccDZ0PKH.o:main.cpp:(.text+0x4ed): undefined reference to `Message::getID()'
/tmp/ccDZ0PKH.o:main.cpp:(.text+0x4ed): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Message::getID()'
/tmp/ccDZ0PKH.o:main.cpp:(.text+0x592): undefined reference to `Message::getID()'
/tmp/ccDZ0PKH.o:main.cpp:(.text+0x592): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Message::getID()'
/tmp/ccDZ0PKH.o:main.cpp:(.text+0x63d): undefined reference to `Message::toString()'
/tmp/ccDZ0PKH.o:main.cpp:(.text+0x63d): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Message::toString()'
compiling using cygwin
g++ main.cpp Message.cpp Packet.cpp
Your cpp file is wrong. You are defining a new class, Message, in the cpp file and defining its functions instead of giving definitions to the functions from the Message class in your header file. Your cpp file should look like this:
Message::Message(int newID, list<Packet> newPackets)
{
ID = newID;
packets = newPackets;
}
int Message::getID()
{
return ID;
}
void Message::setID(const int &newID)
{
ID = newID;
}
list<Packet> Message::getPackets()
{
return packets;
}
void Message::add(int SQN, string text)
{
packets.push_back(Packet(SQN, text));
}
string Message::toString()
{
ostringstream oss;
oss << "Message " << ID;
list<Packet>::iterator itr;
for(itr = packets.begin(); itr != packets.end(); itr++)
{
oss << itr->toString();
}
return oss.str();
}
I have a problem. When I compile the program I don't have any errors, but when I use valgrind:
Uninitialized value was created by a heap allocation (line with new)
Conditional jump or move depends on uninitialized value(s)(line with delete)
I search through the forums however I didn't find much information which could help me.
I would be really grateful for a hint.
My program
#include <cstdlib>
#include <stdint.h>
#include <cstdio>
#include <iostream>
#include <string>
#include <istream>
#include <cstring>
#include <fstream>
#include <sstream>
#include <cctype>
using namespace std;
using std::cout;
using std::endl;
int dlugosc,miejsce;
ifstream file;
class channel
{
public:
int start;
double length;
int bytespix;
int resolution;
channel(double g) : start(g),
length(0),
bytespix(0),
resolution(0)
{
}
};
int fileopen() // opens the file and returns its size
{
file.open ("0_dlc.000", ios::in|ios::binary);
if( file.good() == true )
{
cout << "Uzyskano dostep do pliku!" << endl;
}
else
{
cout<< "File cannot open" <<endl;
}
file.seekg(0, file.end);
dlugosc = file.tellg();
return dlugosc;
}
int findword(const char* slowo,int startplace)
{
int m;
int c=0;
int cur=0;
unsigned int equal=0;
char element=0;
file.seekg (startplace, file.beg);
for(m=0;m<dlugosc;m++)
{
file.get(element);
if(element==slowo[cur])
{
equal++;
cur++;
}
else
{
equal=0;
cur=0;
if(element==slowo[cur])
{
equal++;
cur++;
}
}
if(equal==strlen(slowo))
{
return m+startplace;
}
}
return 0;
}
int findvalue(const char* wartosc,int startpoint)
{
int p;
int g;
char element=0;
char* buffer = new char[9];
miejsce = findword(wartosc,startpoint); // miejsce to global variable
file.seekg (miejsce+1, file.beg);
for(p=0;(int)element<58;p++)
{
file.get(element);
if((int)element>58 || (int)element<48)
break;
else
buffer[p] = element;
}
buffer[p]='\0';
g = atoi(buffer);
delete [] buffer;
return g;
}
int main()
{
int a,h=0,channels,start=0,length=0,resolution=0,bytespix=0,m=0;
const char* slowko="Data offset: ";
dlugosc=fileopen();
channel** kanaly=0;
kanaly = new channel*[9];
miejsce=0;
for(a=0;a<9;a++)
{
kanaly[a] = new channel(4);
start = findvalue("Data offset: ",miejsce+20);
kanaly[a]->start=start;
}
for(m=0;m<9;m++)
{
delete kanaly[m];
}
delete []kanaly;
file.close();
}
The problem is in the constructor of channel. Initialize all member variables, and the problem will go away :
class channel
{
public:
double start;
double length;
int bytespix;
int resolution;
channel(double g) : start(g),
length(0),
bytespix(0),
resolution(0)
{
}
};