Reading from a file into a List using C++ - c++

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.

Related

Writing and reading from a file sequentially using the same file object

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.

Is extracting formatted input from std::cin with a single line of code possible?

Say I have a function compute_number(float k); and in my program, I need to call this function once with some user input as the argument. The intuitive way to achieve formatted input, would be:
int main()
{
...
float input_numbr;
std::cin >> input_numbr;
compute_number(input_numbr);
...
}
The problem with this, though, is that I've declared and used an extra variable float input_numbr which I'll never use again. I think that's a waste.
So my question is if there's any way to reduce these three lines into one. There must be some way to circumvent the need of creating an additional variable to get one-time formatted keyboard input from an input stream. I'm thinking of something like:
compute_number(cin.get());
The problem with that, however, is that cin.get() does not format the input; it simply returns the ASCII value of whichever character happens to be next in the stream.
So is there a way to call compute_number(cin.next_formatted_input()) like so? Or must one create an additional variable for temporarily holding the formatted cin value.
The problem with this, though, is that I've declared and used an extra variable float input_numbr which I'll never use again. I think that's a waste.
Well, I disagree (advocating for code readability), but here you go:
template<typename T>
T getinput(std::istream& is) {
T result;
is >> result;
return result;
}
should do what you want. You can just write
compute_number(getinput<float>(std::cin));
then. Though a variable is still involved (and needed).

Output info from 2 struct arrays into one file

I apologize if this doesn't make sense. I Am not sure what to google.
Lets say I have two arrays
string a_1[16];
string a_2[20];
I need to output these to a file with a function, first, a_1[0] to a_1[n].
Then reads in the a_2's.
It's also possible to run the function again to add in more a_1's and a_2's to the output file.
so the format will be:
//output_file.txt
a_1[0].....a_1[n]
a_2[0].....a_2[M]
a_1[n+1]...a_1[16]
a_2[M+1]...a_2[20]
my question is. Is there a way to read output_file.txt back so that it will read in all of the a_1's to be in order, a_1[0] to a_1[16].
and then input a_2[0] to a_2[20].
maybe just put "something" between each group so that when "something" is read, it knows to stop reading a_1's and switch to reading in for a_2....
What the OP calls "Something" is typically called a Sentinel or Canary value. To be used as a sentinel, you have to find a pattern that cannot exist in the data stream. This is hard because pretty much anything can be in a string. If you use, say, "XxXxXx" as your sentinel, then you have to be very careful that it is never written to the file.
The concept of Escape Characters (Look it up) can be used here, but a better approach could be to store a count of stored strings at the beginning of the file. Consider an output file that looks like
4
string a1_1
string a1_2
string a1_3
string a1_4
2
string a2_1
string a2_2
Read the cont, four, and then read count strings, then read for the next count and then read count more strings
OK, so you're thinking his sucks. I can't just insert a new string into a1 without also changing the number at the front of the file.
Well, good luck with inserting data into the middle of a file without totally smurfing up the file. It can be done, but only after moving everything after the insertion over by the size of the insertion, and that's not as trivial as it sounds. At the point in a programming career where this is the sort of task to which you are assigned, and you have to ask for help, you are pretty much doomed to reading the file into memory, inserting the new values, and writing the file back out again, so just go with it.
So what does this look like in code? First we ditch the arrays in favour of std::vector. Vectors are smart. They grow to fit. They know how much stuff is in them. They look after themselves so there is no unnecessary new and delete nonsense. You gotta be stupid not to use them.
Reading:
std::ifstream infile(file name);
std::vector<std::string> input;
int count;
if (infile >> count)
{
infile.ignore(); // discard end of line
std::string line;
while (input.size() < count && getline(infile, line))
{
input.push_back(line);
}
if (input.size() != count)
{
//handle bad file
}
}
else
{
// handle bad file
}
and writing
std::ofstream outfile(file name);
if(outfile << output.size())
{
for (std::string & out: output)
{
if (!outfile << out << '\n')
{
// handle write error
}
}
}
else
{
// handle write error
}
But this looks like homework, so OP's probably not allowed to use one. In that case, the logic is the same, but you have to
std::unique_ptr<std::string[]> inarray(new std::string[count]);
or
std::string * inarray = new std::string[count];
to allocate storage for the string you are reading in. The second one looks like less work than the first. Looks are deceiving. The first one looks after your memory for you. The second requires at least one delete[] in your code at the right pace to put the memory away. Miss it and you have a memory leak.
You also need to have a variable keeping track of the size of the array, because pointers don't know how big whatever they are pointing at is. This makes the write for loop less convenient.

Function definition to count number of words

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.

Keep a text file from wiping in a function but keep ability to write to it? C++

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