C free linked list - c

I need to know how to modify the free function to remove the first element of the list (last added). I must not interfere with the main function.
This is how the last element added to me remains in the list.
typedef struct TEmployee
{
struct TEmployee *m_Next;
struct TEmployee *m_Bak;
char *m_Name;
} TEMPLOYEE;
TEMPLOYEE *newEmployee (const char *name, TEMPLOYEE *next)
{
TEMPLOYEE *n = (TEMPLOYEE*) malloc(sizeof(*next));
n->m_Name = (char*) malloc(sizeof(char)*100);
strcpy(n->m_Name, name);
n->m_Bak = NULL;
n->m_Next = next;
return n;
}
void freeList ( TEMPLOYEE *q )
{
TEMPLOYEE *x = q;
while( x != NULL)
{
TEMPLOYEE *tmp = x->m_Next;
free(x);
x = tmp;
}
free(x);
x=NULL;
}

Currently, the freeList method deletes all the elements in the linked list.
To just delete the first element of a linked list, the algorithm should be as follows:
Given the head as the input.
It could be possible that the head itself is NULL meaning the list is already empty, in that case we can simply return.
In the other case, we can simply set head = head->m_Next.
Now, since we also have previous pointers, we need to update the previous pointer for the current head, i.e. head->m_Back = NULL.
Please try to use the above algorithm and write the updated freeList method.

The problem is that you pass the pointer to the first element by value. If you want to modify the value of the head pointer, you need to pass it by reference, as in:
void freeList ( TEMPLOYEE **q )
{
TEMPLOYEE *x = *q;
while( x != NULL)
{
TEMPLOYEE *tmp = x->m_Next;
free(x);
x = tmp;
}
/* free(x); this is incorrect, tmp is already NULL when you
* get out of the while loop
* x=NULL; // and this is nonsense, it's already NULL and you are not
* // using x anymore.
*/
*q = NULL; /* this is what you lack, to assign NULL to the pointer. */
}
Later, you need to call freelist() as follows:
freelist(&list_head);
to pass a reference of the pointer instead of the pointer's value.

It cannot reliably be done without modifying the caller.
In it's basic form, you just have to free the node and trust that nobody uses it anymore:
void freeFirst ( TEMPLOYEE *q )
{
if (q) {
free(q->m_Name);
free(q);
}
}
Now to make this a bit more reliable, you should also modify the queue head node. This can be done by passing a double pointer to allow modification of the head node pointer:
void freeFirst ( TEMPLOYEE **q )
{
TEMPLOYEE *x = *q;
if (*q) {
*q = (*q)->m_Next;
free(*x->m_Name);
free(*x);
}
}
Now it's important that the caller is modified, instead of freeList(list) you would now need freeList(&list).
Not that I have also freed the m_Name member, because otherwise you will leak the memory.
You should also use strdup instead of your combination of malloc of arbitrary length and strcpy, that could cause a buffer overflow.

Related

Deleting a list with pointer to pointer in C

