write/read struct to file using functions , Visual C++ 2008 express - c++

I've made three files using Visual C++ 2008 express for a text based RPG game. Before I really dive into the whole thing I want to get the basics ironed out: new game, save game, continue game, quit game. So far I have the make a character section (in this case find a weapon) and quit game all ironed out. I'm stuck on how to pass the weapon stats from a struct to a save file. I appear to pass the members of the struct without issue and check the file to find "junk": Ì and -858993460 in place of my values.
How should I go about fixing my save_game and continue_game functions? I've done a lot of research trying to figure this out and nothing I've tried seems to help.
Here's the important pieces of the code:
struct player_character
{
char type;
int damage;
int stability;
};
void save_game(player_character& pc, ofstream &save);
void continue_game(player_character& pc, ifstream &get);
int main()
{
player_character pc;
ofstream save;
ifstream get;
//rest of main() goes here.
//pause screen
system("pause");
return 0;
}
//rest of functions go here.
void save_game(player_character &pc, ofstream &save_data)
{
save_data.open ("save.dat", ios::binary);
if (save_data.is_open())
{
save_data << "pc.type = " << pc.type << endl;
save_data << "pc.damage = " << pc.damage << endl;
save_data << "pc.stability = " << pc.stability << endl;
//doesn't work
//save_data.write(reinterpret_cast<char*>(&pc), sizeof(pc));
save_data.close();
}
else
{
cout << " Error. Unable to open file.";
}
}
void continue_game(player_character &pc, ifstream &get_data)
{
get_data.open("save.dat");
if (get_data.is_open())
{
//doesn't work
//get.read(reinterpret_cast<char*>(&pc), sizeof(pc));
get.close();
}
else
{
cout << " Error. Unable to open file.";
}
}
Thanks for the reponse. I'm trying the following revisions. The continue_game function appears to work. I recieve no errors (yet). When I select save after making a character I recieve the following error: Unhandled exception at 0x69197a28 in Undone.exe: 0xC0000005: Access violation reading location 0xffffffcc.
Google shows it as some sort of Windows issue.
Why is my function causing this error?
void save_game(ofstream &save, player_character const &pc)
{
save.open ("save.dat");
if (save.is_open())
{
save.write(reinterpret_cast<char const *>(pc.type), sizeof pc.type);
save.write(reinterpret_cast<char const *>(pc.damage), sizeof pc.damage);
save.write(reinterpret_cast<char const *>(pc.stability), sizeof pc.stability);
save.close();
}
else
{
cout << " Error. Unable to open file.";
}
}
int continue_game(ifstream &get)
{
if (!get.read(reinterpret_cast<char *>(&pc.type), sizeof pc.type)) { /* error */ }
if (!get.read(reinterpret_cast<char *>(&pc.damage), sizeof pc.damage)) { /* error */ }
if (!get.read(reinterpret_cast<char *>(&pc.stability), sizeof pc.stability)) { /* error */ }
return pc.type;
return pc.damage;
return pc.stability;
}
I've changed the save_game and continue_game code and included it here. I also collected the debugger and autos output (small version of autos, not all seven pages). Apparently my values are not being evaluated in save_game so continue_game has nothing to work with and doesn't cause errors.
Here's the code and debugger/autos printouts:
int save_game(ofstream &save, player_character& pc)
{
save.open ("save.dat", ios::binary);
if (save.is_open())
{
//the error hits here:
save.write(reinterpret_cast<char const *>(pc.type), sizeof pc.type);
save.write(reinterpret_cast<char const *>(pc.damage), sizeof pc.damage);
save.write(reinterpret_cast<char const *>(pc.stability), sizeof pc.stability);
save.close();
}
else
{
cout << " Error. Unable to open file.";
}
return pc.type;
return pc.damage;
return pc.stability;
}
int continue_game(ifstream &get, player_character& pc)
{
get.open ("save.dat", ios::binary);
if (get.is_open())
{
if (!get.read(reinterpret_cast<char *>(&pc.type), sizeof pc.type)) { /* error */ }
if (!get.read(reinterpret_cast<char *>(&pc.damage), sizeof pc.damage)) { /* error */ }
if (!get.read(reinterpret_cast<char *>(&pc.stability), sizeof pc.stability)) { /* error */ }
get.close();
}
else
{
cout << " Error. Unable to open file.";
}
return pc.type;
return pc.damage;
return pc.stability;
}
Debugger Output Window:
First-chance exception at 0x644e7a28 in Undone.exe: 0xC0000005: Access violation reading location 0xffffffcc.
Unhandled exception at 0x644e7a28 in Undone.exe: 0xC0000005: Access violation reading location 0xffffffcc.
Autos:
- pc {type='Ì' damage=-858993460 stability=-858993460 } player_character &
type -52 'Ì' char
damage -858993460 int
stability -858993460 int
pc.type -52 'Ì' char
- save {_Filebuffer={...} } std::basic_ofstream > &
+ std::basic_ostream > {...} std::basic_ostream >
+ _Filebuffer {_Pcvt=0x00000000 _Mychar='Ì' _Wrotesome=false ...} std::basic_filebuf >
Well I'vve managed to make some progress. I discovered I needed to place arguments into my main_menu function (mind you I'm not taking about the main() function, but one I made) so that they would be passed on to my save_game function. I was also able to stop the access error by adding an & into my write function.
So this:
save.write(reinterpret_cast<char const *>(&pc.type), sizeof pc.type);
save.write(reinterpret_cast<char const *>(&pc.damage), sizeof pc.damage);
save.write(reinterpret_cast<char const *>(&pc.stability), sizeof pc.stability);
instead of:
save.write(reinterpret_cast<char const *>(pc.type), sizeof pc.type);
save.write(reinterpret_cast<char const *>(pc.damage), sizeof pc.damage);
save.write(reinterpret_cast<char const *>(pc.stability), sizeof pc.stability);
The savve_game code still doesn't work properly yet when it comes to putting data into a file but it does printout to the screen.

