Newsgroup: it.comp.lang.c
Titolo: come sempre confuso sui puntatori....

Ciao a tutti, mio malgrado mi trovo a programmare cose che non sono in
grado di fare (nella fattispecie portare su FreeBSD un modulo di python
che e' dipendente dall'architettura, per la gestione dei processi).
Senza entrare nei dettagli ho una variabile
char **argv;
(che sta dentro ad una struct, ma per il momento lasciamo stare) che
devo riempire con quello che ritorna una funzione:
char **kvm_getargvv(…);
Ora, io coi puntatori e i free() mi incasino sempre, sara' per la poca
abitudine a usare il C. Ad ogni modo:
argv = kvm_getargvv(…);
funziona, secco. Pero' a valle mi ritrovo una serie di segfault quando
devo andare a fare i free(). Di fatto credo che sto cercando di liberare
zone della memoria che poco hanno a che fare con gli argomenti del
processo...
Ecco, quello che vorrei sapere, e scusate la banalita' della domanda...
e' come fare a duplicare quello che ritorna da kvm_getargvv in argv,
stringa per stringa...
grazie
d

dawe ha scritto:
<snip>
Nel codice seguente ti scrivo un esempio. Ho costruito una funzione
kvm_getargvv() fittizia, che restituisce oltre al puntatore a puntatore,
anche il numero di puntatori puntati dal puntatore (in *pn). Tieni
presente che questa funzione � solo un esempio, alloca memoria senza
deallocarla, ma a te interessa sapere come duplicare il risultato di
questa funzione, quindi concentrati sul resto del codice. Se il tuo
sistema fornisce la strdup() puoi usare quella, altrimenti usa la dupstr()
che ho scritto nel codice.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *dupstr(const char *s) {
    char *ds = (s!=0) ? malloc(strlen(s)+1) : 0;
    if (ds)
      strcpy(ds, s);
    return ds;
}
char **kvm_getargvv(size_t *pn) {
    /* stub di esempio:
       la memoria allocata in questa funzione
      non viene deallocata da nessuna parte */
    char **result = malloc((*pn=3)*sizeof(char*));
    result[0] = dupstr("pippo");
    result[1] = dupstr("biancaneve");
    result[2] = dupstr("paperino");
    return result;
}
int main()
{
    char **argv = 0;
    size_t i, n = 0;
    /* lettura del risultato della funzione in un valore temporaneo */
    char **tmp_argv = kvm_getargvv(&n);
    /* allocazione memoria per il duplicato */
    argv = malloc(n*sizeof(char*));
    /* duplicazione del risultato della funzione */
    for (i=0; i<n; i++)
       argv[i] = dupstr(tmp_argv[i]);
    /* scrittura a video */
    for (i=0; i<n; i++)
       printf("argv[%d] = "%s"n", i, argv[i]);
    /* deallocazione della copia argv */
    for (i=0; i<n; i++)
       free(argv[i]);
    free(argv);
    return 0;
}
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 Nel codice seguente ti scrivo un esempio. 
Molto gentile... mi metto subito al lavoro :-)
d

     char *ds = (s!=0) ? malloc(strlen(s)+1) : 0;
char *ds = (s!=NULL) ? malloc(strlen(s)+1) : NULL;
<snip>
Un commento ulteriore:
molto spesso di questi vettori non sai la dimensione, ma sono NULL-
terminati (le variabili d'ambiente, per esempio).
Fosse questo il caso, prima devi conoscere la lunghezza, allocare e
copiare.
qualcosa tipo (non ho provato, ma il concetto è questo):
int i;
char **tmp_argv, **p
tmp_argv = kvm_getargvv();
for (i=0, p=tmp_argv; p!=NULL; ++i) p=tmp_argv[i];
p = malloc(i*sizeof(*p));
for (; i>=0; --i)
  if (tmp_argv[i])
    p[i] = strdup(tmp_argv[i]);
  else p[i] = NULL;
P.S. Su FreeBSD la strdup() ci dovrebbe essere.

copiare.
E' quello che fa il mio codice. Solo che fa restituire il valore alla
funzione tramite variabile per riferimento, ma � chiaro che � solo un
esempio. Se la lunghezza si desume dal valore sentinella, il codice di
duplicazione va bene uguale.

 E' quello che fa il mio codice.
Sicuro, ho solo cambiato un ciclo, tutto qua.

 zero 
No, NULL secondo lo standard � sempre definito come 0.


 zero
No, NULL secondo lo standard � sempre definito come 0. Anche perch�, se
non fosse cos�, tutti i controlli if (!p) { ... } non varrebbero.
Aggiungo ci� che afferma Stroustrup a riguardo del C++:
"In C++, the definition of NULL is 0, so there is only an aesthetic
difference. I prefer to avoid macros, so I use 0. Another problem with
NULL is that people sometimes mistakenly believe that it is different from
0 and/or not an integer. In pre-standard code, NULL was/is sometimes
defined to something unsuitable and therefore had/has to be avoided.
That's less common these days."



Il C++ non c'interessa (almeno, relativamente a questo NG).
Di che mi ricordo io, il compilatore con i valori di NULL ci fa un po'
quel che vuole - l'importante per il programmatore è sapere che lo 0,
nel contesto dei puntatori, è un puntatore nullo.
Non ho le specifiche C sottomano e su internet in quattro e
quattr'otto non ho trovato il punto preciso. Quello che ho trovato che
ricorda di più i punti è: "a constant 0 in a pointer context is
converted into a null pointer at compile time" e "in an
initialization, assignment, or comparison when one side is a variable
or expression of pointer type, the compiler can tell that a constant 0
on the other side requests a null	pointer, and generate the correctly-
typed null pointer value." Il che non dice niente sull'effettivo
valore della costante NULL.
Mi riprometto di vedere i punti che riporto sotto appena torno a casa
(me li segno come reference per me stesso, ma se qualcuno li ha
sottomano e li riporta non mi lamento mica, eh =D )
K&R1 Sec. A7.7 p. 190, Sec. A7.14 p. 192 K&R2 Sec. A7.10 p. 207, Sec.
A7.17 p. 209 ANSI Sec. 3.2.2.3 ISO Sec. 6.2.2.3 H&S Sec. 4.6.3 p. 95,
Sec. 6.2.7 p. 171
Ciao!

 quel che vuole 
Non � cos�.



in C++, non in C!
Secondo lo standatd [C99] la macro NULL e' definita
come null pointer a 0 [NULL==((void*)(0))]
Poi che sia la stessa cosa, ok, giusto perche' in C
la conversione e' implicita :-)
-----------------------------------------------------------------------
An integer constant expression with the value 0, or such an expression 
cast to type
void *, is called a null pointer constant.55) If a null pointer constant 
is converted to a
pointer type, the resulting pointer, called a null pointer, is 
guaranteed to compare unequal
to a pointer to any object or function.
55) The macro NULL is defined in <stddef.h> (and other headers) as a 
null pointer constant; see 7.17.
-----------------------------------------------------------------------
Bye,
8.

 > quel che vuole 
Riferimenti:
"6.3.2.3 Pointers
[...]
3 An integer constant expression with the value 0, or such an expression 
cast to type void *, is called a null pointer constant.55)
[...]
55) The macro NULL is defined in <stddef.h> (and other headers) as a null 
pointer constant; see 7.17."
L'"implementation-dependant" del punto 7.17 non significa che NULL pu� 
assumere qualsiasi valore, ma che il valore 0 pu� essere definito in modi 
diversi: 0, 0L, (void*)0, come specificato dal rationale: "NULL can be 
defined as any null pointer constant. Thus existing code can retain 
definitions of NULL as 0 or 0L, but an implementation may also choose to 
define it as (void*)0".


 come null pointer a 0 [NULL==((void*)(0))]
NULL *PUO'* essere definita a quel modo, che � dipendente 
dall'implementazione, non *DEVE*. Lo leggi l'"or" del pezzo: "or such an 
expression[...]"?



Hai ragione, ma mi riferivo a quanto scritto da te:
 >No, NULL secondo lo standard � sempre definito come 0.
il che non e' (sempre) vero.
Ciao
8.


Apposto, dice quello che ho scritto anch'io:
con 0 stai sicuro, ma niente vieta che NULL possa essere un altro
valore.
Nessun punto dice che 0 è il *solo* valore possibile per un null
pointer.

il che non e' (sempre) vero.
Mi riferivo a quanto riportato dallo standard. La costante � sempre 0.
Lo standard attribuisce a NULL il valore 0. Le singole definizioni,
invece, dipendono dal sistema. Ma come sia definito NULL nello
specifico non ha molta importanza relativamente al codice che ho
scritto nel messaggio principale.

pointer.
Niente affatto. Rileggi. Dice ESATTAMENTE questo, invece.

[...]dipendono dal sistema.
Nel senso che dipende dal sistema il modo in cui questo zero �
"macroizzato" (brrr).

 pointer.
Dipende: se con 0 intendi una sequenza di bit tutti a 0 allora e' vero:
ho lavorato su una piattaforma in cui il NULL e' 0x1777.
Se con 0 intendi il puntatore nullo allora non e' vero: alla fine
0 in contesto di puntatore e NULL devono avere la stessa rappresentazione.
Sulla piattaforma di cui sopra, ottieni:
int x = 0; // tutti bit 0
int *y = 0; // i 13 bit bassi a 1
int *z = NULL; // i 13 bit bassi a 1
Non ricordo piu' pero' cosa succede se fai un cast di un intero:
int *k = (void *)x // puntatore non valido? NULL ? boh?
ciao
Giacomo

 Giacomo
Sì, è esattamente lo scenario che avevo in mente io. Fortunatamente
c'è chi è più chiaro di me nelle spiegazioni :-)
il concetto è che: ((int)NULL == 0) non è sempre vero.


credo che kvm_getargv restituisca una lista che termina con il null
quindi non può fare semplicemente:
char **p = kvm_getargv(...);
while(*p)
{
  char * nuova_stringa_da_rilasciare_con_free = strdup(*p);
  inserisci_in_mia_struttura(nuova_stringa_da_rilasciare_con_free);
  p++;
}
?????

 
Mmm... interessante...
d