2012-12-15 2 views
2

Dans ce code jouet exemple:C Pointer aide: équivalence Array/pointeur

int MAX = 5; 

void fillArray(int** someArray, int* blah) { 
    int i; 
    for (i=0; i<MAX; i++) 
    (*someArray)[i] = blah[i]; // segfault happens here 
} 

int main() { 
    int someArray[MAX]; 
    int blah[] = {1, 2, 3, 4, 5}; 

    fillArray(&someArray, blah); 

    return 0; 
} 

... Je veux remplir le tableau someArray, et que les modifications persistent en dehors de la fonction.

Ceci fait partie d'une très grande tâche de devoirs, et cette question résout le problème sans me permettre de copier la solution. On me donne une signature de fonction qui accepte un int ** comme paramètre, et je suis supposé coder la logique pour remplir ce tableau. J'étais sous l'impression que déréférencer 0ArrayEarth dans la fonction fillArray() me donnerait le tableau requis (un pointeur vers le premier élément), et que l'utilisation de l'accès à l'élément tableau entre parenthèses sur ce tableau me donnerait la position nécessaire qui doit être attribué. Cependant, je n'arrive pas à comprendre pourquoi je reçois une erreur de segmentation.

Merci beaucoup!

+1

'bla [5]' 'à bla [999]' sont des bornes extérieures. Pourquoi y accédez-vous dans 'fillArray'? –

+0

Je suis assez sûr que le pointeur vers la déclaration de pointeur est également faux. –

+0

Pas faux, juste redondant – StoryTeller

Répondre

3

Je souhaite remplir le tableau someArray et faire en sorte que les modifications persistent en dehors de la fonction.

juste passer le tableau de la fonction comme il se désintègre en un pointeur vers le premier élément:

void fillArray(int* someArray, int* blah) { 
    int i; 
    for (i=0; i<MAX; i++) 
     someArray[i] = blah[i]; 
} 

et invoqué:

fillArray(someArray, blah); 

Les changements apportés aux éléments sont visibles à l'extérieur de la fonction.

Si le code réel était d'allouer un tableau dans fillArray() alors un int** serait nécessaire:

void fillArray(int** someArray, int* blah) { 
    int i; 
    *someArray = malloc(sizeof(int) * MAX); 
    if (*someArray) 
    { 
     for (i=0; i<MAX; i++) /* or memcpy() instead of loop */ 
      (*someArray)[i] = blah[i]; 
    } 
} 

et invoqua:

int* someArray = NULL; 
fillArray(&someArray, blah); 
free(someArray); 
+0

Cela prend tout son sens pour que cela fonctionne. Cependant, si le tableau est déjà alloué, pourquoi exactement passer & someArray dans fillArray() et accéder au tableau lui-même par * someArray conduit à une erreur de segmentation? – Maestro1

+0

@ Maestro1, il ne devrait pas. Voir http://ideone.com/4YAMfn par exemple. – hmjd

0

Il n'y a pas d'équivalence "tableau/pointeur", et Les tableaux et les pointeurs sont très différents. Ne les confondez jamais. someArray est un tableau . &someArray est un pointeur vers un tableau et a le type int (*)[MAX]. La fonction prend un pointeur vers un pointeur, c'est-à-dire int **, qui doit pointer vers une variable pointeur quelque part en mémoire. Il n'y a aucune variable de pointeur n'importe où dans votre code. Qu'est-ce que cela pourrait indiquer?

Un tableau de valeurs peut dégrader implicitement en un pointeur rvalue pour son premier élément dans certaines expressions. Quelque chose qui nécessite un lvalue comme prendre l'adresse (&) ne fonctionne évidemment pas de cette façon. Voici quelques différences entre les types de tableau et les types de pointeur:

  • Les types de tableau ne peuvent pas être attribués ou transmis.types de pointeur peut
  • pointeur vers le réseau et le pointeur de pointeur existe différents types
  • tableau de tableaux et tableau de pointeurs sont différents types
  • Le sizeof d'un type de réseau est le temps de la longueur de la taille du type de composant; la sizeof d'un pointeur est juste la taille d'un pointeur
1

Lors de la création d'un tableau, tel que int monTableau [10] [20], est affecté un bloc contigu garanti de mémoire à partir de la pile, et normale L'arithmétique de tableau est utilisée pour trouver n'importe quel élément dans le tableau.

