Accidently deleting entire linked list when trying to delete the head - visual-c++

I'm working on a checker's simulation game for my C++ class. My issue is with the linked list that holds the checkers. I can delete any checker perfectly with the exception of the head of the list. I've looked around here and other websites and I believe there's a memory leak somewhere. I'm fairly new to C++ so I'm not sure what to really do other than playing around with things (which will probably just create a bigger problem). I've never posted here before, so excuse me if the formatting is slightly off or too messy. I'll try to make it brief. First, here's a snippet of the node class for the linked list.
class CheckerpieceNode
{
private:
Checkerpiece *Node;
CheckerpieceNode *Next;
public:
CheckerpieceNode(); // sets Node and Next to NULL in .cpp file
void setNode(Checkerpiece *node);
void setNext(CheckerpieceNode *next);
Checkerpiece* getNode();
CheckerpieceNode* getNext();
};
And the functions are set up pretty much as you would expect in a Checkerpiece.cpp class.
Here's how the code is used. Its called by a Checkerboard object in my main class.
theCheckerboard.removeChecker(theCheckerboard.findChecker(selector->getCurrentX() + 0, selector->getCurrentY() - VERTICAL_SHIFT, listHead), listHead);
The VERTICAL_SHIFT simply has to do with the way my checkerboard graphic is on the console. Since it works perfectly for all other nodes (excluding the head) I've ruled it out as a source of error. Selector is a checkerpiece object but its not part of the list.
Here's the actual findChecker and removeChecker code from Checkerboard class.
Checkerpiece* findChecker(int x, int y, CheckerpieceNode* list_head)
{
if(list_head== NULL) return NULL; // do nothing
else
{
CheckerpieceNode* node = new CheckerpieceNode;
node = list_head;
while(node != NULL && node->getNode() != NULL)
{
if()// comparison check here, but removed for space
{
return node->getNode();
delete node;
node = NULL;
}
else // traversing
node = node->getNext();
}
return NULL;
}
}
void removeChecker(Checkerpiece* d_checker, CheckerpieceNode* list_head)
{
if(list_head== NULL) // throw exception
else
{
CheckerpieceNode *temp = NULL, *previous = NULL;
Checkerpiece* c_checker= new Checkerpiece;
temp = list_head;
while(temp != NULL && temp->getNode() != NULL)
{
c_checker= temp->getNode();
if(d_checker!= c_checker)
{
previous = temp;
temp = temp->getNext();
}
else
{
if(temp != list_head)
{
previous->setNext(temp->getNext());
delete temp;
temp = NULL;
}
else if(temp == list_head) // this is where head should get deleted
{
temp = list_head;
list_head= list_head->getNext();
delete temp;
temp = NULL;
}
return;
}
}
}
}

Oh my, you're complicating it. Lots of redundant checks, assignments and unnecessary variables (like c_checker which leaks memory too).
// Write down the various scenarios you can expect first:
// (a) null inputs
// (b) can't find d_checker
// (c) d_checker is in head
// (d) d_checker is elsewhere in the list
void removeChecker(Checkerpiece* d_checker, CheckerpieceNode* list_head) {
// first sanitize your inputs
if (d_checker == nullptr || list_head == nullptr) // use nullptr instead of NULL. its a keyword literal of type nullptr_t
throw exception;
// You understand that there is a special case for deleting head. Good.
// Just take care of it once and for all so that you don't check every time in the loop.
CheckerpieceNode *curr = list_head;
// take care of deleting head before traversal
if (d_checker == curr->getNode()) {
list_head = list_head->next; // update list head
delete curr; // delete previous head
return; // we're done
}
CheckerpieceNode *prev = curr;
curr = curr->next;
// traverse through the list - keep track of previous
while (curr != nullptr) {
if (d_checker == curr->getNode()) {
prev->next = curr->next;
delete curr;
break; // we're done!
}
prev = curr;
curr = curr->next;
}
}
I hope that helps. Take the time to break down the problem into smaller pieces, figure out the scenarios possible, how you'll handle them and only then start writing code.

