Reputation: 38
Im interested in what practices are common when setting or returning large structures generated inside C functions. What is the best and safest way to do so. I can come up with 3 flavors of returning the generated structures. Do they all perform the same actions memory wise, or is one more efficient over the other? Do things change when overwriting existing values? For example when one changes a pointer does the old associated value get garbage collected automatically.
// Returning the instance
Image new_Image(const int height, const int width, const int depth) {
Image out;
out.width = width;
out.height = height;
out.depth = depth;
out.pixels = (float*) calloc((height*width*depth), sizeof(float));
return out;
}
Image image = new_Image(100,100,3);
// OR return a new pointer.
Image *new_Image(const int height, const int width, const int depth) {
Image out;
out.width = width;
out.height = height;
out.depth = depth;
out.pixels = (float*) calloc((height*width*depth), sizeof(float));
return &out;
}
Image *image;
image = new_Image(100,100,3);
// OR init outside function and populate in function. For cleanliness though I'd like as much of the image generating part to be done in the function.
Image *new_Image(Image *out, const int height, const int width, const int depth) {
out.width = width;
out.height = height;
out.depth = depth;
out.pixels = (float*) calloc((height*width*depth), sizeof(float));
}
Image *image = (Image*) malloc(sizeof(Image));
new_Image(image, 100,100,3);
Upvotes: 1
Views: 53
Reputation: 67476
Image new_Image(const int height, const int width, const int depth)
Safe but you return the whole structure by the value - which is not very effective and most implementation will do it through the stack. Stack especially on the small embedded systems is very limited in size. Not recursion friendly as well (a lots of stack consumed on every function call)
Image *new_Image(const int height, const int width, const int depth) {
Image out;
- undefined behaviour as you return the pointer to the local variable, which stops to exists when you leave the function.
Image *new_Image(Image *out, const int height, const int width, const int depth)
safe if you use the objects defined or allocated outside the function. BTW you forgot to return the pointer.
The option you did not mention in your question:
Image *new_Image(const int height, const int width, const int depth) {
Image *out = malloc(sizeof(*out));
/* malloc result tests */
out -> width = width;
out -> height = height;
out -> depth = depth;
out -> pixels = calloc((height*width*depth), sizeof(float));
/* calloc result tests */
return out;
}
You do not test your memory allocation results. It has to be done.
This function is also wrong:
Image *new_Image(Image *out, const int height, const int width, const int depth) {
out.width = width;
out.height = height;
out.depth = depth;
out.pixels = (float*) calloc((height*width*depth), sizeof(float));
}
It should be:
Image *new_Image(Image *out, const int height, const int width, const int depth) {
out -> width = width;
out -> height = height;
out -> depth = depth;
out -> pixels = calloc((height*width*depth), sizeof(float));
return out;
}
You do not need to cast the results of the malloc family functions. It was considered dangerous as using all standard of the language you would not get any warning messages if you forget to include . Nowadays compilers emit warnings if you call the function without the prototype
If you compile your code using the C++ compiler use command line options which will tell the compiler that the code is C (for example gcc or g++ -xc option)
Upvotes: 1