Why can't I succesfully read file data to a struct array - c++

I am writing a program based on the battleship board game for my C++ final, The problem I'm currently working on is how to manage user accounts. I have to allow users to use the same account every time they play and keep track of their win/loss record. I'm able to write the data to a file but I need to read it back in when a player logs back in and then sort it to find their user name. I'm stuck at this part.
this is a the file I'm using, its read as username,wins,losses:
Rocky 0 0
Bob 0 0
dave 0 0
Jerry 0 0
Bert 0 0
Ernie 0 0
Marcus 0 0
edit: this is the output I'm getting repeating many more times though
-858993460
-858993460
-858993460
-858993460
-858993460
-858993460
UserData is a struct
//begin create/find account function
userData createAccount(userData ud){
//local variables
int playerOption;
//creates object to open files
ifstream infile;
//creates object to open files
ofstream outfile;
do {
cout << "Do you have an existing account?" << endl;
cout << "" << endl;
cout << "Enter 1 for yes or 2 for no:" << endl;
cin >> playerOption;
}
while (playerOption >= 3 || playerOption <= 0);
if (playerOption == 1){
cout << "Enter user name:" << endl;
cin >> ud.name;
//opens file in read mode
infile.open("userData.dat");
//tests to make sure the file is open
if (!infile){
cout << "File open failure!";
}
//creates array of user data
userData userDataArray [SIZE];
//reads data from file into array until end of file
int i=0;
while(i<SIZE){
infile >> userDataArray[i].name;
infile >> userDataArray[i].wins;
infile >> userDataArray[i].losses;
i++;
}
///test output
int j=0;
while (j<SIZE){
cout << userDataArray[j].name << endl;
cout << userDataArray[j].wins << endl;
cout << userDataArray[j].losses << endl;
j++;
}
//end test output
//closes file
infile.close();
}
else if(playerOption == 2){
cout << "Enter user name:" << endl;
cin >> ud.name;
ud.wins = 0;
ud.losses = 0;
//opens file in write mode
outfile.open("userData.dat",ios::app);
//tests to make sure the file is open
if (!outfile){
cout << "File open failure!";
}
//writes userData struct to file
outfile << ud.name << " " << ud.wins << " " << ud.losses << endl;
//closes file
outfile.close();
}
return ud;
//end create/find account function
}

That is what a minimal example looks like, and it works perfectly:
#include <iostream>
#include <fstream>
using namespace std;
typedef struct { string name; int wins; int losses; } userData;
void createAccount(){
ifstream infile;
infile.open("userData.dat");
userData userDataArray[3];
for(int i = 0; i < 3; ++i){
infile >> userDataArray[i].name;
infile >> userDataArray[i].wins;
infile >> userDataArray[i].losses;
}
for(int i = 0; i < 3; ++i){
cout << userDataArray[i].name << endl;
cout << userDataArray[i].wins << endl;
cout << userDataArray[i].losses << endl;
}
}
int main(){
createAccount();
}
Output:
Rocky
0
0
Bob
0
0
dave
0
0
So you should simplify your code bit by bit, until it works. Or start from a simple code like mine and build your way up to achieve the functionality you need.
You initial question was "Why can't I succesfully read file data to a struct array", but apparently that is not the problem.
For a start, what is the value of SIZE ? If you say the output is very long, you might have set size to a value much higher than the number of serialized data in the file, and you are printing a lot of uninitialized data.

Related

String doesn't want to store a 2700 character word

