Linked list with void *

D

dam_fool_2003

Hai,
I thank those who helped me to create a single linked list with int
type. Now I wanted to try out for a void* type. Below is the code:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<stddef.h>

struct node
{
void *data;
struct node *next;
};
struct node *insert(void *data,struct node **p)
{
void *temp;
struct node *q;
q = malloc(sizeof *q);
if(q == NULL)
{
printf("MEM ERROR\n");
exit(EXIT_FAILURE);
}
else
{
temp = malloc(sizeof *temp);
if(temp == NULL)
{
printf("MEM ERROR2\n");
exit(EXIT_FAILURE);
}
else
{
data = temp;
q ->data = data;
q -> next = *p;
q-> next = NULL;
*p = q;
return *p;
}
}
return NULL;
}

void disp(struct node *p)
{


for(;p != NULL; p=p->next)
printf("%s",p->data);
}
int main(void)
{
char *data;
int s=49,*a = &s;
struct node *p=NULL;
scanf("%s",data);
insert(data,&p);
disp(p);
insert(a,&p);
disp(p);
return 0;
}

OUTPUT:

latiÿÿÿÿ e

I have some questions:

1) When we use printf function to print something we use format
specifier for printing. (%s,%d etc). But when it comes to void*, do we
have a format specifier? If not then how will we print the void* in
the above type of program where the printing definition is in one
function and that function is called for the printing job?
2) The output I got is totally unexcepted. What ever I type I get the
same above out put. Why?
3) When we copy two void pointers shall we use just the assignment
operator or do we have to use memcpy, memset functions. Is the out put
in the above is different because of this being not used?

Thanks in advance.
 
M

Mark A. Odell

(e-mail address removed) wrote in

int main(void)
{
char *data;

What does data point to? Junk, that's what. You don't own what it points
to so scanf()'ing into is very bad. Malloc() some stinking memory for it
or declare as an array sufficient to hold what you expect the use to enter
(knowing that this still leave you open to buffer overrun).
int s=49,*a = &s;
struct node *p=NULL;
scanf("%s",data);

POP! You scanf'd into some place you shouldn't.
 
M

Martijn

1) When we use printf function to print something we use format
specifier for printing. (%s,%d etc). But when it comes to void*, do we
have a format specifier? If not then how will we print the void* in
the above type of program where the printing definition is in one
function and that function is called for the printing job?

A void* is identified with %p, just as any other pointer. If you make it to
hold different data (e.g. an integer), make sure you cast it when you feed
it to printf (and use the appropriate identifier).
3) When we copy two void pointers shall we use just the assignment
operator or do we have to use memcpy, memset functions. Is the out put
in the above is different because of this being not used?

If you want to copy the pointers themselves, just use the assignment
operator. If you want to copy what they point at, use memcpy or memmove (or
strcpy for strings) - memset fills a region of memory with a certain byte.

Good luck,
 
A

Al Bowers

struct node
{
void *data;
struct node *next;
};
struct node *insert(void *data,struct node **p)
{
void *temp;
struct node *q;
q = malloc(sizeof *q);
if(q == NULL)
{
printf("MEM ERROR\n");
exit(EXIT_FAILURE);
}
else
{
temp = malloc(sizeof *temp);
...........snip.............


OUTPUT:

latiÿÿÿÿ e

I have some questions:

1) When we use printf function to print something we use format
specifier for printing. (%s,%d etc). But when it comes to void*, do we
have a format specifier? If not then how will we print the void* in
the above type of program where the printing definition is in one
function and that function is called for the printing job?

printf has different specifiers for different typed. The specifier for
void pointer is %p. However, in using the generic struct, you will
be converting the void *data to some other type. The code you write
and functions like printf will refer to this type. For example say
void *data will be pointing to a string. Then the specifier would
be %s and printf would look like this: printf("%s\n",(char *)q->data).
2) The output I got is totally unexcepted. What ever I type I get the
same above out put. Why?

The code has numerous errors. I am surprised that it compiled at all.
You have.
void *temp;
then you use function malloc.
..... malloc(sizeof *temp);
The sizeof operand, *temp, is an incomplete type and is not allowed.
3) When we copy two void pointers shall we use just the assignment
operator or do we have to use memcpy, memset functions. Is the out put
in the above is different because of this being not used?

The operations you use will depend on the data type you are using.
For example, a link list of names (strings), could be as follows.

#include<stdlib.h>
#include<stdio.h>
#include<string.h>

struct node
{
void *data;
struct node *next;
};
struct node *insertName(const char *data,struct node **p)
{
void *temp;
struct node *q;

q = malloc(sizeof *q);
if(q != NULL)
{
temp = malloc(strlen(data)+1);
if(temp == NULL)
{
free(q);
q = NULL;
}
else
{
q ->data = temp;
strcpy(q->data,data);
q ->next = *p;
*p = q;
}
}
return q;
}

