I am working on a sample test in the site: https://www.testdome.com/for-developers/solve-question/9808
I added two destructors for base class and derived class respectively to release the memory allocated by constructors. The first two requirements of this question are solve successfully, but the result give a fail as: Using timed multiple choice test as multiple choice test: Memory limit exceeded
My modified code as given below, I will appreciate if you can help to fix the fail...
#include <iostream>
#include <string>
class MultipleChoiceTest
{
public:
MultipleChoiceTest(int questionsCount)
{
this->questionsCount = questionsCount;
answers = new int[questionsCount];
for (int i = 0; i < questionsCount; i++)
{
answers[i] = -1;
}
}
void setAnswer(int questionIndex, int answer)
{
answers[questionIndex] = answer;
}
int getAnswer(int questionIndex) const
{
return answers[questionIndex];
}
~MultipleChoiceTest()
{
delete answers; // release memory
}
protected:
int questionsCount;
private:
int* answers;
};
class TimedMultipleChoiceTest : public MultipleChoiceTest
{
public:
TimedMultipleChoiceTest(int questionsCount)
: MultipleChoiceTest(questionsCount)
{
times = new int[questionsCount];
for (int i = 0; i < questionsCount; i++)
{
times[i] = 0;
}
}
void setTime(int questionIndex, int time)
{
times[questionIndex] = time;
}
int getTime(int questionIndex) const
{
return times[questionIndex];
}
~TimedMultipleChoiceTest()
{
delete times; // release memory
}
private:
int* times;
};
#ifndef RunTests
void executeTest()
{
MultipleChoiceTest test(5);
for (int i = 0; i < 5; i++)
{
test.setAnswer(i, i);
}
for (int i = 0; i < 5; i++)
{
std::cout << "Question " << i + 1 << ", correct answer: " << test.getAnswer(i) << "\n";
}
}
int main()
{
for (int i = 0; i < 3; i++)
{
std::cout << "Test: " << i + 1 << "\n";
executeTest();
}
}
#endif
you should use delete [] instead of delete to deallocate dynamic arrays.
Also, you don't seem to use the derived class but, nevertheless, the destructor in MultipleChoiceTest should be virtual
Related
I am writing a code using classes and am getting the wrong output, this is my function definitions:
void PrintCard(int c)
{
int Rank = c%13;
int Suit = c/13;
const char NameSuit[5] = "SCDH";
const char NameRank[14] = "23456789XJQKA";
cout << NameRank[Rank] << NameSuit[Suit];
}
CardSet::CardSet()
{
Card = NULL;
nCards = 0;
}
CardSet::CardSet(int c)
{
Card = new int[c];
for(int i = 0; i > c; i++)
{
Card[i] = (i % 52);
}
}
CardSet::~CardSet()
{
delete[] Card;
}
bool CardSet::IsEmpty() const
{
return nCards == 0;
}
void CardSet::Print() const
{
for(int i=0; i > nCards; i++)
{
PrintCard(i);
}
}
int CardSet::Size() const
{
return nCards;
}
This is my main
cout << "Testing constructors, Print(), Size() & IsEmpty():" << endl;
CardSet CardSet1; // empty cCardSet
CardSet CardSet2(12); // CardSet with 12 cards
if(CardSet1.IsEmpty()) cout<<"CardSet1 is empty"<<endl;
else cout<<"CardSet1 has "<< CardSet1.Size() <<" cards" << endl;
if(CardSet2.IsEmpty()) cout<<"CardSet2 is empty"<<endl;
else cout<<"CardSet2 has "<< CardSet2.Size() <<" cards" << endl;
cout << "Printout of CardSet1: ";
CardSet1.Print();
cout << "Printout of CardSet2: ";
CardSet2.Print();
cout << endl;
when i am compiling i am getting the correct value (0) for cardset1 however for cardset2 instead of outputting a value of 12, which is what should be the output i am getting very high numbers that are changing each time i compile. i think something is wrong with my for loops or memory allocation.
this is also what the class definition looks like:
class CardSet
{
public:
CardSet();
CardSet(int);
~CardSet();
int Size() const;
bool IsEmpty() const;
void Shuffle();
int Deal();
void Deal(int,CardSet&,CardSet&);
void Deal(int,CardSet&,CardSet&,CardSet&,CardSet&);
void AddCard(int);
void MergeShuffle(CardSet&);
void Print() const;
private:
int* Card;
int nCards;
};
any help would be greatly appreciated !!
Cheers
In CardSet::CardSet change this
for(int i = 0; i > c; i++)
to this
for (int i = 0; i < c; i++)
Also in CardSet::Print change this
for(int i=0; i > nCards; i++)
To this:
for (int i = 0; i < nCards; i++)
Finally, add nCards = c; to CardSet::CardSet.
void CardSet::Print() const
{
for(int i=0; i > nCards; i++)
{
PrintCard(i);
}
}
must be
void CardSet::Print() const
{
for(int i=0; i < nCards; i++)
{
PrintCard(i);
}
}
to correct the end test, and you have the same problem in CardSet::CardSet(int c) which must be
CardSet::CardSet(int c)
{
nCards = c;
Card = new int[c];
for(int i = 0; i < c; i++)
{
Card[i] = (i % 52);
}
}
where nCards must also be set.
In a for the test indicates if the loop continues, not if it ends
for (inits; test; changes) ...
is equivalent to
init;
while (test) {
...
changes;
}
Out of that there is no separator in PrintCard doing cout << NameRank[Rank] << NameSuit[Suit]; so may be you also need to add something like a space in Print :
void CardSet::Print() const
{
for(int i=0; i < nCards; i++)
{
PrintCard(i);
cout << ' ';
}
}
or in PrintCard to also separate the two fields like
cout << NameRank[Rank] << ' ' << NameSuit[Suit] << endl;
Note you can simplify
const char NameSuit[5] = "SCDH";
const char NameRank[14] = "23456789XJQKA";
cout << NameRank[Rank] << NameSuit[Suit];
to be
cout << "23456789XJQKA"[Rank] << "SCDH"[Suit];
Or if you really want to have the arrays I encourage you to not give a size, that avoid problems if you change the literal string and forget to also change the size, so
const char NameSuit[] = "SCDH";
const char NameRank[] = "23456789XJQKA";
For instance having :
#include <iostream>
using namespace std;
class CardSet
{
public:
CardSet();
CardSet(int);
~CardSet();
int Size() const;
bool IsEmpty() const;
void Shuffle();
int Deal();
void Deal(int,CardSet&,CardSet&);
void Deal(int,CardSet&,CardSet&,CardSet&,CardSet&);
void AddCard(int);
void MergeShuffle(CardSet&);
void Print() const;
private:
int* Card;
int nCards;
};
void PrintCard(int c)
{
int Rank = c%13;
int Suit = c/13;
cout << "23456789XJQKA"[Rank] << ' ' << "SCDH"[Suit] << endl;
}
CardSet::CardSet()
{
Card = NULL;
nCards = 0;
}
CardSet::CardSet(int c)
{
nCards = c;
Card = new int[c];
for(int i = 0; i < c; i++)
{
Card[i] = (i % 52);
}
}
CardSet::~CardSet()
{
delete[] Card;
}
bool CardSet::IsEmpty() const
{
return nCards == 0;
}
void CardSet::Print() const
{
for(int i=0; i < nCards; i++)
{
PrintCard(i);
}
}
int CardSet::Size() const
{
return nCards;
}
int main(void)
{
CardSet cs(5);
cs.Print();
}
Compilation and execution :
pi#raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra c.cc
pi#raspberrypi:/tmp $ ./a.out
2 S
3 S
4 S
5 S
6 S
pi#raspberrypi:/tmp $
You should review it (the loop)
void CardSet::Print() const
{
for(int i=0; i > nCards; i++)//## reconsider it
{
PrintCard(i);
}
}
My problem is in adaugare function on this line I think persoane[numar_persoane] = pers. Because that line gives me this error. What problem do I have?
I have to use a dynamic array of pointers.
class baze
{
private: int numar_persoane=0;
persoana (*persoane)=(persoana *)malloc(0);
public: baze()
{
persoane = NULL;
}
~baze()
{
delete[] persoane; //???????????
}
void adaugare(persoana pers)
{
numar_persoane++;
realloc(persoane, sizeof(persoana)*numar_persoane);
persoane[numar_persoane] = pers;
};
void afisarealfa()
{
for (int i = 0; i < numar_persoane; i++)
for (int j = i + 1; j < numar_persoane; j++)
if (persoane[i].gnume()>persoane[i].gnume())
{
persoana aux;
aux = persoane[i];
persoane[i] = persoane[j];
persoane[j] = aux;
}
for (int i = 0; i < numar_persoane; i++)
{
cout << "Nume:" << persoane[i].gnume() << endl;
cout << "Varsta" << persoane[i].gan() << endl;
cout << "sex" << persoane[i].gsex();
}
}
This is persoana class:
class persoana
{
private: string nume;
int an;
char sex;
public: void snume(string numebagat)
{
nume = numebagat;
}
string gnume()
{
return nume;
}
void san(int anbagat)
{
an = anbagat;
}
int gan()
{
return an;
}
void ssex(char sexbagat)
{
sex = sexbagat;
}
char gsex()
{
return sex;
}
};
Main:
int _tmain(int argc, _TCHAR* argv[])
{
persoana a;
a.san(1990);
a.snume("Gogu");
a.ssex('m');
cout << "Nume: " << a.gnume() << endl << "Anul nasterii: " << a.gan() << endl << "Sex: " << a.gsex();
baze b;
b.adaugare(a);
return 0;
}
As #simpletron pointed out, malloc(0) is kind of weird. I wasn't even sure it was legal, but per what's the point in malloc(0)?, it is legal albeit implementation defined (it might be NULL, it might be a valid empty region; either way, you can call free on it, and per Is a malloc() needed before a realloc()? you can just skip that malloc;
Using malloc but then delete is not recommended; per Behaviour of malloc with delete in C++, this IS undefined behavior; you should probably be using free to go with realloc instead of delete
You have an off by one error. You should use persoane[numar_persoane-1] = pers;
You probably should set age/sex to some default value in the constructor.
This might be my personal preference, but I dislike copying classes around versus pointer to classes.
I'm new to C++, and I'm having significant trouble with creating an array of objects using a pass by pointer and reference. This is not the actual code; it's an example of what the code essentially does.
#include <iostream>
class MyClass
{
public:
MyClass();
static int doStuff(MyClass *&classArray);
void print_number();
private:
int number;
};
MyClass::MyClass()
{
}
int MyClass::doStuff(MyClass *&classArray)
{
int i = 0;
for (i = 0; i < 10; i++) {
*classArray[i].number = i;
}
return i;
}
void MyClass::print_number()
{
std::cout << number << "\n";
}
int main(void)
{
MyClass *test = nullptr;
int p = MyClass::doStuff(test);
std::cout << p << '\n';
for (int i = 0; i < 10; i++) {
test[i].print_number();
}
return 0;
}
When compiled, this gives a segmentation fault.
This is how you do it (don't forget do delete classArray with delete[] at the end of your program or destructor:
new operator has to have default constructor, if you want to use non-default it is easier to create copy constructor, then a temporary object and copy.
#include <iostream>
class MyClass
{
public:
MyClass();
MyClass(int x, int y);
MyClass(MyClass &OldClass);
static int doStuff(MyClass *&classArray, int Size, int x, int y);
void print_number();
private:
int number, x, y;
};
MyClass::MyClass()
{
number = 0;
x = 0;
y = 0;
}
MyClass::MyClass(int x, int y)
{
number = 0;
this->x = x;
this->y = y;
}
MyClass::MyClass(MyClass &OldClass)
{
this->number = OldClass.number;
this->x = OldClass.x;
this->y = OldClass.y;
}
int MyClass::doStuff(MyClass *&classArray, int Size, int x, int y)
{
if (Size > 0)
{
classArray = new MyClass[Size];
for (int i = 0; i < Size; i++)
{
classArray[i] = MyClass(x, y);
classArray[i].number = i;
}
return Size;
}
else
return 0;
}
void MyClass::print_number()
{
std::cout << number << " " << x << " " << y << "\n";
}
int main(void)
{
MyClass *test = nullptr;
int p = MyClass::doStuff(test, 10, 5, 6);
std::cout << p << '\n';
for (int i = 0; i < p; i++) {
test[i].print_number();
}
delete[] test;
std::cin.get();
return 0;
}
It is not working because you need to allocate the array, as the function is trying to access elements of an array which has yet not been initialized to hold that amount of elements. You can do this by
MyClass *test = new MyClass[array_size];
Or
MyClass test[array_size];
Or by using a resizable container such as std::vector, and changing the function parameters accordingly
*classArray[i].number = i;
You called doStuff with a null pointer, so classArray is null and is not an array. Dereferencing a null pointer results in undefined behavior and on most implementations you'll usually get a crash.
You're also dereferencing something that's not a pointer so this code will not even compile. The error I get is:
main.cpp:23:9: error: indirection requires pointer operand ('int' invalid)
*classArray[i].number = i;
^~~~~~~~~~~~~~~~~~~~~
Presumably this is just because, as you say, the code you're showing is not your real code and classArray[i].number corresponds to a pointer in your real code. But I thought I'd point this out anyway, just in case.
Given the context of your code, here's a working example of your code:
#include <iostream>
class MyClass
{
public:
MyClass() {}
static int doStuff(MyClass*& classArray, size_t sz)
{
int i = 0;
for (; i < sz; i++) {
classArray[i].number = i;
}
// not sure what you want here, but this will return sz+1 if sz>0
return i;
}
void print_number()
{
std::cout << this->number << std::endl;
}
private:
int number;
};
int main(void)
{
MyClass* test = new MyClass[10];
int p = MyClass::doStuff(test, 10);
std::cout << p << '\n';
for (int i = 0; i < 10; i++) {
test[i].print_number();
}
delete[] test;
return 0;
}
Though as others have pointed out, you are using C++, while it's a great exercise in understand how to pass pointers and arrays around, you might find the STL and C++stdlib contain a lot of these types of idioms in an 'easier to understand context'.
Here's your code with some C++ STL:
#include <iostream>
#include <vector>
class MyClass
{
public:
MyClass() {}
MyClass(int i) : number(i) {}
static int doStuff(std::vector<MyClass>& classArray, size_t sz)
{
int i = 0;
for (; i < sz; i++) {
classArray.push_back(MyClass(i));
}
// not sure what you want here, but this will return sz+1 if sz>0
return i;
}
void print_number()
{
std::cout << this->number << std::endl;
}
private:
int number;
};
int main(void)
{
std::vector<MyClass> test;
int p = MyClass::doStuff(test, 10);
std::cout << test.size() << '\n';
// can use iterators here if you want
std::vector<MyClass>::iterator itr = test.begin();
for (; itr != test.end(); itr++) {
itr->print_number();
}
return 0;
}
Hope that can help.
It's crashing at the very end of the main() function where it needs to delete the starters objects. The error message that pops up when I run the program says: Debug assertion failed! Expression: _BLOCK_IS_VALID(pHead->nBlockUse). How do i fix it from crashing when deleting the starters objects?
#include <iostream>
#include <fstream>
#include "olympic.h"
using namespace std;
ofstream csis;
int main() {
const int lanes = 4;
Ranker rank(lanes);
csis.open("csis.txt");
// First make a list of names and lane assignments.
Competitor* starters[lanes];
starters[0] = new Competitor("EmmyLou Harris", 1);
starters[1] = new Competitor("Nanci Griffith", 2);
starters[2] = new Competitor("Bonnie Raitt", 3);
starters[3] = new Competitor("Joni Mitchell", 4);
// The race is run; now assign a time to each person.
starters[0]->setTime((float)12.0);
starters[1]->setTime((float)12.8);
starters[2]->setTime((float)11.0);
starters[3]->setTime((float)10.3);
// Put everyone into the ranker.
for (int i = 0; i < lanes; i++)
rank.addList(starters[i]);
// Now print out the list to make sure its right.
cout << "Competitors by lane are:" << endl;
csis << "Competitors by lane are:" << endl;
for (int i = 1; i <= lanes; i++)
rank.getLane(i)->print();
// Finally, show how they finished.
cout << "Rankings by finish are:" << endl;
csis << "Rankings by finish are:" << endl;
for (int i = 1; i <= lanes; i++)
rank.getFinish(i)->print();
for (int i = 0; i < lanes; i++)
delete starters[i];
csis.close();
}
ranker.cpp:
#include "ranker.h"
#include "competitor.h"
#include <stdlib.h>
Ranker::Ranker(int lanes) {
athlete = new Competitor*[lanes];
numAthletes = 0;
maxAthletes = lanes;
}
int Ranker::addList(Competitor* starter) {
if (numAthletes < maxAthletes && starter != NULL) {
athlete[numAthletes] = starter;
numAthletes++;
return numAthletes;
}
else
return 0;
}
Competitor* Ranker::getLane(int lane) {
for (int i = 0; i < numAthletes; i++) {
if (athlete[i]->getLane() == lane) {
return athlete[i];
}
}
return NULL;
}
Competitor* Ranker::getFinish(int position) {
switch(position) {
case 1:
return athlete[3];
break;
case 2:
return athlete[2];
break;
case 3:
return athlete[1];
break;
case 4:
return athlete[0];
break;
}
return NULL;
}
int Ranker::getFilled() {
return numAthletes;
}
Ranker::~Ranker() {
delete [] athlete;
}
competitor.h:
#ifndef _COMPETITOR_H
#define _COMPETITOR_H
class Competitor {
private:
char* name;
int lane;
double time;
public:
Competitor(char* inputName, int inputLane);
Competitor();
void setTime(double inputTime);
char* getName();
int Competitor::getLane();
double getTime();
void print();
~Competitor();
};
#endif
competitor.cpp:
#include "competitor.h"
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
Competitor::Competitor(char* inputName, int inputLane) {
name = inputName;
lane = inputLane;
}
Competitor::Competitor() {
name = 0;
lane = 0;
time = 0;
}
void Competitor::setTime(double inputTime) {
time = inputTime;
}
char* Competitor::getName() {
return name;
}
int Competitor::getLane() {
return lane;
}
double Competitor::getTime() {
return time;
}
void Competitor::print() {
cout << setw(20) << name << setw(20) << lane << setw(20) << setprecision(4) << time << endl;
}
Competitor::~Competitor() {
delete [] name;
}
Call stack:
before crash: http://i.imgur.com/d4sKbKV.png
after crash: http://i.imgur.com/C5cXth9.png
After you've added Competitor class, it seems the problem is that you delete its name in Competitor's destructor. But you assign it from string literal which can't really be deleted. I'm sure the stack trace leading to assertion will prove that.
One way of solving the problem would be using std::string to store the name.
Problem is when deleting the char* value on destructor, which is assigned with const char instead new char. So i have slightly changed the constructor to copy the const char to new char.
Competitor::Competitor(char* inputName, int charlen, int inputLane)
{
name = new char[charlen + 1];
memcpy(name , inputName, charlen );
name [charlen] = '\0';
lane = inputLane;
}
#include <iostream>
class MyClass
{
public:
MyClass() {
itsAge = 1;
itsWeight = 5;
}
~MyClass() {}
int GetAge() const { return itsAge; }
int GetWeight() const { return itsWeight; }
void SetAge(int age) { itsAge = age; }
private:
int itsAge;
int itsWeight;
};
int main()
{
MyClass * myObject[50]; // define array of objects...define the type as the object
int i;
MyClass * objectPointer;
for (i = 0; i < 50; i++)
{
objectPointer = new MyClass;
objectPointer->SetAge(2*i + 1);
myObject[i] = objectPointer;
}
for (i = 0; i < 50; i++)
std::cout << "#" << i + 1 << ": " << myObject[i]->GetAge() << std::endl;
for (i = 0; i < 50; i++)
{
delete myObject[i];
myObject[i] = NULL;
}
I am wondering why the objectPointer must be inside the for loop, if I take it out and place it right before the for loop, I get nonsensical results. Help would be appreciated, thanks...sorry for the terrible formatting.
myObject[i] = objectPointer;
It should be inside the loop because you are storing a new reference in the array of the pointers. If it is outside the loop, then all the array of pointers point to the same reference. In such scenario, you should be careful while deallocation as all the array of pointers point to the same memory location.