The partial code, in C, is here:
typedef struct List {
double v;
struct List *next;
} List;
void deleteList (List **p) {
*p = (*p)->next;
}
I am confused about how the deleteList function is working. So the arguement is a pointer to a pointer to a List structure. So we have:
p : pointer_2 --> pointer_1 --> List
So I have some questions:
So what is *p in the function deleteList()? Is it pointer_1 or something else?
Does *p before = mean the same as *p after the = sign?
Is there a difference between *p and (*p) ?
Say we have:
... la --> lb --> lc --> ld ....
And say we want to delete lb. I get the idea, theoretically. You alter the la->next to point to lc. But I am confused about the pointer business.
What is the argument to deleteList()?
Is it, deleteList(la->next)? Or something else?
And then the really confusing part.
*p = ... is supposed to be la->next because this is the pointer we want to alter.
But then ...(*p)->next, wouldn't this just be the lb? But we want lc? So it seems like
*p have different meaning in the same line?!
Let;s at first write the function correctly.
void deleteList( List **head )
{
while ( *head != NULL )
{
List *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
}
A pointer to the head node is passed to the function by reference.
If you will define the function like
void deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
}
that is if the pointer will not be passed by reference then the function will deal with a copy of the pointer. Changing a copy does not influence on the original pointer.
Consider the following demonstrative program.
#include <stdio.h>
#include <stdlib.h>
void f( int *p )
{
p = NULL;
}
int main(void)
{
int x = 10;
int *px = &x;
printf( "Before the function call px = %p\n", ( void * )px );
f( px );
printf( "Adter the function call px = %p\n", ( void * )px );
return 0;
}
Its output might look like
Before the function call px = 0x7ffe26689a2c
Adter the function call px = 0x7ffe26689a2c
That is the original pointer px was not changed because the function dealt with a copy of the pointer.
To change the pointer you need to pass it to the function by reference
#include <stdio.h>
#include <stdlib.h>
void f( int **p )
{
*p = NULL;
}
int main(void)
{
int x = 10;
int *px = &x;
printf( "Before the function call px = %p\n", ( void * )px );
f( &px );
printf( "Adter the function call px = %p\n", ( void * )px );
return 0;
}
Now the program output might look like
Before the function call px = 0x7ffed60815fc
Adter the function call px = (nil)
Within the function you need to dereference the parameter to get the access to the passed by reference pointer.
*p = NULL;
^^^^
The same occurs in the function deleteNode. To check whether the passed pointer is equal to NULL there is used the following statement
while ( *head != NULL )
^^^
To access the data member next of the node pointed to by the origibal pointer you again have to dereference the parameter to get access to the original pointer
*head
So this expression yields the original pointer. So to access the data member next you have to write
( *head )->next
You are using the parentheses because the postfix operator -> has a higher priority but you need at first to get the original pointer.
That is if you had no a referenced pointer you would write
head->next
But when you have a referenced pointer that is when you have a pointer to an original pointer then to get the original pointer you have to derefernce the referenceing pointer like
( *head )->next
You could write the function without accepting the pointer to the head node by reference. But in this case you should to add in the caller one more statement that will set the pointer head to NULL.
For example
void deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
}
and in the caller you need to write
List *head - NULL;
// the code thatf fills the list
deleteList( head );
head = NULL;
Or the function could return a null pointer like
List * deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
return head;
}
and in the caller you could write
List *head - NULL;
// the code thatf fills the list
head = deleteList( head );
The advantage of defining the function that accepts the pointer to the head node by reference is that the user of the function does not need to remember to set the pointer to NULL by himself.
in deleteList function: before you pass to the next element you must free the element you point to.
void deleteList (List **p) {
while(*p != NULL){
List *nextNode = (*p)->next;
free(*P);
*p= nextNode;
}
}

Array pointer always points to NULL

Im trying create a linked list in an array of nodes. When I try to update the pointer for arrTab->h_table[index] to the address of newNode, The address points to newNodes address. But when I try to add to a list that exists in the array, the pointer always points to NULL instead of the previous value in memory. Basically the arrTab->h_table[index] head of the linked list does not update to the address of newNode.
typedef struct node {
struct node* next;
int hash;
s_type symbol;
} node_t;
struct array {
int cap;
int size;
n_type** h_table;
};
int add_to_array (array* arrTab, const char* name, int address) {
if(s_search(arrTab, name, NULL, NULL) == NULL){
s_type *symbol = (s_type*) calloc(1, sizeof(s_type));
symbol->name = strdup(name);
symbol->addr = addr;
n_type *newNode = (n_type*) calloc(1, sizeof(n_type));
newNode->next = NULL;
newNode->hash = nameHash(name);
newNode->symbol = *symbol;
int index = newNode->hash % arrTab->cap;
if(arrTab->h_table[index] == NULL){
arrTab->h_table[index] = newNode;
} else {
newNode->next = arrTab->h_table[index];
arrTab->h_table[index] = newNode;
}
//
arrTab->size++;
return 1;
}
return 0;
}
struct node* s_search (array* arrTab, const char* name, int* hash, int* index) {
int hashVal = nameHash(name);
hash = &hashVal;
int indexVal = *hash % arrTab->cap;
index = &indexVal;
s_type *symCopy = arrTab;
while (symCopy->h_table[*index] != NULL){
if(*hash == symCopy->h_table[*index]->hash){
return symCopy->h_table[*index];
}
symCopy->h_table[*index] = symCopy->h_table[*index]->next;
}
return NULL;
}
I cannot say for sure why the pointer always points to NULL; there is not enough code. Consider posting an MCVE.
The posted code however presents few problems to address.
First, it leaks memory like there is no tomorrow:
symbol_t *symbol = (symbol_t*) calloc(1, sizeof(symbol_t));
allocates some memory, and
newNode->symbol = *symbol;
copies the contents of that memory to the new location. The memory allocated still exists, and continues to exist after the function returns - but there's no way to get to it. I strongly recommend to not allocate symbol, and work directly with newNode->symbol:
newNode->symbol.name = strdup(name);
newNode->symbol.addr = addr;
The hash and index parameters to symbol_search seem to be planned as an out parameters. In that case, notice that the results of hash = &hashVal; and index = &indexVal; are invisible to the caller. You likely meant *hash = hashVal and *index = indexVal.
The biggest problem comes with sym_table_t *symCopy = symTab;.
symTab is a pointer. It points to an actual symbol table, a big piece of memory. After the assignment, symCopy points to the same piece of memory. Which means that
symCopy->hash_table[*index] = symCopy->hash_table[*index]->next;
modifies that piece of memory. Once the search is completed, the hash_table[index] is not the same as it was before the search. This could be a root of your problem. In any case, consider
node_t * cursor = symTab->hash_table[*index];
and work with this cursor instead.
As a side note, a search condition *hash == symCopy->hash_table[*index]->hash is strange. Every node in a given linked list has the same hash (check how you add them). The very first node would produce a match, even if the names are different.

