memory allocation for a linked list

Discussion in 'Mac Programming' started by dougphd, Oct 30, 2016.

  1. dougphd macrumors member

    Joined:
    Apr 28, 2016
    #1
    I have this structure
    Code:
    struct hlv {
     char name[20];
     int num;
     float range;
     float vol;
     float width;  //range/vol
     struct hlv *next;
    };
    /[code]
    
    for which I can declare
    [code]
    struct hlv foundLink[10];
    /[code]
    but for which I cannot allocate memory
    [code]
    struct hlv *foundLink;
    for (i = 0; i < 10; i++)
       foundLink[i] = (struct hlv*) calloc(1, sizeof(struct hlv));
    /[code]
    
    Why not?
     
  2. mfram, Oct 31, 2016
    Last edited: Oct 31, 2016

    mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #2
    There are a couple issues. First, you apparently have a "foundLink" pointer variable that's in local scope and a separate "foundLink" array declared in global scope. The foundLink local variable will mask the global one. Don't name a local variable with the same name as a global variable.

    Then beyond that, calloc() returns a pointer. The foundLink[10] array is declared as an array of 'struct hlv' records, not an array of 'struct hlv" pointers. In your code, the proper declaration would be "struct hlv *foundLink[10];" given what I believe is your intended usage. But normally, you should never need such an array.

    I'm going to include a complete example of reading a simple file into structs using a singly-linked list. Notice there are no arrays declared anywhere.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    struct rec
    {
        struct rec *next;
    
        int a;
        int b;
    } *head=NULL, *tail=NULL;
    
    // Add an allocated record to the list
    void addToList(struct rec *r)
    {
        // Check to set the head pointer
        if (head == NULL)
        {
            head = r;
        }
    
        // Link the tail if there is one
        if (tail != NULL)
        {
            tail->next = r;
        }
    
        // Add new record to tail
        tail = r;
    }
    
    void dumpRecords()
    {
        struct rec *curr = head;
    
        // Iterate through the record pointers
        while(curr != NULL)
        {
            printf("Record a=%d  b=%d\n", curr->a, curr->b);
    
            // Advance the current record pointer
            curr = curr->next;
        }
    }
    
    void readFile(const char *filename)
    {
        FILE *f;
        int fA, fB;
    
        if ((f = fopen(filename, "r")) == NULL)
        {
            perror("couldn't open file");
            return;
        }
    
        while (fscanf(f, "%d %d", &fA, &fB) == 2)
        {
            struct rec *r = calloc(1, sizeof(struct rec));
    
            if (!r)
            {
                break;
            }
    
            r->a = fA;
            r->b = fB;
            addToList(r);
        }
    
        fclose(f);
    }
    
    
    int main(int argc, char *argv[])
    {
        char *fn;
    
        if (argc >= 2)
        {
            fn = argv[1];
        }
        else
        {
            fn = "test.dat";
        }
    
        readFile(fn);
        dumpRecords();
    }
    
     
  3. dougphd thread starter macrumors member

    Joined:
    Apr 28, 2016
    #3
    I just saw your reply. I'll have two hours on the train later. It's a great time for C programming. I'll look in detail then.
    Thanks.
     
  4. dougphd thread starter macrumors member

    Joined:
    Apr 28, 2016
    #4
    Actually, I think this is what I was trying to do.
    struct hlv *foundLink;
    foundLink = (struct hlv*) calloc(10, sizeof(struct hlv));
    Something of a cockpit error but that's what happens when you don't program often.
     
  5. Toutou macrumors 6502a

    Toutou

    Joined:
    Jan 6, 2015
    Location:
    Prague, Czech Republic
    #5
    Both this and that thing in your first post are incorrect usages of a linked list.

    The point of a linked list is that each element knows the position of the next element.
    Therefore, you only need to have ONE pointer (pointing at the first element) to represent your linked list.
    As in:
    Code:
    MyLinkedList * first;
    first = (MyLinkedList*)malloc(sizeof(MyLinkedList));
    This is your first element that also represents the WHOLE linked list.

    If you, for some reason, wanted to allocate memory for a 10-element linked list (without writing any useable data into those elements), that would be:
    Code:
    MyLinkedList * first;
    first = (MyLinkedList*)malloc(sizeof(MyLinkedList));
    MyLinkedList * current = first;
    for (int i = 0; i < 9 ; ++i) {
        current->nextElement = (MyLinkedList*)malloc(sizeof(MyLinkedList));
        current = current->nextElement;
    }
    note that we created the first element manually, and then appended the next element nine times, in a cycle.

    Again, the important thing to grasp is that there's no difference between one element and the whole linked list - they're the same pointer. If you take, say, the fifth element of your ten-element linked list, what you have is essentially the first element of a five-element linked list. Same thing.
     

Share This Page