Store .txt file into a char* 2d Vector C++ - c++

I know there are lots of questions with similar titles here, but no one seems to work for me.
I have this kind of txt file:
tree pine
color blue
food pizza
and I want to store the items in a char* 2d vector, such as
vector<vector<char*>> data;
..
..
data[0][0] = tree
data[0][1] = pine
data[1][1] = blue
ecc
This is the code:
// parse configuration file
bool Configuration::fileParser(char* filename)
{
vector<vector<char*>> data;
fstream fin("data/setup.txt");
string line;
while (fin && getline(fin, line))
{
vector<char*> confLine;
char* word = NULL;
stringstream ss(line);
while (ss && ss >> word)
{
confLine.push_back(word);
}
data.push_back(confLine);
}
storeData(data);
return 0;
}
But when I run the code an exception is thrown.
Exception thrown: write access violation.
How can I solve this problem?
Thank you

You haven't allocated any memory into which the data can be written. You'd need something like char* word = new char[50];. But just use a std::string it is safer and easier.

Disclaimer: I do not have a compiler on hand to test the following code with files, but it should work.
Here is a reference I used: Parse (split) a string in C++ using string delimiter (standard C++)
Discription: Basically the following code parses the passed in file line by line then assigns the first word and second word into the vector. Notice that I used string(s) in the example because I didn't want to think about memory management.
#pragma once
#include <vector>
#include <fstream>
#include <string>
void Configuration::fileParser(string fileName)
{
vector<vector<string>> data;
ifstream configFile(fileName);
string line, token;
string delimiter = " ";
size_t pos;
if (configFile.is_open())
{
int n = 0;
while (getline(configFile, line))
{
if (!line || line == "")
break; //added as a safety measure
pos = 0;
if ((pos = line.find(delimiter)) != string::npos)
{
token = line.substr(0, pos);
data[n][0] = token; //add first word to vector
line.erase(0, pos + delimiter.length());
}
if ((pos = line.find(delimiter)) != string::npos)
{
token = line.substr(0, pos);
data[n][1] = token; //add second word to vector
line.erase(0, pos + delimiter.length());
}
n++;
}
}
storeData(data);
}

Related

implement vector of maps in C++

I am trying to write a code to make a vector of maps to store parts of string by splitting it. This code is giving long compilation errors, i am not able to understand what is the problem. Problem is with initialization way
#include <bits/stdc++.h>
using namespace std;
vector<string> split(string phrase, string delimiter){
vector<string> list;
string s = phrase;
size_t pos = 0;
string token;
while ((pos = s.find(delimiter)) != string::npos) {
token = s.substr(0, pos);
list.push_back(token);
s.erase(0, pos + delimiter.length());
}
list.push_back(s);
return list;
}
int main() {
string line = "tunilib;sebesta;prog lang;14";
vector<string> splitstring = split(line, ";");
vector< map<string,string,string,string> > elements;
map<string,string,string,string> element;
element["library"] = splitstring[0];
element["author"] = splitstring[1];
element["title"] = splitstring[2];
element["reservation"] = splitstring[3];
elements.push_back(element);
for(auto i:splitstring) cout<<i<<" ";
cout<<"success";
return 0;
}
Error was in declaration, simply change,
map<string,string,string,string>
to
map<string,string>
as i wanted to create a list of key value pairs.
#user4581301 thanks for comment

Getting the substring of string with multiple instances of the same delimiter [duplicate]

