When passing a char* as an argument to a function, should the called function do a free on that string? Otherwise the data would be "lost" right and the program would leak data. Or are char* handled in a special way by the compiler to avoid everyone from having to do free all the time and automatically deletes it one it goes out of scope? I pass "the string" to the function so not an instance to an already existing char*. Or should one use char[] instead? Just feels so dumb to set a fixed limit to the argument input.
It sounds like you're asking about this usage:
void foo(char* str);
foo("test string");
This is a special case; "test string"
is a constant string stored in the string table within the executable, and doesn't need to be freed. foo
should actually take a const char*
to illustrate that, and allowing string literals to be stored in non-constant char*
s is deprecated in C++
Whether the function should do a free
or not depends on who owns the string. This code is perfectly valid and doesn't result in any memory leak:
int main()
{
char* s = malloc(.....);
f(s);
free(s);
}
The free
can be performed inside function f
as well if it takes the ownership of the string. However note that it is dangerous since you are assuming that string passed to function f
is always allocated on heap using malloc
or related functions. If a user passes pointer to a string allocated on stack your program will behave unpredicably.
On a general note, compiler doesn't do any special handling for memory management of strings. From compiler's point of view it is just a bunch of characters.
Keep this simple principle in mind: "always free memory at the same level that you allocated it". In other words a function should never try to free memory that it itself has not allocated. A short example to clarify this:
#include "graphics.h"
// The graphics API will get a Canvas object for us. This may be newly allocated
// or one from a pool of pre-allocated objects.
Canvas* canvas = graphics_get_canvas ();
// If draw_image () frees canvas, that violates the above principle.
// The behavior of the program will be unspecified. So, just draw the image
// and return.
draw_image (canvas);
// This is also a violation.
// free (canvas) ;
// The right thing to do is to give back the Canvas object to the graphics API
// so that it is freed at the same 'level' where it was allocated.
graphics_return_canvas (canvas);
Note that the function is not named graphics_free_canvas ()
or something like that, because the API may choose to free it or reuse it by returning it to a pool. The point is, it is an extremely bad programming practice to assume ownership of a resource that we did not create, unless we are specifically told otherwise.
Sometime a API expects a allocated buffer and its upto to the owner of the function which calls that api to free it.
myFunc()
{
char *error = malloc(<max size of error string>);
foo(error);
//Free the pointer here
free(error);
}
Some API like GLIB api's expect pointer to address of a declared variable
myFunc()
{
GError *error;
glib_api(&error);
if (error)
{
printf("Error %s", error-> message);
// can use glib API to free if error is NON NULL but message is allocated by GLIB API
g_error_free(error);
}
}
So even if you have not allocated memory to a variable you need to do the freeing while using standard libraries.
An allocated piece of memory, if not freed will result in lesser memory in a multiprocess environment, thereby degrading the performance of the system.
It seems that you are used to OOP style. I don't like the OOP, and for me it would be weird if I'd obtain a copy of an object after assigning. In this case the string is somewhere in memory, and its address is sent as char*, and not the whole string. Also, be careful that you can free() only the pointers returned by malloc(), and only once.
With plain char *
, I would recommend always writing code with a policy that the caller "owns" the string and is responsible for freeing it if it was obtained by malloc
. On the other hand, one could certainly envision "pseudo-pass by value" string objects in C, implemented as a struct, where policy dictates you have to relinquish ownership of a string (or duplicate it first and pass the duplicate) when passing strings as arguments. This could work especially well if the implementation used reference-counted storage for strings where the object passed was just a reference to the storage, so that the "duplicate" operation would merely be a reference-count increment plus trivial wrapper-struct allocation (or even pass-by-value struct).