Question

I d love to know how I can allocate data through a function, and after the function is returned the data is still allocated. This is both for basic types (int, char**) and user defined types. Below are two snipsets of code. Both have the allocation within the function though after the return the allocation goes.

int* nCheck = NULL;
int nCount = 4;

CallIntAllocation(nCheck, nCount);

nCheck[1] = 3; // Not allocated!
...

CallIntAllocation(int* nCheck, int nCount)
{

    nCheck = (int*)malloc(nCount* sizeof(int));
    for (int j = 0; j < nCount; j++)
        nCheck[j] = 0;
}

The same behaviour for as before though for user defined type:

typedef struct criteriatype
{
    char szCriterio[256];
    char szCriterioSpecific[256];
} _CriteriaType;

typedef struct criteria
{
    int nCount;
    char szType[128];
    _CriteriaType* CriteriaType;
} _Criteria;

...
_Criteria* Criteria;
AllocateCriteria(nTypes, nCriteria, Criteria);
...

void AllocateCriteria(int nTypes, int nCriteria[], _Criteria* Criteria)
{
    int i = 0;
    int j = 0;

    Criteria = (_Criteria*)malloc(nTypes * sizeof(_Criteria));

    for (i = 0; i < nTypes; i ++)
    {
        // initalise FIRST the whole structure
        // OTHERWISE the allocation is gone
        memset(&Criteria[i],'\0',sizeof(_Criteria));

        // allocate CriteriaType
        Criteria[i].CriteriaType = (_CriteriaType*)malloc(nCriteria[i] * sizeof(_CriteriaType));

        // initalise them
        for (j = 0; j < nCriteria[i]; j ++)
            memset(&Criteria[i].CriteriaType[j],'\0',sizeof(_CriteriaType));


    }

}

Any ideas? I think I need to pass the pointers as a reference, though how can i do so?

Thanks in advance, Sunscreen

Was it helpful?

Solution

The reason it is not working is that function arguments in C are copied. So, nCheck = NULL in the outside context, you pass it into the CallIntAllocation function and a copy is made. The CallIntAllocation defines it's local copy of nCheck to be the return of the malloc call. But the outer copy is not updated -- it still points at NULL.

The simplest solution is to return the new pointer value and assign it as already suggested by several people.

When you have functions that need to modify data structures, you need to pass around a pointer to them, rather than copies of them, so that the function can modify what the pointer points at. The same principle applies here, although the data structure you want to modify is itself a pointer.

So another solution would be for CallIntAllocation to take a pointer-to-a-pointer which would let you modify where the pointer points, and also dereference it:

CallIntAllocation(int** nCheck, int nCount)
{

    *nCheck = (int*)malloc(nCount* sizeof(int));
    for (int j = 0; j < nCount; j++)
        (*nCheck)[j] = 0;
}

and invocation

CallIntAllocation(&nCheck, nCount);

Clearly in this situation returning a new pointer value is the sensible approach.

Final point: if you have it available, "memset" (C90 but not C89 afaik, part of the single unix specification however) can be used in place of your "for" loop

memset(ncheck, 0, nCount);

(that's for your version of the function, not the one that takes an int ** argument)

OTHER TIPS

using return?

Criteria *
newCriteria() {
   Criteria *criteria = malloc(..);
   ...
   return criteria;
}

/* the caller */
Criteria *c1 = newCriteria();
Criteria *c2 = newCriteria();

EDIT

the caller is responsible for calling free()

You have 2 possible solutions:

 int *CallIntAllocation(int nCount)
 {

     int *nCheck = (int*)malloc(nCount* sizeof(int));
     for (int j = 0; j < nCount; j++)
         nCheck[j] = 0;

     return nCheck;
 }

 int* nCheck = NULL;
 int nCount = 4;

 nCheck = CallIntAllocation(nCount);

or you should pass a pointer to int* if you want to alloc array:

 void CallIntAllocation(int **nCheck, int nCount)
 {

     *nCheck = (int*)malloc(nCount* sizeof(int));
     for (int j = 0; j < nCount; j++)
         *nCheck[j] = 0;
 }

 int* nCheck = NULL;
 int nCount = 4;

 CallIntAllocation(&nCheck, nCount); 

To answer your question directly:

int* nCheck = NULL;
int nCount = 4;

CallIntAllocation(&nCheck, nCount);

nCheck[1] = 3; // allocated!
...

void CallIntAllocation(int** pnCheck, int nCount)
{
    int* nCheck = NULL;
    nCheck = (int*) malloc(nCount * sizeof(*nCheck));
    for (int j = 0; j < nCount; j++)
        nCheck[j] = 0;
    *pnCheck = nCheck;
}

but I would suggest this in stead:

nCheck = CallIntAllocation(nCount);

nCheck[1] = 3; // allocated!
...
int *CallIntAllocation(int nCount)
{
    int * nCheck
    nCheck = (int*) malloc(nCount * sizeof(*nCheck));
    for (int j = 0; j < nCount; j++)
        nCheck[j] = 0;
    return nCheck;
}

You can "return" the pointer to the allocated memory. If NULL is returned, that means the allocation was unsuccessful.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top