destroy linked list in c with extra deallocating data - c

i have a linked list in C which i need to destroy by request and keep memory allocation
here's the code :
can someone explain to me what exactly i need to add with the parameter dealloc?
/** Destroy and de-allocate the memory hold by a list
\param list - a pointer to an existing list
\param dealloc flag that indicates whether stored data should also be de-allocated
*/
void dbllist_destroy(dbllist_t *list,dbllist_destroy_t dealloc)
{
dbllist_node_t *current = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
dbllist_node_t *current = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(current == NULL || temp == NULL)
return -1;
current = dbllist_tail(list);
while (current != NULL)
{
temp = dbllist_prev(current);
free(current);
current = temp;
dbllist_size(list)--;
}
free(current);
free(temp);
free(list);
return 0;
}
typedef enum { DBLLIST_LEAVE_DATA = 0, DBLLIST_FREE_DATA } dbllist_destroy_t;

So, remaining issues I can see:
the double malloc at the top - all these will do is waste memory. There is no need to be allocing anything here.
dbllist_size(list)-- is meaningless. you are simply getting a value and then reducing it. Presumably you are trying to reduce the stored size of the list. Either dbllist_size returns a pointer to the size (unlikely, but in which case you will need to do (*dbllist_size(list))--)). More likely you will either need to call a dbllist_set_size (if there is one) or (most likely) directly alter the size value (list->size-- or something similar). However, since you are deallocing the entire structure, you could just set size to 0 at the end^1
The point you will want to dealloc the data is just before the free(current) in the middle. Probably it will be something like if (DBLLIST_FREE_DATA==dealloc) { free(dbllist_get_data(current));} (again, depends on the api)
The free(current) after the for loop is not needed, as current must be null at this point.
Checking for null at the top is good, but you are checking the wrong thing. You should be checking if list is null.
You haven't declared temp
[^1]: if you needed destroy to be thread safe then you might want to set the size after freeing each item; in that case you would also want to put a mutex around the inside of the for loop. Also, since this is presumably a double linked list, you would want to updated the last/next pointers as well. Probably this is overkill for you though.

Related

Delete node from singly linked list and do an operation on it

I am tasked with removing a node from a singly linked list and setting the structure that the node's dataPtr points to, to a new value. I create a structure pointer to hold the data of the popped node. There are 2 cases I want to catch 1) in which this new pointer is null, I want to set it to the popped node 2) if the pointer is not null, I want to do some operations on it.
NODE* printer;
printer = (NODE*) malloc(sizeof (NODE)); //dynamically allocate
if(printer==NULL){ //if it has no data
printer= deleteNode(sList); //call deleteNode function which returns popped node from the passed singly linked list
} else if (printer!=NULL && sList->count!=0) { //if it has data
(((PRINTJOB *) printer->dataPtr)->pageNums) -= PAGESPERMINUTE; //decrement the pageNums field by 1 (PAGESPERMINUTE)
if ((((PRINTJOB *) printer->dataPtr)->pageNums) <= 0) { //if the field is less than 0
printer = NULL; //set pointer back to null
}
printf("printers pageNum is: %d\n", ((PRINTJOB *) printer->dataPtr)->pageNums);
}
My compiler is giving me an error on 4th line: The value is never used.
It is also giving me an error in my else if statement: first condition is always true.
When I run this code block as well, it crashes my program.
My deleteNode function is:
#include "headers.h"
void* deleteNode(LIST* list){
NODE *toDelete;
toDelete = list->head;
list->head = toDelete->next;
return toDelete;
}
my NODE structure is:
typedef struct node{
void* dataPtr;
struct node* next;
} NODE;
I am tasked with removing a node from a singly linked list and setting the structure that the node's dataPtr points to, to a new value.
But you remove the node only conditionally (and on a condition that is unlikely to actually occur). If, as stated, the first step is to remove a node then Remove. That. Node.
I create a structure pointer to hold the data of the popped node.
But you shouldn't. If there is any data available to receive then that's because a node containing it already exists, and your deleteNode() function will return a pointer to it (provided that function is in fact called).
There are 2 cases I want to catch 1) in which this new pointer is null, I want to set it to the popped node
That makes no sense, because it makes no sense to create a new, separate node in the first place. What would make sense would be to check whether deleteNode returns a null pointer, which one imagines it might do if the list were empty (but see below).
if the pointer is not null, I want to do some operations on it.
That could make sense, but not in this context. According to your description, you want to perform operations on the node that was removed from the list (provided that one in fact was removed), but instead you are working on the newly-allocated, uninitialized node.
Based only on your description of the task itself, it sounds like you want something more like this:
NODE* printer = deleteNode(sList);
if (printer != NULL) {
(((PRINTJOB *) printer->dataPtr)->pageNums) -= PAGESPERMINUTE;
if ((((PRINTJOB *) printer->dataPtr)->pageNums) <= 0) {
printer = NULL; //set pointer back to null (?)
}
printf("printers pageNum is: %d\n", ((PRINTJOB *) printer->dataPtr)->pageNums);
} // else nothing to do
But there are other possibilities, depending on how the list is structured and used.
Note that the printer = NULL; line that I copied from your original code is questionable. It may make sense if later code performs a null check on printer before doing yet more processing, and you want to circumvent that. Beware, however, that failing to first free() the node might constitute a memory leak. It looks suspicious in that way, but it is possible that the node really shouldn't be freed there.
Note also, however, that your deleteNode() function appears to be likely to break when it operates on an empty list. In that event, it seems like the only sensible thing it could return is a null pointer. It might well be that list->head is in fact such a pointer in that case, but then
NODE *toDelete;
toDelete = list->head;
list->head = toDelete->next;
will attempt to dereference that null pointer when it evaluates toDelete->next, thus reaping undefined behavior. If in fact you can rely on list->head to be null when the list is empty, then you would want to modify the above something like this:
NODE *toDelete;
toDelete = list->head;
if (toDelete != NULL) {
list->head = toDelete->next;
} // else list->head is already NULL
Again, there are other possibilities depending on how the list is structured and used, but I think the above is probably what you want.

