Newsgroup: it.comp.lang.c
Titolo: strncat: comportamento assurdo!

Voglio ottenere e' una stringa formata in questo modo:
<host>:<port>/<name>, passandogli due char* e un int. La cosa funziona
egregiamente finche' non decommento la riga segnalata (nel codice che
allego piu' giu'), ossia quando provo a concatenare al resto della
stringa anche quella che contiene il nome del servizio al quale mi devo
collegare...
Qualcuno mi sa spiegare perche'?
int conn(char **conc, const char *host, int port, const char *name) {
	char ports[6];
	int i = snprintf(ports, 6, "%d", port);
	char *out;
	strncat(out, host, strlen(host));
	strncat(out, (char *) ":", 1);
	strncat(out, ports, strlen(ports));
	strncat(out, (char *) "/", 1);
        /* RIGA INCRIMINATA!!!!!
	strncat(out, name, strlen(name));
        */
	*conc = malloc(strlen(out));
	memcpy(*conc, out, strlen(out));
	return 0;
}
Grazie dell'attenzione, ciao!
GePs

 char *out;
Ok, alla fine ho capito che il problema e' nel fatto che dichiarando
cosi' questa variabile, alloco un certo spazio dal quale pero' poi
"sforo" con le strncat. Se facio una cosa del genere
char out[MAX_SIZE];
oppure
char *out;
out = malloc(MAX_SIZE);
la cosa funziona, ma sono sempre limitato da MAX_SIZE.
Quello che vorrei chiedervi a questo punto e' se c'e' un maledetto modo
per non stabilire a priori la massima lunghezza della mia stringa di
output...

 [CUT]
contrordine: e' vero che la cosa funziona se imposto un MAX_SIZE, ma e'
anche vero che ho fatto una prova tenendo la dichiarazione char *out e
passando alla funzione stringhe da un char, e il programma segmenta lo
stesso....
Qualcuno saprebbe fornirmi una spiegazione?

 char out[MAX_SIZE];
Ultimo aggiornamento: mi sono accorto che facendo cosi' ho dei
caratteri spuri all'inizio della stringa finale, quindi nemmeno va
bene...
Scusate i 4 messaggi, ma sono alla frutta...

 [CUT]
Versione finale e funzionante. Scusate il casino, la prossima volta ci
penso un po' di piu' prima di postare :P.
int conn(char **conc, const char *host, int port, const char *name)
{
	// conversione da intero a char* di port
	char ports[6];
	int i = snprintf(ports, 6, "%d", port);
	// lunghezza sottostringhe
	int h_len = strlen(host);
	int p_len = strlen(ports);
	int n_len = strlen(name);
	// lunghezza totale
	int len = h_len + p_len + n_len + 2;
	// variabile locale d'appoggio
	char *out;
	out = malloc(len);
	// concatenamenti
	strncat(out, host, h_len);
	strncat(out, (char *) ":", 1);
	strncat(out, ports, p_len);
	strncat(out, (char *) "/", 1);
	strncat(out, name, n_len);
	// controllo
	//printf("conn: %s\n", out);
	*conc = malloc(len);
	memcpy(*conc, out, len);
	return 0;
}

 
LP

                     */
