Spesso ci sono problemi che appaiono insormontabili, come la scalata di una montagna: l'unico modo di affrontarli è quello di procedere a piccoli passi, uno dopo l'altro.
Seguendo i forum di programmazione mi sono imbattuto in uno studente che aveva problemi con lo svolgimento di un esercizio sugli array in linguaggio C; la soluzione era a portata di mano ma evidentemente le tante richieste del testo lo avevano mandato in tilt.
In questo articolo cercherò di dare un esempio per affrontare questo tipo di esercizi.

mountain720

Chi si occupa di programmazione matura presto la capacità di suddividere il problema in tanti sottoproblemi, in modo da affrontarne uno alla volta: prima di scrivere anche solo una riga di codice è bene definire i sottoproblemi che si devono affrontare.

Il testo dell'esercizio che dobbiamo svolgere è il seguente:

Scrivere un programma C che acquisisce un array a1 di 10 interi.Il programma crea e visualizza un nuovo array a2 contenente i soli numeri pari presenti in a1 più di una volta, senza salvare le ripetizioni.
Si noti che l’ordine con cui i valori sono salvati in a2 è irrilevante.
Per esempio se l’utente inserisce l’array :
1 2 4 2 8 6 6 8 8 1
il programma creerà e visualizzerà l’array :
2 6 8

Quindi iniziamo a scrivere cosa serve:
- inserimento da tastiera di un array a1[] di 10 interi
- copia in un nuovo array a2[] degli elementi di a1[] che rispettano determinate condizioni
- visualizzazione dell'array a2[] di 10 interi (o meno)

Le condizioni perchè un elemento di a1[] venga copiato in a2[] sono:
- deve essere pari
- non deve essere già presente in a2[]
- deve essere presente in a1[] più di una volta

Il metodo che voglio suggerire in questo articolo è proprio quello di affrontare un passo alla volta, quindi suddividere la stesura dell'algoritmo a piccoli passi, in questo caso affrontando l'implementazione di una condizione alla volta.

PRIMO PASSO
Occupiamoci solo di inserire i dati in a1[], copiare tutti i dati in a2[] e stampare a2[].
Questa cosa è molto facile e sarà la base per i passi successivi:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

#define MAXSTR    80
#define N 10

int main()
{
    int a1[N], a2[N];
    char buff[MAXSTR];
    int i;

    printf("Inserisci gli elementi\n");
    for (i = 0; i < N; i++)
    {
        printf("[%d] ", i);
        a1[i] = atoi(fgets(buff, MAXSTR, stdin));
    }

    for (i = 0; i < N; i++)
    {
        a2[i] = a1[i];            
    }

    for (i = 0; i < N; i++)
    {
        printf("%d ", a2[i]);
    }

    getch();
    return 0;
}

Naturalmente ognuno ha il suo modo di inserire i dati; probabilmente a scuola/università richiederanno l'utilizzo di scanf() quindi il codice va modificato di conseguenza.

SECONDO PASSO
Adesso vogliamo caricare in a2[] solo i valori pari di a1[]. Anche questo risulta molto semplice, con l'accortezza di utilizzare un indice diverso per a1[] e a2[] e di tenersi traccia in una variabile del numero di elementi caricati in a2[].

int main()
{
    int a1[N], a2[N];
    char buff[MAXSTR];
    int na2, i;

    printf("Inserisci gli elementi\n");
    for (i = 0; i < N; i++)
    {
        printf("[%d] ", i);
        a1[i] = atoi(fgets(buff, MAXSTR, stdin));
    }

    na2 = 0;
    for (i = 0; i < N; i++)
    {
        if (a1[i] % 2 == 0)
        {
            a2[na2] = a1[i];
            na2++;
        }
    }

    for (i = 0; i < na2; i++)
    {
        printf("%d ", a2[i]);
    }

    getch();
    return 0;
}

Come si può notare, ho solo aggiunto una variabile na2 che uso sia per contare il numero di elementi di a2[] sia come indice per il caricamento dell'array in questione.

