Quand un double pointeur être utilisé en C? Quelqu'un peut-il expliquer avec un exemple?
Ce que je sais, c'est qu'un double pointeur est un pointeur vers un pointeur. Pourquoi aurais-je besoin d'un pointeur vers un pointeur?
Quand un double pointeur être utilisé en C? Quelqu'un peut-il expliquer avec un exemple?
Ce que je sais, c'est qu'un double pointeur est un pointeur vers un pointeur. Pourquoi aurais-je besoin d'un pointeur vers un pointeur?
Si vous voulez avoir une liste de caractères (un mot), vous pouvez utiliser char *word
Si vous voulez une liste de mots (une phrase), vous pouvez utiliser char **sentence
Si vous voulez une liste de phrases (un monologue), vous pouvez utiliser char ***monologue
Si vous voulez une liste de monologues (une biographie), vous pouvez utiliser char ****biography
Si vous voulez une liste de biographies (une bio-bibliothèque), vous pouvez utiliser char *****biolibrary
Si vous voulez une liste de bio-bibliothèques (un ??lol), vous pouvez utiliser char ******lol
... ...
oui, je sais que ces peut-être pas le meilleur des structures de données
Une des raisons est que vous souhaitez modifier la valeur du pointeur est passé à une fonction comme argument de la fonction, pour ce faire, vous avez besoin de pointeur vers un pointeur.
En termes simples, l'Utilisation **
lorsque vous souhaitez conserver (OU de conserver changement dans) l'Allocation de Mémoire ou de la Cession, même en dehors d'un appel de fonction. (Donc, Passer une telle fonction avec double pointeur arg.)
Cela peut ne pas être un très bon exemple, mais va vous montrer l'utilisation de base:
void allocate(int** p)
{
*p = (int*)malloc(sizeof(int));
}
int main()
{
int* p = NULL;
allocate(&p);
*p = 42;
free(p);
}
J'ai vu un très bon exemple, aujourd'hui, à partir de ce blog, que je résume ci-dessous.
Imaginez que vous avez une structure de nœuds dans une liste, ce qui est probablement
typedef struct node
{
struct node * next;
....
} node;
Maintenant, vous voulez mettre en œuvre un remove_if
de la fonction, qui accepte la suppression du critère rm
comme l'un des arguments et parcourt la liste liée: si une entrée satisfait au critère (quelque chose comme rm(entry)==true
), son nœud sera retiré de la liste. En fin de compte, remove_if
retourne la tête (qui peut être différent de l'original de la tête) de la liste chaînée.
Vous pouvez écrire
for (node * prev = NULL, * curr = head; curr != NULL; )
{
node * const next = curr->next;
if (rm(curr))
{
if (prev) // the node to be removed is not the head
prev->next = next;
else // remove the head
head = next;
free(curr);
}
else
prev = curr;
curr = next;
}
que votre for
boucle. Le message est sans doubles pointeurs, vous devez maintenir un prev
variable pour ré-organiser les pointeurs, et de gérer les deux cas différents.
Mais avec le double de pointeurs, vous pouvez réellement écrire
// now head is a double pointer
for (node** curr = head; *curr; )
{
node * entry = *curr;
if (rm(entry))
{
*curr = entry->next;
free(entry);
}
else
curr = &entry->next;
}
Vous n'avez pas besoin d'un prev
maintenant, parce que vous pouvez modifier directement ce qu' prev->next
a souligné.
Pour rendre les choses plus claires, nous allons suivre un peu le code. Lors de la suppression:
entry == *head
: il sera *head (==*curr) = *head->next
-- head
pointe maintenant vers le pointeur de la nouvelle tête de nœud. Vous faites cela en modifiant directement head
s'contenu d'un nouveau pointeur.entry != *head
: de même, *curr
est-ce que prev->next
a souligné, et maintenant les points de entry->next
.Peu importe dans quel cas, vous pouvez ré-organiser les pointeurs de manière unifiée avec double pointeurs.
Les pointeurs de pointeurs également venir dans maniable comme des "poignées" à la mémoire où vous voulez passer autour d'une "poignée" entre les fonctions de re-localisable mémoire. Que, fondamentalement signifie que la fonction peut modifier la mémoire pointé par le pointeur à l'intérieur de la poignée variable, et chaque fonction ou l'objet à l'aide de la poignée va point à la récemment déplacé (ou attribués) de la mémoire. Les bibliothèques comme à ce faire avec "opaque" types de données, c'est-types de données ont été vous n'avez pas à vous soucier de ce qu'ils font avec la mémoire de relever le faire, il vous suffit de passer autour de la "poignée" entre les fonctions de la bibliothèque pour effectuer certaines opérations sur la mémoire ... la bibliothèque de fonctions d'allocation et de réallocation de la mémoire sous le capot sans avoir explicitement de s'inquiéter au sujet du processus de gestion de la mémoire ou lorsque la poignée est en arrêt.
Par exemple:
#include <stdlib.h>
typedef unsigned char** handle_type;
//some data_structure that the library functions would work with
typedef struct
{
int data_a;
int data_b;
int data_c;
} LIB_OBJECT;
handle_type lib_create_handle()
{
//initialize the handle with some memory that points to and array of 10 LIB_OBJECTs
handle_type handle = malloc(sizeof(handle_type));
*handle = malloc(sizeof(LIB_OBJECT) * 10);
return handle;
}
void lib_func_a(handle_type handle) { /*does something with array of LIB_OBJECTs*/ }
void lib_func_b(handle_type handle)
{
//does something that takes input LIB_OBJECTs and makes more of them, so has to
//reallocate memory for the new objects that will be created
//first re-allocate the memory somewhere else with more slots, but don't destroy the
//currently allocated slots
*handle = realloc(*handle, sizeof(LIB_OBJECT) * 20);
//...do some operation on the new memory and return
}
void lib_func_c(handle_type handle) { /*does something else to array of LIB_OBJECTs*/ }
void lib_free_handle(handle_type handle)
{
free(*handle);
free(handle);
}
int main()
{
//create a "handle" to some memory that the library functions can use
handle_type my_handle = lib_create_handle();
//do something with that memory
lib_func_a(my_handle);
//do something else with the handle that will make it point somewhere else
//but that's invisible to us from the standpoint of the calling the function and
//working with the handle
lib_func_b(my_handle);
//do something with new memory chunk, but you don't have to think about the fact
//that the memory has moved under the hood ... it's still pointed to by the "handle"
lib_func_c(my_handle);
//deallocate the handle
lib_free_handle(my_handle);
return 0;
}
Espérons que cela aide,
Jason
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.