c++ nested while loop runs only once - c++

Please can you advise, why the inner loop runs only once?
I'd like to add suffix to each line of input file and then store the result in output file.
thanks
For example:
Input file contains:
AA
AB
AC
Suffix file contains:
_1
_2
Output file should contain:
AA_1
AB_1
AC_1
AA_2
AB_2
AC_2
My result is :
AA_1
AB_1
AC_1
Code:
int main()
{
string line_in{};
string line_suf{};
string line_out{};
ifstream inFile{};
ofstream outFile{"outfile.txt"};
ifstream suffix{};
inFile.open("combined_test.txt");
suffix.open("suffixes.txt");
if (!inFile.is_open() && !suffix.is_open()) {
perror("Error open");
exit(EXIT_FAILURE);
}
while (getline(suffix, line_suf)) {
while (getline(inFile, line_in))
{
line_out = line_in + line_suf;
outFile << line_out << endl;
}
inFile.close();
outFile.close();
}
}

IMHO, a better method is to read the files into vectors, then iterate through the vectors:
std::ifstream word_base_file("combined_test.txt");
std::ifstream suffix_file("suffixes.txt");
//...
std::vector<string> words;
std::vector<string> suffixes;
std::string text;
while (std::getline(word_base_file, text))
{
words.push_back(text);
}
while (std::getline(suffix_file, text))
{
suffixes.push_back(text);
}
//...
const unsigned int quantity_words(words.size());
const unsigned int quantity_suffixes(suffixes.size());
for (unsigned int i = 0u; i < quantity_words; ++i)
{
for (unsigned int j = 0; j < quantity_suffixes; ++j)
{
std::cout << words[i] << suffix[j] << "\n";
}
}
Edit 1: no vectors
If you haven't learned about vectors or like to thrash your storage device you could try this:
std::string word_base;
while (std::getline(inFile, word_base))
{
std::string suffix_text;
while (std::getline(suffixes, suffix_text))
{
std::cout << word_base << suffix_text << "\n";
}
suffixes.clear(); // Clear the EOF condition
suffixes.seekg(0); // Seek to the start of the file (rewind).
}
Remember, after the inner while loop, the suffixes file is at the end; no more reads can occur. Thus the file needs to be positioned at the start before reading. Also, the EOF state needs to be cleared before reading.

Related

C++ Read txt and put each line into Dynamic Array

I am trying to read input.txt file, and trying to put each line into the array as string (later on I will use each element of array in initializing obj that's why I am putting each line into the array).
string* ptr = new string;
// Read Mode for Input
fstream input;
input.open("input.txt", ios::in);
int size = 0;
if (input.is_open()) {
string line;
while (getline(input, line)) {
cout << line << endl;
ptr[size] = line;
size++;
}
input.close();
}
for (int i = 0; i < size-1; i++) {
cout << "array: " << ptr[i] << endl;
}
I am getting error as:
Proxy Allocated, drain it
Don't use arrays; use std::vector. The std::vector behaves like an array and uses Dynamic Memory:
std::string s;
std::vector<std::string> database;
while (std::getline(input, s))
{
database.push_back(s);
}
Keep it simple. :-)
As was noted in the comments, if you don't know how many lines in the file then you need a container which grows on request at runtime. The natural choice is std::vector :
std::fstream input("input.txt", std::ios::in);
std::vector<std::string> lines;
std::string line;
while (getline(input, line)) {
lines.push_back(line); // std::vector allocates more memory if needed
}
for (int i = 0; i < lines.size(); i++) {
std::cout << lines[i] << std::endl;
}

Modifying a while loop that contains a break statement

