I am learning classes and OOP, so I was doing some practice programs, when I came across the weirdest bug ever while programming.
So, I have the following files, beginning by my class "pessoa", located in pessoa.h:
#pragma once
#include <string>
#include <iostream>
using namespace std;
class pessoa {
public:
//constructor (nome do aluno, data de nascimento)
pessoa(string newname="asffaf", unsigned int newdate=1996): name(newname), DataN(newdate){};
void SetName(string a); //set name
void SetBornDate(unsigned int ); //nascimento
string GetName(); //get name
unsigned int GetBornDate();
virtual void Print(){}; // print
private:
string name; //nome
unsigned int DataN; //data de nascimento
};
Whose functions are defined in pessoa.cpp
#include "pessoa.h"
string pessoa::GetName ()
{
return name;
}
void pessoa::SetName(string a)
{
name = a;
}
unsigned int pessoa::GetBornDate()
{
return DataN;
}
void pessoa::SetBornDate(unsigned int n)
{
DataN=n;
}
A function, DoArray, declared in DoArray.h, and defined in the file DoArray.cpp:
pessoa** DoArray(int n)
{
pessoa* p= new pessoa[n];
pessoa** pointer= &p;
return pointer;
}
And the main file:
#include <string>
#include <iostream>
#include "pessoa.h"
#include "DoArray.h"
#include <cstdio>
using namespace std;
int main()
{
//pessoa P[10];
//cout << P[5].GetBornDate();
pessoa** a=DoArray(5);
cerr << endl << a[0][3].GetBornDate() << endl;
cerr << endl << a[0][3].GetName() << endl;
return 0;
}
The weird find is, if I comment one of the methods above, "GetBornDate" or GetName, and run, the non-commented method will run fine and as supposed. However, if both are not commented, then the first will run and the program will crash before the 2nd method.
Sorry for the long post.
Let's look into this function:
int *get()
{
int i = 0;
return &i;
}
what is the problem with it? It is returning pointer to a local variable, which does not exist anymore when function get() terminates ie it returns dangling pointer. Now your code:
pessoa** DoArray(int n)
{
pessoa* p= new pessoa[n];
return &p;
}
do you see the problem?
To clarify even more:
typedef pessoa * pessoa_ptr;
pessoa_ptr* DoArray(int n)
{
pessoa_ptr p= whatever;
return &p;
}
you need to understand that whatever you assign to p does not change lifetime of p itself. Pointer is the same variable as others.
Related
Below is code for a simple book list with a class to store book names and isbn numbers into an overloaded function using a vector. This program runs fine and I can test it by returning a specific name (or isbn) using an accessor function from my class.
Question: I tried calling (instantiating?) a constructor with parameters from my class but it would not work, so I commented it out. Yet I was still able to run the program without error. From my main below - //BookData bkDataObj(bookName, isbn);
From watching tutorials, I thought I always had to make an object for a specific constructor from a class that I needed to call? My program definitely still uses my overloaded constructor and function declaration BookData(string, int); without making an object for it in main first.
Thanks for any help or input on this matter.
Main
#include <iostream>
#include <string>
#include <vector>
#include "BookData.h"
using namespace std;
int main()
{
string bookName[] = { "Neuromancer", "The Expanse", "Do Androids Dream of Electric Sheep?", "DUNE" };
int isbn[] = { 345404475, 441569595, 316129089, 441172717 };
//BookData bkDataObj(bookName, isbn); //how did program run without instantiating object for class?
vector <BookData> bookDataArr;
int arrayLength = sizeof(bookName) / sizeof(string);
for (int i = 0; i < arrayLength; i++) {
bookDataArr.push_back(BookData(bookName[i], isbn[i]));
}
cout << "Book 4 is: " << bookDataArr[3].getBookNameCl(); //test if works
return 0;
}
BookData.h
#include <iostream>
#include <string>
using namespace std;
class BookData
{
public:
BookData();
BookData(string, int); //wasn't I supposed to make an object for this constructor in my main?
string getBookNameCl();
int getIsbnCl();
private:
string bookNameCl;
int isbnCl;
};
BookData.cpp
#include "BookData.h"
BookData::BookData() {
bookNameCl = " ";
isbnCl = 0;
}
BookData::BookData(string bookNameOL, int isbnOL) { //how did I use this function
bookNameCl = bookNameOL; //definition without an object in main?
isbnCl = isbnOL;
}
string BookData::getBookNameCl() { //can still return a book name
return bookNameCl;
}
int BookData::getIsbnCl() {
return isbnCl;
}
It seems this problem is the so-called dangling pointer problem. Basically I'm trying to parse a pointer into a function (that stores the pointer as a global variable) inside a class, and I want the pointer to be stored in that class and can be used now and then. So from inside the class, I can manipulate this pointer and its value which is outside of the class.
I simplified the code and re-created the situation as the following:
main.cpp
#include <iostream>
#include "class.h"
using namespace std;
void main() {
dp dp1;
int input = 3;
int *pointer = &input;
dp1.store(pointer);
dp1.multiply();
}
class.h
#pragma once
#include <iostream>
using namespace std;
class dp {
public:
void store(int *num); // It stores the incoming pointer.
void multiply(); // It multiplies whatever is contained at the address pointed by the incoming pointer.
void print();
private:
int *stored_input; // I want to store the incoming pointer so it can be used in the class now and then.
};
class.cpp
#include <iostream>
#include "class.h"
using namespace std;
void dp::store(int *num) {
*stored_input = *num;
}
void dp::multiply() {
*stored_input *= 10;
print();
}
void dp::print() {
cout << *stored_input << "\n";
}
There is no compile error but after running it, it crashes.
It says:
Unhandled exception thrown: write access violation.
this->stored_input was 0xCCCCCCCC.
If there is a handler for this exception, the program may be safely continued.
I pressed "break" and it breaks at the 7th line of class.cpp:
*stored_input = *num;
It is not a dangling pointer, but a not initialized, you probably want:
void dp::store(int *num) {
stored_input = num;
}
I'm a beginner (in C++, I'm coming from C (6 months experience)) and I'm trying to create a priority queue, but something is not working.
When I start the program and compile it, there are no errors. But there is nothing printed on the screen and the program crashes.
So here is the code:
PriorityQueue.h
using namespace std;
class PriorityQueue{
private:
struct pqentry_t{
string value;
float priority;
};
pqentry_t **_pqentry;
int _size;
int _next;
public:
PriorityQueue();
~PriorityQueue();
void insert(string value, float priority);
void printQueue();
};
PriorityQueue.cpp
#include <iostream>
#include <string>
#include "PriorityQueue.h"
#define SIZE 8
using namespace std;
PriorityQueue::PriorityQueue(){
_size = SIZE;
_next = 0;
_pqentry = new pqentry_t*[_size];
}
PriorityQueue::~PriorityQueue(){
delete[] _pqentry;
}
void PriorityQueue::insert(string value, float priority){
_pqentry[_next]->value = value; // this is probably not working
_pqentry[_next]->priority = priority;
_next++;
}
void PriorityQueue::printQueue(){
for (int i = 0; i < _next; i++){
cout << "Value: " << _pqentry[i]->value << endl
<< "Priority: " << _pqentry[i]->priority << endl;
}
cout << endl;
}
main.cpp
#include <iostream>
#include <string>
#include "PriorityQueue.h"
using namespace std;
int main()
{
PriorityQueue pq;
pq.insert("Banana", 23);
pq.printQueue();
}
I think, I know where the error is, in the PriorityQueue.cpp, here:
_pqentry[_next]->value = value;
_pqentry[_next]->priority = priority;
But I don't know what's wrong and I can't fix it. The compiler says there are no errors.
I hope, you can help me. Thanks in advance!
You did allocate the _pqentry member but you need to allocate each entry of this array as well, for example:
_pqentry[_next] = new pqentry_t;
before writing to it.
And do not forget to delete those :)
It looks like you are creating an array of pointers to pqentry_t in your constructor, but your insert method is expecting it to be an array of _pqentry structures themselves. You are not allocating space for the pqentry_t elements themselves and so when you try to dereference them in your insert method, the program crashes.
Try changing the definition of _pqentry in the class to pqentry_t *_pqentry and the allocation in the constructor to new pqentry_t[size]. This will allow your insert and printQueue methods to access the entries of _pqentry as they are written.
How could I keep an object valid in a different class? Here is an example below.
This code would give as a result on the screen:
2
2
What I want is to give me this:
2
3
In other words, I desire object Bita (or even the whole class two) to acknowledge object Alpha and not create a new object.
Is there a way to include the object Alpha to object Bita ? Please be simple because I am a beginner.
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
class one
{
int a, b;
public:
one() { a = 2; }
int func()
{
return a;
}
void func2()
{
a = 3;
}
};
class two
{
int z, b;
public:
void test();
};
void two::test()
{
one Alpha;
cout << Alpha.func() << '\n';
}
int main()
{
one Alpha;
cout << Alpha.func() << '\n';
Alpha.func2();
two Bita;
Bita.test();
return 0;
}
Each instance of an object has its own values for its member variables. So when you declare two Bita, and call Bita.test(), test() creates its own object of class Alpha inside of it, with its own value, which is still at 2, prints that, and then that Alpha object goes out of scope and is removed from the stack as test() completes.
What you say you have in mind to do here is to have class one have what is called a static member variable. Add the keyword static:
static int a;
And then a will behave as you intend.
One explanation of this is here: http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
One solution would be to pass the object by reference you method two::test like this
class two
{
int z, b;
public:
void test(one& a);
};
void two::test(one& a)
{
cout << a.func() << '\n';
}
And then call it in main
Bita.test(Alpha);
So the full code will be
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
class one {
int a, b;
public:
one() { a = 2; }
int func() { return a; }
void func2() { a = 3; }
};
class two {
int z, b;
public:
void test(one&);
};
void two::test(one& a) {
cout << a.func() << '\n';
}
int main() {
one Alpha;
cout << Alpha.func() << '\n';
Alpha.func2();
two Bita;
Bita.test(Alpha);
return 0;
}
I am trying to learn C++ OOP and I made the follwing code:
main.cpp
#include <iostream>
#include <string>
#include "monster.h"
using namespace std;
int main(int argc, char** argv) {
Monster monster("Wizard",150,50);
Monster monster2("Gorgoyle",450,15);
cout << monster2.getHealth() << endl;
monster.attack(monster2);
cout << monster2.getHealth() << endl;
}
monster.h
#ifndef MONSTER_H
#define MONSTER_H
#include <iostream>
#include <string>
using namespace std;
class Monster
{
public:
Monster(string name_, int health_, int damage_);
~Monster();
int attack(Monster opponet);
int getHealth();
string name;
int damage;
int health = 0;
int getDamage();
void setHealth(int health_);
void setDamage(int damage_);
void setName(string name);
void doDamageToOpponent(Monster opponent);
string getName();
};
#endif
monster.cpp
#include "monster.h"
Monster::Monster(string name_, int health_, int damage_) {
health = health_;
setDamage(damage_);
setName(name_);
}
Monster::~Monster() { }
int Monster::attack(Monster opponent) {
doDamageToOpponent(opponent);
}
void Monster::doDamageToOpponent(Monster opponent) {
int newHealth = opponent.getHealth() - this->getDamage();
opponent.setHealth(newHealth);
}
int Monster::getHealth() {
return health;
}
int Monster::getDamage() {
return damage;
}
void Monster::setHealth(int health_) {
health = health_;
}
void Monster::setDamage(int damage_) {
this->damage = damage_;
}
void Monster::setName(string name_) {
this->name = name_;
}
string Monster::getName() {
return name;
}
Now my problem is that, when I run this code I expect to have monster2 object to have 400 health left, but it is still 450 :S
What must be done here in order to to so? I noticed that it can be 400 in doDamageToOppoenet but when it leaves that block, then it is still 450. Please help me! Thanks.
You're passing objects by value:
void Monster::doDamageToOpponent(Monster opponent) <- This should be by reference
int Monster::attack(Monster opponent) <- idem
that means: you're creating a new copy of the Monster object you meant to deal damage to in the functions you're calling, and then actually dealing that copy damage but leaving the original old object with the value untouched.
Signatures as follows would work instead:
void Monster::doDamageToOpponent(Monster& opponent)
int Monster::attack(Monster& opponent)
If you want to learn more about this, something to read on: Passing stuff by reference and Passing stuff by value
The reason is that functions attack and doDamageToOpponent are taking copies of arguments, because you pass them by value. What happenes then is you change the copies of passed Monsters inside functions. After functions return, these copies die (as they are local to functions) and nothing happens to original, interested parties.
Try instead pass the argument by reference. Reference works as if it was the original variable. Consider:
int a = 0;
int &refa = a; /* refa acts as real "a", it refers to the same object "a" */
int b = a; /* this is your case */
b = 6; /* b will be changed, but "a" not */
refa = 6; /* a is changed, really "a", refa is just different name for "a" */
Try:
int Monster::attack( Monster &opponent){
doDamageToOpponent( opponent);
}
void Monster::doDamageToOpponent( Monster &opponent){
int newHealth = opponent.getHealth() - this->getDamage();
opponent.setHealth( newHealth);
}
You are passing the opponent by value, i.e., the function:
int Monster::attack(Monster opponent);
will actually receive a copy of the opponent and modify that copy. Every time you have a function that modifies some object you need to pass the object to be modified by reference or pass a pointer to it, e.g.,
int Monster::attack(Monster& opponent);
or
int Monster::attack(Monster* opponent);
I recommend using const T& for input parameters and T* for output parameters, so in this case, the latter form. The reason why I recommend the latter for output parameters is because it makes it more explicit to the caller:
monster.attack(&monster2); // passing a pointer: monster2 will be modified.