I'm trying to make a program that prints all the numbers from 100-999. After that you get to choose how many numbers you want to find. Then you type the number's position and it will be outputed.
There is one problem. The string, named str, stops storing at the number 954.
Here's the code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
//Prints to myFile the numbers from 100 to 999 without a space in between. Like this: 100101102...999
ofstream myFile("numere.txt");
for(int i = 100; i <= 999; i++)
myFile << i;
//Makes the string str to store the line: 100101102103...999. But only stores until 954 (100101102..954)
ifstream myFileRead("numere.txt");
string str;
while(getline(myFileRead, str))
cout << str << endl;
//Ouputs the lenght that should be 2700 but is instead 2565
cout << endl;
cout << "String legth: " << str.size() << endl;
cout << endl;
int n, k;
cout << "Enter how many numbers do you want to find: ";
cin >> n;
for(int i = 1; i <= n; i++){
cout << "Enter number position(it starts from 0) : ";
cin >> k;
cout << "Here's the number on position " << k << ": " << str.at(k);
cout << endl;
}
system("pause>0");
}
Thanks for your attention. I’m looking forward to your reply.
C++ streams are buffered. When you use << to write to a file it is not immediately written to the file.
Try to close or flush the ofstream before you read from it:
myFile.close(); // or...
myFile.flush();
For more details I refer you to flush() and close().
PS: Actually it is rather rare that you need to close a fstream explicitly. You wouldn't need to do it when you used seperate functions for writing and reading:
void write_to_file() {
std::ofstream myFile("numere.txt");
//...
}
void read_from_file() {
std::istream myFile("numere.txt");
//...
}
Because the destructor of ofstream already closes the file.

visual studioc++ array size in struct is too long

I am currently doing an assignment for my beginner C++ course, the chapter is on structs. I am using visual studio so I am can't do anything fancy for dynamic array's (i.e. no vector's etc.).
The part of the homework I am having trouble with is reading a file with some spaces at the end of the file. Since I am using filename.eof() it is reading the blanks and recording that data. I tried doing cin.ignore(xxxxx, '\n'), however that did not work. The my current out put is the data I want but a row of garbage. How do I get rid of the garbage?
a) A function to read the data into the array. You can use the attached file named soccer-1.txt to test your code. It also goes without saying that your code must work with any input data file. Of course, for testing, use your file to avoid entering data while testing. The name of the data file must always be entered by the user (do not hard code a file name). Also, check to make sure that the given input data file exists. If the file does not exist, issue an error message to alert the user about the invalid file name. Make sure to ask the user again for the name of another file. However, terminate the program after the user has entered an incorrect file name for a total of 3 times. NOTE: the data file name can be input inside the function.
The text file looks like this:
"
Duckey E Donald forward 8 2 21
Goof B Goofy defense 12 0 82
Brave A Balto goalkeeper 0 0 5
Snow W White defense 1 2 3
Alice I Wonderful midfield 1 5 15
Samina S Akthar right_defense 1 2 7
Simba P Green left_back 7 3 28
**************WHITESPACE****************************
**************WHITESPACE****************************
Here is my code:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int subSize = 100;
//struct to store nameInfo
struct nameInfo
{
string fName;
char middleInitial;
string lName;
};
//struct to store playerInfo
struct playerInfo
{
nameInfo name;
string postion;
int goals;
int penalties;
int jersey;
};
int getData(playerInfo matrix[]);
void displayData(playerInfo matrix[], int arraySize);
int main()
{
playerInfo p;
playerInfo playerArray[subSize];
int arraySize;
int userSelection;
string searchTerm;
arraySize = getData(playerArray);
cout << arraySize << " records found." << endl << endl;
displayData(playerArray, arraySize); //call to display all data
cout << endl;
return 0;
}
//function to read the data into the array
int getData(playerInfo matrix[])
{
ifstream infile;
string fileName;
int i = 0; //counter to hold array row length
int k = 0; //counter for file input
int x = 0; //counter for user input
cout << "Enter the file name (e.g. soccer-1.txt): ";
getline(cin, fileName);
cout << endl;
infile.open(fileName.c_str());
//checks if file exists
//ask the user again for the name of another file
//loop returns -1 after 3 failed attempts to enter a file
while (!infile)
{
k++;
cout << "After attempt " << k
<< " input file not opened." << endl;
cout << "Attempt " << k + 1 << ", enter the file name (e.g. soccer.txt): ";
getline(cin, fileName);
cout << endl;
infile.open(fileName.c_str());
cout << endl;
if (k == 2) //terminate program at 2 because entered validation loop
{ //after first attempt
cout << "Terminating program.";
return -1;
}
}
while (!infile.eof())
{
infile >> matrix[i].name.fName >> matrix[i].name.middleInitial
>> matrix[i].name.lName >> matrix[i].postion
>> matrix[i].goals >> matrix[i].penalties
>> matrix[i].jersey;
i++; //holds size of array
}
infile.close();
return i;
}
void displayData(playerInfo matrix[], int arraySize)
{
for (int y = 0; y < arraySize; y++)
{
//display format:
//Duckey.(E)Donald:8 2 21 – forward
cout << matrix[y].name.fName
<< ".(" << matrix[y].name.middleInitial << ")"
<< matrix[y].name.lName << ":" << matrix[y].goals << " "
<< matrix[y].penalties << " " << matrix[y].jersey
<< " - " << matrix[y].postion << endl;
}
}
OK, this is where you can apply a change:
while (!infile.eof()) {
infile >> matrix[i].name.fName >> matrix[i].name.middleInitial >>
matrix[i].name.lName >> matrix[i].postion >> matrix[i].goals >>
matrix[i].penalties >> matrix[i].jersey;
i++; // holds size of array
}
Read to a string, or a set of strings, instead of straight to the container. That way you can check they're valid (i.e. not blank) before copying to the matrix container.

