Can't read a text file - c++

I've been coding for a basic Snake Game in C++. I wanted to store the top 5 high-scores in a text file so I could display them in the end.
I'm only showing the relevant code here.
Code:-
#include<fstream>
ofstream outfile("HighScore.txt");
ifstream infile("HighScore.txt");
int main()
{
int a[5]={0},temp;
infile.clear();
infile.seekg(0,infile.beg);
if(infile.is_open())
{
for(int i=0;i<=4;i++) infile>>a[i];
infile.close();
}
else cout<<"Unable to open";
char temp1;
Setup();
do
{
Draw();
Input();
Logic();
if(gameOver==0)
{
cout<<"\x1b[2J\x1b[1;1H"<<flush;
cout<<"\t\t\t\tSNAKE GAME"<<endl;
cout<<"\n\n\n\t\tYour score is:"<<score;
cout<<"\n\n\n\n\t\tDo you want to restart the game?\n\t\t Press y to continue\n\t\t";
temp1=(char)getch();
for(int i=4;i>=0;i--)//Used to make sure that the scores remain in a descending order
{
if(score>a[i])
{
if(i==4) a[i]=score;
else
{
temp=a[i];
a[i]=score;
a[i+1]=temp;
}
}
}
if(outfile.is_open())//Used to write the high-scores in "HighScore.txt"
{
for(int i=0;i<5;i++) outfile<<a[i]<<endl;
}
else cout<<"Unable to open";
outfile.close();
}
}
It seems that the code for writing the file is working and the output is always the current score at the top along with 4 0's.
For example:- If I scored 5 this time then the output will be
5
0
0
0
0
So according to me I'm not able to read the current values of the file because of which the values in the array a is always 0.
[I'm new here so I'm sorry if my formatting or description here is not up to the mark]

Related

How to not show the null character while inserting a character into a 2d string?

I was making a pretty simple Battleship game for my school project (I HAVE to use Turbo C++) and i ran into a problem. I'm basically using a 5x5 2D string as my board and hiding a "ship" in it. What I'm trying to do is that whenever the user makes a wrong guess, I want to replace the "O" in the board with an "X", but when i do that, the "O" in the next block gets replaced by a "/0" and shows as a blank space in the output. How do I fix that?
Here's the code:
#include<conio.h>
#include<iostream.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<stdio.h>
//A function to initialize the board
void start_board(char a[5][5])
{
for(int i=0;i<5;i++)
{ for(int j=0;j<5;j++)
{ strcpy(&a[i][j],"O");
}
}
}
//A function to display the board
void display_board(char a[5][5])
{ for(int i=0;i<5;i++)
{ for(int j=0;j<5;j++)
{ cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
class board
{ public:
char board[5][5];
void start()
{ start_board(board);
}
void display()
{ display_board(board);
}
};
class ship
{ public:
int ship_row, ship_col;
ship()//CONSTRUCTOR FOR PUTTING COORDINATES OF SHIP
{ randomize();
ship_row= random(5);
ship_col=random(5);
cout<<ship_row<<endl<<ship_col;
}
};
class guess: public board, public ship
{ public:
int guess_row,guess_col;
char vboard[5][5];
guess()
{ start_board(vboard);
}
void takeguess();
};
void guess:: takeguess()
{ int count=0;
while(count<3)
{
cout<<endl;
cout<<"Guess a row ";
cin>>guess_row;
cout<<"Guess a column ";
cin>>guess_col;
if(guess_row==ship_row && guess_col==ship_col)
{ cout<<"Congratulations! You sank the battleship!";
break;
}
else if(guess_row>4 || guess_col>4)
{ cout<<"invalid guess";
}
else
{ clrscr();
cout<<"Incorrect Guess!"<<endl;
strcpy(&vboard[guess_row][guess_col],"X");
display_board(vboard);
count+=1;
}
if(count==3)
{ cout<<"GAME OVER!";
}
}
}
void main()
{ clrscr();
board b;
b.start();
b.display();
guess g;
g.takeguess();
getch();
}
For example, If the user guesses 0,2, and that isn't the ship's location the output will show:
OOX O
OOOOO
OOOOO
OOOOO
OOOOO
Sorry for the messy code(it isn't complete) and any mistakes i made while writing this post, it's my first time using stackoverflow. Thank You for your help!
Don't use strcpy!! You're not copying a string, you're setting the value of a single character in the string, so use the right tool for the job.
vboard[guess_row][guess_col] = 'X';
This is because "X" is actual 2 characters 'X' and '\0' so your strcpy hits 2 cells in your array

Real time data from CSV read in C++

I need to read data from CSV file which is updated every second with a new data in the same cell and row.
What i mean is following :
For example i have 1 in the first row and cell then i have already 2 etc. But everything is changed in the same row and column.
struct Node
{
double number;
}
void readData(vector<Node>&Values)
{
Node Data;
ifstream file("file.csv");
if (file.good())
cout << "file ok";
file >> Data.number;
Values.push_back(Data);
}
int main()
{
vector<Node>Values;
while (true)
{
readData(Values);
_sleep(1000);
}
}
The problem i have is that it reads every second the new data but it saves in the vector the same number from the beginning. If the number was 1, it will save the same number hundreds times even if the number has been changed 10 times.
What should i change in the read file to work with the data which can be updated because the csv file is opened and updated, i can not close it?
I am pretty sure that it can be done the problem i did not find any solution in the internet.
Thank you in advance!
I would simplify the code as such;
double ReadData()
{
double val;
ifstream file("file.csv");
if (!file.good())
{// Check if valid, return Error Code
return 0;
}
file >> val;
return val;
}
int main()
{
vector<double> values;
while (true)
{
double retVal = ReadData();
if (retVal == 0)
{// Whatever you defined the error code as
break;
}
values.push_back(retVal);
_sleep(1000);
}
}
and if you really want the structure I'd just return the data and add it to the structure in the main loop.
Change from _sleep(1000) to _sleep(150

Infinite loop when writing blank records to a binary file

The purpose of the following short program is to search through a binary file (that contains details of different trains) for a particular train (whose number is accepted from the user) and then rewrite a blank record at that location.
That is, I wish to 'delete' that train record.
The problem is that the program goes into an infinite loop and repeatedly writes blank records to the binary file, thereby resulting in an enormous 2 GB .dat file being created.
#include<iostream.h>
#include<fstream.h>
struct train {
int train_no;
char train_name[50], source[20], dest[20];
int n_AC1, n_AC2, n_ACC, n_FC, n_SLC, n_SS; // variables for no of seats
train() { //default constructor
train_no = 0;
n_AC1=0, n_AC2=0, n_ACC=0, n_FC=0, n_SLC=0, n_SS=0;
strcpy(train_name, "/0");
strcpy(source, "/0");
strcpy(dest, "/0");
}
//member functions to accept and display the above values
};
void remove_train(fstream &f) {
train t, blank;
int tno, found = 0;
do {
cout<<"Enter the train no: ";
cin>>tno;
if(tno <=0)
cout<<"Invalid train number. Please re-enter."<<endl;
}
while(tno <=0);
f.seekg(0L, ios::beg);
f.read((char*)&t, sizeof(train));
while(!f.eof() && !found) {
if(t.train_no == tno) {
found = 1;
f.seekp(-sizeof(train), ios::cur);
f.write((char*)&blank, sizeof(train));
cout<<"Train number "<<tno<<" has been deleted!"<<endl;
}
else
f.read((char*)&t, sizeof(train));
}
if(found == 0)
cout<<"ERROR: train not found."<<endl;
}
int main() {
fstream f("Trains.dat", ios::binary | ios::in | ios::out);
remove_train(f);
cin.ignore();
cin.get();
}
When the above program is executed, after I input the train number as '1', the only observable output is "Train number 1 has been deleted", following which the program goes into the aforementioned infinite loop.
This doesn't seem to be an isolated issue; whenever I try to move back by one record and
then write a blank record anywhere in the Railway Reservation project that this code is a part of, the same problem ensues. For instance, if it is a passenger record I wish to overwrite, this is the relevant code fragment that seems to be causing the issue:
f.seekp(-1L*sizeof(passenger), ios::cur);
f.write((char*)&p, sizeof(passenger));
MAJOR EDIT: The problem was fixed when I replaced -sizeof(train) with -110L (which is the byte size of the 'train' structure)! Any idea why this is the case?
I must say I am at a loss to find a fault in your code. I've run a copy of it and it worked as expected.
There are a few minor errors (for instance it will fail if your data file does not exist) and the code could certainly be improved (your usage of f.eof() is somewhat awkward), but nothing that can explain the behaviour you're describing.
Here is the exact version I'm running right now. Except for a bit of extra code to create a dummy data file and a few debug outputs, I don't see any difference with yours.
Maybe you could try to compile it and see if it fails in your environment?
#include<iostream>
#include<fstream>
#include <string.h>
using namespace std;
struct train {
int train_no;
char train_name[50], source[20], dest[20];
int n_AC1, n_AC2, n_ACC, n_FC, n_SLC, n_SS; // variables for no of seats
train() { //default constructor
train_no = 0;
n_AC1=0, n_AC2=0, n_ACC=0, n_FC=0, n_SLC=0, n_SS=0;
strcpy(train_name, "");
strcpy(source, "");
strcpy(dest, "");
}
//member functions to accept and display the above values
};
void remove_train(fstream &f) {
train t, blank;
int tno, found = 0;
do {
cout<<"Enter the train no: ";
cin>>tno;
if(tno <=0)
cout<<"Invalid train number. Please re-enter."<<endl;
}
while(tno <=0);
cout<<"deleting train "<<tno<<endl;
f.seekg(0L, ios::beg);
f.read((char*)&t, sizeof(train));
while(!f.eof() && !found) {
cout<<f.tellp()<<endl;
if(t.train_no == tno) {
found = 1;
f.seekp(-sizeof(train), ios::cur);
cout<<"delete "<<f.tellp()<<"/"<<f.tellg()<<endl;
f.write((char*)&blank, sizeof(train));
cout<<"Train number "<<tno<<" has been deleted!"<<endl;
}
else
{
cout<<"read "<<f.tellg()<<endl;
f.read((char*)&t, sizeof(train));
}
}
if(found == 0)
cout<<"ERROR: train not found."<<endl;
else
cout<<"done"<<endl;
}
void create_trains(int n)
{
fstream f("Trains.dat", ios::binary | ios::out);
train t;
for (int i = 1 ; i <= n ; i++)
{
t.train_no = i;
f.write((char*)&t, sizeof(train));
}
}
int main() {
create_trains (10);
fstream f("Trains.dat", ios::binary | ios::in | ios::out);
remove_train(f);
cin.ignore();
cin.get();
}

C++ strange "format" of output string

I am writing a C++ applications that is working with files. I have implemented standard operations like writing and reading from the file, some search functions, etc.
After doing some operations, my output strings come in a very strange way. For example the text "Address -", comes as "?п&&..&":
Is there any buffer in C++ that could be full by the file operations and it is doing this output so i need to empty it or clean it?
Edit: The problem appeared when I write a functions that is reading the records from my file, choosing some of them due to user criteria and then sorting them.
Here is my code:
Stucture:
struct Appartament
{
char address[50];
char telephoneNumber[20];
char view[10];
double price;
double distanceFromCenter;
int roomCount;
};
Function working with the file:
//Search by room count and order by price (rising)
void AdvanceSearch()
{
clrscr();
Appartament currentRecord;
int recordsCount=0;
fstream currentFile("Records.dat",ios::binary|ios::in);
if(!currentFile)
{
cout<<"Error - the file could not be opened."<<endl;
return;
}
else
{
//Array with apartments records
Appartament CurrentRecords[MaxRecords];
currentFile.seekg(0L,ios::end);
long int length=currentFile.tellg();
currentFile.seekg(0L,ios::beg);
int isAppartamentFound=0;
if(length==0)
{
cout<<"The file is empty."<<endl;
return;
}
else
{
int userRoomCount;
do
{
clrscr();
cout<<"Enter apartment room count - ";
cin>>userRoomCount;
}while(userRoomCount<0);
clrscr();
cout<<endl<<"Apartments with "<<userRoomCount<<" rooms order by price:";
currentFile.read((char*)(&currentRecord),sizeof(Appartament));
while(!currentFile.eof())
{
if(currentRecord.roomCount==userRoomCount)
{
CurrentRecords[recordsCount]=currentRecord;
recordsCount++;
isAppartamentFound=1;
}
currentFile.read((char*)(&currentRecord),sizeof(Appartament));
}
currentFile.close();
}
if(isAppartamentFound==0)
{
cout<<endl<<"There are no matches!"<<endl;
}
else
{
//If only one apartment is found
if(recordsCount==1)
{
cout<<endl;
ShowRecord(currentRecord);
}
else
{
//Sort the records
Appartament tempApartament;
int isChangeMade=1;
for(int index=0;index<recordsCount;index++){
//ShowRecord(CurrentRecords[index]);
}
while(isChangeMade==1)
{
isChangeMade=0;
for(int index=0;index<recordsCount-1;index++)
{
if(CurrentRecords[index].price>CurrentRecords[index+1].price)
{
isChangeMade=1;
tempApartament=CurrentRecords[index];
CurrentRecords[index]=CurrentRecords[index+1];
CurrentRecords[index+1]=tempApartament;
}
}
}
for(index=0;index<recordsCount;index++)
{
ShowRecord(CurrentRecords[index]);
}
}
}
}
}
Function for showing a record:
void ShowRecord(Appartament Record)
{
cout<<"Apartment Information"<<endl;
cout<<"The address is - "<<Record.address<<" and it is only "<<Record.distanceFromCenter<<" miles away from the center."<<endl;
cout<<"The price is "<<Record.price<<" $ for "<<Record.roomCount<<" rooms with "<<Record.view<<" view."<<endl;
}
Тhis is possible output:
I have run my program on other machine with other version of Borland and it is working perfectly. That's why the questions is what is wrong with mine compiler :?

Array not being assigned correctly

I'm trying to write a program that accepts user input for a file name. From there it stores the numbers in the file into an array, sorts them, then displays them. However, i'm getting large numbers similar to accessing an out-of-bounds array, but I can tell from the debugger i'm not.
#include <iostream>
using namespace std;
class TestScores
{
public:
TestScores();
TestScores(int scores);
~TestScores();
void AddScore(int newScore);
void DisplayArray();
void SortScores();
bool ArraySorted();
int AvgScore();
private:
int *scoresArray; //Dynamically allocated array
int numScores; //number of scores input by user
int scoreCounter;
const static int default_NumArrays=10; //Default number of arrays
};
#include <iostream>
#include "TestScores.h"
TestScores::TestScores()
{
scoresArray=new int[default_NumArrays];
scoreCounter=0;
numScores=default_NumArrays;
}
TestScores::TestScores(int scores)
{
scoresArray=new int[scores];
numScores=scores;
scoreCounter=0;
for(int i=0; i<scores;i++)
scoresArray[i]=0;
}
TestScores::~TestScores()
{
delete[] scoresArray;
}
void TestScores::AddScore(int newScore)
{
if(scoreCounter<numScores){
scoresArray[scoreCounter]=newScore;
scoreCounter++;
}
else
cout<<"More scores input than number of scores designated"<<endl;
}
void TestScores::DisplayArray()
{
for(int i=0; i<numScores; i++)
cout<<scoresArray[i]<<endl;
cout<<endl<<"This is scoresArray"<<endl;
}
bool TestScores::ArraySorted()
{
for(int i=0; i<(scoreCounter-1);i++){
if(scoresArray[i]<=scoresArray[i+1])
continue;
else
return false;
}
return true;
}
void TestScores::SortScores()
{
int tempValue;
while(ArraySorted()!=true){
for(int i=0; i<(scoreCounter-1); i++){
if(scoresArray[i]<=scoresArray[i+1])
continue;
else{
tempValue=scoresArray[i+1];
scoresArray[i+1]=scoresArray[i];
scoresArray[i]=tempValue;
}
}
}
}
int TestScores::AvgScore()
{
int sumScores=0;
if(scoreCounter>0){
for(int i=0; i<scoreCounter; i++)
sumScores+=scoresArray[i];
return (sumScores/scoreCounter);
}
else{
cout<<"There are no scores stored."<<endl;
return 0;
}
}
#include "TestScores.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//Function prototypes
bool FileTest(ifstream& inData);
void StoreScores(ifstream& inData, int& newNumScores, TestScores satScores);
int main()
{
int newNumScores=0;
string inputFile; //Contains name of the user file being used
//Opening file stream
ifstream inData;
//User prompt for input file
cout<<"Please enter the file name containing the student scores you wish to "
<<"have stored, sorted, and displayed."<<endl;
cin>>inputFile;
//Opening file streams
inData.open(inputFile.c_str());
while(FileTest(inData)==false){
cout<<"I'm sorry, the file you entered was not a valid file. "
<<"Please enter another file name, or enter q to exit"<<endl;
cin>>inputFile;
if(inputFile=="q")
return 0;
//Opening file streams
inData.open(inputFile.c_str());
}
inData>>newNumScores;
TestScores satScores(newNumScores); //Instantiating TestScores variable
StoreScores(inData, newNumScores, satScores); //Storing scores into array
satScores.DisplayArray();
satScores.SortScores();
satScores.DisplayArray();
cout<<endl<<"This is the array after sorting"<<endl<<endl;
cout<<"This is the average score "<<satScores.AvgScore()<<endl;
//Program pauses for user input to continue
char exit_char;
cout<<"\nPress any key and <enter> to exit\n";
cin>>exit_char;
inData.close();
return 0;
}
bool FileTest(ifstream& inData)
{
if(!inData)
{
cout<<"Your file did not open.\n";
return false;
}
return true;
}
void StoreScores(ifstream& inData, int& newNumScores, TestScores satScores)
{
int userScore;
while(inData>>userScore){
satScores.AddScore(userScore);
}
}
My test file is random.dat and contains the following:
15
67
76
78
56
45
234
Based on looking through the debugger, I can tell that scoreCounter is incrementing correctly and that newScore contains the next value, so why isn't it being stored in the array? Thanks for the help
Okay, the problem is pretty simple: You pass satScores by value to StoreScores. This will only fill the local copy, change the signature of StoreScores to the following to fix:
void StoreScores(ifstream& inData, int& newNumScores, TestScores& satScores)
(Btw you don't actually use the newNumScores variable.)
The output is then as expected:
15
67
76
78
56
45
234
0
0
0
0
0
0
0
0
0
0
For further improvement of your code, see GMan's comment and Ben's answer.
You have a user-defined destructor but no copy-constructor or assignment operator. No wonder assignment doesn't work right, you get a leak of one buffer and double-free of the other.
Follow the Rule of Three. Or better yet, use a container that's already been debugged, like std::vector.