Lezione 8: Stringhe

Soluzione di Esercizi

Esercizio 7.1 Scrivere una funzione, int parola(char A[], int n, int k, int *plung), che ritorna la posizione della k-esima parola contenuta nell'array A (di dimensione n) e restituisce in *plung la lunghezza di tale parola. Se il numero di parole contenute nell'array A è minore di k, la funzione ritorna -1 e *plung è lasciato invariato. Ad esempio, se A contiene la sequenza di caratteri "La seconda parola" (quindi n = 17) e k = 2, allora la funzione ritorna 3 e in *plung restituisce il valore 7.

#include <ctype.h>

/* Ritorna la posizione della k-esima parola nell'array A di 
 * dimensione n, in *plung restituisce la lunghezza della parola. */
int parola(char A[], int n, int k, int *plung) {
    int i = 0, p = -1;
    while (i < n && k > 0) {
        if (isalpha(A[i]) && (i == 0 || !isalpha(A[i - 1]))) {
            k--;
            if (k == 0) p = i;
        }
        i++;
    }
    if (k == 0) {
        *plung = 1;
        while (i < n && isalpha(A[i])) {
            (*plung)++;
            i++;
        }
    }
    return p;
}

Esercizio 7.2 Scrivere un programma (usando la funzione dell'esercizio precedente ed eventualmente altre funzioni) che legge dall'input due linee di testo e stampa tutte le parole della prima linea che appaiono anche nella seconda.

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int parola(char A[], int n, int k, int *plung) {
    . . .
}

int inputline(char line[], int maxlen) {
    . . .
}

#define MAX_CHARS    1000

// Stampa le parole di una linea di testo che appaiono in 
// un'altra linea di testo
int main() {    
    char line1[MAX_CHARS], line2[MAX_CHARS];
    printf("Inserire la prima linea: ");
    int n1 = inputline(line1, MAX_CHARS);
    printf("Inserire la seconda linea: ");
    int n2 = inputline(line2, MAX_CHARS);
    int lung1, p1, k1 = 1;
    while ((p1 = parola(line1, n1, k1, &lung1)) != -1) {
        int lung2, p2, k2 = 1, trovata = 0;
        while ((p2 = parola(line2, n2, k2, &lung2)) != -1) {
            if (lung1 == lung2 && strncmp(&(line1[p1]), 
                &(line2[p2]), lung1) == 0) 
                trovata = 1;
            k2++;
        }
        if (trovata) {
            for (int i = 0 ; i < lung1 ; i++)
                printf("%c", line1[p1 + i]);
            printf("\n");
        }
        k1++;
    }
}

Puntatore a null

Fino ad ora abbiamo solo preso puntatori di variabili dichiarate nel programma. In C, possiamo anche indicare un valore addizionale per un puntatore che indica un puntatore invalido, cioe' il cui indirizzo non si riferisce ad una variabile esistente. In C, usiamo il valore NULL per indicare questo valore.

Variabili e Funzioni

Fino ad ora, abbiamo dichiarato tutte le variabili all'interno di funzioni. Queste variabili sono disponibili solo all'interno della funzione in cui sono dichiarate. In C, se si dichiara una variabile all'esterno di funzioni, la variabile si dice essere globale ed e' accessibile da tutte le funzioni.

In generale, si sconsiglia di usare variabili globali il meno possibile dato che rendono il codice illeggibile. Allo stessao tempo, sono a volte necessarie, come vedremo in seguito.

Stringhe

Gli array di tipo char[] terminati dal carattere '\0', equivalente a 0, sono chiamati stringhe. Questo e' il tipo principale supportato in C per la manipolazione del testo. Abbiamo gia' incontrato le constanti di tipo stringa, che sono espresse come testo racchiuso da caratteri ". Ad esempio se vogliamo memorizzare un messaggio di testo possiamo usare la sintassi char messaggio[] = "ciao".

Funzioni sulle Stringhe

Le funzioni principali che agiscono sulle stringhe sono dichiarate nell'header string.h. A seguito riassumiamo le piu' usate.

Input/Output

Le stringhe si possono usare direttamente nelle operazioni di input/output con printf e scanf usando il carattere %s. Nel caso di scanf si intenede il parsing di stringhe delimitato da spazi.

Esempi

Funzione che ritorna vero se le stringhe s1 e s2 sono l'una l'anagramma dell'altra (ad es. "lavagna" e "valanga").

#include <stdio.h>

//Ritorna true se la stringa s1 e' un anagramma della stringa s2
int anagramma(char *s1, char *s2) {
    int cont[256] = {0};
    for (int i = 0 ; s1[i] != '\0' ; i++)
        cont[s1[i]]++;
    for (int i = 0 ; s2[i] != '\0' ; i++)
        cont[s2[i]]--;
    for (int i = 0 ; i < 256 ; i++)
        if (cont[i] != 0) return 0;
    return 1;
}

#define MAXLEN     100

int main() {    //determina se due parole sono l'una l'anagramma dell'altra
    char par1[MAXLEN + 1], par2[MAXLEN + 1];
    printf("Inserire due parole: ");
    scanf("%s %s", par1, par2);
    printf("Le parole \"%s\" e \"%s\" ", par1, par2);
    if (anagramma(par1, par2))
        printf("sono anagrammi\n");
    else
        printf("non sono anagrammi\n");
}

Esercizi

Esercizio 8.1 Scrivere una funzione, char *strw(char *s, int k, char *w), che copia la k-esima parola contenuta nella stringa s in w, come stringa, e ritorna il puntatore w. Se s contiene meno di k parole, allora la funzione ritorna NULL (NULL è una costante in stdlib.h (e in stdio.h) che rappresenta un indirizzo non valido). La funzione strw() è una versione per stringhe della funzione parola() dell'esercizio 7.1.

Esercizio 8.2 Scrivere un programma (usando le funzioni anagramma() e strw()) che prende in input una linea di testo e poi una stringa e stampa tutte le parole contenute nella linea di testo che sono anagrammi della stringa. Ad esempio, se la linea di testo è "Il ratto ha mangiato la torta" e la stringa è "trota", allora il programma stampa:

ratto
torta