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.
-
1Michael's good answer tells you to consider strings stored in what is known as "static storage" -- this is storage initialized in memory by the OS when the program image is loaded. Naveen's example, and free/malloc themselves, use the "free store", sometimes called the "heap." There is also "automatic storage" usually implemented as the "stack." Other storage possibilities are OS-mapped ABI memory regions, memory-mapped files, and so on. An example might be an OS call returning the current directory string -- this `char *` could point to per-thread data structure of OS. – Heath Hunnicutt Jul 20 '10 at 06:39
-
You normally shouldn't set a fixed limit to the argument input. Instead, have the caller give you a pointer and let *them* tell *you* how long the string is. – bta Jul 20 '10 at 16:47
7 Answers
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.

- 26,737
- 4
- 62
- 93
-
4How does that sit with the likes of malloc() and strcmp()? They're meant to be freed at a different level. In fact, reductio ad absurdum, free() itself would never free memory :-) – paxdiablo Jul 20 '10 at 06:38
-
@paxdiablo, strcmp()? Did you mean strdup()? If so, I don't see how they are meant to be freed at a different level. strcmp(), of course, doesn't allocate anything. – Heath Hunnicutt Jul 20 '10 at 06:41
-
@HH, I don't think he really means it. The principle outlined in the answer (clean up your own mess) is sound. Avoid the construct used by one of my former colleagues, that his functions returned a char * to the (text) answer, in which case you had to free it, or to an error message, in which case you had not to free it. – Brian Hooper Jul 20 '10 at 06:55
-
1I agree with paxdiablo. Also that principle doesn't make sense when for example designing an API where you'd need to allocate memory for some data structure and pass that back to a user to fiddle with. Wouldn't it be better to stick to the principle "always free memory in the same context as it was allocated", meaning that if you're allocating memory when in X (X meaning translation unit/part of api/program state) it most probably makes sense to also free that memory when in X. In short; if you're allocating in network_stuff.c and freeing in paint_rectangle.c it's time to redesign =). – manneorama Jul 20 '10 at 07:10
-
@Heath, yes, sorry, a bit of a brainfart there. I meant strdup. I tend to prefer the "responsibility for memory goes with the memory itself" school of thought. In other words, malloc and strdup pass back the memory _and_ the responsibility. When you pass a block to another thread, _don't touch it again_ until that thread gives back the responsibility. If an API function states that you must give it malloced memory which it will then free, the responsibility _never_ comes back to you (e.g., free). – paxdiablo Jul 20 '10 at 07:20
-
There seems to be a lot of confusion on my answer, someone even going to the extreme of stating that 'free() itself would never free memory'. So I added an example. What I said is just a simple, generally accepted practice followed when programming in languages that only have explicit memory management. – Vijay Mathew Jul 20 '10 at 09:15
-
The principle is a good one. It doesn't apply to strdup, malloc and free because they are part of the memory allocation infrastructure, and also they *document their behaviour*. – JeremyP Jul 20 '10 at 12:16
-
@paxdiablo - I do not understand when you write that `malloc` and `strdup` are meant to be freed "at a different level." Can you explain that? – Heath Hunnicutt Jul 20 '10 at 16:58
-
@Heath, the classic implementation of strdup is to call malloc and copy the string to the resultant memory block. If you dogmatically followed the "always free memory at the same level", you would never be allowed to return that memory from strdup since you'd have to clean it up and the same level. To say that that's ok since they document their behaviour is irrelevant since your own code can document its behaviour as well. Keep in mind this is not a bad answer, especially since Vijay has tempered the " _always_ free memory ..." with the phrase "unless we are told otherwise" (less dogmatic). – paxdiablo Jul 20 '10 at 20:34
-
1The paradigm of passing a pointer back to the API for freeing is a good one since if you may want to introduce other cleanup code (more than just a free) at some point in the future. However, others subscribe to YAGNI, which would dictate the right time to allow for that is when it's needed, not in anticipation of the _possible_ need (in other words, change the API at the time when you need to do the extra stuff and clients will have to change their code as well). I just wanted to point out a counter-argument for the original answer. Both sides have their pros and cons. – paxdiablo Jul 20 '10 at 20:44
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++

- 169,610
- 28
- 168
- 175
-
To expand on this a bit, the string literal "test string" exists as a 12-element array of char (const char in C++) with *static extent*, meaning the memory for it is allocated at program startup and held until the program exits. When you pass a string literal as a function argument, the compiler **does not** create a new instance of the string; instead, it passes a pointer to the existing instance. – John Bode Jul 20 '10 at 18:36
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.

- 74,600
- 47
- 176
- 233
-
1Not just a stack-allocated string. If you pass `f()` a string literal, and `f()` tries to free it, you will also get into trouble. – ptomato Jul 20 '10 at 08:58
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.

- 14,714
- 1
- 39
- 40
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.

- 10,355
- 2
- 43
- 69
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).

- 208,859
- 35
- 376
- 711
The pointer to char as a function variable is an address to the same variable except where it's been substituted as a constant string. Your question can't be explained with a simple yes/no guideline; it depends on context. In the code below, a struct allocated on heap and stack individually are passed by reference as well as a string char * and data is inserted into the struct. Notice how the mallocs differ as to when they are used but the function works all the same.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// struct with all data within
typedef struct d
{
int number;
char name[50];
}data;
// struct with dynamic char *
typedef struct d2
{
int number;
char *name;
}dynamic_data;
// generic function placing data into struct
void InsertData ( data * out, int a, char * b )
{
out->number = a;
strcpy(out->name, b);
}
// generic function placing data into second struct
void InsertData2 ( dynamic_data * out, int a, char * b )
{
out->number = a;
strcpy(out->name, b);
}
int main ( void )
{
char * text = "some string\0";
int n = 20;
// allocated struct
data stuff;
dynamic_data stuff2;
dynamic_data * stuff3;
// need to allocate pointer within struct only
stuff2.name = (char *) malloc(50 * sizeof(char));
// heap allocated struct
stuff3 = (dynamic_data * ) malloc(50 * sizeof(dynamic_data));
// heap allocated sub element char *
stuff3->name = (char *) malloc(50 * sizeof(char));
// this is the data
printf ( "Pre insertion data\n" );
printf ( "s=[%s]\n", text );
printf ( "n=%d\n", n );
// this is the function insertting
InsertData ( &stuff, n, text );
printf ( "Post insertion data\n" );
printf ( "stuff.name=[%s]\n", stuff.name );
printf ( "stuff.number=%d\n", stuff.number );
// this is the function inserting
InsertData2 ( &stuff2, n, text );
printf ( "Post insertion data\n" );
printf ( "stuff.name=[%s]\n", stuff2.name );
printf ( "stuff.number=%d\n", stuff2.number );
//
// This is the segfault version - if nothing was allocated for pointers into
// this function scope, it would crash
// this is the function insertting under a heap allocated
InsertData2 ( stuff3, n, text );
printf ( "Post insertion data - dynamic version\n" );
printf ( "stuff3->name=[%s]\n", stuff3->name );
printf ( "stuff3->number=%d\n", stuff3->number );
// free in reverse order
free(stuff3->name);
free(stuff3);
free(stuff2.name);
return 0;
}

- 309
- 2
- 12