C - Check if index of struct array is uninitialized

I'm making a HashMap in C but am having trouble detecting when a Node has been initialized or not.
Excerpts from my code below:
static struct Node
{
void *key, *value;
struct Node *next;
};
struct Node **table;
int capacity = 4;
table = malloc(capacity * sizeof(struct Node));
// At this point I should have a pointer to an empty Node array of size 4.
if (table[0] != NULL)
{
// This passes
}
I don't see what I can do here. I've read tons of other posts of this nature and none of their solutions make any sense to me.
malloc does not initialize the memory allocated. You can use calloc to zero-initialize the memory.
// Not sizeof(struct Node)
// table = calloc(capacity, sizeof(struct Node));
table = calloc(capacity, sizeof(*table));
After that, it will make sense to use:
if (table[0] != NULL)
{
...
}
I suggest you consider something like a HashMapCollection type that you create with a set of functions to handle the various memory operations you need.
So you might have code something like the following. I have not tested this nor even compiled it however it is a starting place.
The FreeHashMapCollection() function below would process a HashMapCollection to free up what it contains before freeing up the management data structure. This may not be what you want to do so that is something for you to consider.
The idea of the following is to have a single pointer for the HashMapCollection struct and the array or list of HashMapNode structs immediately follows the management data so a single free() would free up everything at once.
typedef struct _TAGHashMapNode {
void *key, *value;
struct _TAGHashMapNode *next;
} HashMapNode;
typedef struct {
int iCapacity; // max number of items
int iSize; // current number of items
HashMapNode *table; // pointer to the HashMapNode table
} HashMapCollection;
Then have a function to allocate a HashMapCollection of a particular capacity initialized properly.
HashMapCollection *AllocateHashMapCollection (int iCapacity)
{
HashMapCollection *p = malloc (sizeof(HashMapCollection) + iCapacity * sizeof(HashMapNode));
if (p) {
p->table = (HashMapNode *)(p + 1);
p->iCapacity = iCapacity;
p->iSize = 0;
memset (p->table, 0, sizeof(HashMapNode) * iCapacity);
}
return p;
}
HashMapCollection *ReallocHashMapCollection (HashMapCollection *p, int iNewCapacity)
{
HashMapCollection *pNew = realloc (p, sizeof(HashMapCollection) + sizeof(HashMapNode) * iNewCapacity);
if (pNew) {
pNew->table = (HashMapNode *)(pNew + 1);
if (p == NULL) {
// if p is not NULL then pNew will have a copy of that.
// if p is NULL then this is basically a malloc() so initialize pNew data.
pNew->iCapacity = pNew->iSize = 0;
}
if (iNewCapacity > pNew->iCapacity) {
// added more memory so need to zero out that memory.
memset (pNew->table + iCapacity, 0, sizeof(HashMapNode) * (iNewCapacity - pNew->iCapacity));
}
pNew->iCapacity = iNewCapacity; // set our new current capacity
p = pNew; // lets return our new memory allocated.
}
return p; // return either old pointer if realloc() failed or new pointer
}
void FreeHashMapCollection (HashMapCollection *p)
{
// go through the list of HashMapNode items and free up each pair then
// free up the HashMapCollection itself.
for (iIndex = 0; iIndex < p->iCapacity; iIndex++) {
if (p->table[iIndex].key) free (p->table[iIndex].key);
if (p->table[iIndex].value) free (p->table[iIndex].value);
// WARNING ***
// if these next pointers are actually pointers inside the array of HashMapNode items
// then you would not do this free as it is unnecessary.
// this free is only necessary if next points to some memory area
// other than the HashMapNode table of HashMapCollection.
if (p->table[iIndex].next) free (p->table[iIndex].next);
// even though we are going to free this, init to NULL
p->table[iIndex].key = NULL;
p->table[iIndex].value = NULL;
p->table[iIndex].next = NULL;
}
free (p); // free up the memory of the HashMapCollection
}

