How to correctly create a ofstream of a struct vector? (abort() is called) - c++

I'm currently building a game and in this part my goal is to update a previously created file of High Scores ("rank.txt")
To do so, I've created a couple of functions so they can read what's in the txt file and so it can update it. Though the reading is ok, while adding the update function it gives me an error and tells me abort() has been called.
void highScoresUpdate(vector<PlayerInfo> player)
{
// This function is responsible for updating the High Scores Table present in the RANK.TXT file
vector<HighScoresStruct> highScores_temp;
HighScoresStruct temp;
ofstream out_file_3("rank.txt");
highScores_temp = readHighScores("rank.txt");
for (int k = 0; k < player.size(); k++)
{
player[k].name = temp.name;
player[k].score = temp.score;
player[k].time = temp.time;
highScores_temp.push_back(temp);
}
sort(highScores_temp.begin(), highScores_temp.end(), compareByScore);
for (int i = 0; i < highScores_temp.size(); i++)
{
out_file_3 << highScores_temp[i].name << endl << highScores_temp[i].score << endl << highScores_temp[i].time << endl;
}
out_file_3.close();
}
For background information, so i don't spam this thread with code all you need to know is that readHighScores is the function responsible for extracting information from the txt file and placing it on a vector .
The structs and comparebyScore funtion are listed below.
bool compareByScore(const HighScoresStruct &a, const HighScoresStruct &b)
{
if (a.score < b.score)
return true;
else if (a.score == b.score)
{
if (a.time > b.time)
return true;
else
return false;
}
else
return false;
}
struct PlayerInfo
{
string name;
unsigned int score;
vector<char> hand;
bool inGame;
unsigned int time;
};
struct HighScoresStruct
{
string name;
unsigned int score;
unsigned int time;
};
So... Can anyone help me?

Related

Retrive data using pointers to objects in c++

This a menu based program to create a database of people and for performing operations on their name. After compilation, I am able to add a person successfully using the add function of Person class but when I retrieve the list of the added people using list function it shows garbage values instead of showing the entered names. It's the question no. 4(lab 4) in the below give doc.
https://drive.google.com/open?id=18cR9bgPlqM6q-kXBIcxg5Hpj04bkZMnW&authuser=0
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
class Person
{
const char *name;
public:
Person(const char* n)
{
name=n;
}
bool search(const char* substr)
{
const char *str=name;
while(*str!='\0')
{ int count=0;
if(*str==*substr)
{ const char *s=substr;
const char *p=str;
while(*s!='\0')
{
if(*p==*s)
{
count++;
p++;
s++;
}
else
break;
}
}
if(count==strlen(substr))
{
cout<<name<<endl;
return true;
}
str++;
}
return false;
}
void print()
{
cout<<name<<endl;
}
~Person()
{
cout << ":)";
}
friend class People;
};
class People
{
Person** array;
int length;
void prompt()
{
cout << "\n'A'-Add a person\n'L'-List all persons\n'S'-Search\n'Q'-Quit\n";
}
public:
People()
{
array = NULL;
length = 0;
}
void add()
{
string m;
cout << "Enter a Name:\n";
cin >> m;
Person s(m.c_str());
if (array == NULL)
array = (Person**)malloc(sizeof(Person*));
else
{
array=(Person**)realloc(array, length*sizeof(Person*));
}
array[length] =new Person(s.name);
array[length]->print();
++length;
}
void list()
{
cout << "\nThe names of the person in the list are:\n";
for (int i = 0; i <length; i++)
{
array[i]->print();
}
}
void search()
{
string a;
int flag = 0;
cout << "\nEnter a string to be found in the names present in the list:\n";
cin >> a;
cout << "\n The names with entered substring are:\n";
for (int i = 0; i <length; i++)
{
bool state=array[i]->search(a.c_str());
if (state)
flag = -1;
}
if (flag == 0)
cout << "\nNone of the names contains the entered substring!!!\n";
}
void menu()
{
char c = 'Y';
while (c != 'Q')
{
cout << "Choose an option(character):\n";
prompt();
cin>>c;
switch (c)
{
case 'A':add();
cout << "Name entered sucessfully!!!\n";
break;
case 'L':list();
break;
case 'S':search();
break;
case 'Q':c = 'Q';
break;
}
}
}
};
int main()
{
People All;
All.menu();
return 0;
}
I am not able to find any mistake in my implementation of add function. What could be the possible reason for malfunctioning of list function?
tl;dr
You store a pointer to the internal memory of string (m). That string gets destroyed at the end of add() so you have pointer to unallocated memory, which causes undefined behaviour.
possible solutions
Best would be to store a std::string instead of a const char * inside Person.
walkthrough
If you want a more detailed analyses: You store a pointer to a string that goes out of scope.
void add()
{
string m; // string is initialized and allocates memory for its content
cout << "Enter a Name:\n";
cin >> m; // read content
Person s(m.c_str()); // m.c_str() retrieves a pointer to the memory allocated by m
//this pointer is stored inside s
if (array == NULL)
{
array = (Person**)malloc(sizeof(Person*));
}
else
{
array=(Person**)realloc(array, length*sizeof(Person*));
}
array[length] = new Person(s.name); // s.name still points to the memory allocated by m
array[length]->print();
++length;
} //At the end of the function m gets destroyed and deallocates its memory
So after the function exits you still have stored the pointer to m.c_str() inside a persons name. This pointer now points to unallocated memory. This memory now may (or may not) be overwritten at any time. You get undefined behaviour and print garbage.

Student Results Management System in C++, expression must have pointer to object type

I was wondering if someone could help me fix this. I am looking to grab the lowest score in a student management results analysis project in C++. I am getting a "expression must have pointer to object type" error. I have no idea how to fix this
struct candidate
{
int candidates;
char forename[20], surname[20];
int area[5];
double avg;
public:
void getdata();
string calculateGrade();
void showdata() const;
};
//Prints out the lowest mark
void lowestmark(double avg[])
{
candidate st;
ifstream inFile;
inFile.open("student.dat", ios::binary);
if (!inFile)
{
cout << "File could not be open! Press any Key...";
cin.ignore();
cin.get();
return;
}
while (inFile.read(reinterpret_cast<char *> (&st), sizeof(candidate)))
{
double smallest = st.avg;
// Loop to determine lowest score
for (int i = 0; i < sizeof(candidate); i++)
{
if (smallest > st.avg[i])
{
smallest = st.avg[i];
smallest = i;
}
}
}
}
You don't need an array to find the smallest average score:
double smallest_average = 100000.0;
candidate st;
while (infile.read((unsigned char *) &st, sizeof(st)))
{
const double average_read = st.avg;
if (average_read < smallest_average)
{
smallest_average = average_read;
}
}
The search does not require all items stored into memory; only the current item read from the file.

How can I trace back the error

I was assigned to create an array check (to see if the array is increasing, decreasing, or neither [then exiting if neither]) and a recursive binary search for one of my assignments. I was able to do these things after some help from my peers, but I need help in finding what seems to be causing the error
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Aborted
when running the code. I Googled this error and this error seems to be vague or I just am not understanding. It compiles without errors, but I need help in what finding what I did wrong. It is able to run without the binarySearchR function and its associating code, as the array check on its own was the previous assignment. Below is the code, and I thank you so much in advance!
#include <iosteam>
#include <string>
#include <cstdlib>
#include <fstream>
using namespace std;
int checkArraySort (string *fileLines, int numberOfLines);
int binarySearchR (string *fileLines, string searchKey, int iMin, int iMax);
int main ()
{
int numberOfLines = 0;
string searchKey = 0;
cout << "Input search key: ";
cin >> searchKey;
ifstream fileIn;
fileIn.open("words_in.txt");
string line;
if (fileIn.eof()) /* Checks file to see if it is blank before proceeding */
{
exit (EXIT_SUCCESS);
}
else
{
while(!(fileIn.eof()))
{
fileIn >> line;
numberOfLines++;
}
fileIn.close(); /* closes fileIn, need to reopen to reset the line location */
fileIn.open("words_in.txt");
string *fileInLines;
fileInLines = new string[numberOfLines];
for (int i = 0; i < numberOfLines; i++)
{
fileIn >> line;
fileInLines[i] = line;
}
fileIn.close(); /* closes fileIn */
int resultingCheck = checkArraySort(fileInLines, numberOfLines);
if (resultingCheck == -1)
{
cout << "The array is sorted in descending order." << endl;
}
else if (resultingCheck == 1)
{
cout << "The array is sorted in ascending order." << endl;
}
else
{
cerr << "ERROR: Array not sorted!" << endl;
exit (EXIT_FAILURE);
}
int searchResult = binarySearchR (fileInLines, searchKey, 0, numberOfLines);
if (!searchResult == -1)
{
cout << "Key found at index " << searchResult << "." << endl;
}
else
{
cout << "Key not found at any index." << endl;
}
exit (EXIT_SUCCESS);
}
}
int checkArraySort (string *fileLines, int numberOfLines)
{
int result = 1; /* Ascending by default */
for (int i = 1; i < numberOfLines; i++) /* Checks if decending */
{
if (fileLines[i] < fileLines[i-1])
{
result = -1;
}
}
if (result == -1) /* Makes sure it is descending (or if it is neither) */
{
for (int i = 1; i < numberOfLines; i++)
{
if (fileLines[i] > fileLines[i-1])
{
result = 0;
}
}
}
return result;
}
int binarySearchR (string *fileLines, string searchKey, int iMin, int iMax)
{
// so, its gotta look at the center value and each times, it discards half of the remaining list.
if (iMax < iMin) /* If the minimum is greater than the maximum */
{
return -1;
}
else
{
int iMid = (iMin + iMax) / 2;
if (fileLines[iMid] > searchKey) /* If the key is in the lower subset */
{
return binarySearchR (fileLines, searchKey, iMin, iMid - 1);
}
else if (fileLines[iMid] < searchKey) /*If the key is in the upper subset */
{
return binarySearchR (fileLines, searchKey, iMin, iMid + 1);
}
else /*If anything else besides the two */
{
return iMid;
}
}
}
The easy way: add a bunch of cout s to see where you program goes and what the values are.
Pros
Easy to do
Cons
Requires a recompile each time you want to add more info
The hard way: Learn to use a debugger
Pros
Can inspect "on the fly"
Don't need to rebuild
Can use what you learn in every other C++ program
Cons
Requires a bit of research to learn how to do it.

Create structs with names generated at runtime and refer to them within program