You have to read and write each primitive data type, one by one, and use unformatted I/O only. Example:
void serialize(std::ostream & o, Player const & p)
{
o.write(reinterpret_cast<char const *>(p.type), sizeof p.type);
o.write(reinterpret_cast<char const *>(p.damage), sizeof p.damage);
o.write(reinterpret_cast<char const *>(p.stability), sizeof p.stability);
}
Player deserialize(std::istream & i)
{
Player p;
char pt;
int pd, ps;
if (!i.read(reinterpret_cast<char *>(&pt), sizeof pt)) { /* error */ }
if (!i.read(reinterpret_cast<char *>(&pd), sizeof pd)) { /* error */ }
if (!i.read(reinterpret_cast<char *>(&ps), sizeof ps)) { /* error */ }
p.type = pt; p.damage = pd; p.stability = ps;
return p;
}

Follow-up to the previous answer and edited question.
Judging by your continue_game signature,
int continue_game(ifstream &get)
pc must be some form of global struct that holds the character you're trying to resume. If pc is allocated at run-time, then you are using it incorrectly.
When you do this:
return pc.type;
return pc.damage;
return pc.stability;
A function can only have one return-type; only pc.type would be returned. This is not the cause of the error, but rather a design flaw you should be aware of.
Your initial approach to continue_game, wherein you passed in the relevant struct as a parameter,
void continue_game(player_character &pc, ifstream &get_data)
was a much better idea. I believe that if you combine the two you will find yourself without the error.
If the error continues, please use a debugger and paste the line. In addition, I can provide a sample of the code I described if you wish me to.

