简体   繁体   中英

Adding array nodes to linked list

I have to build a linked list with each node being an 16 byte array. Using code that works with single uint8_t values, I slightly modified it to accept the 16 bytes. However, whenever I print the list, all nodes are the last node added. What am I doing wrong?

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<math.h>

struct array_deck
{
    uint8_t *val;
    struct array_deck *next;
};

struct array_deck *head = NULL;
struct array_deck *curr = NULL;

int sizeOfSet;

struct array_deck *create_list(uint8_t *val)
{
    struct array_deck *ptr = (struct array_deck*)malloc(sizeof(struct array_deck));

    if(NULL == ptr)
        return NULL;

    ptr->val = val;
    ptr->next = NULL;

    head = curr = ptr;
    return ptr;
}

void print_list(void)
{
    struct array_deck *ptr = head;

    while(ptr != NULL)
    {
        printf("\n");
        printf("actually added = ");
        for (int i = 0; i < 16; i++) {
            uint8_t blah = ptr->val[i];
            printf("[%2i] ",blah);
        }
        ptr = ptr->next;
    }

        printf("\n");
    return;
}

struct array_deck *add_to_list(uint8_t *data, bool add_to_end)
{
    printf("array to be added = ");
    for (int i = 0; i < 16; i++) {
        printf("[%2X] ",data[i]);
    }

    if(NULL == head)
        return (create_list(data));

    struct array_deck *ptr = (struct array_deck*)malloc(sizeof(struct array_deck));
    if(NULL == ptr)
        return NULL;

    ptr->val = data;
    ptr->next = NULL;

    if(add_to_end)
    {
        curr->next = ptr;
        curr = ptr;
    }
    else
    {
        ptr->next = head;
        head = ptr;
    }

    return ptr;
}

int main(void)
{
    printf ("# of arrays  >> ");
    scanf ("%d", &sizeOfSet);

    uint8_t data[16];

    for(int i = 1; i<=sizeOfSet; i++){
        for (int j = 0; j < 16; j++) {
            data[j] = i;
        }
        printf("\n");
        add_to_list(data,true);
    }

    print_list();

    return 0;
}

sample run that builds a linked list with 3 nodes:

# of arrays  >> 3

array to be added = [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] 
array to be added = [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] 
array to be added = [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] 
actually added = [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] 
actually added = [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] 
actually added = [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] 
Program ended with exit code: 0

All of your array_deck 's -> val is pointing to the same memory address - to local variable data in main. You're overwriting it N times thats it why its printing last values inserted.

To solve problem you should copy the data array into new and assign to ptr->val the new allocated array address.

struct array_deck *add_to_list(uint8_t *data, bool add_to_end)
{
    ...

    struct array_deck *ptr = (struct array_deck*)malloc(sizeof(struct array_deck));
    if(NULL == ptr)
        return NULL;

    ptr->val = malloc(16*sizeof(uint8_t));
    memcpy(ptr->val, data, 16*sizeof(uint8_t));
    ptr->next = NULL;

    ...
}

PS it would be nice to remove create_list function and do all logic of assigning to head in add_to_list.

In create_list and add_to_list the node data is not being copied correctly. The shown code just stores a pointer to the passed in data instead of making a copy of the data. So the result is that all the nodes end up pointing to the same data defined in main and thus result in the same values when printed out.

There are a number of ways to fix this. Some more elegant than others but all requiring the data to be copied.

The simplest is to assume fixed size data and declare the node struct with static memory for the data. Like so:

#define DATA_BYTES 16
struct array_deck
{
    uint8_t val[DATA_BYTES];
    struct array_deck *next;
};

And then replace the pointer assignments in the list functions with data copies. For example:

memcpy(ptr->val, val, sizeof(ptr->val));

A more flexible/elegant solution would be to explicitly store the size of the data in the node itself so that you could have variable sized data. And then use dynamic memory allocate ( malloc and friends) to get memory for the node val .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM