c++ process file blank line at the end of file - c++

when I use c++ to process a file ,I found there is always a blank line in the end of file .Someone says that vim will append an '\n' in the end of file,but when I use gedit,it also has the same question.Can anyone tell me the reason?
1 #include<iostream>
2 #include<fstream>
3
4 using namespace std;
5 const int K = 10;
6 int main(){
7 string arr[K];
8 ifstream infile("test1");
9 int L = 0;
10 while(!infile.eof()){
11 getline(infile, arr[(L++)%K]);
12 }
13 //line
14 int start,count;
15 if (L < K){
16 start = 0;
17 count = L;
18 }
19 else{
20 start = L % K;
21 count = K;
22 }
23 cout << count << endl;
24 for (int i = 0; i < count; ++i)
25 cout << arr[(start + i) % K] << endl;
26 infile.close();
27 return 1;
28 }
while test1 file just:
abcd
but the program out is :
2
abcd
(upside is a blank line)

while(!infile.eof())
infile.eof() only is true after you tried to read beyond the end of the file. So the loop tries to read one more line than there is and gets an empty line on that attempt.

It's a matter of order, you're reading, assigning and after checking...
you should change your code a little bit, in order to read, check and assign:
std::string str;
while (getline(infile, str)) {
arr[(L++)%K] = str;
}
http://www.parashift.com/c++-faq-lite/istream-and-eof.html
How to determine whether it is EOF when using getline() in c++

Related

Creating a sequence of numbers from a string of digits C++

I need to make a program where a user inputs a string of numbers.
It then outputs the numbers grouped so that each grouping, separated by a space, is larger than the last when you put the numbers together.
If the remaining digits together equal a sum smaller than the previous grouping they are omitted.
Ex.:
314159265 would output 3 14 15 92
Here: 3 < 14 <15 < 92 but 65 was omitted because it is less than 92
or
9876543210 would output 9 87 654 3210
Here: 9 < 87 < 654 < 3210
It has to do this 5 times with strings 1-20 characters long.
My code works for shorter strings, ie the ones above, but when they are longer than around 12 characters the end output messes up.
Ex.:
98765432101234567898 outputs 9 87 654 3211 12333 instead of 9 81 654 3210 12345 67898
Here: 9 < 87 < 654 < 3211 < 12333 it should output 9 < 87 < 654 < 3210 < 12345 < 67898
I have no idea why it doesn't work with larger strings and any help would be greatly appreciated.
#include<iostream>
#include<iomanip>
#include<math.h>
#include<string>
#include<stdlib.h>
using namespace std;
void input (string &a,string num[20]){
string numfinal,temp;
cout<<"Enter the string of numbers: ";
getline(cin, a);
int length=a.length();
for(int i=0;i<length;i++){
num[i]=a.substr(i,1);
}
for(int r=0;r<length;r++){
int n=atoi(temp.c_str());
int o=atoi(num[r].c_str());
int p=temp.length();
if((length-r<=p)&&(o<n)){
}
else if((o>n)||(r==0)){
temp=num[r];
numfinal=numfinal+temp+" ";
}
else if((o<n)||(o=n)){
int w=n;
temp=num[r]+num[r+1];
n=atoi(temp.c_str());
if(n<w){
int a=1;
int q=r+2;
while(n<w){
temp=temp+num[q];
n=atoi(temp.c_str());
p++;
a++;
}
numfinal=numfinal+temp+" ";
r=r+a;
}
else{
numfinal=numfinal+temp+" ";
r++;
}
}
}
cout<<numfinal<<endl;
}
int main(){
string a;
string num[20];
for(int r=0;r<5;r++){
input(a,num);
}
return 0;
}
This code works. But do not forget that write a simple code and use the new style of C++ programming.
#include <vector>
using namespace std;
vector<string> Input( )
{
string a;
cin >> a;
vector<string> num;
string current("-1");
string str;
for(auto c : a)
{
str.append(1, c);
if (stoi(str) > stoi(current) )
{
num.push_back(str);
current = str;
cout << str << " ";
str = "";
}
}
cout << endl;
return num;
}
int main() {
for (int i = 0; i<5; i++) {
vector<string> num;
num = Input();
}
return 0;
}
Looks like you are missing a q++ in your while loop:
while(n < w) {
temp = temp + num[q];
n = atoi(temp.c_str());
p++;
a++;
q++;
}
This is why the fourth third digit was being copied over.
The maximal munch algorithm might give you some inspiration on a cleaner way to solve this problem. It is meant for tokenizing but it may help. Good luck!

Formatting files - C++

I have hit a brick wall trying to format one of my files. I have a file that I have formatted to look like this:
0 1 2 3 4 5
0.047224 0.184679 -0.039316 -0.008939 -0.042705 -0.014458
-0.032791 -0.039254 0.075326 -0.000667 -0.002406 -0.010696
-0.020048 -0.008680 -0.000918 0.302428 -0.127547 -0.049475
...
6 7 8 9 10 11
[numbers as above]
12 13 14 15 16 17
[numbers as above]
...
Each block of numbers has exactly the same number of lines. What I am trying to do is basically move every block (including the headers) to the right of the first block so in the end my output file would look like this:
0 1 2 3 4 5 6 7 8 9 10 11 ...
0.047224 0.184679 -0.039316 -0.008939 -0.042705 -0.014458 [numbers] ...
-0.032791 -0.039254 0.075326 -0.000667 -0.002406 -0.010696 [numbers] ...
-0.020048 -0.008680 -0.000918 0.302428 -0.127547 -0.049475 [numbers] ...
...
So in the end I should basically get a nxn matrix (only considering the numbers). I already have a python/bash hybrid script that can format this file
exactly like this BUT I've switched the running of my code from Linux to Windows and hence cannot use the bash part of the script anymore (since my code has to be compliant will all versions of Windows). To be honest I have no idea how to do it so any help would be appreciated!
Here's what I tried until now (it's completely wrong I know but maybe I can build on it...):
void finalFormatFile()
{
ifstream finalFormat;
ofstream finalFile;
string fileLine = "";
stringstream newLine;
finalFormat.open("xxx.txt");
finalFile.open("yyy.txt");
int countLines = 0;
while (!finalFormat.eof())
{
countLines++;
if (countLines % (nAtoms*3) == 0)
{
getline(finalFormat, fileLine);
newLine << fileLine;
finalFile << newLine.str() << endl;
}
else getline(finalFormat, fileLine);
}
finalFormat.close();
finalFile.close();
}
For such a task, I would do it the simple way. As we already know the number of lines and we know the pattern, I would simply keep a vector of strings (one entry per line of the final file) that I would update as I'm parsing the input file. Once it's done, I would iterate through my strings to print them into the final file. Here is a code that's doing it :
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
int main(int argc, char * argv[])
{
int n = 6; // n = 3 * nAtoms
std::ifstream in("test.txt");
std::ofstream out("test_out.txt");
std::vector<std::string> lines(n + 1);
std::string line("");
int cnt = 0;
// Reading the input file
while(getline(in, line))
{
lines[cnt] = lines[cnt] + " " + line;
cnt = (cnt + 1) % (n + 1);
}
// Writing the output file
for(unsigned int i = 0; i < lines.size(); i ++)
{
out << lines[i] << std::endl;
}
in.close();
out.close();
return 0;
}
Note that, depending of the structure of your input/ouput files, you might want to adjust the line lines[cnt] = lines[cnt] + " " + line in order to separate the columns with the right delimiter.

Read integer data from a file

I am just getting started on C++ and am working on codeval questions, so if anyones done that, they'll recognize this problem as it's the first on the list. I need to open a file that has 3 columns of space separated integer values. Here is mine, under fizbuz.txt. I need to get the integer values from the file and store them for later use elsewhere in the program.
1 2 10
3 5 15
4 5 20
2 8 12
2 4 10
3 6 18
2 3 11
8 9 10
2 5 8
4 9 25
Now I can open the file just fine, and I've used getline() to read the files just fine using my below code. However, I don't want them in string format, I'd like them as integers. So I looked around and everyone basically says the same notation (file>>int1>>int2...). I've written some code exactly how I've seen it in a few examples, and it does not behave at all like they're telling me it should.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string filename = "fizbuz.txt";
string line;
int d1,d2,len;
int i =0;
int res1[10], res2[10], length[10];
ifstream read (filename.c_str());
if (read.is_open())
{
// while(read>>d1>>d2>>len);
// {
// res1[i] = d1;
// res2[i] = d2;
// length[i] = len;
// i++;
// }
while (!read.eof())
{
read>>d1>>d2>>len;
res1[i] = d1;
res2[i] = d2;
length[i] = len;
}
read.close();
}
else
{
cout << "unable to open file\n";
}
for (int j = 0; j < 10;j++)
{
cout<< res1[j] << " " << res2[j] << " " << length[j] << '\n';
}
}
Both of the while loops perform the same in the output function at the bottom. The last line of fizbuz.txt will be returned to the first elements of res1,res2 and length, and the remaining elements of all 3 are psuedorandom values, presumably from whatever program was using that memory block before. ex output below
4 9 25
32767 32531 32767
-1407116911 4195256 -1405052128
32531 0 32531
0 0 1
0 1 0
-1405052128 807 -1404914400
32531 1 32531
-1405054976 1 -1404915256
32531 0 32531
The first version should work except that you need to remove the ; in the while line.
while (read >> d1 >> d2 >> len);
^
Try this
while (!read.eof())
{
read>>d1>>d2>>len;
res1[i] = d1;
res2[i] = d2;
length[i] = len;
i++;
}

Reading variable size 2D-STL vector from file

2
1 3
2 4 8 13
3 5 6 13
4
4
8
3 7 9 10 13
8 10 11
8 9 11 12
9 10
10 15
3 4 8 14
13
12 16
15 17 18
16
18 16
I want to read this these values from file into two dimensional STL vector. Note that the size of inner vector is not uniform and not known in adance so I need to detect '\n'. So far I have been unnsuccessful. My code is as follows. Please help. What is wrong?
int main()
{
ifstream Lin("A.txt");
double d;
vector<vector<double> > A;
vector<double> dummy;
if (Lin.is_open()){
while (Lin >> d) {
if (Lin.peek() == '\n'){
A.push_back(dummy);
dummy.clear();
}else{
dummy.push_back(d);
}
}
Lin.close();
}
...
return 0;
}
When I iterate over the vector using the following code
, it reveals what is stored:
for(int i = 0; i< A.size(); i++){
for(int j = 0; j< A[i].size() ; j++){
cout << A[i][j] << " ";
}
cout << endl;
}
1
2 4 8
3 5 6
3 7 9 10
8 10
8 9 11
9
10
3 4 8
12
15 17
18
The intended output is same as the way it is stored in the file
Make sure that there is no empty space after the last integer in each line in the data file.
In the code currently you are not adding the last integer to the dummy vector. Modify it like this:
while (Lin >> d)
{
dummy.push_back(d); // Add the number first
if (Lin.peek() == '\n') // Then check if it is end of line
{
A.push_back(dummy);
dummy.clear();
}
}
Less is more. This replaces your entire loop. Note: You don't need to check is_open or call close for this to work safely.
for(std::string s; std::getline(Lin, s);)
{
A.emplace_back(std::istream_iterator<double>(std::istringstream(s)),
std::istream_iterator<double>());
}
Consider using getline.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main() {
std::string line;
std::vector<std::vector<double> > v;
while(std::getline(cin, line)) {
std::stringstream ss(line);
double value;
std::vector<double> numbers;
while(ss >> value) {
numbers.push_back(value);
std::cout << value << std::endl;
}
v.push_back(numbers);
}
return 0;
}
There could be other whitespace characters after the number at the end of line, other than \n. Like spaces:
1234 445 445 \n
^^^^
So your approach is not safe. Better would be to read entire line (getline) to some string, then construct istringstream on this string containing line, then just parse this istringstream to your vector for one line.
Like this:
for (string line; getline(filein, line); ) {
vector<double> dd;
istringstream is(line);
for (double d; is >> d; )
dd.push_back(d);
if (not dd.empty())
A.push_back(dd);
}

Merging files with mergesort algorithm in c++