It looks like I figured it out! Here's what I've come up with: struct in array...and it appears to work just fine.
void save_game(fstream& file, player_type& pc)
{
file.open("save.dat");
if (file.is_open())
for (int i = 0; i < 1; i++)
{
file << pc.w_name << endl;
file << pc.d_rate << endl;
file << pc.s_rate << endl;
file.close();
}
else
cout << " Error. Unable to open file.";
menu(pc);
}//end save function
void continue_game(fstream& file, player_type player[])
{
file.open("save.dat");
if (file.is_open())
for (int i = 0; i < 1; i++)
{
file >> player[i].w_name;
file >> player[i].d_rate;
file >> player[i].s_rate;
file.close();
}
else
cout << " Error. Unable to open file.";
for (int i = 0; i < 1; i++)
{
cout << "You are continuing the game with the following weapon: " << player[i].w_name << endl;
cout << "Which has a damage rating of " << player[i].d_rate << " and a stability rating of " << player[i].s_rate << endl;
}
cout << endl;
menu(pc);
}//end continue_game

Related

Segmentation fault: unable to fix the problem

I'm new to C++, and I'm trying to write a project that interacts through command line. Right now, whenever I run my main (which is the executable), I always receive a segmentation fault error when the main program finished.
Edit comment:
I'm told by tutor to use as little as C++ features such as vectors or strings ... I'm also very new to C++, so i'm trying to utilize as many basic C functions as I can.
I'm
My main function looks like this:
int main(int argc, char** argv) {
cout << "starting mvote..." << endl;
int run_flag = 1;
char* actionBuffer = (char*)malloc(100 * sizeof(char));
char* action = (char*)malloc(16 * sizeof(char));
char* readPtr;
char exit[4] = { 'e','x','i','t' };
//parse command line argumentand get the filename
char* filename = argv[2];
cout << filename;
FILE* fp;
char line[64];
//from here, I'm opening the file and read it by lines
fp = fopen(filename, "r");
if (fp == NULL) {
cout << "file not exists";
return -1;
}
while (fgets(line, 64, fp) != NULL) {
cout << line << "\n";
}
fclose(fp);
while (run_flag == 1) {
cout << "what do you want?\n " << endl;
cin.getline(actionBuffer, 1024);
if (strcmp(actionBuffer, exit) == 0) {
cout << "bye!";
run_flag = 0;
break;
}
//if not exit, Look for the space in the input
readPtr = strchr(actionBuffer, ' ');
int size = readPtr - actionBuffer;
//extract the operation
strncpy(action, actionBuffer, size);
for (int i = 0; i < size; i++) {
cout << "operation:" << action[i];
}
// depend on the operation specified before the first empty space
run_flag = 0;
}
free(actionBuffer);
free(action);
return 0;
}
Description:
I first try to open up a csv file which lies in the same folder as main, and I read the file line by line. Then, I just implement a simple command where you can type exit and quit the program.
I allocate two memory, actionBuffer and action, which are used to hold command
Problem: a segmentation fault [core dumped] always exists when I type exit and hit enter, and then the process finished.
Research: So I learned that segmentation fault is due to accessing a memory that does not belongs to me. But where in my program am I trying to access such a memory?
Any advice is appreciated! Thank you.
Just to give you an idea, this would be an example of C++ code
#include<iostream>
#include<fstream>
#include<string_view>
#include<string>
#include<sstream>
#include<exception>
int main(int argc, char** argv) {
std::cout << "starting mvote...\n";
//parse command line argumentand get the filename
std::string filename = argv[2]; // NO CHECKS!
std::cout << filename <<'\n';
//from here, I'm opening the file and read it by lines
{
std::ifstream ifs(filename);
if (!ifs) {
throw std::invalid_argument("file not exists");
}
std::string line;
while (std::getline(ifs, line)) {
std::cout << line << '\n';
}
}
bool run_flag = true;
while (run_flag) {
std::cout << "what do you want?\n";
std::string userInput;
std::getline(std::cin, userInput);
if (userInput == "exit") {
std::cout << "bye!\n";
return 0;
}
std::stringstream userInputSs(userInput);
std::string operation;
while(userInputSs >> operation){
std::cout << "operation: " << operation << '\n';
}
}
}

Memory access violation error c++

I'm trying to exchange messages using multiple covert channels.
So, basically, first i need to select the channel that i want to use for communication and then select the "destination_ip" of the user that i want to chat with and after that the
processMessage()
is called. Now, to move from one channel to another I have to close the existing connection and then open a new connection with the new channel that i want to use. My code below is modified to keep using the same channel after closing the connection and contain only the things that you need.
#include <channelmanager.hpp>
#include <thread>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <openssl/hmac.h>
struct CommunicationFixture {
CommunicationFixture() {
channelmanager.setErrorStream(&cout);
channelmanager.setOutputStream(&cout);
destination_ip = "";
channel_id = channelmanager.getChannelIDs()[0];
}
library::ChannelManager channelmanager;
vector<string> last_adapters;
string destination_ip;
string channel_id = "";
int processMessage(string message) {
if (message.compare("exit") == 0) {
channelmanager.closeConnection(destination_ip);
return 1;
}
vector<string> arguments;
boost::split(arguments, message, boost::is_any_of(" "), boost::token_compress_on);
if (arguments[0].compare("argument") == 0) {
if (arguments.size() < 2) {
cout << "Not enough arguments" << endl;
return 0;
}
string argument_list = arguments[1];
for (unsigned int i = 2; i < arguments.size(); i++) {
argument_list += " " + arguments[i];
}
channelmanager.setChannelArguments(destination_ip, argument_list);
cout << "Set channel argument to '" << argument_list << "'." << endl;
return 0;
}
if (message.compare("help") == 0) {
cout << "Help not available in chat mode. Close chat first with 'exit'" << endl;
return 0;
}
channelmanager.openConnection(destination_ip, channel_id);
channelmanager.sendMessage(destination_ip, message);
return 0;
}
int close(string destination){
cout << "closing.." << endl;
channelmanager.closeConnection(destination); //I believe i have the error because of this!
return 0;
}
};
BOOST_FIXTURE_TEST_SUITE(communication, CommunicationFixture)
BOOST_AUTO_TEST_CASE(basic_communication) {
selectAdapterId(0);
cout << "Test" << endl << endl;
printCommands();
cout << "Enter your command:" << endl;
string command;
int code = 0;
while (code != 2) {
std::getline(cin, command);
code = processCommand(command);
if (code == 1) {
// chat
cout << "chat started.." << endl;
int chatCode = 0;
while (chatCode != 1) {
std::getline(cin, message);
close(destination_ip);
chatCode = processMessage(message);
channelmanager.setErrorStream(&cout);
}
cout << "chat ended." << endl;
}
}
}
BOOST_AUTO_TEST_SUITE_END()
Note that, i think that the error happens due to the
function close()
because without it i don't get any errors. and the error doesn't happen immediately but after exchanging some messages. Here's the error:
unknown location(0): fatal error: in
"communication/basic_communication": memory access violation at
address: 0x00000024: no mapping at fault address
communicationTest.cpp(325): last checkpoint: "basic_communication"
test entry
Memory access violation happen when you are trying to access to an unitialized variable, in this case the channelmanager.
I can only see that you initialize channelmanager in the processMessage() method and you are closing the connection before initializing the channelmanager as it happen in:
close(destination_ip);
chatCode = processMessage(message);
Either you change the initialization or do not close it before the processMessage() method.
Memory access violation is also called a segmentation fault (or segfault), occurs when the program tries to access a memory location that doesn't exist, or is otherwise inaccessible. We call this trying to access an illegal memory location. That memory is either non-existent or we aren't aren't allowed to touch it.
If the first input from user is 'exit', which is going to call
if (message.compare("exit") == 0) {
channelmanager.closeConnection(destination_ip);
return 1;
}
In this case, destination_ip isn't initialised.

throw is causing code to crash instead of just exiting

Beginner programmer here, working in Visual Studio.
vector<string> fileParse(vector<string> & inputStrings, string & fileName) {
ifstream x;
x.open(fileName);
cout << "attempting to open file" << endl;
if (!x.is_open()) {
cout << "Bad input file name. Input was: " << fileName << endl;
throw lab0badInput;
}
else {
string temp;
while (x >> temp) {
inputStrings.push_back(temp);
}
x.close();
}
return inputStrings;
}
Calling throw causes my program to crash instead of throwing the correct value and exiting. Can somebody explain why?
Thanks!
use try and catch block instead :
try { /* */ } catch (const std::exception& e) { /* */ }

