void *

T

TJ

Hello,

I want to adapt my linked list implementation to hold any data types. As I
understand it's a good place to use 'void *'. Here's what I've done:

struct list_node
{
void *data;
struct list_node *next;

};

typedef struct list_node node;

node* list_add_head(node **head, void *data)
{
node *n= malloc(sizeof *n);
/* check if n==NULL ...*/

n->data = (void *)data; /* is that correct use? */
n->next = *head;
...

}

Does such a use of 'void *' guarantee that I can supply various data types,
i.e. ints. long. chars and so forth?
Thanks in advance.

IIRC, packing ints/longs/chars into pointers is not standards
conforming code. You can put pointers to data objects into your list
struct. Pointers to functions are also not storeable in void*.

Cheers,

TJ
 
B

Barry Schwarz

Hello,

I want to adapt my linked list implementation to hold any data types. As I
understand it's a good place to use 'void *'. Here's what I've done:

struct list_node
{
void *data;
struct list_node *next;
};

It would probably help if your structure had a member which identified
the real type of whatever data pointed to.
typedef struct list_node node;

node* list_add_head(node **head, void *data)
{
node *n= malloc(sizeof *n);
/* check if n==NULL ...*/

n->data = (void *)data; /* is that correct use? */

n->data is a void*. data is a void*. What do you think the cast
accomplishes?
n->next = *head;

You need to set *head to n.
...
}

Does such a use of 'void *' guarantee that I can supply various data types,
i.e. ints. long. chars and so forth?

No, it guarantees that you can supply pointers to the various data
types (only object pointers, not function pointers).


Remove del for email
 
F

Flash Gordon

