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!
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 :)
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;
}
Related
I'm trying to initialize (or create) a linked-list with an empty node pointing to NULL, but it's returning an error and I don't know why. Can somebody help me?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int times;
char name[100];
char number[100];
struct node* next;
};
typedef struct node* node;
void mklist(node* n) {
(*n)->times = 0;
strcpy((*n)->name, "null");
strcpy((*n)->number, "null");
(*n)->next = (node)NULL;
}
int main(void) {
node n;
mklist(&n);
return 0;
}
So node is actually a pointer to a struct node, very confusing
typedef struct node* node;
In main() you declare a pointer and pass a pointer to a pointer to mklist()
node n;
mklist(&n);
In mklist(), n is actually a pointer to a pointer to the struct, so derefencing it, you get a pointer to a struct
void mklist(node* n){
(*n)->times=0;
but nowhere in your code have you allocated memory for an actual struct.
The most straightforward fix with the way your code is currently is to add a malloc()
void mklist(node* n) {
*n = malloc(sizeof(*(*n)));
// check for malloc() failure
(*n)->times = 0;
strcpy((*n)->name, "null");
strcpy((*n)->number, "null");
(*n)->next = (node)NULL;
}
You can do this easily in the global scope:
// nil = &nilObj, which means nil->next == nil.
//
// This way, there's no checking for both 'nil' and 'NULL'!
//
// As a consequence of this last point, you can make passing 'NULL'
// to most list functions invalid: it just means the user didn't
// use mklist() on every list they needed to manually work with.
static struct node nilObj = { 0, "null", "null", &nilObj };
node nil = &nilObj;
void mklist(node *n)
{
*n = nil;
}
As Stephen Docy mentioned, using typedef T *Tname; is generally a bad idea as it hides the fact that you're using a pointer, which can be confusing when you use Tname *n as (*n)->foo (I'd expect to use it as n->foo honestly). Some APIs do this, but they do it in a way that expresses that the variable is a pointer to an object rather than an object: instead of Node, something like NodeRef or NodePtr is used, signifying in the name that it's a pointer to a node, not a node. Apple's Core Foundation API uses names like this (e.g. CFStringRef). I highly suggest adopting a convention similar to this henceforth. The above code I posted might then look something like this:
static struct node nilObj = { 0, "null", "null", &nilObj };
nodeRef nil = &nilObj;
void mklist(nodeRef *n)
{
*n = nil;
}
I am writing a generic linked list implementation in pure C.
struct Node {
void *value;
struct Node *next;
};
struct LinkedList {
struct Node *start;
struct Node *end;
};
void LinkedList_new(struct LinkedList* llist) {
llist->start = 0;
llist->end = 0;
return;
}
void addNode( struct LinkedList *ll, void *_value ) {
if ( NULL == ll->start ) {
ll->start = (struct Node *) malloc( sizeof(struct Node) );
ll->end = ll->start;
} else {
ll->end->next = (struct Node *) malloc( sizeof(struct Node) );
ll->end = ll->end->next;
}
ll->end->value = _value;
return;
};
This all works great. My problem is when I get to printing value to the screen. I can't seem to find a generic implementation for printing.
Is there a way to determine the TYPE allocated to void *? (And then just do conversion using a switch statement)
void printFunc(int aInt) {
char str[15];
sprintf(str, "%d", aInt);
printf(str);
}
This is an implementation that works for int. Worst case I was thinking was writing a different function for each TYPE. Is this really my only route when using void *?
Is there a better way to do this?
No, there's no way to figure that out from the pointer alone. That would require type information to be stored at some well-defined location in all run-time structures, which is simply not how C uses the machine.
The common solution is for the user of the datatype to provide the print function that the application needs, since the application will know the type of data being stored. That is, there is usually an iteration function that takes a function pointer, calling the user's function (which might print the element) on each element of the list.
Here's how such a function could look:
void LinkedList_foreach(const LinkedList *start,
bool (*func)(void *element, void *data), void *data);
The above should call func() for each element of the list, passing it the element's data and the additional user-supplied data pointer which can be used by the caller to maintain state for the traversal. The callback func() should return false to stop the iteration, true to keep going.
To print an integer, assuming the integers are stored in the pointers, you could have:
static bool print_int(void *element, void *data)
{
printf("%d\n", (int) element);
return true;
}
Also, please don't cast the return value of malloc() in C.
I have a (hopefully) very simple issue that has been giving me problems for a while now. Given these structs
typedef struct
{
void * entity;
} link_t;
typedef struct
{
link_t * current;
} list_t;
and a function prototype
void *list_get_entity(list_t *list);
I need the function list_get_entity to return the address of the data that "entity" is pointing to. The best I've been able to do so far is
void *list_get_entity(list_t *list)
{
return list->current->entity;
}
which at least compiles and runs, but gives me gibberish. If for some reason the full file is needed to figure something out please let me know, although I'm sure there's other bugs in there I have yet to find because of this error.
Edit: fixed the code
To get the address of the data entity is pointing to just return it directly
return list->current->entity;
The void* is an address hence returning it directly by value will give the caller the address of the data
typedef struct
{
void * entity;
} link_t;
typedef struct
{
link_t * current;
} list_t;
void * list_get_entity(list_t *list)
{
return list->current->entity;
}
list->current is a pointer to link_t; list->current->entity is a pointer to entity type.
If you add &() around list->current->entity, it becomes pointer to pointer to void.
I am passing data of type struct Person to a linked list, so each node's data pointer points to a struct Person.
struct Person {
char name[16];
char text[24];
};
I am trying to traverse the list and print the name/text in each node by calling
traverse(&list, &print);
Prototype for traverse is:
void traverseList(struct List *list, void (*f)(void *));
List is defined as:
struct List {
struct Node *head;
};
My print function accepts a void * data :
print(void *data) { .... }
I know I have to cast the data to struct Person, correct?
struct Person *person = (struct Person *)data;
printf("%s", person->name);
I know this is not sufficient since I am getting an "initialization from incompatible pointer type" warning. How can I successfully cast a void* in this case? Thank you.
The problem's not with the cast, or even with the way you're passing the function around. The problem is that your declaration of print is missing a return type, in which case int is usually assumed. The compiler is complaining because you're passing an int (*)(void*) to a function that's expecting a void (*)(void*).
It's easy to fix: simply add void in front of your print function declaration. See:
https://gist.github.com/ods94065/5178095
My print function accepts a void * data
I would say, rewrite your print function by accepting struct Person * .
Your traverseList function accepts a function pointer (which takes a void pointer), but it doesn't accept an argument for that void data. It seems that this is what you're after:
void print (void* data)
{
printf("%s", ((struct Person*)data)->name);
}
void traverseList (struct List *list, void(*f)(void*), void* data)
{
f(data);
}
Then you can call traverseList:
traverseList (&list, &print, &person);
I'm a newbie in C and I am trying to implement a linked list which nodes are defined as follows:
typedef struct _cListNode
{
void *_data; //generic pointer to any data type
struct _cListNode *next; //next node in the list
} cListNode;
I need the InsertElement(cList myList, void *dataToInsert) function not to grow the list when the element that is being inserted is already in (i.e. no duplicates). My current problem is that I can't find a way to compare dataToInsert (the parameter) with _data (inside my node).
I thought of traversing the list externally before calling the InsertElement function and taking care of the comparisons outside the implementation of the list where I do know what the type is but I was hoping for a better design/solution.
Given two void pointers it is not possible to compare their data. This is because you do not know the size of the types of each of the pointers. If you want to compare their data, then you would need to store the pointers and the size of their data. Then you could use memcmp to compare the memory pointed at:
typedef struct _cListNode
{
void *_data; //generic pointer to any data type
size_t size;
struct _cListNode *next; //next node in the list
} cListNode;
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
So:
memcmp(node_data_ptr, new_data_ptr, size_of_item_pointed_at);
You should only do the memcmp if the size is the same for both pointers, otherwise they are clearly different and you don't want to end up comparing invalid memory.
Your other option is to compare the pointers themselves and see if they are pointing at the same section of memory. It depends on what you mean by "duplicate".
You may want to do something like this. I'm supposing your linked list structure is as follows:
typedef struct _cList
{
cListNode* head;
cListNode* tail;
size_t size;
} cList;
int contains(cList* list, void* data, size_t dataSize)
{
cListNode* temp = list->head;
while(temp)
{
if(!memcmp(data, temp->_data, dataSize))
return 1;
temp = temp->next;
}
return 0;
}
void InsertElement(cList* myList, void *dataToInsert, size_t dataSize)
{
if(!contains(myList,dataToInsert, dataSize))
{
//Insert Data
}
else
{
//Data Is already present.
}
}
You should create the struct cListNode as specified in #jmh's answer.