std::wcout will not print after certain amounts of characters

I've been beating my head against a wall with this one for a while. I'm only trying to make a simple application to read out the contents of a file. Here's some of the code:
errno_t error;
if ((error = fopen_s(&f, file, "r")) == 0) {
while (true) {
std::wcout << std::endl << "NEW RUN" << std::endl;
wchar_t content[4096];
if (fgetswc(content, 4096, f) == 4096) {
std::wcout << content;
std::wcout.flush();
}
else {
std::wcout << content;
std::wcout.flush();
break;
}
}
fclose(f);
std::wcout << "PLEASE PRINT THIS NOW";
system("pause");
return 0;
}
And the custom fgetswc function:
int fgetswc(wchar_t buffer[], int count, FILE * f) {
for (int i = 0; i < count; i = i + 1) {
wchar_t c = fgetwc(f);
if (c != WEOF) {
buffer[i] = c;
} else {
return i;
}
}
return count;
}
It reads the first 4096 bytes out of the file, but then subsequent std::wcout calls will not print out to the console I have. It reads the rest of the file and ends successfully, as I can see using breakpoints and the debugger. content gets filled up every iteration. I also attempted putting in debug statements, but even those don't get printed. Am I just doing something wrong? As far as I can tell there's no special characters in my file, it's just a log file.
std::wcout << content;
This is effectively calling std::wostream::operator<<(const wchar_t *). It doesn't know that content is not a ␀-terminated string. In fact, it can't possibly know that it has valid length 4096 in the first case and some amount less in the second case (you don't save the return value of fgetswc).

Fingerprint calls cause segfaults in c++

I'm trying to write a simple fingerprint scanning program in c++ using libfprint, however it intermittently segfaults when run. Valgrind says the error is in the call to fp_enroll_finger which is consistent with my debugging, however beyond that I have absolutely no idea what is causing this error. Some of the times the program is run its fine, but some times it seems to consistently segfault for a period of time whenever the program is run?
Heres the code:
#include <iostream>
extern "C"
{
#include <libfprint/fprint.h>
}
using namespace std;
fp_dev * fpdev;
fp_print_data ** fpdata;
bool createDevice();
int main(int argc, char **argv)
{
int r = fp_init();
if(r != 0)
{
return r;
}
while(createDevice())
{
cout << "Scan right index finger" << endl;
int enrollStatus = fp_enroll_finger(fpdev, fpdata);
if(enrollStatus != 1)
{
cout << "Bad scan" << endl;
fp_dev_close(fpdev);
}
else
{
cout << "Good scan" << endl;
fp_print_data_save(fpdata[0], RIGHT_INDEX);
break;
}
}
if(fpdev != NULL)
{
fp_dev_close(fpdev);
}
fp_exit();
return 0;
}
bool createDevice()
{
fp_dscv_dev ** listOfDiscoveredDevs;
fp_dscv_dev * discoveredDevice;
listOfDiscoveredDevs = fp_discover_devs();
discoveredDevice = listOfDiscoveredDevs[0];
if(discoveredDevice != NULL)
{
cout << "Device found" << endl;
fpdev = fp_dev_open(discoveredDevice);
}
else
{
cout << "No device found" << endl;
return false;
}
fp_dscv_devs_free(listOfDiscoveredDevs);
return true;
}
You need to define fpdev and fpdata as:
fp_dev * fpdev;
fp_print_data * fpdata;
And use them as:
fp_enroll_finger(&fpdev, &fpdata);
Also don't forget to free fpdata when you no longer need it with fp_print_data_free
fp_dev * fpdev;
fp_print_data ** fpdata;
Will create 2 uninitialised pointers pointing to random memory location and leading to segfault once fp_enroll_finger will attempt to acces that location.
Checking fp_enroll_finger return value can be useful as well.