Docsity
Docsity

Prepara i tuoi esami
Prepara i tuoi esami

Studia grazie alle numerose risorse presenti su Docsity


Ottieni i punti per scaricare
Ottieni i punti per scaricare

Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium


Guide e consigli
Guide e consigli


esercizi sulle stringhe, Esercizi di Programmazione C

In questo documento trovate 5 esercizi svolti sulle stringhe in C. Prima del codice completo con la risposta troverete il ragionamento svolto, passo a passo, su come si arriva effettivamente alla soluzione. I prerequisiti sono: variabili, conoscenza della dualità tipo char e int del C, operatori logici, array e indirizzamento dei loro elementi, cicli for e while

Tipologia: Esercizi

2022/2023

In vendita dal 13/04/2023

frnmst
frnmst 🇮🇹

3 documenti

1 / 19

Toggle sidebar

Questa pagina non è visibile nell’anteprima

Non perderti parti importanti!

bg1
Raccolta di 5 esercizi svolti in C
sulle stringhe
Premessa
In questo documento trovate 5 esercizi svolti sulle stringhe in C.
I prerequisiti sono:
variabili
conoscenza della dualità tipo char e int del C
operatori logici
array e indirizzamento dei loro elementi
cicli for e while
Prima del codice completo con la risposta troverete il ragionamento svolto su
come si arriva effettivamente alla soluzione. Sono presenti anche alcuni
approfondimenti in Python e C++ legati agli esercizi.
Buono studio!
Esercizio 1
Consegna
Data una stringa (array di tipo char) chiamata array, covertire i caratteri dalla a (A) alla
z (Z) da minuscolo a maiuscolo e viceversa.
Suggerimento: prendi una tabella ASCII e fai la differenza in numero decimale tra il
carattere a e A. Guarda se esiste un pattern anche per le altre lettere.
Esempio:
stringa = "thiS Is a WORD!"
risultato = "THIs iS A word!"
Sovrascrivere il risultato in array usando questa traccia:
Franco Masotti, 2023 | https://blog.franco.net.eu.org | 1
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13

Anteprima parziale del testo

Scarica esercizi sulle stringhe e più Esercizi in PDF di Programmazione C solo su Docsity!

Raccolta di 5 esercizi svolti in C

sulle stringhe

Premessa

In questo documento trovate 5 esercizi svolti sulle stringhe in C.

I prerequisiti sono:

  • variabili
  • conoscenza della dualità tipo char e int del C
  • operatori logici
  • array e indirizzamento dei loro elementi
  • cicli for e while

Prima del codice completo con la risposta troverete il ragionamento svolto su

come si arriva effettivamente alla soluzione. Sono presenti anche alcuni

approfondimenti in Python e C++ legati agli esercizi.

Buono studio!

Esercizio 1

Consegna

Data una stringa (array di tipo char) chiamata array, covertire i caratteri dalla a (A) alla

z (Z) da minuscolo a maiuscolo e viceversa.

Suggerimento: prendi una tabella ASCII e fai la differenza in numero decimale tra il

carattere a e A. Guarda se esiste un pattern anche per le altre lettere.

Esempio:

stringa = "thiS Is a WORD!" risultato = "THIs iS A word!"

Sovrascrivere il risultato in array usando questa traccia:

Franco Masotti, 2023 | https://blog.franco.net.eu.org | 1

#include #include #include

int main ( void ){ char array[ 100 ] = "thiS Is a WORD!";

/* Vostro codice */

// Controllo se l'algoritmo funziona correttamente. assert(strcmp(array, "THIs iS A word!") == 0 );

return 0 ; }

Figure 1. Una tabella ASCII, licenza CC

Soluzione

Esistono vari metodi per la soluzione di questo esercizio.

Come scritto nel suggerimento, se guardiamo nella tabella ASCII sopra, la

rappresentazione in numeri decimali dei caratteri a e A sono rispettivamente 97 e 65.

97 - 65 = 32. Proseguiamo con b e B: 98 - 66 = 32. Questo pattern vale fino a z e Z. Questo

significa che per andare da minuscolo a maiuscolo dobbiamo sottrarre 32 alla

rappresentazione decimale. Per contro, se dobbiamo andare da maiuscolo a minuscolo

dobbiamo sommare 32.

Incominciamo a impostare la soluzione. Sappiamo che da qualche parte dobbiamo fare

l’operazione di conversione. Ovviamente bisogna anche iterare tutta la stringa.

Partiamo con questo pseudocodice:

2 | Franco Masotti, 2023 | https://blog.franco.net.eu.org

return 0 ; }

① Importiamo assert.h per verificare la correttezza dell’algoritmo

