c++ String from file to vector - more elegant way - c++

I write a code in which I want to pass several strings from text file to string vector. Currently I do this that way:
using namespace std;
int main()
{
string list_name="LIST";
ifstream REF;
REF.open(list_name.c_str());
vector<string> titles;
for(auto i=0;;i++)
{
REF>>list_name;
if(list_name=="-1"){break;}
titles.push_back(list_name);
}
REF.close();
cout<<titles.size();
for(unsigned int i=0; i<titles.size(); i++)
{
cout<<endl<<titles[i];
}
It works fine, I get the output as expected. My concern is is there more elegant way to pass string from text file to vector directly, avoiding this fragment, when passing string from filestream to string object and assigning it to the vector with push_back as separate step:
REF>>list_name;
if(list_name=="-1"){break;}
titles.push_back(list_name);

More elegant way with algorithms
std::copy_if(std::istream_iterator<std::string>(REF),
std::istream_iterator<std::string>(),
std::back_inserter(titles),
[](const std::string& t) { return t != "-1"; });

The other answers are maybe too complicated or too complex.
Let me first do a small review of your code. Please see my comments within the code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std; // You should not open the full std namespace. Better to use full qualifiacation
int main()
{
string list_name = "LIST";
ifstream REF; // Here you coud directly use the construct ofr the istream, which will open the file for you
REF.open(list_name.c_str()); // No need to use c_str
vector<string> titles; // All variables should be initialized. Use {}
for (auto i = 0;; i++) // Endless loop. You could also write for(;;), but bad design
{
REF >> list_name;
if (list_name == "-1") { break; } // Break out of the endless loop. Bad design. Curly braces not needed
titles.push_back(list_name);
}
REF.close(); // No nbeed to close the file. With RAII, the destructor of the istream will close the file for you
cout << titles.size();
for (unsigned int i = 0; i < titles.size(); i++) // Better to use a range based for loop
{
cout << endl << titles[i]; // end not recommended. For cout`'\n' is beter, because it does not call flush unneccesarily.
}
}
You see many points for improvement.
Let me explain some of the more important topics to you.
You should use the std::ifstreams constructor to directly open the file.
Always check the result of such an operation. The bool and ! operator for the std::ifstream are overwritten. So a simple test can be done
Not need to close the file. The Destructor of the std::ifstream will do that for you.
There is a standard approach on how to read a file. Please see below.
If you want to read file until EOF (end of file) or any other condition, you can simply use a while loop and call the extraction operator >>
For example:
while (REF >> list_name) {
titles.push_back(list_name);
}
Why does this work? The extraction operator will always return a reference to the stream with what it was called. So, you can imagine that after reading the string, the while would contain while (REF), because REF was returned by (REF >> list_name. And, as mentioned already, the bool operator of the stream is overwritten and returns the state of the stream. If there would be any error or EOF, then if (REF) would be false.
So and now the additional condition: A comparison with "-1" can be easily added to the while statement.
while ((REF >> list_name) and (list_name != "-1")) {
titles.push_back(list_name);
}
This is a safe operatrion, because of boolean short-cut evaluation. If the first condition is already false, the second will not be evaluated.
With all the knwo-how above, the code could be refactored to:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
int main() {
// Here our source data is stored
const std::string fileName{ "list.txt" };
// Open the file and check, if it could be opened
std::ifstream fileStream{ fileName };
if (fileStream) {
// Here we will store all titles that we read from the file
std::vector<std::string> titles{};
// Now read all data and store vit in our resulting vector
std::string tempTitle{};
while ((fileStream >> tempTitle) and (tempTitle != "-1"))
titles.push_back(tempTitle);
// For debug purposes. Show all titles on screen:
for (const std::string title : titles)
std::cout << '\n' << title;
}
else std::cerr << "\n*** Error: Could not open file '" << fileName << "'\n";
}

If you knew the number of strings to read beforehand, you could
using StringVector = std::vector<std::string>;
int main(int argc, const char* argv) {
constexpr size_t N = 4; // or however many strings you want...
StringVector data(N);
std::ifstream stream("foo.txt");
for (size_t i =0; (i < N) && stream; i++) {
stream >> data[i];
}
}
But this would be less flexible and it would be trickier to implement your "-1" "terminator" convention.
If that "-1" thing is a true requirement (in contrast to an arbitrary choice), and if you use this more than once, it might pay off to "abstract", how you read those strings. Abstraction is usually done in form of a function.
// compile with:
// clang++-13 -std=c++20 -g -O3 -o words words.cpp
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using StringVector = std::vector<std::string>;
std::istream& operator>> (std::istream& stream, StringVector& sv)
{
std::string word;
while (stream) {
stream >> word;
if (word == "-1")
return stream;
sv.push_back(word);
}
return stream;
}
std::ostream& operator<< (std::ostream& stream,
const StringVector& sv) {
for (const auto& s : sv) {
stream << s << std::endl;
}
return stream;
}
int main(int argc, const char* argv[]) {
std::string file_data{R"(word1 word2
word3
word4 -1)"};
std::istringstream stream(file_data);
StringVector data;
data.reserve(10);
stream >> data;
std::cout
<< "Number of strings loaded: "
<< data.size() << std::endl;
std::cout << data;
return 0;
}
The above operator>>() works for streams in general, so it also works for file streams.
As an aside: One reason, why people would not like the "-1" terminator approach is performance. If you keep pushing into a vector an arbitrary amount of times, the storage of the vector needs to be re-allocated as the vector grows, which is avoidable overhead. So, usually people would use another file format, e.g. giving the number of strings first, then the strings, which would allow for:
size_t n;
stream >> n;
StringVector data;
data.reserve(n); // avoids "spurious reallocs as we load the strings"
for (size_t i = 0; i < n; i++) { ... }

Related

How to skip blank line when reading file in C++?

I want to skip blank line when readhing a file.
I've tried if(buffer == "\n") and if(buffer.empty()), but it not work. I did like this:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream file_pointer;
file_pointer.open("rules.txt", ios::in);
if(!file_pointer.is_open())
{
cout << "failed to read rule file." << endl;
return 0;
}
string buffer;
while(getline(file_pointer, buffer))
{
if(buffer.empty())
{
continue;
}
if(buffer == "\n")
{
continue;
}
cout << buffer << endl;
}
file_pointer.close();
return 0;
}
The problem is that a “blank” line need not be “empty”.
#include <algorithm> // std::any_of
#include <cctype> // std::isspace
#include <fstream>
#include <iostream>
//using namespace std;
bool is_blank( const std::string & s )
{
return std::all_of( s.begin(), s.end(), []( unsigned char c )
{
return std::isspace( c );
} );
}
int main()
{
std::ifstream rules_file("rules.txt");
if(!rules_file)
{
std::cerr << "failed to read rule file." << endl;
return 1;
}
std::string line;
while(getline(rules_file, line))
{
if(is_blank(line))
{
continue;
}
std::cout << line << "\n";
}
return 0;
}
A few notes.
Get used to writing std:: infront of things from the Standard Library. Importing everything en masse with using namespace std is almost always a bad idea.
C++ file streams are not pointers. Moreover, be descriptive with your names! It makes reading your code easier for your future self. Honest!
Open a file at the file stream object creation. Let it close at object destruction (which you did).
Report errors to standard error and signal program failure by returning 1 from main().
Print normal output to standard output and signal program success by returing 0 from main().
It is likely that std::any_of() and lambdas are probably not something you have studied yet. There are all kinds of ways that is_blank() could have been written:
bool is_blank( const std::string & s )
{
for (char c : s)
if (!std::isspace( (unsigned char)c ))
return false;
return true;
}
Or:
bool is_blank( const std::string & s )
{
return s.find_first_not_of( " \f\n\r\t\v" ) == s.npos;
}
Etc.
The reason that the checking for newline didn’t work is that getline() removes the newline character(s) from the input stream but does not store it/them in the target string. (Unlike fgets(), which does store the newline so that you know that you got an entire line of text from the user.) C++ is much more convenient in this respect.
Overall, you look to be off to a good start. I really recommend you make yourself familiar with a good reference and look up the functions you wish to use. Even now, after 30+ years of this, I still look them up when I use them.
One way to find good stuff is to just type the name of the function in at Google: “cppreference.com getline” will take you to the ur-reference site.
https://en.cppreference.com — “the” C and C++ reference site
https://cplusplus.com/reference/ — also good, often an easier read for beginners than cppreference.com
https://www.learncpp.com/ — a good site to learn how to do things in C++
You can skip blank lines when reading a file in C++ by using the getline() function and checking the length of the resulting string. Here is an example of how you can do this:
#include <fstream>
#include <string>
int main() {
std::ifstream file("myfile.txt");
std::string line;
while (std::getline(file, line)) {
if (line.length() == 0) { // check if the line is empty
continue; // skip the iteration
}
// process the non-empty line
}
file.close();
return 0;
}
You can also use the std::stringstream class to skip blank lines, here is an example:
#include <fstream>
#include <sstream>
#include <string>
int main() {
std::ifstream file("myfile.txt");
std::string line;
while (std::getline(file, line)) {
std::stringstream ss(line);
if (ss >> line) { // check if the line is empty
// process the non-empty line
}
}
file.close();
return 0;
}
(1) Here's a solution using the ws manipulator in conjunction with the getline function to ignore leading white-space while reading lines of input from the stream. ws is a manipulator that skips whitespace characters (demo).
#include <iostream>
#include <string>
int main()
{
using namespace std;
string line;
while (getline(cin >> ws, line))
cout << "got: " << line << endl;
return 0;
}
Note that the spaces are removed even if the line is not empty (" abc " becomes "abc ".
(2) If this is a problem, you could use:
while (getline(cin, line))
if (line.find_first_not_of(" \t") != string::npos)
cout << "got: " << line << endl;

Reading custom file formats in C++

I read configuration files of the following format into my C++ code:
# name score
Marc 19.7
Alex 3.0
Julia 21.2
So far, I have adapted a solution found here: Parse (split) a string in C++ using string delimiter (standard C++). For example, the following code snippet reads in the file line by line, and for each line calls parseDictionaryLine, which discards the first line, splits the string as described in the original thread, and inserts the values into a (self-implemented) hash table.
void parseDictionaryLine(std::string &line, std::string &delimiter, hash_table &table) {
size_t position = 0;
std::string name;
float score;
while((position = line.find(delimiter)) != std::string::npos) {
name = line.substr(0, position);
line.erase(0, position + delimiter.length());
score = stof(line);
table.hinsert(name, score);
}
}
void loadDictionary(const std::string &path, hash_table &table) {
std::string line;
std::ifstream fin(path);
std::string delimiter = " ";
int lineNumber = 0;
if(fin.is_open()) {
while(getline(fin, line)) {
if(lineNumber++ < 1) {
continue; // first line
}
parseDictionaryLine(line, delimiter, table);
}
fin.close();
}
else {
std::cerr << "Unable to open file." << std::endl;
}
}
My question would be, is there a more elegant way in C++ to achieve this task? In particular, is there (1) a better split function as for example in Python, (2) a better method to test if a line is a comment line (starting with #), like startsWith (3) potentially even in iterator that handles files similar to a context manager in Python and makes sure the file will actually be closed? My solution works for simple cases shown here but becomes more clunky with more complicated variations such as several comment lines at unpredictable positions and more parameters. Also, it worries me that my solution does not check if the file actually agrees with the prescribed format (two values per line, first is string, second is float). Implementing these checks with my method seems very cumbersome.
I understand there is JSON and other file formats with libraries made for this use case, but I am dealing with legacy code and cannot go there.
I will try to answer all your questions.
First for splitting a string, you should not use the linked question/answer. It is from 2010 and rather outdated. Or, you need to scroll at the very bottom. There you will find more modern answers.
In C++ many things are done with iterators. Because a lot of algorithms or constructors in C++ work with iterators. So, the better approch for splitting a string is to use iterators. This will then always result in a one liner.
Background. A std::string is also a container. And you can iterate over elements like for example words or values in it. In case of space separated values you can use the std::istream_iterator on a std::istringstream. But since years there is a dedicated iterator for iterating of patterns in a string:
The std::sregex_token_iterator. And because it is specifically designed for that purpuse, it should be used.
Ans if it is used for splitting the strings, the overhead of using regexes is also minimal. So, you may split on strings, commas, colons or whatever. Example:
#include <iostream>
#include <string>
#include <vector>
#include <regex>
const std::regex re(";");
int main() {
// Some test string to be splitted
std::string test{ "Label;42;string;3.14" };
// Split and store whatever number of elements in the vector. One Liner
std::vector data(std::sregex_token_iterator(test.begin(), test.end(), re, -1), {});
// Some debug output
for (const std::string& s : data) std::cout << s << '\n';
}
So, regardless of the number of patterns, it will copy all data parts into the std::vector.
So, now you have a one liner solution for splitting strings.
For checking. if the first character is a string, you may use
the index operator (if (string[0] == '#'))
or, the std::string's front function (if (string.front() == '#'))
or again a regex
But, here you need to be careful. The string must not be empty, so, better write:
if (not string.empty() and string.front() == '#')
Closing file or iterating over files.
If you use a std::ifstream then the constructor will open the file for you and the destructor will automatically close it, when the stream variable rund out of scope. The typical pattern here is:
// Open the file and check, if it coud be opened
if (std::iftsream fileStream{"test.txt"};fileStream) {
// Do things
} // <-- This will close the file automatically for you
Then, in general you shoud use a more object oriented approach. Data, and methods operating on this data, should be encapsulated in one class. Then you would overwrite the extractor operatoe >> and the inserter operator << to read and write the data. This, because only the class should know, how to handle the data. And if you decide to use a different mechanism, modify your class and the rest of the outside world will still work.
In your example case, input and output is that simple, that easiest IO will work. No splitting of string necessary.
Please see the following example.
And note especially the only few statements in main.
If you change something inside the classes, it will simple continue to work.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
// Data in one line
struct Data {
// Name and score
std::string name{};
double score{};
// Extractor and inserter
friend std::istream& operator >> (std::istream& is, Data& d) { return is >> d.name >> d.score; }
friend std::ostream& operator << (std::ostream& os, const Data& d) { return os << d.name << '\t' << d.score; }
};
// Datbase, so all data from the source file
struct DataBase {
std::vector<Data> data{};
// Extractor
friend std::istream& operator >> (std::istream& is, DataBase& d) {
// Clear old data
d.data.clear(); Data element{};
// Read all lines from source stream
for (std::string line{}; std::getline(is, line);) {
// Ignore empty and command lines
if (not line.empty() and line.front() != '#') {
// Call extractor from Data class end get the data
std::istringstream(line) >> element;
// And save new data in the datbase
d.data.push_back(std::move(element));
}
}
return is;
}
// Inserter. Output all data
friend std::ostream& operator << (std::ostream& os, const DataBase& d) {
std::copy(d.data.begin(), d.data.end(), std::ostream_iterator<Data>(os, "\n"));
return os;
}
};
int main() {
// Open file and check, if it is open
if (std::ifstream ifs{ "test.txt" }; ifs) {
// Our database
DataBase db{};
// Read all data
ifs >> db;
// Debug output show all data
std::cout << db;
}
else std::cerr << "\nError: Could not open source file\n";
}
You can use operator>> to split at delimiters for you, like this:
#include <iostream>
#include <sstream>
#include <unordered_map>
std::istringstream input{
"# name score\n"
"Marc 19.7\n"
"Alex 3.0\n"
"Julia 21.2\n"
};
auto ReadDictionary(std::istream& stream)
{
// unordered_map has O(1) lookup, map has n(log n) lookup
// so I prefer unordered maps as dictionaries.
std::unordered_map<std::string, double> dictionary;
std::string header;
// read the first line from input (the comment line or header)
std::getline(stream, header);
std::string name;
std::string score;
// read name and score from line (>> will split at delimiters for you)
while (stream >> name >> score)
{
dictionary.insert({ name, std::stod(score) });
}
return dictionary;
}
int main()
{
auto dictionary = ReadDictionary(input); // todo replace with file stream
// range based for loop : https://en.cppreference.com/w/cpp/language/range-for
// captured binding : https://en.cppreference.com/w/cpp/language/structured_binding
for (const auto& [name, score] : dictionary)
{
std::cout << name << ": " << score << "\n";
}
return 0;
}

C++ Read in a file like a grid

I'm coding in C++ and I'm trying to read in a file that I'd like to access certain chars at later. As in, what is the char at (line x, char y), at any given point in the file.
My only thought right now is to look for a newline character, and somehow index them so that I can refer back to newline x, check the length of a line, and pull a char at whatever position given the line length.
I'm not sure if that is a good approach or not.
Try this (for character in line "lineNum" and column "columnNum"):
ifstream inf;
inf.open(filename); //filename being c-string
string str;
for (int i = 0; i < lineNum; i++)
{
std::getline(inf, str);
}
This way "str" stores the line you are interested in (automatically checks for newline character and stops).
Then you can use:
char chr = str[columnNum];
to store the character you want in "chr" variable. And don't forget:
inf.close();
Unfortunately, to my knowledge you need to repeat this process every time you want to access a character.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#define FILENAME "File.txt"
class FileGrid {
public:
typedef std::vector<std::string> Line;
typedef std::vector<std::string>::const_iterator LineIter;
typedef std::vector<std::vector<std::string>> StringMap;
typedef std::vector<std::vector<std::string>>::const_iterator StringMapIter;
void FillGrid(char* fileName) {
grid.clear();
std::ifstream in(FILENAME, std::ifstream::in);
if (!in.is_open()) {
std::cout << "problem reading " << FILENAME << std::endl;
return;
}
std::string words;
std::string word;
std::stringbuf buffer;
while (in.is_open() && std::getline(in, words)) {
std::stringstream ss(words);
Line line;
while (ss >> word) {
line.push_back(word);
}
grid.push_back(line);
}
}
void PrintGrid() {
StringMapIter b = grid.begin();
StringMapIter e = grid.end();
std::cout << "\t\tFile Content:" << std::endl;
while(b != e) {
for (unsigned int i = 0; i < b->size(); ++i) {
std::cout << b->operator[](i) << " ";
}
std::cout << std::endl;
++b;
}
}
char const & GetChar(int lineNo, int charNo) {
// LineNo checks etc
Line const & line = grid[lineNo];
for(std::string const & word : line ) {
if(charNo > word.size() + 1) {
charNo -= word.size() + 1;
}
else {
return word[charNo];
}
}
throw std::exception("charNo higher");
}
private:
StringMap grid;
};
void main() {
FileGrid grid;
grid.FillGrid(FILENAME);
grid.PrintGrid();
std::cout << grid.GetChar(0, 3); // should return first line, 4th character
}
Not the best code I've ever written but pretty much what I could do in a short time.
FileGrid handles reading and accessing the data. It reads the file line by line and stores it in a std::vector. When it finishes reading a line, it pushes that into another std::vector. In the end, we have a (sort of) 2D array of strings.
Again, not the best code and definitely not the most optimized code but the idea is still the same: read from the file line by line, separate each word and put them into an array of strings. If you can't use STL, you can dynamically create a 2D array for each line but since I don't know the specific requirements of your question, I just wrote something simple and bruteforce to show you the main way of storing grid of strings into the memory.
As long as it works. But reading the entire file into memory, if that's an option, would be simpler.

Read file into array and return it from a function C++

In Lua, I have such a function to read a file into an array:
function readFile(file)
local output = {}
local f = io.open(file)
for each in f:lines() do
output[#output+1] = each
end
f:close()
return output
end
Now in C++, I tried to write that like this:
string * readFile(file) {
string line;
static string output[] = {};
ifstream stream(file);
while(getline(stream, line)) {
output[sizeof(output)+1] = line;
}
stream.close();
return output;
}
I know you can't return arrays from functions, only pointers. So I did this:
string *lines = readFile("stuff.txt");
And it threw me the error cannot convert 'std::string {aka std::basic_string<char>} to' std::string* {aka std::basic_string<char>*}' in intialization string *lines = readFile("stuff.txt");
Can anyone tell me what is wrong here, and is there a better way to read files into arrays?
EDIT:
I'm going to be using the returned array to do value matching using a for loop. In Lua this would be written as:
for _, each in ipairs(output) do
if each == (some condition here) then
--Do Something
end
end
How can this be done in C++, using vectors (according to the answer by Jerry Coffin)?
EDIT 2:
I can't match the vectors correctly for some reason. I wrote the code in a separate test file.
int main() {
vector<string> stuff = read_pass();
cout << stuff.size() << endl;
cout << stuff[0] << endl;
if (stuff[0] == "admin") {
cout << "true";
}
else {
cout << "false";
}
return 0;
}
read_pass() looks like this:
vector<string> read_pass() {
ifstream stream("stuff.txt");
string line;
vector<string> lines;
while(getline(stream, line)) {
lines.push_back(line);
}
stream.close();
return lines;
}
And stuff.txt looks like this:
admin
why?
ksfndj
I just put it some random lines to test the code. Every time I compile and run main.cpp the output I get is
3
admin
false
So why isn't the code being matched properly?
EDIT 3:
So instead of forcing myself down the vectors method of doing things, I decided to try this instead:
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include "basefunc.h"
using namespace std;
int main() {
string storedUsrnm;
string storedPw;
string pw = "admin";
string usrnm = "admin";
ifstream usernames("usrnm.accts");
ifstream passwords("usrpw.accts");
while(getline(usernames, storedUsrnm)) {
getline(passwords, storedPw);
print("StoredUsrnm " + storedUsrnm);
print("StoredPw: " + storedPw);
if (storedUsrnm == usrnm && storedPw == pw) {
print("True!");
return 0;
}
}
print("False!");
return 0;
}
Where print() is
void print(string str) {
cout << str << endl;
}
This still prints false, at the end, and it leads me to believe that for some reason, the "admin" read by the ifstream is different from the "admin" string. Any explanations for how this is so? Or does this code not work either?
Doesn't look to me like your current code should even compile. Anyway, I'd probably do something like this:
std::vector<std::string> read_file(std::istream &infile) {
std:string line;
std::vector<std::string> lines;
while (std::getline(infile, line))
lines.push_back(line);
return lines;
}
So the basic idea here is to read a line from the file, and if that succeeded, add that line (with push_back) to the vector of results. Repeat until reading a line from the file fails. Then return the vector of all the lines to the caller.
A few notes: especially at first, it's fairly safe to presume that any use of pointers is probably a mistake. That shouldn't be taken as an indication that pointers are terribly difficult to work with, or anything like that--just that they're almost never necessary for the kinds of things most relative beginners do in C++.
Likewise with arrays--at first, assume that what you might think of as an array in some other language translates to a std::vector in C++. C++ does also have arrays, but using them can wait a while (a long while, IMO--I've been writing C++ for decades now, and virtually never use raw pointers or arrays at all).
In the interest of simplicity, I've consolidated the data into the program, so it reads the data from the stringstream, like this:
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
vector<string> read_pass(istream &is) {
string line;
vector<string> lines;
while (getline(is, line)) {
lines.push_back(line);
}
return lines;
}
int main() {
istringstream input{ "admin\nwhy?\nksfndj" };
// To read from an external file, change the preceding line to:
// ifstream input{ "stuff.txt" };
vector<string> stuff = read_pass(input);
cout << stuff.size() << endl;
cout << stuff[0] << endl;
if (stuff[0] == "admin") {
cout << "true";
}
else {
cout << "false";
}
return 0;
}
At least for me, this produces:
3
admin
true
...indicating that it has worked as expected. I get the same with an external file. If you're not getting the same with an external file, my immediate guess would be that (at least the first line of) the file contains some data you're not expecting. If the problem continues, you might consider writing out the individual characters of the strings you read in numeric format, to give a more explicit idea of what you're really reading.
After a long time, I finally came up with the answer
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <map>
using namespace std;
typedef map<int, string> strArr;
strArr readFile(string file) {
ifstream stream(file);
string line;
strArr output;
while(getline(stream, line)) {
output[output.size()+1] = line;
}
stream.close();
return output;
}
It doesn't read the file into an array, but it does return a map that does basically the same thing

How To Parse String File Txt Into Array With C++

I am trying to write a C++ program, but I am not familiar with C++. I have a .txt file, which contains values as follows:
0
0.0146484
0.0292969
0.0439453
0.0585938
0.0732422
0.0878906
What I have done in my C++ code is as follows:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
string line;
ifstream myReadFile;
myReadFile.open("Qi.txt");
if(myReadFile.is_open())
{
while(myReadFile.good())
{
getline(myReadFile,line);
cout << line << endl;
}
myReadFile.close();
}
return 0;
}
I would like to make the output of the program an array, i.e.
line[0] = 0
line[1] = 0.0146484
line[2] = 0.0292969
line[3] = 0.0439453
line[4] = 0.0585938
line[5] = 0.0732422
line[6] = 0.0878906
Assuming you want your data stored as floating point numbers (not strings) you probably want to do something like this:
#include <iostream>
#include <vector>
#include <iterator>
#include <fstream>
int main() {
std::ifstream in("Qi.txt");
// initialize the vector from the values in the file:
std::vector<double> lines{ std::istream_iterator<double>(in),
std::istream_iterator<double>() };
// Display the values:
for (int i=0; i<lines.size(); i++)
std::cout << "lines[" << i << "] = " << lines[i] << '\n';
}
Just a quick note on style: I prefer to see variables fully initialized right when you create them, so std::ifstream in("Qi.txt"); is preferable to std::ifstream in; in.open("Qi.txt");. Likewise, it's preferable to initialize the vector of lines directly from istream iterators rather than create an empty vector, then fill it in an explicit loop.
Finally, note that if you insist on writing an explicit loop anyway, you never want to use something like while (somestream.good()) or while (!somestream.eof()) to control your loop -- these are mostly broken, so they don't (dependably) read a file correctly. Depending on the type of data involved, they'll frequently appear to read the last item from the file twice. Usually, you want something like while (file >> value) or while (std::getline(file, somestring)). These check the state of the file immediately after reading, so as soon as reading fails they fall out of the loop, avoiding the problems of the while (good()) style.
Oh, as a side note: this is written expecting a compiler that (at lest sort of) conforms with C++11. For an older compiler you'd want to change this:
// initialize the vector from the values in the file:
std::vector<double> lines{ std::istream_iterator<double>(in),
std::istream_iterator<double>() };
...to something like this:
// initialize the vector from the values in the file:
std::vector<double> lines(( std::istream_iterator<double>(in)),
std::istream_iterator<double>() );
First you'll need a vector:
std::vector<std::string> lines; // requires #include <vector>
Then you'll need to take a string taken from the getline operation, and push it back into the vector. It's very simple:
for (std::string line; std::getline(myReadFile, line);)
{
lines.push_back(line);
}
For an output operation, all you need is:
{
int i = 0;
for (auto a : lines)
{
std::cout << "lines[" << i++ << "] = " << a << std::endl;
}
}
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
string line;
ifstream myReadFile;
myReadFile.open("Qi.txt");
if(myReadFile.is_open())
{
for(int i=0;i<7;++i)
if(myReadFile.good())
{
getline(myReadFile,line);
cout<<"line["<<i<<"] = " << line << endl;
}
myReadFile.close();
}
return 0;
}