I have a problem in return values int/double using void*.
For example:
#include "stdio.h"
#include "stdlib.h"
typedef struct list {
void *info;
struct list *prox;
} List;
typedef struct queue {
List* begin;
List* end;
} Queue;
Queue* create_queue (void) {
Queue* f = (Queue*) malloc(sizeof(Queue));
f->begin = f->end = NULL;
return f;
}
Queue* insert_queue_end (List* end, void* v) {
List* p = (List*) malloc(sizeof(List));
p->info=v;
p->prox=NULL;
if(end!=NULL) {
end->prox=p;
}
return p;
}
double queue_empty_double(Queue* f) {
return (f->begin==NULL);
}
double queue_remove_double(Queue* f) {
List* t;
double v;
if(queue_empty_double(f)) {
exit(1);
}
t=f->begin;
v=*((double*)(t->info));
f->begin=t->prox;
if (f->begin==NULL) {
f->end = NULL;
}
free(t);
printf("%.3lf\n",v);
}
void insert_queue(Queue* f, void* v) {
f->end = insert_queue_end(f->end,v);
if(f->begin==NULL) {
f->begin=f->end;
}
}
void print_queue_double(Queue* f) {
List* i;
for(i=f->begin;i!=NULL;i=i->prox)
printf("%.3lf\n",*((double*)i->info));
}
int main () {
Queue* f;
f = create_queue();
char ent1[100];
double n1;
scanf("%s",ent1);
while(ent1[0]!='X')
{
if(ent1[0]=='E') {
scanf("%lf",&n1);
insert_queue(f,&n1);
scanf("%s",ent1);
}
else if (ent1[0]=='D') {
queue_remove_double(f);
scanf("%s",ent1);
}
}
}
But the function doesn't work with double values, just with int.
Another new code, now the code can print double but in the function queue_remove_double there's a problem, she should remove the first element from a queue and print the first element. I believe this problem is from the generic struct because the function remove the first and print him in a normal struct.
Input:
E 1.2
E 2.1
D
X
Output:
1.200
The wrong output:
2.100
It works on codeblocks ide. Specify the type of *info to know how to cast the pointer.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef enum DataTypes {
INTEGER,
FLOAT,
DOUBLE,
CHAR
} DataType;
typedef struct list {
void *info;
struct list *next;
DataType type;
} List;
List* create_list(void *firstInfo, DataType firstType)
{
List *f=(List*)malloc(sizeof(List));
f->info=firstInfo;
f->type=firstType;
f->next=NULL;
return f;
}
List* insertion(List *end, void *data, DataType type)
{
List *p=(List*)malloc(sizeof(List));
p->info=data;
p->next=NULL;
p->type=type;
if(end != NULL)
{
end->next=p;
}
return p;
}
void showTheList(List **theBase)
{
List *run=*theBase;
while(run != NULL)
{
switch(run->type)
{
case INTEGER:
printf("Showing the value: %d \n",*((int*)run->info));
break;
case FLOAT:
printf("Showing the value: %f \n",*((float*)run->info));
break;
case DOUBLE:
printf("Showing the value: %lf \n",*((double*)run->info));
break;
default:
printf("Showing the value: %c \n",*((char*)run->info));
}
run=run->next;
}
}
List* getEnd(List **theBase)
{
List *run=*theBase;
while(run->next != NULL)
run=run->next;
return run;
}
void clearList(List **theBase)
{
List *run=(*theBase)->next;
free(*theBase);
while(run != NULL)
{
*theBase=run;
run=run->next;
free(*theBase);
}
*theBase=NULL;
}
int main(void)
{
List *theList=NULL;
int valA=10;
float valB=1.25;
double valC=23.45;
char valD='C';
theList=create_list(&valA,INTEGER);
insertion(getEnd(&theList),&valB,FLOAT);
insertion(getEnd(&theList),&valC,DOUBLE);
insertion(getEnd(&theList),&valD,CHAR);
showTheList(&theList);
clearList(&theList);
if(theList == NULL)
printf("Ok, all operations realized !");
return 0;
}
Try use a cast with the pointer. You need to know the type of the pointer.
void print_queue_double(Queue* f)
{
List* i;
for(i=f->begin;i!=NULL;i=i->prox)
printf("%.3lf\n",*((double*)i->info));
}
Your problem is pointer. If you use n1, then void * always contain the last n1 value because points to n1. Then when you free the list (queue_remove_double), always is show the value of n1 (the most recent)...
Some Solutions:
(1) Array - showed below - is limited....
(2)New double value with the copy of variable (malloc double) - "ilimited" (limit of your memory...)
In the new double case:
List* insert_queue_end (List* end, void* v) {
List* p = (List*) malloc(sizeof(List));
double *data=(double*)malloc(sizeof(double)); /*New double new address*/
*data=*((double*)v); /*Copy the VALUE and not the address to new double in new and fixed address*/
/*void* points to a new double with a new address in memory */
p->info=data;
p->prox=NULL;
if(end!=NULL) {
end->prox=p;
}
return p;
}
Don't forget to free the memory from the new double in the remove function !
SOME SOLUTIONS:
SOLUTION 1 - The array of doubles:
#include "stdio.h"
#include "stdlib.h"
typedef struct list {
void *info;
struct list *prox;
} List;
typedef struct queue {
List* begin;
List* end;
} Queue;
Queue* create_queue (void) {
Queue* f = (Queue*) malloc(sizeof(Queue));
f->begin = f->end = NULL;
return f;
}
/*Yes the type of return is List* and not Queue* - check your code */
List* insert_queue_end (List* end, void* v) {
List* p = (List*) malloc(sizeof(List));
///If you want create a new double this is the local - don't use the same address in v !
p->info=v;
p->prox=NULL;
if(end!=NULL) {
end->prox=p;
}
return p;
}
double queue_empty_double(Queue* f) {
return (f->begin==NULL);
}
double queue_remove_double(Queue* f) {
List* t;
double v;
double isRemoved=0;
if(queue_empty_double(f)) {
exit(1);
}
t=f->begin;
v=*((double*)(t->info));
f->begin=t->prox;
if (f->begin==NULL) {
f->end = NULL;
}
free(t);
printf("%.3lf\n",v);
}
void insert_queue(Queue* f, void* v) {
f->end = insert_queue_end(f->end,v);
if( f->begin==NULL) {
f->begin=f->end;
}
}
void print_queue_double(Queue* f) {
List* i;
for(i=f->begin;i!=NULL;i=i->prox)
printf("%.3lf\n",*((double*)i->info));
}
int main () {
Queue* f;
f = create_queue();
char ent1[100];
///One Double Allocated - only one address in memory !!!
///double n1;
double listOfDoubles[20]; ///All doubles allocated and one per one have a address in memory !!!
int countDoubles=0;
scanf("%s",ent1);
while(ent1[0]!='X' && countDoubles < 20)
{
if(ent1[0]=='E') {
///IN YOUR CODE:
///Fill the same one double...
///scanf("%lf",&n1);
///Testing new code
scanf("%lf",&listOfDoubles[countDoubles]); ///a new double with your address
///IN YOUR CODE:
///The same address of one variable. The same result.
///Remember void * is a pointer and use the address of n1, and then, print the most recent &n1 content...
///insert_queue(f,&n1);
///A new double in a new address, the content is not equal
insert_queue(f,&listOfDoubles[countDoubles]);
countDoubles++;
}
else if (ent1[0]=='D') {
///free the address and decrement the index of array to reuse a double
queue_remove_double(f);
countDoubles--;
}
else
{
///Print the list - and see the result "debug"
print_queue_double(f);
}
scanf("%s",ent1);
}
free(f);
}
SOME SOLUTIONS:
SOLUTION 2 - A new double with the copy of value
#include "stdio.h"
#include "stdlib.h"
typedef struct list {
void *info;
struct list *prox;
} List;
typedef struct queue {
List* begin;
List* end;
} Queue;
Queue* create_queue (void) {
Queue* f = (Queue*) malloc(sizeof(Queue));
f->begin = f->end = NULL;
return f;
}
/*Yes the type of return is List* and not Queue* check your code */
List* insert_queue_end (List* end, void* v) {
List* p = (List*) malloc(sizeof(List));
double *data=(double*)malloc(sizeof(double)); /*New double new address*/
*data=*((double*)v); /*Copy the VALUE and not the address to new double in new and fixed address*/
/*void* points to a new double with a new address in memory */
p->info=data;
p->prox=NULL;
if(end!=NULL) {
end->prox=p;
}
return p;
}
double queue_empty_double(Queue* f) {
return (f->begin==NULL);
}
double queue_remove_double(Queue* f) {
List* t;
double v;
double isRemoved=0;
if(queue_empty_double(f)) {
exit(1);
}
t=f->begin;
v=*((double*)(t->info));
f->begin=t->prox;
if (f->begin==NULL) {
f->end = NULL;
}
free(t->info); ///free the double
free(t);
printf("%.3lf\n",v);
}
void insert_queue(Queue* f, void* v) {
f->end = insert_queue_end(f->end,v);
if( f->begin==NULL) {
f->begin=f->end;
}
}
void print_queue_double(Queue* f) {
List* i;
for(i=f->begin;i!=NULL;i=i->prox)
printf("%.3lf\n",*((double*)i->info));
}
int main () {
Queue* f;
f = create_queue();
char ent1[100];
double n1;
int countDoubles=0;
scanf("%s",ent1);
while(ent1[0]!='X' && countDoubles < 20)
{
if(ent1[0]=='E') {
scanf("%lf",&n1);
insert_queue(f,&n1);
}
else if (ent1[0]=='D') {
queue_remove_double(f);
}
else
{
///Print the list - and see the result "debug"
print_queue_double(f);
}
scanf("%s",ent1);
}
free(f);
}
Related
For context, I'm a new programmer to C and I wanted to make a toy implementation of a dictionary/map from a 'Person' struct to an integer. I'm using separate chaining, so I have a hash table of linked list pointers.
So far, I've been able to add one value to the linked list just fine, but when I call the function to get the value for the Person key I'm using, the memory at one of my nodes seems to get overwritten.
More info if it's helpful, using a singly linked list with one sentinel node at the head and a tail reference.
New to StackOverflow, so I can't actually embed the image, but pictured on left is the HashTable at the beginning of the function call, when nothing has been changed. The relevant stuff is the expanded part of the Variables menu, which shows that at position 58 is a pointer to 0x61f8e0, the linked list. The linked list has a head pointer to 0x61f760, which is the sentinel value, and a tail pointer to 0x61f864, currently pointing to a Node with the value (3) for a Person named Robert who's 36 years old. The tail pointer's next field points to 0x0 (not pictured), like intended. The picture follows: https://i.stack.imgur.com/F9EJ9.png
This is what happens as soon as the first statement (which hashes the Person pointer very naively) is executed: https://i.stack.imgur.com/UJvGy.png. As you'll see, the value is now some random long number, the intrinsic age is now 1 instead of 36, the saved name is now gibberish, and worst of all the next pointer now points somewhere completely random (0x61fb10).
The function in question follows.
int tableGet(HashTable t, Person key) {
int position = hash(&key) % 100;
List* listLoc = t.table[position];
if ((int) listLoc == 0) {
return -1;
}
Node curr = *(listLoc -> head);
while (curr.next != NULL) {
if (curr.savedAge == key.age && curr.savedName == key.name) {
return curr.val;
}
curr = *curr.next;
}
return -1;
}
Here is the hash function, in case that's what's causing the problems.
int hash(Person* p) {
int sum;
Person person = *p;
int i = 0;
char nameChar = person.name[i];
while (nameChar != '\0'){
sum += (int) nameChar;
i += 1;
nameChar = person.name[i];
}
return (int) (person.age + sum);
}
And just because why not, here's all of the short amount of code I've written for this.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
typedef struct Node {
int val;
int savedAge;
char savedName[100];
struct Node* next;
} Node;
typedef struct {
int age;
char name[100];
} Person;
typedef struct {
Node* head;
Node* tail;
} List;
typedef struct {
List* table[100];
} HashTable;
int hash(Person*);
Person person(int age, char name[]) {
Person p;
p.age = age;
strcpy(p.name, name);
return p;
}
Node node(int val, Person p, Node* next) {
Node n;
n.val = val;
strcpy(n.savedName, p.name);
n.savedAge = p.age;
n.next = next;
return n;
}
List list() {
List l;
Node head = node(-1, person(0, "SENTINEL"), NULL);
l.head = &head;
l.tail = l.head;
return l;
}
void listAdd(List* l, Node n) {
Node* newTailPtr = &n;
l -> tail -> next = newTailPtr;
l -> tail = newTailPtr;
}
HashTable table() {
int table[100] = {0};
HashTable t;
memcpy(t.table, table, sizeof table);
return t;
}
HashTable tableAdd(HashTable t, Person key, int val) {
int num = hash(&key) % 100;
List* loc = t.table[num];
if ((int) loc == 0) {
List newList = list();
t.table[num] = &newList;
}
listAdd((List*) t.table[num], node(val, key, NULL));
return t;
}
int tableGet(HashTable t, Person key) {
int position = hash(&key) % 100;
List* listLoc = t.table[position];
if ((int) listLoc == 0) {
return -1;
}
Node curr = *(listLoc -> head);
while (curr.next != NULL) {
if (curr.savedAge == key.age && curr.savedName == key.name) {
return curr.val;
}
curr = *curr.next;
}
return -1;
}
int hash(Person* p) {
int sum;
Person person = *p;
int i = 0;
char nameChar = person.name[i];
while (nameChar != '\0'){
sum += (int) nameChar;
i += 1;
nameChar = person.name[i];
}
return (int) (person.age + sum);
}
int main() {
Person bob = person(36, "Robert");
printf(bob.name);
printf("\n");
HashTable tab = table();
tab = tableAdd(tab, bob, 3);
printf("Added Robert to table as 3\n");
int val = tableGet(tab, bob);
if (val == 3) {
printf("Success!\n");
} else {
printf("Failure, val is %d\n", val);
}
return 0;
}
I have generic link list in C that know how to push struct to list.
The problem is the I can't implement generic search in those link list:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
struct Node
{
void *data;
struct Node *next;
};
void push(struct Node** head_ref, void *new_data, size_t data_size)
{
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->data = malloc(data_size);
new_node->next = (*head_ref);
int i;
for (i=0; i<data_size; i++)
*(char *)(new_node->data + i) = *(char *)(new_data + i);
(*head_ref) = new_node;
}
struct A
{
int a1;
long a2;
};
struct B
{
long b1;
int b2;
};
void find_a1_in_a_list (int desire_a1 , struct Node *a_list)
{
struct A *a;
while(NULL != a_list)
{
a = (struct A*) a_list->data;
if(a->a1 == desire_a1)
printf("found!\n");
a_list = a_list->next;
}
}
void find_b1_in_b_list (long desire_b1 , struct Node *b_list)
{
struct B *b;
while(NULL != b_list)
{
b = (struct B*) b_list->data;
if(b->b1 == desire_b1)
printf("found!\n");
b_list = b_list->next;
}
}
void find_generic (void* desire_value,int off,struct Node *list)
{
while(NULL != list)
{
void* check_value_void = list->data + off;
int check_value_cast = *(int *) check_value_void; //How to know if cast to int or long ?????
if(check_value_cast == *(int *)desire_value) //How to know if cast to int or long ?????
printf("found generic!\n");
list = list->next;
}
}
void main()
{
struct Node *a_list = NULL;
struct A a;
a.a1=1;
a.a2=2;
push(&a_list, &a, sizeof(struct A));
find_a1_in_a_list(1,a_list);
struct Node *b_list = NULL;
struct B b;
b.b1=1;
b.b2=2;
push(&b_list, &b, sizeof(struct B));
find_b1_in_b_list(1,b_list);
//tried to make it generic
int search = 3;
find_generic(&search,offsetof(struct A, a2),a_list);
}
As you can I tried to makes generic search in function find_generic by passing the offset to the value in struct, that code works but only for int
but how can I pass to this generic function if I want to search int or long ,so I will know how to makes cast ?
Is there any way to cast void * by size so I can pass sizeof(int) or sizeof(long) and makes the casting by this value? or maybe another way?
Passing the compare function directly instead of playing with offsetof/sizeof will be more flexible:
struct Node *find_generic (struct Node *list,
int (*fn_cmp)(void const *a, void const *b),
void const *data)
{
while (list) {
if (fn_cmp(list->data, data) == 0)
break;
list = list->next;
}
return list;
}
and then create custom compare functions
static int cmp_A(void const *a_, void const *b_)
{
struct A const *a = a_;
struct A const *b = b_;
if (a->a1 == b->a1 && a->a2 == b->a2)
return 0;
return 1;
}
and call it like
struct A key = {
.a1 = 23,
.a2 = 42,
};
find_generic(a_list, cmp_A, &key);
My code is basically functions used for making/using a stack. I've tried almost everything, but I don't know why my program is displaying this error:
Error: Syntax error before 'struct'
#include "stack.h"
#include <stdio.h>
#include <stdlib.h>
#define CAPACITY 128
struct stack_struct {
ElemType items[CAPACITY];
int top;
};
StackPtr stk_create(){
StackPtr s = malloc(sizeof(struct stack_struct));
s->top = -1; // stack initially empty
return s;
}
// TODO
StackPtr stk_clone(StackPtr s) {
return NULL; // temporary placeholder
}
void stk_free(StackPtr s) {
free(s);
}
int stk_push(StackPtr s, ElemType val){
if(s->top == CAPACITY - 1)
struct stack_struct * temp;
temp = (struct stack_struct*)malloc(sizeof(struct stack_struct));
s->top++;
s->items[s->top] = val;
return 1;
}
ElemType stk_pop(StackPtr s){
if(s->top == -1)
abort(); // library function which terminates program!!!
s->top--;
return s->items[s->top+1];
}
int stk_is_full(StackPtr s){
return s->top == CAPACITY-1;
}
int stk_is_empty(StackPtr s){
return s->top == -1;
}
int stk_size(StackPtr s) {
return s->top+1;
}
void stk_clear(StackPtr s){
s->top = -1;
}
void stk_print(StackPtr s) {
int i;
printf("\n----TOP-----\n");
for(i=s->top; i>=0; i--) {
printf(FORMAT_STRING, s->items[i]);
}
printf("---BOTTOM---\n");
}
int main() {
StackPtr sptr;
sptr = stk_create();
stk_push(sptr, 1.7);
stk_push(sptr, 3.14);
stk_print(sptr);
stk_pop(sptr);
stk_print(sptr);
stk_free(sptr);
}
As I could see, function stack_push should look like this
int stk_push(StackPtr s, ElemType val){
if(stk_is_full(s))
return -1; // stack already full, we couldn't push new elem
s->top++;
s->items[s->top] = val;
return 1;
}
I think error in this line (line 35 in your source code):
struct stack_struct * temp;
. Let's try
typedef struct stack_struct * temp;
or change declare struct
struct stack_struct {
ElemType items[CAPACITY];
int top;} stack;
and then call
stack* temp;
in line 35.
I have to write an implementation of a binary search tree that can handle a library's stock. It reads a text file with all the books and add the books to the tree in alphabetic order. I have been fighting with the Insertar() function code for DAYS and i can't make it work properly, it basically receives a pointer for the root of the tree along all the data related to the book. If the root is NULL, then it inits a node with all the values entered in the function and asings the memory direction to the null node. The problem is, its doing it locally and in the end it doesnt assigns it. Can somebody help me correct that specific function please?
Functions and Structs:
nodoArbol: The node
ArbolBin: Binary Tree, it has a pointer to a root node and an int with the number of elements
InitNodo: Inits the node, returns pointer to node
Raiz: Returns a pointer to the root of a Binary Tree
Clear,Clear_Aux: Clears a Tree
Ingresar: Insert() function and the source of the problem
Imprimir: rints the elements of a node.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct nodoArbol {
char nombre[51],autor[51];
int valor,stock,anno;
struct nodoArbol *der;
struct nodoArbol *izq;
} tNodoArbol;
typedef struct {
tNodoArbol *root;
int n;
} ArbolBin;
tNodoArbol* InitNodo(char *nombre,char *autor, int stock, int valor, int anno){
tNodoArbol *p;
p= (tNodoArbol*)malloc(sizeof(tNodoArbol));
strcpy(p->nombre, nombre);
strcpy(p->autor, autor);
p->stock = stock;
p->anno = anno;
p->valor = valor;
p->izq = NULL;
p->der = NULL;
return p;
}
tNodoArbol* Raiz(ArbolBin p){
return (&p)-> root;
}
void Init(ArbolBin *p){
p->root = NULL;
p->n = 0;
}
void clear_aux(tNodoArbol *nodo){
if (nodo == NULL){
return;
}
clear_aux(nodo->izq);
clear_aux(nodo->der);
free((void *) nodo);
}
void Clear(ArbolBin *p){
clear_aux(p->root);
p->root = NULL;
p->n = 0;
}
void Insertar (tNodoArbol *nodo, char *nombre,char *autor, int stock, int valor, int anno){
if (nodo == NULL){
nodo = (InitNodo(nombre,autor,stock,valor,anno));
}
else{
int result;
result = strcmp(nodo->nombre,nombre);
if (result>0){
Insertar (nodo->der, nombre,autor,stock,valor,anno);
}
else if (result<0){
Insertar (nodo->izq, nombre,autor,stock,valor,anno);
}
}
}
void Imprimir(tNodoArbol *nodo){
printf("Nombre:%s \n",nodo->nombre);
printf("Autor:%s \n",nodo->autor);
printf("Stock:%d \n",nodo->stock);
printf("Valor:%d \n",nodo->valor);
printf("anno:%d \n",nodo->anno);
}
int main(){
char a[50]= "holi",b[50] ="asdasdasd";
ArbolBin Tree;
tNodoArbol *Root;
Init(&Tree);
Root = Raiz(Tree);
Insertar(Root,a,b,2,1000,2014);
Imprimir(Root);
return 0;
}
tNodoArbol *Root;
Insertar(Root,a,b,2,1000,2014);
void Insertar (tNodoArbol *nodo, char *nombre,char *autor, int stock, int valor, int anno){
if (nodo == NULL){
nodo = (InitNodo(nombre,autor,stock,valor,anno));
}
else{
int result;
result = strcmp(nodo->nombre,nombre);
if (result>0){
Insertar (nodo->der, nombre,autor,stock,valor,anno);/*nodo just a pointer,node->der is illeagl*/
}
else if (result<0){
Insertar (nodo->izq, nombre,autor,stock,valor,anno);/*the same error */
}
}
}
-----------------------------------------------------------------------------------------
your declaration a pointer, you want through the Insertar() change the Root, you need use
Insertar(&Root,a,b,2,1000,2014), because the Root in the Insertar() is not the Root in the main() ,they just have the same value,we just copy the value of Root(main) to Root(Insertar).
---------------------------------------------------------------------------------------
void Insertar (tNodoArbol **nodo, char *nombre,char *autor, int stock, int valor, int anno){
if (*nodo == NULL){
*nodo = (InitNodo(nombre,autor,stock,valor,anno));
}
else{
int result;
result = strcmp((*nodo)->nombre,nombre);
if (result>0){
Insertar ((*nodo)->der, nombre,autor,stock,valor,anno);
}
else if (result<0){
Insertar ((*nodo)->izq, nombre,autor,stock,valor,anno);
}
}
}
This is just another interview question.
Can we have a linked list of different data types, i.e. each element in a linked list can have different structure or union elements? If it's possible can you please explain with an example?
Well in a linked list you don't HAVE to link like for like structs together. As long as they have the appropriate forward and/or backwards pointers you are fine. For example:
struct BaseLink
{
BaseLink* pNext;
BaseLink* pPrev;
int typeId;
};
struct StringLink
{
BaseLink baseLink;
char* pString;
};
struct IntLink
{
BaseLink baseLink;
int nInt;
};
This way you'd have a linked list that goes from BaseLink to BaseLink. The extra data is not a problem. You want to see it as a StringLink? Then cast the BaseLink to a StringLink.
Just remember that you need some form of typeid in there so you know what to cast it to when you arrive at it.
Use union to create the datatype
union u_tag{
char ch;
int d;
double dl;
};
struct node {
char type;
union u_tag u;
struct node *next;
};
Use struct node to create linked list. type decides what is the datatype of the data.
Harsha T, Bangalore
You can use a union type:
enum type_tag {INT_TYPE, DOUBLE_TYPE, STRING_TYPE, R1_TYPE, R2_TYPE, ...};
struct node {
union {
int ival;
double dval;
char *sval;
struct recordType1 r1val;
struct recordType2 r2val;
...
} data;
enum type_tag dataType;
struct node *prev;
struct node *next;
};
Another method I've explored is to use a void* for the data and attach pointers to functions that handle the type-aware stuff:
/**
* Define a key type for indexing and searching
*/
typedef ... key_t;
/**
* Define the list node type
*/
struct node {
void *data;
struct node *prev;
struct node *next;
void *(*cpy)(void *); // make a deep copy of the data
void (*del)(void *); // delete the data
char *(*dpy)(void *); // format the data for display as a string
int (*match)(void *, key_t); // match against a key value
};
/**
* Define functions for handling a specific data type
*/
void *copyARecordType(void *data)
{
struct aRecordType v = *(struct aRecordType *) data;
struct aRecordType *new = malloc(sizeof *new);
if (new)
{
// copy elements of v to new
}
return new;
}
void deleteARecordType(void *data) {...}
char *displayARecordType(void *data) {...}
int matchARecordType(void *data, key_t key) {...}
/**
* Define functions for handling a different type
*/
void *copyADifferentRecordType(void *data) {...}
void deleteADifferentRecordType(void *data) {...}
char *displayADifferentRecordType(void *data) {...}
int matchADifferentRecordType(void *data, key_t key) {...}
/**
* Function for creating new list nodes
*/
struct node *createNode(void *data, void *(*cpy)(void *), void (*del)(void *),
char *(*dpy)(void *), int (*match)(void *, key_t))
{
struct node *new = malloc(sizeof *new);
if (new)
{
new->cpy = cpy;
new->del = del;
new->dpy = dpy;
new->match = match;
new->data = new->cpy(data);
new->prev = new->next = NULL;
}
return new;
}
/**
* Function for deleting list nodes
*/
void deleteNode(struct node *p)
{
if (p)
p->del(p->data);
free(p);
}
/**
* Add new node to the list; for this example, we just add to the end
* as in a FIFO queue.
*/
void addNode(struct node *head, void *data, void *(*cpy)(void*),
void (*del)(void *), char *(*dpy)(void *), int (*match)(void*, key_t))
{
struct node *new = createNode(data, cpy, del, dpy, match);
if (!head->next)
head->next = new;
else
{
struct node *cur = head->next;
while (cur->next != NULL)
cur = cur->next;
cur->next = new;
new->prev = cur;
}
}
/**
* Examples of how all of this would be used.
*/
int main(void)
{
struct aRecordType r1 = {...};
struct aDifferentRecordType r2 = {...};
struct node list, *p;
addNode(&list, &r1, copyARecordType, deleteARecordType, displayARecordType,
matchARecordType);
addNode(&list, &r2, copyADifferentRecordType, deleteADifferentRecordType,
displayADifferentRecordType, matchADifferentRecordType);
p = list.next;
while (p)
{
printf("Data at node %p: %s\n", (void*) p, p->dpy(p->data));
p = p->next;
}
return 0;
}
Obviously, I've left out some error checking and handling code from this example, and I don't doubt there are a host of problems with it, but it should be illustrative.
You can have each node in a linked list have a void* that points to your data. It's up to you how you determine what type of data that pointer is pointing to.
If you don't want to have to specify the type of every node in the list via the union solution you can always just store the data in a char* and take type-specific function pointers as parameters to type-sensitive operations such as printing or sorting the list.
This way you don't have to worry about what node is what type and can just cast the data however you like.
/* data types */
typedef struct list_node list_node;
struct list_node {
char *data;
list_node *next;
list_node *prev;
};
typedef struct list list;
struct list {
list_node *head;
list_node *tail;
size_t size;
};
/* type sensitive functions */
int list_sort(list *l, int (*compar)(const void*, const void*));
int list_print(list *l, void (*print)(char *data));
Yes, I do this by defining the list's element's value as a void pointer void*.
In order to know the type stored in each element of the list I also have a .type field in there, so I know how to dereference what the pointer is pointing to for each element.
struct node {
struct node* next;
int type;
void* value;
};
Here's a full example of this:
//
// An exercise to play with a struct that stores anything using a void* field.
//
#include <stdio.h>
#define TRUE 1
int TYPE_INT = 0;
int TYPE_STRING = 1;
int TYPE_BOOLEAN = 2;
int TYPE_PERSON = 3;
struct node {
struct node* next;
int type;
void* value;
};
struct person {
char* name;
int age;
};
int main(int args, char **argv) {
struct person aPerson;
aPerson.name = "Angel";
aPerson.age = 35;
// Define a linked list of objects.
// We use that .type field to know what we're dealing
// with on every iteration. On .value we store our values.
struct node nodes[] = {
{ .next = &nodes[1], .type = TYPE_INT , .value=1 },
{ .next = &nodes[2], .type = TYPE_STRING , .value="anyfing, anyfing!" },
{ .next = &nodes[3], .type = TYPE_PERSON , .value=&aPerson },
{ .next = NULL , .type = TYPE_BOOLEAN, .value=TRUE }
};
// We iterate through the list
for ( struct node *currentNode = &nodes[0]; currentNode; currentNode = currentNode->next) {
int currentType = (*currentNode).type;
if (currentType == TYPE_INT) {
printf("%s: %d\n", "- INTEGER", (*currentNode).value); // just playing with syntax, same as currentNode->value
} else if (currentType == TYPE_STRING) {
printf("%s: %s\n", "- STRING", currentNode->value);
} else if (currentType == TYPE_BOOLEAN) {
printf("%s: %d\n", "- BOOLEAN (true:1, false:0)", currentNode->value);
} else if (currentType == TYPE_PERSON) {
// since we're using void*, we end up with a pointer to struct person, which we *dereference
// into a struct in the stack.
struct person currentPerson = *(struct person*) currentNode->value;
printf("%s: %s (%d)\n","- TYPE_PERSON", currentPerson.name, currentPerson.age);
}
}
return 0;
}
Expected output:
- INTEGER: 1
- STRING: anyfing, anyfing!
- TYPE_PERSON: Angel (35)
- BOOLEAN (true:1, false:0): 1
As said, you can have a node this questionwith a void*. I suggest using something to know about your type :
typedef struct
{
/* linked list stuff here */
char m_type;
void* m_data;
}
Node;
See this question.
Actually, you don't have to put the pointer first in the structure, you can put it anywhere and then find the beginning fo the struct with a containerof() macro. The linux kernel does this with its linked lists.
http://isis.poly.edu/kulesh/stuff/src/klist/
I use these macros I wrote to make general linked lists. You just create your own struct and use the macro list_link somewhere as a member of the struct. Give that macro one argument naming the struct (without the struct keyword). This implements a doubly linked list without a dummy node (e.g. last node links back around to first node). The anchor is a pointer to the first node which starts out initialized by list_init(anchor) by giving it the lvalue (a dereferenced pointer to it is an lvalue). Then you can use the other macros in the header. Read the source for comments about each available macro functions. This is implemented 100% in macros.
http://phil.ipal.org/pre-release/list-0.0.5.tar.bz2
Yes,Sure You can insert any data type values in the linked list I've designed and its very simple to do so.I have used different constructors of node and boolean variables to check that which type value is inserted and then I do operation and command according to that value in my program.
//IMPLEMENTATION OF SINGLY LINKED LISTS
#include"iostream"
#include"conio.h"
#include <typeinfo>
using namespace std;
class node //struct
{
public:
node* nextptr;
int data;
////////////////////////////////just to asure that user can insert any data type value in the linked list
string ss;
char cc;
double dd;
bool stringTrue=0;
bool intTrue = 0;
bool charTrue = 0;
bool doubleTrue = 0;
////////////////////////////////just to asure that user can insert any data type value in the linked list
node()
{
nextptr = NULL;
}
node(int d)
{
data = d;
nextptr = NULL;
intTrue = 1;
}
////////////////////////////////just to asure that user can insert any data type value in the linked list
node(string s)
{
stringTrue = 1;
ss = s;
nextptr = NULL;
}
node(char c)
{
charTrue = 1;
cc = c;
nextptr = NULL;
}
node(double d)
{
doubleTrue = 1;
dd = d;
nextptr = NULL;
}
////////////////////////////////just to asure that user can insert any data type value in the linked list
//TO Get the data
int getintData()
{
return data;
}
string getstringData()
{
return ss;
}
double getdoubleData()
{
return dd;
}
char getcharData()
{
return cc;
}
//TO Set the data
void setintData(int d)
{
data = d;
}
void setstringData(string s)
{
ss = s;
}
void setdoubleData(double d)
{
dd = d;
}
void setcharData(char c)
{
cc = c;
}
char checkWhichInput()
{
if (intTrue == 1)
{
return 'i';
}
else if (stringTrue == 1)
{
return 's';
}
else if (doubleTrue == 1)
{
return 'd';
}
else if (charTrue == 1)
{
return 'c';
}
}
//////////////////////////////Just for the sake of implementing for any data type//////////////////////////////
node* getNextptr()
{
return nextptr;
}
void setnextptr(node* nptr)
{
nextptr = nptr;
}
};
class linkedlist
{
node* headptr;
node* addnodeatspecificpoition;
public:
linkedlist()
{
headptr = NULL;
}
void insertionAtTail(node* n)
{
if (headptr == NULL)
{
headptr = n;
}
else
{
node* rptr = headptr;
while (rptr->getNextptr() != NULL)
{
rptr = rptr->getNextptr();
}
rptr->setnextptr(n);
}
}
void insertionAtHead(node *n)
{
node* tmp = n;
tmp->setnextptr(headptr);
headptr = tmp;
}
int sizeOfLinkedList()
{
int i = 1;
node* ptr = headptr;
while (ptr->getNextptr() != NULL)
{
++i;
ptr = ptr->getNextptr();
}
return i;
}
bool isListEmpty() {
if (sizeOfLinkedList() <= 1)
{
return true;
}
else
{
false;
}
}
void insertionAtAnyPoint(node* n, int position)
{
if (position > sizeOfLinkedList() || position < 1) {
cout << "\n\nInvalid insertion at index :" << position;
cout <<".There is no index " << position << " in the linked list.ERROR.\n\n";
return;
}
addnodeatspecificpoition = new node;
addnodeatspecificpoition = n;
addnodeatspecificpoition->setnextptr(NULL);
if (headptr == NULL)
{
headptr = addnodeatspecificpoition;
}
else if (position == 0)
{
addnodeatspecificpoition->setnextptr(headptr);
headptr = addnodeatspecificpoition;
}
else
{
node* current = headptr;
int i = 1;
for (i = 1; current != NULL; i++)
{
if (i == position)
{
addnodeatspecificpoition->setnextptr(current->getNextptr());
current->setnextptr(addnodeatspecificpoition);
break;
}
current = current->getNextptr();
}
}
}
friend ostream& operator<<(ostream& output,const linkedlist& L)
{
char checkWhatInput;
int i = 1;
node* ptr = L.headptr;
while (ptr->getNextptr() != NULL)
{
++i;
checkWhatInput = ptr->checkWhichInput();
/// <summary>
switch (checkWhatInput)
{
case 'i':output <<ptr->getintData()<<endl;
break;
case 's':output << ptr->getstringData()<<endl;
break;
case 'd':output << ptr->getdoubleData() << endl;
break;
case 'c':output << ptr->getcharData() << endl;
break;
default:
break;
}
/// </summary>
/// <param name="output"></param>
/// <param name="L"></param>
/// <returns></returns>
ptr = ptr->getNextptr();
}
/// <summary>
switch (checkWhatInput)
{
case 'i':output << ptr->getintData() << endl;
break;
case 's':output << ptr->getstringData() << endl;
break;
case 'd':output << ptr->getdoubleData() << endl;
break;
case 'c':output << ptr->getcharData() << endl;
break;
default:
break;
}
/// </summary>
/// <param name="output"></param>
/// <param name="L"></param>
/// <returns></returns>
if (ptr->getNextptr() == NULL)
{
output << "\nNULL (There is no pointer left)\n";
}
return output;
}
~linkedlist() {
delete addnodeatspecificpoition;
}
};
int main()
{
linkedlist L1;
//Insertion at tail
L1.insertionAtTail(new node("dsaf"));
L1.insertionAtTail(new node("sadf"));
L1.insertionAtTail(new node("sfa"));
L1.insertionAtTail(new node(12));
L1.insertionAtTail(new node(67));
L1.insertionAtTail(new node(23));
L1.insertionAtTail(new node(45.677));
L1.insertionAtTail(new node(12.43556));
//Inserting a node at head
L1.insertionAtHead(new node(1));
//Inserting a node at any given point
L1.insertionAtAnyPoint(new node(999), 3);
cout << L1;
cout << "\nThe size of linked list after insertion of elements is : " << L1.sizeOfLinkedList();
}
The output is
1
dsaf
sadf
999
sfa
12
67
23
45.677
12.4356
Thats what you can use to create a linked list without worrying of data type
Just an FYI, In C# you can use Object as your data member.
class Node
{
Node next;
Object Data;
}
User can then use something like this to find out which Object the Node stores:
if (obj.GetType() == this.GetType()) //
{
}