Search code examples
clistdoubly-linked-listunions

Problem with double linked list with union as data type


I have to create a list with union as data type but it turns out that after the creation of my list there is only the same value which is repeated on all my list. How Can I handle this?

Can you help me in this direction?

Good day to you

Structure, Union and Function declaration

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

//Declaration of list
struct list_t{
    struct node_t *head;
    struct node_t *tail;
};
struct node_t {
    union val_t *vals;
    struct node_t *prev;
    struct node_t *next;
};

//Declaration of Union
union val_t{
    int as_int;
    double as_double;
    char *as_str;
};
int insert(struct list_t *list, union val_t*value);

Function definition

//Push to create my list
int push_none(struct list_t *list, union val_t*value){
    if(list==NULL || value==NULL)return 1;
    struct node_t *node = (struct node_t*) malloc(sizeof(struct node_t));
    if(node==NULL)return 2;
    node->vals =value;


    if(list->head==NULL){
        node->next=NULL;
        node->prev=NULL;
        list->head = node;
        list->tail=node;

    } else{
        node->next=NULL;
        node->prev = list->tail;
        list->tail->next = node;
        list->tail = node;
    }
    return 0;
}

Main

int main() {
    //initialization of my list

    struct list_t * list = malloc(sizeof(struct list_t));
    list->tail=NULL;
    list->head=NULL;

    printf("Create a double linked list of 3 element :");
    char buf[100],**ptr=NULL;
    int type[3][3];

    union val_t values[4];
    int as_int1;
    double as_double1;
    int i=0;
    //Data input
    while (i<3){

        int j=0;
        while(j<3){
            while(1){
                printf("\n1 - INT\n2 -DOUBLE\n3 - CHAR\nEnter type:");
                scanf("%d", &type[i][j]);
                if(type[i][j]>0 && type[i][j]<4)break;
            }
            printf("\nEnter value :");
            scanf("%s",buf);

            if(type[i][j]==1){
                as_int1 = (int)strtol(buf,ptr,10);
                (values+j)->as_int = as_int1;
            }
            else if(type[i][j]==2){
                as_double1 = strtod(buf,ptr);
                ((values+j)->as_double) = as_double1;
            }
            else if(type[i][j]==3){
                (values + j)->as_str = strdup(buf);
            }
            j++;
        }
        //Creation of the list
        push_node(list,values);
        i++;
    }
    i=0;
    //Display values
    while(list->head!=NULL){
        int j=0;
        while(j<3){
            if(type[i][j]==1){
                printf("%d ",list->head->vals->as_int);
            }
            if(type[i][j]==2){
                printf("%lf ",list->head->vals->as_double);
            }
            if(type[i][j]==3){
                printf("%s ",list->head->vals->as_str);
            }
            j++;
        }
        printf("\n");
        i++;
        list->head=list->head->next;
    }
    return 0;
}