Based on this edit by the question author, the solution he used was to:
I modified the code to show the address passing in the checker delete
function.
void delete_checker(Checker* d_checker, CheckerNode* &list_head) // pass by address
{
if(list_head== NULL) // throw exception
else
{
CheckerNode*temp = NULL, *previous = NULL;
Checker* c_checker= new Checker;
temp = list_head;
while(temp != NULL && temp->node!= NULL)
{
c_checker= temp->node;
if(d_checker!= c_checker)
{
previous = temp;
temp = temp->next;
}
else
{
if(temp != list_head)
{
previous->next = temp->next;
delete temp;
temp = NULL;
}
else if(temp == list_head) // this is where head should get deleted
{
temp = list_head;
list_head= list_head->next;
delete temp;
temp = NULL;
}
delete c_checker;
c_checker = nullptr;
return;
}
}
}
}

removeChecker cannot modify the value of list_head as it is past by value. The method signature should be:
void removeChecker(Checkerpiece* d_checker, CheckerpieceNode** list_head)
// You will need to call this function with &list_head
or
void removeChecker(Checkerpiece* d_checker, CheckerpieceNode* &list_head)
// Calling code does not need to change

Related

How do i delete any item from a linked list?

I'm trying to write a function that deletes an element at a given position from a linked list, for now im using a linked list with only a head pointer. Now it may be that the user inputs a position that is larger than the size of the linked list so to remedy that i wrote this:
int delete(struct node** head, int pos)
{
struct node* temp = *head;
while(pos!=0 && temp->next!=NULL)
{
temp=temp->next;
pos--;
}
if(pos>0)
return 0;
}
but it gives the following error
fish: './a.out' terminated by signal SIGSEGV (Address boundary error)
i tried to debug it by writing a new code
int delete(struct node** head)
{
if((*head)->next==NULL)
return 1;
}
but it gives the same error
When head is NULL the evaluation of temp->next will give undefined behaviour or the error as you experienced.
However, there is more to correct to your function.
There is no deletion happening. To delete a node, its predecessor should have its next property update to point to the node after the removed node. The removed node should then be freed.
The value of *head should be modified when the first node of the list is removed.
The function should return an int, and so also when the deletion was successful (and pos == 0 after the loop), there should be a return that is executed, probably returning 1 to indicate success.
Not a problem, but I would advise using a different name for your function. If ever you move to C++, then delete will be a reserved word.
So:
int removeNode(struct node** head, int pos) {
if (*head == NULL) {
return 0;
}
struct node* temp = *head;
if (pos == 0) { // Case where first node must be removed
*head = (*head)->next; // Modify head reference
free(temp);
return 1; // Indicate success
}
while (pos > 1 && temp->next != NULL) {
temp = temp->next;
pos--;
}
if (pos != 1 || temp->next == NULL) {
return 0; // Invalid position
}
// Remove the node
struct node* prev = temp;
temp = temp->next;
prev->next = temp->next;
free(temp);
return 1; // Indicate success
}
as #paddy commented,
i didn't consider the case where head itself is pointing to NULL.
a simple if statement solved it
struct node* temp = *head;
if(temp==NULL){
printf("Empty LL\n");
free(temp);
return 0;
}

Problem using TVN_SELCHANGED seems to go in a continuous cycle

