Retrieving memory address with multiple nested struct pointers - 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.

Related

Why is this linked-list initialization not working?

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;
}

Generic programming in C

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.

Casting from void* to struct

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);

Need implementation for generic list in C that avoids duplicates at insertion

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.

c function merge help

I have two functions:
void free_this(THIS *this)
{
THIS *this_tmp;
while (this_tmp = this)
{
if (this->str)
free(this->str);
this = this_tmp->next;
free(this_tmp);
}
}
void free_that(THAT *that)
{
THAT *that_tmp;
while (that_tmp = that)
{
if (that->id)
free(that->id);
that = that_tmp->next;
free(that_tmp);
}
}
Since they are very similar I was trying to come up with one function to handle them both. I can already just use a pointer to point to the correct data to free (i.e. point to either str from THIS struct or to id of THAT struct) however I can't figure out how to get around what type of struct is being dealt with since I can't just use a void pointer since void* has no member named 'NEXT'.
Any ideas?
Maybe I should just combine the two structs THIS and THAT into one somehow? here they are:
typedef struct this {
struct this *next;
char *str;
} THIS;
typedef struct that {
struct that *next;
char *id;
unsigned short result;
OTHERTHING *optr;
} THAT;
Could I possibly use the offsetof function somehow to get the next element?
You could implement the free function with a void * and field offsets. Untested:
void free_either(void *either, size_t other_offset, size_t next_offset)
{
void *either_tmp;
while (either_tmp = either)
{
free((char *)either + other_offset);
either_tmp = (char *)either + next_offset;
free(either);
}
}
free_either(this,offsetof(THIS,str),offsetof(THIS,next));
free_either(that,offsetof(THAT,id),offsetof(THAT,next));
You could then create macros to replace the old free_this or free_that functions.
Depends on the exact structure of THIS and THAT. If they are very similar, especially if str and id have the same offsets, you may be able to merge them into one object.
structure THIS {
void* str;
...
};
structure THIS {
void* id; /* is at the same offset as str */
...
};
union THAS {
structure THIS this;
structure THAT that;
void* pointer; /* at the same offset as str and id */
};
/* and use it like */
void free_thas(THAS* thas) {
free(thas->pointer);
...
}
If you have a bad feeling about this, your are right. Some small change in THIS may cause THAT to explode and so on. Don't do it.
You have two different singly linked list types here. You could get around this by creating only a single type:
typedef struct node {
struct node *next;
void *data;
} NODE;
and have data point to either a char* (or simply a char) or another struct with the three data fields from THAT. Of course you have to remember to free() the data in your free_node() function.
Yet another way is through some primitive inheritance:
struct node {
struct node *next;
}
struct this {
struct node mynode;
...
}
struct that {
struct node mynode;
...
}
free_any(struct node *this)
{
struct node *this_tmp;
while (this_tmp = this)
{
this = this_tmp->next;
free(this_tmp);
}
}
This only works if "node" is at the top of the structures, and only allows you to thread one linked-list through these structures.
Also, this doesn't allow you to free anything specific to that type of structure; to do that, you would have to setup a callback function ( either by passing it in the free or in some control structure ) that would get invoked. I would probably instead implement a "pop" function which removes the element from the list, and to free the entire list I would pop off each element and then free them as required.
There are more fancy ways to do what you want - but the following example will suffice.
void free_that(void *mem, int type)
{
switch(type) {
case THIS_FLAG: {
THIS *this = (THIS*)mem;
for(this; this->str != NULL; this = this->next)
(void)free(this->str);
break;
}
case THAT_FLAG: {
THAT *that = (THAT*)mem;
for(that; that->id != NULL; that = that->next)
(void)free(that->id);
}
default: {
(void)free(mem);
}
}
return;
}
The more fancy way would be to add a void *mem as the first element in the structure and assign str and id as pointers that point to mem (where you malloc the memory). Doing this allows you to either always free the mem element or free the offset of zero cast to void*.

Resources