Solution

  • This incorporates what I was saying in my top comments.

    1. Add type to node struct
    2. Have an instance of the value in the node struct (not a pointer)
    3. Only one value per node

    Here is the refactored code. It compiles and has been [cursorily] tested:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    //Declaration of list
    struct list_t {
        struct node_t *head;
        struct node_t *tail;
    };
    
    //Declaration of Union
    union val_t {
        int as_int;
        double as_double;
        char *as_str;
    };
    
    struct node_t {
        int type;
        union val_t vals;
        struct node_t *prev;
        struct node_t *next;
    };
    
    int insert(struct list_t *list, union val_t *value);
    
    //Push to create my list
    int
    push_node(struct list_t *list, union val_t value, int type)
    {
        if (list == NULL)
            return 1;
    
        struct node_t *node = malloc(sizeof(*node));
        if (node == NULL)
            return 2;
    
        node->vals = value;
        node->type = type;
    
        if (list->head == NULL) {
            node->next = NULL;
            node->prev = NULL;
            list->head = node;
            list->tail = node;
    
        }
        else {
            node->next = NULL;
            node->prev = list->tail;
            list->tail->next = node;
            list->tail = node;
        }
    
        return 0;
    }
    
    int
    main(void)
    {
    
        // initialization of my list
        struct list_t *list = malloc(sizeof(*list));
        list->tail = NULL;
        list->head = NULL;
    
        printf("Create a double linked list of 3 element :");
        char buf[100], **ptr = NULL;
        int type;
    
        union val_t values;
        int i = 0;
    
        // Data input
        for (;  i < 3;  ++i) {
            while (1) {
                printf("\n1 - INT\n2 -DOUBLE\n3 - CHAR\nEnter type:");
                scanf("%d", &type);
                if (type > 0 && type < 4)
                    break;
            }
    
            printf("\nEnter value :");
            scanf("%s", buf);
    
            switch (type) {
            case 1:
                values.as_int = strtol(buf, ptr, 10);
                break;
    
            case 2:
                values.as_double = strtod(buf, ptr);
                break;
    
            case 3:
                values.as_str = strdup(buf);
                break;
            }
    
            // Creation of the list
            push_node(list, values, type);
        }
    
        // Display values
        for (struct node_t *node = list->head;  node != NULL;  node = node->next) {
            switch (node->type) {
            case 1:
                printf("%d ", node->vals.as_int);
                break;
            case 2:
                printf("%f ", node->vals.as_double);
                break;
            case 3:
                printf("%s ", node->vals.as_str);
                break;
            }
            printf("\n");
        }
    
        return 0;
    }
    

    Here is some test output:

    Create a double linked list of 3 element :
    1 - INT
    2 -DOUBLE
    3 - CHAR
    Enter type:1
    
    Enter value :23
    
    1 - INT
    2 -DOUBLE
    3 - CHAR
    Enter type:2
    
    Enter value :37.889
    
    1 - INT
    2 -DOUBLE
    3 - CHAR
    Enter type:3
    
    Enter value :jwelrjlewjrowejrowier
    23 
    37.889000 
    jwelrjlewjrowejrowier 
    

    Here is a slightly more cleaned up version. In particular, node_push has been simplified:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    //Declaration of list
    struct list_t {
        struct node_t *head;
        struct node_t *tail;
    };
    
    //Declaration of Union
    union val_t {
        int as_int;
        double as_double;
        char *as_str;
    };
    
    struct node_t {
        int type;
        union val_t vals;
        struct node_t *prev;
        struct node_t *next;
    };
    
    int insert(struct list_t *list, union val_t *value);
    
    //Push to create my list
    int
    push_node(struct list_t *list, union val_t value, int type)
    {
        if (list == NULL)
            return 1;
    
        struct node_t *node = malloc(sizeof(*node));
        if (node == NULL)
            return 2;
    
        node->vals = value;
        node->type = type;
    
        node->next = NULL;
        node->prev = list->tail;
    
        if (list->head == NULL)
            list->head = node;
        else
            list->tail->next = node;
    
        list->tail = node;
    
        return 0;
    }
    
    int
    main(void)
    {
    
        // initialization of my list
        struct list_t *list = calloc(1,sizeof(*list));
    
        printf("Create a double linked list of 3 element :");
        char buf[100], **ptr = NULL;
        int type;
    
        union val_t values;
        int i = 0;
    
        // Data input
        for (;  i < 3;  ++i) {
            while (1) {
                printf("\n1 - INT\n2 -DOUBLE\n3 - CHAR\nEnter type:");
                scanf("%d", &type);
                if (type > 0 && type < 4)
                    break;
            }
    
            printf("\nEnter value :");
            scanf("%s", buf);
    
            switch (type) {
            case 1:
                values.as_int = strtol(buf, ptr, 10);
                break;
    
            case 2:
                values.as_double = strtod(buf, ptr);
                break;
    
            case 3:
                values.as_str = strdup(buf);
                break;
            }
    
            // Creation of the list
            push_node(list, values, type);
        }
    
        // Display values
        printf("\n");
        printf("List:\n");
        for (struct node_t *node = list->head;  node != NULL;  node = node->next) {
            printf("type: %d ",node->type);
    
            switch (node->type) {
            case 1:
                printf("%d ", node->vals.as_int);
                break;
            case 2:
                printf("%f ", node->vals.as_double);
                break;
            case 3:
                printf("%s ", node->vals.as_str);
                break;
            }
    
            printf("\n");
        }
    
        return 0;
    }
    

    Although somewhat different, you may want to have a look at my answer on "generic" structs in C: Writing a 'generic' struct-print method in C