Si vous souhaitez allouer ce "tableau" 3D à partir du tas, vous utilisez malloc() et récupérez de la mémoire. Ce souvenir est "stupide". C'est juste un morceau de mémoire, qui devrait être considéré comme un vecteur. Aucun élément de la logique de navigation associé à un tableau ne vient avec cela, ce qui signifie que vous devez trouver un autre moyen de naviguer dans le tableau 3D souhaité.

Depuis votre appel à malloc() renvoie un pointeur, la première variable dont vous avez besoin est un pointeur pour tenir le vecteur de int * s que vous allez avoir besoin de tenir certaines données entier réel IE:

int * pArray;

... mais ce n'est toujours pas le stockage que vous souhaitez stocker les entiers. Ce que vous avez est un tableau de pointeurs, pointant actuellement vers rien. Pour obtenir le stockage de vos données, vous devez appeler malloc() 10 fois, chaque malloc() allouant de l'espace pour 20 entiers sur chaque appel, dont les pointeurs de retour seront stockés dans le vecteur * pArray des pointeurs. Cela signifie que

int * parray

doit être changé pour

int ** parray

pour indiquer à juste titre qu'il est un pointeur sur la base d'un vecteur de pointeurs. Le premier déréférencement, * pArray [i], vous place quelque part dans un tableau de pointeurs int, et le 2ème déréférencement, * p [i] [j], vous place quelque part dans un tableau d'ints, pointé par un pointeur int dans pArray [i].

IE: vous avez un nuage de vecteurs entiers dispersés sur tout le tas, pointé par un tableau de pointeurs gardant la trace de leurs emplacements. Pas du tout similaire à Array [10] [20] alloué statiquement à partir de la pile, qui est tout le stockage contigu, et n'a pas un seul pointeur dans n'importe où.

Comme d'autres ont échappé à, la méthode de tas de pointeur ne semble pas avoir beaucoup de choses à faire à première vue, mais s'avère être massivement supérieure. Tout d'abord, vous pouvez free() ou realloc() pour redimensionner la mémoire de tas quand vous voulez, et il ne sort pas de la portée lorsque la fonction retourne. Plus important encore, les codeurs C expérimentés organisent leurs fonctions pour fonctionner sur des vecteurs lorsque cela est possible, où 1 niveau d'indirection est supprimé dans l'appel de fonction. Enfin, pour les grands tableaux, par rapport à la mémoire disponible, et en particulier sur les grandes machines partagées, les gros morceaux de mémoire contiguës sont souvent indisponibles et ne sont pas compatibles avec d'autres programmes nécessitant de la mémoire. Les codes avec de grands tableaux statiques, alloués sur la pile, sont des cauchemars de maintenance.

Ici, vous pouvez voir que la table est juste une coquille rassemblant des pointeurs vectoriels retournés par des opérations vectorielles, où tout intéressant se produit au niveau du vecteur, ou au niveau de l'élément. Dans ce cas particulier, le code vectoriel dans VecRand() est calloc() en mémoire propre et renvoyant le pointeur de retour de calloc() à TblRand(), mais TblRand a la possibilité d'allouer aussi le stockage de VecRand(), simplement en remplaçant l'argument NULL à VecRand() avec un appel à calloc()

/*-------------------------------------------------------------------------------------*/ 
dbl **TblRand(dbl **TblPtr, int rows, int cols) 
{ 
    int i=0; 

    if (NULL == TblPtr){ 
     if (NULL == (TblPtr=(dbl **)calloc(rows, sizeof(dbl*)))) 
      printf("\nCalloc for pointer array in TblRand failed"); 
    } 
    for (; i!=rows; i++){ 
     TblPtr[i] = VecRand(NULL, cols); 
    } 
    return TblPtr; 
} 
/*-------------------------------------------------------------------------------------*/ 

dbl *VecRand(dbl *VecPtr, int cols) 
{ 
    if (NULL == VecPtr){ 
     if (NULL == (VecPtr=(dbl *)calloc(cols, sizeof(dbl)))) 
      printf("\nCalloc for random number vector in VecRand failed"); 
    } 

    Randx = GenRand(VecPtr, cols, Randx); 
    return VecPtr; 
} 
    /*--------------------------------------------------------------------------------------*/ 

static long GenRand(dbl *VecPtr, int cols, long RandSeed) 
{ 
    dbl r=0, Denom=2147483647.0; 

    while (cols--) 
    { 
     RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF; 
     r  = sqrt(-2.0 * log((dbl)(RandSeed/Denom))); 
     RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF; 
     *VecPtr = r * sin(TWOPI * (dbl)(RandSeed/Denom)); 
     VecPtr++; 
    } 
    return RandSeed; 
}