I have text file which has n words. I am trying to read it and print using c++. But, I am able to print only last string. Please help me
int main()
{
ifstream inFile;
inFile.open("test.txt");
if (inFile.fail()) {
cerr << "Error opening file" << endl;
exit(1);
}
string x;
string a[100];
int count = 0, i = 0;
while (!inFile.eof()) {
inFile >> x;
a[i] = x;
count++;
}
for (i = 0; i < 100; i++) {
cout << a[i];
}
return 0;
}
You did not increment the i variable in your while loop, therefore assigning and overwriting always the first element:
int main() {
ifstream inFile;
inFile.open("test.txt");
if(inFile.fail()) {
cerr << "Error opening file"<< endl ;
exit(1);
}
string x;
string a[100];
int count=0,i=0;
while( !inFile.eof()) {
inFile >> x;
a[i]=x;
i++; // i think you meant i++ not count++
}
for (i=0;i<100;i++){
cout<< a[i];
}
return 0;
}
Your bug is that you forgot to increment i in the loop:
while (!inFile.eof()) {
inFile >> x;
a[i] = x;
// You don't increment the `i`
// That is why you only see the last word.
count++;
}
But that is not enough there is another bug that was previously hidden.
while (!inFile.eof()) { // The last read read up to but not past the eof
// So the eof() is still false but there are no
// words left in the file.
inFile >> x; // So this read will fail
a[i++] = x; // Even though your read failed you still
// Add it to the array.
count++;
}
Let us fix this bug by testing to see if the read worked.
while (!inFile.eof()) {
if (inFile >> x) {
a[i++] = x;
count++;
}
}
Here you can see we test the state of the stream after the read. But this puts all the meaningful code inside the if branch. Why not just push this out one level.
while (inFile >> x) {
a[i++] = x;
count++;
}
Here we read a word from the file. If it works enter the loop, otherwise don't.
That should fix all the bugs for small files, but it is worth going through the rest of the file to look for bad practice and improvements.
// You don't show your headers.
// You should include them.
// Also through the code you don't use `std::` objects with the prefix. This means
// your code contains a `using namespace std;` I know all the books use this
// but it is considered exceedingly bad practice in real code. You should
// avoid it (even for small programs as the habit may cause you to use it
// large programs).
int main()
{
// Not sure why you want to take two lines here?
// There is a constructor that takes a file name.
ifstream inFile;
inFile.open("test.txt");
// The stream object when used by itself in a boolean context
// (i.e. when used in an if expression like here. Will convert itself
// to bool checking the current state. So you don't need to explicitly
// call the `fail()` method.
if (inFile.fail()) {
// It's not going to make much difference here.
// But in general you should prefer to use '\n' unless you
// absolutely must force a flush of the stream (which generally is no
// as the stream will flush itself at the most appropriate time). In
// this case it is also useless as `cerr` is unbuffered and `exit()`
// would force a flush of any other buffers.
cerr << "Error opening file" << endl;
exit(1);
}
string x;
// You only ever have 100 words in the input file?
// Arrays are not resizable and force the initialization of all members.
// So this will either be too little space and you will overflow (or need
// to add specific code to check for overflow and prevent it) or it is
// way too much space and you have needlessly constructed all those objects.
//
// For dynamic array like storage prefer std::vector
string a[100];
// Come on. Every coding standard in the world says one variable per line.
// A lot of people are fine with short variables like `i` but I prefer
// to use meaningful names for all variables. Especially if the code
// may grow in the future.
int count = 0, i = 0;
// This `while (!inFile.eof())` is WRONG and an anti-pattern.
//
// Testing for `eof` here will find the EOF after the you
// have read the last word from the file. Remember the last
// read will read up to but not past the eof. So when your read
// in the loop reads the last word `eof()` is still false.
// So now you will re-enter the loop and try and read past the
// end and the read will fail. Since the read fails `x` is
// unchanged and the last word will be added to `a` twice.
//
// The correct way to do this is to read in the while condition.
// while(inFile >> x) {
//
// This will read a word from the file and return the stream to
// be used in a bool context (which will be true if you read a
// word correctly from the stream). So what this does is try
// and read a word if it works enter the loop if it fails (i.e.
// you reach the end of the file) the loop will not be entered
// as the stream object returned is in a bad state with eof set
while (!inFile.eof()) {
inFile >> x; // read a string
a[i] = x; // Copy the string
// You can do this in a single line
// inFile >> a[i]
// You don't increment the `i`
// That is why you only see the last word.
// Whats the difference between `count` and `i`?
count++;
}
// That was a nice loop but with a vector you can read the whole
// file into the vector in a single line.
// std::vector<std::string> a(std::istream_iterator<std::string>(inFile),
// std::istream_iterator<std::string>());
// Here `i` is normal and OK (single line loop variable).
for (i = 0; i < 100; i++) {
cout << a[i]; // No space between words?
}
// But you can declare it as part of the for loop and prevent it leaking
// into the scope of the rest of your code.
// for(int i = 0; i < count; ++i) {
//
// Note 1: declare and initialize.
// Note 2: the number of words read is not 100 but count.
// Note 3: Prefer the prefix increment ++i
// It makes no difference here. But when using some objects it
// can. A lot of C++ code is changed simply by changing the type
// of the variables. So if you use the most efficient version of
// the code in all contexts then it will remain the most
// efficient even after maintenance.
//
// In C++ we usually loop over containers using begin() and end()
// to get iterators. This make sit easy to convert to standard
// algorithms if we need to. This is easier when you use a container
// rather than an array as they maintain an accurate end. But it can
// be done with arrays.
// for(auto loop = std::begin(a); loop != std::end(a); ++loop) {
//
// Also note that in modern C++ you can use `range based for`.
// So it will find the begin and end of the array for you.
// for(auto const& obj: a) {
//
// More useful for std::vector than an array but worth mentioning.
// It allows things like the trick I do with creating the vector
// directly from the file as the vector can be constructed using
// iterators and the iterator library has input iterators that
// work on streams.
// Not required in main()
// If your application can not fail then prefer to not return
// anything.
return 0;
}
I would write it like this:
#include <string>
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
std::ifstream inFile("test.txt");
if (!inFile) {
std::cerr << "Error opening file" << "\n";
exit(1);
}
std::vector<std::string> data(std::istream_iterator<std::string>(inFile),
std::istream_iterator<std::string>());
for(auto const& word: data) {
std::cout << word << "\n";
}
}
You need to increment i, as per RoQuOTriX's answer, but you probably also want to increment count so you know how many words you have. Also you should avoid over filling your array/
Try this:
int main() {
ifstream inFile;
inFile.open("test.txt");
if(inFile.fail()) {
cerr << "Error opening file"<< endl ;
exit(1);
}
string x;
string a[100];
int count=0,i=0;
while( (!inFile.eof()) && (count<100)) // avoid array overrun!
inFile >> x;
a[i]=x;
i++; // i think you meant i++ not count++ (as per RoQuOTriX)
count++; // as per your original answer
}
for (i=0;i<count;i++){ // only show values you actually read!
cout<< a[i];
}
return 0;
}
On this line:
a[i] = x;
You use i but it's never incremented. Instead do:
a[i++] = x;
You don't require to implement everything again. This is already implemented in C++ directory
#include <iostream>
#include <fstream>
int main()
{
std::ifstream f("file.txt");
if (f.is_open())
std::cout << f.rdbuf();
}
Hope this works!!
Another part that would require attention is your while loop.
while( !inFile.eof() ) {
inFile >> x; (2)
a[i]=x;
i++;
}
In this way, the last string of your input file will be written twice. This is because your check happens before you grab the last x (2).
What you need to do is,
while( inFile >> x ) {
a[i++] = x;
count ++;
}
Lastly, what happens if there are more than 100 variables in the input file? Do you ignore them or have you thought of a way to deal with that? In the code you give, you will just get a segmentation fault.
Related
I am having trouble with an assignment for my freshman Computer Science class.
I am trying to have PrintAllConcepts print each item of an array, once per line.
For some reason all I get is the last line printed from LIST.txt and a bunch of extra empty lines that usually end up nearly crashing the program. There appears to be no syntactical errors, so I'm afraid I am not reading the concepts into the array correctly. This is where I would like assistance.
Below is my code.
I also apologize if this seems like a noob question, as I am a beginner in C++.
Edit: Also, explaining why the Number parameter is so funky, my assignment seems to be requiring me to do it that way. That is also why PrintAllConcepts and ReadConcepts returns void.
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <iomanip>
void ReadConcepts(std::string Concepts[100], int &Number) {
std::ifstream fin;
fin.open("LIST.txt");
if (!fin.is_open()) {
std::cerr << "error: file open failed.\n";
}
std::string theConcepts[100];
std::string line;
int i;
for (i = 0; i <= 99; i++) {
while (std::getline(fin, line)) {
theConcepts[i] = line;
Number++;
}
}
}
void PrintAllConcepts(std::string Concepts[100], int Number) {
int i;
std::string line;
for (i = 0; i < Number - 1; i++) {
line = Concepts[i];
std::cout << line << std::endl;
}
std::cout << i;
}
int main() {
// Initiate variables
std::string Concepts[100];
int Number = 100;
// Read concepts
ReadConcepts(Concepts, Number);
// Open file for void function PrintAllConcepts
std::ifstream fin;
fin.open("LIST.txt");
if (!fin.is_open()) {
std::cerr << "error: file open failed.\n";
}
int i;
std::string line;
for (i = 0; i < 99; i++) {
while (std::getline(fin, line)) {
Concepts[i] = line;
}
}
PrintAllConcepts(Concepts, Number);
}
As you commented, the errors are in the ReadConcepts function.
To begin with you should not increment Number in the loop, as it's already the number of elements in the array. Because you increment Number you will pass the value 200 to PrintAllConcepts which will make it go out of bounds of the array.
Secondly you put all strings into the local array theConcepts instead of the array Concepts passed to the function. This means none of the strings in Concepts will be set, giving you the "empty" output. Remove the theConcepts array and use Concepts instead.
Thirdly you should have either the for loop, or the while loop, but not both. Since you have both the first iteration of the for loop will read all lines from the file, putting all of it into theConcepts[0], and leave the rest of the array with empty strings. I recommend a combination of both loops, as in:
for (int i = 0; i < Number && std::getline(fin, line); ++i)
{
Concepts[i] = line;
}
There are also some other "problem" that aren't serious and won't cause any errors. One of them is passing the Number argument by reference. Since Number should not be modified you should pass it by value.
As a perfunctory node to your question, you may want to insert a condition for reading the file in its entirety, i.e., while (fin.good()), etc.
That said, the above hints and tips are second to none. Debugging programs can teach you a lot, and are as good a learning tool as writing the code yourself. I should know; I'm new at this too. Good luck.
p.s.: Don't forget the good practice of closing your file once finished with it.
not sure what i'm doing wrong but this is my code
int main (){
int marks [100];
int i=0;
ifstream inputfile;
ofstream outputfile;
inputfile.open("data.txt");
if(!inputfile.is_open())
{
cout<< "File did not open"<< endl;
return 0;
}
cout<<"Marks in File:"<<endl;
while (marks [i] != -1)
{
inputfile>>marks[i];
cout << marks[i] <<endl;
i++;
}
return 0;
}
the output is messed up and returns stuff that was never in the data file to begin with
Here is the minimal code for reading data from a file and write it to console. Description is added as comments
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
int main()
{
ifstream configrecord("D:\\Temp\\temp.txt"); // opening the file named temp for reading.
if(configrecord.good()) // check whether the file is opened properly.
{
string line;
while (getline(configrecord, line)) // reading a line from file to std::string
{
cout << line; // printing the line, if you want it to store in an array, you can use the std::string::data() api to get the character pointer.
}
configrecord.close(); // closing the file after reading completed
}
}
If we translate your code to English, we get:
Check if the current array element is -1, if it is, break the loop.
Read the value into the current array element.
Output the value.
Move to the next array element and repeat.
Notice a big problem: We're checking if the value is -1 before we actually read it. We need to reverse the order of steps 1 and 2 so that we get:
Read the value into the current array element.
Check if the current array element is -1, if it is, break the loop.
Output the value.
Move to the next array element and repeat.
We can do this by using true as our loop condition and then using an if statement to check if the inputted value is -1 later in the loop, using break to break the loop if it is.
#include <fstream>
#include <iostream>
//using namespace std; is considered bad practice
int main()
{
std::ifstream inFile("input.txt");
int marks[100];
//check if file is open stuff...
for(int i = 0; true; i++)
{
inFile >> marks[i];
if(marks[i] == -1) break;
std::cout << marks[i] << '\n'; //endl flushes the buffer, unnecessary here.
}
}
Of Note: it is good practice that if you use an if statement, you also include an else statement. Also, your while loop is confusing, because it stops if it encounters negative one, so I am assuming you know that integer -1 is not in the file.
int n = -1;
if(!inputfile.is_open())
{
cout<< "File did not open"<< endl;
}
else
{
cout<<"Marks in File:"<< endl;
while(!inputfile.eof()){ // .eof is bad practice, but for this instance it works.
File >> marks[n];
n++; // Essentially the size of the array (Number of values), keeping track of how many values there are will assist you in the output process.
}
}
When you are done reading the file, you should close it and then use the data in the array.
inputfile.close();
Lastly, in order to output an array of data, you must use a for loop or some type of iterator to access the values stored in the array.
for(int i=0; i < n ; i++) // Output array. Where array size is less than n.
{
cout << marks[i] << " "; // " " inputs a space in between each word.
}
I have attached my full source code of my program that can open a .txt file. It doesn't execute after the cout << length. I am trying to store the .txt file information in memory by using an array.
#include <iostream>
#include <string.h>
#include <fstream>
using namespace std;
char filename[128];
char file[10][250];
int count;
int length;
string line;
int main ()
{
int count = 0;
int length = 0;
cout << "Filename: ";
cin.clear();
cin.getline(filename, sizeof(filename));
string new_inputfile(filename);
ifstream inputfiles (new_inputfile.c_str());
if(!inputfiles.is_open())
{
cout << "File could not be opened. \n ";
}
else
{
for (int i=0; getline(inputfiles,line); i++)
{
length++;
}
cout << length;
// char file[length][250]; <- How can I create the array based on the length variable?
// CODE DOES NOT EXECUTE AFTER THIS.
while(!inputfiles.eof() && (count<10))
{
inputfiles.getline(file[count],250);
count++;
}
for(int i=0; i < count; i++)
{
cout << file[i] << endl;
}
}
inputfiles.close();
return 0;
}
Also, since file[] is char, say for example file[1] contained the char Name=Mike, how do I strip off everything before the =. I want just Mike. I know with string, I can use substr() method, but I don't know for char.
This is horribly wasteful way to count number of lines in a file.
for (int i=0; getline(inputfiles,line); i++) // i is also completely useless here
{
length++;
}
You're reading the whole file only to throw everything away and start again! And after this loop is done, inputfiles.eof() will be true and you'll never enter neither the next while loop nor the last for loop (because i == count). Execution skips directly to inputfiles.close() and then you return from main.
I suggest you work on the line string as you go:
for ( ; getline(inputfiles, line); )
{
// do stuff with line and ditch the global char arrays
}
If you want store the lines for later, well, just save them :) The easiest thing to do is to use a vector:
std::vector<std::string> all_them_lines;
while (getline(file, line) all_them_lines.emplace_back(line);
There, the entire file is now saved in all_them_lines, line by line. You can access them just like you would in an array, like all_them_lines[0]. You also don't need to know the number of lines beforehand - vectors expand automatically when you add stuff to them.
Now to parse a line and extract formatted input from it, check out what stringstream class has to offer.
You asked:
// char file[length][250]; <- How can I create the array based on the length variable?
Declare file as:
char (*file)[250] = NULL;
and then,
file = new char[length][250];
Make sure you call delete [] file before the end of the function.
You said:
// CODE DOES NOT EXECUTE AFTER THIS.
You can rewind the stream and start reading from it again.
inputfiles.seekg(0);
count = 0;
while(!inputfiles.eof())
{
inputfiles.getline(file[count],250);
count++;
}
I'm kind of a newbie in C++ programming.. My command prompt output is a big bulk (repeated) of the characters I have in my txt file. I create a 2d array map[15][15] and try to read the txt file. the reading part is ok but now I dunno how to put them in a 2D character array..
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
char map[15][15];
int alp = 0;
int i = 0;
int main()
{
ifstream in;
//string s;
in.open("city.txt");
if(!in.is_open())
{
cout << "File open error! " << endl;
}
else
{
while(!in.eof())
{
//getline(in, s);
in >> map[i];
i++;
alp++;
//if(in.eof()) break;
cout << map[i] << endl;
}
}
for(i = 0; i <= alp; i++)
{
cout << map[i];
}
in.close();
return 0;
}
eof() will only return true only after the first failed read operation. That operation will not be caught by your code. You could have a test for eof directly after the read and then break if eof(), but that's not elegant:
IO operations on streams return a ref to the given stream. Streams have a meaningful conversion to bool. True indicates that the read was successful, e.g. eof wasn't reached yet, and the read target contains a new correct input value. The idiomatic way of using this feature is "while(in >> map[i])".
As to the algorithm: You say that there are no spaces and I assume it's all ascii chars, so it boils down to double looping over the array's lines and columns with two for loops. Inside those loops would be a line reading each character explicitly with get() like
if(!cin.get(map[i][j])) {/* unexpected eof/io error, abort or whatever */ }
As the data is textual, and separated into lines, I suggest you read directly into the sub-array using e.g. std:istream::getline:
for (size_t i = 0; in.getline(map[i], 15); ++i)
;
I have a file that has a number in which is the number of names that follow. For example:
4
bob
jim
bar
ted
im trying to write a program to read these names.
void process_file(ifstream& in, ofstream& out)
{
string i,o;
int tmp1,sp;
char tmp2;
prompt_user(i,o);
in.open (i.c_str());
if (in.fail())
{
cout << "Error opening " << i << endl;
exit(1);
}
out.open(o.c_str());
in >> tmp1;
sp=tmp1;
do
{
in.get(tmp2);
} while (tmp2 != '\n');
in.close();
out.close();
cout<< sp;
}
So far I am able to read the first line and assign int to sp
I need sp to be a counter for how many names. How do I get this to read the names.
The only problem I have left is how to get the names while ignoring the first number.
Until then i cannot implement my loop.
while (in >> tmp1)
sp=tmp1;
This successfuly reads the first int from the and then tries to continue. Since the second line is not an int, extraction fails, so it stops looping. So far so good.
However, the stream is now in fail state, and all subsequent extractions will fail unless you clear the error flags.
Say in.clear() right after the first while loop.
I don't really see why you wrote a loop to extract a single integer, though. You could just write
if (!(in >> sp)) { /* error, no int */ }
To read the names, read in strings. A loop is fine this time:
std::vector<std::string> names;
std::string temp;
while (in >> temp) names.push_back(temp);
You'd might want to add a counter somewhere to make sure that the number of names matches the number you've read from the file.
int lines;
string line;
inputfile.open("names.txt");
lines << inputfile;
for(i=0; i< lines; ++i){
if (std::getline(inputfile, line) != 0){
cout << line << std::endl;
}
}
First of all, assuming that the first loop:
while (in >> tmp1)
sp=tmp1;
Is meant to read the number in the beginning, this code should do:
in >> tmp1;
According to manual operator>>:
The istream object (*this).
The extracted value or sequence is not returned, but directly stored
in the variable passed as argument.
So don't use it in condition, rather use:
in >> tmp1;
if( tmp1 < 1){
exit(5);
}
Second, NEVER rely on assumption that the file is correctly formatted:
do {
in.get(tmp2);
cout << tmp2 << endl;
} while ( (tmp2 != '\n') && !in.eof());
Although whole algorithm seems a bit clumsy to me, this should prevent infinite loop.
Here's a simple example of how to read a specified number of words from a text file in the way you want.
#include <string>
#include <iostream>
#include <fstream>
void process_file() {
// Get file name.
std::string fileName;
std::cin >> fileName;
// Open file for read access.
std::ifstream input(fileName);
// Check if file exists.
if (!input) {
return EXIT_FAILURE;
}
// Get number of names.
int count = 0;
input >> count;
// Get names and print to cout.
std::string token;
for (int i = 0; i < count; ++i) {
input >> token;
std::cout << token;
}
}