TERZO PASSO
A questo punto affrontiamo la seconda condizione, ovvero che l'elemento non sia già presente in a2[]. In questo caso avere una base solida ci permette di trovare una soluzione velocemente: prima di inserire un valore in a2[] basta controllare che tale valore non sia già presente in a2[].

int main()
{
    int a1[N], a2[N];
    char buff[MAXSTR];
    int na2, i, j;
    int found_in_a2;

    printf("Inserisci gli elementi\n");
    for (i = 0; i < N; i++)
    {
        printf("[%d] ", i);
        a1[i] = atoi(fgets(buff, MAXSTR, stdin));
    }

    na2 = 0;
    for (i = 0; i < N; i++)
    {
        if (a1[i] % 2 == 0)
        {
            // cerca se il valore è già presente in a2[]
            found_in_a2 = 0;
            for (j = 0; j < na2; j++)
            {
                if (a1[i] == a2[j])
                {
                    found_in_a2 = 1;
                    break;
                }
            }

            if (!found_in_a2)
            {
                a2[na2] = a1[i];
                na2++;
            }
        }
    }

    for (i = 0; i < na2; i++)
    {
        printf("%d ", a2[i]);
    }

    getch();
    return 0;
}

Come si può notare, prima di caricare il valore in a2[] mi accerto che questo non sia già presente e per fare questo faccio un ciclo sugli na2 elementi di a2[] caricati fino a quel punto.
Se lanciate il programma e caricate i valori di esempio otterrete come risultato la sequenza "2 4 6 8": c'è ancora da eliminare quel 4 che è presente una volta sola in a1[].

QUARTO E ULTIMO PASSO
Ora dobbiamo solo aggiungere la verifica che il dato che vogliamo inserire sia presente più di una volta nell'array a1[]; ci sono sicuramente milioni di modi di fare questo ma noi, copiando un po' il ciclo creato al passo precedente, decidiamo di controllare se esiste almeno un altro elemento in a1[] uguale a quello corrente.

int main()
{
    int a1[N], a2[N];
    char buff[MAXSTR];
    int na2, i, j;
    int found_in_a1;
    int found_in_a2;

    printf("Inserisci gli elementi\n");
    for (i = 0; i < N; i++)
    {
        printf("[%d] ", i);
        a1[i] = atoi(fgets(buff, MAXSTR, stdin));
    }

    na2 = 0;
    for (i = 0; i < N; i++)
    {
        if (a1[i] % 2 == 0)            
        {
            // cerca se il valore è già presente in a2[]
            found_in_a2 = 0;
            for (j = 0; j < na2; j++)
            {
                if (a1[i] == a2[j])
                {
                    found_in_a2 = 1;
                    break;
                }
            }

            // cerca se il valore è presente in a1[] in una posizione diversa dalla posizione corrente
            found_in_a1 = 0;
            for (j = 0; j < N; j++)
            {
                if((i!=j) && (a1[i] == a1[j]))
                {
                    found_in_a1 = 1;
                    break;
                }
            }

            // se il valore non è già presente in a2[] ed è presente più volte in a2[]
            if( (!found_in_a2) && (found_in_a1))
            {
                a2[na2] = a1[i];
                na2++;
            }
        }
    }

for (i = 0; i < na2; i++)
    {
        printf("%d ", a2[i]);
    }

    getch();
    return 0;
}

Ecco fatto! Ho semplicemente aggiunto un flag found_in_a1 per indicare se c'è un altro valore uguale in a1[] con un ciclo che controlla tutti gli N elementi in a1[] tranne ovviamente l'elemento alla posizione i.

CONCLUSIONI

Naturalmente il codice qui sopra può essere migliorato e abbellito; la sostanza, comunque, è che l'esercizio è stato svolto correttamente, provare per credere!
Inoltre, l'aver affrontato il problema per passi di difficoltà crescente ci permette, nel caso la problematica sia troppo complessa per il nostro grado di apprendimento, di consegnare qualcosa di funzionante anche se incompleto (se siamo a scuola) o di farci aiutare dai colleghi (se siamo al lavoro).