I'm currently trying to write a loop to keep extracting each line from an input file using getline, and keep running until it detects the end of a paragraph.
I found this as a reference:
while (getline(inFile, line))
{
if (line.empty())
break;
else
{
for (int j = 0; j < line.length(); j++)
{
//Doing stuff here
}
}
}
I've tested this and it runs fine. However, I'm not allowed to use break statements for my assignment.
I thought I could do something like this:
while (getline(inFile, line))
{
while (!line.empty())
{
for (unsigned int i = 0; i < line.length(); i++)
{
//Do stuff
}
}
}
But the program ends up crashes when the loop iterates for the first time. I was wondering if anyone had some input how I could resolve this issue
This is how you solve it:
while (getline(inFile, line) && !line.empty()) { ... }
it has the exact same effect and it arguably improves the readability. The problem with your approach is that it causes an infinite loop. The fact that line.empty() evaluates false does not effect the outer while there.
The following also demonstrates the use of a stringstream for testing. exec contains 3 tests snippets.
int exec(int , char** )
{
int retVal = 0;
cout << "\n\n";
string s =
" now is the time\n"
" for all good men\n"
"\n" // empty line
" to come to the aid \n"; // eof()
// solution 1 has infinite loop
if(0) // disable
{
stringstream ss;
ss << s; // load ss
string line;
while (getline(ss, line))
{
while (!line.empty())
{
for (uint j=0; j < line.length(); ++j)
cout << line[j];
}
cout << endl;
}
}
// solution 2 exits too soon, line 3 is empty, line 4 dropped
{
cout << "\n\n";
stringstream ss;
ss << s; // load ss
string line;
while (getline(ss, line) && !line.empty())
{
cout << line << endl;
}
}
// output:
// now is the time
// for all good men
// solution 3 - small test effort, but seems to work
{
cout << "\n\n";
stringstream ss;
ss << s; // load ss
do
{
string line;
getline(ss, line); // read a line
if (!line.empty()) // test it has content
cout << line << endl; // use when non-empty
} while(!ss.eof()); // how continue when file has more lines
} // solution 3 seems to work
// output:
// now is the time
// for all good men
// to come to the aid
return retVal;
}

Adding words from a text file to a vector c++

I am trying to add each word from a file to a vector but if I make the size of the vector (500) and I only have 20 words in the file. The size of the vector is still considered 500. How do I fix this?
Am I doing this a bad way? Could this be made simpler?
void loadFile(string fileName)
{
vector<string> fileContents(500);
int p = 0;
ifstream file;
file.open(fileName);
if (!file.is_open()) return;
string word;
while (file >> word)
{
fileContents[p] = word;
p++;
}
for (int i = 0; i < fileContents.size(); i++)
{
cout << fileContents[i] << endl;
}
}
You could also use a more direct approach, copying immediately from the input stream.
std::vector<std::string> loadFile(std::string fileName) {
std::ifstream file(fileName);
assert(file);
std::vector<std::string> fileContents;
std::copy(std::istream_iterator<std::string>(file),
std::istream_iterator<std::string>(),
std::back_inserter(fileContents));
return fileContents;
}
#drescherjm in the comments gave me the correct answer.
void loadFile(string fileName)
{
vector<string> fileContents;
ifstream file;
file.open(fileName);
if (!file.is_open()) return;
string word;
while (file >> word)
{
fileContents.push_back(word);
}
for (int i = 0; i < fileContents.size(); i++)
{
cout << fileContents[i] << endl;
}
}

Alternative for deleted copy constrctor of ifstream