how to use a pointer to pointer to insert in a linked list

Think is a function to insert new element in the order of name.
I knew how to do it if I use a if to separate condition of inserting at the start and others. But I was asked to merge the if and while into a single while loop.
How could i integrate the insert function into one while loop with pointer to pointer?
person* insert_sorted(person *people, char *name, int age)
{
person *p=NULL;//,*t=NULL,*q=NULL;
person *ptr= people;
person **ptr2ptr=&ptr;
p=malloc(sizeof(person));
if ( p == NULL ){
printf("malloc() failed\n");
return NULL;
}
else {
p->name = name;
p->age = age;
if ( people == NULL ){ // empty list
people = p;
people->next =NULL;
}
else{
*ptr2ptr = ptr;
while( (*ptr2ptr) !=NULL )
{
if ( compare_people(p, people)<=0 ) // insert at the start
break;
else if ( (*ptr2ptr)->next == NULL) //insert at the end
break;
else if ( compare_people(*ptr2ptr, p) <=0 && compare_people( p, (*ptr2ptr)->next)<=0 )//insert at the middle
break;
*ptr2ptr = (*ptr2ptr)->next;
}
//insert at the end
p->next = (*ptr2ptr)->next;
(*ptr2ptr)->next = p;
}
}
eInstead of trying to find the person element in the list which has no successor, try to find the first null pointer. Something like this (untested):
void insert_sorted(person **p, char *name, int age)
{
while (*p) {
p = &(*p)->next;
}
*p = malloc( ... );
/* ... */
}
This kind of problem is usually best solved with a pen an paper and then drawing a couple of boxes and arrows. The idea is that your 'p' pointer no longer points at a specific person but rather at some pointer which points to a person.
There can be a few options.
I would move the if inside the compare_people function provided that you can change it. After all, adding the very first element in a list is like adding a new "top of the list" element (of least of the list). I know this can be seen as "cheating". And it is, indeed!
You can create a "fake" list element which will always be tested to be the first (or the last) of the sorted list (like with an empty name).
So the list won't ever be empty and there won't ever be a "check for an empty list" test. Of course the content of that fake item needs to comply with the semantics of the compare_people function.
At a cost that's slightly higher than the current O(n), O(n*log(n)) actually, you could use a temporary support structure (like an array of pointers) and qsort() from stdlib.h in order to keep the list sorted.
Finally, implement insertion sort which would exploit the fact that the original set is already sorted before inserting the new element.
The function can be written the following way (without testing because I do not know some definitions of the list)
person * insert_sorted( person **people, char *name, int age )
{
person *p = malloc( sizeof( person ) );
if ( p == NULL )
{
printf( "malloc() failed\n" );
}
else
{
p->name = name;
p->age = age;
person *prev = NULL;
person *current = *people;
while ( current && !( compare_people( p, current ) < 0 ) )
{
prev = current;
current = current->next;
}
p->next = current;
if ( prev == NULL ) *people = p;
else prev->next = p;
}
return p;
}
And the function should be called like
insert_sorted( &people, name, age );
^^^^^^^
Without testing:
person* insert_sorted(person** people, char *name, int age) {
person* added = malloc(sizeof(person));
added->name = name;
added->age = age;
added->next = NULL;
person* previous = NULL;
person* current = *people;
while (current && compare_people(current, added) <= 0) {
previous = current;
current = current->next;
}
if (!people) {
*people = added;
} else {
previous->next = added;
added->next = current;
}
return added;
}
The way you use the pointer to pointer doesn't make use of the indirection. You only write (*ptr2ptr) where you would normally have written ´ptr`.
The idea of using a pointer to a node pointer is that by adding one level of indirection, you are able to access and modify the head pointer from the calling function. If you just pass in a node pointer, all changes to that pointer are local to the insert function and will not update the head pointer of your list in the calling function if necessary.
Your function signature should already pass a pointer to a node pointer:
void insert(person **p, const char *name, int age);
and call it like so:
person *head = NULL;
insert(&head, "Betty", 26);
insert(&head, "Ralph", 23);
insert(&head, "Chuck", 19);
insert(&head, "Alice", 42);
insert(&head, "Simon", 34);
When you enter the fuction, p is the address of head in the calling function. As you iterate through the list with
p = &(*p)->next;
*p hold the address of the next pointer of the previous node. p is a "whence" pointer: It holds the address of the pointer that points to the ode you are processing. That means an empty list isn't a special case any longer.
Your function requires to return the new head pointer. It is easy to forget to assign it and it also adds some redundancy to the call. The pointer-to-pointer approach also fixes this.
Here's how your insertion code could look like with a function that takes a pointer to pointer as argument:
struct person {
const char *name;
int age;
person *next;
};
int compare(const person *p1, const person *p2)
{
return strcmp(p1->name, p2->name);
}
person *person_new(const char *name, int age)
{
person *p = malloc(sizeof(*p));
p->name = name;
p->age = age;
p->next = NULL;
return p;
}
void insert(person **p, const char *name, int age)
{
person *pnew = person_new(name, age);
while (*p && compare(*p, pnew) < 0) {
p = &(*p)->next;
}
pnew->next = *p;
*p = pnew;
}
here i found the most useful answer to this question:http://www.mvps.org/user32/linkedlist.html
ptr2ptr = &people;
while ( *ptr2ptr!=NULL && compare_people(*ptr2ptr,p) ) {
ptr2ptr = &(*ptr2ptr)->next;
}
p->next = *ptr2ptr;
*ptr2ptr = p;

Realloc behaviour using a pointer-to-pointer

I don't understand why when I run this code, the printf statements aren't working.
Here is the code:
typedef struct list {
int n;
struct list *next;
}List;
List **head;
List *tmp=malloc(sizeof(List));
tmp->n=34;
tmp->next=NULL;
List *tmp2=malloc(sizeof(List));
tmp2->n=45;
tmp2->next=NULL;
List *tmp3=malloc(sizeof(List));
tmp3->n=26;
tmp3->next=NULL;
head=malloc(sizeof(head));
head[0]=tmp;
head[1]=tmp2;
head=realloc(head,sizeof(head));
head[2]=tmp3;
printf("n of tmp:%d \n",head[0][0].n);
printf("n of tmp2:%d \n",head[1][0].n);
printf("n of tmp3:%d \n",head[2][0].n);
I think that the reason for that is probably realloc, but why ? I'm using it properly, no ? I have followed this tutorial http://www.tutorialspoint.com/c_standard_library/c_function_realloc.htm
Not only realloc, here
head = malloc(sizeof(head));
You allocate space for just one pointer, and then
head[0]=tmp;
head[1]=tmp2;
you try to store 2.
If you need space for 2 pointers, then the correct way is
head = malloc(2 * sizeof(*head));
/* ^ always dereference when using sizeof */
/* in this case it's not a problem, but in other cases it will be */
then you can fill the two elements, after checking the return value of malloc() so
head = malloc(2 * sizeof(*head));
if (head == NULL)
doSomething_But_DontDereference_head_mayBe_exit();
head[0] = tmp;
head[0] = tmp2;
Now, realloc(), what if realloc() returns NULL, and you alread overwrite the head pointer, now you can't do anything else with it, so
void *pointer;
pointer = realloc(head, 3 * sizeof(*head));
if (pointer == NULL)
doSomethingAndProbablyFree_head_and_abort();
head = pointer;
is much safer.
And also, note that you need to multiply the size of the pointer sizeof(*head) by the number of pointers you want to store.
ALWAYS CHECK THE RESULT OF malloc()
Your code is relatively broken. Here's a fairly sane way of going about this:
typedef struct list {
int n;
struct list *next;
} List;
int main() {
List *tmp1 = malloc(sizeof(List));
tmp1->n = 34;
tmp1->next = NULL;
List *tmp2 = malloc(sizeof(List));
tmp2->n = 45;
tmp2->next = NULL;
List *tmp3 = malloc(sizeof(List));
tmp3->n = 26;
tmp3->next = NULL;
List **head = malloc(2 * sizeof(List *));
head[0] = tmp1;
head[1] = tmp2;
head = realloc(head, 3 * sizeof(List *));
head[2] = tmp3;
printf("n of tmp1: %d\n", head[0]->n);
printf("n of tmp2: %d\n", head[1]->n);
printf("n of tmp3: %d\n", head[2]->n);
}
I haven't included this, but you should also verify that malloc() and realloc() return a non-null pointer.

Resources