Newsgroup: it.comp.lang.c
Titolo: void *

Ciao a tutti, spesso ho sentito parlare dei puntatori a void * come 
qualcosa da evitare. Però non ho capito il perchè! Il mio problema è che 
dovrei fare una lista di oggetti allocati a run-time(blocchi di stringhe 
principalmente) e non posso conoscere la dimensione e il tipo di ogni 
blocco, così ho pensato di costruirmi la lista che ha un puntatore void 
*next. Così facendo sarebbe possibile aggiungere alla lista blocchi di 
qualiasi tipo? che controindicazioni ci sarebbero(ammesso che funzioni 
:-) )?
Grazie
Wezzy

I puntatori di tipo void non sono propriamente da evitare, ma semplicemente
da trattare "con le pinze", ossia con ancora più attenzione dei normali
puntatori.
La caratteristica principale di tale puntatore è quella di potergli
assegnare e di poter essere assegnato a qualsiasi altro tipo di puntatore;
proprio per questa sua potenzialità, tuttavia, e qua sorgono i problemi, il
suo riferimento NON potrà essere risolto e NON vi si potrà applicare
l'aritmetica dei puntatori.
Il loro utilizzo è limitato, personalmente ne ho fatto uso ben poche volte;
nel tuo caso, se hai proprio la necessità di accogliere nella tua lista vari
tipi di array (è questo che intendi per "blocchi", giusto?) e non riesci a
trovare un altro approccio, i puntatori void possono risolverti il problema,
anche se non capisco perchè tu lo voglia chiamare *next: se intendi lista
dinamica, come suppongo, il puntatore al nodo successivo (che si indica di
solito con next) non ha nulla a che fare con i void...se non ho ben capito
il tuo problema fammelo sapere!
In ogni caso, se decidi di utilizzarli, fà attenzione quando (e se) dovrai
dereferenziarli: ricordati che non potrai farlo direttamente, dovrai prima
convertirli nel puntatore appropriato e se sbaglierai tipo avrai un errore
in run-time!
Saluti,
Sergio

 :-) )?
Il tuo problema non si puo` risolvere con i puntatori a void: la soluzione al problema si chiama
*polimorfismo*, ed e` uno dei concetti chiave su cui si basa la OOP. Purtroppo pero` il C non ha il
supporto per il paradigma OO, anche se e` possibile usarla, con qualche sforzo ed un po` di
attenzione. Se vuoi ti posto un pezzo di codice di esempio.
Ciao,
Cecco

 
Ciao & Grazie
Wezzy

 
In realtà sto pensando di passare al C++, che non conosco troppo, ma è 
un buon motivo per approfondirlo! Anche perchè ho visto che le Stl 
contengono delle Liste che sembrano fare al caso mio. ti sarei grato 
comunque se mi postassi qualche esempio.
Grazie
Wezzy

:-) )?
Per fare una lista devi usare le strutture e il puntatore lo dichiari
del tipo della struttura.
Un esempio potrebbe essere questo:
typedef struct s_elem {
	char data[LEN];
	struct s_elem *next;
} elem;
cosi' hai dichiarato una struttra. Come puoi notare il puntatore e' a
struct s_elem ovvero alla stessa struttura. Si potrebbe quasi dire che
e' un costrutto ricorsivo nel senso che continua a ritornare a se
stesso finche' non incontra NULL, ma sarebbe forse una forzatura.
In un caso come questo comunque il dato interno alla struttura si
utilizza cosi':
elem pippo;   /* dichiarato una variabile di nome pippo */
pippo.data = "Giovanni"
pippo.(*next) = puntatore
In modo piu' generale ti troverai a usare solo altri puntatori quindi
elem *testa;    /* Ecco la testa della lista */
elem *item;       /* Questo e' il singolo elemento della lista */
testa = creaElem(stringa);
Dove creaElem e' una funzione che passato un dato restituisce un
puntatore a una nuova testa di lista.
e quindi item->next.data indichera' il campo data dell'elemento
successivo a item. Stai bene attento a non perdere il valore della
testa altrimenti non vai piu' da nessuna parte e perdi tutti i dati
allocati.
Spero di non aver scritto bestialita'... Se ho scritto troppo scusami.
 
-- 
try: troll = "Brain"
except TypeError, data: 
   troll.plonk()
Co-Responsabile Hardware Information & Technology 
http://hit.edengames.net

In realtà mi ero espresso male io. Ciò che voglio fare è una struttura 
del tipo
struct oggetto
{
     //mi segno che tipo di oggetto è
     char tipo[30];
     //indica la posizione dei dati
     void *data;
     //prossimo elemento della lista
     struct oggetto *next;
}
(vd il mio post in risposta a Sergio B.)
così ogni elemento della struttura ha un collegamento all'oggetto che ho 
appena allocato! La domanda era se posso collegare oggetti di qualsiasi 
tipo e dimensione ad un puntatore void*.
Grazie mille per il tuo codice comunque.
Wezzy


oppure utilizzando dei flag, dei valori numerici...
Fà comunque attenzione.
Spero di essere stato d'aiuto, se ti va fammi sapere,
Saluti,
Sergio B.

 comunque se mi postassi qualche esempio.
Infatti il C++ supporta non solo OOP, ma anche la programmazione generica, grazie alle ai template.
Comunque ti posto un esempio di polimorfismo in C: nel main usa un array statico di puntatori a
Base, ma e` fatto solo per dimostrare come fare; se vuoi usare una struttura dati dinamica, basta
semplicemente realizzare una lista che abbia per nodi puntatori a Base.
Ciao,
Cecco
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// classe base, dichiara solo un puntatore a funzione
// che deve essere ridefinito nelle derivate
// (sarebbe una funzione virtuale in C)
typedef struct Base {
    void (*print)(struct Base *);
} Base;
// prima classe derivata
typedef struct A {
    Base base;
    int i;
} A;
// seconda classe derivata
typedef struct B {
    Base base;
    char *str;
} B;
// per usare il polimorfismo e` necessario
// passare un oggetto della classe base
void printA(Base* b) {
    A *acast = (A*) b; // cast per accedere a A::i
    printf("%d\n", acast->i);
}
A* initA(A*a, int val) {
    a->base.print = printA;
    a->i = val;
    return a;
};
void printB(Base *b) {
    B *bcast = (B*)b;
    printf("%s\n", bcast->str);
}
B* initB(B *b, char *str) {
    b->base.print = printB;
    b->str = (char*)malloc(strlen(str+1));
    strcpy(b->str, str);
    return b;
};
int main(void)
{
    A a;
    B b;
    Base *arr[2];
    initA(&a, 10);
    initB(&b, "Hello world!");
    arr[0] = (Base*)&a;
    arr[1] = (Base*)&b;
    arr[0]->print(arr[0]); // richiama printA
    arr[1]->print(arr[1]); // richiama printB
    return 0;
}

 attraverso la lista. Può funzionare?
No, perche` per poter usare l'oggetto a cui punta un void* dovresti fare un opportuno cast, ma una
volta che lo hai inserito nella lista non sai piu` a che oggetto si riferiva. Il C e` troppo
tipizzato rispetto a Python: devi usare necessariamente il polimorfismo.
Ciao,
Cecco

Ok grazie mille ti farň sapere.
Ciao
Wezzy

 ha scritto nel messaggio
news:hHhU9.111708
Grazie mille, il tuo codice mi sta illuminando, mi scuso se sforo nell'OT ma
a questo punto non mi conviene fare tutto con le classi C++ come verrebbe il
codice in versione C++? il tutto penso risulti piů chiaro! DAto che non ho
ancora cominciato posso usare il c++ invece del C se, come dici, č molto piů
fantaggioso(e ti dirň l'idea mi stuzzica cosě finalmente me lo imparo un
po').
Grazie Mille
Wezzy

 Wezzy
Prego, ciao
Cecco

Il tuo problema non si puo` risolvere con i puntatori a void:
Si` che si puo`.
Il problema, pero`, e` che non si puo` usare un puntatore non
tipizzato per il puntatore "next", come il nostro amico vuol fare.  
Infatti il puntatore in questione deve, appunto, puntare al prossimo
nodo, quindi ad una struttura.  Poi, il puntamento ai dati contenuti
nel nodo si puo` fare benissimo con un puntatore void, a meno di
"castare", al momento di usare i dati.  Il C++ e` sicuramente un
linguaggio in cui vi sono strumenti migliori per risolvere un problema
del genere (sto pensando alle liste mesase a disposizione dalla
libreria standard).  Ma questa e` solo un'alternativa e il
polimorfismo non c'entra nulla, semmai si parla di programmazione
generica (v. classi template).