I am learning data file handling basics in c++ (and am working in the compiler turbo C++).
So I wanted to create a text file , write some data onto it and then read it.
So I wrote this: -
int main()
{
fstream fin;
fin.open("textfile.txt",ios::in|ios::out);
for(int i=0;i<3;i++)
{
char x;
cin>>x;
fin<<x;
}
fin.seekg(0,ios::beg); //I added this and also tried seekp() when I didn't get the desired output
//but to no use
while(!fin.eof())
{
char v;
fin>>v;
cout<<v;
}
fin.close();
getch();
return 0;
}
But instead of outputting only the 3 characters which I input, it outputs 4 characters.
I tried removing the loops and taking input and giving outputs one by one like this (among other things):
...
char x,y,z;
cin>>x>>y>>z;
fin<<x<<y<<z;
fin.seekg(0,ios::beg);
char q,w,e;
fin>>q>>w>>e;
cout<<q<<w<<e;
...
But it still didn't work.
I think it has something to do with file pointers and their location but don''t know what. I tried finding a similar question on the net but to no avail.
So I want to know what is wrong with what I did and how to I improve this to actually write and read in a file sequentially using the same file object (if it is even possible). And is seekg() even necessary here?
Thanks.
The problem you face is a general problem. Your input code is right and there is no error in that. The problem is your ouput code and to be more specific the line while(!fin.eof()). eof(end-of-file) works on a end of file mark whose numeric value is generally -1. But this function goes false only when the end character is encountered and traversed. To remove this error just replace this statement with a read statement that is move this line fin>>v from loop statements to the conditional statements. In this false will be when it encounters a end character.
Related
I'm currently working on this program for a class in my university. I've tried multiple approach with no success. I'm pretty sure it's just a conversion problem, but I want to understand the differences.
What the program supposed to do : We're to create a program that ask the user for two filenames. One will be an input and another will be an output. The program is supposed to read the input and write the line to the output while until the end of the input file is not reached.
My Code :
#include <iostream>
#include <fstream> //included for read/writing files
#include <string> //Included this for getline to read the file
using namespace std;
int main() {
ifstream infile; // Stream to read from input file
ofstream outfile; // Stream to write to output file
char inputfilename[80], outputfilename[80]; //declaring two character arrays to save the file names.
string text;
cout << "What is the name of your input file (text.txt)" ; // Prompting user for input file name
cin >> (inputfilename); // Getting input file
infile.open(inputfilename, ios::in); // Opening the input file.
cout << "What is the name of your output file" ; // Prompting user for output file name
cin >> (outputfilename);
outfile.open(outputfilename, ios::out);
if(!infile) { // If cannot open file
cout << "There was an error opening your file!" ;
return 1;
}
if (!outfile) {
cout << "There was an error opening your file!" ;
return 1;
}
while (infile.eof()==0) {
fgets(text, 80, infile);
fprintf(outfile,"%d. %s\n", text);
}
infile.close(); // Closing input file
outfile.close(); // Closing output file
return 0;
}
What I've tried : I didn't know if it was being affected by how I opened the file. I previously tried.
ifstream infile;
ofstream outfile;
char text, inputfilename[80], outputfilename[80]; <----- 1
cout << "What is the name of your input file (text.txt)" ;
gets(inputfilename); <----- 2
infile.open(inputfilename);
cout << "What is the name of your output file" ;
gets(outputfilename); <----- 2
outfile.open(outputfilename);
1) I switched char I previous tried
char text
char text[80]
char *text[80]
2) Would switching how getting the file name change anything in the while loop(I previous tried getline and gets)? Additionally the "f" in front of fgets/fprints/etc are always associated with a file stream?
Note: My teacher gave us the hint.
"Suppose you read a line from the input file into a string variable called str using the following statement: fgets(str, 80, infile);You can add a line number and save the line with the line number to the output file using the same statement using: fprintf(outfile,"%d. %s\n",Next_line_number++, str);"
from this I tried :
while (infile.eof()==0) {
fgets(text, 80, infile);
fprintf(outfile,"%d. %s\n", text);
}
as well as
while (infile.eof()==0) {
fgets(text, 80, infile);
fputs(text, outFile);
}
and
while (infile.eof()==0) {
getline(infile, text);
fprintf(outfile,"%d. %s\n", text);
}
I also tried making a long and using that to increment the line number. I'm fairly new to programming; if any of the methods I'm using our dated please let me know (on some sites they were saying fgets is dated and not supported on cx11 or some version of C++)! I want to understand the concepts vs just get the programming running. Should note Lines 34-35 are where my code is always erroring out and it's
cannot convert 'std::__cxx11::string {aka std::__cxx11::basic_string}' to 'char*' for argument '1' to 'char* fgets(char*, int, FILE*)'
I figured I was getting this because it has a pointer to the file and I'm asking the user vs having the file declared in the program. This is causing a conversion that causing my error.
fgets(text, 80, infile);
fgets() is a C library function, that expects a char * as its first parameter. It knows absolutely nothing about any C++ class, and not just std::string that you are passing as the first parameter. Neither does fgets() has any clue about the C++ std::ifstream class you're attempting to pass to it as its third parameter. And that's exactly what your compiler's error message states.
You are randomly mixing up C and C++ code, which results in repeated confusion.
char inputfilename[80], outputfilename[80];
You should also use std::strings, instead of arbitrary-sized C style arrays, here.
while (infile.eof()==0) {
This is always a bug, and read this linked article for more information.
fprintf(outfile,"%d. %s\n", text);
Again: fprintf is also a C library function, that knows absolutely nothing about C++ classes like std::string and std::ofstream. In either case, this is a bug because this string has placeholders for two parameters, an integer, %d, and C style string, %s; and you're giving just one parameter here, text. In the event that you were writing C instead of C++ code, this would not've worked either, but that's mostly academic. This is a C++ program, and this C library function has no business doing anything here, in the first place.
When you are reading from a std::ifstream:
You can use std::getline to read an entire line of text into a std::string
Alternatively you can use the >> formatted extraction operator
Or you can use various methods of the std::ifstream object to read from the file and into a suitable buffer
These alternatives are not equivalent (otherwise what would be the point?) and they do different things, and the right one to use depends on what the requirements are.
Similarly, to write to a std::ofstream you can use:
The << formatted output operator.
Various methods of the std::ofstream object itself.
And, in some advanced situations you can take advantage of the iterator library, and implement reading and writing using input and output iterators, too.
The correct approach depends on the individual situation. For more information on how to read and write from files in C++ using these approaches, see any good C++ book. Whichever C++ book actually advised you to use fgets() to read from a std::ifstream and into a std::string: throw it away, and get a better book, from the list linked above. If this is just what you found in some program somewhere on the Internet -- you can't learn C++ this way, by piecing together different parts of different programs, and hope that the results work. To fix all of your compilation errors: remove all that C code that knows absolutely nothing about C++, and replace it with proper C++ code, using any of the options I outlined above, using the examples from the C++ books linked above, as a reference.
On a C++ project, I have been trying to use an array to store data from a textfile that I would later use. I have been having problems initializing the array without a size. Here is a basic sample of what I have been doing:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
int i = 0;
ifstream usern;
string data;
string otherdata;
string *users = nullptr;
usern.open("users.txt");
while(usern >> otherdata)
i++;
users = new (nothrow) string[i];
for (int n = 0; usern >> data; n++)
{
users[n] = data;
}
usern.close();
return 0;
}
This is a pretty rough example that I threw together. Basically I try to read the items from a text file called users.txt and store them in an array. I used pointers in the example that I included (which probably wasn't the best idea considering I don't know too much about poniters). When I run this program, regardless of the data in the file, I do not get any result when I try to test the values by including cout << *(users + 1). It just leaves a blank line in the window. I am guessing my error is in my use of pointers or in how I am assigning values in the pointers themselves. I was wondering if anybody could point me in the right direction on how to get the correct values into an array. Thanks!
Try reopening usern after
while(usern >> otherdata)
i++;
perhaps, try putting in
usern.close();
ifstream usern2;
usern2.open("users.txt");
right after that.
There may be other issues, but this seems like the most likely one to me. Let me know if you find success with this. To me it appears like usern is already reaching eof, and then you try to read from it a second time.
One thing that helps me a lot in finding such issues is to just put a cout << "looping"; or something inside the for loop so you know that you're at least getting in that for loop.
You can also do the same thing with usern.seekg(0, ios::beg);
What I think has happened in your code is that you have moved the pointer in the file that shows where the file is being read from. This happened when you iterated the number of strings to be read in using the code below.
while(usern >> otherdata)
i++;
This however brought the file pointer to the end of the file this means that in order to read the file you need to move the file pointer to the beginning of the file before you re-read it into your array of strings that you allocated of size i. This can be acheived by adding usern.seekg(0, ios::beg); after your while loop, as shown below. (For a good tutorial on file pointers see here.)
while(usern >> otherdata)
i++;
// Returns file pointer to beginning of file.
usern.seekg(0, ios::beg);
// The rest of your code.
Warning: I am unsure about how safe dynamically allocating STL containers are, I have previously run into issues with code similar to yours and would recommend staying away from this in functional code.
Write a function definition that counts the number of words in a line from your text source.
I tried two different codes and got two different results
countwords()
{
ifstream file("notes.txt");
int count=0;
char B[80];
file>>B;
While (!file.eof())
{
cout<<B<<endl;
file>>B;
count++;
}
}
This gives the desired answer.
The other way around :
countwords()
{
ifstream file("notes.txt");
char B[80];
int count=0;
While (!file.eof())
{
file>>B;
cout<<B<<endl;
count++;
}
}
But this gives an answer which is 1 more than the actual number of words.
Can someone please explain the working of the eof() function and the difference in these two loops?
The second version of your answer will always loop one extra time.
Think about this: what happens if file >> B fails? You'll still increment count.
Also, do not loop on eof() because you'll typically loop one too many times. (Why is iostream::eof inside a loop condition considered wrong?)
Instead, do the following:
while(file >> B)
{
std::cout << B << std::endl;
++count;
}
Because your filestream has an implicit conversion to bool that checks the state of it, and returns false if it's not good.
The problem is not EOF however to see its working Read this.
Talking about your code, note the file>>B; in first code. Since file>>B; fails in last execution of second code, you get one less the correct answer.
The reason for outputting 1 more than the actual number of words: In the 2nd version you output B before reading it for the first time. This is a usage of an uninitialized variable and can result in outputting what will look like garbage, or an empty line. Unreliable code.
Also I would suggest using an std::string instead of char[80] as the type for your variable B.
I'm a little new to using file input/output so bear with me.
I've got a function called RunList(filename), that takes the name of the file as input and returns nothing. The file will have the format of having one line that is useless and I plan on using ignore() on and then the next line which is important has the format
"i 1 2 3 4 5 ...."
where the numbers go on for a very long way, about 250000 or so.
So what I want to do is to open this file, ignore the first line, and then for each number in the file I want to use the function void insert(x, p) which is a function I have defined to insert x after the current iterator position p. The end result is that I want to have my list contain all of the numbers in the file after the "i" and be in the same order. I have also defined the functions ListItr find(x) and ListItr first() which will return the iterator to the position that views x and to the first potion respectively.
Could anyone provide me with a means of doing this? I was thinking of using a for() loop and taking in each word at a time from the file and using my function to insert each element, but I'm a little lost as to how to do this, as I said I'm very new to using file input/output.
So, my RunList function currently looks something like this, although obviously its not finished nor does it really work, hence me needing some help on it.
void Runlist(filename){
ifstream in;
in.open(filename);
in.ignore(1000, '\n'); //this is me trying to ignore the first line
for (int i, i < 250000, i++){
int number;
in >> number
void insert(number, i)
}
}
But the plan was, I select the file, ignore the first line, then set up a for loop where i can use my void insert(number, i) to insert each number, but then i don't really understand how to read in each word at a time, or to preserve the order because if I just kept using the function on each number over and over then the list would have the numbers in the reverse order I believe.
There are several issues in your code:
You do not specify void for the return type of the function.
Instead of ignore, you could just drop the first line when reading by using getline once.
Your for loop usage is also pretty invalid: commas instead of semi-colons
No initialization of i, and so on.
insert is not shown, but you could probably use append anyway since that is what you seem to be doing.
i is not an "iterator" either, so probably you meant index.
You are having a function declaration in the middle of the function rather than calling it.
This pseudo code should get you going about understanding the input file stream class and its usage for this in C++:
void Runlist(filename)
{
ifstream in(filename, ifstream::in);
in.getline(0, 1024);
int number;
while (in >> number)
append(number);
in.close();
}
Disclaimer: this pseudo code is missing proper error checking, and so on.
I have a function that swaps two chars, in a file, at a time, which works, however if i try to use the function more than once the previous swap i made will be wiped from the text file and the original text in now back in, therefore the second change will seem as my first. how can i resolve this?
void swapping_letters()
{
ifstream inFile("decrypted.txt");
ofstream outFile("swap.txt");
char a;
char b;
vector<char> fileChars;
if (inFile.is_open())
{
cout<<"What is the letter you want to replace?"<<endl;
cin>>a;
cout<<"What is the letter you want to replace it with?"<<endl;
cin>>b;
while (inFile.good())
{
char c;
inFile.get(c);
fileChars.push_back(c);
}
replace(fileChars.begin(),fileChars.end(),a,b);
}
else
{
cout<<"Please run the decrypt."<<endl;
}
for(int i = 0; i < fileChars.size(); i++)
{
outFile<<fileChars[i];
}
}
What you probably want to do is to parameterize your function :
void swapping_letters(string inFileName, string outFileName)
{
ifstream inFile(inFileName);
ofstream outFile(outFileName);
...
Because you don't have parameters, calling it twice is equivalent to:
swapping_letters("decrypted.txt", "swap.txt");
swapping_letters("decrypted.txt", "swap.txt");
But "decrypted.txt" wasn't modified after the first call, because you don't change the input file. So if you wanted to use the output of the first operation as the input to the second you'd have to write:
swapping_letters("decrypted.txt", "intermediate.txt");
swapping_letters("intermediate.txt", "swap.txt");
There are other ways of approaching this problem. By reading the file one character at a time, you are making quite a number of function calls...a million-byte file will involve 1 million calls to get() and 1 million calls to push_back(). Most of the time the internal buffering means this won't be too slow, but there are better ways:
Read whole ASCII file into C++ std::string
Note that if this is the actual problem you're solving, you don't actually need to read the whole file into memory. You can read the file in blocks (or character-by-character as you are doing) and do your output without holding the entire file.
An advanced idea that you may be interested in at some point are memory-mapped files. This lets you treat a disk file like it's a big array and easily modify it in memory...while letting the operating system worry about details of how much of the file to page in or page out at a time. They're a good fit for some problems, and there's a C++ platform-independent API for memory mapped files in the boost library:
http://en.wikipedia.org/wiki/Memory-mapped_file