② string.h ci serve per chiamare strcmp

③ Iteriamo tutta la stringa

④ Troviamo le minuscole e facciamo la conversione

⑤ Troviamo le maiuscole e facciamo la conversione

⑥ La funzione assert permette di verificare se il nostro algoritmo funziona. Viene

spesso usata in fase di debug. Se quello che si trova dentro assert è falso il

programma termina immediatamente con un errore. La funzione strcmp confronta

una stringa con un altra. Se le due stringhe in input sono uguali la funzione ritorna

0. Quindi, usando assert assieme a strcmp possiamo verificare di aver fatto tutto

correttamente

NOTE

Per risolvere questo esercizio è anche possibile utilizzare le funzioni

isupper, islower, toupper, tolower definite in ctype.h. L’approfondimento

qui sotto, anche se in C++, riporta un’altra soluzione che utilizza queste

funzioni.

Approfondimento

Qui sotto trovate la soluzione in C++ usando alcune funzioni integrate. La logica è la

stessa della soluzione originaria in C.

#include #include

int main ( void ) { std::string array = "thiS Is a WORD!"; int i = 0 ;

while (array[i] != '\0') { if (isupper(array[i])) { array[i] = tolower(array[i]); }

else if (islower(array[i])) { array[i] = toupper(array[i]); }

i++; }

4 | Franco Masotti, 2023 | https://blog.franco.net.eu.org

std::cout << array;

assert(array.compare("THIs iS A word!") == 0 );

return 0 ; }

Esercizio 2

Consegna

Data una stringa (tipo char *) chiamata array, invertirla e salvare il risultato in result.

Non è consentito sapere a priori la lunghezza, quindi non si può usare la funzione

strlen oppure codificare la lunghezza direttamente nel codice.

Per esempio:

array = "Questa e' una stringa di prova" result = "avorp id agnirts anu 'e atseuQ"

Usare questa traccia

#include

int main ( void ) { char array[ 100 ] = "Questa e' una stringa di prova"; char result[ 100 ];

/* Vostro codice */

printf("%s\n", result);

return 0 ; }

Soluzione

Una possibile soluzione è quella di calcolare la lunghezza con un ciclo while e poi

leggere dalla fine della stringa per proseguire al contrario usando un ciclo for.

int length = 0 , i;

while ... length++;

Franco Masotti, 2023 | https://blog.franco.net.eu.org | 5

④ Aggiungo il carattere terminatore alla fine della stringa risultato

Soluzione alternativa

È anche possibile invertire una stringa senza calcolare a priori la lunghezza ma

comunque scorrendola normalmente dall’inizio fino alla fine. Quando si è giunti alla

fine si scorre al contrario salvando carattere per carattere in result.

#include

int main ( void ) { char array[ 100 ] = "Questa e' una stringa di prova"; char result[ 100 ];

int i = 0 , j = 0 , done = 0 , go_back = 0 ;

while (!done) { if (array[i] == '\0') ① { go_back = 1 ; i--; }

if (go_back) { result[j] = array[i]; ② j++; ③ i--; } else i++; ④

if (go_back && i == -1 ) ⑤ done = 1 ; }

result[j] = '\0';

printf("%s\n", result);

return 0 ; }

① Una volta arrivati in fondo alla stringa, si va indietro di una posizione per saltare il

carattere terminatore. Setto anche il flag go_back che dice di spostare l’indice

indietro.

② Salvo un carattere per volta nella stringa result

③ Proseguo sulla casella successiva di result e sulla casella precendente di array

Franco Masotti, 2023 | https://blog.franco.net.eu.org | 7

④ Proseguo sulla casella successiva di array perché devo ancora arrivare alla fine della

stringa.

⑤ Setto il flag done per uscire dal ciclo. In questo modo si evita di andare in underflow

leggendo la stringa originale array

Esercizio 3

Consegna

Modificare l’esercizio precedente per fare in modo che la stringa venga letta

dall’utente all’interno di un ciclo.

Quando l’utente inserisce la stringa EOF il programma deve terminare e si deve

stampare a video il programma e' terminato.

Non è consentito usare funzioni quali strcmp, strlen, ecc…

Potete usare la traccia precedente.

Soluzione

Possiamo estendere la soluzione precedente mettendola all’interno di un ciclo while,

così:

while

Per sapere se l’utente ha inserito esattamente "EOF\0" si può procedere carattere per

carattere. Non sapendo a priori la lunghezza della stringa bisogna controllare di non

raggiungere il carattere terminatore '\0'.

Possiamo migliorare lo pseudocodice precedente con questo:

done = false;

