Can't get last int from .txt file - c++

My Issue involves reading integers from a text file, saving them to an array and then copying the array to a new .txt file.
So there is a file "krol.txt"
2 4
3 7
3 13
2 4
3 1
The problem is that it never ever save the last '1' from the input .txt file. I have no idea why. I think its about EOF on last character in file but why it works like that? Can anyone help me?
This is my code:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main() {
ofstream outFile;
ifstream fin;
fin.open("krol.txt");
int l=0;
char ch;
while (fin.good()) {
fin.get(ch);
if(ch=='\n') l++;
}
fin.close();
fin.open("krol.txt");
int temp[l][2];
int savel=l;
l=0;
int i=0;
while (fin >> (temp[l][i])) {
i++;
if(i==2) {
i=0;
l++;
}
}
outFile.open("save.txt");
for (int i=0, j=0;j<savel;i++) {
if (i==2) {
i=0; j++;
}
outFile << temp[j][i];
}
outFile.close();
system("PAUSE");
return 0;
}

This saves all the numbers just fine. The problem is, it stores additional numbers in save.txt.
With
while (fin.good()){
...
}
you count the last line twice. This gives you two additional uninitialized ints. These two ints can show up as any integer.
I see two problems. Your first loop to get the number of lines should be more like
while (fin.get(ch)){
if (ch == '\n')
l++;
}
If the last line doesn't have a final \n, you could end with one line less than you need.
And the output loop could be simplified to
for (int j = 0; j < savel; j++){
for (int i = 0; i < 2; i++)
outFile << temp[j][i] << ' ';
}
And finally, if you use c++, you should consider using std::vector instead of plain arrays. Then you don't need to preallocate your array and can read the file in just one pass.

There might be 4 '\n' chars in that file have you considered that?

Related

How do you read a text file into a vector in c++?