I have a set of datafiles stored within a directory.
eg.
./FT/Fourier_1
./FT/Fourier_2
./FT/Fourier_3
...
My code initially generates a list of the paths to these files.
std::string fileStringSearch="Fourier";
std::stringstream resultFileName;
std::vector<std::string> fileList;
int numLines=0;
DIR *parentDirPointer;
struct dirent *dp;
if ((parentDirPointer = opendir("FT")) == NULL)
{
std::cout << "Unable to open the parent (FT) directory" << std::endl;
return(3);
}
while ((dp = readdir(parentDirPointer)) != NULL)
{
std::string testFileName = dp->d_name;
if (testFileName.find(fileStringSearch) != std::string::npos)
{
resultFileName << "FT/" << dp->d_name;
std::string blahblah=resultFileName.str();
fileList.push_back(blahblah);
numLines++;
resultFileName.str(std::string());
resultFileName.clear();
}
};
sort(fileList.begin(),fileList.end());
for (unsigned n=0; n<fileList.size(); ++n)
{
resultFileName << fileList.at(n) << std::endl;
}
FTFilePaths = resultFileName.str();
I then want to read data from each file and store it in some format which I can later read, use in functions, etc.
My current thought is a struct - I have:
struct Wavenum_struct {
std::string name;
double timestep;
double indexToK_Multiplier;
std::vector<double> Amp_k;
std::vector<double> dFTdt_prev_to_this;
}
and at a later point in my program I read these files like :
for (int lineCounter=0; lineCounter < numLines; lineCounter++)
{
getline(readPath, FilePathLine);
c = FilePathLine.c_str();
readFile.open(c);
extern Wavenum_struct c;
c.name = FilePathLine;
//print_name(c);
while(getline (readFile, lineToRead))
{
readFile >> value;
c.Amp_k.push_back(value);
}
//print_amps(c);
}
The commented out print_amps(c); will work just fine with a function something like:
void print_amps(struct Wavenum_struct t)
{
for(int i=0; i<t.Amp_k.size(); i++)
{
std::cout << i << ": " << t.Amp_k[i] << std::endl;
}
}
but this obviously prints the amplitudes of every struct, and only once. If I want to refer to specific structs later in the program, and print them selectively, (or not print them, but use them for some function) eg
void dFTdt(struct Wavenum_struct t_i, struct Wavenum_struct t_i1)
{
int numWavenums = t_i.Amp_k.size();
double dt = t_i1.timestep - t_i.timestep;
double dFTdt[numWavenums];
for (int k=0; k<numWavenums; k++)
{
dFTdt[k] = (t_i1.Amp_k[k] - t_i.Amp_k[k])/dt;
}
t_i1.dFTdt_prev_to_this.assign(dFTdt, dFTdt+numWavenums);
}
then I can't seem to get anywhere, since c returns to being recognised as a const * char outside of the for loop, and anything I've tried like:
print_amps(reinterpret_cast<Wavenum_struct*>("FT/Fourier_1"));
refuses to compile.
I assume that what I need might involve pointers to functions and print_name() as a function of the struct, but this doesn't seem likely to help me with my void dFTdt() function, and I still don't know how to refer to a given struct once c no longer gives the name of that struct.
Is this in any way possible?
In this function (which really should have a name):
for (int lineCounter=0; lineCounter < numLines; lineCounter++)
{
getline(readPath, FilePathLine);
c = FilePathLine.c_str();
readFile.open(c);
extern Wavenum_struct c;
c.name = FilePathLine;
//print_name(c);
while(getline (readFile, lineToRead))
{
readFile >> value;
c.Amp_k.push_back(value);
}
//print_amps(c);
}
apart from the fact that you appear to be reusing the variable name "c" (which is unseemly), your Wavenum_struct c gets overwritten with each iteration through the loop, so even if you have this "extern" set up correctly, the most you will retain is the last one. You have to save these Wavenums somewhere, so why not use a vector?
std::vector<Wavenum_struct> wavenums;
for (int lineCounter=0; lineCounter < numLines; lineCounter++)
{
...
//print_amps(c);
wavenums.push_back(c);
}

Call to function is ambiguous in C++. Candidate functions are the Prototype and the function itself

