0

I'm currently making a RedBlackTree in C and I still don't understand which one is better / more ideal when it comes to having a constuctor function for your structures.

struct RedBlackTree* RedBlackTree_new()
{
    struct RedBlackTree *tree = calloc(1, sizeof(struct RedBlackTree));
    if (tree == NULL)
        error(DS_MSG_OUT_OF_MEM);
    return tree 
}

VS.

struct RedBlackTree RedBlackTree_new()
{
    struct RedBlackTree tree;
    tree.root = NULL;
    tree.size = 0;
    return tree;
}

I mean, if I do the second option, then I constantly have to pass it into my functions as a pointer using & and to my knowledge, I can never destroy it until my program ends (can someone verify if that's true?). For example, if I had adestroy function for my Tree, I wouldn't be able to free the memory allocated from structures within the RedBlackTree if they weren't created with malloc or calloc right?

Also in a more general case, what are the advantages and disadvantages of either? I can always retrieve the data from the pointer by using * and I can always turn my data into a pointer by using &, so it almost feels like they are completely interchangable in a sense.

Hatefiend
  • 3,416
  • 6
  • 33
  • 74
  • 2
    The latter is less efficient because you are returning the entire structure which needs to be copied into the caller's variable. That's generally why pointers are passed around rather than the entire struct. – kaylum Sep 14 '16 at 02:22
  • Returning a pointer doesn't require the caller to know the contents of the struct... – Dmitri Sep 14 '16 at 02:30
  • Also there is `void RedBlackTree_new(RedBlackTree *)` . Each has their advantage and disadvantage! – M.M Sep 14 '16 at 02:53
  • @M.M: That would require a `RedBlackTree **` actually. – too honest for this site Sep 14 '16 at 03:11
  • Note using old-style function declarators with empty argument list is deprecated by the standard. Use prototype-style like `f(void)`. – too honest for this site Sep 14 '16 at 03:12
  • 1
    @Olaf `RedBlackTree *` is enough if the caller handles the allocation – Dmitri Sep 14 '16 at 03:14
  • @Dmitri: The suffix `new` normally implies the object is created in the function and initialised. But the question compares apples and oranges anyway, so maybe that would be another option for him, too. – too honest for this site Sep 14 '16 at 03:16
  • The functions serve different purposes. I don't see how they are alternatives to each other. Note that the `new` suffix for the second one is missleading, as it does not really create a new `struct` for the caller, but returns a template. That can much easier be accomplished by a simple assignment of a `const` qualified "template-`struct`". No need for a function. – too honest for this site Sep 14 '16 at 03:17
  • @Olaf the second one returns a object with automatic storage duration, that didn't previous exist, therefore it is a new object – M.M Sep 14 '16 at 03:21
  • @M.M: The object is not an lvalue in C, so it cannot be used by the caller. It has to use an assignment, i.e. its own object (wherever it gets that from). So from the caller's view, the function does much the same as provide a template `struct` which it has to assign to a pre-allocated `struct`. – too honest for this site Sep 14 '16 at 03:25
  • "The object is not an lvalue in C, so it cannot be used by the caller" - there is no such rule. Also, a compiler may implement a sort of 'return value optimization' and avoid an extra copy for code that initializes a variable with the return value. – M.M Sep 14 '16 at 03:38
  • You might want to take a look at [this](http://stackoverflow.com/questions/39472797/oop-programming-with-data-encapsulation-in-c) for an example how to design ADTs/classes. – Lundin Sep 14 '16 at 06:34

2 Answers2

5

The real difference is the lifetime of the object. An object allocated on heap through dynamic allocation (malloc/calloc and free) survives until it's explicitly freed.

On the contrary an object which has automatic storage, like in your second example, survives only the scope in which it's declared and must be copied somewhere else to make it survive.

So this should help you in choosing which suits better a specific circumstance.

From an efficiency perspective dynamic allocation is more expensive and requires additional indirections but allows you to pass pointers around, which prevents data from being copied thus can be more efficient in other situations, eg. when objects are large and copies would be expensive.

Jack
  • 131,802
  • 30
  • 241
  • 343
  • Of course, with the struct return like the second example, the caller could still allocate a struct dynamically and then assign the function return to it if desired... but with the pointer version dynamic allocation is essentially mandatory. – Dmitri Sep 14 '16 at 02:33
  • The C standard does not enforce using a stack. And where the object in the caller is lacated for the second variant is not specified. It could be some `malloc`ed object. – too honest for this site Sep 14 '16 at 03:14
  • @Olaf: And this justifies a down-vote? Your observation just applies to my footnote regarding efficiency, which will be true in 99% of the situations and false only when automatic storage is not implemented through stack (which probably applies to few obscure C implementations somewhere but it is definitely something you shouldn't care about when trying to understand the difference between automatic and dynamic allocations). – Jack Sep 14 '16 at 03:23
  • @Jack: Well, maybe I missunderstood your second paragraph. As it reads to me, you assume the caller has to provide an `auto` variable for the LHS of an assignment. On second thought, I might be wrong. Removed the DV (it was not for the stack, but good you corrected that). I'm still not happy with that part. Which scope has an object returned from a function? AFAIS only the expression it is used. (too tired to check now, good night). – too honest for this site Sep 14 '16 at 03:31
-4

firstly it's better to use typedef. it's easier.

if u create an object dynamically, u need to free every member of the object urself. or, the memory leak.

if it is a big struct , when u return it, it create a temp object. it cost more. so I prefer pointer! and forget what i say before. I just sleepwalking.

qcc
  • 1
  • 2
  • 1
    This doesn't really answer the question. Furthermore, you [shouldn't be casting the return value of malloc](http://stackoverflow.com/a/605858/268025). – tangrs Sep 14 '16 at 03:30
  • 3
    There's a bunch of issues with this answer. Saying you can return a "typedef" from a function is misleading. Your grammar may be very difficult for someone to decipher if English isn't their first language. Your code needs to be in a code block - right now it looks very much like there are syntax errors in it. Your statement that a local primitive variable cannot be returned from a function is incorrect and you should not cast the return value of malloc – Tibrogargan Sep 14 '16 at 03:31
  • Also, why is `int abc(){int a = 5 ; return a;}` wrong? It's perfectly defined behaviour to return integers from a function. – tangrs Sep 14 '16 at 03:32
  • I heard that typedef overpolutes the global namespace. I think I agree with it. – Hatefiend Sep 14 '16 at 03:40