I want to extract data from a csv file but I have to get the number of rows and columns of the table first.
What I have so far is the following:
std::ifstream myfile(filename); // filename is a string and passed in by the constructor
if (myfile.is_open())
{
// First step: Get number of rows and columns of the matrix to initialize it.
// We have to close and re-open the file each time we want to work with it.
int rows = getRows(myfile);
std::ifstream myfile1(filename);
int columns = getColumns(myfile1);
if (rows == columns) // Matrix has to be quadratic.
{
std::ifstream myfile2(filename);
abwicklungsdreieck.set_Matrix(QuantLib::Matrix(rows, columns, 0)); // abwicklungsdreieck is initialised before
//...
}
else
{
std::cout << "\nNumber of rows has to equal number of columns.";
}
}
// [...]
int getRows(std::ifstream &myfile)
{
std::string line;
int rows = 0;
while (std::getline(myfile, line)) // While-loop simply counts rows.
{
rows++;
}
myfile.close();
return rows - 1;
}
int getColumns(std::ifstream &myfile)
{
std::string line;
char delimiter = ';';
size_t pos = 0;
int columns = 0;
while (std::getline(myfile, line) && columns == 0) // Consider first line in the .csv file.
{
line = line + ";";
while ((pos = line.find(delimiter)) != std::string::npos) // Counts columns.
{
line.erase(0, pos + 1);
columns++;
}
}
myfile.close();
return columns - 1;
}
This code is working. However, I have to open the file for three times which I do not like. Is there a way to evade this?
I was thinking about working with tempfiles in getRows() and getColumns() but the copying streams isn't possible since it doesn't make sense as I learned recently.
So, is there another way do that? Or can I for example evade the getline() and the line.erase() methods?
You can read the file line by line, convert each line to a stream, then read the columns on the stream:
std::ifstream myfile(filename);
if(!myfile) return 0;
std::string line;
while(std::getline(myfile, line))
{
std::stringstream ss(line);
std::string column;
while(std::getline(ss, column, ';'))
{
cout << column;
}
cout << "\n";
}
getline(myfile, line) will copy each row in to line.
Convert line to ss stream.
getline(ss, column, ';') will break the line in to columns.
Use std::stoi to convert the string in to integer.
If your matrix is based on std::vector, you can grow the vector one row at a time, so you don't need to know the size in advance.
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
void readfile(const std::string &filename)
{
std::vector<std::vector<int>> matrix;
std::ifstream myfile(filename);
if(!myfile) return;
std::string buf;
while(std::getline(myfile, buf))
{
int maxrow = matrix.size();
std::stringstream ss(buf);
matrix.resize(maxrow + 1);
cout << "break in to columns:" << buf << "\n";
while(std::getline(ss, buf, ';'))
{
try {
int num = std::stoi(buf);
matrix[maxrow].push_back(num);
}
catch(...) { }
}
}
for(auto &row : matrix) {
for(auto col : row)
cout << col << "|";
cout << "\n";
}
}

c++ initializing array storage size

void start ( string fname )
{
string FirstElement;
int count = 0 ;
fstream Infile;
Infile.open( fname.c_str(), ios::in ); // Open the input file
while(!Infile.eof()) // using while to look for the total lines
{
count++;
}
//read to the array
string data_array[]; //initializing an array
for(int i=0; !Infile.eof(); i++){
Infile >> data_array[i]; // storing the value read from file to array
}
//Display the array
// for(int i=1; i<11; i++){
// cout << data_array[i] << endl;
//}
cout << data_array[0] << endl;
cout << count << endl;
return;
}
I have a text files contain values lines by lines
My plan was to use the while loop to do a total count of the lines
and place it in the "string data_array[]" but somehow it doesnt work that way.
anyone can advise me on how can I make it in a way that It can have a flexible storage size going according to the numbers of values in the text files? thanks
For flexible storage as you call it, you may use STL's container, such as std::vector<T> or std::list<T>. Other issues are highlighted in inline comments.
// pass by reference
void start(const std::string& fname)
{
// use std::ifstream, instead of std::fstream(..., std::ios::in);
std::ifstream Infile(fname.c_str());
// prefer std::vector to raw array
std::vector<std::string> data_array;
std::string line;
// read line by line
while (std::getline(Infile, line))
{
data_array.push_back(line); // store each line
}
// print out size
std::cout << data_array.size() << std::endl;
// display the array, note: indexing starts from 0 not 1 !
for(int i = 0; i < data_array.size(); ++i)
{
std::cout << data_array[i] << std::endl;
}
}