Pop consecutive items on a stack if value is the same - c

For my program I have a stack of strings and I'm trying to pop the value at the top, but if the next string on the stack has the same name I want to pop that one too and so on until all the ones on top with that name are gone. I'm probably butchering the implementation so can someone guide me in the right direction?
char *dropoff(struct stack *tosPtr)
{
printf("current tos is %s\n", tosPtr->name);
if(tosPtr == NULL)
return STACK_IS_EMPTY;
while(strcmp(tosPtr->name, tosPtr->next->name) == 0) {
stack *oldBox = tosPtr;
tosPtr = tosPtr->next;
if(oldBox == tosPtr)
tosPtr = NULL;
free(oldBox);
}
return tosPtr;
}

Looks like you are close. You forgot to remove the first word (you state you want to do this regardless). Then your while is nearly there. Also you are comparing two pointers that should always be un-equal (tosPtr and tosPtr->next) - unless there should be some circular reference you did not mention?
struct stack *dropoff(struct stack *tosPtr) {
printf("current tos is %s\n", tosPtr->name);
if(tosPtr == NULL)
return STACK_IS_EMPTY;
struct stack *oldBox = tosPtr;
tosPtr = tosPtr->next;
//Double check in while we didn't hit bottom of stack
while(tosPtr && strcmp(oldBox->name, tosPtr->name) == 0) {
free(oldBox); //Maybe need to free oldBox->name as well?!
oldBox = tosPtr;
tosPtr = tosPtr->next;
}
//One node left to free - maybe name?
free(oldBox);
return tosPtr ? tosPtr : STACK_IS_EMPTY; //Return empty stack if needed
}
Note you need struct in the variable definition as well if you did not typedef it, and I guess you did not because the argument is defined that way. If the name was mallocd you would need to free it is well before freeing the stack node.

Related

Popping a value from one stack and Pushing to another using C

I am currently learning some C and have created a basic connect 4 game. I am trying to now implement a undo/redo function, I have created a stack using an array basically saving every move made by each player. I can push moves and pop moves to and from the stack, so the undo part I can get working, the redo part is where I'm struggling. I am wondering if I can create a temp stack and when I Pop from my master stack I can push to this temp one? In my head this will then allow me to redo moves as well.
I can't find any decent examples that explain this very well and am just looking for a point in the right direction if anyone has created something similar? Also if there is a more efficient method I'm completely open to that also.
Thank you in advance
<>
void push2(int y)
{
if(top2 == MAX_SIZE2 -1) { // stack full case.
printf("Error: stack is full\n");
return;
}
top2 = top2 + 1;
stack2[top2] = y;
//A[++top] = y;
}
// Pop operation to remove an element from top of first stack.
void pop()
{
push2(top); //add to second stack
if(top == -1) { // If stack is empty, throw error.
printf("Error: No items to pop\n");
return;
}
//x = stack[top];
//top = top - 1;
top--;
}
I think changing push2(top); to push2(stack[top]); might help.
Your top variable seems to be an index variable, therefore it makes only sense in the context of stack

Clear the last element from a linked list

I am working on a C program which has a linked list. I need to remove the last element from the linked list and it is mostly working except when it hits particular part of my code it then has a segmentation fault.
The code that I have is as follows:
int clearOutboundLegFromList(callLogSearchOutboundStruct ** outboundLeg, int dataCol, int rowTargets)
{
//callLogSearchOutboundStruct *currentStruct = *outboundLeg;
//callLogSearchOutboundStruct *temp;
if (*outboundLeg == NULL)
{
return 0;
}
SL_DebugAll(DBG_ALWAYS, "DEBUG: Clearing outbound legs: DataCol: %i RowTargets: %i",
dataCol, rowTargets);
callLogSearchOutboundStruct *legToRemove = NULL;
callLogSearchOutboundStruct *last = NULL;
legToRemove = *outboundLeg;
while (legToRemove->nextLeg != NULL)
{
last = legToRemove;
legToRemove = legToRemove->nextLeg;
}
if (legToRemove->target != NULL)
{
free(legToRemove->target);
legToRemove->target = NULL;
}
if (legToRemove->cleardownCause)
{
free(legToRemove->cleardownCause);
legToRemove->cleardownCause = NULL;
}
free(legToRemove);
if (last != NULL)
{
last->nextLeg = NULL;
}
legToRemove = NULL;
}
It crashes on the line of free(legToRemove->target);.
In the core dump I have the following:
Program terminated with signal 11, Segmentation fault.
#0 0x00b01336 in _int_free () from /lib/libc.so.6
Missing separate debuginfos, use: debuginfo-install cyrus-sasl-lib-2.1.23-13.el6_3.1.i686 glibc-2.12-1.132.el6_5.2.i686 keyutils-libs-1.4-4.el6.i686 krb5-libs-1.10.3-15.el6_5.1.i686 libcom_err-1.41.12-18.el6.i686 libcurl-7.19.7-37.el6_5.3.i686 libidn-1.18-2.el6.i686 libselinux-2.0.94-5.3.el6_4.1.i686 libssh2-1.4.2-1.el6.i686 mysql-libs-5.1.73-3.el6_5.i686 nspr-4.9.2-1.el6.i686 nss-3.14.0.0-12.el6.i686 nss-softokn-freebl-3.12.9-11.el6.i686 nss-util-3.14.0.0-2.el6.i686 openldap-2.4.23-31.el6.i686 openssl-1.0.1e-16.el6_5.14.i686 zlib-1.2.3-29.el6.i686
(gdb) bt
#0 0x00b01336 in _int_free () from /lib/libc.so.6
#1 0x0805cd0b in clearOutboundLegFromList (outboundLeg=0xb5de7984, dataCol=9, rowTargets=11) at performreport.c:6731
#2 0x08058f33 in processDrilldownData (reportParameterArray=..., csvFile=0x8e3fc78, HandleDB=0xbfca7a14, resultReport=0x8e457a8,
If I print from the core dump legToRemove->target gdb outputs the following:
$1 = 0x99235d8 ""
Now that looks like its a properly allocated memory space, it just contains an empty string so I don't understand why this would cause a segfault.
You don't show how your struct looks like or how you add legs to your linked list, but you have an error in your removal function that occurs if you remove the last node: In that case, your list head should be set to NULL.
This special case is the reason to pass the list head as pointer to pointer to leg: The function must be able to update the head when the first node is removed. If you don't do that, the value of the head in the calling function will be the same and it will refer to memory that you have just freed. It is illegal to access such memory.
So, an updated version of your code could look like this:
void clearOutboundLegFromList(callLogSearchOutboundStruct **outboundLeg)
{
callLogSearchOutboundStruct *last = NULL;
legToRemove = *outboundLeg;
if (legToRemove == NULL) return;
while (legToRemove->nextLeg) {
last = legToRemove;
legToRemove = legToRemove->nextLeg;
}
free(legToRemove->target);
free(legToRemove->cleardownCause);
free(legToRemove);
if (last) {
last->nextLeg = NULL;
} else {
*outboundLeg = NULL;
}
}
You need the explicit assignment at the end, because once you have initialised legToRemove, you are operating only with that local pointer.
If you are feeling more confident with double indirections via pointers to pointers, you could iterate to the end without local variabes:
void clearOutboundLegFromList(callLogSearchOutboundStruct **outboundLeg)
{
if (*outboundLeg == NULL) return;
while (*outboundLeg) {
outboundLeg = &(*outboundLeg)->nextLeg;
}
free((*outboundLeg)->target);
free((*outboundLeg)->cleardownCause);
free(*outboundLeg);
*outboundLeg = NULL;
}
This will update the head pointer automatically when the first element is removed. The idea here ist that outboundLeg points to the head node at the beginning and to the previous node's nextLeg pointer on subsequent iterations. The additional indirection via (*outboundLeg) is more or less the same as accessing a node via the nextLeg member, except for the first node, in which you access the pointer through the head node pointer.
(Distraction: Your code is overly cautious when freeing the member pointers. It is legal to free a null pointer; this doesn't do anything, but means that you don't have to check for NULL in client code. Such a check might still be good practice, because many functions won't take null pointers. Setting the member pointers to NULL is a good idea if these pointers were still around for some time. But you are going to free the containing struct anyway soon. Setting the pointers to NULL is a bit like cleaning the bathroom just before you tear down the house. Setting legToRemove to NULL at the end of the function doesn't do anything: The pointer will go out of scope anyway. That's just an aside and retionale for my shorter code. Your checks aren't wrong and it is better to be cautious.)

Whether code is read from top to bottom

I am creating a program in c which is based on a linked list, where every node (of struct) holds an integer and a pointer to the next node.
I use dynamic allocation (malloc) and deallocation (free) as new nodes are added and old nodes are deleted.
when a node is deleted a function named delete is called.
I discovered that the program crashes sometimes when this delete-function is called and I KNOW that its something with the pointers in the method but I dont know WHERE in the code (row number) and WHY this happends.
I am used to high-level languages such as Java and I am used to encircle the problem by putting print-syntax at certain places in the method just to reveal WHERE it crashes.
I thought I could do the same with c and with pointer because to my knowledge I beleive the code is read from top to bottom that is 1, 2, 3, 4, and so on. (maybe interrupt handlers behave another way?)
So in this function named delete I have gone so far by putting this printf() at the very beginning of the delete-function - and all the same the program crashes.
So my Question - is it really possible that its some syntax in the delete-function (when I loop pointers for instance) that causes the crash WHEN not even the printf() is printing?
Am I wrong when I believe that the program is executed from to to bottom - that is 1, 2, 3 ....
You can se my printf-function in the very beginning of delete-function
And by the way - how could I solve this problem when I get this cryptic crash message from windows? See the bitmap!!
Greatful for answers!!!
int delete(int data) {
printf("IN THE BEGINNING OF DELETE!!!");
int result = 0;
if (queueref.last != NULL) {
node *curr_ptr;
node *prev_ptr;
node *temp_ptr;
if (queueref.first->data == data) {
temp_ptr = queueref.first;
queueref.first = queueref.first->next;
destroy_node(temp_ptr);
result = 1;
if (queueref.first == NULL) {
queueref.last = NULL;
puts("queue is now empty!!!");
}
} else {
prev_ptr = queueref.first;
curr_ptr = queueref.first->next;
printf("prev_ptr: %d\n", prev_ptr);
printf("curr_ptr: %d\n", curr_ptr);
while(curr_ptr != NULL) {
if (curr_ptr->data == data) {
result = 1;
if (curr_ptr->next != NULL) {
temp_ptr = curr_ptr;
destroy_node(temp_ptr);
prev_ptr->next = curr_ptr->next;
} else {
temp_ptr = curr_ptr;
queueref.last = prev_ptr;
prev_ptr->next = NULL;
destroy_node(temp_ptr);
}
}
curr_ptr = curr_ptr->next;
prev_ptr = prev_ptr->next;
}
}
}
return result;
}
Common mistake, here's the deal. This
printf("IN THE BEGINNING OF DELETE!!!");
needs to be
printf("IN THE BEGINNING OF DELETE!!!\n");
^^ note the newline
The reason is because stdio does not flush stdout until it sees a newline. If you add that newline, you should see the printf when the code enters the function. Without it, the program could crash, the stdout buffer would not have been flushed and would not see the printf.
Your code seems to have lots of implementation flaws. As a general advice I would recommend using some standard well-tested queue support library and static code analyzers (in this case you would even find dynamic analyzer valgrind very helpful, I guess).
For example, if implementation of destroy_node(ptr) is equivalent to free(ptr), then your code suffers from referencing destroyed data (or ,in other words, garbage) in this code snippet:
while(curr_ptr != NULL) {
if (curr_ptr->data == data) {
result = 1;
if (curr_ptr->next != NULL) {
temp_ptr = curr_ptr;
destroy_node(temp_ptr);
prev_ptr->next = curr_ptr->next; //<- curr_ptr is still in stack
//or register, but curr->next
//is garbage
// what if curr_ptr is first node? did you forget to update queueref.first?
} else {
temp_ptr = curr_ptr;
queueref.last = prev_ptr;
prev_ptr->next = NULL;
destroy_node(temp_ptr);
}
// if you you need to destroy only one node - you can leave the loop here with break;
}
curr_ptr = curr_ptr->next; /// assigning garbage again if node is found
prev_ptr = prev_ptr->next;
The reason why using destroyed data can work in * most * (if I can say that, basically this is unpredictable) cases is that the chances that this memory can be reused by other part of program for dynamically allocated data can vary on timings and code flow.
PS
Regarding cryptic messages in the Windows box - when program crashes OS basically generates crashdump and prints registers (and dumps some relevant memory parts). Registers and memory dumps can show the place of crash and immediate register/stack values but you have to now memory map and assembler output to understand it. Crashdump can be loaded to debugger (WinDbg) together with unstripped binary to check stactrace and values of local variables at the moment of crash. All these I described very very briefly, you could find tons of books / guides searching for "windows crash or crashdump analysis"

Having trouble deleting elements in doubly linked list

I've been trying for about 5 hours to get this code to work properly, and the code is written based on hours of internet research.
I have modified it several times, all of which gave me segmentation faults, so this is the only version that runs.
What is happening, is that the code is cycling through, and deleting not only the element you want to get rid of, but all elements preceding it. So, if you want to delete the last element, everything in the list goes. Or, if you wanted to delete the second element, the first and second go, and so on.
It thinks that every name entered is the top name for some reason.
static void menu_delete_employee(void)
{
char deletename[MAX_NAME_LENGTH+1];
char namecheck[MAX_NAME_LENGTH+1];
int errorcheck = 0;
int foundit = 0;
fprintf(stderr, "Enter the name of the employee you wish to delete\n");
gets(deletename);
employee_list = top;
employee_list->name;
do
{
strcpy (namecheck, employee_list->name);
printf("namecheck = %s\n", namecheck);
errorcheck = (strcmp (namecheck, deletename));
printf("errorcheck = %i\n", errorcheck);
switch (errorcheck)
{
case 0:
{
printf("This is the right name\n");
foundit = 1;
if (employee_list->prev == NULL)
{
printf("top name\n");
top = employee_list->next;
}
else
{
if (employee_list->next == NULL)
{
printf("last one\n");
temp = employee_list->prev;
temp-> next = NULL;
free (employee_list);
}
else
{
printf("somewhere in the middle");
temp = employee_list->prev;
temp->next = employee_list->next;
employee_list->next->prev = temp;
free (employee_list);
}
}
printf("delete successful\n");
break;
}
default:
{
printf("not this one\n");
errorcheck = 0;
employee_list = employee_list->next;
break;
}
}
}
while (foundit == 0);
if (foundit == 0)
printf("Name not recognised\n.");
return;
}
Any help would be much appreciated.
Maybe the doubly-linked list is not built up the way you think it should. This has to be checked first.
Assuming the topology is correct, there are still a couple of issues with this code:
employee_list->name; (just above the do loop): what is this?
strcpy (namecheck, employee_list->name); : you do not need to copy, this is just a shorthand, so namecheck could be a (const) string pointer.
switch (errorcheck) : this has only 2 arms, why don't you use an if ?
if (employee_list->prev == NULL) ...: you just move the top pointer here but do not delete the top item, this will cause memory leaks. You also do not set the prev pointer of the next-to-top item to NULL.
In the "somewhere in the middle" part: you free employee_list which is the current position pointer. The next item to be processed should be temp->next, right? This is probably your problem because you do not take care of moving the current pointer along. Moreover, it is much better to set a pointer explicitly called tobedeleted to the item to be deleted, make sure the pointer used to iterate along the list (employee_list in your case) is moved appropriately, and when *tobedeleted is appropriately isolated out from the doubly linked list then issue the free(tobedeleted) command.
employee_list = employee_list->next; : you should check for employee_list turning into NULL at the last item, and exit the loop. Otherwise Bad Things will happen.
Final advice: you really need to consult a good C book... Kernighan and Ritchie
for instance. Way better than "Internet research".

How to use free on a handle inside a list?-> C -> windows API

I have a list in C that is something like this:
typedef struct _node
{
int number;
DWORD threadID;
HANDLE threadH;
struct *_node next;
} *node;
And you have somthing like this:
node new_node = malloc(sizeof(node));
As you may have guessed out, this list will store information for threads, including their handlers and Id's. Still I am having trouble when I try to do this:
free(new_node);
Everytime I try to do this I encounter an unexpected error, VS saying that there was a data corruption. I've pinned down as much as possible and I found that the problem resides when I try to use free the handle.
I've searched on MSDN how to do this but the only thing I can find is the function that closes the thread (which is not intended here, since I want the thread to run, just deleting it's record from the list).
The question is: how I am supposed to free an handle from the memory? (Considering that this is only a copy of the value of the handle, the active handle is not being deleted).
EDIT: This is the function to insert nodes from the list:
int insereVisitanteLista(node* lista, DWORD threadID, HANDLE threadH, int num_visitante)
{
node visitanteAnterior;
node novoVisitante = (node)malloc(sizeof(node));
if(novoVisitante == NULL)
return 0;
novoVisitante->threadID = threadID;
novoVisitante->threadH = threadH;
novoVisitante->number = num_visitante;
novoVisitante->next = NULL;
if(*lista == NULL)
{
*lista = novoVisitante;
return 1;
}
visitanteAnterior = *lista;
while(visitanteAnterior->next != NULL)
visitanteAnterior = visitanteAnterior->next;
visitanteAnterior->next =novoVisitante;
return 1;
}
And this is the function to delete nodes:
int removeVisitanteLista(node * lista, DWORD threadID)
{
node visitanteAnterior = NULL, visitanteActual;
if(*lista == NULL)
return 0;
visitanteActual = *lista;
if((*lista)->threadID == threadID)
{
*lista = visitanteActual->next;
visitanteActual->next = NULL;
free(visitanteActual);
return 1;
}
while(visitanteActual != NULL && visitanteActual->threadID != threadID)
{
visitanteAnterior = visitanteActual;
visitanteActual = visitanteActual->next;
}
if (visitanteActual == NULL)
return 0;
visitanteAnterior->next = visitanteActual->next;
free(visitanteActual);
return 1;
}
What exactly is a node that you are trying to free? Is this a pointer to a struct _node? If yes, have you allocated it previously? If no, free is not needed, otherwise you have to check if node is not NULL and make sure you do not free it multiple times. It is hard to guess what you are doing and where is an error without a minimal working example reproducing the problem. The only thing I can suggest is to read about memory management in C. This resource might help.
UPDATE:
node in your code is a pointer to _node. So sizeof (node) is a size of a pointer, which is either 4 or 8 bytes (depending on architecture). So you allocate 8 bytes, for example, but assume you have a pointer to the structure which is much larger. As a result, you corrupt memory, and behavior of the program becomes undefined. So changing node novoVisitante = (node)malloc(sizeof(node)) to node novoVisitante = (node)malloc(sizeof(_node)) should fix the problem.
You haven't shown us the context of your call to free() so I need to speculate a little but my first concern is that you didn't mention removing the node from the list before deleting it.
Start by unlinking the node by modifying the next field of the previous (or head) node. If you still get the error, then you have corrupted memory somehow by writing past the end of one of your allocated memory structures or something similar.
Also, I assume node is a pointer. You really haven't provided much information about what you're doing.

Resources