segfault after return 0; - recursion

I wrote a program to test my binary tree and when I run it, the program seems to crash (btree.exe has stopped working, Windows is checking for a solution ...).
When I ran it through my debugger and placed the breakpoint on the function I suspect is causing it, destroy_tree(), it seemed to run as expected and returned back to the main function. Main, in turn, returned from the program but then the cursor jumped back to destroy_tree() and looped recusively within itself.
The minimal code sample is below so it can be ran instantly. My compiler is MinGW and my debugger is gdb (I'm using Code::Blocks).
#include <iostream>
using namespace std;
struct node
{
int key_value;
node *left;
node *right;
};
class Btree
{
public:
Btree();
~Btree();
void insert(int key);
void destroy_tree();
private:
node *root;
void destroy_tree(node *leaf);
void insert(int key, node *leaf);
};
Btree::Btree()
{
root = NULL;
}
Btree::~Btree()
{
destroy_tree();
}
void Btree::destroy_tree()
{
destroy_tree(root);
cout<<"tree destroyed\n"<<endl;
}
void Btree::destroy_tree(node *leaf)
{
if(leaf!=NULL)
{
destroy_tree(leaf->left);
destroy_tree(leaf->right);
delete leaf;
}
}
void Btree::insert(int key, node *leaf)
{
if(key < leaf->key_value)
{
if(leaf->left!=NULL)
insert(key, leaf->left);
else
{
leaf->left = new node;
leaf->left->key_value = key;
leaf->left->left = NULL;
leaf->left->right = NULL;
}
}
else if (key >= leaf->key_value)
{
if(leaf->right!=NULL)
insert(key, leaf->right);
else
{
leaf->right = new node;
leaf->right->key_value = key;
leaf->right->left = NULL;
leaf->right->right = NULL;
}
}
}
void Btree::insert(int key)
{
if(root!=NULL)
{
insert(key, root);
}
else
{
root = new node;
root->key_value = key;
root->left = NULL;
root->right = NULL;
}
}
int main()
{
Btree tree;
int i;
tree.insert(1);
tree.destroy_tree();
return 0;
}
As an aside, I'm planning to switch from Code::Blocks built-in debugger to DDD for debugging these problems. I heard DDD can display visually pointers to objects instead of just displaying the pointer's address. Do you think making the switch will help with solving these types of problems (data structure and algorithm problems)?

Your destroy_tree() is called twice, you call it once and then it gets called after the execution leaves main() from the destructor.
You may think it should work anyway, because you check whether leaf!=NULL, but delete does not set the pointer to NULL. So your root is not NULL when destroy_tree() is called for the second time,

Not directly related (or maybe it is) to your problem, but it's good practice to give structs a constructor. For example:
struct node
{
int key_value;
node *left;
node *right;
node( int val ) : key_val( val ), left(NULL), right(NULL) {}
};
If you do this, your code becomes simpler, because you don't need worry about setting the pointers when you create a node, and it is not possible to forget to initialise them.
Regarding DDD, it;'s a fine debugger, but frankly the secret of debugging is to write correct code in the first place, so you don't have to do it. C++ gives you a lot of help in this direction (like the use of constructors), but you have to understand and use the facilities it provides.

Btree::destroy_tree doesn't set 'root' to 0 after successfully nuking the tree. As a result, the destructor class destroy_tree() again and you're trying to destroy already destroyed objects.
That'll be undefined behaviour then :).

Once you destroy the root.
Make sure it is NULL so it does not try to do it again (from the destructor)
void Btree::destroy_tree(node *leaf)
{
if(leaf!=NULL)
{
destroy_tree(leaf->left);
destroy_tree(leaf->right);
delete leaf;
leaf = NULL; // add this line
}
}

Related

After I declare an object from a class, and try to set a variable to that object inly, why does it say that it does not declare a type?

I am writing code for a school project that will be used for a Chromebook charging station with security. The problem I am having now is when I am detecting if a Chromebook is actually in the slot after the user has been assigned one, I am using a rocker switch to simulate this but when I am declaring the pin to the rocker, the arduino verfier comes up with that
"'slot1' does not name a type".
Code is below:
//class
class Chromebook_slot {
public:
String Name = "";
String RFID_tag = "";
int rocker = 0;
boolean chromebook_in = false;
//class function to check if chromebook is in.
//if not, redirect already to reassigning so chromebook slot is entered as open and free.
void set_if_in()
{
int momen_1_state = digitalRead(momen_1);
int momen_2_state = digitalRead(momen_2);
// the button has been pushed down and the previous process has been completed
// eg. servos would have been reset if there was a previous user
if (momen_1_state == HIGH || momen_2_state == HIGH)
{
chromebook_in = digitalRead(this->rocker);
if (chromebook_in == 0)
{
re_assigning();
}
else
{
return;
}
}
}
};
//this is now outside the class..
//class declarations
Chromebook_slot slot1;
Chromebook_slot slot2;
//variables for rocker switches which will act for detecting chromebooks.
// in my final version, this will replaced by a photoresistor and laser.
slot1.rocker = 3;
slot2.rocker = 2;
Where the function re_assigning() is a separate function declared further in the code and just resets the slot as open for future use.
slot1.rocker = 3;
slot2.rocker = 2;
These are statements that cannot be at the top level of a C++ (or .ino) file. They need to be inside of a function. What's happening is the compiler is looking looking at the slot1 identifier through the lens of potential valid constructions. It sees an identifier, and about the only thing that could legally exist at this point in the code that starts with an identifier like that is some declaration, e.g. int a = 7;, or more abstractly some_type some_more_stuff. So it expects slot1 to be a type, which it isn't, hence the message.
If you want an assignment like those to happen early on in an Arduino program, the simplest thing you could do is put them in setup():
void setup() {
slot1.rocker = 3;
slot2.rocker = 2;
// ...
}
Or, you'd make these part of the Chromebook_slot's constructor, such that they could be given in slot1 and slot2's declaration:
class Chromebook_slot {
public:
Chromebook_slot(int rocker_init_value) {
rocker = rocker_init_value;
}
// ...
Or in a maybe less familiar but more proper form, using the constructor's initialization list:
class Chromebook_slot {
public:
Chromebook_slot(int rocker_init_value)
: rocker(rocker_init_value) {}
// ...
Once you have a constructor for Chromebook_slot, your variables can become:
Chromebook_slot slot1(3);
Chromebook_slot slot2(2);

How can i get this tree to work properly?

I cannot get this tree to act correctly. i keep getting exit error codes. What is going on with the tree and how would i use the search function in main? it seems the methods are coded correctly but i am not using it correctly in main. i keep geting exit errors that are not 0 and none of the methods i try to use in the main function work. now i am just typing to fill in space because apparently my post is mostly code and not enough text!
//Binary Tree Practice
#include <iostream>
struct node{
int data;
node* right;
node* left;
};
class bTree{
public:
bTree(){
root=NULL;
}
~bTree(){
destroyTree();
}
void addNode(int key);
node *search(int key);
void destroyTree();
private:
node* root;
void addNode(int key,node*nod);
node *search(int key, node *leaf);
void destroyTree(node*&node);
};
node *bTree::search(int key)
{
return search(key, root);
}
void bTree::destroyTree()
{
destroyTree(root);
}
void bTree::addNode(int key)
{
if(root!=NULL)
addNode(key, root);
else
{
root=new node;
root->data=key;
root->left=NULL;
root->right=NULL;
}
}
void bTree::addNode(int key, node* nod) {//ADD a node in correct position.
if (key < nod->left->data) {
if (nod->left != NULL)
addNode(key, nod->left);//RECURSION traverse tree to the left until
find a NULL node
else {//When NULL node is found
nod->left = new node;
nod->left->data = key;
nod->left->left = NULL;
nod->right = NULL;
std::cout<<"node added"<<std::endl;
}
} else if (key > nod->right->data) {
if (nod->right != NULL)
addNode(key, nod->right);//RECURSIONTraverse right till find a null
node
else {//NULL node found
nod->right = new node;//Create new node
nod->right->data = key;//set NODE data to KEY
nod->right->right = NULL;
nod->left = NULL;
}
}
}
node *bTree::search(int key, node *leaf)
{
if(leaf!=NULL)
{
if(key==leaf->data)
return leaf;
if(key<leaf->data)
return search(key, leaf);
else
return search(key, leaf->right);
}
else return NULL;
}
void bTree:: destroyTree(node*&node){
if(node==NULL){
destroyTree(node->left);
destroyTree(node->right);
delete node;
}
}
int main() {
bTree *trees=new bTree();
trees->addNode(10);
trees->addNode(6);
trees->addNode(14);
node *check;
}
The first thing your addNode function with signature void bTree::addNode(int key, node* nod) does is this:
if (key < nod->left->data) {
The problem with your code is that nod->left will lead to a crash, since the left node has not been initialized and leads to an unauthorized memory access, or what is called a segmentation fault. Let's go through the main loop.
addNode(10) - The addNode function with signature void bTree::addNode(int key) is called, root is null, so root is created with left and right nodes set to NULL.
addNode(6) - The addNode function with signature void bTree::addNode(int key) is called, root is NOT null, so addNode with signature void bTree::addNode(int key, node* nod) is called. Then nod->left, and crash.
This is a common problem in low level programming, and my advice to you is to put debug prints inside the functions to see which parameters entered, and where exactly the code crashed. If you can pinpoint the exact line that leads to the crash (in thise case the line with nod->left) you can solve these kinds of problems more easily in the future.
In order to fix your issue, simply make sure to initialize the left and right nodes before you access them.

QtInputContextFactory returning NULL on embedded target

On my embedded system I don't have X11, Mac, Win, S60, etc. I keep getting a NULL ( 0 ) pointer returned from the create method of the QInputContextFactory class. I verified that QT_NO_LIBRARY is not defined.
On my Desktop Qt Build this works just fine.
I also verified that my custom key and parent are being passed to the method.
What could cause this to fail? -->
if (QInputContextFactoryInterface *factory =
qobject_cast<QInputContextFactoryInterface*>(loader()->instance(key))) {
result = factory->create(key);
}
Here is the entire method:
QInputContext *QInputContextFactory::create( const QString& key, QObject *parent )
{
QInputContext *result = 0;
#if defined(Q_WS_X11) && !defined(QT_NO_XIM)
if (key == QLatin1String("xim")) {
result = new QXIMInputContext;
}
#endif
#if defined(Q_WS_WIN)
if (key == QLatin1String("win")) {
result = new QWinInputContext;
}
#endif
#if defined(Q_WS_MAC)
if (key == QLatin1String("mac")) {
result = new QMacInputContext;
}
#endif
#if defined(Q_WS_S60)
if (key == QLatin1String("coefep")) {
result = new QCoeFepInputContext;
}
#endif
#ifdef QT_NO_LIBRARY
Q_UNUSED(key);
#else
qDebug() << "Here we are";
if (QInputContextFactoryInterface *factory =
qobject_cast<QInputContextFactoryInterface*>(loader()->instance(key))) {
result = factory->create(key);
}
#endif
if (result)
result->setParent(parent);
return result;
}
Within Qt, the QInputContextFactory class is front-end on loading input context plug-ins. It will fail to load an input context plug-in if it fails to exist, or hasn't been deployed properly. Input context plug-ins are typically stored under $QT_PLUGIN_PATH/inputmethods. As such, if there is no plug-in within that directory, the create method of the QInputContextFactory will return NULL.
Of note, Qt does provide a few mechanisms for customizing the location of plug-ins. Refer to the following for more detail on this:
http://qt-project.org/doc/qt-4.8/deployment-plugins.html

passing a HANDLE variable to an unmanaged .dll in C++/CLI

I am trying to wrap an unmanaged c++ dll that talks to a video capture card in c++/CLI so i can reference the functions from a c# project that i have. I am having trouble getting the 1st wrapped call to work as I am new to c++/cli syntax. here is what i have.
here is the function declataion i am trying to wrap.
__declspec(dllimport) BOOL AZ_DeviceCreate(HANDLE& hLiveEvent, DWORD* hEncoderEvent, DWORD* pdwEncoderAddress, HANDLE& hAudioEvent, DWORD& dwAudioAddress);
here is my c++/cli .h file
namespace CaptureLibrary
{
public ref class CaptureCard
{
public:
HANDLE m_hLiveEvent;
DWORD *m_hEncoderEvent;
HANDLE m_hAudioEvent;
public:
CaptureCard();
bool CreateDevice();
void DisposeDevice();
};
}
and my .cpp
namespace CaptureLibrary
{
CaptureCard::CaptureCard()
{
m_hLiveEvent = INVALID_HANDLE_VALUE;
m_hEncoderEvent = new DWORD[MAX_VIDEO_CHANNEL];
for (BYTE i=0;i<MAX_VIDEO_CHANNEL;i++)
{
m_hEncoderEvent[i] = (DWORD)INVALID_HANDLE_VALUE;
}
m_hAudioEvent = INVALID_HANDLE_VALUE;
}
bool CaptureCard::CreateDevice()
{
DWORD dwEncoderBuff[MAX_VIDEO_CHANNEL];
DWORD dwACaptureBuffer = 0;
if(AZ_DeviceCreate(m_hLiveEvent, m_hEncoderEvent, dwEncoderBuff, m_hAudioEvent, dwACaptureBuffer)==FALSE)
{
return false;
}
return true;
}
void CaptureCard::DisposeDevice()
{
AZ_DeviceClose();
}
}
when i compile this with the required headers, i get this error:
error C2664: 'AZ_DeviceCreate' : cannot convert parameter 1 from 'HANDLE' to 'HANDLE &'
Can anyone help me as I know this is a stupid syntax thing that I am doing wrong.
Thanks in advance.
I mean this constructively: you're off on the wrong foot. Your goal with C++/CLI here is to wrap the unmanaged library in a manner that won't seem foreign in .NET, but your CaptureCard class doesn't do that.
Don't expose fields, expose properties (I assume they should be get-only for CaptureCard's members)
Don't expose raw pointer types (e.g. HANDLE), expose IntPtr
Don't expose raw C-arrays (e.g. DWORD*), expose array<T>^, ReadOnlyCollection<T>^, or IEnumerable<T>^ (but don't expose array<T>^s intended to be read-only via properties, only via methods + Array::Copy)
Don't only expose a DisposeDevice method, also make the class actually implement IDisposable so the device can be closed with a using statement rather than forcing use of try..finally
As the class controls unmanaged resources, it needs a finalizer
.h:
namespace CaptureLibrary
{
public ref class CaptureCard sealed
{
public:
CaptureCard();
~CaptureCard();
!CaptureCard();
property IntPtr LiveEvent { IntPtr get(); }
property IEnumerable<DWORD>^ EncoderEvent { IEnumerable<DWORD>^ get(); }
property IntPtr AudioEvent { IntPtr get(); }
bool CreateDevice();
void DisposeDevice();
private:
bool m_bOpened;
IntPtr m_hLiveEvent;
array<DWORD>^ m_hEncoderEvent;
IntPtr m_hAudioEvent;
};
}
.cpp:
namespace CaptureLibrary
{
CaptureCard::CaptureCard()
: m_hLiveEvent(INVALID_HANDLE_VALUE),
m_hEncoderEvent(gcnew array<DWORD>(MAX_VIDEO_CHANNEL)),
m_hAudioEvent(INVALID_HANDLE_VALUE)
{
for (int i = 0, i_max = m_hEncoderEvent->Length; i != i_max; ++i)
m_hEncoderEvent[i] = reinterpret_cast<DWORD>(INVALID_HANDLE_VALUE);
}
CaptureCard::~CaptureCard()
{
this->!CaptureCard();
}
CaptureCard::!CaptureCard()
{
DisposeDevice();
}
IntPtr CaptureCard::LiveEvent::get()
{
return m_hLiveEvent;
}
IEnumerable<DWORD>^ CaptureCard::EncoderEvent::get()
{
return m_hEncoderEvent;
}
IntPtr CaptureCard::AudioEvent::get()
{
return m_hAudioEvent;
}
bool CaptureCard::CreateDevice()
{
DisposeDevice();
DWORD dwAudioAddress = 0u;
DWORD dwEncoderAddress[MAX_VIDEO_CHANNEL];
HANDLE hLiveEvent = m_hLiveEvent.ToPointer();
HANDLE hAudioEvent = m_hAudioEvent.ToPointer();
{
pin_ptr<DWORD> hEncoderEvent = &m_hEncoderEvent[0];
m_bOpened = AZ_DeviceCreate(hLiveEvent, hEncoderEvent, dwEncoderAddress, hAudioEvent, dwAudioAddress) == TRUE;
}
m_hLiveEvent = IntPtr(hLiveEvent);
m_hAudioEvent = IntPtr(hAudioEvent);
return m_bOpened;
}
void CaptureCard::DisposeDevice()
{
if (m_bOpened)
{
AZ_DeviceClose();
m_bOpened = false;
}
}
}
Suggestions for further improvement:
Get rid of CreateDevice and DisposeDevice altogether. This code has a very C-ish mentality; .NET users would expect a constructed object to have a meaningful value without calling a separate initialization function, so assuming AZ_DeviceCreate is not expected to fail regularly then CreateDevice's logic should go straight in the class' constructor and an exception should be thrown upon failure
If calling AZ_DeviceClose multiple times is harmless then get rid of m_bOpened altogether
The problem here is that you are trying to pass m_hLiveHandle as a reference (i.e. HANDLE &), but this would require that m_hLiveHandle could be pointed to by a native pointer (i.e. it would be guaranteed not to move in memory). However, m_hLiveHandle is a member of a ref class (CaptureCard) which means instances of it are stored on the managed heap. This in turn means that the instance of CaptureCard can be moved in memory (by a garbage collection action). So, if you want to use m_hLiveHandle as a pointer parameter or reference parameter, you'd have to use pin_ptr to tell the garbage collector not to move this object during the duration of the call to the native method. Read up here for more:
http://msdn.microsoft.com/en-us/library/1dz8byfh(v=vs.80).aspx

Call by reference with QVector

I have in an Object an QVector of Coordinates (my type) that I want to transfer to an other Vector ( I validate and than want to use ist ).
Header
bool getVector(QVector<Coordinates> &getCoordinates );
C File
static QVector<Coordinates> current;
int getVector( QVector<Coordinates> &getCoordinates)
{
.... stuff ...
getCoordinates = current;
.... stuff ....
return 0;
}
And I use it like
....
QVector<Coordinates> currentCoordinates;
getVector(currentCoordinates);
currentCoordinates.X // CRASH
The debugger goes to this line where an Live Crash happens
inline QVector(const QVector<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
So my how can I fix this? As I can use this to get all the other Variables with this methode.
A likely cause of your problem is that current has not been constructed before getVector is called. Initialization of static objects in C++ is a thorny area, and a frequent source of bugs - for more information, see this question, and the static initialization order fiasco FAQ entry.
A simple solution to this problem is to provide access to current via a function, i.e. replace
static QVector<Coordinates> current;
with
static QVector<Coordinates>& getCurrent()
{
static QVector<Coordinates> current;
return current;
}
Note, however, that the function as written above is not thread-safe. If multiple threads may call getCurrent, then it should be protected with a QMutex.
For gareth and the Forum :
the header:
typedef QVector<Coordinates> VesselCoordinates;
bool (*getVessel)(Charakter forCharakter, Vessel& getVessel,VesselCoordinates &getCoordinates );
later i bind tis function pointer to an static function ( cause this part of my Program will be one day convertet to c)
cpp file lower layer:
static struct {
Charakter currentPlayerVessel;
VesselCoordinates possibility;
}data;
static bool getVessel(Charakter forCharakter, Vessel& getVessel,VesselCoordinates &getCoordinates );
// funktion to bind the funktion pointer to this static funktion so it can be called outside the File
static bool serverNamespace::getVessel(Charakter forCharakter, Vessel& getVessel,VesselCoordinates &getCoordinates )
{
bool retValue= false;
if ( forCharakter == data.currentPlayerVessel){
// TODO abfragen ob die Adresse regestriert ist!
if ((true == minSize()) and ((true == shipsInRow())or (true == shipsInLine())))
{
retValue = true;
Vessel test = (Vessel)data.possibility.size();
getVessel = test;
getCoordinates = data.possibility;
}
}
return retValue;
}
And then i can use this in the upper layer cpp file to get the information i need:
// in an Funktion :
VesselCoordinates currentCoordinates;
currentCoordinates.clear();
Vessel currentVessel;
if (true == basicFleet->getVessel(currentCharakter,currentVessel, currentCoordinates ))
// doing stuff to it
so its worik fine but your idea worked just as fine. Maybe you can see why my idea is also working.
Thank you
elektor

Resources