while (!done) { scanf ...

if (array[0] != '\0' && array[0] == 'E' && array[1] != '\0' && array[1] == 'O' && array[2] != '\0' && array[2] == 'F'

8 | Franco Masotti, 2023 | https://blog.franco.net.eu.org

return 0 ; }

① Rimaniamo all’interno del ciclo finchè non viene settato il flag done

② Usiamo il classico scanf

③ Controllo se l’utente ha immesso esattamente "EOF\0"

④ Il codice all’interno dell' if è uguale a quello dell’esercizio precedente.

WARNING

Usando scanf non c’è nessun controllo di overflow con la stringa!

Infatti inserendo troppi caratteri si incappa in un errore di

segmentazione. Inoltre la funzione scanf con %s ignora gli spazi

prima e dopo la stringa. In generale scanf non è una funzione

sicura ma è comunque adatta per spiegare questi problemi

introduttivi.

Esercizio 4

Consegna

Data una stringa controllare se è palindroma.

Una parola palindroma si legge allo stesso modo da sinistra a destra e da destra a

sinistra: onorarono, per esempio, è una parola palindroma.

Il programma non deve prevedere la gestione dei caratteri whitespace: per esempio

onora rono non deve risultare come palindromo.

La funzione main deve ritornare true se è palindroma oppure false se non lo è. Questo

viene fatto salvando il risultato nella variabile booleana palindrome.

Le variabili booleane in C sono definite in stdbool.h e sono di tipo bool

Infine è necessario stampare:

  • la stringa e' palindroma
  • la stringa non e' palindroma

a seconda dei casi.

Usare questa traccia:

#include

10 | Franco Masotti, 2023 | https://blog.franco.net.eu.org

#include

bool main ( void ) { // La stringa e' di 128 caratteri + 1 carattere terminatore di stringa. char array[ 129 ] = "EaQDQeLCUsddXqFOUjFMcFPUxNZzdtuctIIKZzOmDyxHoNDbqtaT" "oBAbWBCoIqDzzDqIoCBWbABoTatqbDNoHxyDmOzZKIItcutdzZNx" "UPFcMFjUOFqXddsUCLeQDQaE" bool palindrome;

/* Vostro codice */

return palindrome; }

Soluzione

Per sapere se una parola è palindroma possiamo partire dal caso base di una stringa da

una lettera: a per esempio è palindroma perché pur essendo di una lettera solo si legge

sempre allo stesso modo in tutti i versi.

Proviamo ora con la stringa dacad e impostiamo due indici i e j in questo modo: i parte

sempre da 0 mentre j è sempre l’ultimo elemento della stringa (per semplicità

ignioriamo il terminatore '\0').

array = [d, a, c, a, d] | | i j

La domanda da fare è: array[i] == array[j]? Sì, allora proseguiamo così: facciamo

avanzare i (i++) e regredire j (j--):

array = [d, a, c, a, d] | | i j

Facciamo la stessa domanda di prima: array[i] == array[j]? il risultato è ancora sì.

Facciamo un altro passaggio:

array = [d, a, c, a, d] | i,j

Se i == j allora ci troviamo nel caso base esposto precedentemente: una stringa di una

lettera soltanto è per definizione palindroma. Quindi, con questo metodo, sappiamo

che dacad è palindroma.

Franco Masotti, 2023 | https://blog.franco.net.eu.org | 11

else { printf("la stringa non e' palindroma\n"); }

return palindrome; }

① Conto la lunghezza della stringa meno 1 perché il conteggio parte da 0 e non da 1

② Evito di contare il carattere terminatore '\0'

③ Continuo a iterare sulla stringa se i due caratteri in analisi sono uguali.

④ Se i due caratteri in analisi sono diversi allora la stringa sicuramente non è

palidroma: bisogna uscire dal ciclo e dal programma.

⑤ Se i == j allora significa che tutti i caratteri fino al centro della stringa sono

speculari, quindi la stringa è palindroma. L’altro caso, quando i > j, si verifica con

una stringa di lunghezza pari. Potete provare l’algoritmo con la stringa dccd.

Arrivando a uno di questi due casi il ciclo deve terminare e il programma deve

uscire stampando la stringa e' palindroma

Con la stringa fornita la viene stampato a video la stringa e' palindroma e la funzione

main deve ritornare 1.

Approfondimento

Generazione di una stringa casuale di 128 caratteri palindroma in Python.

>>> import secrets , string >>> left = ''.join([secrets.choice(string.ascii_letters) for i in range( 0 , 64 )]) ① >>> left + left[::- 1 ] ② 'EaQDQeLCUsddXqFOUjFMcFPUxNZzdtuctIIKZzOmDyxHoNDbqtaToBAbWBCoIqDzzDqIoCBWbABoTatqbDNoHxyDmOzZKI ItcutdzZNxUPFcMFjUOFqXddsUCLeQDQaE'

① Genero una stringa di 64 lettere minuscole e maiuscole casuali

② Concateno la stringa originale con il suo inverso

Esercizio 5

Scrivete un piccolo parser in C per HTML.

Fate in modo che il programma trasformi i tag

  • h1 in h
  • em in b

Franco Masotti, 2023 | https://blog.franco.net.eu.org | 13

ignorando altri tag e senza calcolare a priori la lunghezza della stringa.

Usando questa stringa di esempio:

< h1 >Questo e' un titolo < p >Questo e' un po' di < em >contenuto

deve diventare:

< h2 >Questo e' un titolo < p >Questo e' un po' di < b >contenuto

Savlate il risultato nell’array result. Usate questa traccia:

#include

int main ( void ) { char array[ 100 ]= "Questo e' un titolo\n

Questo e' un po' di contenuto

"; char result[ 100 ];

/* Vostro codice */

return 0 ; }

IMPORTANT

La soluzione non può prevedere l’indirizzamento diretto

dell’array per fare le sostituzioni, per esempio:

char array[ 100 ] = "test char result[ 100 ];

result[ 0 ] = array[ 0 ] result[ 1 ] = array[ 1 ] result[ 2 ] = '2' result[ 3 ] = array[ 3 ] // ecc... result[ 11 ] = '2'

NOTE

Guardate l’array un elemento per volta stando attenti alla fine della

stringa. Dovere trovare l’inizio dei tag HTML (il carattere <) e capire se il

tag in questione è tra quelli da convertire.

14 | Franco Masotti, 2023 | https://blog.franco.net.eu.org

k,l

result = [<] | j

// Quindi alla fine del ciclo diventa cosi'.

array = [<,h,1,>] | | k l

result = [<] | j

// Quindi e' sicuramente un tag di apertura perche' l - k == 2. // Ora vediamo quello che c'e' nel tag.

array = [<,h,1,>] | k

result = [<] | j

// Il tag incomincia con 'h' quindi forse deve essere cambiato.

array = [<,h,1,>] | k

result = [<,h,2] | j

// Abbiamo trovato un h1 quindi basta cambiarlo in h2.

array = [<,h,1,>] | k

result = [<,h,2,>] | j

// Copia dell'ultimo carattere.

Per trasformare h1 in h2 basta inserire manualmente il carattere 2 al posto di 1 invece

che copiare i caratteri esistenti come negli altri casi. Un discorso simile vale per

trasformare em in b. In questo caso però bisogna anche saltare l’incremento dell’indice

j al momento della copia in result.

16 | Franco Masotti, 2023 | https://blog.franco.net.eu.org

#include

int main ( void ) { char array[ 100 ]= "Questo e' un titolo\n

Questo e' un po' di contenuto

"; char result[ 100 ];

result[ 99 ] = '\0'; ① int i = 0 , j = 0 , k = 0 , l = 0 , valid_closing_tag = 0 ;

while (array[i] != '\0') { k = i;

result[j] = array[k];

if (array[k] == '<') ② { k++; j++;

if (array[k] != '\0' && array [k] == '/') ③ { result[j] = array[k]; k++; j++; } }

if (k > i) ④ { ⑤ l = k; valid_closing_tag = 0 ; while (valid_closing_tag == 0 && array[l] != '\0') { if (l - k == 2 && array[l] == '>') { valid_closing_tag = 1 ; } l++; }

if (valid_closing_tag == 1 && array[k] != '\0' && array[k] == 'h') ⑥ { result[j] = array[k]; k++; j++;

if (array[k] != '\0' && array[k] == '1') ⑦ { result[j] = '2'; j++; k++;

Franco Masotti, 2023 | https://blog.franco.net.eu.org | 17

⑨ Trovo l' e di em

⑩ In questo punto NON avanzo j perché da em, che è composto da due caratteri,

passiamo a b che è di un solo carattere

⑪ Trovo la m di em

⑫ Caso base: non è stato trovato nessun tag HTML all’indice corrente

NOTE

L’indice i ci dice in generale dove siamo arrivati ad iterare sulla stringa

originale alla fine di ogni ciclo, mentre k può venire incrementato più

volte all’interno del ciclo in base alle condizioni. Vedere anche il punto

WARNING

Alcuni controlli sono incompleti: manca il confronto tra opening

tag e closing tag che dovrebbero essere uguali se corrispondono allo

stesso livello.

Franco Masotti, 2023 | https://blog.franco.net.eu.org | 19