I am currently getting this error in my code: Unhandled exception at 0x0FF321E8 (msvcp110d.dll) in bankAccountp5.exe: 0xC0000005: Access violation writing location 0xCCCCCCF8. And I'm certain it's to do with an array of objects I have created.
Here is part of my code:
class bankAccount: public bankBranch
{
public:
bankAccount(int, int, int, string, int);
int setAccountNumber ()
{
bankAccountNumber = ++minAccountNumber;
return this->bankAccountNumber;
}
void setAccountBalance ()
{
for(i = 0; i < getNumOfBankAccounts(); i++)
{
cout << "Enter the balance for your bank Account: " << endl;
cin >> accounts[i]->bankAccountBalance;
if (bankAccountBalance > MAX_BALANCE || bankAccountBalance < MIN_BALANCE)
{
cout << "Incorrect bank balance, please try again!" << endl;
--i;
} else {
++i;
}
}
}
void menuSystem(int choice) {
}
void displayBankBranchDetails()
{
cout << "\n";
cout << "DETAILS OF YOUR BANK BRANCH" << endl;
cout << "BSB Number: " << this->getBsbNumber() << endl;
cout << "Address: " << this->getAddress() << endl;
cout << "Postal code: " << this->getPostCode() << endl;
}
void setBankAccountDetails() {
}
int getNumOfBankAccounts() {
return this->numOfBankAccounts;
}
void createBankAccounts()
{
valid = false;
while (valid == false) {
cout << "How many Bank Accounts would you like to create under the Bank Branch BSB: " << getBsbNumber() << endl;
cin >> numOfBankAccounts;
if ( numOfBankAccounts <= MAX_NUMBER_ACCOUNTS)
{
valid = true;
} else {
valid = false;
}
}
}
private:
//bankAccount Data
int bankAccountNumber;
int numOfBankAccounts;
int bankAccountBalance;
int interestRate;
//constants
const static int MAX_NUMBER_ACCOUNTS = 10;
const static int MAX_BALANCE = 100000;
const static int MIN_BALANCE = 0;
//objects
bankBranch homeBranch;
bankAccount* accounts[MAX_NUM_ACCOUNTS];
//misc
int minAccountNumber;
int i;
bool valid;
};
The error occurs when I get to void setAccountBalance(), and I call the array of objects accounts, could anyone help me out with this? Cheers.
You have declared an array of pointers, you have to assign memory to it dynamically, bankAccount* accounts[MAX_NUM_ACCOUNTS];
moreover you don't need to write the else part in setAccountBalance()
This
bankAccount* accounts[MAX_NUM_ACCOUNTS];
creates an array of pointers. You need to take the next step of actually allocating memory for each account. Something like
accounts[some-index] = new bankAccount();
accounts = new bankAccount[MAX_NUM_ACCOUNTS]; needs to be done in one of your functions. You have declared a dynamic array, but still need to initialize it.
EDIT: You should really consider using stl structure vector. This will allow you to just push new accounts into your array and a variety of other things. Using pointers and dynamically allocated arrays need you to manage your memory and other such unnecessary pains.
Check this out: http://www.cplusplus.com/reference/vector/vector/
Add using std::vector after your inclusions. This way you don't need to keep typing std::vector, you can just say vector.
Then, vector<bankAccount> accounts will declare a vector called accounts. When adding new accounts, you can just call accounts.push_back(_______). You can access elements with [] and you also have accounts.size().
As #scottwilson said. Instead use a std::vector<bankAccount> that contain statically allocated bankAccounts.
Else, you might have to allocate memory for each bankAccount pointer, either statically or as you might require, dynamically.
You also need a createBankAccount() function that will allocate this for you whenever you want another bankAccount object:
like so:
public:
void createBankAccount() {
accounts[getNumberOfBankAccounts()] = new bankAccount();
numOfBankAccounts++;
}
Call this function each time you need a new bank account.
Related
I have a class that has to store the weight of the animal and it's type.
Depending on what the user wants, there can be as many instances of that class created at runtime.
My problem is with not being able to properly declare a dynamic array that can resize itself once the entire array has been filled with objects.
class FarmAnimal
{
private:
short int type;
int weight;
double WaterConsumed;
public:
static int NumberOfSheep;
static int NumberOfHorse;
static int NumberOfCow ;
static double TotalWaterUsed;
FarmAnimal(int type, int weight)
{
this->type = type;
this->weight = weight;
}
int CalculateWaterConsumption(void);
void ReturnFarmInfo(int& NumberOfSheep, int& NumberOfHorse, int& NumberOfCow, int& TotalWaterUsed)
};
int main()
{
...
short int k;
...
do
{
...
FarmAnimal animal[k](TypeOfAnimal, weight);
k++;
cout << "Would you like to add another animal to your farm?\n Press\"0\" to exit and anything else to continue" << endl;
cin >> ExitButton;
} while (ExitButton != 0)
and the end of the program
animal[0].ReturnFarmInfo(NumberOfSheep, NumberOfHorse, NumberOfCow, TotalWaterUsed)
cout << " Your farm is made up of :" << NumberOfSheep << " sheeps " << NumberOfHorse" horses " << NumberOfCow << " cows " << endl;
cout << "The total water consumption on your farm per day is: " << TotalWaterUsed << endl;
}
Array cannot change size in C++. You need to use a dynamic container such as std::vector. A documentation of the vector class can be found here.
std::vector<FarmAnimal> animals;
bool done = false;
while (!done)
{
animals.push_back(FarmAnimal(TypeOfAnimal, weight));
cout << "Would you like to add another animal to your farm?\n Press\"0\" to exit and anything else to continue" << endl;
cin >> ExitButton;
done = (ExitButton != 0);
}
Use the std::vector from the standard library and the method push_back() to add new elements
http://www.cplusplus.com/reference/vector/vector/
As mentioned in the comments by Some programmer dude and Ron, variable-length arrays are not supported in C++ by default. The std::vector class is a useful tool should you require them.
Some basic info about vectors:
http://www.cplusplus.com/reference/vector/vector/
I am writing a program that takes some contact information from user and grows the array dynamically when it gets full. But when I am trying to run the program I get Write access violation popping up a line from "iosfwd standard header". I don't know where I went wrong. Please do help.
My code looks like this:
# include "pch.h"
# include <iostream>
# include <string>
using namespace std;
struct Contact {
string name;
string number;
string address;
string exit;
};
void userPrompt(Contact &contact) {
cout << "Name: ";
getline(cin, contact.name);
cout << "Phone number: ";
getline(cin, contact.number);
cout << "Address: ";
getline(cin, contact.address);
cout << "Exit? (y/n): ";
getline(cin, contact.exit);
}
void printContact(Contact &contact) {
cout << "Name: " << contact.name << endl;
cout << "Phone number: " << contact.number << endl;
cout << "Address: " << contact.address << "\n" << endl;
}
void growArray(int ¤tLength, Contact *contacts) {
int multiplyer = 2;
Contact *new_array = new Contact[currentLength * multiplyer];
for (int i = 0; i < currentLength; i++) {
new_array[i] = contacts[i];
}
delete[] contacts;
contacts = new_array;
currentLength *= multiplyer;
}
void showAllContacts(Contact *contacts, int length) {
for (int i = 0; i < length; i++) {
if (contacts[i].name.length() != 0) {
printContact(contacts[i]);
}
}
}
int main() {
// Prompt the user to fill in the address book.
// If the array gets full, make it bigger.
Contact *contacts = new Contact[1];
int currentLength = 1;
int i = 0;
while (true) {
userPrompt(contacts[i]);
if (contacts[i].exit == "y" or contacts[i].exit == "Y") {
break;
}
i++;
if (i == currentLength) {
growArray(currentLength, contacts);
}
}
// Show the address book
showAllContacts(contacts, currentLength);
}
But when I am running the code it throws exception like this:
enter image description here
"Write Access Violation"
I think the bug is in the growArray function. But I can't fugure out where did I screw up. Please do help.
In
growArray(currentLength, contacts);
a copy of the pointer contacts is modified inside the function; but outside, the pointer's value stays the same. After growArray returns, contacts points to deleted memory, hence UB, hence the crash.
==> Full program demonstration of the issue <==
There are basically two solutions: the bad one and the good one. The bad one is to change the signature of growArray to take a reference to the pointer:
void growArray(int ¤tLength, Contact *&contacts)
The good one is to stop this manually allocated memory non-sense and use a std::vector<Contact>!
Before my program can free up memory and end it crashes. Crashes seem to happen on transition from the function UserDataCollection and back to main. This is only my second program using pointers so I'm still quite the newbie considering the whole point of c++ is to use pointers.
Here is the aforementioned code:
#include <iostream>
//Prototypes
void UserDataCollection(int * &movieData_ptr, int &numSurveyed); // Movie Statistics
void DisplayOutput(int *movieData_ptr, int numSurveyed); //Mean, Median, Mode (Display To Console)
//Global Constants
int main()
{
//Variables
int numSurveyed = 0;
//Pointers
int * movieData_ptr = nullptr;
movieData_ptr = new int[numSurveyed];
//"Program Start"
std::cout << "Program start...\n\n";
UserDataCollection(movieData_ptr, numSurveyed);
DisplayOutput(movieData_ptr, numSurveyed);
//Release Memory
delete[] movieData_ptr;
std::cout << "Memory Cleared.";
return 0;
}
void UserDataCollection(int * &movieData_ptr, int &numSurveyed)
{
//Get Number of Students Surveyed
std::cout << "How many students were surveyed: ";
std::cin >> numSurveyed;
//Student Data Input Loop
for (int i = 0; i < numSurveyed; i++)
{
//Get Student Data
std::cout << "Enter How many movies student " << i + 1 << " has seen in ONE month: ";
std::cin >> *(movieData_ptr + i);
//Validation Check
while (*(movieData_ptr + i) >= 337)
{
std::cout << "\nImpossible value!" << std::endl
<< "Hours in a month: 730. Average movie length: 130 minutes."
<< "Total Possible movies: 337";
std::cout << "\n\nEnter How many movies student " << i + 1 << " has seen in ONE month: ";
std::cin >> *(movieData_ptr + i);
} //end while (Validation Check)
} // end for (Data Input)
}
void DisplayOutput(int *movieData_ptr, int numSurveyed)
{
//Display loop for pointer array
for (int i = 0; i < numSurveyed; i++)
{
std::cout << *(movieData_ptr + i) << " ";
}
//End Message
std::cout << "\n\nProgram end.";
}
You never allocated any memory.
int numSurveyed = 0;
//Pointers
int * movieData_ptr = nullptr;
movieData_ptr = new int[numSurveyed];
This is the equivalent of
int *movieData_ptr = new int[0];
You are allocating size of 0 ints. This is undefined behaviour. You can't do anything useful with that pointer without a segmentation fault. You need to either pre-allocate a certain amount, and make sure you don't overflow, or dynamically allocate every time you plan to add data.
Since this is C++, it's probably better not to use raw pointers, but use vector or something instead.
Sorry:
From 5.3.4/7
When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.
From 3.7.3.1/2
The effect of dereferencing a pointer returned as a request for zero size is undefined.
I am just started learning OOP concepts and to help myself learning, I have created a Characters class. From this class I have made instance called main and an instance called monster. Here is the code for the class:
#include <iostream>
#include <string>
using namespace std;
class Character {
public:
string name;
float health;
int attackLevel;
int defenseLevel;
void setAttr(string sName,float sHealth, int sAttackLevel, int sDefenseLevel) {
name = sName;
health = sHealth;
attackLevel = sAttackLevel;
defenseLevel = sDefenseLevel;
}
void attack(int whatInstanceToAttack) {
whatInstanceToAttack.hitpoints -= 20; //obviously not valid but how do i do this?
return whatInstanceToAttack;
}
int defend(string defend) {
int damageRelieved = defenseLevel * 2;
return damageRelieved;
}
};
int main() {
Character main;
Character monster;
main.setAttr("Rafael",200,100,30);
monster.setAttr("Monster1",30,40,30);
cout << "Default Values for Raf are;" << endl;
cout << main.name << endl;
cout << main.health<< endl;
cout << main.attackLevel << endl;
cout << main.defenseLevel << endl;
cout << "Default values for monster are" << endl;
cout <<monster.name << endl;
cout <<monster.health << endl;
cout << monster.attackLevel<< endl;
cout << monster.defenseLevel << endl;
return 0;
}
Basically what I want to do is somehow access the monster instance via the main instance. I want to do this by running the attack method. So if I run
main.attack(monster);
then I want the monster to lose 20 hitpoints.
How do I go about doing this?
All you need is to pass reference of Character in attack method.
I think you must be aware of pass by value and pass by reference concept. If not you can read it here
void attack(Character &whatInstanceToAttack) {
whatInstanceToAttack.hitpoints -= 20; //obviously not valid but how do i do this?
}
Yes you can access the variables of an instance from another instance of the same class. You need to use a reference to the object to ensure the changes are reflected in the other instance. So here is what your attack function should look like.
void attack(Character &c)
{
c.hitpoints - = 20;
}
Now when you call main.attack(monster) from the main() function, the hitpoints of monster will get decremented by 20.
As a side note, it is considered a good practice to make the data members of a class private, to avoid illegal access/modification of the data. Always use the member functions as an interface to your class instances.
overload the method attack and you can pass by value or reference as per your requirement.
void attack(Character chr)
or
void attack(Character &chr)
I'm working on a project that deals with creating two strings, a username and a password. The two elements make an object of an Account. In the main, there is an Array of Accounts that is initialized at 10.
I have a Save & Quit option, which saves the Username on one line and the Password on the next in the same file. A pair of lines signifies another account.
My question is, how do you properly save the data from the Array of Accounts, then load the data from the previous Array of Accounts?
I get a std::bad_alloc memory error every time I try the loadAccounts() function. I've several different methods, but to no avail.
So far I've come up with this for saving the array (works just as it should so far) :
void saveAccounts(Account accs [], int numIndexes)
{
std::ofstream savefile("savedata.sav", std::ofstream::binary); // By re-initializing the file, the old contents are overwritten.
for (int i = 0; i < numIndexes; i++)
{
savefile << accs[i].getUsername() << endl;
savefile << accs[i].getPassword() << endl;
}
savefile.close();
}
As for my loading function I have :
Account* loadAccounts() // Load the data from the file to later print to make sure it works correctly.
{
cout << "LOADING ACCOUNTS!" << endl;
std::ifstream loadfile("savedata.sav", std::ifstream::binary);
Account * acc_arr; // The "Array" to be returned.
Account tmp_arr [10]; // The array to help the returned "Array."
acc_arr = tmp_arr; // Allowing the "Array" to be used and returned because of the actual array.
if (loadfile.is_open())
{
int i = 0;
while (loadfile.good())
{
cout << "Loadfile is good and creating Account " << i+1 << "." << endl; // For my own benefit to make sure the data being read is good and actually entering the loop.
std::string user;
std::getline(loadfile, user);
std::string pass;
std::getline(loadfile, pass);
Account tmpAcc(user, pass);
tmp_arr[i] = tmpAcc;
++i;
}
Account endAcc = Account(); // The default constructor sets Username to "NULL."
tmp_arr[i] = endAcc;
}
loadfile.close();
cout << "ACCOUNTS LOADED SUCCESSFUL!" << endl;
return acc_arr;
}
I've gathered that I can return an array by using a pointer and an actual array to do that same, since an array can't actually be returned.
I try to use the returned array here, which I'm trying to "copy" over the loaded array to the Array that will actually be printed. Later, I'll print the array (acc_arr) to ensure that the loaded array was loaded successfully :
else if (selection == 'l' || selection == 'L')
{
Account * tmp_acc_arr = new Account [10];
tmp_acc_arr = loadAccounts();
_getch();
for (size_t i = 0; i < size_t(10); i++)
{
if (tmp_acc_arr[i].getUsername() == "NULL")
{
break;
}
acc_arr[i] = tmp_acc_arr[i];
cout << "Added Account " << i << " succesfully." << endl;
}
}
The error is caused by this last block of code. I've checked to make sure the data copied correctly by using
EDIT: Awkward... by using an if statement to make sure the data within the tmp_acc_arr actually has data stored once it was returned and initialized in the main.
tmp_arr ist local in loadAccounts and on the stack. It will be invalid once loadAccounts() returns. Your return value is an invalid stack-pointer.
You could hand your pointer tmp_acc_arr to the function as an argument and fill it with the values from your file.
You should also check for overflow or better use STL containers like std::vector.
edit
void loadAccounts(Account * acc_memory, std::allocator<Account> alloc, size_t acc_array_size) // Load the data from the file to later print to make sure it works correctly.
{
Account *end_of_construction = acc_memory;
try
{
cout << "LOADING ACCOUNTS!" << endl;
std::ifstream loadfile("savedata.sav", std::ifstream::binary);
if (loadfile.is_open() && loadfile.good())
{
size_t i = 0;
for (size_t i=0; i<acc_array_size; ++i)
{
if (loadfile.good())
{
cout << "Loadfile is good and creating Account " << i+1 << "." << endl; // For my own benefit to make sure the data being read is good and actually entering the loop.
std::string user, pass;
std::getline(loadfile, user);
if (loadfile.good())
{
std::getline(loadfile, pass);
alloc.construct(end_of_construction++, user, pass);
}
else alloc.construct(end_of_construction++);
}
else alloc.construct(end_of_construction++);
}
}
loadfile.close();
cout << "ACCOUNTS LOADED SUCCESSFUL!" << endl;
}
catch (...)
{
size_t num_constructed = end_of_construction-acc_memory;
for (size_t i=0; i<num_constructed; ++i) alloc.destroy(acc_memory + i);
throw;
}
}
Used like
size_t const num_elements = 10;
std::allocator<Account> acc_alloc;
Account * tmp_acc_arr = acc_alloc.allocate(num_elements);
loadAccounts(tmp_acc_arr, acc_alloc, num_elements);
// do stuff
for (size_t i=0; i<num_elements; ++i) acc_alloc.destroy(tmp_acc_arr + i);
acc_alloc.deallocate(tmp_acc_arr, num_elements);
You return a pointer that points to an array that is destroyed as soon as you exit the function. Using that pointer leads to undefined behavior, that is BAD.
As you observed, array is not a valid return type, so to return it actually you shall put it inside a struct, and return the struct.