0

I think i have a beginner doubt. I don't know if it is a very stupid question, but there is any difference between this two cases:

Generic struct:

typedef struct {

    void* data;

} Object;

1st case: This case allocates memory on a pointer and then, the pointer is returned.

Object* NewObject1(const void* data) {

    Object* This = (Object*)malloc(sizeof(Object));
    memcpy_s(&This->data, sizeof(void**), &data, sizeof(void**));

    return This;
}

2nd case: In this case, the memory is allocated on a pointer that was given by the user.

void NewObject2(Object** This, const void* data) {

    *This = (Object*)malloc(sizeof(Object));
    memcpy_s(&(*This)->data, sizeof(void**), &data, sizeof(void**));

}

The result, actually, is the same:

int main(){

    Object* a = NewObject1((void*)10);
    printf("a->data = %d\n", (int)a->data);

    Object* b = NULL;
    NewObject2(&b, (void*)10);
    printf("b->data = %d\n", (int)b->data);

    return 0;
}

Output:

a->data = 10
b->data = 10

So my question is: There is any real difference between allocating memory as in the first case or as in the second. For example, memory safety, performance, etc.

  • The memory allocation is the same in both, the only difference is in one you return a pointer and the other you pass in a pointer to a pointer and set it there. There's no difference except in clarity of code. – Paul Hankin Jun 14 '20 at 12:10

1 Answers1

1

The two methods of returning a value the same. You can either return by value, or use a pointer argument that points to where the "returned" value should be written.

However there are several other strange things with your code:

  • Instead of memcpy_s, you should just write This->data = data; and (*This)->data = data; respectively. And fix the const-correctness.
  • (void *)10 is probably not a valid address, this might cause a trap, bus error or other problem. (undefined behaviour if it is not the address of an actual object)
  • Casting the result of malloc is redundant or worse.
  • The return value of malloc should be checked.
M.M
  • 130,300
  • 18
  • 171
  • 314
  • But i am using `(void*)10` as a value, not as an address. Is this a bad habit or an error? – Álvaro Rodrigo Jun 14 '20 at 12:16
  • The C standard: "6.3.2.3:5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation." – Paul Hankin Jun 14 '20 at 12:21
  • Use a union if you want to store different types into the same field. – Paul Hankin Jun 14 '20 at 12:22
  • 1
    @PaulHankin or `uintptr_t` if pointers and integers are the only requirement – M.M Jun 14 '20 at 12:25
  • @M.M there is no guarantee that converting a `uintptr_t` and back preserves the value I think? Only that if you convert a `void*` to `uintptr_t` and back you get the same pointer. – Paul Hankin Jun 14 '20 at 12:27
  • @PaulHankin not sure if there is a guarantee, but it's one of those things you can pretty safely rely on a compiler to behave as expected – M.M Jun 14 '20 at 12:28
  • Not sure how you align your last comment with what you said in your answer, since the exact same concerns apply for uintptr_t as they do for any other int type - the only difference is the other way round, that converting the pointer to a uintptr_t won't lose information. – Paul Hankin Jun 14 '20 at 12:33
  • So, summarizing. The functions do the same thing, also I should delete the `const` keyword from the two functions, use the `=` instead of the `memcpy_s` and assert the result of the `malloc` (Note: I didn't do this, because it was an example). Anything else?. – Álvaro Rodrigo Jun 14 '20 at 13:01