42 votes

Utilise plusieurs niveaux de déréférences de pointeur?

Lorsque l'utilisation de pointeurs dans n'importe quelle langue nécessite que quelqu'un en utilise plusieurs, disons un triple pointeur. Quand est-il judicieux d'utiliser un triple pointeur au lieu d'utiliser simplement un pointeur normal?

Par exemple:

 char  * * *ptr;
 

au lieu de

 char *ptr;
 

57voto

IfLoop Points 59461

chaque étoile doit être lu comme "qui pointé par un pointeur" donc

char *foo;

est "char qui pointé par un pointeur foo". Cependant

char *** foo;

est "char qui pointé par un pointeur qui pointe vers un pointeur qui pointe vers un pointeur foo". Donc toto est un pointeur. À cette adresse est un deuxième pointeur. À l'adresse pointée par là, c'est un troisième pointeur. Un déréférencement de la troisième pointeur de résultats dans un char. Si ce n'est, il est difficile de faire beaucoup de cas, pour que.

Il est toujours possible d'obtenir un travail utile, cependant. Imaginez que nous sommes en train d'écrire un substitut pour le bash, ou tout autre procédé de contrôle du programme. Nous voulons gérer nos processus invocations dans un objet orienté vers les...

struct invocation {
    char* command; // command to invoke the subprocess
    char* path; // path to executable
    char** env; // environment variables passed to the subprocess
    ...
}

Mais nous voulons faire quelque chose de fantaisie. Nous voulons avoir une façon de parcourir tous les différents ensembles de variables d'environnement comme on le voit par chaque sous-processus. pour ce faire, nous nous réunissons chaque ensemble d' env des membres de l'invocation des instances dans un tableau env_list et le passer à la fonction qui traite avec ça:

void browse_env(size_t envc, char*** env_list);

11voto

Randy Marsh Points 3229

Si vous travaillez avec des "objets" en C, vous avez probablement ce:

struct customer {
    char *name;
    char *address;
    int id;
} typedef Customer;

Si vous souhaitez créer un objet, il vous faudrait faire quelque chose comme ceci:

Customer *customer = malloc(sizeof Customer);
// Initialise state.

Nous sommes à l'aide d'un pointeur à un struct ici parce qu' struct arguments sont passés par valeur et nous avons besoin de travailler avec un objet. (Aussi: Objective-C, une orientée objet wrapper langage C, utilise en interne mais visiblement pointeurs vers structs).

Si j'ai besoin de stocker plusieurs objets, j'utilise un tableau:

Customer **customers = malloc(sizeof(Customer *) * 10);
int customerCount = 0;

Depuis une variable de tableau en C points pour le premier point, j'utilise un pointeur... encore une fois. Maintenant, j'ai le double de pointeurs.

Mais imaginez maintenant que j'ai une fonction qui filtre le tableau et retourne un nouveau. Mais imaginez qu'il ne peut pas via le mécanisme de retour, car il doit retourner un code d'erreur-ma fonction accède à une base de données. J'ai besoin de le faire par le biais d'une référence argument. C'est ma fonction de signature:

int filterRegisteredCustomers(Customer **unfilteredCustomers, Customer ***filteredCustomers, int unfilteredCount, int *filteredCount);

La fonction prend un tableau de clients et renvoie une référence à un tableau de clients (qui sont des pointeurs vers une struct). Il prend également le nombre de clients et renvoie le nombre de filtré les clients (de nouveau, en référence de l'argumentation).

Je peux l'appeler de cette façon:

Customer **result, int n = 0;
int errorCode = filterRegisteredCustomers(customers, &result, customerCount, &n);

Je pourrais continuer à imaginer des situations plus... C'est sans l' typedef:

int fetchCustomerMatrix(struct customer ****outMatrix, int *rows, int *columns);

Évidemment, je serais un horrible et/ou sadique développeur de quitter de cette façon. Donc, à l'aide de:

typedef Customer *CustomerArray;
typedef CustomerArray *CustomerMatrix;

Je peux faire ça:

int fetchCustomerMatrix(CustomerMatrix *outMatrix, int *rows, int *columns);

Si votre application est utilisée dans un hôtel où vous utilisez une matrice par niveau, vous aurez probablement besoin d'un tableau à une matrice:

int fetchHotel(struct customer *****hotel, int *rows, int *columns, int *levels);

Ou tout simplement ceci:

typedef CustomerMatrix *Hotel;
int fetchHotel(Hotel *hotel, int *rows, int *columns, int *levels);

Ne m'obtenez pas le même commencé sur un tableau d'hôtels:

int fetchHotels(struct customer ******hotels, int *rows, int *columns, int *levels, int *hotels);

...disposées dans une matrice (une sorte de grand hôtel de société?):

int fetchHotelMatrix(struct customer *******hotelMatrix, int *rows, int *columns, int *levels, int *hotelRows, int *hotelColumns);

Ce que j'essaie de dire, c'est que vous pouvez l'imaginer fou des applications pour de multiples indirections. Juste assurez-vous d'utiliser typedef si le multi-pointeurs sont une bonne idée et que vous décidez de les utiliser.

(Est-ce la nombre de post comme une demande de SevenStarDeveloper?)

5voto

Brian R. Bondy Points 141769

Un pointeur est simplement une variable qui contient une adresse mémoire.

Si vous utilisez un pointeur vers un pointeur, quand vous voulez pour contenir l'adresse d'un pointeur de variable.

Si vous souhaitez retourner un pointeur, et vous êtes déjà à l'aide de la variable de retour pour quelque chose, on passe l'adresse d'un pointeur. La fonction déréférence le pointeur de sorte qu'il peut définir la valeur du pointeur. I. e. le paramètre de cette fonction est un pointeur vers un pointeur.

Plusieurs niveaux d'indirection sont également utilisées pour les dimensions des tableaux. Si vous souhaitez revenir à 2 dimensions d'un tableau, utilisez un triple pointeur. Lors de leur utilisation pour les multiples dimensions des tableaux être bien prudent de jeter correctement comme vous allez à travers chaque niveau d'indirection.

Voici un exemple de retour d'un pointeur de valeur par l'intermédiaire d'un paramètre:

//Not a very useful example, but shows what I mean...
bool getOffsetBy3Pointer(const char *pInput, char **pOutput)
{
  *pOutput = pInput + 3;
  return true;
}

Et vous appelez cette fonction comme suit:

const char *p = "hi you";
char *pYou;
bool bSuccess = getOffsetBy3Pointer(p, &pYou);
assert(!stricmp(pYou, "you"));

5voto

René Nyffenegger Points 14898

Baguette d'ImageMagicks a une fonction qui est déclarée comme

 WandExport char* * * * * * DrawGetVectorGraphics    (  const DrawingWand  *) 
 

Je n'invente rien .

4voto

Matt J Points 15475

Les tableaux N-dimensionnels alloués dynamiquement, où N> 3, nécessitent trois niveaux d'indirection ou plus en C.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X