void dispNames(struct node *p)
{
for(;p != NULL; p=p->next)
printf("%s\n",(char *)p->data);
}

void freeAll( struct node **p)
{
struct node *tmp, *current;

for(current = *p; current; current = tmp)
{
tmp = current->next;
free(current->data);
free(current);
}
*p = NULL;
}

int main(void)
{
unsigned i,number;
char buf[80],*s;
struct node *names=NULL;

printf("Enter the number of names to add to the list: ");
fflush(stdout);
fgets(buf,sizeof buf, stdin);
number = atoi(buf);
putchar('\n');
for(i = 0;i < number;i++)
{
printf("Enter name #%d: ",i+1);
fflush(stdout);
fgets(buf,sizeof buf,stdin);
if((s = strrchr(buf,'\n')) != NULL) *s = '\0';
insertName(buf,&names);
}
puts("\n\nThe names in the list are");
dispNames(names);
freeAll(&names);
return 0;
}
 
D

dam_fool_2003

Al Bowers said:
struct node
{
void *data;
struct node *next;
};
struct node *insert(void *data,struct node **p)
{
void *temp;
struct node *q;
q = malloc(sizeof *q);
if(q == NULL)
{
printf("MEM ERROR\n");
exit(EXIT_FAILURE);
}
else
{
temp = malloc(sizeof *temp);
..........snip.............


OUTPUT:

latiÿÿÿÿ e

I have some questions:

1) When we use printf function to print something we use format
specifier for printing. (%s,%d etc). But when it comes to void*, do we
have a format specifier? If not then how will we print the void* in
the above type of program where the printing definition is in one
function and that function is called for the printing job?

printf has different specifiers for different typed. The specifier for
void pointer is %p. However, in using the generic struct, you will
be converting the void *data to some other type. The code you write
and functions like printf will refer to this type. For example say
void *data will be pointing to a string. Then the specifier would
be %s and printf would look like this: printf("%s\n",(char *)q->data).
2) The output I got is totally unexcepted. What ever I type I get the
same above out put. Why?

The code has numerous errors. I am surprised that it compiled at all.
You have.
void *temp;
then you use function malloc.
.... malloc(sizeof *temp);
The sizeof operand, *temp, is an incomplete type and is not allowed.
3) When we copy two void pointers shall we use just the assignment
operator or do we have to use memcpy, memset functions. Is the out put
in the above is different because of this being not used?

The operations you use will depend on the data type you are using.
For example, a link list of names (strings), could be as follows.

#include<stdlib.h>
#include<stdio.h>
#include<string.h>

struct node
{
void *data;
struct node *next;
};
struct node *insertName(const char *data,struct node **p)
{
void *temp;
struct node *q;

q = malloc(sizeof *q);
if(q != NULL)
{
temp = malloc(strlen(data)+1);
if(temp == NULL)
{
free(q);
q = NULL;
}
else
{
q ->data = temp;
strcpy(q->data,data);
q ->next = *p;
*p = q;
}
}
return q;
}

void dispNames(struct node *p)
{
for(;p != NULL; p=p->next)
printf("%s\n",(char *)p->data);
}

void freeAll( struct node **p)
{
struct node *tmp, *current;

for(current = *p; current; current = tmp)
{
tmp = current->next;
free(current->data);
free(current);
}
*p = NULL;
}

int main(void)
{
unsigned i,number;
char buf[80],*s;
struct node *names=NULL;

printf("Enter the number of names to add to the list: ");
fflush(stdout);
fgets(buf,sizeof buf, stdin);
number = atoi(buf);
putchar('\n');
for(i = 0;i < number;i++)
{
printf("Enter name #%d: ",i+1);
fflush(stdout);
fgets(buf,sizeof buf,stdin);
if((s = strrchr(buf,'\n')) != NULL) *s = '\0';
insertName(buf,&names);
}
puts("\n\nThe names in the list are");
dispNames(names);
freeAll(&names);
return 0;
}

Sir,
Thanks for the code.It works well except that it prints the out put
in reverse order.
The function *insertName() takes only char pointer (string) as a
input. If some body wants to insert int data type then he has to
redefine a different function which takes int type as a input in its
parameter. I am trying to make the function *insertName() generic with
void pointer as a parameter. What to do? Cannot we make the whole
thing in a preprossor macro?

#define list(xxx) \
struct ann{ \
struct ann * next; \
xxx item; }*

int main(void)
{
list(int) fool1 = 10;
printf("%s\n",(int)fool1);
return 0;
}
OUTPUT:
10

Even though I am getting warning about the initialization I am getting
the output correctly! But I am not claming that the above code is
correct but may be to the point.
But we cannot make two objects with list(xxx). I don't know why?
 
A

Al Bowers