This question already has answers here:
How do I iterate over the words of a string?
(84 answers)
Closed 4 years ago.
I have a string of data that looks like
string line = "Number:Description:Price:Weight";
I want to separate the string into 4 different variables via the delimiter ":". I was trying this via the substring method
char delimiter = ':';
string number = line.substr(0, line.find(delimiter));
It works fine for the first variable. However, I am unable to figure out how to iterate to the next instance of the ":" for the other variables.
std::string::find() takes a starting index as an optional parameter:
string line = "Number:Description:Price:Weight";
string::size_type start, end;
char delimiter = ':';
end = line.find(delimiter);
string number = line.substr(0, end);
start = end + 1;
end = line.find(delimiter, start);
string desc = line.substr(start, end-start);
start = end + 1;
end = line.find(delimiter, start);
string price = line.substr(start, end-start);
string weight = line.substr(end + 1);
Alternatively, you can split the string on delimiters by using std::istringstream with std::getline():
string line = "Number:Description:Price:Weight";
string number, desc, price, weight;
char delimiter = ':';
istringstream iss(line);
getline(iss, number, delimiter);
getline(iss, desc, delimiter);
getline(iss, price, delimiter);
getline(iss, weight);
It is much easier with a simple for loop:
#include <iostream>
#include <vector>
int main()
{
std::string line = "Number:Description:Price:Weight";
std::vector<std::string> vecStrings;
std::string word;
size_t count = 0;
for (auto const& it : line)
{
if (it != ':') word += it;
if ((it == ':') || (count + 1 == line.size()))
{
vecStrings.emplace_back(word);
word.clear();
}
++count;
}
for(const auto& it: vecStrings)
std::cout << it << "\n";
return 0;
}
See live action: https://www.ideone.com/DiAvjO
Update: If you need something different, you can do the same thing with std::for_each() and a lambda:
#include <algorithm>
std::for_each(std::begin(line), std::end(line), [&](char &letter)
{
if (letter != ':') word += letter;
if ((letter == ':') || (count + 1 == line.size()))
{
vecStrings.emplace_back(word);
word.clear();
}
++count;
});
However, a much simpler solution to this would be to use std::istringstream. Thanks to RemyLebeau for pointing out this:
#include <sstream>
std::stringstream sstr(line);
std::string word;
while (std::getline(sstr, word, ':'))
{
vecStrings.emplace_back(word);
}
you can make use of strtok like below
#include <string.h>
int main()
{
char line[] = "Number:Description:Price:Weight";
char * token = std::strtok (line,":");
while (token != NULL)
{
cout << token << '\n';
token = std::strtok(NULL, ":");
}
return 0;
}
Make necessary changes as per your need
cstring has strtok that does exactly what you want.

Program gets "Expression: string subscript out of range"

#include <iostream>
#include <string>
using namespace std;
string Latin(string words)
{
string strWord, strSentence = "";
int length = 0, index = 0;
while (words[index] != '\0')
{
if(words.find(' ', index) != -1)
{
length = words.find(' ', index);
length -= index;
strWord = words.substr(index,length);
strWord.insert(length, "ay");
strWord.insert(length, 1, words[index]);
strWord.erase(0,1);
index += length +1;
}
else
{
strWord = words.substr(index);
length = strWord.length();
strWord.insert(length, "ay");
strWord.insert(length,1,words[index]);
strWord.erase(0,1);
index = words.length();
}
strSentence += (strWord + " ");
}
return strSentence;
}
int main()
{
string str;
getline(cin,str);
str = Latin(str);
cout<<str<<endl;
return 0;
}
I get this error that says
I have no clue what to do. As I am new to this, this is a program that is suppose to ask for user input of a length of words and translate them into pig Latin. Any help would be greatly appreciated.
Unless I really wanted to make my own life difficult, I'd do this quite a bit differently. First, I'd use a std::stringstream to break the input string into words to process. Then, I'd use std::rotate to move the first character of the string to the end. Finally, I'd wrap that all in std::transform to manage applying the function to each word in succession.
std::string line;
std::getline(std::cin, line);
std::stringstream buffer(line);
std::stringstream result;
std::transform(std::istream_iterator<std::string>(buffer),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(result, " "),
[](std::string s) {
std::rotate(s.begin(), s.begin() + 1, s.end());
s += "ay";
return s;
});
Of course, this doesn't know the special rules for things like words that start with vowels or letter pairs like sh or ch, but it looks like that's outside the scope of the task at hand.
For more on std::rotate, I recommend watching some of Sean Parent's videos.

Read a string line by line using c++

