Error Vector subscript out of range - c++

I believe my error is within my writeline function, when I attempt to write the contents of the vector to the new file using a while loop.
//Read from txt file, write to new text file
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
void readline();
void sortline(vector<string>& sortthis);
void writeline(vector<string>& list);
int main()
{
readline();
system("pause");
return 0;
};
void readline()
{
string line;
vector<string> lines;
ifstream myfile("classes.txt");
if (myfile.is_open())
{
while (myfile.good())
{
getline(myfile, line);
lines.push_back(line);
};
myfile.close();
}
cout << "readline() has run" << endl;
sortline(lines);
writeline(lines);
};
void sortline(vector<string>& sortthis)
{
sort(sortthis.begin(), sortthis.end());
};
void writeline(vector<string>& list)
{
ofstream myfile2("new.txt");
if (myfile2.is_open())
{
int i = 0;
while(i !=list.size()-1)
{
myfile2 << list[i] << endl;
i++;
};
myfile2.close();
};
cout << "writeline() has run" << endl;
};
this is a project from a semester ago that i'm revisiting. I wrote the program on my mac, now i'm trying to run it on my windows comp with visual studio. I'll describe what I'm attempting to do, I apologize if my choice of words is terrible in advance. anywhere I put a * is where I'm not sure what is happening, but I'll take a stab at it.. any explanations of my code is very appreciated!!
my readline() function does the following: creates a string called line, creates a vector of string type called lines, **input the file classes.txt and establish myfile as it's object, then open myfile for writing, **use the while loop to write the lines from the txt into the myfile object, then close myfile, print out a statement to let the user know readline() has run, then **pass the vector called lines into the sortline function, and then pass lines into the writeline function.
** sortline takes in a vector of strings as its arg, and assigns it the object sortthis?? then I'm not sure what happens, but it looks like i applied a sorting algorithm, anybody have any thoughts?
and finally we get to my writeline function which takes in a vector of strings as its arg and assigns them the name lines (is that correct?) i then want to establish a new out file stream to a new textfile called "new.txt" with an object name myfile2, if myfile2 is open, then i want to write all the lines from the vector of strings(which contain the contents of the original text file) into myfile2, which will write them to the new.txt file, then close myfile2, print a message stating the function has run, and that is all.