How a free sucession of pointers?

So I have struct that has two pointer tags inside it: next, which points to a chain of other structs (all linked by pointers their next field as well) and the other one points to the last struct in the chain. I'm trying to free them but somehow I keep getting a core dump due to an invalid free. I'm a new C coder. Is there something I am doing that's obviously wrong?
void free_if(myTik *the){
while(the->endif != NULL){
myTik *eh;
eh = the->next;
the->next = the->next->next;
free(eh);
}
}
i think there is an error in your logic.
You check if 'current node' is NULL or not, but erase 'next' of current node.
the->next = the->next->next;
so above code can be error if
node(current) -> NULL (because the->next is NULL, so the->next->next will corrupt run-time error)
it is better to use 'dummy header' to erase total node in one-way linked-list
void free_if(node header){
while(header->head->next != NULL){
node *eh;
eh = header->head;
header->head = eh->next;
free(eh);
}
//if escape while loop, you get this
//HEADER(dummy) -> node -> NULL;
so, just free it
free(header->head);
}
You simply want to work down you linked-list, node-by-node, saving a copy of the current pointer (the victim to delete) and advancing the pointer you are using to iterate over your list before freeing the memory of the victim node. (you were close, you just had too many ->next thrown in there)
A normal traversal freeing all nodes is:
void free_if (myTik *the)
{
while (the != NULL) {
myTik *victim = the;
the = the->next;
free (victim);
}
}

Difference between free() function with or without malloc

