C: How to free memory after realloc for string arrays - c

I'm learning C and want to create a simple function which keeps track of a list of paths.
I start with a default path ["/bin/"] and have a function "change_paths" which updates this list based on some input, so for example ["/bin/"] -> ["/temp/", "/auxillary/"].
However, I encounter problems when I try to free my memory at the end. Specifically, fsanitize tells me that the 6 bytes from my default PATH paths[0] = malloc(6 * sizeof(char)); are not freed properly.
What should I do to correctly free this memory if I use change_paths arbitrarily many times with arbitrarily many inputs (including possibly 0 new PATHs)? Is this structure appropriate for storing data with this mechanism?
Note: I've edited this code for brevity, so even though the line "char** new_paths = {"/temp/", "/auxillary/"};" is not technically correct, please think of it as working. I just want to give an example and I'm not sure how to define a char** manually.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void change_paths(int *num_paths, char*** paths, int num_new_paths, char** new_paths){
*paths = realloc(*paths, num_new_paths * sizeof(char*));
for (int i = 0; i < num_new_paths; i++){
*paths[i] = malloc((strlen(new_paths[i]) + 1) * sizeof(char));
strcpy(*paths[i], new_paths[i]);
}
}
int main(int argc, char *argv[]){
// A Default PATH
char** paths = malloc(1 * sizeof(char*));
paths[0] = malloc(6 * sizeof(char)); // <- HOW TO FREE THIS AFTER REALLOC OF paths?
strcpy(paths[0], "/bin/");
int num_paths = 1;
// A new set of PATHs
int num_new_paths = 2;
char** new_paths = {"/temp/", "/auxillary/"};
change_paths(&num_paths, &paths, num_new_paths, new_paths);
// Free memory
for(int i = 0; i < num_new_paths; i++){
free(paths[i]);
}
free(paths);
return 0;
}

You need to keep track of the number of old path entries, and free each one before you overwrite the reallocated space with new path entries.
void change_paths(int *num_paths, char ***paths, int num_new_paths, char **new_paths)
{
for (int i = 0; i < *num_paths; i++)
free((*paths)[i]);
*paths = realloc(*paths, num_new_paths * sizeof((*paths)[0]));
for (int i = 0; i < num_new_paths; i++)
{
(*paths)[i] = malloc((strlen(new_paths[i]) + 1));
strcpy((*paths)[i], new_paths[i]);
}
*num_paths = num_new_paths;
}
Consider using strdup() in the second loop:
void change_paths(int *num_paths, char ***paths, int num_new_paths, char **new_paths)
{
for (int i = 0; i < *num_paths; i++)
free((*paths)[i]);
*paths = realloc(*paths, num_new_paths * sizeof((*paths)[0]));
for (int i = 0; i < num_new_paths; i++)
(*paths)[i] = strdup(new_paths[i]));
*num_paths = num_new_paths;
}
Also, don't forget to error check memory allocations and handle them appropriately. Note that the idiom:
old_space = realloc(old_space, new_size);
leaks memory if the reallocation fails. It is important to use:
void *new_space = realloc(old_space, new_size);
if (new_space == NULL)
…deal with error…
old_space = new_space;
That leads to this code:
void change_paths(int *num_paths, char ***paths, int num_new_paths, char **new_paths)
{
for (int i = 0; i < *num_paths; i++)
free((*paths)[i]);
*num_paths = 0; // In case realloc fails
void *new_space = realloc(*paths, num_new_paths * sizeof((*paths)[0]));
if (new_space == NULL)
return;
*paths = new_space;
for (int i = 0; i < *num_paths; i++)
free((*paths)[i]);
for (int i = 0; i < num_new_paths; i++)
(*paths)[i] = strdup(new_paths[i]));
*num_paths = num_new_paths;
}
Note that if strdup() fails, some of the entries in the array may be null pointers. You could use other error handling for failures in strdup().
Warning: no compiler was consulted about the validity of any of this code.

Related

My program crashes whenever i try to delocate the old memory

