Если вы хотите от content
до хранить различных типов данных, а не указывать на объекты разных типов, то это неправильный способ go об этом. Вам было бы лучше использовать тип объединения:
struct listNode{
union {
int i;
char c;
char *s;
float f;
} content;
char datatype;
void *next;
};
Каждый элемент был бы назначен как
element1->content.s = "Hello World";
element1->datatype = 's';
element1->next = (struct listNode *) &element2;
element2->content.c = 'z';
element2->datatype = 'c';
element2->next = (struct listNode *) &element3;
element3->content.i = 5;
element3->datatype = 'i';
element3->next = (struct listNode *) NULL;
, и тогда ваши выходные логики c были бы
if ( item->datatype == 'i' )
printf( "%d\n", item->content.i );
else if ( item->datatype == 's' )
printf( "%s\n", item->content.s );
else if ( item->datatype == 'c' )
printf( "%c\n", item->content.c );
else if ( item->datatype == 'f' )
printf( "%f\n", item->content.f );
...
A void *
используется в качестве универсального c указателя типа; он не предназначен для хранения значений без указателей. Не гарантируется, что вы можете преобразовать исходный тип в указатель и обратно и получить исходное значение. Его главное достоинство заключается в том, что вы можете назначить любой тип указателя на void *
и наоборот, без необходимости явного приведения.
Если вы не хотите использовать union
, другой вариант - сохранить content
как void *
и динамически распределять память для хранения содержимого различных типов объектов, не являющихся указателями, и присвойте адрес этой памяти content
:
element1->content = "Hello, World"; // I'll explain this below
element1->datatype = 's';
element1->next = &element2;
element2->content = malloc( sizeof 'z' );
if ( element2->content )
*((int *)element2->content) = 'z'; // character constants have type int, not char!!
element2->next = &element3;
element3->content = malloc( sizeof 5 );
if ( element3->content )
*((int *)element3->content) = 5;
element3->next = NULL;
Вы спросите, почему я не делаю malloc
для строки "Hello, World"
, а это потому, что я не нужно. Выражения типа массива, включая строковые литералы, «распадаются» на выражения типа указателя, а значением выражения является адрес первого элемента массива. В этом случае я сохраняю адрес строкового литерала в content
. Поскольку строковые литералы существуют в течение всего жизненного цикла программы, это не проблема - этот указатель будет действителен в течение всего жизненного цикла программы.