This is part of cs50 pset5 speller. Background is that I load a dictionary into a hash table with linked list and check word against the hash table to decide if that word is in the dictionary, after that I unload the hash table.
When I load the dictionary, I used malloc() and free() to insert a node into the linked list. The result of free() here is that it free the memory allocated to a pointer, but it will not remove the pointee (a node inserted into linked list in this case).
Here is my code:
bool load(const char *dictionary)
{
FILE *inputfile = fopen(dictionary, "r");
if (inputfile == NULL)
{
return false;
}
char tempWord[LENGTH+1];
while (fscanf(inputfile, "%s", tempWord) != EOF)
{
//create a tempNode and make sure
node *tempNode = malloc(sizeof(node));
if (tempNode == NULL)
{
return false;
}
strcpy(tempNode->word, tempWord);
tempNode->next = NULL;
//get the index of this word
int index = hash(tempWord);
//move tempNode to the next node in the linked list
if (table[index]->next != NULL)
{
tempNode->next = table[index];
}
table[index]->next = tempNode;
free(tempNode);
word_count ++;
}
fclose(inputfile);
return true;
}
When I unload the dictionary, I used free() again, but this time without calling malloc() at all. So the elements on the linked list can be freed one after another. The result of free() here is that it 'removes' the node from the linked list.
Here is my code:
bool unload(void)
{
for (int i = 0; i < N; i ++)
{
//freeing linked list, we need two tempNode in order to do this
node *tempPtr = table[i];
while (tempPtr != NULL)
{
node *deletePtr = tempPtr;
tempPtr = tempPtr->next; //move the tempPtr to the next element, so we are note losing the linked list
free(deletePtr); //once we moved the tempPtr to the next element, now we can delete where deletePtr is pointing at
}
}
return true;
}
Although my code was compiled and can run without issue, I am very confused of why free() does different things here.
To summarize my questions:
(1)Am I correct to say that: in 'load', free(tempNode) does not 'erase' what tempNode is pointing to (which is a node in a linked list), but only free the memory allocated to tempNode; in 'unload', however, free(deletePtr) 'erase' both deletePtr and what deletePtr is pointing to (which is a node in a linked list)?
(2) If my observation in (1) is correct, why is free() doing different things here? Is that caused by the fact that load called malloc() and unload didn't?
(3) I understand I have to call free() if I called malloc(), but when malloc() isn't called, what does free() do?
=================================
Edit:
After more research, I realized that in load section, it is unnecessary to free() the memory assigned by malloc(). The reason is, in unload section, by free() each node, I will eventually be able to free the memory assigned before.
(1)Am I correct to say that: in 'load', free(tempNode) does not
'erase' what tempNode is pointing to (which is a node in a linked
list), but only free the memory allocated to tempNode;
The object to which tempNode points is not meaningfully distinguished from the memory occupied by the object to which tempNode points. If that is a block of dynamically allocated memory then you must not attempt to access it after freeing it. Any attempt to do so produces undefined behavior.
The question is thus meaningless. There is no conforming way to tell whether the memory in question has been "erased", because you must not attempt to read it. If you do attempt to read it then the program might behave as if the memory had been overwritten in some way, or it might not. And it might do anything else within its power, too. Crashing the program (eventually) is a popular alternative, but by no means a guaranteed one.
in 'unload',
however, free(deletePtr) 'erase' both deletePtr and what deletePtr is
pointing to (which is a node in a linked list)?
See above.
(2) If my observation in (1) is correct [...]
Observation (1) is not correct.
(3) I understand I have to call free() if I called malloc(), but when
malloc() isn't called, what does free() do?
The free() function has undefined behavior (see above) if it is passed a pointer value that is non-null and was not obtained from a memory allocation function, or one that has already been freed.

Linked List Function?

