invalid realloc/realloc returns NULL - c

In one function I used malloc :
void name1(struct stos* s)
{
s = malloc (4 * sizeof (int));
}
And everything is ok. But later I used realloc
void name2(struct stos* s)
{
s->size = 2*(s->size);
s = realloc (s, (s->size + 1) * sizeof (int));
}
and I get invalid free/delete/realloc in valgrind and realloc returns NULL.
Declaration of Structure and rest of program is:
struct stos
{
int top;
int size;
int stk[];
};
void name1(struct stos* s);
void name2(struct stos* s);
int main()
{
struct stos stosik;
struct stos* s;
s = &stosik;
name1(s);
//some operations on the array and int top here
name2(s);
}
What did I do wrong here? I looked for what might have gone wrong for quite long, read quite a few articles about pointers, malloc/realloc etc. but with no result. I would be really grateful, if someone could help me.

The problem is slightly subtle and caused by a combination of two things. Let's start here:
struct stos stosik;
struct stos* s;
s = &stosik;
name1(s);
First, you make s point to an a valid chunk of memory that is allocated on the stack (stosik) and then you call name1 passing into s. Let's look at what name1 looks like:
void name1(struct stos* s)
{
s = malloc (4 * sizeof (int));
}
Hmm, we can see that name1 takes in a pointer to a struct stos called s; inside that function, we are allocating some memory and making s point to it. This is a problem.
First of all, note that s already points to a valid chunk of memory. So using a malloc here is suspicious. It will cause a subtle bug that will actually hide the real bug in your program, which is bad. So, let's remove stosik completely:
int main()
{
struct stos* s = NULL;
name1(s);
if(s == NULL)
return -1;
Now, if you run this program, you will see that after you call name1 the variable s still points to NULL. What's happening here?
Well, we are changing the function's LOCAL copy of s (i.e. the s that exists only inside name1)... but the s in main isn't changed! Remember, that we are passing a pointer into name1 but we are passing it by value.
To do what you seem to be trying to do you can do you would have to either pass a pointer to s into name1 (that is, to pass a double pointer) or you should return the result of the malloc from name1 as a return value. Let's look at each of these options:
Passing s in via a double pointer
void name1(struct stos **s)
{
/* sanity check */
if(s == NULL)
return;
/* now, allocate enough space for four integers and make
* whatever s points to, point to that newly allocated
* space.
*/
*s = malloc(4 * sizeof(int));
}
And calling it from main requires us to use the "address-of" operator:
struct stos *s = NULL;
/* we need to pass a pointer to s into name1, so get one. */
name1(&s);
/* malloc can fail; check the result! */
if(s == NULL)
return -1;
Returning a pointer to the allocated memory from name1
struct stos *name1()
{
return malloc(4 * sizeof(int));
}
Calling this from main is slightly easier:
struct stos *s = name1();
/* malloc can fail; check the result! */
if(s == NULL)
return -1;
Changing your code to what I show you here will fix this issue (but there may be others) but let me touch briefly upon something else:
The other bug
The crash you encounterd crops up partially because of the problem we just covered; another issue is that inside name2 you are calling realloc. The pointer you pass into realloc however, is not a pointer that you got back from malloc or realloc, which is what realloc expects. It points to stosik instead. So that code causes undefined behavior and after that anything can happen.
If you're lucky (it seems you were), it will just crash right then and there and if you're not... well, who knows what will happen?

if you want to dynamically allocate s in name1 you need it to be declared as name1(struct stos** s) and pass pointer to the pointer where the allocated memory should appear.
Your main allocates stosik staticaly, meaning you don't need to do any further dynamic allocation. Then when you try doing name1(statically allocated mem) it does … um, something. I don't know what, but certainly not what you expect.

Related

Realloc issue: free(): double free detected in tcache 2 [duplicate]

Building on what I learned here: Manipulating dynamic array through functions in C.
void test(int data[])
{
data[0] = 1;
}
int main(void)
{
int *data = malloc(4 * sizeof *data);
test(data);
return 0;
}
This works fine. However, I am also trying to using realloc in a function.
void increase(int data[])
{
data = realloc(data, 5 * sizeof *data);
}
This complies but the program crashes when run.
Question
How should I be using realloc in a function?
I understand that I should assign the result of realloc to a variable and check if it is NULL first. This is just a simplified example.
You want to modify the value of an int* (your array) so need to pass a pointer to it into your increase function:
void increase(int** data)
{
*data = realloc(*data, 5 * sizeof int);
}
Calling code would then look like:
int *data = malloc(4 * sizeof *data);
/* do stuff with data */
increase(&data);
/* more stuff */
free(data);
Keep in mind the difference between a pointer and an array.
An array is a chuck of memory in the stack, and that's all.If you have an array:
int arr[100];
Then arr is an address of memory, but also &arr is an adress of memory, and that address of memory is constant, not stored in any location.So you cannot say arr=NULL, since arr is not a variable that points to something.It's just a symbolic address: the address of where the array starts.Instead a pointer has it's own memory and can point to memory addresses.
It's enough that you change int[] to int*.
Also, variables are passed by copy so you need to pass an int** to the function.
About how using realloc, all the didactic examples include this:
Use realloc;
Check if it's NULL.In this case use perror and exit the program;
If it's not NULL use the memory allocated;
Free the memory when you don't need it anymore.
So that would be a nice example:
int* chuck= (int*) realloc (NULL, 10*sizeof(int)); // Acts like malloc,
// casting is optional but I'd suggest it for readability
assert(chuck);
for(unsigned int i=0; i<10; i++)
{
chunk[i]=i*10;
printf("%d",chunk[i]);
}
free(chunk);
Both code are very problematic, if you use the same pointer to send and receive from realloc, if it fails, you will lose your pointer to free it later.
you should do some thing like this :
{
...
...
more = realloc(area , size);
if( more == NULL )
free(area);
else
area=more;
...
...
}

program crashes at repetitive calloc() call

Edit: solved by kaylums little comment. Thank you!
good morning,
I am relatively new to C still and I'm trying to make a doubly linked list.
I got my program to run properly with all the functions with this kind of element:
the program crashes after either 2 or 3 inserted elements in the list in the calloc() call of my insertElement() function. I don't get any SIGSEGV or anything, the program just stops with a random negative return.
I'll try to give a minimum code example of the function and the function call:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct Element {
char name[30];
}Element;
typedef struct List {
int size;
Element* first;
Element* last;
}List;
Element* insertElement(List* List, char name[30]) {
Element* element;
element = (Element*)calloc(0, sizeof(Element));
strncpy_s(element->name, name, 30);
return element;
}
List globalList;
char name[30];
int main() {
while (true) {
printf("insert the name >>");
if (fgets(name, 30, stdin) != NULL)
name[strcspn(name, "\n")] = 0;
insertElement(&globalList, name);
}
}
is there already something obvious wrong with that basic stuff?
Thank you very much in advance! Any advice would be very much appreciated, have a good day!
element = (Element*)calloc(0, sizeof(Element));
what is 0 in first argument?
actually you ask for 0 number of your type from memory!
here is some explanation about dynamic memory allocation:
Dynamic memory allocation is a process of allocating memory at run time. There are four library routines, calloc(), free(), realloc(), and malloc() which can be used to allocate memory and free it up during the program execution. These routines are defined in the header file called stdlib.h.
What is malloc() ?
It is a function which is used to allocate a block of memory dynamically. It reserves memory space of specified size and returns the null pointer pointing to the memory location.
The pointer returned is usually of type void. It means that we can assign malloc function to any pointer. The full form of malloc is memory allocation.
What is calloc() ?
Calloc() function is used to allocate multiple blocks of memory. It is a dynamic memory allocation function which is used to allocate the memory to complex data structures such as arrays and structures. If this function fails to allocate enough space as specified, it returns will null pointer. The full form of calloc function is contiguous allocation.
Why use malloc() ?
Here are the reasons of using malloc()
You should use malloc() when you have to allocate memory at runtime.
You should use malloc when you have to allocate objects which must exist beyond the execution of the current memory block.
Go for malloc() if you need to allocate memory greater than the size of that stack.
It returns the pointer to the first byte of allocated space.
It enables developers to allocate memory as it is needed in the exact amount.
This function allocates a memory block size of bytes from the heap.
Why use calloc() ?
Here are the reasons of using calloc()
When you have to set allocated memory to zero.
You can use calloc that returns a pointer to get access to memory heap.
Used when you need to initialize the elements to zero to returns a pointer to the memory.
To prevent overflow that is possible with malloc()
Use calloc() to request a page that is known to already be zeroed.
Syntax of malloc()
Here is a Syntax of malloc()
ptr = (cast_type *) malloc (byte_size);
n above syntax, ptr is a pointer of cast_type. The malloc function returns a pointer to the allocated memory of byte_size.
Example of malloc() in C
In the bellow code, sizeof(*ptr) is used to allocate a memory block of 15 integers. In the printf statement, we are finding the value of the 6th integer.
#include<stdlib.h>
#include<stdio.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr));
if (ptr != NULL) {
*(ptr + 5) = 480;
printf("Value of the 6th integer is %d",*(ptr + 5));
}
}
Output:
Value of the 6th integer is 480
Syntax of calloc()
Here is a Syntax of malloc()
ptr = (cast_type *) calloc (n, size);
The above syntax is used to allocate n memory blocks of the same size. After the memory space is allocated, all the bytes are initialized to zero. The pointer, which is currently at the first byte of the allocated memory space, is returned.
Example of calloc() in C
The C language program below calculates the sum of the first ten terms. If the pointer value if null, then the memory space will not be allocated.
For loop is used to iterate the value of a variable "i" and print the sum. Lastly, function free is used to free-up the pointer.
#include <stdio.h>
#include <stdlib.h>
int main() {
int i, * ptr, sum = 0;
ptr = calloc(10, sizeof(int));
if (ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
printf("Building and calculating the sequence sum of the first 10 terms \n");
for (i = 0; i < 10; ++i) { * (ptr + i) = i;
sum += * (ptr + i);
}
printf("Sum = %d", sum);
free(ptr);
return 0;
}
Output:
Building and calculating the sequence sum of the first 10 terms n Sum = 45
I will not extend on the actual problem (specifying 0 as the number of elements requested to calloc()). I will point you to several other things found in your code.
The first problem in reading your code is that you lack to include the file <stdbool.h>, necessary to use the constants true and false and the type bool. I have added it in the first line.
#include <stdbool.h>
Next, you use at several places the value 30 as the size of several objects that are all related. If you decide in the future to change that value, it will be difficult to find all the ocurrences of the constan 30 and change all of them (and the risk you have used also 30 for anything else and it gets changed in the middle)
I have included a constan with the following lines:
#define NAME_LENGTH (30)
and all the definitions:
...
char name[NAME_LENGTH];
in the structure...
Element* insertElement(List* List, char name[NAME_LENGTH]) {
in the prototype of insertElement (you don't need as name is actually defined as char *, not as an array of NAME_LENGTH elements...
On other side, you need to include a pointer on each Element to link each to the next element of the list. This is done right after name:
struct Element *next; /* we need to include struct as the type Element is not yet defined */
Next, include sizeof *element as the second parameter to calloc() and 1 to the first. Better, if you are going to initialize all fields in the Element structure, then it is better to call malloc() (see the final code , posted at the end)
NEVER, NEVER, NEVER cast the value returned by malloc()
(and friends) This is a legacy that causes a lot of
errors, that get undetected (and very difficult to find),
due to the cast. When you cast you tell the compiler:
leave it in my hands, as I know what I'm doing. And this
makes the compiler silent, when it should be complaining.
The problem mainly has to do with forgetting to include
the header file where malloc (and friends) are declared
(<stdlib.h>) and you will take long time to detect and
see why your program has crashed.
For the same reason, don't use the size of the type, when
you can use the pointed to expression as template of the
type. This is because if you change the type of the
pointed to object, you need to remember that here you have
put the type of the object (and you need to change it too)
This way, this expression
will only be bad if you change the object into a non
pointer object. Also, you have requested for 0 elements
of the specified type, which has already been noticed in other answers. This will make calloc() to return NULL, value you don't check in your code, and you try to use it later on. This will crash your program, but in the best case, it is Undefined Behaviour (and a very difficult error to find, so be careful and always check the value returned by malloc()).
Next, don't use strncpy_s() as it is Microsoft specific routine, and isn't included in any standard. A proper substitute has been provided by strncpy():
strncpy(element->name, name, sizeof element->name);
also use the sizeof operator, as it protects you if you decide in the future to change the type of the pointer.
Finally, it is better to use fgets() as the test expression for the while statement in main(). The reason is that you can end the loop when the end of file is detected.
Finally, you code ends as (including the linking of Elements in the linked list):
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define NAME_LENGTH (30)
typedef struct Element {
char name[NAME_LENGTH];
struct Element *next;
} Element;
typedef struct List {
int size;
Element* first;
Element* last;
} List;
Element* insertElement(List* List, char name[NAME_LENGTH]) {
Element* element;
/* NEVER, NEVER, NEVER cast the value returned by malloc
* (and friends) This is a legacy that causes a lot of
* errors, that get undetected (and very difficult to find),
* due to the cast. When you cast you tell the compiler:
* leave it in my hands, as I know what I'm doing. And this
* makes the compiler silent, when it should be complaining.
* The problem mainly has to do with forgetting to include
* the header file where malloc (and friends) are declared
* (<stdlib.h>) and you will take long time to detect and
* see why your program has crashed. */
/* for the same reason, don't use the size of the type, when
* you can use the pointed to expression as template of the
* type. This is because if you change the type of the
* pointed to object, you need to remember that here you have
* put the type of the object. This way, this expression
* will only be bad if you change the object into a non
* pointer object. Also, you have requested for 0 elements
* of the specified type. */
element = malloc(sizeof *element);
/* don't use strncpy_s as it is not standard. Use the sizeof
* operator again, to protect the expression if you change
* the type of element->name */
strncpy(element->name, name, sizeof element->name);
element->next = NULL;
if (List->last) {
List->last->next = element;
List->last = element;
} else {
List->first = List->last = element;
}
return element;
}
List globalList;
char name[NAME_LENGTH];
int main() {
/* if you put the fgets() call as the test of the while
* statement below, you will process each line until you get
* an end of file condition. Then you can do both things: to
* null the occurence of the \n char, and the call to
* insertElement() I have not corrected because it's a
* question of taste. */
printf("insert the name >> ");
while (fgets(name, sizeof name, stdin) != NULL) {
/* sizeof name is better than the constant, as if you
* change the type definition of object name, you have to
* remember that you are using here its size. sizeof
* does the job for you. */
name[strcspn(name, "\n")] = 0;
insertElement(&globalList, name);
printf("insert the name >> ");
}
Element *p;
char *sep = "\n\n{ ";
for (p = globalList.first; p; p = p->next) {
printf("%s\"%s\"", sep, p->name);
sep = ", ";
}
printf(" };\n");
}

C - Storing pointers with malloc() in an array, can't free() them afterwards

I want to store pointers that have been allocated using malloc() in an array and then free all of them after. However even though the program doesn't complain it doesn't work. Below cleanMemManager() won't actually free the memory as when tested inside main() the char* pointer is not NULL and it will print ???.
code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void **ptrList = NULL;
void tfree(void** ptr)
{
free(*ptr);
*ptr = NULL;
}
void* talloc(int size)
{
void* ptr = malloc(size);
ptrList[0] = ptr; ///No clue if this actually does what I think it does
return ptrList[0];
}
void initMemManager()
{
ptrList = (void**)malloc(sizeof(void**) * 3);
memset(ptrList, 0, sizeof(void**) * 3);
}
void cleanMemManager()
{
tfree(&ptrList[0]); //Doesn't free the right pointer it seems
}
int main()
{
initMemManager();
char* ptr = (char*)talloc(3);
cleanMemManager();
if (ptr != NULL) //This will trigger and I'm not expecting it to
printf("???");
getchar();
return 0;
}
I don't understand the syntax to use for this, does the pointer not actually get touched at all? What is it freeing then since it doesn't throw any errors?
In main, char *ptr = (char*)talloc(3); declares ptr to be a local variable. It contains a copy of the value returned by talloc, and none of your subroutines know about ptr or where it is. So none of them change the value of ptr. Thus, when you reach if (ptr != NULL), the value of ptr has not changed.
Additionally:
In initMemManager, you should use sizeof(void *) in two places where you have sizeof(void**). In these places, you are allocating and copying void * objects, not void ** objects.
It looks like you are trying to implement a sort of smart memory manager that automatically sets pointers to NULL when they are freed. To do that in C, you would have to give up having copies of pointers. For example, ptr is a copy of ptrList[0], but tfree only sets whichever copy it is passed to NULL. We could give advice on building such a system, but it would quickly become cumbersome—your memory manager needs to keep a database of pointers and their copies (and pointers derived from them, as by doing array arithmetic). Or you have to refer to everything indirectly through that ptrList array, which adds some mess to your source code. Unfortunately, C is not a good language for this.
Freeing doesn't guarantee that pointers pointing to the allocated block will be set to NULL. If you actually try doing
if (ptrList[0] != NULL)
printf("ptrList[0] != NULL");
you will see that the program won't output and if you remove the cleanMemManager() function call, it will output. This means tfree function is working as intended, it's freeing the memory that was allocated.
Now as to why ptr variable being not set to NULL, it's simply because ptr is still storing the old address. cleanMemManager() has no way of mutating the variable ptr. This is commonly called dangling pointer or use after free.
Also free() doesn't clean/zero out the the allocated space, the block is simply marked as "free". The data will most likely remain in the memory for a moment until the free block is overwritten by another malloc request.

How to use realloc in a function in C

Building on what I learned here: Manipulating dynamic array through functions in C.
void test(int data[])
{
data[0] = 1;
}
int main(void)
{
int *data = malloc(4 * sizeof *data);
test(data);
return 0;
}
This works fine. However, I am also trying to using realloc in a function.
void increase(int data[])
{
data = realloc(data, 5 * sizeof *data);
}
This complies but the program crashes when run.
Question
How should I be using realloc in a function?
I understand that I should assign the result of realloc to a variable and check if it is NULL first. This is just a simplified example.
You want to modify the value of an int* (your array) so need to pass a pointer to it into your increase function:
void increase(int** data)
{
*data = realloc(*data, 5 * sizeof int);
}
Calling code would then look like:
int *data = malloc(4 * sizeof *data);
/* do stuff with data */
increase(&data);
/* more stuff */
free(data);
Keep in mind the difference between a pointer and an array.
An array is a chuck of memory in the stack, and that's all.If you have an array:
int arr[100];
Then arr is an address of memory, but also &arr is an adress of memory, and that address of memory is constant, not stored in any location.So you cannot say arr=NULL, since arr is not a variable that points to something.It's just a symbolic address: the address of where the array starts.Instead a pointer has it's own memory and can point to memory addresses.
It's enough that you change int[] to int*.
Also, variables are passed by copy so you need to pass an int** to the function.
About how using realloc, all the didactic examples include this:
Use realloc;
Check if it's NULL.In this case use perror and exit the program;
If it's not NULL use the memory allocated;
Free the memory when you don't need it anymore.
So that would be a nice example:
int* chuck= (int*) realloc (NULL, 10*sizeof(int)); // Acts like malloc,
// casting is optional but I'd suggest it for readability
assert(chuck);
for(unsigned int i=0; i<10; i++)
{
chunk[i]=i*10;
printf("%d",chunk[i]);
}
free(chunk);
Both code are very problematic, if you use the same pointer to send and receive from realloc, if it fails, you will lose your pointer to free it later.
you should do some thing like this :
{
...
...
more = realloc(area , size);
if( more == NULL )
free(area);
else
area=more;
...
...
}

How can I allocate memory and return it (via a pointer-parameter) to the calling function?

I have some code in a couple of different functions that looks something like this:
void someFunction (int *data) {
data = (int *) malloc (sizeof (data));
}
void useData (int *data) {
printf ("%p", data);
}
int main () {
int *data = NULL;
someFunction (data);
useData (data);
return 0;
}
someFunction () and useData () are defined in separate modules (*.c files).
The problem is that, while malloc works fine, and the allocated memory is usable in someFunction, the same memory is not available once the function has returned.
An example run of the program can be seen here, with output showing the various memory addresses.
Can someone please explain to me what I am doing wrong here, and how I can get this code to work?
EDIT: So it seems like I need to use double pointers to do this - how would I go about doing the same thing when I actually need to use double pointers? So e.g. data is
int **data = NULL; //used for 2D array
Do I then need to use triple pointers in function calls?
You want to use a pointer-to-pointer:
void someFunction (int **data) {
*data = malloc (sizeof (int));
}
void useData (int *data) {
printf ("%p", data);
}
int main () {
int *data = NULL;
someFunction (&data);
useData (data);
return 0;
}
Why? Well, you want to change your pointer data in the main function. In C, if you want to change something that's passed in as a parameter (and have that change show up in the caller's version), you have to pass in a pointer to whatever you want to change. In this case, that "something you want to change" is a pointer -- so to be able to change that pointer, you have to use a pointer-to-pointer...
Note that on top of your main problem, there was another bug in the code: sizeof(data) gives you the number of bytes required to store the pointer (4 bytes on a 32-bit OS or 8 bytes on a 64-bit OS), whereas you really want the number of bytes required to store what the pointer points to (an int, i.e. 4 bytes on most OSes). Because typically sizeof(int *)>=sizeof(int), this probably wouldn't have caused a problem, but it's something to be aware of. I've corrected this in the code above.
Here are some useful questions on pointers-to-pointers:
How do pointer to pointers work in C?
Uses for multiple levels of pointer dereferences?
A common pitfall especially if you moved form Java to C/C++
Remember when you passing a pointer, it's pass by value i.e the value of the pointer is copied. It's good for making changes to data pointed by the pointer but any changes to the pointer itself is just local since it a copy!!
The trick is to use pass the pointer by reference since you wanna change it i.e malloc it etc.
**pointer --> will scare a noobie C programmer ;)
You have to pass a pointer to the pointer if you want to modify the pointer.
ie. :
void someFunction (int **data) {
*data = malloc (sizeof (int)*ARRAY_SIZE);
}
edit :
Added ARRAY_SIZE, at some point you have to know how many integers you want to allocate.
That is because pointer data is passed by value to someFunction.
int *data = NULL;
//data is passed by value here.
someFunction (data);
//the memory allocated inside someFunction is not available.
Pointer to pointer or return the allocated pointer would solve the problem.
void someFunction (int **data) {
*data = (int *) malloc (sizeof (data));
}
int* someFunction (int *data) {
data = (int *) malloc (sizeof (data));
return data;
}
someFunction() takes its parameter as int*. So when you call it from main(), a copy of the value you passed created. Whatever you are modifying inside the function is this copy and hence the changes will not be reflected outside. As others suggested, you can use int** to get the changes reflected in data. Otherway of doing it is to return int* from someFunction().
Apart from using the doublepointer technique, if there's only 1 return param needed rewrite is as following:
int *someFunction () {
return (int *) malloc (sizeof (int *));
}
and use it:
int *data = someFunction ();
Here's the general pattern for allocating memory in a function and returning the pointer via parameter:
void myAllocator (T **p, size_t count)
{
*p = malloc(sizeof **p * count);
}
...
void foo(void)
{
T *p = NULL;
myAllocator(&p, 100);
...
}
Another method is to make the pointer the function's return value (my preferred method):
T *myAllocator (size_t count)
{
T *p = malloc(sizeof *p * count);
return p;
}
...
void foo(void)
{
T *p = myAllocator(100);
...
}
Some notes on memory management:
The best way to avoid problems with memory management is to avoid memory management; don't muck with dynamic memory unless you really need it.
Do not cast the result of malloc() unless you're using an implementation that predates the 1989 ANSI standard or you intend to compile the code as C++. If you forget to include stdlib.h or otherwise don't have a prototype for malloc() in scope, casting the return value will supress a valuable compiler diagnostic.
Use the size of the object being allocated instead of the size of the data type (i.e., sizeof *p instead of sizeof (T)); this will save you some heartburn if the data type has to change (say from int to long or float to double). It also makes the code read a little better IMO.
Isolate memory management functions behind higher-level allocate and deallocate functions; these can handle not only allocation but also initialization and errors.
Here you are trying to modifying the pointer i.e. from "data == Null" to "data == 0xabcd"some other memory you allocated. So to modify data that you need pass the address of data i.e. &data.
void someFunction (int **data) {
*data = (int *) malloc (sizeof (int));
}
Replying to your additional question you edited in:
'*' denotes a pointer to something. So '**' would be a pointer to a pointer to something, '***' a pointer to a pointer to a pointer to something, etc.
The usual interpretation of 'int **data' (if data is not a function parameter) would be a pointer to list of int arrays (e.g. 'int a [100][100]').
So you'd need to first allocate your int arrays (I am using a direct call to malloc() for the sake of simplicity):
data = (int**) malloc(arrayCount); //allocate a list of int pointers
for (int i = 0; i < arrayCount; i++) //assign a list of ints to each int pointer
data [i] = (int*) malloc(arrayElemCount);
Rather than using double pointer we can just allocate a new pointer and just return it, no need to pass double pointer because it is not used anywhere in the function.
Return void * so can be used for any type of allocation.
void *someFunction (size_t size) {
return malloc (size);
}
and use it as:
int *data = someFunction (sizeof(int));
For simplicity, let me call the above single pointer parameter p
and the double pointer pp (pointing to p).
In a function, the object that p points to can be changed and the change goes out of
the function. However, if p itself is changed, the change does not
leave the function.
Unfortunately, malloc by its own nature, typically
changes p. That is why the original code does not work.
The correction (58) uses the pointer pp pointing to p. in the corrected
function, p is changed but pp is not. Thus it worked.

Resources