Thread: Memory adress as output

  1. #1
    Registered User
    Join Date
    Feb 2021
    Posts
    22

    Memory adress as output

    Hello,

    I'm trying to implement an insert function to my linked list but when I try to print the values I only get what I assume is memory adresses. Why is this the case? I have also noticed that one of my malloc calls messes with one of my functions. I dont understand why that's the case either. Here is my code for reference:

    Code:
    #include "stdio.h"
    #include "stdlib.h"
    
    
    typedef struct node
    {
        int value;
        struct node *next;
    }node_t;
    
    
    typedef struct list
    {
        node_t *head;
        int size;
    }list_t;
    
    
    void initList(list_t *list)
    {
        list = (list_t*)malloc(sizeof(list_t));
        list->head = NULL;
        list->size = 0;
    }
    
    
    int IsEmpty(list_t * list)
    {
        if (list->size == 0)
        {
            printf("0\n");
            return 0;
        }
        else
        {
            printf("1\n");
            return 1;
        }
    }
    void printlist(list_t list)
    {
        node_t *current = list.head;
        while (current != NULL)
        {
            printf("%d ", current->value);
            current = current->next;
        }
        printf("\n");
    }
    
    
    int insert(list_t *list, node_t * node)
    {
        node_t * pointer = node;
        pointer = malloc(sizeof(node_t));
        pointer->value = node->value;
        pointer->next = list->head;
        list->size += 1;
    }
    
    
    
    
    int main()
    {
        node_t node1;
        node_t node2;
        node1.value = 2;
        node2.value = 4;
        list_t list3;
        initList(&list3);
        IsEmpty(&list3);
    
    
        insert(&list3, &node1);
        insert(&list3, &node2);
        printlist(list3);
        
    }
    Okay so I've been testing around and I have some interesting foundings that I dont really understand why it is the way it is. I'll list them here:

    The first thing is that when im trying to allocate memory for the list in the InitList function it messes with size? Because when I pass the list into the IsEmpty function it returns 1 if the malloc call is there and 0 if it isnt. I dont understand why this is the case.

    The second thing is that im having trouble with is the Insert function. If I define the nodes above the other calls the printlist function prints two garbage values which I assume is the location of the nodes in the memory. But if I define them under the list calls in the main function I get nothing.

    I have a theory on what some of my errors could be which is that I think im doing something wrong by defining nodes and then try to allocate space for them in memory. But im not quite sure. Any ideas?

    Thanks in advance!
    Last edited by Lax; 02-16-2021 at 02:30 AM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    This is wrong:
    Code:
    void initList(list_t *list)
    {
        list = (list_t*)malloc(sizeof(list_t));
        list->head = NULL;
        list->size = 0;
    }
    The problem is that you are assigning the result of malloc to a local variable whose lifetime is that of the function, but you don't return its value, so you end up with a memory leak. There are two general approaches here:
    Code:
    list_t *createList(void)
    {
        list_t *list = malloc(sizeof(*list));
        if (list)
        {
            list->head = NULL;
            list->size = 0;
        }
        return list;
    }
    In the above code, I choose to return the pointer, so I renamed the function to createList. Notice that I check the return value of malloc before using it, and that this returns a null pointer in the unlikely situation that the list could not be created. We would expect createList to be used like this:
    Code:
    list_t *list = createList();
    if (!list)
    {
        // Handle memory allocation failure, or rage quit
        // ...
    }
    // Code that uses the linked list
    // ...
    If you really prefer to initialise the linked list instead:
    Code:
    void initList(list_t **list)
    {
        list_t *temp = malloc(sizeof(*temp));
        if (temp)
        {
            temp->head = NULL;
            temp->size = 0;
        }
        *list = temp;
    }
    You can see that the parameter is a pointer to a pointer instead. This way, the list_t pointer in the caller can be modified from within the function. I have kept to the same pattern as with createList by making use of the temp local variable, but if you prefer you could use *list instead. We would expect initList to be used like this:
    Code:
    list_t *list = NULL;
    initList(&list);
    if (!list)
    {
        // Handle memory allocation failure, or rage quit
        // ...
    }
    // Code that uses the linked list
    // ...
    Notice that for both createList and initList, the caller (i.e., the main function in your case) declare list to be a pointer. If you really want list to be a list_t object instead, then you would not use malloc within initList. Rather:
    Code:
    void initList(list_t *list)
    {
        list->head = NULL;
        list->size = 0;
    }
    As you can see, this is almost the code that you originally wrote, but with the malloc line deleted. If you do it this way, then your original idea will work:
    Code:
    list_t list;
    initList(&list);
    // Code that uses the linked list
    // ...
    Next, I don't recommend this:
    Code:
    int insert(list_t *list, node_t * node)
    {
        node_t * pointer = node;
        pointer = malloc(sizeof(node_t));
        pointer->value = node->value;
        pointer->next = list->head;
        list->size += 1;
    }
    You're basically using the node parameter as a way to pass the value. Why do that when you can just pass the value? For example:
    Code:
    int insert(list_t *list, int value)
    {
        node_t *node = malloc(sizeof(*node));
        if (!node)
        {
            return 0;
        }
        node->value = value;
        node->next = list->head;
        list->head = node;
        list->size += 1;
        return 1;
    }
    Notice that I am making use of the int return value as a boolean value, i.e., true for success, false for failure. You can consider #include <stdbool.h> to use bool, true, and false instead of int, 1, and 0. Notice also that I take care to assign the new node as the new head of the linked list, otherwise you'll be incrementing the size, but your linked list won't actually grow.

    Oh, and remember to free what you malloc, e.g., by writing a destroyList or freeList function and calling it. It doesn't matter for such a short-lived program, but it will be good practice.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Feb 2021
    Posts
    22
    Thank you so much for this. This cleared a lot that I was confused about. What you said about memory leak really made a lot of sense to me. I really appreciate that you took the time to explain this to me.
    Cheers!!

  4. #4
    Registered User
    Join Date
    Feb 2021
    Posts
    22
    After thinking things through a bit there is something here I dont quite fully understand.
    This bit here:
    Code:
    list_t *createList(void)
    {
        list_t *list = malloc(sizeof(*list));
        if (list)
        {
            list->head = NULL;
            list->size = 0;
        }
        return list;
    }
    I get that the function returns a list type. But what confuses me is using it.
    I got this to work:
    Code:
    	list_t list2;
    	list2 = *createList();
    But what am I really doing here? I define a constant of type list. I set it to the pointer of a function that returns a list? I really dont know how to explain this but it just feels weird. Why is the pointer necessary before the function call?

    Thanks!

  5. #5
    Registered User
    Join Date
    May 2012
    Posts
    505
    Quote Originally Posted by Lax View Post
    After thinking things through a bit there is something here I dont quite fully understand.
    This bit here:
    Code:
    list_t *createList(void)
    {
        list_t *list = malloc(sizeof(*list));
        if (list)
        {
            list->head = NULL;
            list->size = 0;
        }
        return list;
    }
    I get that the function returns a list type. But what confuses me is using it.
    I got this to work:
    Code:
        list_t list2;
        list2 = *createList();
    But what am I really doing here? I define a constant of type list. I set it to the pointer of a function that returns a list? I really dont know how to explain this but it just feels weird. Why is the pointer necessary before the function call?

    Thanks!

    You've managed to create something which is correct C, but the wrong way to use pointers.

    createList returns a pointer to allocated memory. So you need to hold on to that pointer to free it later. What you are doing is dereferencing (taking what the pointer points to) and assigning it to the structure variable list2. C allows that, but it is not correct programming. If a function return a pointer, you should always assign to a pointer variable. I can't think of an exception.
    I'm the author of MiniBasic: How to write a script interpreter and Basic Algorithms
    Visit my website for lots of associated C programming resources.
    https://github.com/MalcolmMcLean


  6. #6
    Registered User
    Join Date
    Feb 2021
    Posts
    22
    Thanks for the reply!

    Ohh I see that makes sense. So if I would like to acess that point in memory, (but not dereference) I would just store the adress in another variable?
    Code:
    	list_t *list2;
    	list2 = createList();
    And now since I have the location of the memory I could just free it by doing something like free(list2)?

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Yes, but note that that will only free the memory allocated for the list_t object, not the memory for its nodes, if any.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    Feb 2021
    Posts
    22
    I have now made a couple of changes to my program to try and get a greater understanding of pointers, aswell as memory allocation. I have now implemented a previous pointer to make it a doubly linked list. One problem that I've encountered however is in my insert function. An error im getting is incompatible pointer types. I dont understand why this is the case becuase all im trying to do is asign a new node into the last node in my list.

    Here is the code snippet in question with some comments on what I think im doing. To summerize what I want my code to do is that I want it to take a node as input and add into the end of a list.
    Code:
    int insert(list_t *list, node_t *node)
    {    
        node->prev = list->head; // linking the node that I had as inparameter with the list I also had as inparameter
        node->next = NULL;        // Set the new nodes next parameter to NULL which indicates that this is now the headnode.
        list->head = node;          // Sets the previous firstnodes head equal to the position of the new node. Which means there is now a link forwards and backwards between the new node and link.
        list = node;                    // Set the inparameter node as the last node in the list. (This is where im getting the error),
        list->size += 1;
        return 1;
    }
    Any thoughts on what im donig wrong and where my reasoning is incorrect?

    Here is also the rest of the code if that makes things a little clearer.
    Code:
    #include "stdio.h"
    #include "stdlib.h"
    
    
    typedef struct node
    {
        struct node *prev;
        int value;
        struct node *next;
    }node_t;
    
    
    typedef struct list
    {
        node_t *head;
        int size;
        node_t *tail;
    }list_t;
    
    
    list_t *createList(void)
    {
        list_t *list = malloc(sizeof(*list));
        if (list)
        {
            list->head = NULL;
            list->size = 0;
            list->tail = NULL;
        }
        return list;
    }
    node_t * createNode(int n)
    {
        node_t *newnode = malloc(sizeof(node_t));
        if (!newnode)
        {
            return NULL;
        }
        newnode->value = n;
        newnode->next = NULL;
        newnode->prev = NULL;
        return newnode;    
    }
    void printlist(list_t list)
    {
        node_t *current = list.head;
        while (current != NULL)
        {
            printf("%d ", current->value);
            current = current->next;
        }
        printf("\n");
    }
    
    
    int insert(list_t *list, node_t *node)
    {    
        node->prev = list->head;
        node->next = NULL;
        list->head = node;
        list = node;
        list->size += 1;
        return 1;
    }
    
    
    
    
    int main()
    {
        list_t *list2;
        list2 = createList();
        node_t *node1;
        node1 = createNode(6);
        insert(list2, node1);
    }
    Im sorry if this was the wrong place to post this but I thought since this is related to my previous questions I might aswell post it here.
    Thanks in advance!

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    The first thing I'd do is rename the insert function: does it insert at the tail? Then name it append or tail_insert. Does it insert at the head? Then name it prepend or head_insert. Just calling it insert is ambiguous.

    Next, a node is not a list, so it should be obvious why assigning node to list is an error. The problem is that your logic is a bit faulty: it looks like you're trying to append, so you need to set the new node's prev to be the current tail, set the new node's next to be null, set the current tail's next to be the new node, and then set the new node to be the new tail. The only time you mess around with head is when the list is empty.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Feb 2021
    Posts
    22
    A right that makes sense since they are not the sama data type. I have to be honest here all these pointers are a bit confusing to me but asking these question is really making it easier for me to understand so thanks for that!

    A question that comes to mind when I read your response is what would the current tail be? Is it something along the lines of list->tail ? Because if I follow this correctly would it look something like this?

    Code:
    	node->prev = list.tail;
    	node->next = NULL;
            list.tail =node;
    Bu what does it mean to set the new node to be the new tail? Sorry im not really following on this one.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    A question that comes to mind when I read your response is what would the current tail be? Is it something along the lines of list->tail ?
    Yes.

    Because if I follow this correctly would it look something like this?
    Yes. Something like that, but you need to compile and find out.

    what does it mean to set the new node to be the new tail?
    What does this mean?
    Code:
    list->tail = NULL;
    What does this mean?
    Code:
    list->tail = node;
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Feb 2021
    Posts
    22
    So I compiled what I wrote and while I didnt get any errors after some fixes.
    This is what I got so far:
    Code:
    node->prev = list->tail; // Copies the adress of the tail of the previous node into the new nodes previous pointer.
    node->next = NULL; // Sets the next pointer to NULL which means that this is the head? I'm not 100% sure if this is what happens exactly
    list->tail = node; // stores the adress of the new node into the tail of the previous node.
    To your questions:
    Code:
    list->tail = NULL // sets the tail of the head? to NULL
    as for the other I answered it above I think.
    Now after writing some code and testing im starting to get unsure what list actually does. I get what im using it for but im confused how it works in relation to the nodes. Like how are they "connected". I dont really understand how I can use it to link the nodes together since they are different datatypes.

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Your linked list has a head node and a tail node, which it stores as pointers to the node objects. You could do without the list object: then you would pass pointers to the head node and the tail node around, which tends to be a bit more inconvenient.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    node->prev = list->tail; // Copies the adress of the tail of the previous node into the new nodes previous pointer.
    Nodes don't have tails. What this does is set the prev pointer of the node to be the tail of the linked list. This means that we're about to make this node the new tail of the linked list.

    node->next = NULL; // Sets the next pointer to NULL which means that this is the head? I'm not 100% sure if this is what happens exactly
    Yes, it sets the node's next pointer to be a null pointer. Think about it: if a node has no next node, then it must be the tail of the linked list. It cannot be the head of the linked list, unless the linked list has only one node.

    Code:
    list->tail = node; // stores the adress of the new node into the tail of the previous node.
    Again, nodes don't have tails. It is like saying "the foot of a foot" rather than "the foot of a human". This sets node to be the tail of the linked list.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #15
    Registered User
    Join Date
    Feb 2021
    Posts
    22
    Yea that makes sense. I have seen plenty other examples where that solution is used.

    If I may ask, is my previous assumptions correct? I feel like there is still something wrong with either my insertTail function or the printlist function. I tried to run it by running the main function:
    Code:
    int main()
    {
    	list_t *list2;
    	list2 = createList();
    	node_t *node1;
    	node_t *node2;
    	node1 = createNode(6);
    	node2 = createNode(7);
    	insertTail(list2, node1);
    	insertTail(list2, node2);
            printlist(list2)
    	IsEmpty(list2);	
    }
    And now I would assume that list2 have 2 nodes with values 6 and 7. However when I try to call the printlist function all is a newline which means either the list is empty or something is wrong. I then attempted to call my IsEmpty function to see if there were any errors with the insert function. That function returned a 1 which means the int.size != 0. This leads me to believe there is something wrong with my insertfunction. Would that be correct?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Dynamic memory. Output problems.
    By qwes3r in forum C++ Programming
    Replies: 3
    Last Post: 06-04-2015, 09:10 AM
  2. NUMA Virtual Adress Space / Physical Adress Space
    By NUMA Orly in forum Windows Programming
    Replies: 0
    Last Post: 03-14-2011, 03:19 AM
  3. Replies: 4
    Last Post: 11-01-2009, 06:19 AM
  4. Tell adress of object from adress of member
    By TriKri in forum C++ Programming
    Replies: 5
    Last Post: 10-07-2007, 05:04 AM
  5. Searching memory for an adress?
    By Blackroot in forum C++ Programming
    Replies: 12
    Last Post: 03-27-2007, 11:59 PM

Tags for this Thread