These two “methods” do exactly the same thing. And as you said, the second one is just a compound literal.
struct Object obj1 = { .id = 1 };
struct Object *obj1_p = &obj1;
// The same, just in a compound literal?
struct Object *obj2_p = &(struct Object){ .id = 1 };
This allocates enough memory for struct Object without initializing it. And no you don't need to cast it, because malloc returns void *, which is automatically and safely promoted to any other pointer. But if you do, you should cast it to struct Object* instead of Object*.
struct Object *obj3_p = (struct Object*) malloc(sizeof(struct Object));
That looks very bulky though... My preferred way of doing it is this:
struct Object *obj3_p = malloc(sizeof *obj3_p);
Answer from Andy Sukowski-Bang on Stack OverflowThese two “methods” do exactly the same thing. And as you said, the second one is just a compound literal.
struct Object obj1 = { .id = 1 };
struct Object *obj1_p = &obj1;
// The same, just in a compound literal?
struct Object *obj2_p = &(struct Object){ .id = 1 };
This allocates enough memory for struct Object without initializing it. And no you don't need to cast it, because malloc returns void *, which is automatically and safely promoted to any other pointer. But if you do, you should cast it to struct Object* instead of Object*.
struct Object *obj3_p = (struct Object*) malloc(sizeof(struct Object));
That looks very bulky though... My preferred way of doing it is this:
struct Object *obj3_p = malloc(sizeof *obj3_p);
I wrote this piece of code, hope it helps you to better understand some features of pointers:
#include <stdio.h>
#include <stdlib.h>
struct Object { int id; };
struct Object *getObjectNaive() {
struct Object* obj2_p = &(struct Object) { .id = 2 };
return obj2_p; // UB: Returns the address of a local object (the compound literal).
}
struct Object *getObject() {
struct Object* obj3_p = malloc(sizeof(*obj3_p)); // Better way of calling malloc than using sizeof(struct Object).
obj3_p->id = 3; // You don't need to do this.
return obj3_p; // This needs to be freed later on!
}
int main(void) {
struct Object obj1 = { .id = 1 };
struct Object* obj1_p = &obj1;
printf("obj1.id = %d\n", obj1_p->id);
obj1_p->id = 10; // You can change values using the pointer
printf("obj1.id = %d\n", obj1_p->id);
// The only different thing with this case is that you don't
// "lose" your object when setting the pointer to NULL
// (although you can only access it through the object, not through the pointer).
obj1_p = NULL;
printf("obj1.id = %d\n", obj1_p->id); // This won't work (undefined behaviour).
printf("obj1.id = %d\n", obj1.id); // This will.
struct Object* obj2_p = &(struct Object) { .id = 1 };
obj2_p->id = 2; // You can change the id
printf("obj2.id = %d\n", obj2_p->id);
// If you make this pointer point to another address, you "lose" your object.
obj2_p = NULL;
printf("obj2.id = %d", obj2_p->id); // This won't work at all (undefined behaviour).
// Both of these pointers point to objects in the stack, so, for example,
// they don't work when returning from a function.
obj2_p = getObjectNaive();
obj2_p->id = 20; // This won't work (undefined behaviour).
printf("obj2.id = %d\n", obj2_p->id); // This works if you don't dereference the pointer.
// The third case is not the same as the other two, since you are allocating memory on the heap.
// THIS is a time where you can only use one of these three methods.
struct Object *obj3_p = getObject(); // This works!
printf("obj3.id = %d\n", obj3_p->id);
obj3_p->id = 30; // This works now.
printf("obj3.id = %d\n", obj3_p->id);
free(obj3_p); // You need to do this if you don't want memory leaks.
return 0;
}
This is the output when commenting out undefined behaviour:
obj1.id = 1
obj1.id = 10
obj1.id = 10
obj2.id = 2
obj2.id = 2
obj3.id = 3
obj3.id = 30
I'd recommend you to check out these links, they turned out to be pretty helpful for me:
- Returning a pointer from a function
- What and where are the stack and heap?
- What EXACTLY is meant by “de-referencing a NULL pointer”?
- Why dereferencing a null pointer is undefined behaviour?
- Do I cast the result of malloc?
Bjarne Stroustrup said:
The choice between "int* p;" and "int *p;" is not about right and wrong, but about style and emphasis. C emphasized expressions; declarations were often considered little more than a necessary evil. C++, on the other hand, has a heavy emphasis on types.
A "typical C programmer" writes "int *p;" and explains it "*p is what is the int" emphasizing syntax, and may point to the C (and C++) declaration grammar to argue for the correctness of the style. Indeed, the * binds to the name p in the grammar.
A "typical C++ programmer" writes "int* p;" and explains it "p is a pointer to an int" emphasizing type. Indeed the type of p is int*. I clearly prefer that emphasis and see it as important for using the more advanced parts of C++ well.
Source: http://www.stroustrup.com/bs_faq2.html#whitespace
I'd recommend the latter style because in the situation where you are declaring multiple pointers in a single line (your 4th example), having the asterisk with the variable will be what you're used to.
I personally prefer to place the * with the rest of the type
char* p; // p is a pointer to a char.
People will argue "but then char* p, q; becomes misleading", to which I say, "so don't do that".