Some methods of reading from txt files - c++

I am trying to learn some techniques of reading from files in C++ and I came up with this example.
Assume the following is the content of the txt file that I want to read from
A
1 2 3
4 5 6
7 8 9
B
1 2 3
4 5 6
7 8 9
So, what I want to do here is that if we read A, then we start to read the matrix A from below and store them into a[i][j]. And the same for B. In other circumstances we take them as exception, which we don't care here now.
The problem for me now is mixed reading. I know how to read integer and how to read strings from the file separately, like the stupid way while(fin>>it). but can anyone tell me a fast way of this kind of mixed reading that I don't have to declare several reading variables (type) such as string and int?
For example, I only know how to read integer in a whole line and don't know the newline handler, which means I don't know how to recognize if we reached the end of the line or something like this:
ifstream fin;
fin.open(infilename);
int it;
int arr[3][3];
int i=0, j=0;
while(fin>>it){
arr[i][j]=it;
`\\I am confused at this place and don't know how to write the condition`
}
fin.close();
Moreover, since there are both char and int type, do I have to declare char? and how does fin>>char really work? reading char by char in a line or something else?
I'll really appreciate if someone can guide me on this! Thanks!

You shouldn't have to worry about newlines as >> skips whitespace and newlines. However, putting fin>>it in the while condition complicates things if you want different data types. You could instead read in to a character to represent each matrix, then within the loop read from fin to the matrix:
char c;
int mat[3][3];
while (fin>>c){
//save c somewhere
fin>>mat[0][0]>>mat[0][1]>>mat[0][2];
fin>>mat[1][0]>>....;
fin>>mat[2][0]>>....;
//store mat
}

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.

How to read a file line by line without using the string class?

So in my c++ class, we're not allowed to use the string class right now. To substitute strings, we're using character arrays.
The assignment requires that i read from a file that contains a sentence on each line. The first line of the file is an integer that tells how many lines are in the file.
My first problem is that reading in the integer into a variable and using that variable in an array causes an error saying that the variable must be constant.
How can I get past that? I need a 2D array to count how many characters each sentence has. I want to initialize my array as char FileSentences[numberOfLines][81]. It's been decided that the sentence character cap will be 80 characters long, so the width of each row has to be 81 to account for the \0.
My second problem comes from how I'm reading in the integer. Since the first line in the file is an integer, I'm reading it like:
int numberOfLines;
ifstream fin;
fin.open("TestTextFile.txt");
fin >> numberOfLines;
This works and it sets the variable numberOfLines to the correct value. However, when I call fin.getline, the next thing it will read in is a blank. If I call fin.getline again, it is the first sentence of the file. Is there another way to read in the integer to prevent that or should I just set a blank sentence in memory to hold the first fin.getline value and then proceed to reading sentences into my array?
For the first problem, use a std::vector.
// Define a typedef for a line.
typedef char Line[81];
// Read the number of lines.
fin >> numberOfLines;
// Define a vector for the lines.
std::vector<Line> lines(numberOfLines);
For the second problem, use ifstream::ignore() to ignore the rest of the line.
fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Make sure to add
#include <limits>
to use std::numeric_limits.
I need a 2D array to count how many characters each sentence has. I
want to initialize my array as char FileSentences[numberOfLines][81].
Easy solution is to allocate what you need:
typedef char LINE[81];
LINE* FileSentences = new LINE[numberOfLines];
After you are done iterating on FileSentences, free the memory as follows:
delete [] FileSentences;

C++ Can programs run out of stack memory even when plenty of memory is available?

I'm writing a parser for a large file and one of my functions responsible for reading from the input file has a char buffer called peek. Basically, as main repeatedly calls this function, peek is eventually getting over-written with some odd values. Here's the function that's being called by main. bufferAsInt:
void bufferAsInt(ifstream &inf, int &i)
{
char peek[3];
inf.read(peek, 3);
i = atoi(peek);
//I'm not using the >> operator to read an int because the int is just
//3 chars long in the input file and two consecutive integer values can
//be written like this: 123456 for 123 and 456.
}
I found that as I wrote these values to an output file, when reading an int value that was only two digits long, the third digit (or some other number) would be left over in the char buffer peek and the value would be written incorrectly to the output file (this only happened after reading a very very large amount of data from the input file.) So after tens of thousands of iterations, when reading a number like 15, the value that would get written to my output file might have been something like 156.
To solve the problem I changed my implementation of bufferAsInt to this:
void bufferAsInt(ifstream &inf, int &i)
{
char *peek = new char[3];
inf.read(peek, 3);
i = atoi(peek);
delete [] peek;
}
(Of course I was guessing at what the issue was). What I'd like to know is if the fact that my problem was solved is some sort of weird consequence of declaring this char buffer on the heap or if the issue actually was that my program was running out of stack memory.
I have 6GB of RAM in my computer and at the time of running, no other programs would have been using enough memory to cause this issue to the best of my knowledge.
You're off by one.
atoi expects a null-terminated string. So a three-digit number needs a char[4] to be properly stored. Also, read doesn't put a null on the end.
Try this:
void bufferAsInt(ifstream &inf, int &i)
{
char peek[4];
inf.read(peek, 3);
peek[3] = 0;
i = atoi(peek);
}
atoi() expects a C 'NUL terminated string' as input, that is, ASCII characters followed by an ASCII zero byte. That's the only way the function knows where to stop converting.
In your first code listing, you read three bytes into a three byte buffer, but you have no control over the byte that follows in memory. I believe that's undefined behavior in C++, so literally anything can happen. Typically, though, if the following byte happens to be a zero or a non-digit, the string will convert properly; if it happens to be a digit, you get a different number when you were expecting.
The proper fix is to use your first example, but:
char peek[4]; // 4 char buffer instead of 3
inf.read(peek, 3);
peek[3] = '\0'; // ensure the 4th char is zero
i = atoi(peek);
Most likely the only thing that changed was that the new, with your compiler and options, zeroes the array.
To guarantee that you could write
char *peek = new char[3]();
But the dynamic allocation serves no purpose, so instead do it like this:
char peek[3] = {};
Note: if the file contains 3 digits, then you should instead use four digits array, in order to have room for terminating zero.

Implementing External Merge Sort

I am aware of External merge sort and how it works.
But currently i'm stuck while implementing it. I've written code to sort and merge the arrays but I'm facing problem while reading and writing the data from/into the file, i want to implement the following methods in C++:
1. int * read(int s, int e) : This method should read from file all the number
starting from 's' till 'e' and return the array
2. write(int a[], int s, int e) : This method should write to file the input
array by replacing the numbers from s to e.
For eg.
Given file has the following numbers:
1
2
3
4
5
6
read(0, 2) should return [1,2,3]
write([4,5,6], 0, 2) should update the file to :
4
5
6
4
5
6
How can I implement both these methods?
The first thing you should do is stop working with raw pointers.
std::vector<int> will be just as efficient, and far less bug prone.
Second, the file format matters. I will assume a binary file with packed 32 bit signed integers.
The signature for read and write is now:
std::vector<int> read( std::ifstream const& f, int offset );
void write( std::ofstream& f, int offset, std::vector<int> const& data );
ifstream and ofstream have seek methods -- in particular, ifstream has seekg and ofstream has seekp.
ifstream.read( char* , length ) reads length bytes from the file at the current get position (set by seekg, and advanced by read). If you aren't concerned with memory layout of your file, you can get the .data() from the std::vector<int>, reinterpret it to a char*, and proceed to read( reinterpret_cast<char*>(vec.data()), sizeof(int)*vec.size() ) to read in the buffer all at once.
ofstream has a similar write method which works much the same way.
While writing data rawly to disk and back is dangerous, in most (every?) implementation you'll be safe with data written and read in the same execution session (and probably even between sessions). Take more care if the data is meant to persist between sessions, or if it is output/input from your code.
There are no C++ standard functions to jump to lines in files. So you have to read the file line by line (with getline, for example. http://www.cplusplus.com/reference/string/string/getline/).
As far as I remember, external merge sort (the old one, designed for a computer with a few tape drives), when used with separate files, doesn't need an interface like yours - you can work sequentially.

Reading constant number of characters in C++

How would you read a string if it was no longer than 20 characters and could contain spaces in C++? For example I have this kind of file:
3
Namama 4 5 12
Cool 4 2 34
Not So Cool 4 2 45
I want to write it in the most basic way possible. And I would prefer using only C++ (no C thingies) in this case. This means I want to store it in std::string.
I could use istream::get or istream::getline but then I have to avoid the new line characters. This is problematic (and the code I'm writing is going to be shown to beginners).
What are your solutions for this problem?
Edit:
As asked I'm going to tell you what I have tried but I don't think it's going to be any good. I am not a C++ beginner and usually I would have used something like istream::get and char array but removing new line characters might seem too techy for some people.
So... Either reading char array or std::string using istream::operator>> fails because it stops reading when they see space character (and I may have to read several words). This means the following code fails:
char name[21];
std::cin >> name;
or...
std::string name;
std::cin >> name;
Another thing is that new line characters differ from system to system and actually Windows use two of them by default and I have tried using istream::ignore with 2 as an argument on Windows and that was the only way to ignore the new line and I came to conclusion that it's because Windows use two characters for a new line mark. That means it wouldn't work on Linux and it would have to be more complex... Again - bad for beginners.
If you want to read exactly 20 characters,
for(int i=0; i<3; ++i) {
std::string result;
int one, two, three;
result.resize(20);
if (!std::cin.read(&result[0], 20)) throw std::runtime_error("reading buffer failed!");
if (!std::cin >> one >> two >> three) throw std::runtime_error("reading numbers failed!");
if (!std::cin.ignore(1000, '\n')) throw std::runtime_error("ignore failed!");
}
If you don't want exactly 20 characters, how do you know when you've reached the end of the string?
One way to accomplish this would be to use istream::read into a temporary buffer of sufficient size, and then use that buffer to initialize a std::string.
char name[21];
std::cin.read(name, 20);
std::string nameString(name); // If you want it in a std::string
This reads exactly 20 characters, newlines and everything. If it's for an exercise, then this is at the very least very simple. If you sometimes want less than 20 characters, it is possible to determine how many extra were read and back the get pointer by std::istream::unget or equivalent.