2010-06-11 18 views
9

Es la propiedad especial que a void * también se le puede asignar un puntero a un puntero y devolverlo y se recibe el valor original.¿Cuál es la diferencia entre void * y void **?

Leí esta línea en alguna parte. ¿Significa que void* y void** son iguales? ¿Cuál es la diferencia?

Editar

void* puede contener cualquier puntero. Entonces, ¿para qué se necesita void**?

+0

Necesita nulo ** cuando necesita desreferenciarlo y averiguar a qué nulo * apunta, o incluso cambiar ese nulo * a otra cosa. No puede eliminar la referencia vacía *, o no debería sin gafas de seguridad de alta resistencia. –

+0

Bueno, si quieres pensar de esa manera, ¿para qué sirven los tipos de puntero que no sean 'void * '? – JohnMcG

Respuesta

52

Un punto en un agujero negro.

El otro apunta a la cosa que apunta al agujero negro.


No son realmente la misma cosa, pero los punteros se pueden convertir en void *. Puede convertir int * en void * porque, bueno, es un puntero. void ** es todavía un puntero (solo apunta a un puntero), y como es un puntero, puede convertirlo a void *. Eso tiene sentido?

Dicho esto, no creo que he tenido un uso para un void **, pero si usted necesita una gran variedad de void * s, entonces el tipo habría void **. (En C) void * se usa a menudo para mantener un puntero a algunos datos de usuario, pero no sabrá de antemano de qué tipo serán esos datos. Si tenía una matriz de esos, entonces void **.

Dado que también tiene esto etiquetado como C++: El caso anterior no se aplica realmente: podría utilizar un std::vector<void *>. Realmente, void * podría ser cuestionable: una base abstracta podría ajustarse mejor a tus propósitos. void * es útil principalmente en C.

+9

+1. descripción épica. – Femaref

+2

He utilizado void ** como parámetro de una función que llamó a un puntero de función que se le pasó. En este caso particular, el bastón fue mutable. – Joshua

+1

+1 nuevamente. muy épico – Aaron

6

Un vacío ** es un puntero a un vacío *. Un vacío * se puede convertir de un lado a otro en cualquier tipo de puntero (incluido el vacío **). Por lo que puede hacer:

char* -> void* 
void* -> void** 
void** -> void* 
void* -> char* 

Usted puede no hacer:

char* -> void** 
void** -> char* 

por lo que no son los mismos.

2

A void * puede contener cualquier puntero. Dado que no hay objetos reales void, un void * es siempre un puntero a algún otro tipo.

A void ** es un puntero a un puntero a anular, o la dirección de un void *, es decir, la dirección de un puntero a vacío. Este es un tipo real y no tiene propiedades mágicas.

Pero como un void * puede contener cualquier puntero, también puede contener, por ejemplo, un void **.

void **f(int x) { 
    static void *y; 
    static int *iy; 
    y = &x; 
    iy = &x; 
    // return &iy; // not ok 
    return &y; // ok 
} 
+0

Tenga en cuenta que, por el contrario, un vacío ** puede contener un vacío *, NO está garantizado. –

+0

Buen punto, estaba tratando de decir eso, en realidad. Es por eso que esa línea de retorno, que intenta poner un 'void *' en 'void **', se comenta con la nota * no está bien *. – DigitalRoss

1

Una diferencia importante es que la regla que cita en negrita no se aplica a void **.

2

si desea almacenar algún puntero o cualquier cosa que probablemente use nulo *.

Sin embargo, si desea escribir una función que puede ser capaz de inicializar este puntero magia, entonces necesita pasar este argumento para esta función como nula **

void fun1(); 
int fun2(int); 
double fun3(long); 
bool fun4(int, long, double); 


int rand(void** pp) 
{ 
    switch(time()%4) 
    { 
    case 0: *pp = fun1; return 0; 
    case 1: *pp = fun2; return 1; 
    case 2: *pp = fun3; return 2; 
    case 3: *pp = fun4; return 3; 
    } 
} 

int main() 
{ 
    void* pointer; 
    int funId; 

    funId = rand(&pointer); 

    setCallback(pointer, funId); 
} 
+0

Idea correcta, pero confunde punteros de función con punteros de datos; esto no es estándar. Haga esos cuatro tipos de estructuras diferentes en su lugar y está en lo cierto. –

0

void * es un puntero (o una puntero al comienzo de una matriz de tipo desconocido). void * es un puntero a la dirección de un puntero (o un puntero al comienzo de una matriz 2D).

Además, si está escribiendo en C (y no en C++), entonces no hay ningún parámetro de referencia, solo por valor o por puntero.

E.g.

// By value C and C++ 
void MyFunction(int a) 
{ 
} 

// By pointer C and C++ 
void MyFunction(int* a) 
{ 
} 

// By reference C++ only 
void MyFunction(int& a) 
{ 
} 

Si desea una función que modifica la dirección de un puntero (por ejemplo void * ptr;)
y permite el código de llamada a por afectado por el cambio,
entonces usted necesita para pasar un puntero por referencia pase ptr a (void * &) y use ptr dentro de la función
o pase un puntero a un puntero (void **) y pase & ptr y use * ptr dentro de la función.

Cuestiones relacionadas