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");
Related
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);
}
I am trying implement a method that adds a given string to an array that ends with a NULL pointer. This is what I have so far but I am getting an error saying that the pointer being realloc'd was not allocated.
int main(void)
{
char **strings = init_array();
strings = add_string(strings, "one");
strings = add_string(strings, "two");
return 1;
}
char **init_array(void)
{
char **array = malloc(sizeof(char *));
array[0] = NULL;
return array;
}
char **add_string(char **array, const char *string)
{
unsigned int size = 0;
while (*array) {
size++;
array++;
}
char **newarr = (char **)realloc(array, sizeof(char *) * (size + 2));
newarr[size] = malloc(strlen(string)+1);
strcpy(newarr[size], string);
newarr[size+1] = NULL;
return newarr;
}
The issue is array++. You have to pass realloc the same value malloc returned (your array argument), but you modify it during the loop, so it'll work only the first time (because *array will immediately false). You could use:
size_t size;
for(size = 0; array[size]; size++);
And leave the rest untouched.
In your while (*array) loop you are incrementing not only the size, but also the array pointer itself. As a result, at the end of the loop size contains the length of the array, and the array pointer points to the last (NULL) element. This pointer was never allocated, (it points within an allocated block,) therefore it is not a valid pointer to reallocate. (And definitely that's not what you intended to do.)
So, just don't do array++ within that loop.
Your loop that calculates the number of strings in the array also advances the variable itself. You could use a temporary variable instead:
char **temp = array;
while (*temp)
...
Or separate the counting into a function.
BTW you don't need a casting when using realloc, for the same reason you don't do the casting with malloc. This is not a bug, but it better be consistent.
Summarizing all other answers given so far, adding some best practise tweaks, the relevant code should look like this:
char **add_string(char **array, const char *string)
{
char ** newarr;
size_t size = 0;
assert (NULL != string); /* Need to include assert.h */
if (NULL != array)
{
while (NULL != array[size])
{
++size; /* Just count, do not touch the pointer value allocated. */
}
}
newarr = realloc(array, (size + 2) * sizeof *newarr);
if (NULL == newarr) /* Test the outcome of reallocation. */
{
perror("realloc() failed"); /* Need to include stdio.h */
return NULL;
}
newarr[size] = malloc(strlen(string) + 1);
if (NULL == newarr[size])
{
perror("malloc() failed"); /* Need to include stdio.h */
/* Might want to clean up here and indicate the failure to the
caller by returning NULL. */
}
else
{
strcpy(newarr[size], string);
}
newarr[size+1] = NULL;
return newarr;
}
Or even tighter:
char **add_string(char **array, const char *string)
{
assert (NULL != string); /* Need to include assert.h */
{
size_t size = 0;
if (NULL != array)
{
while (NULL != array[size])
{
++size; /* Just count, do not touch the pointer value allocated. */
}
}
{
char ** newarr = realloc(array, (size + 2) * sizeof *newarr);
if (NULL == newarr)
{
perror("realloc() failed"); /* Need to include stdio.h */
}
if (NULL != newarr)
{
newarr[size] = malloc(strlen(string) + 1);
if (NULL == newarr[size])
{
perror("malloc() failed"); /* Need to include stdio.h */
}
else
{
strcpy(newarr[size], string);
}
newarr[size+1] = NULL;
}
return newarr;
}
}
}
The easiest way would be to preserve initial array pointer and use it to realloc memory.
int main(void)
{
char **strings = init_array();
strings = add_string(strings, "one");
strings = add_string(strings, "two");
return 1;
}
char **init_array(void)
{
char **array = malloc(sizeof(char *));
array[0] = NULL;
return array;
}
char **add_string(char **array, const char *string)
{
char** cache = array;
unsigned int size = 0;
while (*array) {
size++;
array++;
}
char **newarr = (char **)realloc(cache, sizeof(char *) * (size + 2));
newarr[size] = malloc(strlen(string)+1);
strcpy(newarr[size], string);
newarr[size+1] = NULL;
return newarr;
}
Another note - main function should return 0 on success.
I have to write a function that adds the given string to array of strings.
char **add_string(char **array, const char *string)
{
array = realloc(array, (sizeof(string)) * sizeof(char *));
int i = 0;
while (array[i] != NULL){
i++;
}
array[i] = malloc((strlen(string) + 1));
strcpy(array[i], string);
array[i + 1] = NULL;
return array;
}
At the moment I get memory leaks according to Valgrid. I didn't use malloc correctly, but I can't figure out how to fix it. I would really appreciate your help.
The realloc allocates a new size given its second argument but you are not increasing the size, so basically every time you call your function it allocates the same size not increasing the area allocated.
you would need to pass the current number of strings in the array to add_string and then increment it in the add_string
char** add_string(char** array, int* size, const char* string)
{
char* newArray = realloc(array, (*size + 1) *sizeof(char*) );
newArray[*size] = malloc(strlen(string)+1);
strcpy(newArray[*size], string);
*size += 1;
...
}
You should also check if realloc succeeds or not by checking the return value.
Normally the above method is not a very effective way to handle increasing sizes since you are calling realloc every time and that is time consuming. Instead you should allocate in chunks then keep track of how much of the chunk you have used up, when the chunk is used up realloc a new one.
Your re-allocation of array is broken, it needs to search to figure out how long the array is, assuming it's always "tightly" allocated (with the last allocated element being the only one that is NULL).
char **add_string(char **array, const char *string){
int i = 0;
while (array[i] != NULL){
i++;//First, count the elements and find NULL element
}
array[i] = malloc(strlen(string) + 1);//or strdup(string);
strcpy(array[i], string);
char **temp;
temp = realloc(array, (i+1+1) * sizeof(char *));
if(temp == NULL){
perror("realloc at add_string");
} else {
array = temp;
array[i + 1] = NULL;
}
return array;
}
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);
Say I assigned an array like so:
char* array[]={"This"};
And then later I wanted to assign array[ ] a new value so that it stores "This" and "That," is there a way that I could change the size of array so that it could hold a new number of values?
No, you can't change the size of an array. You could use a dynamically allocated list of char* instead and realloc() as required:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main()
{
char** array = malloc(1 * sizeof(*array));
if (array)
{
array[0] = "This";
printf("%s\n------\n", array[0]);
char** tmp = realloc(array, 2 * sizeof(*array));
if (tmp)
{
array = tmp;
array[1] = "That";
printf("%s\n", array[0]);
printf("%s\n", array[1]);
}
free(array);
}
return 0;
}
See online demo: https://ideone.com/ng00k.
There is no way to resize an array. You can simply create a new array of size 2, then copy all the data from the previous one to the new one. realloc does it for you with dynamic memory. The better way is to use data structures such as LinkedLists or Vectors which you can find more about online.
You cannot resize array objects.
You would have to dynamically allocate the memory for array and extend it using realloc. Example:
size_t current_size = 0;
char **array = malloc((current_size + 1) * sizeof *array);
if (array)
{
array[current_size++] = "This";
}
...
/**
* If realloc cannot extend the buffer, it will return NULL and leave
* the original buffer intact; however, if we assign NULL back to array,
* we lose our handle to the original buffer, causing a memory leak, so
* we assign the result to a temporary variable.
*/
char **tmp = realloc(array, (current_size + 1) * sizeof *array)
if (tmp)
{
array = tmp;
array[current_size++] = "That";
}
else
{
// realloc failed to extend the buffer; original buffer
// is left intact.
}
Caveats:
realloc is a relatively expensive call, so you (generally) don't want to extend your buffer one element at a time like I did here. A more common strategy is to pick an initial starting size that covers most cases, and if you need to extend the buffer, double its size.
You could abstract the resize operation into a separate function, like so:
int addItem(char ***arr, char *newElement, size_t *count, size_t *bufSize)
{
if (*count == *bufSize)
{
// we've run out of room; extend the buffer
char **tmp = realloc(**arr, 2 * *bufSize * sizeof **arr);
if (tmp)
{
*arr = tmp;
*bufSize *= 2;
}
else
{
// could not extend the buffer; return failure code
return 0;
}
}
(*arr)[(*count)++] = newElement;
}
and call it as
#define N ... // initial array size
char **array = malloc(N * sizeof *array);
size_t bufSize = N;
size_t count = 0;
...
if (addItem(&array, "This", &count, &bufSize))
printf("# elements = %zu, buffer size = %zu\n", count, bufSize);
if (addItem(&array, "That", &count, &bufSize))
printf("# elements = %zu, buffer size = %zu\n", count, bufSize);
This is all untested and off the top of my head; no warranties express or implied. But it should be enough to point you in the right direction.
This is not possible. You can allocate an array of char*, though:
char **array = calloc(2, sizeof(char *));
array[0] = "This";
array[1] = "That";