2016-01-26 12 views
5

Viene visualizzato il seguente avviso: incompatible pointer types 'void**' and 'int* [2]'.vuoto ** puntatore e vuoto * [] come parametri di funzione

Quando provo a compilare il codice seguente:

#include <stdlib.h> 

void func1(void *arr[]) { } 

int main() { 
    int *arr[2]; 
    for (int i = 0; i < 5; i++) { 
     arr[i] = (int*)malloc(sizeof(int)); 
     *(arr[i]) = 5; 
    } 
    func1(arr); 
} 

Ora, funziona quando ho gettato arr con (void**), e non riuscivo a trovare una ragione per questo. Inoltre ho scoperto che ho anche bisogno di lanciare nel codice seguente:

#include <stdlib.h> 

void func1(void **arr) { } 

int main() { 
    int **arr; 
    int i[] = { 1, 2 }; 
    int j[] = { 3, 4 }; 
    *arr = i; 
    *(arr+1) = j; 
    func1(arr); //Doesn't compile unless I use (void*) or (void**) casting 
} 

so che se il parametro di una funzione è un puntatore a void possiamo passare ad essa tutto ciò puntatore che vogliamo senza fusione, perché tutti i puntatori sono della stessa dimensione allora perché non posso passare un puntatore a un puntatore allo stesso modo?

+4

Forse cercavi 'int * arr [5];'? –

+4

Perché il puntatore a un puntatore non è un puntatore a 'void'. Solo un puntatore a 'void' è garantito per essere compatibile con altri puntatori. –

+0

Se i puntatori erano array, non sarebbero chiamati "puntatori". – Olaf

risposta

2

Tutti i tipi di puntatore, tra cui oggetto int *, sono garantiti per essere interconvertibili con void *, ma non sono intercambiabili . La rappresentazione del tipo int * non deve essere uguale alla rappresentazione del tipo void * (anche se in pratica, lo è quasi sempre), quindi non c'è conversione automatica da un puntatore a int * (ad esempio int **) a un puntatore a void * (cioè void **). Non è sicuro assumere che una cosa puntata di un tipo possa essere correttamente reinterpretata come una cosa dell'altro tipo puntato.

nota, tra l'altro, che questo:

se il parametro di una funzione è un puntatore a void possiamo passare ad essa tutto ciò puntatore che vogliamo senza fusione, perché tutti i puntatori sono della stessa dimensione

è una caratterizzazione errata. I puntatori sono non richiesti per tutti essere della stessa dimensione. È necessario solo che ogni puntatore dell'oggetto possa essere convertito per digitare void * e che il risultato di tale conversione round-trip sia uguale al puntatore originale.

Prendi a cuore i commenti di Lundin: gli array non sono indicatori. Tuttavia, i valori del tipo di array fanno decadere in molti casi, incluso quando appaiono come argomenti di funzione o come l'operando di destra di un operatore di assegnazione.

4

Ci sono diversi problemi con il tuo secondo frammento di codice:

void func1(void** arr) { } 
int main() { 
    int** arr; 
    int i[] = {1,2}; 
    int j[] = {3,4}; 
    *arr = i; 
    *(arr+1) = j; 
    func1(arr); //Doesn't compile unless I use (void*) or (void**) casting 
} 

Non si può mai inizializzare arr per puntare a un puntatore o un array di puntatori a int. Non è inizializzato, quindi il suo valore può essere qualsiasi cosa. Quando si imposta *arr su i, si richiama un comportamento non definito.

Inoltre, int ** e void ** non sono tipi interoperabili, non è possibile convertirli l'uno in modo implicito. La logica di questo è che su alcuni sistemi rari, int * e void * potrebbero avere una rappresentazione diversa.La trasmissione di un puntatore a int * come puntatore a void * sarebbe errato come il puntatore a float come puntatore a double. Su sistemi in cui la rappresentazione è la stessa, puoi semplicemente scrivere il cast esplicito.

Ecco una versione corretta:

#include <stdlib.h> 

void func1(void **arr) { } 

int main(void) { 
    int *int_pointer_array[2]; 
    int **arr = &int_pointer_array; 
    int i[] = { 1, 2 }; 
    int j[] = { 3, 4 }; 
    *arr = i;  /* this line modifies int_pointer_array[0] */ 
    *(arr+1) = j; /* this line modifies int_pointer_array[1] */ 
    func1((void **)arr); 
    return 0; 
} 
+0

La "versione corretta" causa ancora un comportamento non definito anche se i tipi di puntatore avevano la stessa dimensione e rappresentazione. Inoltre viola la rigida regola di aliasing ('int *' è aliasato come 'void *') –

+0

@MM: lo fa, ma in funzioni separate, è improbabile che causi un problema se la rappresentazione di 'int *' e 'void *' sono uguali – chqrlie