Are the memory allocations done via malloc() inside a loop destroyed upon exiting the loop?

I am new to C++. I am trying to implement Linked Lists and doing so using classes. In order to allocate the Nodes, I use malloc() and allocate the memory for each node inside a for loop (for the 2nd to 2nd last node).

But, when I try to print the values, by using the printList() function, the memory addresses change and I can no longer access the value stored earlier.

Code in question:

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

class Node{
    private:
        // Attributes
        int value;
        Node* nextNode;

    public:
    
        // Empty Constructor
        Node(){
            value = 0;
        }

        // Value-and-address Constructor
        Node(int localValue, Node* localAddress){
            value = localValue;
            nextNode = localAddress;
        }

        // Value Setter
        void setValue(int localValue){
            value = localValue;
        }

        // Address Setter
        void setAddress(Node* localAddress){
            nextNode = localAddress;
        }

        // Value Getter
        int getValue(){
            return value;
        }

        // Next Node Address Getter
        Node* getNextNode(){
            return nextNode;
        }
};


class linkedList{
    private:
        Node* firstNode;
        Node* lastNode;
        int sizeOfNode = sizeof(Node);
        int lengthOfList = 0;
        int iter;
        Node* container = (Node*)malloc(sizeof(Node)); // Container for last node

    public:

        // Constructor
        linkedList(int sizeOfList, int* localArray){

            // Creation of first Node
            firstNode = (Node*)malloc(sizeOfNode);
            *firstNode = Node(localArray[0], container);

            Node* previousNode = previousNode; // Current Node
            lengthOfList ++;

            for(int i = 1; i < sizeOfList-1; i++){
                iter = i;
                Node* currentNode = (Node*)malloc(sizeOfNode);
                printf("n Next Node Location: %p", currentNode);
                (*previousNode).setAddress(currentNode);
                printf("n Current Node Location: %p", (*previousNode).getNextNode());
                *currentNode = Node(localArray[i], container);
                previousNode = currentNode;
                lengthOfList ++;
            }

            // Creation of last Node
            iter++;            
            lastNode = (Node*)malloc(sizeOfNode);
            *lastNode = Node(localArray[iter], container);
            lengthOfList ++;
        }

        void printList(){
            // First Print
            Node* currentNode = firstNode;
            for(int i = 0; i < lengthOfList; i++){
                printf("n%d: %dn", i, (*currentNode).getValue());
                printf("Next Node Location: %pn", (*currentNode).getNextNode());
                currentNode = (*currentNode).getNextNode();
            }
        }
};


int main(){

    int passedArray[] = {1, 2, 3, 4};
    int sizeOfPassedArray = sizeof(passedArray)/sizeof(int);

    linkedList list1 = linkedList(sizeOfPassedArray, passedArray);
    list1.printList();
}

Upon running it, the output is:

 Next Node Location: 00000261A1E6F940
 Current Node Location: 00000261A1E6F940
 Next Node Location: 00000261A1E6F700
 Current Node Location: 00000261A1E6F700
0: 1
Next Node Location: 00000261A1E6F780

1: 0
Next Node Location: 0000000000000000

The reason I think the address is changed when the loop is exited is because:

  1. The output prints a different address.

  2. I can still access the firstNode normally.

What is the issue, and how do I solve it?

The debugger shows segmentation fault at the return value line in the getValue() function, if that is relevant, but that is only from the second iteration of the printList() loop and onwards.

17

I will try to summarize it for you:

  1. malloc will never call the constructor of your class as it is mainly used for C not for C++.
  2. to dynamically allocate class instances in C++ you should use new instead of malloc
  3. allocated memory using malloc or new must be freed with free or delete respectively
  4. using free will never call your instance destructor

once you are done with your instance delete it.

1

All right, something constructive to think about here. You have the basic idea down, just a few things to help clarify stuff in your head.

Node

A “node” should be a very simple class. The idea of setters and getters is a good one, but you typically only need them when modifying them needs to involve functionality affecting the other parts of the class. In the case of a node in a linked list, the node itself should not be public facing, so no setters or getters are really necessary:

struct node
{
  int    value;
  node * next;
};

But if you really want to add setters and getters, it is also a good idea to be careful with your vocabulary. An “address” is the value stored in a pointer. You aren’t storing any old address, you are storing the address of the next node, which we can abbreviate to just “next” (or not: “nextNode” works too).

In any case, try to stick to the same vocabulary word when dealing with an object:

class node
{
  int    _value;
  node * _next;

public:
  int    getValue() const { return _value; }
  void   setValue( int value ) { _value = value; }
  node * getNext() const { return _next; }
  void   setNext( node * next ) { _next = next; }
};

This keeps things simple and easy to track (meaning: it is less easy to confuse yourself when using the class later).

Names

Notice also that I did not capitalize the name of the class. You can, of course, but then be consistent: (Node and LinkedList) or (node and linkedList).

⟶ I personally prefer snake_case: linked_list, but most people seem to prefer camelCase or PascalCase. Meh.

Also, you will notice that I added a leading underscore to private member variables. You do not need to do this, but a lot of people like to decorate them as such — it helps you (the programmer) to remember that this is a private field and should only be accessed by methods that have a good reason to be touching them directly. Other common ways to decorate them include m_value and value_.

⟶ Keep in mind that leading underscores are not valid for global object names.

Linked List

A doubly-linked list comes in two flavors:

  • head and tail node pointers reference the actual head and tail nodes of the list
  • head and tail nodes (actual node objects) are empty and are used to bracket the actual list. That is, head’s value is ignored, and it’s next pointer points to the actual first node in the list. This comes at the cost of using more space for every list (by a count of two nodes with unused values) but makes life a whole lot easier when writing the code to deal with inserting and deleting nodes from the list.

Yours is a singly-linked list, but things change only a little. The head still works the same as it does in a doubly-linked list (whichever option you choose), but the tail is now only useful for quickly appending data to the list, and therefore must always just be a pointer to the actual last node in the list regardless of whether or not head is a pointer.

⟶ Many singly-linked lists do not have a tail pointer, since their needs only require adding a node to the head and rarely the tail. Again, use case matters!

container vs tail/last node

Because the tail pointer must always point to the actual tail node of the list, there is no need to allocate a container. Again, vocabulary here matters. The word “container” is expected to refer to the structure managing the entire collection. (You have already named that “linkedList”.)

Since you already have a tail pointer, you do not need another magic empty node to manage the tail. Just make sure that tail always points to the last node in the list and all is good.

sizeOfNode is…?

Beware to not use variables to store values that are easily obtained from the compiler. All that does is obfuscate what is really happening. Hence:

int sizeOfNode = sizeof(Node);

is totally unnecessary. If at any time you need the size of an object, just use sizeof. Using sizeOfNode makes the reader wonder if there is something unusual going on that he or she cannot immediately see, since you are taking the effort to store a value it is reasonable to assume that there is a reason for that, and the only reason would be if there is some spot where sizeOfNode is not equal to sizeof(Node). That is not the case, hence doing that adds complexity for no reason.

iter doesn’t belong

The word “iter” refers to an iterator, which is a pointer (or pretends to be one). Further, the variable itself is only used in a function. Again, do not declare anything not strictly necessary to store the data in the class definition. Variables like this should be declared in the function they are used, as close to where they are used as possible.

For a simple integer index into an array, variable names like i and j and k and n are common.

Revised list

Your revised linked list class might look like this:

class linkedList
{
  node * _firstNode;  // or head or headNode etc
  node * _lastNode;   // or tail or tailNode etc
  int    _lengthOfList;

public:

  linkedList() : _firstNode{nullptr}, _lastNode{nullptr}, _lengthOfList{0} { }

  linkedList( int length, int * array )
  : _firstNode{nullptr}, _lastNode{nullptr}, _lengthOfList{0}
  {
    ...
  }

  int getLength() const { return _lengthOfList; }
};

Note that we have a default constructor (which just gives you an empty list) and a constructor that takes an array of integers to build a list. The : indicates a “member initializer list”, which allows us to easily give all the class member objects an initial value, which we should. (Otherwise you would have to assign initial directly in the body of the construct, which also works, but whatever floats your boat.)

  linkedList()
  {
    _firstNode = nullptr;
    _lastNode = nullptr;
    _lengthOfList = 0;
  }

Notice also the addition of a getter to obtain the current list length. There is no setter. To change the length nodes must be added or deleted.

⟶ Standard C++ containers call this “size”. So you could name _lengthOfList just _size and the getter int size() const { return _size; } and everyone who reads your code will understand that it refers to the number of elements in your linked list.

Adding nodes to the end of your list

Before you worry about the array ⟶ linked list constructor, you should have a method to simply append a single node to the end of the list. Something like:

class linkedList
{

public:

  ...

  void append( int value )
  {
    ...
  }

  ...
};

This method should do nothing more than tack a new node onto the end of the list. It needs to:

  • allocate memory for the new node (using either malloc() or even better, since this is C++, using new)
  • set the newly-allocated node’s _value to the argument value
  • set the newly-allocated node’s _nextNode to nullptr
  • set _lastNode->_nextNode to your new node (thus linking your node to the end of the list)
  • set _lastNode to point to the new node (in order to keep _lastNode pointing to the actual last node in the list)
  • increment the _lengthOfList (in order to keep it accurate)

This kind of thing is something you should draw on a piece of paper. You should use a paper and pencil every time you do something to link or unlink nodes in your list.

Caveats for your singly-linked list:

  • The _firstNode may be nullptr. If it is you must set both its value and _lastNode’s value to point to the new node.
  • If _firstNode is not nullptr, you only need to update _lastNode.

Again, drawing this out on paper will help you to see these issues!

Now that you have a function to append nodes, your array ⟶ linked list constructor is super easy to write:

  linkedList( int length, int * array )
  : _firstNode{nullptr}, _lastNode{nullptr}, _lengthOfList{0}
  {
    for (int n = 0;  n < length;  n++)
      append( array[n] );
  }

That was surprisingly easy, no?

Final Thoughts

As you learn to use C++ and work your way through these kinds of structures life will get easier. Remember, it is always okay to build yourself a model of what you are trying to do, whether it be with paperclips or a pencil and paper (or whatever seems useful).

In this case, the most basic blocks of a linked list are:

  • how to store the structure
  • adding a node
  • removing a node
  • indexing a node

Everything else is just sweet, sweet sugar to help you do those things.

6

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật