Newsgroup: it.comp.lang.c
Titolo: realloc di char ** da altra funzione

Continuano i miei problemi di allocazione di char ** :-/
praticamente, devo riempire un char ** da una funzione diversa da quella che 
lo dichiara. Per far cio' ho provato il codice sotto ma purtroppo windows mi 
dice che il programma ha generato un errore e sara' terminato...
Uff.. che brutta domenica :-)
grazie 1000
Denis
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
int funzione1(char **pippo);
int main(void){
 int i=0;
 int result=0;
 char **termini=NULL;
 result=funzione1(termini);
 for(i=0;i<100;i++){
  printf("%s\n",termini[i]);
 }
 printf("Ho rialloccato %d pippo",realloc);
 return 0;
}
int funzione1(char **pippo){
 int i=0;
 int result=0;
 for(i=0;i<100;i++){
  pippo=(char **)realloc(pippo,sizeof(pippo)+1);
  if (pippo==NULL)
    printf("errore nella realloc di pippo!!!");
  else
   pippo[i]=strdup("CIAO");
 }
 result=sizeof(pippo);
 return result;
} 

"Dade - Home -" <cucca7...@NOSPAMgmail.com> ha scritto nel messaggio 
news:yLwCe.79108$h5.33...@news3.tin.it...
[CUT]
ho provato questa piccola modifica pensando che forse quando il char ** e' 
null fosse meglio una malloc che una realloc ma niente... il risultato non 
cambia! Trovo strano che sia un problema di allocazione della memoria, se 
cosi' fosse il realloc dovrebbe ritornarmi null invece questo non accade 
mai...
grazie
Denis
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
int funzione1(char **pippo);
int main(void){
 int i=0;
 int result=0;
 char **termini=NULL;
 result=funzione1(termini);
 for(i=0;i<100;i++){
  printf("%s\n",termini[i]);
 }
 printf("Ho rialloccato %d pippo",realloc);
 return 0;
}
int funzione1(char **pippo){
 int i=0;
 int result=0;
 for(i=0;i<100;i++){
  if(pippo==NULL)
   pippo=(char **)malloc(1);
  else


 Continuano i miei problemi di allocazione di char ** :-/
[...]

Prendiamola alla larga: in C il passaggio di argomenti avviene *sempre*
per copia. Puoi tuttavia utilizzare un puntatore per accedere (tramite
dereferenziazione) alla stessa variabile usata dal chiamante e simulare
un passaggio per reference.
Quindi se vuoi che una funzione ti modifichi un int e vuoi che tale
modifica sia visibile anche al chiamante, passerai un int *.
Generalizzando, se vuoi che una funzione modifichi una variabile di tipo
T e vuoi che la modifica sia visibile al chiamante dovrai usare un T *.
Nel tuo caso il tipo T e` char **, quindi dovrai passare T*, ovvero char
***.
Il secondo errore che fai e` quella realloc: sizeof(pippo) e` la
dimensione di un puntatore! Anche l'assegnamento di result e` sbagliato
per lo stesso motivo. sizeof puoi usarlo solo con gli array, e anche se
ci sono alcune simulitudini array e puntatori *non* sono la stessa cosa.
Per allocare un array di stringhe devi prima allocare lo spazio per un
array di char *, poi allocare lo spazio per ogni singola stringa.
Supponendo di voler allocare 100 stringhe e mantenendo la strdup (che
*non* e` una funzione prevista all'ISO C):
int funzione1(char ***pippo) {
        int i;
        char **tmp;
        /* Alloco lo spazio per un array di 100 char* */
        tmp = malloc(sizeof(char *) * 100);
        if (tmp == NULL) {
                ....
        }
 
        /* Allocazione delle singole stringhe */
        for (i = 0; i < 100; i++) {
                tmp[i] = strdup("ciao");
                if (tmp[i] == NULL) {
                        ...
                }
        }
        *pippo = tmp;
        return i;
}
Se invece vuoi ridimensionare l'array (ma in questo caso non e`
necessario), devi necessariamente tenere traccia della dimensione dello
stesso perche` non puoi ricavare questa informazione a partire dal
puntatore; sempre con il tuo esempio si puo` usare la variabile i a
questo scopo:
int funzione1(char ***pippo) {
        int i;
        char **tmp = NULL;
        char **p;
        for (i = 0; i < 100; i++) {
                p = realloc(tmp, sizeof(char *) * (i + 1));
                if (!p) {
                        /* Errore, cleanup possibile utilizzando tmp che
                         * punta ancora alla vecchia area di memoria.
                         */
                }
                p[i] = strdup("ciao");
        }
 
        *pippo = tmp;
        return i;
}
Luca
-- 
Home: 
http://kronoz.cjb.net
Windows NT crashed.
I'm the Blue Screen of Death.
No one hears your screams.

        *pippo = tmp;
        ^^^^^^^^^^^^^
        questo non l'ho capito scusa...


        questo non l'ho capito scusa...
Serve a propagare la modifica al chiamante. Se volessi modificare un
intero:
void foo(int *bar) {
        *bar = 123;
}
i.e. dereferenzio il puntatore ed assegno il valore. Stessa cosa nella
funzione sopra. Non farti confondere dal fatto che pippo e` un char** e
non un int ;)
Teoricamente avrei potuto modificare direttamente pippo:
        p = realloc(*pippo, ...);
        *pippo = p;
ma preferisco usare delle variabili temporenee quando ci sono troppi
asterischi in giro :P
Per il valore di ritorno di realloc uso un'altra variabile temporanea
perche` in questo modo, anche in caso di fallimento, continuo ad avere a
disposizione i vecchi dati (e posso almeno fare una free per evitare
leak). Se scrivessi:
tmp = realloc(tmp, ...);
in caso di fallimento la vecchia area non sarebbe piu` accessibile:
oltre ad aver perso l'accesso ai vecchi dati avrei perso la possibilita`
di liberare la vecchia area di memoria (leak).
Luca
-- 
Home: 
http://kronoz.cjb.net
"L'abilita` politica e` l'abilita` di prevedere quello che
 accadra` domani, la prossima settimana, il prossimo mese e
 l'anno prossimo. E di essere cosi` abili, piu` tardi,
 da spiegare  perche' non e` accaduto."