I have a std::string with multiple lines and I need to read it line by line.
Please show me how to do it with a small example.
Ex: I have a string string h;
h will be:
Hello there.
How are you today?
I am fine, thank you.
I need to extract Hello there., How are you today?, and I am fine, thank you. somehow.
#include <sstream>
#include <iostream>
int main() {
std::istringstream f("line1\nline2\nline3");
std::string line;
while (std::getline(f, line)) {
std::cout << line << std::endl;
}
}
There are several ways to do that.
You can use std::string::find in a loop for '\n' characters and substr() between the positions.
You can use std::istringstream and std::getline( istr, line ) (Probably the easiest)
You can use boost::tokenize
this would help you :
http://www.cplusplus.com/reference/iostream/istream/getline/
If you'd rather not use streams:
int main() {
string out = "line1\nline2\nline3";
size_t start = 0;
size_t end;
while (1) {
string this_line;
if ((end = out.find("\n", start)) == string::npos) {
if (!(this_line = out.substr(start)).empty()) {
printf("%s\n", this_line.c_str());
}
break;
}
this_line = out.substr(start, end - start);
printf("%s\n", this_line.c_str());
start = end + 1;
}
}
I was looking for some standard implementation for a function which can return a particular line from a string. I came across this question and the accepted answer is very useful. I also have my own implementation which I would like to share:
// CODE: A
std::string getLine(const std::string& str, int line)
{
size_t pos = 0;
if (line < 0)
return std::string();
while ((line-- > 0) and (pos < str.length()))
pos = str.find("\n", pos) + 1;
if (pos >= str.length())
return std::string();
size_t end = str.find("\n", pos);
return str.substr(pos, (end == std::string::npos ? std::string::npos : (end - pos + 1)));
}
But I have replaced my own implementation with the one shown in the accepted answer as it uses standard function and would be less bug-prone..
// CODE: B
std::string getLine(const std::string& str, int lineNo)
{
std::string line;
std::istringstream stream(str);
while (lineNo-- >= 0)
std::getline(stream, line);
return line;
}
There is behavioral difference between the two implementations. CODE: B removes the newline from each line it returns. CODE: A doesn't remove newline.
My intention of posting my answer to this not-active question is to make others see possible implementations.
NOTE:
I didn't want any kind of optimization and wanted to perform a task given to me in a Hackathon!

finding substring c++ [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How to split a string?
Hi,
I have a string say "1,0,1", how can i get the substring separated by comma operator.
C++ doesn't have a built in function for doing exactly this. However, it can be implemented using either the std::string::find_first_of member function, or the non-member std::find.
Here's an example using the latter:
#include <string>
#include <vector>
#include <algorithm>
// given a string str, split it on every occurrence of the character delim
std::vector<std::string> tokenize(std::string str, char delim) {
// store the results in a vector of strings
std::vector<std::string> tokens;
std::string::iterator end = str.end();
std::string::iterator left = str.begin();
for (;;) {
// find the next occurrence of the delimiter
std::string::iterator right = std::find(left, end, delim);
// create a string from the end of last one up until the one we just foun
tokens.push_back(std::string(left, right));
// if we reached the end of the string, exit the loop
if (right == end) { break; }
// otherwise, start the next iteration just past the delimiter we just found
left = right + 1;
}
return tokens;
}
// test program
int main() {
std::string str = "foo, bar, baz";
std::string str2 = "foo, bar, baz,";
std::string str3 = "foo";
std::string str4 = "";
std::string str5 = ",";
std::vector<std::string> tokens = tokenize(str, ',');
std::vector<std::string> tokens2 = tokenize(str2, ',');
std::vector<std::string> tokens3 = tokenize(str3, ',');
std::vector<std::string> tokens4 = tokenize(str4, ',');
std::vector<std::string> tokens5 = tokenize(str5, ',');
}
Of course there are a lot of border cases to handle, and this implementation might not do exactly what you want, but it should give you a starting point.
another way of doing this is by using strtok. This is a old c way but it still applies to the problem.
using <vector>
using <string>
char* token, line[512];
std::string tokenStr;
std::string lineStr = "0, 1, 2";
std::vector<std::string> commaSplit;
strcpy ( line, lineStr.c_str());
//Remove spaces and find the first instance of ','
token = strtok( line, " ," );
while(token != NULL)
{
//Copy the token to a string
tokenStr = token;
//Add the token to the vector
commaSplit.push_back(token);
//Find next instance of the ,
token = strtok(NULL, " ,");
}
Search google for an algorithm to explode or tokenize your string. It's trivial.
You can also check out the documentation and use available tools : http://www.cplusplus.com/reference/string/string/
A simple implementation could be :
void tokenize(const string & text, vector<string> & tokens, char delim)
{
size_t length = text.size();
string token = "";
for(size_t i=0;i<length;i++)
{
if(text[i] != delim)
{
token += text[i];
}
else
{
if(token.size() > 0)
{
tokens.push_back(token);
}
token = "";
}
}
tokens.push_back(token);
}