Karsten has already addressed the problem of unsafe data types that are also accessed globally. Global variables and the limitation of a pointer field should be avoided. Especially if the code is to be used flexibly by other developers with as little adaptation effort as possible. In the following example, this is all solved dynamically and the data is copied so that the caller can also delete or overwrite it. Some effort would still be required to delete the list and to secure access for multithreading. In addition, the original data type and length could also be remembered to make the access verifiable later.
typedef struct nodetyp {
void* dataptr;
struct nodetype* next;
} node;
int save(node** head, void* p, size_t len)
{
if (len == 0)
return -1;
node* newnode = (node*)malloc(sizeof(node));
newnode->next = NULL;
newnode->dataptr = (void*)malloc(len);
memcpy(newnode->dataptr, p, len);
if (*head == NULL) {
*head = newnode;
return 0;
}
node* tmp = *head;
for ( ; tmp->next != NULL; tmp = tmp->next);
tmp->next = newnode;
return 0;
}
This approach could also be used with fields or structures without global variables.
int main(void)
{
node* head = NULL;
int rtn = 0;
int data1[5] = {1, 3, 6, 2, 4};
double data2[5] = { 2.1, 3.4, 1.6, 7.2, 8.3 };
rtn = save(&head, (void*)&data1[0], sizeof(data1));
...