I have this event handler in a modelless popup dialog tree control:
void CAssignHistoryDlg::OnTvnSelchangedTreeHistory(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
if (!m_bBuildTreeMode)
{
if ((pNMTreeView->itemOld.hItem == nullptr && !m_bFirstSelChangeEvent) ||
pNMTreeView->itemOld.hItem != nullptr)
{
m_bFirstSelChangeEvent = true;
if (m_treeHistory.GetParentItem(pNMTreeView->itemNew.hItem) == nullptr)
{
// We must update the correct combo
// and associated string (in the SERVMEET_S structure)
if (m_pCombo != nullptr && m_pStrText != nullptr)
{
CString strExtractedName = ExtractName(pNMTreeView->itemNew.hItem);
m_pCombo->SetWindowText(strExtractedName);
*m_pStrText = strExtractedName;
}
GetParent()->PostMessage(UM_SM_EDITOR_SET_MODIFIED, (WPARAM)TRUE);
}
}
}
*pResult = 0;
}
What I don't understand is why once this event is triggered is that it goes in a continuous cycle.
Does anything jump out at you as wrong?
I don't know why the message seemed to be going in a continuous cycle. Maybe it was because I was inserting breakpoints or adding temporary popup message boxes to debug. Either way, I worked out the minor adjustment I needed:
void CAssignHistoryDlg::OnTvnSelchangedTreeHistory(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
if (!m_bBuildTreeMode)
{
if ((pNMTreeView->itemOld.hItem == nullptr && !m_bFirstSelChangeEvent) ||
pNMTreeView->itemOld.hItem != nullptr)
{
m_bFirstSelChangeEvent = true;
if (m_treeHistory.GetParentItem(pNMTreeView->itemNew.hItem) == nullptr)
{
// We must update the correct combo
// and associated string (in the SERVMEET_S structure)
if (m_pCombo != nullptr && m_pStrText != nullptr)
{
CString strExtractedName = ExtractName(pNMTreeView->itemNew.hItem);
m_pCombo->SetWindowText(strExtractedName);
// Bug fix - Only set as modified if the name is different
if(*m_pStrText != strExtractedName)
GetParent()->PostMessage(UM_SM_EDITOR_SET_MODIFIED, (WPARAM)TRUE);
*m_pStrText = strExtractedName;
}
}
}
}
*pResult = 0;
}
As you can see, I have changed how and where I post the UM_SM_EDITOR_SET_MODIFIED message. This causes my application to work correctly. Previously it was always setting it as modified (multiple times). So even if you had just saved the file, it then was marked as modified again. This problem no longer happens.

lotus.domino.local.Item cannot be cast to lotus.domino.RichTextItem

