Home > Enterprise >  Bridging struct initializations on the heap (when using Dynamically Allocated Memory) to struct init
Bridging struct initializations on the heap (when using Dynamically Allocated Memory) to struct init

Time:11-07

When dealing with memory to be placed on the stack, there are comfortable ways for doing struct initialization: https://en.cppreference.com/w/c/language/struct_initialization

I want to do the same when the memory is placed on the heap (i.e., when using Dynamically Allocated Memory). To base the discussion, let us use the following struct:

// Definition for a binary tree node.
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

First, I get the address:

struct TreeNode * target = malloc(sizeof(struct TreeNode));

Now what? I offer one possibility (possibility 2: Initialization by assignment), and I have two questions:

  1. Is my possibility a solution? I could not find resources about doing initializations by assignment.
  2. Are there any other solutions?

Possibility 1: Direct access through dereference

We do the following:

target -> val = 1;
target -> left = NULL;
target -> right = NULL;

I find this method tedious.

Possibility 2: Initialization by assignment

We do the following:

struct TreeNode sub_target = {.val = val_1, .left = NULL, .right = NULL};
*target = sub_target;

This method seems better, as it allows using all types of struct initializations on the stack but for the heap. It works when I try it, but I do not know if it works in general.

CodePudding user response:

malloc does not initialize the memory it allocates. Only variables can be initialized. In your example, target is initialized with the address return by malloc, but the corresponding memory is not. There is no mechanism to do that. The only thing I can think of is calloc that zeroes out the memory, but that's a different story, and initialization to zero is a somewhat limited use case.

Note that what you call "initialization by assignment" is not initialization. In your example, *target is first allocated and already "contains" something. Only then do you assign a specific value to it, but that's just an assignment, not an initialization.

Also, I would expect the compiler to generate the exact same code from your two scenarios. Your "direct access through dereference" is just the assignment of each member one by one, which is pretty much what happens with a struct assignment (like in your "possibility 2"). It's all just memcpy, or assembly mov instructions. The only difference is that in the second scenario you create another variable sub_target, but that is most likely optimized away.

Here is what I suggest in my comment:

TreeNode* create_node(int val) {
    struct TreeNode* node = malloc(sizeof(*node));
    node->val = val;
    node->left = NULL;
    node->right = NULL;
    return node;
}
// [...]
struct TreeNode* target = create_node(1);

It does not answer my question, as I would still need to do initialization inside such a function.

I'm afraid there is no way to do exactly what you want. The system itself would need to provide some other kind of allocating function , maybe with a variadic parameter list of values to initialize the memory with, but it would be more complicated to implement and give no real benefit.

Sidenote: in C (and a lot of other languages), classes have constructors. Constructors take care of initialization, and in fact, the C standard defines default-initialization for such classes as calling the default constructor. But in reality, a constructor is only just a fancy version of a create_node function.

  • Related