I wrote a program to do an external mergesort on a file of 100,000 doubles. I couldn't quickly find and external storage libraries for c++ because googling it just leads to a bunch of pages about the extern keyword, so I decided to just write my own, and I think that's where the problem is.
The program actually works, except for a couples details. The output fill will have all of the doubles in sorted order, but at the end of the file are 30 lines of
-9.2559631349317831e+061
which is not in the input file. I also have 21 more values in the output file and the input file, not counting the 30 lines of the single number I just mentioned.
How the program runs is it reads the 100,000 doubles ~4000 lines at a time and sorts them, then stores them in to 26 text files, then those 26 files are merged into 13 files, and those 13 into 7, etc... until there is only one file.
I'm sorry if the code is really ugly, I figured out all of the external storage stuff on my own by pencil, paper, trial, and error. The program is not going to be used for anything. I haven't cleaned it up yet. The driver doesn't do much other than call these methods.
//reads an ifstream file and stores the data in a deque. returns a bool indicating if the file has not reached EOF
bool readFile(ifstream &file, deque<DEQUE_TYPE> &data){
double d;
for(int i = 0; i < DEQUE_SIZE && file.good(); i++){
file >> d;
data.push_back(d);
}
return file.good();
}
//opens a file with the specified filename and prints the contents of the deque to it. if append is true, the data will be appended to the file, else it will be overwritten
void printFile(string fileName, deque<DEQUE_TYPE> &data, bool append){
ofstream outputFile;
if(append)
outputFile.open(fileName, ios::app);
else
outputFile.open(fileName);
outputFile.precision(23);
while(data.size() > 0){
outputFile << data.front() << endl;
data.pop_front();
}
}
//merges the sortfiles until there is one file left
void mergeFiles(){
ifstream inFile1, inFile2;
ofstream outFile;
string fileName1, fileName2;
int i, k, max;
deque<DEQUE_TYPE> data1;
deque<DEQUE_TYPE> data2;
bool fileGood1, fileGood2;
i = 0;
k = 0;
max = 25;
while(max > 1){
fileName1 = ""; fileName1 += "sortfile_"; fileName1 += to_string(i); fileName1 += ".txt";
fileName2 = ""; fileName2 += "sortfile_"; fileName2 += to_string(i+1); fileName2 += ".txt";
try{
inFile1.open(fileName1);
inFile2.open(fileName2);
} catch(int e){
cout << "Could not open the open the files!\nError " << e;
}
fileGood1 = true;
fileGood2 = true;
while(fileGood1 || fileGood2){
fileGood1 = readFile(inFile1, data1);
fileGood2 = readFile(inFile2, data2);
data1 = merge(data1, data2);
printFile("temp", data1, true);
data1.clear();
}
inFile1.close();
inFile2.close();
remove(fileName1.c_str());
remove(fileName2.c_str());
fileName1 = ""; fileName1 += "sortfile_"; fileName1 += to_string(k); fileName1 += ".txt";
rename("temp", fileName1.c_str());
i = i + 2;
k++;
if(i >= max){
max = max / 2 + max % 2;
i = 0;
k = 0;
}
}
}
//merge function
deque<double> merge(deque<double> &left, deque<double> &right){
deque<double> result;
while(left.size() > 0 || right.size() > 0){
if (left.size() > 0 && right.size() > 0){
if (left.front() <= right.front()){
result.push_back(left.front());
left.pop_front();
}
else{
result.push_back(right.front());
right.pop_front();
}
}
else if(left.size() > 0){
result.push_back(left.front());
left.pop_front();
}
else if(right.size() > 0){
result.push_back(right.front());
right.pop_front();
}
}
return result;
}
I sorted a file of 26 numbers (0 - 25), as ThePosey suggested, and here are the results:
-9.2559631349317831e+061 (47 lines of this)
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
25
25
25
25
25
So I'm pretty sure the last number of the file is being duplicated, but I'm still not sure what the 47 occurrences of the random large number is caused by. I checked and the last number of the 100,000 number word is only in the output file twice, not 22 times, So I think I have 11 separate last number being duplicated.
I don't know if this is the whole problem or not, but you have a classic error in your input loop. file.good() doesn't guarantee that the next read will succeed, it only tells you that the previous one did. Try restructuring it like this:
for(int i = 0; i < DEQUE_SIZE && (file >> d); i++){
data.push_back(d);
}
The expression file >> d returns a reference to file, which calls good when you try to evaluate it as a boolean.
Is there a reason why you can't use a few megs of memory to read the entire list in at once into RAM and sort it all at once? It would simplify your program a lot. If you are trying to do this as a challenge I would start by shrinking the problem to say like 1 file of 100 doubles, split that into 4, 25 double reads, and then it should be very easy to trace through and see where the additional lines are coming from.
Assuming your files are in text format, you can use std::merge to do an external merge just as well as an internal one, by using std::istream_iterators.
std::ifstream in1("temp1.txt");
std::ifstream in2("temp2.txt");
std::ofstream out("output.txt");
std::merge(std::istream_iterator<double>(in1),
std::istream_iterator<double>(),
std::istream_iterator<double>(in2),
std::istream_iteraror<double>(),
std::ostream_iterator<double>(out, "\n"));