so basically there is a function that allocates a new pointer memory and when i try to delocate the old one the program basically crashes my code
char** AddingToTheBook(char** original, int* size, char *number)
{
char** newArray = (char**)malloc(sizeof(char*)*(*size));
//allocating and copying the values
for (int i = 0; i < *size; i++)
{
*(newArray + i) = (char*)malloc(sizeof(char)*(strlen(*(original + i))));
strcpy(*(newArray + i), *(original + i));
}
//allocating a new memory to the new number
*(newArray + (*size)) = (char*)malloc(sizeof(char)*strlen(number));
strcpy(*(newArray + (*size)), number);
(*size)++;
//delocating the allocated memories
for (int i = 0; i < size; i++)
free(original[i]);
free(original);
return newArray;
}
You are freeing too much of your original memory.
Look at the for loop when you're freeing the memory:
(*size)++;
//delocating the allocated memories
for (int i = 0; i < size; i++)
free(original[i]);
Since size is a int * you will end up with a very big number of iterations which will free to free much more memory than you allocated. To fix this do the following:
(*size)++;
//delocating the allocated memories
for (int i = 0; i < *size; i++)
free(original[i]);
Now you're still freeing one element too much since you've incremented *size when adding a new element. The final version to free the original memory is
(*size)++;
//delocating the allocated memories
for (int i = 0; i < *size - 1; i++)
free(original[i]);
strlen only returns the number of chars. Make room for the ending zero
*(newArray + i) = (char*)malloc(sizeof(char)*(strlen(*(original + i))) +1);
Better to strncpy instead of strcpy
How can you go *size ahead in newArray:
*(newArray + (*size)) = (char*)malloc(sizeof(char)*strlen(number));
You can only go *size -1 ahead, since it starts from zero.
In the for loop, it seems you forgot to add the asterisk *
for (int i = 0; i < size; i++)
You can use realloc instead
char** AddingToTheBook(char** original, size_t oldsize, char *number)
{
char** tmp = realloc(**original, (oldsize + 1) * sizeof(char *));
if(tmp)
{
tmp[oldsize] = malloc(strlen(number) + 1'
if(tmp[oldsize])
{
strcpy(tmp[oldsize], number);
}
else
{
/* do something for example realloc back to the old size */
tmp = NULL;
}
}
return tmp;
}
example correct usage
char **tmp = AddingToTheBook(book, size, "Test String")
if(tmp)
{
book = tmp;
size++;
}
else
{
/* do something adding to book failed */
}

Freeing malloc of unknown size

I'm trying to free the malloc that is generated with a not fixed number of arrays.
char ** get_moves(){
// some code
char **moves = malloc(sizeof(char *) * k); // 'k', could ranges between 1~9
if (!moves){
return NULL;
}
for(int i = 0; i < k; i++){
moves[i] = malloc(82);
if (!moves[i]) {
free (moves);
return NULL;
}
// more code
return moves;
}
int main(){
//some code
char **res = get_moves(some_input);
//more code
for (int i = 0; i < (sizeof(res)/sizeof(res[0)); i ++){
free(res[i]);
}
free(res);
}
In one of the inputs to get_move, res should have 2 arrays but the sizeof(res)/sizeof(res[0) gives me just 1.
How is the proper way to handle this?
The only way is to keep track of the element count of the array, if you don't want to pass it to every function when passing the array, you can combine both pieces of information in a struct, like here
#include <stdlib.h>
struct ArrayOfStrings
{
int count;
char **data;
};
struct ArrayOfStrings get_moves()
{
struct ArrayOfStrings result;
char **moves;
// some code
result.count = 0;
result.data = malloc(sizeof(char *) * k); // 'k', could ranges between 1~9
if (result.data == NULL)
return result;
result.count = k;
moves = result.data;
for (int i = 0; i < k; i++)
{
moves[i] = malloc(82);
if (moves[i] == NULL)
{
/* also free succesfully allocated ones */
for (int j = i - 1 ; j >= 0 ; --j)
free(moves[j]);
free(moves);
}
result.count = 0;
result.data = NULL;
return result;
}
// more code
return result;
}
int main(){
//some code
struct ArrayOfStrings res = get_moves(some_input);
//more code
for (int i = 0; i < res.count ; i ++)
free(res.data[i]);
free(res.data);
return 0; // you should return from main.
}
sizeof is not for the length of an object's content but for the size of a data type, it is computed at compile time.
So in your case
sizeof(res) / sizeof(res[0]) == sizeof(char **) / sizeof(char *) == 1
since sizeof(char **) == sizeof(char *) it's just the size of a pointer.
sizeof(res)
Returns the sizeof(double-pointer);
So if you intend to get the number of pointers stored then you might not get this by doing what you are doing.
You need to do something like
for(i=0;i<k;i++) /* As I see you are allocating k no of pointer Keep track of it*/
free(res[i]);
free(res);
res is in fact not an array of arrays of char type. Instead it is a pointer to pointer to char type. sizeof(res) will give you the size of char**. You need to keep track of the number of allocations.
Since the maximum number of arrays to allocate is small (9), you can simplify your code by allocating the maximum number. Fill the unused elements with NULL:
#define MAX_K 9
char **moves = malloc(sizeof(char *) * MAX_K);
for(int i = 0; i < k; i++){
...
}
for(int i = k; i < MAX_K; i++){
moves[i] = NULL;
}
To deallocate, just ignore the NULL pointers:
for (int i = 0; i < MAX_K; i ++){
if (res[i])
free(res[i]);
}
free(res);

memory allocation - call by reference String-Array-Paramater

The question is how to correctly allocate/free the memory in this example:
void test(char*** array, int* count) {
*array = malloc(sizeof(char*) * MAX_ARRAY);
while (...) {
(*array)[i] = (char*)malloc(strlen(fooString));
}
}
call of the function:
char** array;
int count;
test(&array, &count);
// now free the memory - i think i have to?
for(i = 0; i < count; i++) {
free(array[i]); // <-- crash here
}
free(array);
It looks like that array[0] has a different address inside the test-function than outside. How can this be? Looks like i misunderstood sth, because the address of array is the same outside and inside the function.
Edit: The Problem is that i am not able to free the allocated memory (see "crash here" in code). Why? And how will it work?
Instead of
void test(char*** array, int* count) {
*array = malloc(sizeof(char*) * MAX_ARRAY);
while (...) {
(*array)[i] = (char*)malloc(strlen(fooString));
}
}
do
void test(char*** array, int count) {
*array = malloc(sizeof(char*) * count); // number of pointers
for (int i = 0; i < count; ++i)
{
(*array)[i] = malloc(strlen(fooString));
}
}
although i am not sure about what fooString is since you don't show the decl/def. Normally you would allocate one byte extra for the \0
(*array)[i] = malloc(strlen(fooString) + 1)
this seems to work
#include <stdio.h>
#include <inttypes.h>
#include <malloc.h>
#include <string.h>
char fooString[256];
void test(char*** array, int count)
{
int i = 0;
*array = malloc(sizeof(char*) * count);
for (i = 0; i < count; ++i)
{
(*array)[i] = malloc(strlen(fooString)+1);
}
}
int main()
{
char** array = NULL;
int count = 100;
int i = 0;
test(&array, count);
for(i = 0; i < count;++i)
{
free(array[i]);
}
free(array);
return 0;
}
For your particular problem:
You allocate (*array)[i] which is a char* to strlen(fooString) which is usually equivalent to sizeof(char) * strlen(fooString) : this is error prone. You should use sizeof(*((*array)[i])) in this case to be sure not to miss the correct type.
To free it, loop from i = 0 to i < MAX_ARRAY and call free(array[i])
What you put in place of ... in your code is very important.
In general, when allocating memory, be sure to respect these general ideas:
If a functions allocates memory it frees it itself except when it is needed outside afterwards.
If a function allocates memory needed outside afterwards, it does just this.
This allows for better code architecture and easier freeing of the memory.
For example:
First point:
void foo()
{
char *a;
a = malloc(sizeof(*a) * 5);
a[0] = 'a';
a[1] = 'b';
a[2] = 'c';
a[3] = 'd';
a[4] = 0; //or '\0' if you prefer
do_something_cool(a);
free(a);
}
The function foo allocates memory, processes it, and frees it.
Second point:
char *halfstrdup(char *str)
{
int len;
int i;
char *newstr;
len = strlen(str);
newstr = malloc(sizeof(*newstr) * len / 2)
for (i = 0; i < len; i++)
{
if ((i % 2) == 0)
newstr[i / 2] = str[i];
}
return (newstr);
}
void foo2()
{
char *half;
half = halfstrdup("Hello, world !");
do_something_cooler(half);
free(half);
}
The function halfstrdup just allocates and sets the memory you need and returns it, the function foo2 allocates memory through the use of halfstrdup, then uses it and frees it.
Do not forget to free before losing track of your pointers, for example after returning from foo or foo2, you won't be able to free the allocated memory.

Passing Array By Reference To Function in C

I'm having a real difficult time getting this code to work. I'm trying to pass an array by reference to a function, in order to modify it in that function. Then I need the modifications to be handed back to the original caller function.
I have searched here for a similar problem, but couldn't find anything that can run successfully like the way I want to do it.
Here's my code, I would really appreciate any help. Thanks a lot:
#include <stdio.h>
#include <stdlib.h>
#define SIZE_OF_VALUES 5
#define SIZE_OF_STRING 100
void set_values(char **values);
void set_values(char **values)
{
*values = malloc(sizeof(char)*SIZE_OF_VALUES);
for (int i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++) {
values[i] = malloc(sizeof(char)*SIZE_OF_STRING);
values[i] = "Hello";
//puts(values[i]); //It works fine here.
}
}
int main (int argc, const char * argv[])
{
char *values;
set_values(&values);
for (int i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++) {
puts(values[i]); //It does not work!
}
return 0;
}
There are several problems with your code:
You should have three-level pointers - void set_values(char ***values), read it as a "a reference (first *) to an array (second *) of char* (third *)"
Each element in *values should be a pointer (char*) not char, so you need:
*values = malloc(sizeof(char*)*SIZE_OF_VALUES);
You are leaking memory, first mallocing then assigning literal, and additionally not dereferencing values, you need either:
(*values)[i] = "Hello";
or
(*values)[i] = strdup("Hello"); // you will have to free it later
or
(*values)[i] = malloc(sizeof(char)*SIZE_OF_STRING); // you will have to free this as well
strcpy((*values)[i], "Hello");
In your main, you should declare char **values; as it is a pointer to an array of char* (character string/array).
In you loop you are incorrectly multiplying indices by sizeof, index is counted in elements not in bytes. Thus, you need:
for (int i = 0; i < SIZE_OF_VALUES; i++)
Don't forget to free the memory at the end.
Use a char *** type for your parameter of your set_values function:
#include <stdio.h>
#include <stdlib.h>
#define SIZE_OF_VALUES 5
void set_values(char ***values)
{
*values = malloc(sizeof (char *) * SIZE_OF_VALUES);
for (int i = 0; i < SIZE_OF_VALUES; i++) {
(*values)[i] = "Hello";
}
}
int main (int argc, char *argv[])
{
char **values;
set_values(&values);
for (int i = 0; i < SIZE_OF_VALUES; i++) {
puts(values[i]);
}
return 0;
}
Of course you have to check for malloc return value and free allocated memory before exit of main.
Here is the solution.
void set_values(char ***values)
{
int i;
char ** val;
val = *values = (char**)malloc(sizeof(char*)*SIZE_OF_VALUES);
for (i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++)
val[i] = "Hello";
}
int main (int argc, const char * argv[])
{
char **values;
int i;
set_values(&values);
for (i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++)
puts(values[i]);
return 0;
}
char * is a one dimensional array of char. but you want your code in set_values sets values to a two dimensional array.
In order to make this work, define:
values as char **values;
set_values as void set_values(char ***values)
allocate the pointers for the char arrays as:
*values = malloc(sizeof(char*)*SIZE_OF_VALUES);
Besides that your loop is a bit strange:
for (int i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++) {
should be replaced with
for (int i = 0; i < SIZE_OF_VALUES; i++) {
and finally, if you want to copy a string into your now allocated array use
strncpy((*values)[i], "Hello", SIZE_OF_STRING-1);
(*values)[i][SIZE_OF_STRING-1] = '\0';
so in total:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_OF_VALUES 5
#define SIZE_OF_STRING 100
void set_values(char ***values);
void set_values(char ***values)
{
const char * content = "Hello";
*values = malloc(sizeof(char*)*SIZE_OF_VALUES);
for (int i = 0; i < SIZE_OF_VALUES; i++) {
(*values)[i] = malloc(sizeof(char)*SIZE_OF_STRING);
strncpy((*values)[i], content, SIZE_OF_STRING-1);
(*values)[i][SIZE_OF_STRING-1] = '\0';
if(strlen(content) >= SIZE_OF_STRING){
fprintf(stderr,"Warning content string did not fit into buffer!\n");
}
}
}
int main (int argc, const char * argv[])
{
char **values;
set_values(&values);
for (int i = 0; i < SIZE_OF_VALUES; i++) {
printf("%s\n", values[i]);
}
for (int i = 0; i < SIZE_OF_VALUES; i++) {
free(values[i]);
}
free(values);
return 0;
}
You have an extra * in this line:
*values = malloc(sizeof(char)*SIZE_OF_VALUES);
Which should be:
values = malloc(sizeof(char)*SIZE_OF_VALUES);
Also you have considerable problem in your main, char* values should be char** values, passing your char* values by reference (set_values(&values);) may cause segmentation fault I suspect.
For affecting the outer array, it's already being affected because when passing to the function you are only copying a pointer that points to the same place, so the modifications will affect the same memory blocks.

C memory leak despite free

In debugging my program with Valgrind, I have discovered a memory leak despite what I thought were effective calls to free. First, the code that is allocating the memory and storing it:
row = malloc(sizeof(Row));
row->columns = malloc(sizeof(char*) * headcnt);
row->numcol = 0;
...
row->numcol = colcnt;
rows = realloc(rows, (rowcnt+1) * sizeof(Row));
rows[rowcnt++] = *row;
The code responsible for attempting to free the memory:
void cleanUp(){
int i = 0;
int j = 0;
for (i = 0; i < rowcnt; i++){
for (j = 0; j < rows[i].numcols; j++){
free(rows[i].columns[j]);
}
free(&rows[i]);
}
free(rows);
exit(0);
}
The declaration of Row:
typedef struct {
char** columns;
unsigned short int numcol;
} Row;
Row* rows = NULL;
Worse still, this program sometimes causes a glibc error at free(&rows[i]) that complains of a double free. I am new to C, and would appreciate any pointers (ahem) someone might have.
Doing rows[rowcnt++] = *row; effectively makes a copy of the memory you allocated. Your array rows should be an array of pointers. Also like Oli Chalesworth pointed out, you free for columns should be a single free for all the columns.
rows = malloc(count * sizeof(Row*)); // This is probably done somewhere
row->columns = malloc(sizeof(char*) * headcnt);
row->numcol = 0;
...
row->numcol = colcnt;
rows = realloc(rows, (rowcnt+1) * sizeof(Row*));
rows[rowcnt++] = row;
Now if your cleanup
void cleanUp(){
int i = 0;
int j = 0;
for (i = 0; i < rowcnt; i++){
free(rows[i]->columns);
}
free(rows);
exit(0);
}
Every call to malloc (or realloc) must be matched with a corresponding call to free. If you dynamically allocate an array thus:
int *p = malloc(sizeof(int) * NUM);
You free it like this:
free(p);
Not like this:
for (int i = 0; i < NUM; i++)
{
free(p[i]);
}
It appears that you are doing this incorrectly. I suspect that your cleanup code ought to be:
void cleanUp(){
int i = 0;
int j = 0;
for (i = 0; i < rowcnt; i++){
for (j = 0; j < rows[i].numcols; j++){
free(rows[i].columns[j]); // Free whatever rows[i].columns[j] points to
}
free(rows[i].columns); // Matches row->columns = malloc(sizeof(char*) * headcnt);
}
free(rows); // Matches rows = realloc(rows, (rowcnt+1) * sizeof(Row));
exit(0);
}
Also, there is no way to match the row = malloc(sizeof(Row));. I suspect that your allocation code ought to be:
row->numcol = colcnt;
rows = realloc(rows, (rowcnt+1) * sizeof(Row));
rows[rowcnt].columns = malloc(sizeof(char*) * headcnt);
rows[rowcnt].numcol = 0;
rowcnt++;
Maybe I'm being dense, but isn't this totally unnecessary? All of your memory will be released as soon as the program exits, anyway.

Resources