Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Per quanto riguarda l'uso delle stringhe in C, la mia opinione personale è che dove serva manipolazione delle stringhe molto avanzata usare il C è un controsenso.
Nonostante questo ci sono molti software scritti in C che lavorano molto con il testo, ad esempio gli editor di testo (vim tanto per dirne uno). In quei casi ho visto che a parte qualche helper di solito si preferisce andare di malloc+funzioni standard, è quello che ci si aspetta normalmente.
Un approcio che considero interessante in C è quello di sdstring, https://github.com/antirez/sds (ricordo che antirez è Salvatore Sanfilippo, autore di Redis dove si usa anche sds).
Il codice è molto facile da comprendere e la particolarità è che gli oggetti sdstring si possono passare in modo compatibile alle funzioni che vogliono un const char* con terminatore nullo.
Secondo me è molto più didattico implementare un clone di std::string semplice (magari senza tutto il lato C++ che serve per interagire con la STL, cioè iteratori e allocatore ridefinibile).
Come struttura si usa il classico puntatore + lunghezza + memoria allocata.
Di solito std::string è più complicato perché utilizza delle ottimizzazioni, una decina di anni fa era il copy-on-write, adesso mi pare che quasi tutte le librerie standard per C++ comuni utilizzino la small string optimization, ci sono molti video su youtube su questo argomento ben fatti.
Ultima modifica effettuata da lumo il 23/05/2017 alle 17:22
Ragazzi carissimi, vi ringrazio veramente tanto per la pazienza che mi riservate e per gli spunti che mi proponete. Alcuni sono in grado di comprenderli e state ben certi che ne faccio tesoro, altri volano oggettivamente un po' troppo alto sopra la mia testa.
Rimane un fatto: non sto più usando "buffer", bensì "tampone". Ovviamente, se prima abbrevviavo con "buff", ora abbrevio con "tamp" (colpa tua, lumo). Vi avverto: sono a un passo dal cominciare a usare nomenclature in piemontese... ad esempio, sostituisci_frammento() potrebbe diventare cambeja_n_toc()
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
Ragazzi carissimi, vi ringrazio veramente tanto per la pazienza che mi riservate e per gli spunti che mi proponete. Alcuni sono in grado di comprenderli e state ben certi che ne faccio tesoro, altri volano oggettivamente un po' troppo alto sopra la mia testa.
Ho ripescato la mia vecchia funzione DoppioSpazio().
Funziona (almeno pare) non ho avuto tempo di ricontrollarla per bene, mi piacerebbe poi vedere la tua di implementazione AldoBaldo.
(p.s. ho pure incluso un piccolo main() per una prova al volo se volete)
Codice sorgente - presumibilmente C++
/*
* Data una stringa, crea una stringa con l'eliminazione dei doppi spazi.
* Ritorna la dimensione della nuova stringa. Source e destination devono
* essere della stessa dimensione per il caso limite che source non avesse doppiSpazi
*** MANCANO I CONTROLLI SULL'INPUT****
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* Controlla un carattere con il successivo, se sono entrambi spazi, avanza il primo indice e ne copia solo 1
* altrimenti copia normalmente il carattere. Se si trova un doppio spazio ripete il do while
* (potrebbero esserci 3 spazii consecutivi ad esempio). Infine ritorna la dimensione nella nuova stringa pulita
Facilissimo un buffer overflow con quella funzione, sta nel mucchio "insicure e inutili" a mio avviso.
Questo è come si potrebbe fare in C++ (da standard 2011 in poi)
L'avevo scritta 10 anni fa più o meno...
Non voglio essere presuntuoso, ma per capire,
Un esempio pratico di un possibile buffer overflow?
P.s. conosco a malapena il C, il tuo codice in C++ lo capisco a malapena XD
Fermo restando l'utilità o meno (almeno un utilità didattica potrebbe averla) mi piacerebbe vedere un implementazione in C in modo da orientare le mie prossime (e vecchie) funzioni nella giusta direzione.
(Ad esempio, se avessi chiesto come parametri di input solo source, e allocato dentro la funzione destination, ritornando il puntatore a destination e demandando il compito di deallocare la stringa al chiamante, sarebbe stata più sicura?)
Ultima modifica effettuata da Mikelius il 23/05/2017 alle 21:59
constchar*po = orig;// puntatore per scorrere la stringa originale
char*pm =modf;// puntatore per scorrere la stringa modificata
size_t l =0;// per la lunghezza della stringa risultante
int spazio =0;// !=0 se si tratta di uno spazio; 0 altrimenti
while(isspace(*po))++po;// eliminiamo gli eventuali spazi iniziali
while(*po ){// finche' ci sono caratteri nella stringa originale
spazio =isspace(*po );// il carattere corrente e' uno spazio?
++l;// copia comunque, quindi la stringa modificata si "allunga"
*pm++=*po++;// spazio o no, copia il carattere corrente
if( spazio )// se il carattere appena copiato e' uno spazio...
while(isspace(*po))// ...e fintanto che ci sono spazi...
++po;// ... passa al carattere successivo
}
if(!spazio ){// l'ultimo carattere copiato e' uno spazio?
*pm ='\0';// se non lo e', "termina" la stringa modificata
}
else{// si', l'ultimo carattere e' uno spazio: eliminiamolo!
--l;// la stringa viene accorciata di un carattere (lo spazio)
*(pm-1)='\0';// il terminatore viene posto un carattere prima
}
return l;// restituisce la lunghezza della stringa modificata
}elsereturn-1;// essendo size_t senza segno, questo significa
// restituire il valore massimo possibile per size_t
}
int main(void){
char src[50]="Ciao Mondo Bello ";
char dest[50]="";
size_t dimN =0;
printf("\n**** STRINGHE INIZIALI ****\n\n");
printf("Stringa Iniziale =[%s]\n", src );
printf("Stringa Finale =[%s]\n", dest );
dimN = EliminaSpaziatureMultiple( src, dest );
printf("\n\n\n\n**** STRINGHE FINALI ****\n\n");
printf("Stringa Iniziale =[%s]\n", src );
printf("Stringa Finale =[%s]\n", dest );
printf("Lunghezza della stringa finale: %u\n", dimN );
return0;
}
Ultima modifica effettuata da AldoBaldo il 23/05/2017 alle 23:29
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
Mi piace. Comunque, come nel mio bisogna stare attenti alla memoria allocata per *modf, se nel main() si passa un Array di 2 char, ad esempio, si genera un errore.
Io prima per l'esempio di Buffer Overflow, mi riferivo al fatto di passare dei parametri "giusti" facendo ora delle prove mi accorgo che non è bene fidarsi del main() .
Io prima per l'esempio di Buffer Overflow, mi riferivo al fatto di passare dei parametri "giusti" facendo ora delle prove mi accorgo che non è bene fidarsi del main() .
Sono stato un po' brusco con "insicuro e inutile", comunque è proprio quello di cui parlo. Riscrivere la funzione non serve a molto se poi ha la stessa interfaccia insicura.
Consiglio due alternative
Codice sorgente - presumibilmente Plain Text
// ritorna la stringa senza spazi doppi, il chiamante deve occuparsi di liberare la memoria allocata dinamicamente
char* eliminaDoppiSpazi(const char* s);
oppure
Codice sorgente - presumibilmente C/C++
// ritorna la lunghezza della stringa modificata per convenienza
int eliminaDoppiSpazi(char* s);
Siccome la stringa dopo l'elaborazione non può essere più lunga di quella originale, si può usare la stessa memoria (che sicuramente è sufficiente), modificando però la stringa originale.
È un caso particolare permesso da questo algoritmo, se la lunghezza potesse aumentare non si potrebbe fare.
È anche lo stesso metodo che uso io con std::unique in C++
Una interfaccia un po' più sicura per la tua potrebbe essere questa in altri casi
Codice sorgente - presumibilmente C/C++
// ritorna la lunghezza di dest
int eliminaDoppiSpazi(const char* s1, char* dest, size_t maxDestLength);
Così si rifà un po' a strcat -> strncat, ma in questo caso non ha molto senso.