Roman Mashak wrote, On 28/06/07 21:35:
But the structure can't have members for all possible types. And I expected
'void *' is to hold _pointers_ on the objects of various types (perhaps I
wasn't very clear in my original post), i.e. I could you something like
this:

int main(void)
{
node *p = NULL;

list_add_head(&p, (int *)100);

This is *not* getting a pointer to an int, it is coercing an int in to
an int pointer. There is no guarantee that all int values can be
converted to pointers.
list_add_head(&p, (char *)'X');

This is converting another int (not char), this time to a pointer to
char. Same problem.
...
return 0;
}

That was my understanding of 'void *' concept.

The concept of void* is what you described in your text, *not* what you
show in your code. I.e.

void *p;
int i;
char c;
p = &i;
p = &c;

Note that it does *not* require a cast.

In fact at your level the first thing you should assume when you appear
to need a cast is that you have done something wrong and a cast is *not*
the solution. If it appears that you have not done anything wrong then
your next assumption should be that you have completely misunderstood
something fundamental and done something very wrong.

There are a few places where casts are required, but not in general
where you would expect.
So, n->data = data is enough?

When two variables are of the same type of *course* it is.

Personally I don't think you understand the concept of pointers yet, so
you need to read the sections of your text book and the comp.lang.c FAQ
that refer to pointers. The comp.lang.c FAQ is available at
http://c-faq.com/
 
U

user923005

But the structure can't have members for all possible types. And I expected
'void *' is to hold _pointers_ on the objects of various types (perhaps I
wasn't very clear in my original post), ...

He meant:

struct list_node
{
void *data;
unsigned datatype; /* 0 = invalid, 1=char, 2=short, 3=...*/
struct list_node *next;
};

[snip]
 
K

Keith Thompson

Flash Gordon said:
This is *not* getting a pointer to an int, it is coercing an int in to
an int pointer. There is no guarantee that all int values can be
converted to pointers.
[...]

Quibble: Well, yes, it is guaranteed. The result is
implementation-defined, and can even be a trap representation.
In particular, different integer values may convert to the same
pointer value (and almost certainly will if the integer type is
bigger than the pointer type).
 
R

Richard Heathfield

Roman Mashak said:

And I
expected 'void *' is to hold _pointers_ on the objects of various
types (perhaps I wasn't very clear in my original post), i.e. I could
you something like this:

int main(void)
{
node *p = NULL;

list_add_head(&p, (int *)100);

No. That's just silly.
list_add_head(&p, (char *)'X');
...
return 0;
}

That was my understanding of 'void *' concept.

Your understanding is going nowhere, I'm afraid - but that can be fixed,
if only you can put down your void * and your cast and your &, and
instead tell us what you're trying to do.
 
R

Richard Heathfield

Roman Mashak said:
I want to hold pointers on to objects of various types in the
structurre member, named 'data'. I declared it as 'void *' and faced
various problems
:(

That still isn't very clear. What real world problem are you trying to
solve? Here's my guess at what you want:

A container that can store any kind of object, such that you can process
the object (create it, initialise it, copy it, compare it, change it,
print it, etc) without the container knowing anything about its type.

Is that right?

If so, I can certainly help you. But at present, I still don't know what
you want.
 
R

Richard Heathfield

Roman Mashak said:
I'm implementing single linked list,
Aha!

I want to store in my LL objects of different types: ints, longs,
chars etc. My assumption was that declaring a structure member as
'void *' may help me (please also check my reply to Flash Gordon).

If you want to *store* objects in the linked list, as you say, then
you'll need to know how big they are so that you can copy them.
Otherwise you're not storing, just pointing.

Simple objects are easy to copy:

#include <stdlib.h>

void *objdup(const void *old, size_t size)
{
void *new = malloc(size);
if(new != NULL)
{
memcpy(new, old, size);
}
return new;
}

but some objects are more complicated than that - strings, structs with
pointers in them, etc. If you're only dealing with simple objects,
either make each list homogenous (i.e. only deals with objects of one
particular size) and keep a size in the header, or if you need
heterogenous lists, store a size and a type indicator in each node.

If you need to be able to store complicated objects - strings, or
anything with a pointer in it - you might want to look at callback
functions to do your copying (and other object-related activity) for
you.
 
R

Richard

Richard Heathfield said:
Roman Mashak said:



No. That's just silly.


Your understanding is going nowhere, I'm afraid - but that can be fixed,
if only you can put down your void * and your cast and your &, and
instead tell us what you're trying to do.

It seems fairly obvious to me.

A single set of code to store references to data elements of various types.
 
R

Richard

Richard Heathfield said:
Roman Mashak said:


If you want to *store* objects in the linked list, as you say, then
you'll need to know how big they are so that you can copy them.
Otherwise you're not storing, just pointing.

He was pointing and he specifically said that above. Yes, he got his
language wrong in the last reply - but you prompted him into that.

Why do you always feel the need to embellish and obfuscate?


Here:

,----
| I want to hold pointers on to objects of various types in the structurre
| member, named 'data'. I declared it as 'void *' and faced various problems
| :(
`---

How is that anyway unclear?
 
M

Manish Tomar

If you need to be able to store complicated objects - strings, or
anything with a pointer in it - you might want to look at callback
functions to do your copying (and other object-related activity) for
you.

He is write. What you want can be achieved with callback functions. In
fact, I've implemented very similar linked list storing void* and
taking in callbacks for data specific operations like:

int list_display(node *head, void (*disp)(void *data)) {
if (disp) {
(*disp)(head->data);
}
else {
printf("data %p\n", head->data);
}
}

similarly, getting element, freeing can take user specific callbacks.

Regards,
Manish
(http://manishtomar.blogspot.com)
 
B

Barry Schwarz

But the structure can't have members for all possible types. And I expected

No, but it could have an enum member which had values defined for
e_char, e_short, e_int, e_long, e_float, e_double, e_struct_1, etc so
that any code that needed to manipulate whatever data pointed to could
determine the real type.
'void *' is to hold _pointers_ on the objects of various types (perhaps I
wasn't very clear in my original post), i.e. I could you something like
this:

int main(void)
{
node *p = NULL;

list_add_head(&p, (int *)100);
list_add_head(&p, (char *)'X');

I hope not. Casting integer literals to pointers is implementation
defined at best. If an int must be aligned on a four-byte boundary,
you could never do
list_add_head(&p, (int*)5);

You really don't want data to contain the value of interest; you want
it to point to an object set to that value.
...
return 0;
}

That was my understanding of 'void *' concept.

A void* can point to any type of object. It cannot contain an
arbitrary value of any type. On my system, sizeof(void*) is 4 and
sizeof(double) is 8. I cannot stuff a double into a void* but I can
assign the address of a double to a void*. (It gets even worse if you
intend your structure to be able to point to other structures or
arrays.)
So, n->data = data is enough?

Yes. Since both types are the same, a cast is never needed.
Furthermore, there is an implied conversion in either direction
between any unqualified type of object pointer and void* so if either
operand is a void* a cast is not needed. (See your statement that
calls malloc for an example of this.)


Remove del for email
 
J

Jens Thoms Toerring

He was pointing and he specifically said that above. Yes, he got his
language wrong in the last reply - but you prompted him into that.

That's still absolutely unclear. One of the code snippets Roman
posted upthread on the use of the function was:

| int main(void)
| {
| node *p = NULL;
|
| list_add_head(&p, (int *)100);
| list_add_head(&p, (char *)'X');
| ...
| return 0;
| }

This makes it look as if he tries to store the value of an
object (of arbitrary type) in a void pointer and not just
pointers to objects. And that's what he then repeated in
words in his last post.

Or, if his other post is to believed,

| I want to hold pointers on to objects of various types in the structurre
| member, named 'data'. I declared it as 'void *' and faced various problems

then he might be assuming wrongly that e.g. "(int *) 100"
would result in a pointer to somewhere where the number 100
would be stored. So Roman may be believing that he want's
to store pointers, but what he's actually doing is storing
is a pointer that is the result of a non-portable conversion
data he won't be able to use reasonably. My bet at the moment
is that he actually wants to store values and doesn't realize
that casting to a void pointer and storing the result won't
do what he expects it to do. But he's the only person that
can tell us.
Why do you always feel the need to embellish and obfuscate?

Richard Heathfield is just trying to figure out what Roman
is up to and what exactly his mis-conceptions are. And what
you call "embellish and obfuscate" is actually trying to
elicit a clear answer about what Roman really wants to do.

And, of course, there also still remains the problem of how
to get the data out of the list again when it's not stored
what the original type was, independent of the question if
values or pointers are to be stored in the list elements.

Regards, Jens
 
R

Richard Heathfield

Richard said:

Why do you always feel the need to embellish and obfuscate?

I'm just trying to find out what he actually wants to do, which is still
far from clear (although clearer than it was).

If you really want to help him, why not answer his question yourself?
Here:

,----
| I want to hold pointers on to objects of various types in the
| structurre member, named 'data'. I declared it as 'void *' and faced
| various problems
| :(
`---

How is that anyway unclear?

If you think it's clear, answer it yourself.
 
C

CBFalconer

Roman said:
.... snip ...

I'm implementing single linked list, with such traditional node's
structure:

struct list_node
{
void *data;
struct list_node *next;
};

I want to store in my LL objects of different types: ints, longs,
chars etc. My assumption was that declaring a structure member as
'void *' may help me

That's fine so far, but whatever function receives the void* MUST
know what the actual type is, IF it is going to dereference it. So
you have code something like:

whatever foo(void *p, etc) {
T pt = p;

/* process based on pt */
return something;
}

Notice the lack of casts.
 
R

Roman Mashak

Hello,

I want to adapt my linked list implementation to hold any data types. As I
understand it's a good place to use 'void *'. Here's what I've done:

struct list_node
{
void *data;
struct list_node *next;
};

typedef struct list_node node;

node* list_add_head(node **head, void *data)
{
node *n= malloc(sizeof *n);
/* check if n==NULL ...*/

n->data = (void *)data; /* is that correct use? */
n->next = *head;
...
}

Does such a use of 'void *' guarantee that I can supply various data types,
i.e. ints. long. chars and so forth?
Thanks in advance.
 
F

Flash Gordon

Roman Mashak wrote, On 29/06/07 01:47:
Agree, I was mistaken. Here's the changed version:

struct list_node
{
void *data;
struct list_node *next;
};

int main(void)
{
int i, j;
node *p = NULL;
...
i = 10; j = 20;
list_add_tail(&p, &i);
list_add_tail(&p, &j);
}

Now p->data holds the pointers of 'i' and 'j', and this matches the concept
of generic pointer 'void *'. But how to print the _value_ of 'data'? This
code is not compilable:

while (p != NULL) {
printf("Node %p\nNext %p\nData %d\n\n", (void *)p, (void *)p->next,
*(p->data));
p = p->next;
}

warning: dereferencing 'void *' pointer
error: invalid use of void expression

Since a pointer to void gives no indication of what it points to how do
you expect the compiler to know? You have to tell it. In order to tell
it you have to decide on a way that you can decide, one possibility
being adding another field to your node specifying what the type is in
some manner.
And I think I used (void *) casting here properly, because otherwise
compiler generates warning: void format, node arg (arg 2).

Printing a pointer is one of the *very* few instances where you actually
need a cast (or a temporary).
I'm keen to understand the pointers hell.

Read the sections on pointers in the comp.lang.c FAQ and your text book
and ask specific questions about what you do not understand.
[skip]
The concept of void* is what you described in your text, *not* what you
show in your code. I.e.

<snip a lot of quote with no reply>

Please remove parts of the post you are not replying to as I have done here.
 
R

Roman Mashak

Barry Schwarz said:
It would probably help if your structure had a member which identified
the real type of whatever data pointed to.

But the structure can't have members for all possible types. And I expected
'void *' is to hold _pointers_ on the objects of various types (perhaps I
wasn't very clear in my original post), i.e. I could you something like
this:

int main(void)
{
node *p = NULL;

list_add_head(&p, (int *)100);
list_add_head(&p, (char *)'X');
...
return 0;
}

That was my understanding of 'void *' concept.
n->data is a void*. data is a void*. What do you think the cast
accomplishes?

So, n->data = data is enough?
 
R

Roman Mashak

Flash Gordon said:
This is *not* getting a pointer to an int, it is coercing an int in to an
int pointer. There is no guarantee that all int values can be converted to
pointers.
Agree, I was mistaken. Here's the changed version:

struct list_node
{
void *data;
struct list_node *next;
};

node* list_add_tail(node **head, void *data)
{
node *current = *head;
node *n;

n = malloc(sizeof *n);
if (n == NULL)
return NULL;

n->data = data;
n->next = NULL;

/* special case for length 0 */
if (current == NULL) {
*head = n;
} else {
/* locate the last node */
while (current->next != NULL) {
current = current->next;
}
current->next = n;
}

return n;
}

int main(void)
{
int i, j;
node *p = NULL;
...
i = 10; j = 20;
list_add_tail(&p, &i);
list_add_tail(&p, &j);
}

Now p->data holds the pointers of 'i' and 'j', and this matches the concept
of generic pointer 'void *'. But how to print the _value_ of 'data'? This
code is not compilable:

while (p != NULL) {
printf("Node %p\nNext %p\nData %d\n\n", (void *)p, (void *)p->next,
*(p->data));
p = p->next;
}

warning: dereferencing 'void *' pointer
error: invalid use of void expression

And I think I used (void *) casting here properly, because otherwise
compiler generates warning: void format, node arg (arg 2).

I'm keen to understand the pointers hell.

[skip]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top