C Aide du pointeur: équivalence tableau / pointeur

Dans cet exemple de code de jouet:

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 faire en sorte que les modifications persistent en dehors de la fonction.

Cela fait partie d’un très gros devoir, et cette question aborde le problème sans me permettre de copier la solution. On me donne une signature de fonction qui accepte un int ** en tant que paramètre et je suis censé coder la logique pour remplir ce tableau. J’avais l’impression que le déréférencement & someArray dans la fonction fillArray () me donnerait le tableau requirejs (un pointeur sur le premier élément) et que l’utilisation de l’access à l’élément de tableau entre crochets me donnerait la position nécessaire qui doit être atsortingbuée . Cependant, je ne peux pas comprendre pourquoi je reçois une erreur de segmentation.

Merci beaucoup!

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

Il suffit de passer le tableau à la fonction lorsqu’il se décompose en un pointeur sur le premier élément:

 void fillArray(int* someArray, int* blah) { int i; for (i=0; i 

et invoqué:

 fillArray(someArray, blah); 

Les modifications apscopes aux éléments seront visibles en dehors de la fonction.

Si le code réel allouait un tableau dans fillArray() un int** serait requirejs:

 void fillArray(int** someArray, int* blah) { int i; *someArray = malloc(sizeof(int) * MAX); if (*someArray) { for (i=0; i 

et invoqué:

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

Lorsque vous créez un tableau, tel que int myArray [10] [20], un bloc de mémoire contigu garanti est alloué à partir de la stack et l’arithmétique de tableau normale est utilisée pour rechercher un élément donné dans le tableau.

Si vous voulez allouer ce “tableau” 3D à partir du tas, utilisez malloc () et récupérez de la mémoire. Ce souvenir est “muet”. C’est juste un morceau de mémoire, qui devrait être considéré comme un vecteur. Aucun des opérateurs logiques de navigation avec un tableau ne l’accompagne, ce qui signifie que vous devez trouver un autre moyen de naviguer dans votre tableau 3D souhaité.

Étant donné que votre appel à malloc () renvoie un pointeur, la première variable dont vous avez besoin est un pointeur destiné à contenir le vecteur des int * s dont vous aurez besoin pour contenir un élément IE de données de type entier:

int * pArray;

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

int * pArray

doit être changé pour

int ** tableau

d’indiquer correctement qu’il s’agit d’un pointeur sur la base d’un vecteur de pointeurs.

Le premier déréférencement, * pArray [i], vous amène quelque part dans un tableau d’interseurs, et le deuxième déréférencement, * p [i] [j], vous amène quelque part dans un tableau d’ints, pointé par un pointeur int tableau [i].

IE: vous avez un nuage de vecteurs entiers dispersés sur tout le tas, pointé par un tableau de pointeurs gardant une trace de leurs emplacements. Pas du tout semblable à Array [10] [20] alloué de manière statique à partir de la stack, qui est tout le stockage contigu, et ne contient aucun pointeur nulle part.

Comme d’autres l’ont laissé entendre, la méthode du tas basée sur un pointeur ne semble pas avoir grand intérêt pour elle à première vue, mais s’avère être massivement supérieure.

D’abord et avant tout, vous pouvez libérer () ou realloc () pour redimensionner la mémoire de tas à tout moment, sans que la scope de celle-ci ne disparaisse au retour de la fonction. Plus important encore, les codeurs C expérimentés organisent leurs fonctions pour opérer 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ë ne sont souvent pas disponibles et ne sont pas conviviaux pour les autres programmes nécessitant de la mémoire. Les codes avec de grands tableaux statiques, alloués sur la stack, sont des cauchemars de maintenance.

Ici, vous pouvez voir que la table est juste un shell rassemblant des pointeurs de vecteurs renvoyés par des opérations vectorielles, où tout ce qui est intéressant se passe au niveau du vecteur, ou au niveau des éléments. Dans ce cas particulier, le code de vecteur dans VecRand () appelle calloc () et renvoie le pointeur de retour de calloc () vers TblRand (), mais TblRand a la possibilité d’allouer également le stockage de VecRand (). simplement en remplaçant l’argument NULL à VecRand () par 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; } 

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 sur un tableau et est de type int (*)[MAX] . La fonction prend un pointeur sur un pointeur, c’est-à-dire int ** , qui doit pointer sur une variable de pointeur quelque part en mémoire. Il n’y a pas de variable de pointeur dans votre code. Que pourrait-il éventuellement pointer?

Une valeur de tableau peut se dégrader implicitement en une valeur de pointeur pour son premier élément dans certaines expressions. Quelque chose qui nécessite une valeur 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 tableaux ne peuvent être ni atsortingbués ni passés. Les types de pointeurs peuvent
  • Pointeur vers tableau et pointeur vers pointeur sont de types différents
  • Les tableaux de tableaux et les tableaux de pointeurs sont de types différents
  • La sizeof d’un type de tableau est la longueur multipliée par la taille du type de composant; la taille d’un pointeur est juste la taille d’un pointeur