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.
Related
#include <stdio.h>
#include <stdlib.h>
int find_lenght(int *arrr){
int i = 0;
while(arrr[i] != '\0'){
i++;
}
return i;
}
void init_array(int *arrr){
arrr=(int*)malloc(1*sizeof(int));
printf("New element:");
int lenght = find_lenght(arrr);
scanf("%d", &arrr[lenght]);
printf("Lenght = %d\n",lenght);
printf("Array elements are:\n");
for(int i = 0; i <= lenght; i++) {
printf("%d,", arrr[i]);
}
}
void print_array(int *arrr){
printf("Array elements are:\n");
int lenght = find_lenght(arrr);
for(int i = 0; i == lenght; i++) {
printf("%d,", arrr[i]);
}
}
int main() {
int *arr = NULL;
init_array(arr);
print_array(arr);
}
I don't know what am i missing here.
My point is to fill in and then print dynamic array
Also my taught is it's not filling the way it should, so it hasn't anything to print.
Your arr pointer in main is never assigned because your init_array assign the address of the allocated memory (the return value of malloc) to the input parameter arrr, which is, a local variable.
You have mainly two solutions to properly achieve what you want to do. The first one (the better one in my point of view), by making your init_array returning the allocated memory address to be assigned:
int* init_array()
{
int* retval = (int*)malloc(1*sizeof(int));
// ...
return retval;
}
int main()
{
int *arr = init_array(); //< assign arr with returned value
}
Another way is to make your init_array function taking a pointer to a pointer, so the function can assign this pointer:
void init_array(int** arrr)
{
(*arrr) = (int*)malloc(1*sizeof(int));
// ...
}
int main()
{
int* arr = NULL;
init_array(&arr); //< pass reference to arr
}
You need to pass the pointer to pointer to int to change passed pointer. Your for loop is invalid in print function. You need also to set the sentinel value yourself.
size_t find_length(const int *arrr)
{
size_t i = 0;
if(arrr)
while(arrr[i]) i++;
return i;
}
void add_element(int **arrr, int element)
{
size_t length = find_length(*arrr);
int *tmp = realloc(*arrr, (length + 2) * sizeof(**arrr));
if(tmp)
{
*arrr = tmp;
(*arrr)[length] = element;
(*arrr)[length + 1] = 0;
}
}
void print_array(const int *arrr)
{
printf("Array elements are:\n");
size_t lenght = find_length(arrr);
for(size_t i = 0; i < lenght; i++)
{
printf("arrr[%zu] = %d\n", i, arrr[i]);
}
}
int main(void) {
int *arr = NULL;
add_element(&arr, 5);
add_element(&arr, 15);
add_element(&arr, 25);
add_element(&arr, 35);
print_array(arr);
}
https://godbolt.org/z/drKej3KT5
the array on your main function is still NULL. the better way to do is just call the print_array() function after you initialize it. you just simply put print_array(arrr) inside init_array() and after the for loop statement.
The line
int lenght = find_lenght(arrr);
may invoke undefined behavior, because find_length requires its argument to be a pointer to the first element of a null-terminated int array. However, the content of the memory pointed to by arrr is indeterminate, because it has not been initialized. Therefore, it is not guaranteed to be null-terminated.
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 */
}
I've been trying O(n ^2) sorting algorithm just to practice C, but have encountered this annoying "realloc(): invalid pointer" error and cannot figure out why. I've viewed other explanations but they have not helped too much.
#include <stdio.h>
#include <stdlib.h>
int* removeIndex(int* list, int index, int len){
for(int i = index; i < len - 1; i++){
list[i] = list[i+1];
}
return realloc(list, len - 1);
}
int* sort(int* unsorted, int len){
int* sorted = malloc(len * sizeof(int));
for(int placement = 0; placement < len; placement++){
int smallest_index = 0;
int smallest = unsorted[smallest_index];
int len_unsorted = len - placement;
for(int i = 0; i < len_unsorted; i++){
if (unsorted[i] < smallest){
smallest = unsorted[i];
smallest_index = i;
}
}
unsorted = removeIndex(unsorted, smallest_index, len_unsorted);
sorted[placement] = smallest;
}
return sorted;
}
int main()
{
int len = 5;
int unsorted[5] = {5,4,3,2,1};
int* sorted = sort(unsorted, len);
for(int i = 0; i < len; i++){
printf("%d\n", sorted[i]);
}
return 0;
}
On a side note, why do I get an error if I write
int len = 5;
int unsorted[len] = {5,4,3,2,1};
so I have to force write it as int unsorted[5] = {5,4,3,2,1};
Cheers
The pointer passed to realloc pointing to a array with auto storage duration, which is declared and initialized in main(), and not pointing to a memory block previously allocated with malloc, calloc or realloc.
From realloc [emphasis added]
Reallocates the given area of memory. It must be previously allocated by malloc(), calloc() or realloc() and not yet freed with a call to free or realloc. Otherwise, the results are undefined.
On top of the answer of H.S., I believe the sorting algorithm is ill designed. The first call to the function removeIndex is done with the parameters as so
removeIndex(unsorted, 4, 5)
The for loop is not entered and a reallocation is supposed to take place with realloc(list, 4).
As far as I can see the sorting algorithm cannot work in general. In particular the example you gave with 5,4,3,2,1.
Try to do that with pencil and paper and you will see what I mean.
For this code
#include <stdlib.h>
#include <stdio.h>
int *f (int n)
{
int *ptr = malloc (sizeof (int));
*ptr = n;
return ptr;
}
int main()
{
int i;
int **ptr = malloc (sizeof (int *));
ptr[0] = f (0);
for (i = 0; i < 5; ++i)
{
ptr = realloc (sizeof (int *) * (i + 2));
ptr[i + 1] = malloc (sizeof (int));
ptr[i + 1] = f (i + 1);
}
for (i = 0; i < 5; ++i)
{
printf ("%d\n", *ptr[i]);
free (ptr[i]);
}
free (ptr);
return 0;
}
does program allocate twice than it is needed?
Yes, You don't need the malloc in main as it is immediately overwritten on the next line and you leak that memory. Is this a homework question?
EDIT for question change
This is now leaking memory in an odd way.
The first few lines aren't leaking but when you get into the loop you're allocating and assigning randomly. (As a first, realloc takes as it's first arguement a pointer to reallocate, so you're missing ptr in there)
Now you're allocating ptr to be of size 2, then 3 then 4 etc... up to 6. And then immediately leaking that memory as you overwrite the pointer with the call to f()
You could write that all like this:
int i;
int **ptr = malloc (sizeof(int*) * 6);
for (i = 0; i < 6; ++i)
{
ptr[i] = f(i);
}
for (i = 0; i < 6; ++i)
{
printf ("%d\n", *ptr[i]);
free (ptr[i]);
}
free (ptr);
return 0;
As an aside, you should in general try not to allocate memory too often, it is relatively slow. If you can use the stack you should, and if not, try and allocate all the memory you need up front, calling realloc in a loop is a bad idea and should be avoided.
In this specific case you don't need a pointer to a pointer, you could have just allocated one array of 6 integers, with int* array = malloc(sizeof(int) * 6) and then array[0] = 0; which would be easier and better.
Yes, it does allocate twice the needed memory. Also, the value of "ptr" in main is overwrite by return of "f" so you don't even have a chance to free it. You could remove the call to malloc in "main":
int main()
{
int *ptr = f (3);
printf ("%d\n", *ptr);
free (ptr);
return 0;
}
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.