I try to put a file into a richtext but it crashes !
In my first code, I try to use directly "getFirstItem", in first time it was ok but now i try to use it again and it crashed.
In second time i pass with an object and it find my obj doesn't an richtextItem (instanceof) ???
I don't understand.
I have the message : "lotus.domino.local.Item cannot be cast to lotus.domino.RichTextItem" ?
Could you help me ?
public void copieFichierDansRichText(String idDocument, String nomRti, File file,
String nameFichier, String chemin) throws NotesException {
lotus.domino.Session session = Utils.getSession();
lotus.domino.Database db = session.getCurrentDatabase();
lotus.domino.Document monDoc = db.getDocumentByUNID(idDocument);
lotus.domino.RichTextItem rtiNew = null;
try {
try {
if (monDoc != null) {
// if (monDoc.getFirstItem(nomRti) != null) {
// rtiNew = (lotus.domino.RichTextItem)
// monDoc.getFirstItem(nomRti);
// } else {
// rtiNew = (lotus.domino.RichTextItem)
// monDoc.createRichTextItem(nomRti);
// }
Object obj = null;
if (monDoc.getFirstItem(nomRti) != null) {
obj = monDoc.getFirstItem(nomRti);
if (obj instanceof lotus.domino.RichTextItem) {
rtiNew = (lotus.domino.RichTextItem) obj;
}
} else {
obj = monDoc.createRichTextItem(nomRti);
if (obj instanceof lotus.domino.RichTextItem) {
rtiNew = (lotus.domino.RichTextItem) obj;
}
}
PieceJointe pieceJointe = new PieceJointe();
pieceJointe = buildPieceJointe(file, nameFichier, chemin);
rtiNew.embedObject(EmbeddedObject.EMBED_ATTACHMENT, "", pieceJointe.getChemin()
+ pieceJointe.getNomPiece(), pieceJointe.getNomPiece());
monDoc.computeWithForm(true, false);
monDoc.save(true);
}
} finally {
rtiNew.recycle();
monDoc.recycle();
db.recycle();
session.recycle();
}
} catch (Exception e) {
e.printStackTrace();
}
}
EDIT : I try to modify my code with yours advices but the items never considerate as richtextitem. It is my problem. I don't understand why, because in my field it is a richtext ! For it, the item can't do :
rtiNew = (lotus.domino.RichTextItem) item1;
because item1 not be a richtext !!!
I was trying to take all the fields and pass in the item one by one, and it never go to the obj instance of lotus.domini.RichTextItem....
Vector items = doc.getItems();
for (int i=0; i<items.size(); i++) {
// get next element from the Vector (returns java.lang.Object)
Object obj = items.elementAt(i);
// is the item a RichTextItem?
if (obj instanceof RichTextItem) {
// yes it is - cast it as such // it never go here !!
rt = (RichTextItem)obj;
} else {
// nope - cast it as an Item
item = (Item)obj;
}
}
A couple of things. First of all I would set up a util class method to handle the object recycling in a neater way:
public enum DominoUtil {
;
public static void recycle(Base... bases) {
for (Base base : bases) {
if (base != null) {
try {
base.recycle();
} catch (Exception e) {
// Do nothing
}
}
}
}
}
Secondly I would remove the reduntants try/catch blocks and simplify it like this:
private void copieFichierDansRichText(String idDocument, String nomRti, File file,
String nameFichier, String chemin) {
Session session = DominoUtils.getCurrentSession();
Database db = session.getCurrentDatabase();
Document monDoc = null;
try {
monDoc = db.getDocumentByUNID(idDocument);
Item item = monDoc.getFirstItem(nomRti);
if (item == null) {
item = monDoc.createRichTextItem(nomRti);
} else if (item.getType() != Item.RICHTEXT) {
// The item is not a rich text item
// What are you going to do now?
}
RichTextItem rtItem = (RichTextItem) item;
PieceJointe pieceJointe = new PieceJointe();
pieceJointe = buildPieceJointe(file, nameFichier, chemin);
rtItem.embedObject(EmbeddedObject.EMBED_ATTACHMENT, "", pieceJointe.getChemin()
+ pieceJointe.getNomPiece(), pieceJointe.getNomPiece());
monDoc.computeWithForm(true, false);
monDoc.save(true);
} catch (NotesException e) {
throw new FacesException(e);
} finally {
DominoUtil.recycle(monDoc);
}
}
Finally, apart from the monDoc, you need not recycle anything else. Actually Session would be automatically recycled and anything beneath with it (so no need to recycle db, let alone the session!, good rule is don't recycle what you didn't instantiate), but it's not bad to keep the habit of keeping an eye on what you instantiate. If it were a loop with many documents you definitively want to do that. If you also worked with many items you would want to recycle them as early as possible. Anyway, considered the scope of the code it's sufficient like this. Obviously you would call DominoUtil.recycle directly from the try block. If you have multiple objects you can recycle them at once possibly by listing them in the reverse order you set them (eg. DominoUtil.recycle(item, doc, view)).
Also, what I think you miss is the check on the item in case it's not a RichTextItem - and therefore can't be cast. I put a comment where I think you should decide what to do before proceeding. If you let it like that and let the code proceed you will have the code throw an error. Always better to catch the lower level exception and re-throw a higher one (you don't want the end user to know more than it is necessary to know). In this case I went for the simplest thing: wrapped NotesException in a FacesException.

Natively buffering audio

This probably is one of my own mistakes, but I can't seem to find what is wrong. After trying to improve performance of my application, I moved audio buffering from the Java layer to the native layer. Audio handling (recording/playing) is already done natively using the OpenSL ES API.
Yet the native buffering is causing my application to crash whenever I start the application. I use a simple Queue implementation as my buffer, where the first node is the oldest data (FIFO).
struct bufferNode{
struct bufferNode* next;
jbyte* data;
};
struct bufferQueue{
struct bufferNode* first;
struct bufferNode* last;
int size;
};
The audio data is referred to by the jbyte* in the bufferNode. Access to the Queue is done via these two methods, and is synchronized with a mutex.
void enqueueInBuffer(struct bufferQueue* queue, jbyte* data){
SLresult result;
if(queue != NULL){
if(data != NULL){
result = pthread_mutex_lock(&recMutex);
if(result != 0){
decodeMutexResult(result);
logErr("EnqueueInBuffer", "Unable to acquire recording mutex");
} else {
struct bufferNode* node = (struct bufferNode*)malloc(sizeof(struct bufferNode));
if(node == NULL){
logErr("EnqueueInBuffer", "Insufficient memory available to buffer new audio");
} else {
node->data = data;
if(queue->first == NULL){
queue->first = queue->last = node;
} else {
queue->last->next = node;
queue->last = node;
}
queue->size = queue->size + 1;
node->next = NULL;
}
}
result = pthread_mutex_unlock(&recMutex);
if(result != 0){
decodeMutexResult(result);
logErr("EnqueueInBuffer", "Unable to release recording mutex");
}
} else {
logErr("EnqueueInBuffer", "Data is NULL");
}
} else {
logErr("EnqueueInBuffer", "Queue is NULL");
}
}
void dequeueFromBuffer(struct bufferQueue* queue, jbyte* returnData){
SLresult result;
result = pthread_mutex_lock(&recMutex);
if(result != 0){
decodeMutexResult(result);
logErr("DequeueFromBuffer", "Unable to acquire recording mutex");
} else {
if(queue->first == NULL){
returnData = NULL;
} else {
returnData = queue->first->data;
struct bufferNode* tmp = queue->first;
if(queue->first == queue->last){
queue->first = queue->last = NULL;
} else {
queue->first = queue->first->next;
}
free(tmp);
queue->size = queue->size - 1;
}
}
result = pthread_mutex_unlock(&recMutex);
if(result != 0){
decodeMutexResult(result);
logErr("DequeueFromBuffer", "Unable to release recording mutex");
}
}
Where the log and decode methods are selfdeclared utility methods. Log just logs the message to the logcat, while the decode methods "decode" any error number possible from the previous method call.
Yet I keep getting an error when I try to enqueue audio data. Whenever I call the enqueueInBuffer method, I get a SIGSEGV native error, with code 1 (SEGV_MAPERR). Yet I can't seem to find what is causing the error. Both the Queue and the audio data exist when I try to make the enqueueInBuffer method call (which is done in an OpenSL ES Recorder callback, hence the synchronization).
Is there something else going on what causes the segmentation fault? Probably I am responsible for it, but I can't seem to find the error.
Apparently, this was caused by a line of code I have in my OpenSL ES Recorder callback.
The callback originally looked like this:
void recorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context){
SLresult result;
enqueueInBuffer(&recordingQueue, (*recorderBuffers[queueIndex]));
result = (*bq)->Enqueue(bq, recorderBuffers[queueIndex], RECORDER_FRAMES * sizeof(jbyte));
if(checkError(result, "RecorderCallB", "Unable to enqueue new buffer on recorder") == -1){
return;
}
queueIndex = queueIndex++ % MAX_RECORDER_BUFFERS;
}
However, it seems that the last line of the callback didn't correctly create the new index. The buffers I use are in an array, which is 4 long.
Changing the last line to
queueIndex = (queueIndex + 1) % MAX_RECORDER_BUFFERS;
seems to have fixed the error.

