Newsgroup: it.comp.lang.c
Titolo: [C] Un po' di confusione con char *

Sera a tutti,
lo sò che è una cosa trita e ritrita ma mi è successa una cosa che mi
ha portato qualche dubbio circa l'uso di char *.
Precisamente stò scrivendo un modulo python in c, lo dico giusto per
completezza ma non è fondamentale.
Per contenere dei dati ho creato una struct simile a quella che segue:
struct mydata_s
{
    char *appname;
    char *other;
};
ed ho una funzione che prima inizializza una variabile di tipo struct
mydata_s e in seguito un puntatore per gestire i dati della suddetta
struct:
struct mydata_s dati;
struct mydata_s *p = &dati;
riempo la struct con 0 (in seguito capirete perchè) ed richiamo una
funzione che accetta come parametro il puntatore *p.
memset(p, '\0', sizeof dati);
get_input(p); //definita come void get_input(struct mydata_s *p);
Nella funzione esamino dei dati in python (precisamente delle
pystring) e poi le converto in char * assegnando il risultato (la
stringa di tipo char *) rispettivamente a p->appname e p->other senza
ottenere alcun errore. Questo mi stà bene, ma uscendo dalla funzione e
ritornando nella funzione che ha effettuato la chiamata provo a
stampare i valori della struct puntata da p e incredibilmente ho i
valori esatti, non ottengo (null) come mi sarei aspettato, ne un
segmentation fault. Concludo dicendo che il codice completo non l'ho
postato poichè è piuttosto lungo e complesso e la parte in dubbio sono
proprio quelle due cosette... e la struct l'ho riempita di zero per
evitare il warning del compilatore circa "p may be used uninitialized
here" (o qualcosa del genere :-)
Qualcuno sà il perchè di questo comportamento? ho provato a rigenerare
il problema in un semplicissimo programma di puro C, ma ovviamente
ottengo segmentation fault se non effettuo l'allocazione dello spazio
necessario...
Quindi come è possibile?
Il tutto funziona ma ci sono particolari rischi in qualche sfortunato
evento?
Se fosse necessario semplificherò le funzioni per postare il codice
reale.
Distinti saluti e buona notte.

 segmentation fault. 
Quindi qual � il problema? Perch� ti aspettavi null?
E.

 segmentation fault. 
Senza vedere il resto del codice, presumo che
nessuno si preoccupi di rilasciare la memoria
allocata per le stringhe  e/o nessuno rimette a
NULL i due puntatori, quindi ti ritrovi degli
indirizzi (piu' o meno) validi.
Se la memoria per le stringhe e' stata veramente rilasciata
pero' puoi avere problemi, specie se nel frattempo quell'
area viene riallocata da altri....
A.

 A.
In fatti è cosi, la struct viene dichiarata nella funzione A (per
capirci), e non alloco memoria quindi non ne libero... dovrei
liberarla lo stesso anche senza averne allocata io? -magari senza
causare il crash del programma tentando di usare free su un puntatore
vuoto :).
Semplicementemi è venuto il dubbio che in determinate condizioni il
compilatore si occupasse di allocare lo spazio in modo sicuro, e
volevo quindi capire quando *devo* allocare lo spazio io e quando
posso evitare di doverlo fare.
Questi sono i miei dubbi, oltre al fatto che non avendo allocato dello
spazio io, non ne libero, aspettandomi che come ogni variabile termini
di esistere quando termina la funzione che l'ha generata. Inoltre temo
che un una data condizione questo possa diventare un bug difficile da
trovare...
A questo punto tempo di mettere mano al codice per semplificarlo e lo
posto, cosi potremmo essere più chiari.
Intanto voi cosa mi consigliate? Io non sò quanto spazio devo allocare
essendo l'input dell'utente... uno (appname) deve contenere una
posizione del filesystem e posso risolvere con FILENAME_MAX e l'altro
una stringa più breve... non volevo allocare tanta memoria poi per
niente per questo visto che funziona avevo preferito lasciare cosi, ma
non vorrei mai cadere dalla padella nella brace e soprattutto vorrei
capire come usare char* in modo sicuro :)
Grazie ancora.

errl
    //continuazione delle operazione
}
static int
get_data(PyObject *pydict_data, struct data_s *data)
{
    //controlli di routine per filtrare gli input
    //una sequenza di controlli condizionali e fatto ciò devo capire
che tipo di dato è.
    //essendo un pydict uso un array per ciclarlo quindi sò che:
    // 1 si riferisce a accl, 2 si riferisce a errl e cosi via -in
seguito i valori cresceranno-
    switch(i)
    {
        //qui assegno i valori ai puntatori ovviamente senza aver
prima allocato nulla
        case 1:
            data->accl = PyString_AsString(value);
            break;
        case 2:
            data->errl = PyString_AsString(value);
            break;
    }
}
Spero possa essere d'aiuto per una maggiore comprensione del problema
e chiedo scusa per il doppio post consecutivo.

> errl
Non capisco cosa ci sia di strano. E' in questa printf che ti 
aspetteresti null?
E.

?manu* ha scritto:

E c'ha ragione Manu difatti: googlando PyString_AsString dice 
chiaramente che la memoria ï¿œ gestita da python
char* PyString_AsString(PyObject *string)
Returns a NUL-terminated representation of the contents of string. The 
pointer refers to the internal buffer of string, not a copy. The data 
must not be modified in any way, unless the string was just created 
using PyString_FromStringAndSize(NULL, size). It must not be 
deallocated. If string is a Unicode object, this function computes the 
default encoding of string and operates on that. If string is not a 
string object at all, PyString_AsString() returns NULL and raises TypeError.
Cioï¿œ anzichï¿œ darti una copia, ti dï¿œ l'originale che si ï¿œ allocato lui, 
ma tu non devi toccarlo o lui impazzisce.
Non vedo dov'ï¿œ il problema.

 Non vedo dov' il problema.
Hai perfettamente ragione, ora mi è chiaro che mi restituisce proprio
l'originale, mentre io pensavo mi desse una copia di tipo char * della
variabile in pystring. Mi deve proprio essere sfuggito quell'internal
buffer, infatti pensavo si riferisse al contenuto della stringa, non
proprio il puntatore della memoria.
Grazie mille a tutti quelli che mi hanno aiutato,
almeno sono tranquillo che non è uno di quegli errori che non si
presentano subito per poi impedirmi di continuare quando il sorgente
diventa più complicato :-)
Buona serata a tutti.