2

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
2
  • 1
    ptr->val = val;. That means that all your nodes are pointing to the same data that was declared in main. You need to allocate new memory and copy into the node. Not just point to the passed in buffer. Commented Sep 8, 2015 at 23:42
  • Thanks for the tip @AlanAu, and for your detailed answer below! Commented Sep 9, 2015 at 14:32

2 Answers 2

4

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;

    ...
}

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

Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.