Reading in from a .txt file to a struct array that contains enum

Here is my code
enum Status {IN, OUT };
const int TITLE_SIZE = 50, ISBN_SIZE = 13, AUTHOR_SIZE = 25;
struct Info
{
char title[TITLE_SIZE];
char isbn[ISBN_SIZE];
char author[AUTHOR_SIZE];
Status inOrOut;
};
int main()
{
fstream dataFile;
string filename;
int numOfBooks = 0;
Info *test = 0;
int enumHolder = 0;
cout << "How many books does the file contain? ";
cin >> numOfBooks;
test = new Info[numOfBooks];
cout << "Enter a file (with path) for input and output: ";
cin >> filename;
dataFile.open(filename.c_str(), ios::in );
if (dataFile.fail())
{
cout << "Could not open file; closing program" << "\n";
return 0;
}
for (int i=0; i < (numOfBooks-1); i++)
{
dataFile >> test[i].title;
dataFile >> test[i].isbn;
dataFile >> test[i].author;
dataFile >> enumHolder;
test[i].inOrOut = static_cast<Status>(enumHolder);
}
for (int j=0; j < (numOfBooks-1); j++)
{
cout << test[j].title << " ";
cout << test[j].isbn << " ";
cout << test[j].author << " ";
cout << test[j].inOrOut << " ";
cout << "\n";
}
Here is the .txt file
The Book
012345678901
Guy Duder
1
THAT Article
210987654321
Mr. Dr. Professor
0
Here is the output
How many books does the file contain? 2
Enter a file (with path) for input and output: D:/Documents/input.txt
The Book 012345678901 0
Question
What does the dataFile stop reading in a the first test[i].author? Is using static_cast causing this?
In order to convert an enum to printable text and text to an enum, you need to use a lookup table or an associative array. You could use a switch statement, but that is not as easy to maintain.
See also: std::map.
Search Stackoverflow for "c++ lookup table".

get string array from text list c++

my text file was like
123456123456
Jason
uk
012456788
1000
456789456789
david
uk
012456788
1000
i'm trying to get the data from a text file and save it into arrays
however when i want to store the data from the text file into array it loop non-stop.
what should i do ?
the problem exiting in looping or the method i get the data from text file ?
code:
#include <iostream>
#include <fstream>
using namespace std;
typedef struct {
char acc_no[12];
char name[30];
char address[50];
char phone_no[12];
double balance;
} ACCOUNT;
//function prototype
void menu();
void read_data(ACCOUNT record[]);
int main() {
ACCOUNT record[31]; //Define array 'record' which have maximum size of 30
read_data(record);
}
//--------------------------------------------------------------------
void read_data(ACCOUNT record[]) {
ifstream openfile("list.txt"); //open text file
if (!openfile) {
cout << "Error opening input file\n";
return 0;
} else {
int loop = -1; //size of array
cout << "--------------Data From File--------------"<<endl;
while (!openfile.eof()) {
if (openfile.peek() == '\n')
openfile.ignore(256, '\n');
openfile.getline(record[++loop].acc_no, 12);
openfile.getline(record[loop].name, 30);
openfile.getline(record[loop].address, 50);
openfile.getline(record[loop].phone_no, 12);
openfile >> record[loop].balance;
}
openfile.close(); //close text file
for (int i = 0; i <= loop + 1; i++) {
cout << "Account " << endl;
cout << "Account No. : " << record[i].acc_no << endl;
cout << "Name : " << record[i].name << endl;
cout << "Address : " << record[i].address << endl;
cout << "Phone Number : " << record[i].phone_no << endl;
cout << "Balance : " << record[i].balance << endl;
}
}
}
UPDATE:
The OP didn't properly cite the correct format in his data file. This answer is only valid up until the last iteration.
Don't use .eof() - that's more applicable to when you want to open the file and read it by characters.
A better way would be to use the insertion operator >> as follows:
#define ARR_SIZE 31
ACCOUNT temp;
ACCOUNT record[ARR_SIZE];
int i=0;
while(i < ARR_SIZE) {
openfile >> temp.acc_no >> temp.name >> temp.address >> temp.phone_no >> temp.balance;
record[i] = temp;
i++;
}
Of course, even better is to use std::string to hold the values from the input file, in addition to using std::vectors instead of arrays.

Segmentation fault when accessing a structure

The program works all the way up until it checks for the name the user enters. When you enter the name you wish to search for in the array of structures that have been imported from a file full of customer info) it comes back segmentation fault core dumped. This puzzles me.
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
using namespace std;
struct AccountsDataBase{
char name[50];
string email;
long int phone;
string address;
};
#define MAX 80
AccountsDataBase * account = new AccountsDataBase[MAX];
void readIn(ifstream& file){
int i=0;
while(!file.eof()){
file >> account[i].name >> account[i].email >> account[i].phone >> account[i].address;
}
}
void getAccount(){
char userPick[50];
char streamName[50];
cout << " What account will we be using? " << endl;
cin.getline(streamName, 50);
for(int i=0; strcmp(account[i].name, streamName)!=0; i++){
if( strcmp(account[i].name, streamName)==0){
cout << "\n\n FOUND IT!! \n\n";
cout << account[i].name << "\n" << account[i].email << "\n" << account[i].phone << "\n" << account[i].address << endl;
}
}
}
int main(){
ifstream file;
file.open("2.dat"); //opens data account records text
readIn(file);
getAccount();
delete account;
return 0;
}
Your loop keeps reading everything into the initial element of the array:
while(!file.eof()){
file >> account[i].name >> account[i].email >> account[i].phone >> account[i].address;
}
because the value of i is never incremented. You can convert this to a for loop, like this:
for (count = 0 ; count < MAX && !file.eof() ; count++) {
file >> account[count].name >> account[count].email >> account[count].phone >> account[count].address;
}
Note that I changed i to count:
AccountsDataBase * account = new AccountsDataBase[MAX];
int count = 0;
This will help you solve another problem - determining when the array ends in the getAccount function. Currently, you assume that the record is always there, so the outer loop keeps going on. Now that you have count, you could change the loop like this:
for(int i=0; i < count && strcmp(account[i].name, streamName)!=0; i++){
if( strcmp(account[i].name, streamName)==0){
cout << "\n\n FOUND IT!! \n\n";
cout << account[i].name << "\n" << account[i].email << "\n" << account[i].phone << "\n" << account[i].address << endl;
break;
}
}
if (i == count) {
cout << "Not found." << endl;
}