Thanks for the code.It works well except that it prints the out put
in reverse order.
The function *insertName() takes only char pointer (string) as a
input. If some body wants to insert int data type then he has to
redefine a different function which takes int type as a input in its
parameter. I am trying to make the function *insertName() generic with
void pointer as a parameter. What to do? Cannot we make the whole
thing in a preprossor macro?

You can make a macro. But not the way you did it here.
First of all you can make the insert function generic by including
a size argument where you can allocate the size and then use memcpy
to copy. The prototype:
struct node *insert(const void *data,size_t size, struct node **p);
And the call would be like:
insert(buf,sizeof buf,&names);

You can use the macro for the display (printing) of the list.

#define disp(NODE,SPEC,TYPE) {struct node *tmp;\
for(tmp = NODE;tmp != NULL; tmp=tmp->next)\
printf(#SPEC"\n",TYPE(tmp->data));}

There are probably better ways or languages to do this.
#define list(xxx) \
struct ann{ \
struct ann * next; \
xxx item; }*

int main(void)
{
list(int) fool1 = 10;
printf("%s\n",(int)fool1);
return 0;
}

Plug these ideas into your code and it appears to work.

#include<stdlib.h>
#include<stdio.h>
#include<string.h>

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

#define disp(NODE,SPEC,TYPE) {struct node *tmp;\
for(tmp = NODE;tmp != NULL; tmp=tmp->next)\
printf(#SPEC"\n",TYPE(tmp->data));}

void freeAll( struct node **p);
struct node *insert(const void *data,size_t size, struct node **p);

int main(void)
{
int i,number;
char buf[80],*s;
struct node *names=NULL;

printf("Enter the number of names to add to the list: ");
fflush(stdout);
fgets(buf,sizeof buf, stdin);
number = atoi(buf);
putchar('\n');
for(i = 0;i < number;i++)
{
printf("Enter name #%d: ",i+1);
fflush(stdout);
fgets(buf,sizeof buf,stdin);
if((s = strrchr(buf,'\n')) != NULL) *s = '\0';
insert(buf,sizeof buf, &names);
}
puts("\n\nThe names in the list are");
disp(names,%s,(char *));
freeAll(&names);
puts("\n**********************\nList of integers");
printf("Enter the number of integers to add to the list: ");
fflush(stdout);
fgets(buf,sizeof buf, stdin);
number = atoi(buf);
putchar('\n');
for(i = 0;i < number;i++)
{
int value;
printf("Enter integer #%d: ",i+1);
fflush(stdout);
fgets(buf,sizeof buf,stdin);
value = atoi(buf);
insert(&value,sizeof value, &names);
}
puts("\n\nThe integers in the list are");
disp(names,%d,*(int*));
freeAll(&names);
puts("\n**********************\nList of type doubles");
printf("Enter the number of doubles to add to the list: ");
fflush(stdout);
fgets(buf,sizeof buf, stdin);
number = atoi(buf);
putchar('\n');
for(i = 0;i < number;i++)
{
double value;
printf("Enter double value #%d: ",i+1);
fflush(stdout);
fgets(buf,sizeof buf,stdin);
value = atof(buf);
insert(&value,sizeof value, &names);
}
puts("\n\nThe numbers(2 decimal places) in the list are");
disp(names,%.2f,*(double*));
freeAll(&names);
return 0;
}

struct node *insert(const void *data,size_t size, struct node **p)
{
void *temp;
struct node *q, *cur;

q = malloc(sizeof *q);
if(q != NULL)
{
temp = malloc(size);
if(temp == NULL)
{
free(q);
q = NULL;
}
else
{
q ->data = temp;
memcpy(q->data,data,size);
q ->next = NULL;
if(*p == NULL) *p = q;
else
{
for(cur = *p; cur->next; cur = cur->next) ;
cur->next = q;
}
}
}
return q;
}

void freeAll( struct node **p)
{
struct node *tmp, *current;

for(current = *p; current; current = tmp)
{
tmp = current->next;
free(current->data);
free(current);
}
*p = NULL;
}
 
D

dam_fool_2003

Al Bowers said:
You can make a macro. But not the way you did it here.
First of all you can make the insert function generic by including
a size argument where you can allocate the size and then use memcpy
to copy. The prototype:
struct node *insert(const void *data,size_t size, struct node **p);
And the call would be like:
insert(buf,sizeof buf,&names);

You can use the macro for the display (printing) of the list.

#define disp(NODE,SPEC,TYPE) {struct node *tmp;\
for(tmp = NODE;tmp != NULL; tmp=tmp->next)\
printf(#SPEC"\n",TYPE(tmp->data));}

There are probably better ways or languages to do this.


Plug these ideas into your code and it appears to work.

#include<stdlib.h>
#include<stdio.h>
#include<string.h>

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

Thanks for the code .Btw it is not a home work.
 

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

Queue in C 25
Infinite loop problem 1
Stack using doubly linked list 1
linked list 19
Queue in C 0
double linked list 4
Singly Linked List in C 62
linked list 26

Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
KetoBurn
Top