So i'm writing this function that makes the smallest node at the end of the linked list. So Far it works except for the last element. if the linked list is created as nodes containing items from 0~9, the list after this function is {1,2,3,4,5,6,7,8,0,9} and the zero does not become at the end.
Any ideas why?
my function;
int connecting(linkk A)
{
linkk L = A;
for (int i = 0; i<sizeof(L);i++)
{
if (L->item < L->next->item)
{
int a = L->item;
L->item = L->next->item;
L->next->item = a;
L = L->next;
}
else{L=L->next;}
}
return 0;
}
Let's start with what I think you should be doing differently:
The name of your function is connecting. Given the description of what you'd like the function to do, this is not a good name.
I can infer from the usage that linkk is a typedef'ed pointer. Hiding pointers this way is not a good idea, most of the time.
Your function returns an int. It's always 0. Why? This does not make any sense.
Because linkk is probably a pointer to a node, and you pass the head pointer by value (i.e. a copy of it) to the function, you're unable to handle the case where the head of your list is the minimum. Either return the "new" head pointer, or pass a pointer to the head pointer to be able to modify the head pointer.
Your use of sizeof is completely wrong, as already suggested. sizeof(L) will give you the size (in chars) of the pointer, thus probably 8 on a 64 bit system or 4 on a 32 bit system.
You're not changing the nodes, but rather moving the values in between the nodes. This is OK if it's what you want to do, but the description of your algorithm suggest that you want to move the node instead.
Your function is doing too much, IMO. This can be hard to split, but a better approach would be to separate finding / extracting the minimum and putting it at the end of the list.
You're modifying a lot more than you originally wanted to. Consider a list like 1, 2, 3, 0, 4. Using your algorithm, the list will be changed to 2, 3, 1, 4, 0. Doing this is not only bad for the performance, but also very surprising for the caller. Surprises aren't good when it comes to programming!
So, let's get to a hopefully good implementation, step by step:
struct node {
int item;
struct node * next;
};
I assume that you want to move the node containing the minimum value to the end of the list, as in your description. I'm also going to keep this into a single function receiving a struct node * head pointer, despite my point above, in order to keep closer to the original code. Let's get out the special / base cases first: Moving the minimum element of an empty list as well as of a single element list is trivial: Do nothing.
if (head == NULL || head->next == NULL) {
return head;
}
I'm returning the "new" head of the list to allow the caller to update it's own head pointer. (As already said, head is just a copy of the caller's head pointer, modifying it will not have any effect at the call site).
Because we're dealing with a singly linked list here, and the implementation should not unnecessarily iterate over the list, we should remember the node we've previously visited. Otherwise we couldn't easily extract a node from the list:
struct node * follow, * point;
follow follows directly behind the point.
Initially, we place the point to the second node of the list (we already checked that there are at least 2 nodes in the list). follow will thus point to the head:
point = head->next;
follow = head;
Since we want to find the minimum item, we need to keep track of the minimum of the already searched part of the list. We initialize it with the head node's value:
int currentMinimum = head->item;
Now we're ready to iterate over the list, in order to find the node containing the minimum. But we need not only find the node containing the minimum, but also the one before it and the one after it, in order to be able to extract it easily. So, 3 pointers:
struct node * predecessor, * minimum, * successor;
As we set the currentMinimum to heads item, we should also set the pointers accordingly:
predecessor = NULL; // Nothing preceding the head
minimum = head;
successor = head->next;
Now let's iterate, moving the point completely over the list, until it falls off at the end:
while (point != NULL) {
// to be continued
follow = point;
point = point->next;
}
// when we're here, follow will point to the last node
In each iteration, we need to check if we found a smaller value than the current minimum, and eventually remember the node containing it:
if (point->item < currentMinimum) {
predecessor = follow;
minimum = point;
successor = point->next;
currentMinimum = point->item;
}
Now, when we get out of the loop, the following state should be reached:
minimum points to the node containing the minimum.
follow points to the last node of the list.
The two above could be the same, which is a special case!
predecessor could still be NULL, which is another special case!
Considering first the special case of minimum = follow: In that case, the minimum is already at the end of the list, so profit! Otherwise, we need to "cut" the node at minimum out of the list and append it to the last node, pointed to by follow:
if (follow != minimum) {
if (predecessor != NULL) {
predecessor->next = successor; // Cut out
minimum->next = NULL; // will be the last node
follow->next = minimum; // append at end
} else {
// to be continued
}
}
As you can see, there's the second special case to consider: If predecessor is still NULL, then no item was smaller than heads item. (Therefore, we could also test for minimum == head) Thus, the first node of the list will be moved to the end. We need to inform the caller about this!
head = head->next; // Second node is now the first one, though this is not all we need to do, see further down!
minimum->next = NULL; // Will be the last node
follow->next = minimum; // Append at end
Since the assignment to head only changed the function parameter (which is a copy of the pointer with which the function has been called), we need to return the (possibly modified!) head pointer, giving the caller the ability to update its own head pointer:
return head;
A caller would thus use this function like so:
struct node * head = get_a_fancy_list();
head = move_minimum_to_end(head); // This is our function being called!
Finally, a thing to consider: As you can see, moving the node (instead of the item) is more complicated. We need to modify at least 2 pointers in order to achieve what we want. In contrast: Moving the item value requires two modifications of item values (and iterating is easier). Moving the node instead of the item thus makes only sense when pointer assignments are faster than item assignments. Since the items are of type int this is not the case here.
Moving the item instead of the node containing the item is considerably easier. First of all, we need to keep track of the minimum (value as well as node):
struct node * minimum;
int currentMinimum;
To iterate, we're again going to use two pointers. It can be done with a single one, but the code is going to be more readable this way:
struct node * point, * follow;
We start off with the same initial state:
minimum = head;
currentMinimum = head->item;
follow = head;
point = head->next;
Iterating is similar to the other implementation, as is the iteration step:
while (point != NULL) {
if (point->item < currentMinimum) {
minimum = point;
currentMinimum = point->item;
}
follow = point;
point = point->next;
}
// follow points to the last node now
Now, doing the same as the previous implementation, we can swap the items of the last node and the node with the minimum:
minimum->item = follow->item;
follow->item = currentMinimum; // contains minimum->item
There's no point in checking for follow != minimum like in the previous approach: You could do it, but swapping the item of a node with its own item won't do any harm. OTOH adding an if will add a branch, and thus a possible performance penalty.
Since we didn't change the list structure (the linking between nodes), there's not much more to consider. We don't even need to inform the caller about a new head, as there will never be any change to it. For style purposes, I'd add it either way:
return head;
Ok, this got a bit long now, but hopefully it's easy to understand!
Try this function
int connecting(linkk A)
{
linkk L = A;
while(L->next!=NULL)
{
if (L->item < L->next->item)
{
int a = L->item;
L->item = L->next->item;
L->next->item = a;
}
L=L->next;
}
return 0;
}

Pushing to a stack containing ONLY unique values in C

I've implemented a stack with pointers, that works like it's suppose too. Now, I need it push to the stack, without it pushing a duplicate. For example, if I push '2' into the stack, pushing another '2' will still result with only one '2' in the stack because it already exists.
Below is how I went about trying to create the new push function. I know that I'm suppose to traverse the stack and check it for the element I'm adding, but I guess I'm doing that wrong? Can anyone help me out?
typedef struct Node {
void *content;
struct Node *next;
} Node;
typedef struct Stack {
Node *head;
int count;
} Stack;
void push(Stack *stack, void *newElem) {
Node *newNode = (Node*) malloc(sizeof(Node));
if (stack->count > 0) {
int i;
for (i = 0, newNode = stack->head; i < stack->count; i++, newNode =
newNode->next) {
if (newNode->content == newElem) return;
}
} else {
newNode->next = stack->head;
newNode->content = newElem;
stack->head = newNode;
stack->count++;
}
}
if (newNode->content == newElem)
You are comparing two pointers. I guess you want to check whether their contents are equal:
#include <string.h>
if (memcmp(newNode->content, newElem, size) == 0)
The value size may be indicated by the caller. In your case, it should be sizeof(int).
Moreover, once you have traversed the stack, you don't add the element to your data structure.
The problem is that if your stack is non-empty, and you don't find the element already in the stack, you don't do anything. You need to get rid of the else keyword and make that code unconditional. Then, you allocate space for the new Node before you know if you need it or not, and, even worse, overwrite the newly allocated pointer with your iteration over the stack to see if you need to push it or not. So move the malloc down after the } ending the if
You already have a working
void push(Stack *stack, void *newElem);
right?
So, why not write a new function
int push_unique(Stack *stack, void *newElem) {
if (find_value(stack, newElem) != NULL) {
return 1; // indicate a collision
}
push(stack, newElem); // re-use old function
return 0; // indicate success
}
Now you've reduced the problem to writing
Node *find_value(Stack *stack, void *value);
... can you do that?
I'm not sure you realized it, but your proposed implementation is performing a linear search over a linked list. If you're pushing 2,000 elements on a stack with an average of 2 duplicates of each element value, that's 2,000 searches of a linked list averaging between 500-750 links(it depends on when, IE:what order, the duplicates are presented to the search function in. This requires 1 million+ compares. Not pretty.
A MUCH more efficient duplicate detection in find_value() above could use a hash table, with search time O(1), or a tree, with search time O(log N). The former if you know how many values you're potentially pushing onto the stack, and the latter if the number is unknown, like when receiving data from a socket in real-time. (if the former you could implement your stack in an array instead of a much slower, and more verbose linked-list)
In either case, to properly maintain the hashtable, your pop() function would need to be paired with a hashtable hashpop() function, which would remove the matching value from the hashtable.
With a Hashtable, your stack could just point to the element's value sitting in it's hash location - returned from find_value(). With a self-balancing tree however, the location of the node, and thus the element value, would be changing all the time, so you'd need to store the element's value in the stack, and the tree. Unless you're writing in a very tight memory environment, the performance the 2nd data structure would afford would be well worth the modest cost in memory.

Resources