I am trying to read a certain line from a text file using a function for later use, but it does not seem to be returning a string. Function below:
std::vector<std::string> TextArray(string filePath) {
int arrayNum = 0;
std::vector<std::string> stringArray;
ifstream file (filePath);
std::string str;
while (std::getline(file,str)){
stringArray.push_back(str);
}
return stringArray;//returns an array
}
Inside main:
std::vector<std::string> fileString = TextArray("c:/computerAi/saved");
std::cout << fileString[1] << std::endl;
I get an error saying "Vector subscript out of range"
I suspect that the path may be the problem. "c:/computerAi/saved" is not a valid path. It should be "C:\\computerAi\\saved". The double backslashes are necessary because backslash is the escape character in C/C++. If the file stream failed to open, then the vector might be empty. Also, I'm assuming here that C:\computerAi\saved is actually a file and not a directory.
Also, as bvj mentioned in a comment, subscript 1 is the second element in the vector, not the first. So, if you were wanting the first element, try fileString[0] instead of fileString[1].
Edit: I still suspect that the path is the problem. The following program works for me:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
std::vector<std::string> TextArray(std::string filePath)
{
int arrayNum = 0;
std::vector<std::string> stringArray;
std::ifstream file(filePath.c_str());
std::string str;
while (std::getline(file,str))
{
stringArray.push_back(str);
}
return stringArray;//returns an array
}
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<std::string> fileString = TextArray("c:\\temp\\testing.txt");
std::cout << fileString[1] << std::endl;
return 0;
}
When I tried this program with an invalid path (a file that did not exist,) I got the exact behavior described by the question. When I tried it with a valid path, it returned the second line of the input file, exactly as expected.
Related
I'm trying to find the longest word on a file in c++. I have the solution for that but the code is also considering the punctuation and I don't know how to avoid this.
This is the function "get_the_longest_word()":
string get_the_longest_word(const string &file_name){
int max=0;
string s,longest_word;
ifstream inputFile(file_name);
if(inputFile.is_open())
{
while(inputFile>>s)
{
if(s.length()>max)
{
max=s.length();
s.swap(longest_word);
}
}
inputFile.close();
}else
cout<<"Error while opening the file!!\n";
return longest_word;}
Thanks in advance for the help
In c++ we have since long a good method to specify patterns of characters, that form a word. The std::regex. It is very easy to use and very versatile.
A word, consisting of 1 or many alphanum characters can simply be defined as \w+. Nothing more needed. If you want other patterns, then this is also easy to create.
And for such programs like yours, there is also no complexity overhead or runtime issue with regexes. So, it should be used.
Additionally, we have a very nice iterator, with which we can iterate over such patterns in a std::string. The std::sregex_token_iterator. And this makes life really simple. With that, we can use many useful algorithms provided by C++.
For example std::maxelement which takes 2 iterators and then returns the max element in the given range. This is, what we need.
And then the whole program boils down to just a few simple statements.
Please see:
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <regex>
#include <algorithm>
const std::regex re{ "\\w+" };
std::string getLongestWord(const std::string& fileName) {
std::string result{};
// Open the file and check, if it could be opened
if (std::ifstream ifs{ fileName }; ifs) {
// Read complete file into a string. Use range constructor of string
std::string text(std::istreambuf_iterator<char>(ifs), {});
// Get the longest word
result = *std::max_element(std::sregex_token_iterator(text.begin(), text.end(), re), {}, [](const std::string& s1, const std::string& s2) {return s1.size() < s2.size(); });
} // Error, file could not be opened
else std::cerr << "\n*** Error. Could not open file '" << fileName << "'\n\n";
return result;
}
int main() {
std::cout << getLongestWord("text.txt") << '\n';
}
1I am currently working on a project of creating my own game in OpenGL. My problem is right now, that if I read a file, that my function reading that file results in a SIGABRT, because of something inside the std::ifstream deconstructor (more specifically in "std::basic_ifstream<char, std::char_traits<char> >::~basic_ifstream()"). This function previously worked for me, but suddenly stopped working.
My Goal is simple: A reliable implementation for reading a file to a char*. Multi threading is currently not my concern.
Here is my implementation of the file reading function.
It takes in a path, and should write the content of the file at that path into the out parameter.
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <cassert>
#include "Utility.h"
char * Utility::readFile(const char* path,char*& out){
#ifndef NDEBUG
std::cout<<"Getting file: "<<path<<"\n";
#endif
// Open the file, but freak out if not valid.
std::ifstream file=std::ifstream(path);
assert(file.good());
if(!file.good())
{
throw std::runtime_error((std::string)"Couldn't open file for loading: "+path);
}
// Read the file contents into a char buffer.
std::stringstream buffer;buffer << file.rdbuf();
std::string fileContentsStr = buffer.str();
out = new char[fileContentsStr.size()];
strcpy(out,fileContentsStr.c_str());
return out;
}
My code is located at C0D3-M4513R/OpenGlGame.
I already tried a minimal example, which is working and using the same compile flags (except linker flags). test.txt and test1.txt just contain some rubbish text generated by randomly hacking on my keyboard.
#include <cassert>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
//This Function is the same as the one above!!!
char *readFile(const char *path, char *&out) {
#ifndef NDEBUG
std::cout << "Getting file: " << path << "\n";
#endif
// Open the file, but freak out if not valid.
std::ifstream file = std::ifstream(path);
assert(file.good());
if (!file.good()) {
throw std::runtime_error((std::string) "Couldn't open file for loading: " + path);
}
// Read the file contents into a char buffer.
std::stringstream buffer;
buffer << file.rdbuf();
//convert the stringstream to a string
std::string fileContentsStr = buffer.str();
//copy the contents of the string to a char array
out = new char[fileContentsStr.size()];
strcpy(out, fileContentsStr.c_str());
//return char array address (which should be the same as the start?)
return out;
}
int main() {
//The programm started!
std::cout << "Hello, World!" << std::endl;
//Define a space for the contents of the file to live
char *out;
//Read the contents of a file
out = readFile("test.txt", out);
//Print contents of the file
std::cout << out << std::endl;
char *out1;
//Read the contents of a file
out1 = readFile("test1.txt", out1);
//Print contents of the file
std::cout << out1 << std::endl;
return 0;
}
strcpy:
Copies the character string pointed to by src, including the null terminator, to the character array whose first element is pointed to by dest.
The behavior is undefined if the dest array is not large enough. The behavior is undefined if the strings overlap.
c_str:
Returns a pointer to a null-terminated character array with data equivalent to those stored in the string.
out = new char[fileContentsStr.size()];
strcpy(out,fileContentsStr.c_str());
You need to be careful when mixing std::string with c-strings, because a std::string is not null-terminated and does not count the nullterminator for its size. However, c_str does return a pointer to a null-terminated character array.
You are asking strcpy to write fileContentsStr.size()+1 (size + null terminator) into a char array with only fileContentsStr.size() elements.
PS: As mentioned in a comment, you should consider to return a std::string instead. You are using a raw owning pointer which is error prone and should be avoided. Either use a smart-pointer or let a std::string manage the char-array (thats what its made for actually ;).
This question already has answers here:
Read file line by line using ifstream in C++
(8 answers)
Closed 3 years ago.
I cant write a words from a file to an array.
I have tried to use char and strings, but i have problem with both of them.
FILE *file = fopen("films.txt", "r");
string FILMS[500];
while (!feof(file))
{
fscanf(file, "%s", FILMS);
//fgets(FILMS, 500, file);
}
I expect that in each cell there will be a word.
Use the C++ classes and functions to make it easier. Instead of a fixed C style array of exactly 500 films, use a std::vector<std::string>> that will grow dynamically when you put film titles in it.
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> get_films() {
std::ifstream file("films.txt");
std::vector<std::string> FILMS;
if(file) { // check that the file was opened ok
std::string line;
// read until getline returns file in a failed/eof state
while(std::getline(file, line)) {
// move line into the FILMS vector
FILMS.emplace_back(std::move(line));
// make sure line is in a specified state again
line.clear();
}
}
return FILMS;
} // an fstream is automatically closed when it goes out of scope
int main() {
auto FILMS = get_films();
std::cout << "Read " << FILMS.size() << " film titles\n";
for(const std::string& film : FILMS) {
std::cout << film << "\n";
}
}
As I'm not sure why you tried using c style arrays and files, I posted a 'not too elegant' solution like that one, too, hoping it might help. You could always try to make it more dynamic with some malloc (or new), but I sticked with the easy solution for now.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
void readcpp(const char* fname, std::vector<std::string>& data)
{
std::ifstream file_in(fname, std::ios::in);
if (file_in.is_open())
{
std::string film;
while (std::getline(file_in, film))
{
data.push_back(film);
}
file_in.close();
}
else std::cerr << "file cant be opened" << std::endl;
}
#include <cstdio>
#include <cstdlib>
#include <cstring>
void readc(const char* fname, char data[500][500])
{
FILE* file_in = fopen(fname, "r");
if (file_in)
{
char film[500];
for (unsigned int i = 0; fgets(film, 500, file_in) && i < 500; i++)
{
memcpy(data + i, film, 500);
}
fclose(file_in);
}
else fprintf(stderr, "file cant be opened\n");
}
int main()
{
const char* fname = "films.txt";
char cFilms[500][500];
std::vector<std::string> cppFilms;
readc(fname, cFilms);
readcpp(fname, cppFilms);
return 0;
}
And as the others mentioned before, do not use feof or for that matter, ifstream's eof member function either, for checking wheter you reached the end of file, as it may be unsafe.
Hm, I see a lot of code in answers.
The usage of algorithm will drastically reduce coding effort.
Additionally it is a "more modern" C++ approach.
The OP said, that he want to have words in some array. OK.
So we will use a std::vector<std::string> for storing those words. As you can see in cppreference, the std::vector has many different constructors. We will use number 4, the range constructor.
This will construct the vector with a range of similar data. The similar data in our case are words or std::string. And we would like to read the complete range of the file, beginning with the first word and ending with the last word in the file.
For iterating over ranges, we use iterators. And for iterating of data in files, we use the std::istream_iterator. We tell this function what we want to read as template parameter, in our case a std::string. Then we tell it, from which file to read.
Since we do not have files on SO, I use a std::istringstream. But that's the same reading from a std::ifstream. If you have na open file stream, then you can hand it over to the std::istream_iterator.
And the result of using this C++ algorithms is that we read the complete file into the vector by just defining the varaible with its constructer as a one-liner.
We do similar for the debug output.
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <sstream>
std::istringstream filmFile{ R"(Film1 Film2
Film3 Film4 Film5
Film6
)" };
int main()
{
// Define the variable films and use its range constructor
std::vector<std::string> films{ std::istream_iterator<std::string>(filmFile), std::istream_iterator<std::string>() };
// For debug pruposes, show result on console
std::copy(films.begin(), films.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
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
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;
}