ngwilliams
ngwilliams

Reputation: 269

Alternate Solution to Passing Parameter by Reference in C

I'm trying to implement the insert-at-head functionality of a linked list, and would like to return a void* pointer to the newly inserted node via passing by reference. I unfortunately cannot change the parameters. This is my relevant code:

typedef struct List_t_def{
 spinlock_t * lock_counter;
 unsigned int key;
 struct List_t_def *next;
}list_t;

typedef volatile unsigned int spinlock_t;//basic lock

void List_Insert(list_t *list, void *element, unsigned int key) {  
  list_t * list_new = (list_t *)malloc(sizeof(list_t));
  spinlock_t * lock_temp = (spinlock_t*)malloc(sizeof(spinlock_t));
  list_new->lock_counter = lock_temp;

  spinlock_acquire(list->lock_counter);
  list_new->key = key;    //inserting the new created node as the first one (head of the linked list)
  list_new->next = list->next;
  list_new->lock_counter = list->lock_counter;    

  list->next = list_new;

  element = (void*)list_new; 

  spinlock_release(list->lock_counter);

  return;
}

I'm trying to set element to the start of the newly inserted node, but when it returns, element doesn't change its previous value. Any suggestions or help is appreciated, thanks!

Upvotes: 1

Views: 116

Answers (2)

dkz
dkz

Reputation: 971

As already was suggested if you can't modify function prototype, you can still use your void* parameter to pass any kind of pointer into the function, including pointer-to-pointer to return your new element.

Let me just refine the code to show less abstract example for this usage:

void List_Insert_Caller() {
    // ...
    list_t *new_element;
    List_Insert(list, &new_element, key);
    // new_element now points to newly created list_t element
}

void List_Insert(list_t *list, void *new_element_ptr_ptr, unsigned int key) {
    // ...
    list_t **new_element = (list_t **)new_element_ptr_ptr;
    // ...
    *new_element = list_new;
}

Upvotes: 0

pughar
pughar

Reputation: 148

Well, I know you can't change the parameters but if you can change the implementation and and the caller of this function you could do it!

The horrible(ly nice) thing about C is that you can cast anything to anything you want. So even though you can't change the function signature to take a void** you can still pass one anyway. Example:

char *element = (char *)malloc(0xDEADBEEF);
List_Insert(list, (void*)&element, key);

Inside the function, you can cast it back to a void**:

void List_Insert(list_t *list, void *element, unsigned int key) {
    void **e = (void **)element;

    /* do stuff */

    *e = (void *)list_new;
}

Voila! BTW, this is horrible and not intuitive for the caller. I hope this is not production code :)

Upvotes: 1

Related Questions