The way you loop through list in writeline is not safe. You should use a for loop or a while loop with iterator. As it is, your code probably doesn't do what you intend it to do even if there are several elements in list. Consider the following:
std::vector<std::string> vLines;
vLines.push_back("Hello");
vLines.push_back("File");
vLines.push_back("World");
std::ofstream of("file.txt");
int i = 0;
while (i != vLines.size() - 1)
{
of << vLines[i] << std::endl;
++i;
}
Even with several elements in vLines, this will only actually print output 2 elements into of.
i will be 0 which is not 2, so "Hello" will be output to of.
i will be 1 which is not 2, so "File" will be output to of.
i is now 2, which is equal to 2, so "World" will not be output to of.
That's with elements. If there are 0 elements in vLines, you will be indexing out of bounds (which I suspect is what you are doing, hence your error):
std::vector<std::string> vLines;
std::ofstream of("file.txt");
int i = 0;
while (i != vLines.size() - 1)
{
of << vLines[i] << std::endl;
++i;
}
i will be 0, which is not equal to -1, so the code will run and try to output vLines[0] to of, but there is no vLines[0]! I suspect this is what you are experiencing.
This will go away if you use a proper range-based loop instead (credit to #WhozCraig for C++11 solution):
for (auto const& s : vLines)
of << s;
Or if you don't have C++11 you can still mimic a proper range-based loop with the following:
for (int i = 0; i < vLines.size(); ++i)
of << vLines[i] << std::endl;
Or an iterator:
for (auto it = vLines.begin(); it != vLines.end(); ++it)
of << *it << std::endl;
You will now output all elements in your std::vector to your std::ofstream as well as properly handle situations where there are no elements.

Related

Checking if one document has the contents of the other c++

I am writing a code to check to see if one document (text1.txt) contains a list of banned words (bannedwords.txt) in it.
For example, the text1 document contains lyrics to a song and i want to check whether the word pig from the banned document is included in it. I then want the out put to be similar to:
"pig" found 0 times
"ant" found 3 times
This is what I have come up with so far but cannot seem to put the array of banned words into the search. Any help would be amazing :D
Thanks Fitz
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool CheckWord(char* filename, char* search)
{
int offset;
string line;
ifstream Myfile;
Myfile.open(filename);
if (Myfile.is_open())
{
while (!Myfile.eof())
{
getline(Myfile, line);
if ((offset = line.find(search, 0)) != string::npos)
{
cout << "The Word " << search<< " was found" << endl;
return true;
}
else
{
cout << "Not found";
}
}
Myfile.close();
}
else
cout << "Unable to open this file." << endl;
return false;
}
int main()
{
ifstream file("banned.txt");
if (file.is_open())//file is opened
{
string bannedWords[8];//array is created
for (int i = 0; i < 8; ++i)
{
file >> bannedWords[i];
}
}
else //file could not be opened
{
cout << "File could not be opened." << endl;
}
ifstream text1;//file is opened
text1.open("text1.txt");
if (!text1)//if file could not be opened
{
cout << "Unable to open file" << endl;
}
CheckWord("text1.txt", "cat");
system("pause");
}
Your main() function is reading the contents of banned.txt into an array of 8 std::string named bannedWords.
The array bannedWords is not being used anywhere after that. C++ doesn't work by magic, and compilers are not psychic so cannot read your mind in order to understand what you want your code to do. If an array (or its elements) are not accessed anywhere, they will not be used to do what you want with them.
You need to pass strings from the bannedWords array to CheckWord(). For example;
CheckWord("text1.txt", bannedWords[0].c_str());
will attempt to pass the contents of the first string in bannedWords to CheckWord().
However, that will not compile either unless you make the second parameter of CheckWord() (named search) be const qualified.
Or, better yet, change the type of the second argument to be of type std::string. If you do that, you can eliminate the usage of c_str() in the above.
I don't claim that is a complete solution to your problem - because there are numerous problems in your code, some related to what you've asked about, and some not. However, my advice here will get you started.
Your question is really vague; it looks like you need to spend some time to pin down your program structure before you could ask for help here.
However, since we were all new once, here's a suggestion for a suitable structure:
(I'm leaving out the file handling bits because they're irrelevant to the essential structure)
//Populate your array of banned words
std::string bannedWords[8];
int i;
for (int i = 0; i < 8; ++i)
{
file >> bannedWords[i];
}
//Load the entire file content into memory
std::ifstream in("text1.txt");
std::string fileContents((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
So now the entire file content is in the string "fileContents", and the 8 banned words are in "bannedWords". I suggest this approach because otherwise you're opening, reading, and closing the file for every word. Hardly a good design.
Now you've got to check each word against the file content. There's some more sophisticated ways to do this, but your simplest option is a loop.
//Loop through each banned word, and check if it's in the file
for (int i = 0; i < 8; i++)
{
if (fileContents.find(bannedwords[i]) != std::string::npos)
{
//Do whatever
}
}
Obviously you'll need to do the find a little differently if you want to count the number of occurrences, but that's another question.

Output not displaying all information C++

I have to create a program that will output various information about 1343 runners in a marathon. I'm having to import the data from a csv spreadsheet, so I chose to use the getline function. I use simple recursion to fill a string array and then simply use recursion once more to output the data. But for some reason, it only wants to display 300 or so runners' data. Here's the code:
int main(){
string data[1344];
vector<string> datav;
string header;
ifstream infile("C:\\Users\\Anthony\\Desktop\\cmarathon.csv");
int i = 0;
if (infile.is_open()) {
for (i=0; i<=1343; i++) {
getline(infile, data[i]);
}
datav.assign(data, data+1344);
for (int i = 0; i < datav.size(); i++) {
cout << datav[i] << "\n";
}
}
}
I attempted to use a vector in hopes it would help to allocate the required memory to execute the program properly (if that is in fact the problem here).
That code yields the perfect output of runners 1045-1343. I've tried simple work arounds, such as using several for() loops to combine the output seamlessly to no avail. Any information would be appreciated.
You do not need to copy from the array to the vector. You can add to the vector directly instead. Also, it is somewhat bad practice to shadow another local variable at the outer scope.
int main(){
string line;
vector<string> datav;
string header;
ifstream infile("C:\\Users\\Anthony\\Desktop\\cmarathon.csv");
if (infile.is_open()) {
// Are you supposed to read the header line first?
getline( infile, header );
while( getline( infile, line ).good() )
datav.push_back( line );
cout << "Container has " << datav.size() << " lines\n";
for (size_t i = 0; i < datav.size(); i++) {
cout << datav[i] << "\n";
}
}
}
Of course, you still have to break down each line to the individual fields, so pushing back a class or struct as EToreo suggested would be a good idea.
You should try using a struct to represent the fields in the CSV file and then make a vector of that struct type.
Now, loop through the file, reading each line till you reach the end of the file (Google how to do that) - DO NOT assume 1343, you don't have to. When you read in each line, create a new object from your struct and fill it with the content of that line (you will need to parse it by reading till a tab (\t) or the end of the string) and then datav.push(newObj) it onto your vector.
I suggest using the correct type's in your struct (int for age, string for name, etc.) and passing the string values from the file into those types. It will be much easier to do things like make a sum of everyone's age. You will thank yourself (and maybe me?) later.
If your not needing to use a vector:
for (i=0; i<=1343; i++) {
cout << data[i] << endl;
}
should work to print out whatever is in the data array
It is also possible to specify a delimeter for the getline function if you need to put different strings in different variables.
However EToreo's method may be more useful to you in the long run.

C++ vector subsctript out of range

In file called abc.txt, I have input following text:
sample text
sample text
sample text
sample text
sample text
Firstly I created variable(named text) for saving text- read from the file. Then program reads file abc.txt. I created vector named: ArrSent for saving each line from the file abc.txt. After loop while ends program close the file abc.txt. Then program have to output all sentences from vector ArrSent to the screnn.I have this kind of problem: after end of program, appears alert with message: vector subscript out of range. I have no idea why..
#include<iostream>
#include<string>
#include<fstream>
#include<vector>
using namespace std;
void function()
{
string text;//variable to save text from file
ifstream myfile("abc.txt");//reading from file colled abc.txt
vector<string> ArrSent;
if (myfile.is_open())
{
//cout <<"myplik.good()= "<< myfile.good() << endl;
while (myfile.good())
{
getline(myfile, text);
ArrSent.push_back(text);
}
myfile.close();
}
for (int i = 0; i <= ArrSent.size(); i++)
{
cout << ArrSent[i] << endl;
}
}
int main()
{
function();
system("pause");
return 0;
}
It is wrong here
for (int i = 0; i <= ArrSent.size(); i++)
{
cout << ArrSent[i] << endl;
}
should be
for (int i = 0; i < ArrSent.size(); i++)
{
cout << ArrSent[i] << endl;
}
The reason for that is that in C/C++, vector/array are zero based. That is to say that, if you have a vector, my_vector, size of 10, it goes like, my_vector[0], my_vector[1], ... my_vector[9]. There is no my_vector[10].
A better way to iterate through it , could be (C++11)
for (const auto & v : ArrSent)
{
cout << v << endl;
}
or
for (vector<string>::const_iterator i = ArrSent.begin(); i != ArrSent.end(); ++i)
cout << *i << endl;
As pointed out by WhozCraig, the while loop for reading is also buggy, a better version could be
while (getline(myfile, text))
{
ArrSent.push_back(text);
}
A Word About function
Notable: Your function name is function. While that may be descriptive, you should know that standard library headers can freely include other standard library header (and very frequently do just that). One such header in the standard library is <functional> which declares, as luck would have it, std::function.
Why would you care? Because your using namespace std; brings everything in std out in the open with no namespace qualifier requirements, including potentially std::function (whether or not you included <functional>).
Which means although this will still compile:
void function()
{
// .. stuff
}
This may not:
int main()
{
function(); // HERE
//... other stuff
}
This doesn't know whether you're calling your function or attempting to instantiate a single temporary of type std::function<> (which it can't anyway, as no template parameters are described). The result may be a ambiguous.
You can fix this by using ::function(); in your main(), but it would be better if you got developed the habit of not slurping in the entire std library in via using namespace std;, and/or not using names of common types/ids from the standard library.

c++ how to build a 2D matrix of strings from a .dat file? 5 columns x rows

I need to read a .dat file which looks like this:
Atask1 Atask2 Atask3 Atask4 Atask5
Btask1 Btask2 Btask3 Btask4 Btask5
Ctask1 Ctask2 Ctask3 Ctask4 Ctask5
Dtask1 Dtask2 Dtask3 Dtask4 Dtask5
and i need to be able to output information like this:
cout << line(3) << endl; // required output shown below
>>Ctask1 Ctask2 Ctask3 Ctask4 Ctask5
cout << line(2)(4) << endl; // required output shown below
>>Btask4
I don't know how to read 1 line and split it into an array of 5 different strings.
I'd ideally like to have the whole .dat file converted into a vector or a list or some kind of matrix/array structure for easy reference
any simple code or solutions for this??
PLEASE HELP?!?!?!? :-)
EDIT:
vector<string> dutyVec[5];
dut1.open(dutyFILE);
if( !dut1.is_open() ){
cout << "Can't open file " << dutyFILE << endl;
exit(1);
}
if(dut1.eof()){
cout << "Empty file - no duties" << endl;
exit(1);
}
while ( !dut1.eof()){
int count = 0;
getline(dut1, dutyVec[count]);
count++;
}
Your problem addresses a number of issues, all of which I will attempt to answer in one go. So, forgive the length of this post.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <fstream>
int main(int argc, char argv[]){
std::vector <std::string> v;//just a temporary string vector to store each line
std::ifstream ifile;
ifile.open("C://sample.txt");//this is the location of your text file (windows)
//check to see that the file was opened correctly
if(ifile.is_open()) {
//while the end of file character has not been read, do the following:
while(!ifile.eof()) {
std::string temp;//just a temporary string
getline(ifile, temp);//this gets all the text up to the newline character
v.push_back(temp);//add the line to the temporary string vector
}
ifile.close();//close the file
}
//this is the vector that will contain all the tokens that
//can be accessed via tokens[line-number][[position-number]
std::vector < std::vector<std::string> > tokens(v.size());//initialize it to be the size of the temporary string vector
//iterate over the tokens vector and fill it with data
for (int i=0; i<v.size(); i++) {
//tokenize the string here:
//by using an input stringstream
//see here: http://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g
std::istringstream f(v[i].c_str());
std::string temp;
while(std::getline(f, temp, ' ')) {
tokens[i].push_back(temp);//now tokens is completely filled with all the information from the file
}
}
//at this point, the tokens vector has been filled with the information
//now you can actually use it like you wanted:
//tokens[line-number][[position-number]
//let's test it below:
//let's see that the information is correct
for (int i=0; i<tokens.size(); i++) {
for(int j=0; j<tokens[i].size(); j++) {
std::cout << tokens[i][j] << ' ';
}
std::cout << std::endl;
}
system("pause");//only true if you use windows. (shudder)
return 0;
}
Note, I did not use iterators, which would have been beneficial here. But, that's something I think you can attempt for yourself.

C++: Large multidimensional vector causes seg fault

I have a large file (50x11k) of a grid of numbers. All i am trying to do is place the values into a vector so that i can access the values of different lines at the same time. I get a seg fault everytime (i cannot even do a cout before a the while loop). Anyone see the issue?
If there is an easier way to do this then please let me know. Its a large file and I need to be able to compare the values of one row with another so a simple getline does not work, Is there a way to jump around a file and not "grab" the lines, but just "examine" the lines so that I can later go back an examine that same line by putting in that number? Like looking at the file like a big array? I wanna look at the third line and 5 character in that line at the same time i look at the 56th line and 9th character, something like that.
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
//int g_Max = 0;
int main() {
vector<vector<string> > grid;
ifstream in("grid.txt");
int row = 0;
int column = 0;
string c;
if (!in) {
cout << "NO!";
}
while (!in.eof()) {
c = in.get();
if ( c.compare("\n") == 0) {
row++;
column = 0;
}
else {
c = grid[column][row];
cout << grid[column][row];
column++;
}
}
return 0;
}
vector<vector<string> > grid;
This declares an empty vector, with no elements.
c = grid[column][row];
This accesses elements of the vector, but there are no elements.
If you change it to use vector::at() instead of vector::operator[] like so:
c = grid.at(column).at(row);
then you'll get exceptions telling you you're accessing out of range.
You need to populate the vector with elements before you can access them. One way is to declare it with the right number of elements up front:
vector<vector<string> > grid(11000, std::vector<string>(50));
You probably also want to fix your IO loop, testing !in.eof() is usually wrong. Why not read a line at a time and split the line up, instead of reading single characters?
while (getline(in, c))
If all you need is to access all lines at once why you don't declare it as std::vector<std::string> and each line is an string??
std::string s;
std::vector<std::string> lines;
while( std::getline(in, s) ) lines.push_back( s );
std::cout << "File contain " << lines.size() << " line" << std::endl;
std::cout << "Char at [1][2] is " << lines[1][2] << std::endl; // assume [1][2] is valid!