Spiegagli il problema: tu usi strncat per copiare le stringhe. Il problema è 
che la memora non essendo inizializzata, la strncat potrebbe pensare che ci 
sia già una stringa e iniziare da un punto X.
Inoltre usare la strncat indicando il numero massimo di caratteri da copiare 
non è una gran furbata, perchè così facendo la strncat non copia lo 0 finale 
(che è fuori computo) (per questo ti è stato suggerito di fare una 
memset(out, 0, len)
Esempio
"Pippo" = 'P', 'i', 'p', 'p', 'o', 0
strlen("Pippo") = 5
char *c = (char*) malloc(10000);
*c = 0;
strcat(c, "Pippo");
Ora c punta a 'P', 'i', 'p', 'p', 'o', 0
*c = 0;
strncat(c, "Pippo", strlen("Pippo"));
Ora c punta a 'P', 'i', 'p', 'p', 'o' NON TERMINATA! strncat ha copiato i 
primi 5 caratteri!!
cosa sarebbe successo con la memset:
Immaginiamo che questa sia la memoria dopo la memset
00000000000000000000000000000000000
Ora ci scriviamo Pippo NON TERMINATA
Pippo000000000000000000000000000000
Ora Pippo è terminata (bella forza... tutta la memoria era composta da 
stringhe ben terminate)
Capirai cmq che questo non è un metodo "ottimale" di fare le cose. Non sei 
un programmatore di VB. Se programmi in C devi cercare di essere "veloce". 
Perchè non è ottimale?
Vediamolo.
Allora, tu computi un tot di strlen, quindi ogni stringa viene analizzata 
carattere per carattere.
Fai una memset pari alla lunghezza calcolata, quindi scrivi X caratteri.
Ogni strncat per trovare il punto di inserzione deve leggersi tutta la 
stringa precedente. Quindi è come se facesse tante strlen ogni volta di una 
stringa più lunga.
Ogni strncat copia il suo bel pezzo di stringa.
Se ci pensi quella stringa è stata letta e riletta a bizzeffe.
Vediamo un metodo più veloce:
I len li calcoli come prima.
Ora, visto che tanto i len li hai calcolati tutti, puoi però usare solo 
strcpy usando i vari len come punti di partenza:
out = (char*)malloc(out + h_len + 1 + p_len + 1);
*out = 0;
strcpy(out, host);
*(out + h_len) = ':';
strcpy(out + h_len + 1, ports);
*(out + h_len + 1 + p_len) = '/';
strcpy(out + h_len + 1 + p_len + 1, name);
CPU consumata? Allora, tu computi un tot di strlen, quindi ogni stringa 
viene analizzata carattere per carattere.
Ogni strcpy copia il suo bel pezzo di stringa.
Osserva che i caratteri singoli li ho inseriti direttamente invece che usare 
strcpy (è quasi di sicuro più veloce (su architetture standard E' più 
veloce. Qualcuno potrebbe inventarsi un architettura "strana" in cui NON E' 
più veloce), perchè la strcpy deve fare dei controlli per vedere se ha 
raggiunto il fine stringa)
Addirittura, se sei un amante del brivido, potresti copiare usando memcpy 
(così non copieresti i terminatori di stringa centrali) e magari aggiungere 
lo 0 a mano (questo perchè dopo ogni strcpy tu avevi una stringa ben 
terminata (osserva però che dopo gli inserimenti di singoli caratteri ciò 
non era vero). Inoltre la memcpy di solito è più veloce della strcpy, perchè 
può copiare i caratteri a blocchi (cosa significa: se hai una stringa di 4 
lettere "ABCD" (ignorando lo 0 finale) su un Pentium ti occupa 4 bytes. La 
strcpy dovrebbe copiarla carattere per carattere. Però un Pentium è in grado 
di fare operazioni a 32 bits, quindi potrebbe copiarla con un'unica 
operazione (32 bits = 4 bytes) (lascia perdere cosa succede se la stringa è 
di 5 caratteri. memcpy NON è così stupida. Copierà 4 caratteri e poi 1 
carattere)
out = (char*)malloc(out + h_len + 1 + p_len + 1);
*out = 0;
memcpy(out, host, h_len);
*(out + h_len) = ':';
memcpy(out + h_len + 1, ports, p_len);
*(out + h_len + 1 + p_len) = '/';
memcpy(out + h_len + 1 + p_len + 1, name, p_name);
*(out + h_len + 1 + p_len + p_name) = 0;

Mi sembra che la strncat() aggiunga il terminatore di stringa.
Vi risulta diversamente???
Ciao

 Vi risulta diversamente???
Mea culpa... la prima volta non aveva terminato
--- bye 

 Scusa se quoto il tuo codice sotto il mio commento
Ma figurati! Grazie per la risposta!

 [CUT]
Cutto solo per questioni di spazio: stampero' il tuo messaggio e lo
appicichero' al K&R!
Grazie mille!

 Mea culpa... la prima volta non aveva terminato
Quindi posso andare tranquillo sul fatto che la strnlen() aggiunge il
carattere di fine stringa (la pagina man in effetti su questo e'
chiara...)? In ogni caso devo sempre tenerne conto nelle malloc(),
giusto?

 la cosa funziona, ma sono sempre limitato da MAX_SIZE.
Ma non puoi usare la malloc dopo che sai già quanto spazio allocare?
out = (char*)malloc(strlen(stringa1) + strlen(stringa2));
strcpy(out, stringa1);
strcat(out, stringa2); 

 out = (char*)malloc(strlen(stringa1) + strlen(stringa2));
malloc(... +1) // ricordati dello 0

 malloc(... +1) // ricordati dello 0
Hai ragione, ciao 

 65535)
      return 1;
   if('\0' == host[0] || '\0' == name[0])
      return 1;
   snprintf(ports, sizeof(ports), "%d", port);
   strLen = sizeof(ports) +2; // Inutile stare a fare tanto i difficili
                              // se la conversione in caratteri della
porta
                              // e' lunga 1, 2 o 5... E due caratteri
sono
                              // sempre necessari per ':' e '/'
    strLen += strlen(host);
    strLen += strlen(name);
    *conc = malloc(strLen); // aggiungere 1 non serve perche' e' gia'
stato
                            // considerato in sizeof(ports);
    if(NULL != *conc)
    {
       *conc[0] = '\0';
       strcat(*conc, host);
       strcat(*conc, ":");
       strcat(*conc, ports);
       strcat(*conc, "/");
       strcat(*conc, name);
    }
    else
       return 1;
    return 0;
}
HTH
C:\>iao Angelo
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG