2009-06-15 7 views
1

Je souhaiterais savoir comment je peux allouer des données via une fonction, et après que la fonction est retournée, les données sont toujours allouées. C'est à la fois pour les types de base (int, char **) et les types définis par l'utilisateur. Voici deux snipsets de code. Les deux ont l'allocation au sein de la fonction mais après le retour de l'allocation va.Affectation de données via une fonction (ANSI C)

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; 
} 

Le même comportement pour qu'avant que pour le type défini par l'utilisateur:

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)); 


    } 

} 

Toutes les idées? Je pense que je dois passer les pointeurs comme référence, mais comment puis-je le faire?

Merci à l'avance, antisolaires

Répondre

2

La raison pour laquelle cela ne fonctionne pas est que les arguments de fonction dans C sont copiés. Donc, nCheck = NULL dans le contexte externe, vous le passez dans la fonction CallIntAllocation et une copie est faite. CallIntAllocation définit local copie de nCheck pour être le retour de l'appel malloc. Mais la copie externe n'est pas mise à jour - elle pointe toujours sur NULL.

La solution la plus simple consiste à renvoyer la nouvelle valeur de pointeur et à l'affecter comme déjà suggéré par plusieurs personnes. Lorsque vous avez des fonctions qui doivent modifier des structures de données, vous devez leur passer un pointeur, plutôt que des copies, afin que la fonction puisse modifier le pointeur. Le même principe s'applique ici, bien que la structure de données que vous voulez modifier soit elle-même un pointeur.

donc une autre solution serait pour CallIntAllocation de prendre un pointeur à un pointeur qui vous permet de modifier où les points de pointeur, et aussi déréférencer:

CallIntAllocation(int** nCheck, int nCount) 
{ 

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

et invocation

CallIntAllocation(&nCheck, nCount); 

Il est clair que dans cette situation, renvoyer une nouvelle valeur de pointeur est l'approche sensible.

Point final: si vous l'avez disponible, "memset" (C90 mais pas C89 afaik, une partie de la spécification unix unique cependant) peut être utilisé à la place de votre "pour" boucle

memset(ncheck, 0, nCount); 

(c'est pour votre version de la fonction, pas celle qui prend un argument int **)

+0

Merci à tous, et merci jmtd. Et je pense que je peux initialiser mon Struct encore par memset: \t memset (& Criteria, 0x00, sizeof (Critères)); – Sunscreen

5

en utilisant le retour?

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

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

EDIT

l'appelant est responsable d'appeler gratuitement()

+1

Pour être complet, vous pourriez dire quelques mots sur la responsabilité de libérer() résidant dans l'appelant. – dmckee

+0

oui j'ai utilisé de cette façon et a travaillé. Merci – Sunscreen

0

Vous pouvez "retour" le pointeur vers la mémoire allouée. Si NULL est renvoyé, cela signifie que l'allocation a échoué.

4

Vous avez 2 solutions possibles:

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); 

ou vous devez passer un pointeur vers int * si vous voulez tableau Alloc:

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); 
+0

Votre réponse n'était pas là quand j'ai tapé le mien:/ – Pod

+0

Merci, j'ai utilisé l'option de retour. – Sunscreen

3

Pour répondre à votre question directement:

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; 
} 

mais je le suggère à la place:

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; 
} 
+0

Merci Pod, je l'ai fait de cette façon (retour int * et _Criteria * respectivement) et fonctionne. – Sunscreen

Questions connexes