I feel that working with dynamically-typed languages has fried my intuition about this!
Say if I malloc space for a string and then update that pointer with another malloc (which uses the data from the first), is that a memory leak?
char* my_string = (char*)malloc(length + 1);
(void)snprintf(my_string, length, "blah...");
my_string = some_manipulation(my_string);
Where we have char* some_manipulation(const char* str); assigning memory for its output, which is generated from the provided argument (and may not be the same length).
Is the first malloc now lost, but occupying space, until exit?
Say if I malloc space for a string and then update that pointer with another malloc (which uses the data from the first), is that a memory leak?
Yes, if you do not store the 1st value of string, before overwriting it by the 2nd call to malloc().
Leaking code
char * p = malloc(42);
p = malloc(41);
/* here the program leaks 42 bytes. */
You can only free() the 41 bytes of the 2nd call
free(p);
as the reference to the 42 bytes block is lost.
Non-leaking code
char * p = malloc(42);
char * q = p;
p = malloc(41);
Here you have no leak, as you still can do:
free(p); /* Frees 41 bytes. */
free(q); /* Frees 42 bytes */
which uses the data from the first
All of this does not depend at all on what had been stored (or not) in the memory allocated.
Yes, of course. You seem to think about your string here as an immutable object which is a nice concept, but doesn't leverage you from freeing the memory occupied.
If you know that the call to your function conceptionally invalidates the input string (so, no caller would ever need it again after calling the function), you could instead do something like this:
int some_manipulation(char **str)
{
char *ret = malloc(...);
/* handle error, return -1 */
/* do whatever manipulation */
free(*str);
*str = ret;
return 0;
}
If you have two malloc calls and one free on the same pointer, you almost certainly have a leak (short of the first malloc failing).
Every successful malloc should have an associated free somewhere at the end of the life of the pointer.
Leak:
foo* bar = NULL;
bar = malloc(sizeof(foo) * 10);
if (bar) {
bar = malloc(sizeof(foo) * 20);
}
else {
fprintf(stderr, "Error: Could not allocate memory to bar\n");
exit(EXIT_FAILURE);
}
free(bar);
bar = NULL;
No leak:
foo* bar = NULL;
bar = malloc(sizeof(foo) * 10);
if (bar) {
free(bar);
bar = NULL;
}
else {
fprintf(stderr, "Error: Could not allocate memory to bar\n");
exit(EXIT_FAILURE);
}
bar = malloc(sizeof(foo) * 20);
if (bar) {
free(bar);
bar = NULL;
}
else {
fprintf(stderr, "Error: Could not allocate memory to bar\n");
exit(EXIT_FAILURE);
}
Related
I wanted to know what happens in this piece of code?
Here, I have a variable f2 in func2 where it is allotted a block of space via malloc and a variable f1 in func1 which is also allotted a block of space via malloc.
#include <stdio.h>
#include <stdlib.h>
char* func2(){
char *f2 = (char *)malloc (sizeof(char) * 10);
f2[0] = '1';
f2[1] = '2';
f2[2] = '3';
f2[3] = '\0';
return f2;
}
char* func1(){
char *f1 = (char *)malloc (sizeof(char) * 10);
f1 = func2();
return f1;
}
int main()
{
printf("String: %s", func1());
return 0;
}
Now, since I have allotted a heap memory in func2, and func1 is calling it, then func1 should free that memory. But I am allocating the returned value to one of func1's local variable f1 and would return that variable to main function I can't delete it in func1.
So, how will I free the memory that was allocated in func2.
Is the heap memory space for f1 in func1 and f2 in func2 the same?
If you expect func1 to free anything, it should call free:
char *
func1(void)
{
char *f1 = malloc (sizeof *f1 * 10);
free(f1);
f1 = func2();
return f1;
}
If you do not explicitly free the memory, then you have a memory leak, since overwriting f1 with the result of func2 discards the previous value of f1 and your program no longer knows the value of the address that was previously allocated, so you will not be able to free it.
There is no relationship between the values returned by malloc. Consider:
int x = 5;
x = 7;
What happened to the 5? It got discarded. There is nothing magical about an address returned by malloc. If you assign a different value to f1, the previous value is discarded.
When you malloc a chunk of memory, that chunk of memory stays there until you explicitly call free on it. malloc returns a pointer to that chunk of memory, and if you overwrite the pointer with a pointer to a different chunk of memory, it doesn't get rid of the first chunk of memory. You can either free the old f1 in func1 like William Pursell suggested, or you could just not allocate a second chunk of memory in the first place, since allocating more unused memory does nothing:
char* func1() {
char* f1 = func2();
return f1;
}
As a side note, you should never cast the result of malloc.
First of all, I'm sorry for my bad English.
I have a question about 'realloc' function in language C.
I thought it allocates memories with given length.
When the memories ain't enough for the given length, it copies whole memories to another memory pointer and returns it.
I wanted to use realloc function with preserving the old memories.
So I sentenced another pointer and made it pointing at the old memories.
But whenever 'realloc' function works, it frees the old memories.
How can I preserve old memories?
In addition, I want to know why this is happenend.
the below is code and its result I've used for testing realloc function.
#include <stdio.h>
#include <stdlib.h>
int* ptr1, lenPtr1;
int* ptr2;
void double_ptr1(){
lenPtr1 *= 2;
ptr1 = (int*)realloc(ptr1, sizeof(int) * lenPtr1);
}
void print(){
printf("ptr1 -> %p, *ptr1 = %d\n", ptr1, *ptr1);
printf("ptr2 -> %p, *ptr2 = %d\n", ptr2, *ptr2);
printf("\n");
}
int main(){
lenPtr1 = 10;
ptr1 = (int*)malloc(sizeof(int) * lenPtr1);
ptr2 = ptr1;
*ptr1 = 10;
print();
double_ptr1();
print();
system("pause");
return 0;
}
ptr1 -> 0108D2F0, *ptr1 = 10
ptr2 -> 0108D2F0, *ptr2 = 10
ptr1 -> 00FF5740, *ptr1 = 10
ptr2 -> 0108D2F0, *ptr2 = -17891602
An example incorporating all improvements suggested in the comments and avoiding the use of global variables, and freeing all allocated memory before the program exits. There is only a need to hold the terminal window open on windows, so conditionally enclose the system("pause");.
Putting it altogether, you would have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *double_ptr (int *ptr, int *ptrsz) /* pass needed information as parameters */
{
int *newptr = malloc (2 * *ptrsz * sizeof *newptr); /* allocate new block of mem */
if (newptr) { /* validate allocation */
memcpy (newptr, ptr, *ptrsz * sizeof *ptr); /* copy to new block of mem */
*ptrsz *= 2; /* update allocated size */
}
return newptr; /* return pointer */
}
void print (int *ptr1, int *ptr2) /* pass needed information as parameters */
{
/* only one call to printf required */
printf ("ptr1 -> %p, *ptr1 = %d\nptr2 -> %p, *ptr2 = %d\n\n",
(void*)ptr1, *ptr1, (void*)ptr2, *ptr2);
}
int main (void) {
int *ptr1 = NULL, *ptr2 = NULL, lenPtr1 = 10; /* avoid global variables */
if (!(ptr1 = malloc (lenPtr1 * sizeof *ptr1))) { /* validate EVERY allocation */
perror ("malloc-ptr");
return 1;
}
ptr2 = ptr1; /* pointer 1 and 2 hold same address where 10 is stored in memory */
*ptr1 = 10;
printf ("lenPtr1: %d\n", lenPtr1); /* output len, addresses, values */
print (ptr1, ptr2);
if (!(ptr1 = double_ptr (ptr1, &lenPtr1))) { /* double size of ptr1 */
perror ("malloc-double-ptr1");
return 1;
}
printf ("lenPtr1: %d\n", lenPtr1); /* output len, addresses, values */
print (ptr1, ptr2);
free (ptr1); /* free allcoated memory */
free (ptr2);
#if defined (_WIN32) || defined (_WIN64)
system("pause");
#endif
}
Example Use/Output
$ ./bin/doubleptrsz
lenPtr1: 10
ptr1 -> 0xb18260, *ptr1 = 10
ptr2 -> 0xb18260, *ptr2 = 10
lenPtr1: 20
ptr1 -> 0xb186a0, *ptr1 = 10
ptr2 -> 0xb18260, *ptr2 = 10
Let me know if you have further questions.
When you realloc the original pointer, which is pointed by ptr2, the address of the original pointer is removed.
So after you realloc the ptr1, ptr2 points address that does not exists anymore.
If you want to preserve old memory, then you just need to malloc(or calloc) new memory to ptr1 with no realloc original one.
When the memories ain't enough for the given length, it copies whole memories to another memory pointer and returns it.
Not quite. realloc always deallocates the old memory. It may return the same pointer.
From C11 7.20.3.4 realloc...
The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size.... The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object)
I wanted to use realloc function with preserving the old memories.
You can't.
If you need more memory, malloc a new hunk of memory instead of reallocing the old one.
If you want to shrink memory, continue to use the memory as is. It'll work fine, it's just a waste of memory.
I'd recommend neither. Instead, redesign whatever you're doing so the pointer is accessed indirectly. Perhaps using a pointer to a pointer. Or put the pointer inside a struct and pass around a pointer to the struct.
Alternatively, redesign it so you do not need to realloc. For example, when reading from a file use a fixed size buffer to read the line and then copy that to memory with exactly enough space.
// A large buffer to reuse for each line.
char buf[BUFSIZ];
while( fgets(buf, sizeof(buf), fp) ) {
// Allocate exactly enough space for the line.
// In reality, use strdup.
char *string = malloc(strlen(buf) + 1);
strcpy(string, buf);
}
Or change to a data structure which does not rely on a single block of memory. For example, a linked list instead of an array.
In addition, I want to know why this is happened.
There are many implementations of malloc, but they all must allocate contiguous blocks of memory with no overlap.
Consider two calls to malloc.
char *foo = malloc(8);
char *bar = malloc(8);
And let's say foo and bar are allocated adjacent blocks of memory like so. (Note: there's no guarantee they will be adjacent and many reasons why they shouldn't be.)
0123456789abcdef0123456789abcdef
^^^^^^^^
| ^^^^^^^^
foo |
bar
Now you try to grow foo.
foo = realloc(foo, 16);
If realloc tries to keep the same pointer, foo would have to overlap into bar's memory.
0123456789abcdef0123456789abcdef
^^^^^^^^^^^^^^^^
| ^^^^^^^^
foo |
bar
That's not allowed, allocations cannot overlap. They also must be contiguous, so it cannot do this:
0123456789abcdef0123456789abcdef
^^^^^^^^ ^^^^^^^^
| ^^^^^^^^
foo |
bar
If it were allowed to do that, pointer math would not work. You would not be able to reliably add to foo to walk through its allocated memory.
So realloc must free foo and allocate a new block. (Again, no guarantee where it will be allocated.)
0123456789abcdef0123456789abcdef
^^^^^^^^
| ^^^^^^^^^^^^^^^^
bar |
foo
I know this has been asked quite a bit, but every example I looked at never seemed to fit exactly. In the code below if I keep the free(), the resulting compiled binary segfaults. If I remove it, the code works just fine. My question is, why?
int convertTimeToStr(time_t* seconds, char* str)
{
int rc = 0;
if (str == NULL) {
printf("The passed in char array was null!\n");
rc = 1;
} else {
char* buf = malloc(sizeof(char) * 100);
memset(buf, '\0', sizeof(buf));
buf = asctime(gmtime(seconds));
strcpy(str, buf);
free(buf);
}
return rc;
}
The problem is that you reassign the pointer to your allocated memory. What you're doing is basically equivalent to
int a = 5;
int b = 10;
a = b;
and then wondering why a is no longer equal to 5.
With the assignment buf = asctime(gmtime(seconds)) you lose the original pointer and have a memory leak.
What the asctime function returns is a pointer to a static internal buffer, it's not something you should pass to free.
You should not be surprised by that, since you've changed the value of the pointer buf from what malloc() returned.
char* buf = malloc(sizeof(char) * 100); // value returned by malloc()
memset(buf, '\0', sizeof(buf));
buf = asctime(gmtime(seconds)); // change value of buf
strcpy(str, buf);
free(buf); // buf differs from above
Calling free() with an argument that was not returned from malloc() (or calling it for the second time) is undefined behaviour.
You call malloc and memset, which allocates a buffer and sets it to zeroes, but then you overwrite the value of buf with the return value from asctime. By the time you call free, it is on the return value from asctime, not your original allocation. This has three issues:
You never use the buffer you allocated with malloc for any useful purpose, so you don't need that malloc nor the memset
You lose the pointer returned by malloc so you can never free it. Your process has leaked memory.
You try to free the return value from asctime. The return value from asctime does not need to be freed and should not be freed. This causes undefined behavior, in your case a segfault.
I've some trouble understanding how to free my memory correctly in following codesnippet:
char *func(char* s){
/* do something with s */
// pass s to function, create new string, return this string
s = function_allocating_mem(s);
// pass s to function, create new string, return this string
s = other_function_allocation_mem(s);
/* do other stuff again */
return s;
}
int main(void){
char str[] = "somestring";
str = func(str);
}
Now I allocated different sizes of memory two times. But if I get it right, I just change the pointer address and never free the memory.
I don't really know, what to google to find an example
Is that correct and how would I change it?
EDIT:
I removed the second parameter of the function. It was not necessary and confusing.
When you allocate memory from the heap in your program, you have to have a clear understanding of:
Where memory from heap is allocated in your program.
How the ownership of heap allocated memory is transferred from one function to the next, and
Where it is deallocated before the program ends.
In your case, assuming function_allocating_mem and other_function_allocation_mem don't call free on the input argument, you have to make sure that the memory allocated in those functions is deallocated in either fun or main.
char *func(char* s, const char* os){
char* s1 = NULL;
char* s2 = NULL;
/* do something with s and os */
// pass s to function, create new string, return this string
s1 = function_allocating_mem(s);
// pass s to function, create new string, return this string
s2 = other_function_allocation_mem(s1);
/* do other stuff again */
// Deallocate memory that was allocated by function_allocating_mem().
free(s1);
// Memmory allocated by other_function_allocation_mem is returned to the
// calling function.
return s2;
}
int main(void){
char str[] = "somestring";
// This is not legal anyway.
// str = func(str, "some other string");
char* s = fun(str);
// Use s ...
// Before returning from this function, deallocate memory
// that was allocated in the call to fun().
free(s);
}
In code You've provided, correct way to free memory would be:
char *s2;
s2 = other_function_allocation_mem(s);
free( s );
s = s2;
...
free( s );
return ns;
So many problems.
1. You declared that func takes two parameters. Then you only called it with one param.
2. You declared that func returns a char*, then you try to assign that to a char[].Arrays and pointers are related, but they are not interchangable.
3. In func, you never use param os.
4. You return variable ns. It was never declared.
Here is my situation:
main allocates memory based on string and calls function by passing an address. The function then appropriately resizes the passed memory to accommodate more data. After which when I try to release the memory I get heap error.
Here is the code:
typedef char * string;
typedef string * stringRef;
/**************************
main
**************************/
int main()
{
string input = "Mary had";
string decoded_output = (string)calloc(strlen(input), sizeof(char));
sprintf(decoded_output, "%s", input);
gen_binary_string(input, &decoded_output);
free(decoded_output); /*this causes issue*/
return 0;
}
void gen_binary_string(string input,stringRef output)
{
int i=0, t=0;
size_t max_chars = strlen(input);
/*
the array has to hold total_chars * 8bits/char.
e.g. if input is Mary => array size 4*8=32 + 1 (+1 for \0)
*/
string binary_string = (string)calloc((BINARY_MAX*max_chars) + 1, sizeof(char));
int offset = 0;
/* for each character in input string */
while (*(input+i))
{
/* do some binary stuff... */
}
/* null terminator */
binary_string[BINARY_MAX*max_chars] = '\0';
int newLen = strlen(binary_string);
string new_output = (string) realloc((*output), newLen);
if (new_output == NULL)
{
printf("FATAL: error in realloc!\n");
free(binary_string);
return;
}
strcpy(new_output, binary_string);
(*output) = new_output;
free(binary_string);
}
You may be misunderstanding the purpose of realloc. Calling realloc will not necessarily return a newly allocated object. If possible, it will return the same object, extended to hold more bytes. Also, it automatically copies the object's contents. Theferore: (1) you should not copy and (2) you should not free the old buffer.
The realloc() function changes the size of the memory block pointed
to by ptr to size bytes. The contents will be unchanged in the range
from the start of the region up to the minimum of the old and new
sizes... (snip) Unless ptr is NULL, it must have been returned by an
earlier call to malloc(), calloc() or realloc(). If the area
pointed to was moved, a free(ptr) is done.
After a better reading of your code, I don't understand why you're using realloc at all here, as you're not using the old contents of output. You'd get the same behaviour (and the same error) if you replaced realloc with malloc. I think your real problem is that you're not allocating enough bytes: you should have strlen(binary_string) + 1 to accommodate the '\0' at the end of the string.
A better option would be to pass in a char** from the caller, let the callee allocate the char* and then pass back the pointer at the end of the function.
This prevents the need for two allocations and one free (always a bad sign).