Newsgroup: it.comp.lang.c
Titolo: [newbie] funzione per la modifica una stringa

Ciao,
provenendo da un linguaggio dove i puntatori e/o tipi sono gestiti da
"qualcun altro", sto trovando alcune (tante?) difficoltà nella loro
gestione e sono qui a chiedervi un aiuto.
Ho una funzione che devo usare, non scritta da me, che è così definita :
void info __P((char *, ...));
per usarla "semplicemente", nessun problema, solo che vorrei farle fare
anche il lavoro di formattazione "a la sprintf", quindi sto cercando di
creare una funziona _myinfo che, dato dei messaggi in ingresso, faccia:
(scusate il linguaggio non C)
  my_info (msgin, argument)
     char msg[strlen(msgin) + strlen(argument)]
     return sprintf(msgin, msg, argument)
info( my_info("test %s", "1"))
info( my_info("test %s", "2"))
Solo che mi sto incartando su come far creare il buffer a my_info e non
alla funzione chiamante (per non ripetere il codice misurare la
lunghezza del buffer e creare il buffer stesso)
Un'idea, senza successo, era di far ritornare un indirizzo di memoria a
my_info contenente l'indirizzo della stringa creta, ma non ce l'ho fatta.
Qualche consiglio?
Michele

On Mar 28, 12:23 pm, Michele Petrazzo

Non credo di aver capito bene il tuo problema con i buffer:
char *ptr = malloc(120);
dentro ptr hai un puntatore a 120 char (oppure NULL se l'allocazione è
fallita). A questo punto usi ptr come qualsiasi altra variabile:
return ptr; /* ritorna il valore del puntatore */
func(ptr); /* passi il valore del puntatore alla funzione */
quando vuoi liberare la memoria puntata da ptr, lo puoi fare dove/
quando vuoi con una
free(ptr);
Ho risposto alla domanda o c'erano altri dubbi? :-|
Ciao!


Non capisco esattamente cosa vuoi fare.
Dal prototipo della info() dovrebbe già essere in grado di funzionare 
come desideri tu, cioè fare il lavoro di formattazione "a la sprintf".
Il prototipo che fornisci è indicativo di una funzione con numero di 
argomenti variabile, cioè dovrebbe funzionare come la printf().
Se invece la vuoi duplicare ma con un target diverso (un buffer) temo 
che non sia facile misurate la dimensione del buffer fino a quando non 
la processi con la sprintf().  Ma prima devi allocare un buffer che ti 
contenga sicuramente tutta la stringa espansa.  La sprintf() o le 
simili ad argomenti variabili (vsprintf(), vsnsprintf() snprintf()) 
ritornano tutte il numero di caratteri scritti nel buffer.
Generalmente si alloca un buffer (con malloc()) di dimensioni 
generiche e sufficienti per l'applicazione.  Poi si usa la snprintf() 
anziché la sprintf() per scrivere nel buffer verificando poi che il 
numero di caratteri inseriti nel buffer sia inferiore alla dimensione 
allocata.  Se la dimensione del buffer è insufficiente a contenere la 
stringa si può espandere la stringa con la realloc() e ripetere 
l'operazione di scrittura.
int len = 0;
char *buffer = NULL;
int size = 100;
do {
	buffer = realloc(buffer, size);
	len = vsnprintf(buffer, size, ..............);
	if (len < size) break;
	size *= 2;
} while (1);
return buffer;
Questo è un veloce esempio che va corredato con quanto necessario per 
le funzioni con un numero di argomenti variabile (vedi stdarg.h).
Ciao
Giovanni
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   < 
http://giovanni.homelinux.net/
 >

On 28 Mar, 12:23, Michele Petrazzo

ciao.
Ti do un consiglio di tipo "filosofico": ricordati che in c non hai
garbage collection quindi devi ricordarti tu di deallocare lo spazio
ogni volta.
Per lavorare correttamente con la tua my_info dovresti fare cosi':
// my_info alloca un buffer e lo restituisce
// scrivendo solo info( my_info(...) ) => memory leak
char *p;
p = my_info("test %s", "1");
info( p );
free( p );
Dal momento che e' facile dimenticarsi di fare le deallocazioni
(soprattutto se provieni da linguaggi con GC ;) di solito
e' pericoloso adottare una strategia come la tua (cioe' fare
allocare lo spazio direttamente da my_info) perche' porta
facilmente a memory leak
In genere in c si consiglia di scrivere funzioni che lavorano su
stringhe allocate e liberate all'esterno e che vengono passate
come parametro.
Naturalmente non e' una regola ferrea ed e' solo una linea guida
comunque tutta la libreria standard e' concepita cosi'. Tant'e'
che la funzione strdup() che allocava da sola lo spazio per la
stringa duplicata e' stata tolta dallo standard.
ciao
Giacomo

 Ciao!
Grazie,
Michele

 Giovanni
Grazie,
Michele


Michele


Ma sì dai, butta il Python che è per perdenti e diventa un vero
uomo ;-)
Ciao!

 (N_str *2)  // *2 perché ho i formati a %s
Il codice che ho postato è generico e funziona con qualsiasi formato 
e, a mio avviso, è più semplice di un complicato calcolo delle 
lunghezze delle singole stringhe.
Il calcolo che fai sembra semplice, ma il problema che io vedo sono 
'N_str` e la lunghezza delle stringhe.  Non conoscendo N_str devi 
praticamente fare il parsing della prima stringa per calcolare quante 
ne seguiranno e poi calcolare le lunghezze.  Dato che questo calcolo 
già lo fanno la sprintf() e simili perché non lasciarlo fare a loro?
Tra l'altro, per rispondere, mi sono riletta la documentazione delle 
varie printf() e mi sono accorto che il codice suggerito potrebbe 
essere più efficiente modificandolo come segue:
char *my_info(char *fmt,...)
{
    int len = 0;
    char *buffer = NULL;
    int size = 100;
    va_list ap;
    va_start(ap, fmt);
    do {
        buffer = realloc(buffer, size);
        len = vsnprintf(buffer, size, fmt, ap);
        if (len < size) break;
        size = len + 1;
    } while (1);
    va_end(ap);
    return buffer;
}
Tuttavia ribadisco che questo lavoro dovrebbe già farlo la funzione di 
cui hai postato il prototipo.



il progetto, open, è pppoe server (pacchetto ppp sotto debian)
<cut>
Grazie della perfetta spiegazione, ma ho optato per un codice più
"semplice", considerate le mie conoscenze di C!
Michele

 Ciao!
Ciao,
Michele