Sincronizza Indice |
Scarica il progetto |
Testo dell'articolo |
Stampa l'articolo |
In alcune situazioni può essere necessario invertire una stringa, dal primo all'ultimo carattere. Il suo scopo si rivela utile nelle operazioni di ricerca partendo dalla fine. Ben lo sapevano i programmatori della Microsoft, tanto che dalla versione 6 tutte le edizioni di Visual Basic includono la funzione di inversione di una stringa chiamata StrReverse.
Ma come sviluppare questa funzione con Visual Basic 5? Prima versione (lenta, senza l'utilizzo dell'API) Difficoltà: 1 / 5 Per effettuare l'inversione di una stringa sarà necessario leggere ogni carattere della stringa partendo dall'ultimo carattere e memorizzarlo nella nuova stringa. La prima soluzione consiste nell'utiilzzare l'istruzione Mid per estrarre un carattere partendo da una posizione specifica.
La funzione è semplicissima: il suo nome è SlowStrReverse (ovvero StrReverse lenta) e richiede come parametro la stringa da invertire. Al suo interno abbiamo un ciclo che parte dall'ultimo carattere della stringa e procede fino al primo. All'interno del ciclo viene estratto di volta in volta un carattere e viene aggiunto alla stringa SlowStrReverse, che restituirà alla fine della funzione, la stringa invertita. Questa procedura, tuttavia, risulta molto lenta perché l'istruzione
Mid, di volta in volta, deve estrarre un carattere specifico. Seconda versione (lenta, senza l'utilizzo dell'API) Difficoltà: 1 / 5 Questa seconda versione rappresenta una variante della versione precedente, a dimostrare l'inefficienza del metodo risultivo. Questa funzione si differenzia dalla precedente per il fatto che ogni volta che un carattere viene estratto dalla stringa, viene di fatto eliminato dalla stringa originale.
Alla riga 3 viene estratto l'ultimo carattere della stringa ed alla riga esso stesso viene eliminato, cosicchè ogni volta la stringa diventi sempre più corta. Apparentemente potrebbe sembrare un'ottimizzazione del metodo precedente
in quanto la stringa da trattare diventa regolarmente più breve;
ma in realtà non è affatto così. In linguaggio C le stringhe sono memorizzate come vettori di caratteri, ed i riferimenti ai vettori sono puntatori. Pertanto per il compilatore, estrarre il carattere in posizione n anziché m è esattamente la stessa cosa; infatti la richiesta di estrarre un carattere dalla posizione n si trasforma in una richiesta di lettura dall'area di memoria x, senza che il compilatore di fatto debba analizzare tutta la stringa. Pertanto l'operazione di accorciamento della stringa si trasforma in
un ciclo inutile che rallenta ulteriormente l'operazione di inversione
della stringa. Le due versioni saranno paragonate più avanti, ma le motivazioni appena accennate, da sole, dovrebbero bastare a dimostrare che conoscere il funzionamento delle stringhe nel linguaggio C può di fatto, evitare inutili rallentamenti.
Terza versione (veloce, con l'utilizzo dell'API) Difficoltà: 3 / 5 L'ultima versione che vedremo sarà la più efficiente, sia perché utilizzeremo funzioni API, notoriamente più veloci delle funzioni fornite dal linguaggio Visual Basic, sia perché riporteremo le stringhe al loro stato naturale, ovvero vettori di caratteri. Il codice che sembra assomiglia molto ad una soluzione di linguaggio C anziché di Visual Basic, ma si dimostra estremamente efficiente.
La funzione si chiamerà FastStrReverse (StrReverse
veloce). La funzione utilizza una funzione API di nome RtlMoveMemory, ma
ridefinita da molti, per comodità, CopyMemory. Essa richiede
tre parametri: un puntatore all'area di memoria di destinazione (pDst),
uno all'area di partenza da cui leggere (pSrc) ed un valore indicante
il numero di bytes da copiare (ByteLen). Alle righe 4 e 5 abbiamo dichiarato due vettori di caratteri (Byte) senza
dimensione fissa, di nome Buffer1 e Buffer2. Essi serviranno
per contenere i dati della stringa da invertire e lavoreremo sopra d'essi
anziché sopra le stringhe. Nota però che il secondo vettore è di un carattere più piccolo del primo vettore. Questo perché la funzione API lavora con le convenzioni C che richiedono alla fine un codice ASCII 0 di terminazione.
Alla riga 11 abbiamo la chiamata alla funzione CopyMemory. Essa
copierà i dati da Stringa al vettore Buffer1. La dimensione del
buffer da copiare è indicata in Conta1. Mediante quest'operazione, potremo richiamare i caratteri della stringa direttamente senza utilizzare l'istruzione Mid e l'elaborazione lavorerà su numeri interi, anziché su stringhe. Nel ciclo alle righe 13-16 effettueremo l'estrazione di un valore dal primo vettore e lo inseriremo nel secondo vettore. Quest'operazione risulta particolarmente veloce poiché non sono necessarie allocazioni di memoria temporanee. Così, all'uscita dal ciclo, il vettore Buffer2 conterrà la nostra stringa invertita, ma in formato ANSI invece che UNICODE. Si rende pertanto necessaria un'ultima conversione di formato prima della restituzione del risultato finale (riga 17). Difficoltà: 1 / 5 La prova delle tre versioni verrà effettuata mediante cronometrazione di un certo numero di inversioni di una stringa a scelta dell'utente. Inseriamo sopra un form una TextBoxdi nome Testo con il testo "Stringa da invertire" ed una TextBoxdi nome Ripetizioni con il testo "5000". Inseriamo anche una matrice di CommandButtondi nome Inverti, con indici da 0 a 2. Le caption dei tre pulsanti sono: "Inverti (Lento)", "Inverti (Lento 2)" e "Inverti (Veloce)". Aggiungiamo anche una Labeldi nome TempoImpiegato. Tutto il codice si riassume in una sola routine (sono naturalmente escluse le tre funzioni viste in precedenza):
Alla prima riga abbiamo dichiarato la funzione API GetTickCount che restituisce il numero di millisecondi trascorsi dall'avvio di Windows. Essa ci servirà come cronometro per testare la velocità delle tre funzioni.
Nella routine che gestisce l'eventoClick sopra i tre pulsanti, inseriremo il nostro codice cronometrato. Abbiamo dichiarato la variabile Tempo che servirà per effettuare i tempi di calcolo delle funzioni; la variabile Conta servirà per eseguire più volte le funzioni di inversione di stringa; infine la variabile Risultato conterrà la stringa invertita. Alla riga 8 viene letto il tempo iniziale dalla pressione del pulsante.
Segue un ciclo che si ripete tante volte quanto il numero scritto nella
casella di testo Ripetizioni. All'interno di tale ciclo sarà
necessario controllare quale pulsante è stato premuto, mediante
controllo del parametro Index. Ad ogni tasto premuto corrisponderà
una funzione di inversione. Solo dopo che la funzione è stata richiamata il numero di volte richiesto, la funzione potrà terminare, ma prima verrà calcolato il tempo di elaborazione (riga 16) ed esso sarà mostrato nella Label TempoImpiegato (riga 17). In chiusura della funzione, sarà cambiata la Caption del form con il risultato dell'inversione. Come
già anticipato, la funzione più veloce è la terza
(FastStrReverse), mentre si dimostra più lenta la seconda
versione (Slow2StrReverse). |
Comunque, la vera velocità della terza versione si dimostra nelle richieste di inversioni di stringhe superiori a 20 caratteri. In questo esempio, è vano richiedere che il parametro Stringa per la prima funzione (SlowStrReverse) sia passato per riferimento, anziché per valore, in quanto non è possibile passare una proprietà di un'oggetto per riferimento. Fibia
FBI
|
Torna all'indice degli HowTo |