I came across an issue that I am not sure if it's an issue at all. I have a simple C funcion that gets a char* passed from string like so:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
passString("hello");
return (EXIT_SUCCESS);
}
void passString(char * string) {
// .... some code ....
free(string); // ???
}
and I was taught to free every memory block that I'm not working with anymore (mainly arrays). So my though was to free string as well but the program freezes or crashes even with this simple example. I'm not sure whether I really need to free string here or not and if so how do I achieve that?
You do not need to free memory which you did not allocate with malloc.
In your example string is not allocated by malloc in your program so you do not need to free it. string is a string literal and is allocated somewhere in the read-only memory(implementation defined) and is automatically freed.
For standerdese fans:
References:
c99 Standard: 7.20.3.2 The free function
Synopsis
#include
void free(void *ptr);
Description:
The free function causes the space pointed to by ptr to be deallocated, that is, made
available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if
the argument does not match a pointer earlier returned by the calloc, malloc,or
realloc function, or if the space has been deallocated by a call to free or realloc,
the behavior is undeļ¬ned.
Returns
The free function returns no value.
The string you're freeing is statically allocated, "during compilation" if you will. Indeed any string literal ("hello") is done this way. You cannot free statically allocated memory as it does not live in the heap.
As a general rule, it's actually better to free at the point of allocation. In this case, were you to dynamically allocate space for "hello", you would do this:
int main(int argc, char** argv) {
char *s = strdup("hello");
passString(s);
free(s);
return (EXIT_SUCCESS);
}
void passString(char * string) {
// .... some code ....
}
You only need to free what you've allocated dynamically (via malloc in C or via keyword new in C++). Basically, for any allocation call like malloc() there should be a free() somewhere.
String literals aren't dynamically allocated and you don't need to be concerned about them.
Related
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
char* test() {
char* s = "Hello World";
size_t len = strlen(s);
char* t = malloc(sizeof(char)*(len+1));
strcpy(t, s);
free(t);
return t;
};
int main(void) {
printf("%s\n", test());
return 0;
};
I would like to allocate and de-allocate memory inside the function. I tested this code and works, but I am wondering:
Why does this work?
Is it good practice to use the value of a freed pointer in main ?
Once you call free on a pointer, the memory it pointed to is no longer valid. Attempting to use a pointer to freed memory triggers undefined behavior. In this particular case it happened to work, but there's no guarantee of that.
If the function returns allocated memory, it is the responsibility of the caller to free it:
char* test() {
char* s = "Hello World";
size_t len = strlen(s);
char* t = malloc(sizeof(char)*(len+1));
strcpy(t, s);
return t;
};
int main(void) {
char *t = test();
printf("%s\n", t);
free(t);
return 0;
};
malloc reserves memory for use.
free releases that reservation. In general, it does not make the memory go away, it does not change the contents of that memory, and it does not alter the value of the pointer that held the address.
After free(t), the bytes of t still contain the same bit settings they did before the free. Then return t; returns those bits to the caller.
When main passes those bits to printf, printf uses them as the address to get the characters for %s. Since nothing has changed them, they are printed.
That is why you got the behavior you did with this program. However, none of it is guaranteed. Once free was called with t, the memory reservation was gone. Something else in your program could have used that memory. For example, printf might have allocated a buffer for its own internal use, and that could have used the same memory.
For the most part, malloc and free are just methods of coordinating use of memory, so that different parts of your program do not try to use the same memory at the same time for different purposes. When you only have one part of your program using allocated memory, there are no other parts of your program to interfere with that. So the lack of coordination did not cause your program to fail. If you had multiple routines in your program using allocated memory, then attempting to use memory after it has been released is more likely to encounter problems.
Additionally, once the memory has been freed, the compiler may treat a pointer to it as if it has no fixed value. The return t; statement is not required to return any particular value.
It doesn't matter where do you free() a pointer. Once it is free()d, the pointer is not deferrenciable anymore (neither inside nor ouside the function where it was free()d)
The purpose of free() is to return the memory allocated with malloc() so the semantics are that, once you have freed a chunk of memory, it is not anymore usable.
In C, all parameters are passed by value, so free() cannot change the value expression you passed to it, and this is the reason the pointer is not changed into an invalid pointer value (like NULL) but you are advised that no more uses of the pointer can be done without incurring in Undefined Behaviour.
There could be a solution in the design of free() and it is to pass the pointer variable that holds the pointer by address, and so free() would be able to turn the pointer into a NULL. But this not only takes more work to do, but free() doesn't know how many copies you have made of the value malloc() gave to you... so it is impossible to know how many references you have over there to be nullified. That approach makes it impossible to give free() the responsibility of nullifying the reference to the returned memory.
So, if you think that free doesn't turn the pointer into NULL and for some strange reason you can still use the memory returned, don't do it anymore, because you'll be making mistakes.
You are adviced! :)
#include <stdio.h>
int main() {
char *demo = "demo";
fprintf(stdout, "string point: %p\n", demo);
demo = "Hello World";
fprintf(stdout, "string point: %p\n", demo);
return 0;
}
The two strings are located at different memory addresses.
string point: 0x55b2b9207004
string point: 0x55b2b920701b
Will this cause a waste of memory?
Do I need to use the free(void *ptr) function of stdlib.h to release it manually?
The standard function free() can only be used for pointers allocated by previous calls to malloc/calloc/realloc, and this is not the case. The strings in your program are allocated statically (probably in the read-only memory section of your program) or may be allocated on the stack.
The important thing to remember is that dynamic allocations (allocations on the heap) are always done explicitly by calling malloc() etc. either by you directly, or by a function indirectly (that calls malloc at some point). These dynamic pointers must always be freed when you're done using them.
I was a bit confused with the concept of char pointers so I made a simple code just printing my name provided by user (me). I also wanted to practice malloc so I referenced the pointer to a certain memory in RAM, but I really didn't know what to put after "sizeof(char) *" because that is the user input, which is not yet decided.
Also, after doing that, I freed the memory, but I got an error message on command line saying:
*** Error in `./char': double free or corruption (fasttop): 0x00000000017fe030 ***
Aborted
It seems like I freed the same memory twice or something, but I don't know what to delete or add. Please help!
#include <stdio.h>
#include <cs50.h>
int main (void)
{
char *strings = malloc(sizeof(char) * 10);
printf("What is your name?\n");
//wait for use to type his/her name
strings = get_string();
printf("Hello %s\n", strings);
free (strings);
return 0;
}
The line strings = get_string(); actually assigns the value returned by get_string() to strings. It doesn't write it into the memory you allocated.
So the value returne by malloc() has been overwritten (and lost in this case).
The free(strings) is releasing whatever get_string() returned. The question doesn't provide the code for that but presumably it isn't valid to free() it.
Because the run-time told you it was freed twice I'm guessing you have allocated memory in get_string() then freed it and returned an invalid pointer.
If you want to use the memory you allocated you need to change get_string() to accept a pointer:
void get_string(char *str){
//Do whatever writing you value into str[] as an array of char..
}
Good practice would have:
void get_string(char *str, size_t max){
//Do whatever writing you value into str[] as an array of char..
//Use max to avoid writing beyond the end of the space allocated...
}
Then call as get_string(strings,10);.
EDIT: After a bit of research the flaw has been identified. get_string() doesn't directly free() the string it returns but adds it to a list of allocations made by the library which are freed on exit (in a function called teardown() registered with atexit() or other compiler dependent features).
That is poor design because consumer code is provided no safe way of itself freeing the memory which in a typical use case will not be required for the whole application execution. get_double() is worse because it never returns the allocated data but never reuses it and amounts to a straight memory leak.
The code should either:
Conform to the documentation and require consumer code to free() the string (maybe rename it as say get_string_alloc() for clarity).
Offer a library routine to free the string (get_new_string() and release_string())
There is no very nice way to shift ownership of allocated memory in C but holding onto it for the remainder of execution is definitely not the answer.
Many libraries go round the houses to push allocation onto consumer code but that is onerous when the full size of the space required can't be known such as here.
I'd suggest putting _alloc() at the end of any function that returns objects that consumer code must later free().
So the answer for the question posed is remove the malloc() and the free() because the library handles both. However beware if your program makes many calls to that function and others that internally rely on it (like get_double()) you may run out of memory because the library is sitting on dead space.
The problem is your get_strings overrides your initial malloc. A pointer value is a value. By equating it with something else, you replaced your malloc value.
Memory is allocated at the statement:
strings = get_string();
You dont have to malloc it ( char *strings = malloc(sizeof(char) * 10);
)
Without malloc it will work fine
First You have created a dynamic memory which will be pointed by *strings. But then you are pointing to the local string (from get_string() function) using *strings pointer. when you call free, program is trying delete local (stack) reference and throwing error.
To solve that error, the program should be
#include <stdio.h>
#include <cs50.h>
int main (void)
{
char *strings = malloc(sizeof(char) * 10);
printf("What is your name?\n");
//wait for use to type his/her name
strcpy(strings, get_string()); // Use strcpy instead of assigning
printf("Hello %s\n", strings);
free (strings);
return 0;
}
You don't include the code for get_string(), but you're overwriting strings with its return value which is wrong. The address you pass to free() must come from malloc(), and it seems you're violating that (in addition to losing the original returned address for your 10 bytes).
Assuming get_string() returns static storage (i.e. you don't need to free it) you can do this without involving malloc().
If you really want to, something like this might work:
printf("What is your name?\n");
const char *name = get_string();
const size_t nlen = strlen(name);
char * const name_copy = malloc(nlen + 1);
if(name_copy != NULL)
{
memcpy(name_copy, name, nlen + 1);
printf("Hello %s (from my own memory!)\n", name_copy);
free(name_copy);
}
This is rather convoluted but you get the idea.
char *strings;
No need for new malloc as string returned from get_string() function is already on the heap, you just need to pick up pointer to first character. (get_string() function reference)
strings = get_string();
printf("Hello %s\n", strings);
After printing string you should free memory allocated for it, as it is stated in get_string() function reference
Stores string on heap (via malloc); memory must be freed by caller to
avoid leak.
I think everything else is fine, try this code:
#include <stdio.h>
#include <cs50.h>
int main (void)
{
char *strings;
printf("What is your name?\n");
//wait for use to type his/her name
strings = get_string();
printf("Hello %s\n", strings);
free (strings);
return 0;
}
Does strdup allocate another memory zone and create another pointer every time?
For example: does the following code result in a memory leak?
void x(char** d, char* s){
*d = strdup(s);
}
int main(){
char* test = NULL;
x(&test, "abcd");
x(&test, "etc");
return 0;
}
Yes, the program leaks memory because it allocates objects and then loses references to them.
The first time this happens is in the line:
x(&test, "etc");
The variable test holds the one and only copy of a pointer that was allocated in a previous call to x. The new call to x overwrites that pointer. At that point, the pointer leaks.
This is what it means to leak memory: to lose all references to an existing dynamically allocated piece of storage.*
The second leak occurs when the main function returns. At that point, the test variable is destroyed, and that variable holds the one and only copy of a pointer to a duplicate of the "etc" string.
Sometimes in C programs, we sometimes not care about leaks of this second type: memory that is not freed when the program terminates, but that is not allocated over and over again in a loop (so it doesn't cause a runaway memory growth problem).
If the program is ever integrated into another program (for instance as a shared library) where the original main function becomes a startup function that could be invoked repeatedly in the same program environment, both the leaks will turn into problems.
The POSIX strdup function behaves similarly to this:
char *strdup(const char *orig)
{
size_t bytes = strlen(orig) + 1;
char *copy = malloc(bytes);
if (copy != 0)
memcpy(copy, orig, bytes);
return copy;
}
Yes; it allocates new storage each time.
If you have a garbage collector (such as Boehm) in your C image, then it's possible that the leaked storage is recycled, and so strdup is able to re-use the same memory for the second allocation. (However, a garbage collector is not going to kick in after just one allocation, unless it is operated in a stress-test mode for flushing out bugs.)
Now if you want to actually reuse the memory with realloc, then you can change your x function along these lines:
#include <stdlib.h>
#include <string.h>
void *strealloc(char *origptr, char *strdata)
{
size_t nbytes = strlen(strdata) + 1;
char *newptr = (char *) realloc(origptr, nbytes); /* cast needed for C++ */
if (newptr)
memcpy(newptr, strdata, nbytes);
return newptr;
}
(By the way, external names starting with str are in an ISO C reserved namespace, but strealloc is too nice a name to refuse.)
Note that the interface is different. We do not pass in a pointer-to-pointer, but instead present a realloc-like interface. The caller can check the return value for null to detect an allocation error, without having the pointer inconveniently overwritten with null in that case.
The main function now looks like:
int main(void)
{
char *test = strealloc(NULL, "abcd");
test = strealloc(test, "etc");
free(test);
return 0;
}
Like before, there is no error checking. If the first strealloc were to fail, test is then null. That doesn't since it gets overwritten anyway, and the first argument of strealloc may be null.
Only one free is needed to plug the memory leak.
* It's possible to have a semantic memory leak with objects that the program hasn't lost a reference to. For instance, suppose that a program keeps adding information to a list which is never used for any purpose and just keeps growing.
Yes, it allocates memory and leaks if you don't free it. From the man page:
The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3).
new_s = strdup(s) is essentially equivalent to:
new_s = malloc(strlen(s)+1);
strcpy(new_s, s);
Consider the following definition for strdup:
#include <string.h>
char *strdup(const char *string);
strdup reserves storage space for a copy of string by calling malloc. The string argument to this function is expected to contain a null character (\0) marking the end of the string. Remember to free the storage reserved with the call to strdup.
You must free the string yourself.
Imagine this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTRSIZE 2048
int main()
{
char *str;
str = get_string();
return 0;
}
char * get_string()
{
char temp[MAXSTRSIZE], *str;
fgets(temp,MAXSTRSIZE,stdin);
str = malloc( sizeof(char) * (strlen(temp) + 1) );
strcpy(str, temp);
return str;
}
Do I need to free() the temp variable in function get_string?
What if did the get_string code inside the main()?
free call applies only for dynamically allocated memory and not for static memory allocations
so if there is anything allocated dynamically using malloc/calloc needs to be freed when ever the reference count to the specified memory block will reach to zero, on the other hand statically allocated memory must not be freed at all, the program itself I suppose will not have right to free the memory allocated statically
in case you try to free static memory compiler ideally throws a warning at compile time like below
warning: attempt to free a non-heap object
in case, where the warning is ignored will present a nice runtime crash at free
* glibc detected ./a.out: free(): invalid pointer:*
never attempt to free a non-heap object
The caller will need to make sure str is freed. temp was not dynamically allocated, so you cannot free it.
You must free() whatever you malloc(), it does not matter when or where but it must be happen to prevent a memory leak. When free() is called, the pointer must not be dereferenced again.
Note that get_string() must be declared or defined prior to main().
You do not need to (MUST NOT) free the temp variable, but you need to free str in your main (as it's malloced in get_string).