Please help me understand this:
I have a pointer to a pointer
char** word_array = NULL;
Then I dynamically allocate memory in my code:
n = 6;
word_array = (char *) malloc(n* sizeof(char*));
How do I delete all the memory allocated for the "array" of pointers? Is this call to free right?
free(word_array);
Or should I make a loop:
for(int i = 0 ; i < n; i++) free(word_array + i);
You used one malloc, so you should use one free.
Also the cast to char* is nonsense: word_array has type char**, not char*, and casting result of malloc() is discouraged.
So the entire flow will be like this:
int n;
char** word_array = NULL;
n = 6;
word_array = malloc(n* sizeof(char*));
if (word_array == NULL) {
/* handle allocation error */
} else {
/* do some work with word_array */
/* free pointers stored in word_array if they are dynamically allocated
and not freed yet */
free(word_array);
}
Related
I have a 2d pointer array:
char **fields = calloc(1, sizeof(char *));
I add to it different strings, like this:
if(i > 0) fields = realloc(fields, (i+1) * sizeof(char *));
fields[i] = calloc(size, sizeof(char));
I then use memcpy into the fields[i] the desired string.
At the end of the program, when I try to free fields, I do it like this:
int j=0
while(fields != NULL && fields[j]){
free(fields[j]);
j++;
}
free(fields);
The program inserts 4 strings into fields.
The first string frees as expected, however on the second iteration of the loop (j=1) the program stops and outputs the error: free(): invalid pointer
EDIT: I made a short program with the same problem:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
char **fields = calloc(1, sizeof(char *));
int fieldsIndex = 0,i=0;
while (i<4) {
if(fieldsIndex > 0){
fields = realloc(fields, (fieldsIndex + 1) * sizeof(char *));
fields[fieldsIndex] =NULL;
printf("amount of field places: %d\n", (fieldsIndex + 1));
}
fields[fieldsIndex] = calloc(8, sizeof(char));
fields[fieldsIndex] = "88888888";
fieldsIndex++;
i++;
}
int j=0;
for(j=0; j<i; j++){
printf("field: %s\n", fields[j]);
free(fields[j]);
}
free(fields);
return 0;
}
Can anyone help?
Addressing mainly the MRE.
The main problems are around this line:
fields[fieldsIndex] = "88888888";
It's not right for two reasons:
Firstly you need one more element in the array for the null byte.
Secondly, you make the fields[fieldsIndex] pointers point to string literals, it not only causes a memory leak, but also those string literals are usually stored in a readonly section of memory, either way the behavior freeing a pointer pointing to a string literal is undefined.
You need to copy the strings to the memory you just allocated. Using memcpy should work as long as you reserve enough memory as mentioned in the previous point, a cleaner way would be to use strdup.
Another issue is if(fieldsIndex > 0) because then fields[0] will not have allocated memory.
Some other notes, if you know the amount of strings (i < 4) you shouldn't need to realloc, just allocate space for all the pointers in the first calloc* (assuming that is not brought about by the construction of the MRE) , also i and fieldsIndex seem to be redundant.
Here is a demo keeping realloc (as it's tangential to the OP):
int main()
{
char **fields = NULL;
char **tempfields; // I advise the use of an auxiliary pointer for reallocation
int fieldsIndex = 0;
while (fieldsIndex < 4)
{
tempfields = realloc(fields, (fieldsIndex + 1) * sizeof *fields); //*
if (!tempfields)
{
// handle the allocation error appropriately
}
fields = tempfields;
printf("amount of field places: %d\n", (fieldsIndex + 1));
fields[fieldsIndex] = strdup("88888888");
// Or
// fields[fieldsIndex] = calloc(9, sizeof **fields); // check return
// strcpy(fields[fieldsIndex], "88888888");
fieldsIndex++;
}
// With int iterator
int j = 0;
for (j = 0; j < fieldsIndex; j++)
{
printf("field: %s\n", fields[j]);
free(fields[j]);
}
free(fields);
}
Or with a sentinel element in fields:
Live demo
// With sentinel
tempfields = realloc(fields, (fieldsIndex + 1) * sizeof *fields);
if (!tempfields)
{
// handle the allocation error appropriately
}
fields = tempfields;
fields[fieldsIndex] = NULL;
while (*fields)
{
printf("field: %s\n", *fields);
free(*fields);
fields++;
}
free(tempfields);
So, my goal was to define a struct in which there is -
A command name (e.g. - "print")
Command arguments counter
A strings array containing the arguments.
You can review my code, but I'm really having a hard time understanding what am I doing wrong -
I use malloc to dynamically set my_struct.command size
I use malloc to dynamically set my_struct.arguments array size
I use realloc to dynamically increase my_struct.arguments size for every argument I set
I use malloc to dynamically set my_struct.arguments[i] size
I finally call cleanup(), to free any dynamically assigned pointers.
I keep getting LOTS of memory leaks. But I cannot understand why.
Help and tips will be kindly appreciated.
#include <stdio.h>
#include <stdlib.h>
struct {
char *command;
int arguments_count;
char **arguments;
} my_struct;
void cleanup(void);
int main() {
int i;
my_struct.command = (char *)malloc(6*sizeof(char));
my_struct.command = "print";
my_struct.arguments_count = 1;
my_struct.arguments = (char **)malloc(sizeof(char *));
my_struct.arguments[0] = "hello";
for(i = 1 ; i < 10; i++) {
my_struct.arguments = (char **)realloc(my_struct.arguments, sizeof(char *)*(i+1));
my_struct.arguments[i] = (char *)malloc(8*sizeof(char));
my_struct.arguments[i] = "hello";
my_struct.arguments_count++;
}
printf("Arguments count is: %d\n", my_struct.arguments_count);
printf("The arguments are:\n");
for(i = 0; i < 10; i++) {
printf("%s\n", my_struct.arguments[i]);
}
cleanup();
exit(0);
}
void cleanup(void) {
int i;
for(i = 0; i < 10; i++)
free(my_struct.arguments[i]);
free(my_struct.arguments);
free(my_struct.command);
}
strdup - 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, and can be freed with free.
my_struct.command = strdup("print");
my_struct.arguments_count = 1;
my_struct.arguments = (char**) malloc(sizeof(char*));
my_struct.arguments[0] = strdup("hello");
for (int i=1; i < 10; ++i) {
// if the number of args is known, allocate before entering the loop
my_struct.arguments = (char**) realloc(my_struct.arguments, sizeof(char*)*(i+1));
my_struct.arguments[i] = strdup("hello");
my_struct.arguments_count++;
}
// in your cleanup use the arguments_count var instead of the literal 10
for (int i=0; i < my_struct.arguments_count; ++i)
Your mistake was:
// allocate a memory block of 6 bytes
// assign the address of that block to command
my_struct.command = malloc(6);
// then you assigned the address of the string 'print' to command
// therefore the previous allocated block is lost -> mem leak
my_struct.command = "print";
// strdup does the following
return memcpy(malloc(strlen(str) + 1), str, strlen(str) + 1);
im looking to understand why this script dont completly free his memory allocation.
The windows memory used chart drop just a little from these about 400Mb total allocated.
All the memory are free with an array of int, but not with an array of char*
How to do it right ? many thanks for your help...
void testAlloc() {
unsigned char error = 0;
char **arr;
char **buf;
size_t size = 1;
size_t idx = 0;
size_t nextIdx;
size_t newSize;
arr = calloc(size, sizeof(char*));
while(idx < 9999999) {
nextIdx = idx+1;
newSize = nextIdx*2;
if(nextIdx > size) {
buf = realloc(arr, newSize * sizeof(char*));
if(buf != NULL) {
arr = buf;
size = newSize;
}else{
error = 1;
}
}
if(!error) {
arr[idx] = calloc(32, sizeof(char));
arr[idx] = "sample text";
}
idx++;
}
MessageBox(NULL, "stop before free", "", MB_OK);
size_t i = 0;
if(!error && arr != NULL) {
while(i < idx) {
free(arr[i]);
i++;
}
free(arr);
arr = NULL;
}
}
testAlloc();
Here:
arr[idx] = calloc(32, sizeof(char));
arr[idx] = "sample text";
You are allocating 32 bytes of memory and storing a pointer to them in arr[idx], then you are overwriting that pointer with a pointer to the array represented by the string literal. The dynamic allocation is leaked. Furthermore, you invoke undefined behavior later when you attempt to free the space pointed to by the array element, because the pointer then stored in the array was not obtained from any of the allocation functions.
Presumably, you wanted to copy the contents of the string into the allocated space, instead of overwriting the pointer to the space. For that, you want strcpy().
arr[idx] = calloc(32, sizeof(char));
// Note: an error check really ought to be performed here
strcpy(arr[idx], "sample text");
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
void createDynamicArrayForChar(int dimension, char **ptr)
{
ptr = (char**)malloc(dimension*sizeof(char*));
for (int i = 0; i < dimension; i++)
{
ptr[i] = (char*)malloc(20 * sizeof(char));
ptr[i] = "value";
}
}
int main()
{
char **ptrArray;
createDynamicArrayForChar(5, ptrArray);
printf("%s", ptrArray[3]);
getchar(); getchar();
return 0;
}
It gives some errors when I try to compile this codes. How can I solve this problem? How to send 2D char pointer to a function in C?
Firstly, as per the present code, I see two issues.
You're passing ptrArray to the function and trying to allocate memory inside the function. Please be aware, C uses pass by value for function argument passing, so, if you want to allocate memory to ptrArray and expect that to be refeclted back to the caller, without returning, you'll be needing to pass a pointer to that `ptrArray.
in the code
ptr[i] = (char*)malloc(20 * sizeof(char));
ptr[i] = "value";
You're leaking memory. Once you've allocated memory using malloc(), you should use strcpy() to copy the data into the allocated memory.
That said, some advice:
Please see why not to cast the return value of malloc() and family in C.
sizeof(char) is guaranteed to be 1 in C. Using that as a multiplier is not required.
Always check the success of malloc() before using the returned pointer.
You probably need this (no error checking and not debugged code):
void createDynamicArrayForChar(int dimension, char ***ptr)
{
*ptr = (char**)malloc(dimension*sizeof(char*));
for (int i = 0; i < dimension; i++)
{
(*ptr)[i] = (char*)malloc(20 * sizeof(char));
strcpy((*ptr)[i],"value");
}
}
or
char **createDynamicArrayForChar(int dimension)
{
char **ptr = (char**)malloc(dimension*sizeof(char*));
for (int i = 0; i < dimension; i++)
{
ptr[i] = (char*)malloc(20 * sizeof(char));
strcpy(ptr[i],"value");
}
return ptr;
}
int main()
{
char **ptrArray;
ptrArray = createDynamicArrayForChar(5);
...
Read also Sourav Ghosh's answer.
Okay, imagine I have a char**, would this be the correct way to allocate memory?
I mean: allocate memory for the char** itself and then for each char*...
char** fraseUsuario = NULL;
int length = 100, i = 0;
fraseUsuario = (char **) malloc(sizeof (char*)); //Not pretty sure
for (i = 0; i < 3; i++) {
fraseUsuario[i] = (char *) malloc(length * sizeof (char));
if (fraseUsuario[i] == NULL) {
printf("error\n");
return -1;
}
gets(fraseUsuario[i]);
}
for (i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]);
}
And btw, how exactly does free() work? I mean, when I call it at the end, with the debugger it seems as if it does "nothing", if "Hello" is stored in the array, it will continue to be stored there after the free call... is that the normal behavior?
What do you mean allocate memory for the char ** itself? You allocate memory for a variable on the stack when you define it. The following statement defines (allocates memory) fraserUsuario and initializes it to NULL.
char **fraseUsuario = NULL;
I think what you probably meant is how to dynamically allocate an array of char **, i.e., pointer to a pointer to a character. Then you again dynamically allocate an array for each element of the previous allocated array. Do not use gets. It's deprecated and unsafe to use. Use fgets instead. Also, please don't cast the result of malloc. You don't get any benefit and you can run into error if you forget to include the header stdlib.h which contains its prototype. Here's how you do it.
char **fraseUsuario = NULL;
int max_string_len = 100 + 1; // maximum string length. +1 for null byte
int num_string = 3; // number of strings to read
int i, j;
fraseUsuario = malloc(num_string * sizeof *fraseUsuario);
if(fraseUsuario == NULL) { // check for NULL
// handle the case
printf("not enough memory\n");
return -1;
}
for(i = 0; i < num_string; i++) {
fraseUsuario[i] = malloc(max_string_len * sizeof(char));
if(fraseUsuario[i] == NULL) { // check for NULL
printf("not enough memory\n");
for(j = 0; j < i; j++)
free(fraseUsuario[j]); // free memory before returning
free(fraseUsuario); // free memory before returning
return -1;
}
if(fgets(fraserUsuario[i], max_string_len, stdin) == NULL) {
// reading string failed
*fraserUsuario[i] = '\0'; // empty string
}
}
for(i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]); // free memory allocated for strings
}
free(fraseUsuario); // free memory allocated for pointers to strings
fraseUsuario = NULL;
When you call free on a memory address which you got by a call to malloc, the memory block is returned to the free pool on the heap. This memory block can then later be reused by malloc. Once you free memory, you have given up your ownership of it. It no longer belongs to you and attempting to use it is illegal and will result in undefined behaviour and likely segfault.
You only allocate memory for one char* but use three.
To fix this do:
#define STR_MAXIMUM (3)
...
size_t length = 100, i = 0; /* No need to use a signed type.
size_t is meant as index and size type. */
char ** fraseUsuario = malloc(STR_MAXIMUM * sizeof(*fraseUsuario));
for (i = 0; i < STR_MAXIMUM; ++i)
{
fraseUsuario[i] = malloc(length * sizeof(*fraseUsuario));
...
Also add error checking to system calls.
Also^2: Do not use gets() as there is no way for the compiler or the machine to prevent the buffer passed in from overflowing. Use fgets() instead.
fgets(fraseUsuario[i], length, stdin);