I am trying to read a text file containing 9 lines of single integers into a vector. VS Code returns no syntax error but when I debug the program, I got a segmentation fault under main(I commented on the specific line). Am I doing something wrong with my implementation? Thank you in advance!
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
vector <int> list = {};
int count_line(){ //Count the number of accounts in the txt file
int count = 0;
string line;
ifstream count_file;
count_file.open("text.txt"); //The text file simply have 9 lines of single integers in it
if (!count_file){
cerr<<"Problem reading from file"<<endl;
return 1;
}
while (!count_file.eof()){
getline(count_file,line);
count ++;
}
count_file.close();
return count - 1;
}
int main(){
int i{0};
count_line();
ifstream input {"text.txt"};
if (!input){
cout<<"Problem reading from file"<<endl;
return 1;
}
while (i <= count_line() && count_line() > 0){
input>>list[i]; //I am getting a segmentation fault error here
i++;
}
for (int k = 0; k < 9 ; k++){
cout<<list[k];
}
}
This vector:
vector <int> list = {};
Has exactly zero members. You never try and increase its size so any access to this array will result in a bad result.
There are a couple of places you accesses this vector:
input>>list[i];
// and
cout<<list[k];
These are both invalid access to the list.
To fix the problem you can read the data into a value and then append it to the vector:
int value;
input >> value;
list.emplace_back(value); // emplace back expands the vector by one place.
But that is not your only problem:
while (i <= count_line() && count_line() > 0){
This while statement contains to calls that open a file parse the whole file and return a count. I doubt the compiler can optimize that away so that is exceedingly expensive call to make.
Can you just read values until there are none left?
int value;
while(input >> value) {
list.emplace_back(value);
}
But the proper way to do this:
#include <vector>
#include <iterator>
#include <iostream>
#include <fstream>
int main()
{
std::ifstream file("text.txt");
std::vector<int> data(std::istream_iterator<int>{file},
std::istream_iterator<int>{});
for(auto val: data) {
std::cout << val << " ";
}
std::cout << "\n";
}
You must allocate elements before using them.
one of fix:
while (i <= count_line() && count_line() > 0){
if (list.size() <= (size_t)i) list.resize(i + 1); // add this
input>>list[i];

HW Help - Reading from file character by character C++

For a project I am currently working on, I have to read from a file and depending on the certain character in the file, output either a 1 or 0 to an array.
So here is an example of file input:
* * *
* * *
** ** **
*** *
And here is the function I have written to handle this:
void input (int cellGrid[][MAX]) //takes info from a .txt and puts it into an array
{
ifstream infile; //declare a file variable
int row;
int column;
int number;
infile.open("life.txt"); //open a file
while(infile>>row>>column) { //inserts bacteria places into array
cout << row << " " << column << endl;
cellGrid[row][column]=1; //makes it equal one if bacteria is present
}
infile.close(); //closes file
}
My thinking was that the function needs to see if there is a character that exists and if so, place a 1 in its respective position ([row][column]) in the array. However with this current code, nothing is input into my array.
Generally in C++ use std::vector wherever possible.
Array example:
You have to go through the file and record position of each *. Then set it to 1 for that position. Something like the following (we use getline and i as counter for rows, then we loop through the line using j as counter for columns):
#include <fstream>
#include <string>
using namespace std;
void input(int cellGrid[][100]) {
ifstream infile;
infile.open("life.txt");
int i = 0;
for (string line; getline(infile, line); ++i)
{
for (size_t j = 0; j < line.size(); ++j) {
if (line[j] == '*') {
cellGrid[i][j] = 1;
}
}
}
infile.close();
}
Vector example #1:
Here you can find a solution using std::vector. It will be always in a size rows x columns. One thing it requires is to pass default constructed vector and not constructed with vector(size_type count); c-tor. You can write your own version that doesn't have this problem:
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void input(vector<vector<int>> &cellGrid) {
ifstream infile;
infile.open("life.txt");
int i = 0;
for (string line; getline(infile, line); ++i)
{
cellGrid.push_back(vector<int>(line.size()));
for (size_t j = 0; j < line.size(); ++j) {
if (line[j] == '*') {
cellGrid[i][j] = 1;
}
}
}
infile.close();
}
int main() {
vector<vector<int>> cellGrid;
vector<vector<int>> cellGrid2(100);
input(cellGrid);
//input(cellGrid2); - THIS WILL THROW AN EXCEPTION
return 0;
}
Vector example #2:
It would be even better for you function to return a newly created and populated vector:
#include <fstream>
#include <string>
#include <vector>
using namespace std;
vector<vector<int>> input() {
ifstream infile;
infile.open("life.txt");
vector<vector<int>> cell_grid;
int i = 0;
for (string line; getline(infile, line); ++i)
{
cell_grid.push_back(vector<int>(line.size()));
for (size_t j = 0; j < line.size(); ++j) {
if (line[j] == '*') {
cell_grid[i][j] = 1;
}
}
}
infile.close();
return cell_grid;
}
int main() {
auto vec = input();
return 0;
}
My thinking goes like this:
set row to 0
while can read a line from file
set column to 0
for each character on line
if character is '*'
set cellGrid(row,column) to 1
else
set cellGrid(row,column) to 0
increment column
increment row
You may want additional logic to trap row or column trying to go out of bounds or characters that aren't ' ' or '*'.

Not getting the output I want

I am trying to write a c++ program to read a txt file containing data (122X300 matrix - tab delimited matrix) into my code and get it to display. The following is the code I wrote after referring extensively to google and many similar questions on this site. On running the code, I do not get any errors, however it does give me huge list of numbers which I cant seem to make any sense of. The following is the code: Any help would be great. I do not know where I am going wrong. Thanks.
DID some changes after considering the comment below by #ZekeMarsh, the problem now is that my text data is like:
Data Matrix Snapshot
The output I am getting is this:
Output of Code
The row counter does not move over to the next row,instead continues in the same row after incrementation....No idea why. The code modified is as follows:
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
using namespace std;
int main(){
int HEIGHT = 3;
int WIDTH = 2;
int array_req[HEIGHT][WIDTH];
string userinputprompt, filename;
userinputprompt = "Data Filename: ";
cout<<userinputprompt<<endl;
getline(cin,filename);
ifstream inputfile;
inputfile.open(filename.c_str());
for(int i=0; i<HEIGHT; i++)
{
for(int j=0; j<WIDTH; j++)
{
/*if(!(inputfile>>array_req[i][j]))
{
cerr<<"Error";
break;
}
else if(!inputfile) // its error.. , can use a cerr here...
{
cerr<<"Error";
break;
}
else*/
inputfile>>array_req[i][j];
cout<<i<<","<<j<<"-->"<<array_req[i][j]<<endl;
}
/* This is not needed, read above comment
else
{
inputfile >> array_req[i][j];
}*/
}
for(int p=0; p<HEIGHT; p++)
{
for(int q=0; q<WIDTH; q++)
{
cout<<array_req[p][q]<<" ";
}
cout<<"\n";
}
inputfile.close();
getchar();
return 0;
}
.
EDITED CODE - The output array is a null matrix. Please help. What is wrong in the code ..compiles correctly. Trying to read line by line using getline and stringstream based on a lot of examples I read here..still not working.
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
#include <sstream>
#include <stdlib.h>
const int HEIGHT = 3;
const int WIDTH = 4;
const int BUFFSIZE = 10000;
using namespace std;
int main(){
int array_req [HEIGHT][WIDTH];
char buff[BUFFSIZE];
string userinputprompt, filename;
userinputprompt = "COLORDATA FILENAME: ";
cout<<userinputprompt<<endl;
getline(cin,filename);
ifstream inputfile;
stringstream ss;
inputfile.open(filename.c_str());
for (int i=0; i<HEIGHT; i++)
{
inputfile.getline(buff,BUFFSIZE,'\n');
ss<<buff;
for(int j=0;j<WIDTH; j++)
{
ss.getline(buff,1000,'\n');
array_req[i][j]=atoi(buff);
}
ss<<"";
ss.clear();
}
for(int p=0; p<HEIGHT; p++)
{
for(int q=0; q<WIDTH; q++)
{
cout<<array_req[p][q]<<" ";
}
cout<<"\n";
}
inputfile.close();
getchar();
return 0;
}
First of all during the printing of your array, you are not delimiting your data with anything which will result in a line of numbers. You should add delimiter and line breaks.
Second and most importantly: you try printing the full value of the array while it has not been filled up yet. I believe you meant to put the printing outside of the loop that works with your variable i . Now you are printing garbage in the places where the array was not filled yet.
Edit: Here is only the reading part as I believe that is only what you are looking for:
for (int i = 0; i < HEIGHT; ++i)
{
std::string tmpString;
std::getline(inputfile, tmpString);
std::stringstream ss(tmpString);
for(int j=0;j < WIDTH; ++j)
{
ss >> array_req[i][j];
}
}

Searching for a word in cstring text (1-D array/c++)

I'm practicing 1-D array and the question asks from the user to input a line of text and then input a word that the user wants to search and find out how many times it's repeated in the line of text. It doesn't have to be a separated by spaces and can be in a word (i.e. 'go' in 'goalkeeper').
My problem is creating a proper if condition in the loop that searches through the sentence. Thing is, my line variable is char ( char line[200]; ) while my word variable was string (string word;) so my program gave me an error when I wrote a condition in the loop that went like this:
if ( line[i] == word)
Then I tried changing the word variable to char and created a loop to get the input but then I got stuck with how to work out the loop that searches through the line of text.
I just want some pointers. This is my current code so far (it's a mess):
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main()
{
char liner[200], word[200];
int i, counter1 = 0, counter2 = 0;
cout<<"Enter a line of text: ";
cin.get (liner, 200);
cout<<"Enter a word to search: ";
for (i = 0; word[i] != ' '; i++)
{
cin>>word[i];
}
cout<<endl;
for (i = 0; i < 200; i++)
{
if (liner[i] == word[t])
{
counter2++;
}
}
cout<<word<<" was found "<<counter2<<" times."<<endl;
return 0;
}
One possible solution is to use strncmp, which compares 2 strings up to the specified length to see if they are equal (stopping when end of either is reached or number of chars have been compared).
So, the code would be something like:
int main()
{
char liner[200], word[200];
int i, counter1 = 0, counter2 = 0;
cout<<"Enter a line of text: ";
cin.getline(liner, 200);
cout<<"Enter a word to search: ";
cin.getline(word, 200);
cout<<endl;
int lineLen = strlen(line);
int wordLen = strlen(word);
for (i = 0; i < lineLen && I < wordLen; i++)
{
if (strncmp(&line[i], word, wordLen)
{
counter2++;
}
}
cout<<word<<" was found "<<counter2<<" times."<<endl;
return 0;
}
To improve the program, you can try not using a fixed size array, but read the data into a std::string.

For-Loop - value of i is not 0 even if code says 'int i = 0'. i = BIG number, why? How to fix?

I'm designing a program to clean up a text file that contains code. It removes comments, excess spaces/lines, and creates a new line for lines in the file with multiple semi-colons.
I actually got this program to work, but it used arrays. Since I am working on another program that builds on this, except with a more diverse size of data inputs, I'm converting it to use vectors instead of standard arrays so I can re-purpose the program...which is kind of the point.
My problem is that after the program iterates through the first for-loop, the rest of the for-loops initialize the iterator with a value of '3435973836', regardless of proper declaration ('int i = 0', 'int k = 0', etc). I declare them unsigned and omitting singed/unsigned still initializes the value incorrectly (-858993460).
This does 1 of 2 things:
unsigned the loop never starts as the value is too high to start the loop.
omitting makes the loop run for a long, long time.
Any thoughts? I've posted the code below. Please ignore any other errors I've made other than this, as I have been unable to get past this to debug anything else.
EDIT --> SOLVED: the problem that I was passing the vectors by value. But even when I changed it to pass by reference the program would still not work. The actual problem was with Microsoft Visual Studio 2012. Once I PBV once, it corrupted my project. I had to start a new VS project and insert the code. If you do this, be careful you don't run the program while still PBV or you'll have to do it again. I don't know why this happens. Maybe somebody who knows MS Visual Studio could answer that.
Thanks again community!
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void removeComments(vector<string> row, ifstream & myfile);
void sortLines (vector<string> row);
//void cleanCode (vector<string> row);
int main()
{
vector<string> row;
ifstream myfile;
//Open txt file
myfile.open("newdata.txt");
if(myfile.is_open())
{
//Remove comments, create proper lines, and remove/add spaces.
removeComments(row, myfile);
sortLines(row);
//cleanCode(row);
}
else
{
cout<< "ERROR: No file was able to open. Check the file name or location and try again."<< endl << endl;
}
for (unsigned int i = 0; i < row.size(); i++)
{
cout<< row[i] << endl;
}
cout<< endl;
myfile.close();
system("PAUSE");
return 0;
}
//FUNCTIONS
//Removes all comments.
void removeComments(vector<string> row, ifstream & myfile)
{
string line;
while(getline(myfile, line))
{
string tempString;
for(unsigned int i = 0; i < line.length(); i++)
{
//Copy characters to row string array until "//".
//All character following and including "//" will be ignored.
if(line.at(i) == '/' && line.at(i+1) == '/')
{
break;
}
else
{
tempString += line.at(i);
}
}
row.push_back(tempString);
}
}
//Creates a new line after every semi-colon.
void sortLines (vector<string> row)
{
vector<string> tempRow;
string tempLine;
string tempString;
for (unsigned int i = 0; i < row.size(); i++)
{
tempLine = row [i];
for (unsigned int j = 0; j < tempLine.length(); j++)
{
tempString += tempLine[j];
if (tempLine[j] == ';')
{
tempRow.push_back(tempString);
}
}
}
//Revalue row array elements.
//DEBUGGING OUTPUT
for (unsigned int i = 0; i < tempRow.size(); i++)
{
cout<< tempRow[i] << endl;
}
row.clear();
row = tempRow;
}
Okay, this is my by-reference edit:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void removeComments(vector<string> &row, ifstream & myfile);
void sortLines (vector<string> &row);
//void cleanCode (vector<string> &row);
int main()
{
vector<string> row;
ifstream myfile;
//Open txt file
myfile.open("newdata.txt");
if(myfile.is_open())
{
//Remove comments, create proper lines, and remove/add spaces.
removeComments(row, myfile);
sortLines(row);
//cleanCode(row);
}
else
{
cout<< "ERROR: No file was able to open. Check the file name or location and try again."<< endl << endl;
}
for (unsigned int i = 0; i < row.size(); i++)
{
cout<< row[i] << endl;
}
cout<< endl;
myfile.close();
system("PAUSE");
return 0;
}
//FUNCTIONS
//Removes all comments.
void removeComments(vector<string> &row, ifstream & myfile)
{
string line;
while(getline(myfile, line))
{
string tempString;
for(unsigned int i = 0; i < line.length(); i++)
{
//Copy characters to row string array until "//".
//All character following and including "//" will be ignored.
if(line.at(i) == '/' && line.at(i+1) == '/')
{
break;
}
else
{
tempString += line.at(i);
}
}
row.push_back(tempString);
}
}
//Creates a new line after every semi-colon.
void sortLines (vector<string> &row)
{
vector<string> tempRow;
string tempLine;
string tempString;
for (unsigned int i = 0; i < row.size(); i++)
{
tempLine = row [i];
for (unsigned int j = 0; j < tempLine.length(); j++)
{
tempString += tempLine[j];
if (tempLine[j] == ';')
{
tempRow.push_back(tempString);
}
}
}
//Revalue row array elements.
//DEBUGGING OUTPUT
for (unsigned int i = 0; i < tempRow.size(); i++)
{
cout<< tempRow[i] << endl;
}
row.clear();
row = tempRow;
}
As others have noted you're:
Passing vectors by value
Using something possibly uninitialized out-of-my-scope (this is nowhere declared/defined in your question) as increment variable
//Creates a new line after every semi-colon.
void sortLines (vector<string> row)
{
vector<string> tempRow;
string tempLine;
string tempString;
for (unsigned int i = 0; i < row.size(); k++) // <-- what is k??
{
Why pass "string line" to removeComments? It should be local to that function cos you don't use it outside. It looks dodgy for the same reason that the passed vectors did.