I am working through Stanford CS106B C++ assignments and I have a 'semantic issue' with an assignment.
It seems as if the compiler cannot deduce whether the call is to a function or to the prototype of the function. I don't understand why a call would ever be made to the prototype. How can I make it so that the call is made to the function rather than the prototype? The error message I get it "Call to 'humansTurn' is ambiguous".
The error messages relate to the calls of the humansTurn(Lexicon,Lexicon) function, within the humansTurn(Lexicon,Lexicon) function, at the bottom of the page. The prototype for this function is above the main function.
Any help would be greatly appreciated.
Kind regards,
Mehul
/*
* File: Boggle.cpp
* ----------------
*/
#include <iostream>
#include "gboggle.h"
#include "graphics.h"
#include "grid.h"
#include "vector.h"
#include "lexicon.h"
#include "random.h"
#include "simpio.h"
using namespace std;
/* Constants */
const int BOGGLE_WINDOW_WIDTH = 650;
const int BOGGLE_WINDOW_HEIGHT = 350;
const string STANDARD_CUBES[16] = {
"AAEEGN", "ABBJOO", "ACHOPS", "AFFKPS",
"AOOTTW", "CIMOTU", "DEILRX", "DELRVY",
"DISTTY", "EEGHNW", "EEINSU", "EHRTVW",
"EIOSST", "ELRTTY", "HIMNQU", "HLNNRZ"
};
const string BIG_BOGGLE_CUBES[25] = {
"AAAFRS", "AAEEEE", "AAFIRS", "ADENNN", "AEEEEM",
"AEEGMU", "AEGMNN", "AFIRSY", "BJKQXZ", "CCNSTW",
"CEIILT", "CEILPT", "CEIPST", "DDLNOR", "DDHNOT",
"DHHLOR", "DHLNOR", "EIIITT", "EMOTTT", "ENSSSU",
"FIPRSY", "GORRVW", "HIPRRY", "NOOTUW", "OOOTTU"
};
/* Function prototypes */
void welcome();
void giveInstructions();
// Create random board
static Grid <char> randomBoard();
// Create custom board
static Grid<char> customBoard();
static void drawAndFillBoard(Grid<char>);
static void humansTurn(Lexicon,Lexicon);
int main() {
initGraphics(BOGGLE_WINDOW_WIDTH, BOGGLE_WINDOW_HEIGHT);
welcome();
giveInstructions();
string custom = getLine("Type y to create custom board:" );
Grid<char> gridData;
if (custom=="y"){
gridData = customBoard();
} else {
gridData = randomBoard();
}
drawAndFillBoard(gridData);
Lexicon english("EnglishWords.dat");
// Lexicon holds words previously encountered
Lexicon previousWords;
humansTurn(english, previousWords);
return 0;
}
/*
* Function: welcome
* Usage: welcome();
* -----------------
* Print out a cheery welcome message.
*/
void welcome() {
cout << "Welcome! You're about to play an intense game " << endl;
}
/*
* Function: giveInstructions
* Usage: giveInstructions();
* --------------------------
* Print out the instructions for the user.
*/
void giveInstructions() {
cout << endl;
cout << "The boggle board is a grid onto which I ";
cout << "or triple your paltry score." << endl << endl;
cout << "Hit return when you're ready...";
getLine();
}
static Grid<char> randomBoard(){
Vector<string> standardCubes;
for(int i = 0; i<16;i++){
standardCubes.add(STANDARD_CUBES[i]);
}
// Shuffle cubes
for (int i = 0; i < standardCubes.size(); i++) {
int r = randomInteger(i, standardCubes.size()-1);
if (i!=r){
string stringToMove1 = standardCubes.get(i);
string stringToMove2 = standardCubes.get(r);
standardCubes.set(r, stringToMove1);
standardCubes.set(i, stringToMove2);
}
}
// Update grid with random side of cube
Grid<char> gridData(4, 4);
int counter = 0;
for (int columnNo = 0; columnNo <4; columnNo++){
for (int rowNo = 0; rowNo<4; rowNo++) {
string s = standardCubes.get(counter);
int r = randomInteger(0, 5);
gridData[columnNo][rowNo] = s[r];
counter++;
}
}
return gridData;
}
static Grid<char> customBoard(){
Grid<char> gridData(4,4);
string s = getLine("Please enter 16 characters to make up the custom board. Characters will fill the board left to right, top to bottom: ");
for (int i = 0; i < s.length(); i++) {
s[i] = toupper(s[i]);
}
if (s.length()<16){
cout << "String has to be 16 characters long, try again" << endl;
customBoard();
}
int i =0;
for (int columnNo = 0; columnNo <4; columnNo++){
for (int rowNo = 0; rowNo<4; rowNo++) {
gridData[columnNo][rowNo] = s[i];
i++;
}
}
return gridData;
}
static void drawAndFillBoard(Grid<char> gridData){
drawBoard(4, 4);
for (int columnNo = 0; columnNo <4; columnNo++){
for (int rowNo = 0; rowNo<4; rowNo++) {
labelCube(rowNo, columnNo, gridData[rowNo][columnNo]);
}
}
}
static void humansTurn(Lexicon englishWords, Lexicon &previousWords){
/*
Human’s turn (except for finding words on the board). Write the loop that allows the user to enter words. Reject words that have already been entered or that don’t meet the minimum word length or that aren’t in the lexicon. Use the gboggle functions to add words to the graphical display and keep score.
*/
string humanGuess = getLine("Please enter your guess: ");
for (int i = 0; i < humanGuess.length(); i++) {
humanGuess[i] = tolower(humanGuess[i]);
}
if (humanGuess.length()<4){
cout << "Min guess length is four characters" << endl;
humansTurn(englishWords, previousWords);
}
if (!englishWords.contains(humanGuess)) {
cout << "That word is not English, please try another word" << endl;
humansTurn(englishWords, previousWords);
}
if (previousWords.contains(humanGuess)){
cout << "That word has already been guessed, please try another word" << endl;
humansTurn(englishWords, previousWords);
}
// check if word can be made using data on board
}
Your function humansTurn definition has different signature with declaration
function declaration:
static void humansTurn(Lexicon,Lexicon);
Function definition:
static void humansTurn(Lexicon englishWords, Lexicon &previousWords)
^^
//Here