Comparing pointers fails mystically in VC++

I have a tree structure and I want to find all nodes matching a given criteria. Each time I call the find function, it returns next matching node. Children are searched by recursive function call.
For some reason a key comparison of pointers fails for this implementation. Please see the code below, I have pointed out the failing comparison.
HtmlTag* HtmlContent::FindTag(string tagName, string tagParameterContent)
{
if (tagName.empty() && tagParameterContent.empty())
return NULL;
if (this->startTag == NULL)
return NULL;
this->findContinue = this->FindChildren(this->startTag, &tagName, &tagParameterContent);
return this->findContinue;
}
HtmlTag* HtmlContent::FindChildren(HtmlTag* firstTag, string* tagName, string* tagParameterContent)
{
HtmlTag* currentTag = firstTag;
HtmlTag* childrenFound = NULL;
while (currentTag != NULL)
{
if (!tagName->empty() && *tagName == currentTag->tagName)
{
if (tagParameterContent->empty() || currentTag->tagParameters.find(*tagParameterContent, 0) != -1)
{
if (this->findContinue == NULL)
break; // break now when found
else if (this->findContinue == currentTag) // TODO why this fails?
this->findContinue == NULL; // break on next find
}
}
if (currentTag->pFirstChild != NULL)
{
childrenFound = this->FindChildren(currentTag->pFirstChild, tagName, tagParameterContent);
if (childrenFound != NULL)
{
currentTag = childrenFound;
break;
}
}
currentTag = currentTag->pNextSibling;
}
return currentTag;
}
VC++ compiler accepts this code but for some reason I can't put a breakpoint on this comparison. I guess this is optimized out, but why? Why this comparison fails?
I think that you shoud replace == with = in assignment after comparison. Compiler optimalized this whole section because it doesnt do anything useful.

Resources