Esercizi sugli array e funzioni

di il
23 risposte

Esercizi sugli array e funzioni

Salve a tutti, mi sono appena iscritta e sto cercando aiuto per la costruzione di una determinata funzione in C.
Ho un esame di programmazione in vista, l'unico del mio corso e non sono proporio portata per la programmazione. In particolare gli array mi creano molte perplessità e mi sto un po' disperando, ho cercato su internet e qui in giro ma vorrei una risposta precisa su come si svolge questo esercizio:

A) Si scriva la funzione C
void fondi(v1[], v2[], l)
che riceve in ingresso due vettori di egual lunghezza l, già ordinati in modo crescente.
La funzione deve "fondere" i due vettori in un terzo vettore v3[] appositamente creato che contenga tutti gli elementi
ordinati tra di loro in modo crescente e stamparlo a schermo.

Ad esempio, se il primo vettore contiene gli elementi
1 4 5 8 12 ...
e il secondo
2 5 6 8 9 ...
il vettore "fusione" sarà
1 2 4 5 5 6 8 8 9 12 ...

B) Si scriva il metodo main che permetta di provare la funzione "fondi"

C) Si scriva la funzione
int ordinato(v[], l)
che sia in grado di verificare se il vettore v[] è ordinato, e risponda il valore 1 in caso affermativo e 0 in caso negativo

D) Si utilizzi la funzione "ordinato" nel main creato in B) per verificare i vettori prima di passarli a "fondi"

E) Si modifichi la funzione "fondi" affinchè sia in grado di gestire vettori di lunghezza diversa tra di loro (l1 ed l2)

F) Si modifichi "fondi" affinchè il vettore risultante non contenga valori duplicati, che quindi non verranno neppure stampati

H) Si scriva la funzione
void separa(v[], l)
in grado di separare dal vettore v[], di lunghezza l, i valori pari da quelli dispari, producendo e stampando a schermo i due vettori risultanti

23 Risposte

  • Re: Esercizi sugli array e funzioni

    Ok, ma fai troppe domande in un solo thread ... cosa non sai fare in particolare?

    Partiamo anche da un codice di partenza su cui discutere ...
  • Re: Esercizi sugli array e funzioni

    oregon ha scritto:


    Ok, ma fai troppe domande in un solo thread ... cosa non sai fare in particolare?

    Partiamo anche da un codice di partenza su cui discutere ...
    mi mette in crisi soprattutto la parte della prima domanda, sul fondere i vettori in ordine. Ho guardato su molti siti ma usano tantissimi indici per spostarsi e segnalare la posizione e mi perdo.
    Pensavo di fare un ciclo for ma non saprei proprio come strutturarlo.
    #include<stdio.h>
    
    void fondi(v1[], v2[], 1)
    {
    
    
    }
    
    int main(){
    
    
    int vettore1[5]={1,4,7,8,9}, vettore2[5]={2,3,4,5,6}, vettoretot[10];
    
    }



    Ho iniziato a fare così, volevo mettere il for nella funzione e fare un unico vettore ma non so proprio cosa fare e la cosa mi scoraggia abbastanza.
  • Re: Esercizi sugli array e funzioni

    La funzione dovrebbe ricevere quattro parametri: i due vettori sorgente, il vettore di destinazione e la quantita' degli elementi contenuti nei due vettori sorgente (che è la stessa per entrambi):

    int fondi( const int *v1, const int *v2, int *vr, size_t l );

    Il valore di ritorno l'ho messo solo per permettere di restituire qualcosa che faccia capire se l'operazione e' o non e' andata a buon fine. A me piace restituire 1 se e' andato tutto bene, 0 se ci sono stati errori (in questo caso l'unico errore che mi viene in mente è il passaggio di puntatori NULL). Nota l'uso di const per rendere evidente che il contenuto di v1 e v2 non sarà modificato mentre quello di vr sì.

    Siccome devi "scorrere" per intero tre vettori hai due possibilità: o usi tre indici e l'operatore [], oppure usi tre puntatori ausiliari e l'aritmetica dei puntatori. Secondo me è più immediato seguire il meccanismo degli indici. E' pratico usare nomenclature che permettano di collegare a colpo d'occhio l'indice al suo vettore. Quindi:

    size_t i1 = 0; /* segue l'avanzamento nel vettore v1 */
    size_t i2 = 0; /* segue l'avanzamento nel vettore v2 */
    size_t ir = 0; /* segue l'avanzamento nel vettore risultante vr */

    Usando l'operatore ternario ?: puoi copiare i valori minori da v1 e v2, fino all'esaurimento di uno, dell'altro o di entrambi i vettori.
    L'operatore ternario ?: sembra complicato, ma in definitiva è solo una specie di forma sintetica di if-else:

    while( i1<l && i2<l ) vr[ir++] = v1[i1]<v2[i2] ? v1[i1++] : v2[i2++];

    Nota che gli indici vengono incrementati solo quando vengono usati, per cui "seguono" dappresso la lettura e lo "svuotamento" dei vettori ai quali si riferiscono.

    A questo punto, uno dei due vettori è senz'altro esaurito mentre l'altro (chissà quale?) potrebbe non esserlo. Devi copiare tutti gli elementi "residui" del vettore che non è stato esaurito. Il while, con la sua verifica anteposta, permette di saltare completamente qualsiasi operazione sul/sui vettori eventualmente già esauriti.

    while( i1<l ) vr[ir++] = v1[i1++];
    while( i2<l ) vr[ir++] = v2[i2++];

    Mettendo insieme "i pezzi", viene fuori la funzione che ti serve. Più semplice di quel che poteva sembrare, no?
    int fondi( const int *v1, const int *v2, int *vr, size_t l ) {
        if( v1 && v2 && vr ) { /* i puntatori sono validi? */
            /* definisce tre indici (uno per vettore) e li inizializza a zero */
            size_t i1 = 0; /* segue l'avanzamento nel vettore v1 */
            size_t i2 = 0; /* segue l'avanzamento nel vettore v2 */
            size_t ir = 0; /* segue l'avanzamento nel vettore vr */
    
            /* copia i valori minori da v1 e v2, fino all'esaurimento
               di uno, dell'altro o di entrambi i vettori; l'operatore
               ternario "?:" sembra complicato, ma e' solo una specie
               di forma sintetica di if-else */
            while( i1<l && i2<l )
                vr[ir++] = v1[i1]<v2[i2] ? v1[i1++] : v2[i2++];
    
            /* a questo punto, uno dei due vettori e' senz'altro esaurito
               mentre l'altro (chissa' quale?) potrebbe non esserlo */
    
            /* se e' il primo vettore a non essere esaurito, copia tutti
               i valori restanti del primo vettore in vr */
            while( i1<l )
                vr[ir++] = v1[i1++];
    
            /* se e' il secondo vettore a non essere esaurito, copia
               tutti i valori restanti del secondo vettore in vr */
            while( i2<l )
                vr[ir++] = v2[i2++];
    
            return 1; /* 1: ok */
        }
    
        return 0; /* 0: errore */
    }
  • Re: Esercizi sugli array e funzioni

    AldoBaldo ha scritto:


    Più semplice di quel che poteva sembrare
    Forse per te AldoBaldo è semplice (e serve solo a dimostrare a te stesso che sapevi fare l'esercizio ...), ma lui doveva arrivarci senza "pappa pronta", ragionandoci da solo a piccoli passi.

    Il metodo del 'so farlo e lo faccio al posto tuo' non va bene per insegnare a risolvere esercizi di programmazione.
  • Re: Esercizi sugli array e funzioni

    AldoBaldo ha scritto:


    La funzione dovrebbe ricevere quattro parametri: i due vettori sorgente, il vettore di destinazione e la quantita' degli elementi contenuti nei due vettori sorgente (che è la stessa per entrambi):

    int fondi( const int *v1, const int *v2, int *vr, size_t l );

    Il valore di ritorno l'ho messo solo per permettere di restituire qualcosa che faccia capire se l'operazione e' o non e' andata a buon fine. A me piace restituire 1 se e' andato tutto bene, 0 se ci sono stati errori (in questo caso l'unico errore che mi viene in mente è il passaggio di puntatori NULL). Nota l'uso di const per rendere evidente che il contenuto di v1 e v2 non sarà modificato mentre quello di vr sì.

    Siccome devi "scorrere" per intero tre vettori hai due possibilità: o usi tre indici e l'operatore [], oppure usi tre puntatori ausiliari e l'aritmetica dei puntatori. Secondo me è più immediato seguire il meccanismo degli indici. E' pratico usare nomenclature che permettano di collegare a colpo d'occhio l'indice al suo vettore. Quindi:

    size_t i1 = 0; /* segue l'avanzamento nel vettore v1 */
    size_t i2 = 0; /* segue l'avanzamento nel vettore v2 */
    size_t ir = 0; /* segue l'avanzamento nel vettore risultante vr */

    Usando l'operatore ternario ?: puoi copiare i valori minori da v1 e v2, fino all'esaurimento di uno, dell'altro o di entrambi i vettori.
    L'operatore ternario ?: sembra complicato, ma in definitiva è solo una specie di forma sintetica di if-else:

    while( i1<l && i2<l ) vr[ir++] = v1[i1]<v2[i2] ? v1[i1++] : v2[i2++];

    Nota che gli indici vengono incrementati solo quando vengono usati, per cui "seguono" dappresso la lettura e lo "svuotamento" dei vettori ai quali si riferiscono.

    A questo punto, uno dei due vettori è senz'altro esaurito mentre l'altro (chissà quale?) potrebbe non esserlo. Devi copiare tutti gli elementi "residui" del vettore che non è stato esaurito. Il while, con la sua verifica anteposta, permette di saltare completamente qualsiasi operazione sul/sui vettori eventualmente già esauriti.

    while( i1<l ) vr[ir++] = v1[i1++];
    while( i2<l ) vr[ir++] = v2[i2++];

    Mettendo insieme "i pezzi", viene fuori la funzione che ti serve. Più semplice di quel che poteva sembrare, no?
    int fondi( const int *v1, const int *v2, int *vr, size_t l ) {
        if( v1 && v2 && vr ) { /* i puntatori sono validi? */
            /* definisce tre indici (uno per vettore) e li inizializza a zero */
            size_t i1 = 0; /* segue l'avanzamento nel vettore v1 */
            size_t i2 = 0; /* segue l'avanzamento nel vettore v2 */
            size_t ir = 0; /* segue l'avanzamento nel vettore vr */
    
            /* copia i valori minori da v1 e v2, fino all'esaurimento
               di uno, dell'altro o di entrambi i vettori; l'operatore
               ternario "?:" sembra complicato, ma e' solo una specie
               di forma sintetica di if-else */
            while( i1<l && i2<l )
                vr[ir++] = v1[i1]<v2[i2] ? v1[i1++] : v2[i2++];
    
            /* a questo punto, uno dei due vettori e' senz'altro esaurito
               mentre l'altro (chissa' quale?) potrebbe non esserlo */
    
            /* se e' il primo vettore a non essere esaurito, copia tutti
               i valori restanti del primo vettore in vr */
            while( i1<l )
                vr[ir++] = v1[i1++];
    
            /* se e' il secondo vettore a non essere esaurito, copia
               tutti i valori restanti del secondo vettore in vr */
            while( i2<l )
                vr[ir++] = v2[i2++];
    
            return 1; /* 1: ok */
        }
    
        return 0; /* 0: errore */
    }

    Grazie mille! ora ho capito meglio la cosa degli indici, ma i puntatori ho crisi totale proprio, non mi entrano in testa
  • Re: Esercizi sugli array e funzioni

    oregon ha scritto:


    AldoBaldo ha scritto:


    Più semplice di quel che poteva sembrare
    Forse per te AldoBaldo è semplice (e serve solo a dimostrare a te stesso che sapevi fare l'esercizio ...), ma lui doveva arrivarci senza "pappa pronta", ragionandoci da solo a piccoli passi.

    Il metodo del 'so farlo e lo faccio al posto tuo' non va bene per insegnare a risolvere esercizi di programmazione.
    Lo dicono anche i professori di sistemi di elaborazione all'università, solo che temo di non essere proprio portata, da sola mi blocco e non so da dove prendere, perché gli array mi risultano abbastanza complicati
  • Re: Esercizi sugli array e funzioni

    Ok, magari saranno complicati (per te), ma dal codice pronto non impari nulla.

    Prova a battere su "cosa" ti sembra complicato, "cosa" non capisci, dacci delle domande e delle risposte e controlliamo se hai capito male.
  • Re: Esercizi sugli array e funzioni

    Ma per piacere! Gli array complicati?

    Indossare un paio di jeans attilati senza essersi fatta la ceretta, quello si che e' complicato!

    Sono la struttura dati piu' stupida che ci sia in circolazione!

    Hai fatto
    1) algebra lineare?
    2) Calcolo vettoriale?
    3) Spazio in n-dimensioni?
    4) Battaglia navale?
    5) Numeri complessi?
    6) Numeri razionali?
    7) dama/scacchi/othello/go/..?

    4,5,6 sono esempi di vettori a DUE dimensioni:
    - 4,7: le cpordinate sulla scacchiera
    - 5: parte reale, parte immaginaria
    - 6: numeratore, denominatore

    1,2,3 sono la versione generalizzata a N dimensioni

    l'array monodimensionale e' la sua rappresentazione con il computer.

    per accedere ad un elemento del vettore che cosa usi? un indice!
    stessa cosa per gli array: indice, che deve essere un intero.

    EVITA COME LA LEBBRA/EBOLA/INFLUENZA AVIARIA l'aritmetica dei puntatori: e' fonte di INFINITE rogne per chiunque, dal neofita al super-mega-iper-espertone

    Purtroppo il C e' STUPIDO, ma, quali dono le caratteristiche di un vettore?

    - il tipo del dato che deve contenere
    - la sua lunghezza

    in C i vettori/array (condidera i termini SINONIMI) si ALLOCANO (e si deve dire QUANTO deve essere lungo) e quando non servono piu' si LIBERANO. E siccome il C e' STUPIDO, bisogna sempre tenere traccia della lunghezza, visto che sto scemo di linguaggio non ti permette, dato un vettore, di sapere la sua lunghezza (pero' si puo' fare in C++ con i std::vector<T>).

    Come di crea/libera un vettore?
    
    int* parray = (int*)calloc(100,sizeof(int));
    free(parray);
    
    Come di legge/scrive in un elemento del vettore?
    
    int indice=10;
    int valore = parray[indice];
    parray[indice] = valore+1
    
    Ora sai il 99% delle cose da sapere sui vettori/array!
  • Re: Esercizi sugli array e funzioni

    @AldoBaldo: se vuoi mostrare un esempio ad un neofita, NON PUOI PENSARE che il tizio/tizia sappia che cosa sia const, size_t, gli operatori di pre/post incremento/decremento!

    EVITA di giocare con il fatto che qualunque cosa sia zero, il C lo consideri FALSO e diverso da zero VERO! Scrivi 'p!=NULL' NON SOLO 'p''

    SCRIVI CODICE STRA-SEMPLICE con NESSUN orpello e compatibile con il linguaggio: C, NON C++
    e NESSUN trucchetto da smanettone!
  • Re: Esercizi sugli array e funzioni

    [quote="migliorabile"]
    Come di crea/libera un vettore?
    
    int* parray = (int*)calloc(100,sizeof(int));
    free(parray);
    
    Come di legge/scrive in un elemento del vettore?
    
    int indice=10;
    int valore = parray[indice];
    parray[indice] = valore+1
    
    Ora sai il 99% delle cose da sapere sui vettori/array![/quote

    non mi e' chiara una cosa. solitamente quando creo un array (o almeno ciò che ho visto a lezione) scrivevo, per esempio (faccio un array di interi lungo 20)
    int nomevettore[20];
    Vedo che qui ci sono degli asterischi e non ci sono le parentesi quadre, cosa sono?

    altra cosa: una stringa, a quanto ne so, è un array di caratteri. Come faccio a riempire un array di caratteri?
  • Re: Esercizi sugli array e funzioni

    Ma avrai uno straccio di libro su cui studi, o vai avanti a tentoni?

    Se non c'e' l'hai, COMPRALO.
    Se c'e' l'hai, APRILO E STUDIA.

    Stai facendo domande la cui risposta e' all'inizio del capitolo sugli array su QUALUNQUE libro!
  • Re: Esercizi sugli array e funzioni

    Migliorabile: "compatibile con il linguaggio: C, NON C++"

    Cosa c'è di C++ nello spezzone e nel ragionamento che ho proposto? Io non ce ne vedo. Per favore, indicami con precisione dov'è il C++ nella funzione che ho proposto (e descritto).

    Quanto a if(p) è una notazione che si trova un po' su tutti i testi sui quali ho studiato e che viene spiegata proprio con la motivazione delli maggiori sinteticità e leggibilità e proprio motivandola col fatto che in C if(0) è sempre falso e che if(<numero qualsiasi, non zero>) è sempre vero. Essendo che NULL è un puntatore generico che punta ad un indirizzo 0, ne consegue che if(p) dove p è NULL è sempre falso e if(p) dove p non è NULL è sempre vero.

    Ora, non sono certo un esperto, però queste cose le ho lette e rilette tante di quelle volte e sempre con le stesse formulazioni da indurmi a pensare che siano attendibili. La pratica ha sempre confermato la validità di quegli assunti. Finora. Poi sappiamo tutti che gli standard sono tali finché non arriva qualche gruppoi di buontemponi che decide di cambiarli...

    L'unica cosa un po' più che "base" tra i costrutti che ho usato è l'operatore ternario. L'aritmetica dei puntatori l'ho citata e ho subito precisato che è meno "maneggevole" del sistema degli indici, lasciando intenzionalmente perdere quella strada.

    Tra l'altro, è interessante che tu consideri sconsigliabile per un principiante l'uso del tipo size_t (ampiamente usato anche nelle librerie standard che si impiegano nei primissimi esercizi, tipo string.h) e poi butti lì esempi con allocazione dinamica della memoria! Lasciando intendere, peraltro, che gli array sono sempre e soltanto dinamici ("in C i vettori si ALLOCANO e quando non servono piu' si LIBERANO"), il che non corrisponde al vero.
  • Re: Esercizi sugli array e funzioni

    migliorabile ha scritto:


    Ma avrai uno straccio di libro su cui studi, o vai avanti a tentoni?

    Se non c'e' l'hai, COMPRALO.
    Se c'e' l'hai, APRILO E STUDIA.

    Stai facendo domande la cui risposta e' all'inizio del capitolo sugli array su QUALUNQUE libro!

    ho studiato tutto il libro. Tutto.
    per come mi è stata spiegata la materia, il professore dava per scontato che tutti avessero già fatto programmazione alle superiori. Non l'avevo mai fatta e sto studiando tutto da sola.
    Ho letto la definizione e tutto ma non riesco ad applicarlo senza esempi concreti sugli esercizi, e il prof è restio a mettere le soluzioni degli esercizi fatti.
    Comunque io studio statistica e la programmazione in c che facciamo è più soft rispetto a quella fatta ad informatica, ma i libri sono creati per i corsi di informatica quindi contengono un sacco di cose più complicate, quindi per la teoria ok ma per gli esercizi non aiuta molto, almeno me.

    Ho provato, ci ho messo ore a risolvere da sola l'esercizio di cui al punto a, compila ma il risultato viene sbagliato: i primi due numeri escono e poi viene una sequenza di zeri.
    #include<stdio.h>
    #include<stdlib.h>
    
    int main(){
    
    int lunghezza;
    int v1[lunghezza], v2[lunghezza], vtot[lunghezza*2];
    int i, a, b;
    
    printf("Quanto lungo il vettore?\n\n");
    scanf("%d", &lunghezza);
    
    printf("Inserisci gli elementi del primo vettore\n\n");
    
    for(i=0; i<lunghezza; i++)
    	{
    	printf("Elemento %d: ", i+1);
    	scanf("%d", &v1[i]);
    	}
    printf("Stampa gli elementi del primo vettore\n\n");
    
    for(i=0; i<lunghezza; i++)
    	{
    	printf("Elemento %d: %d\n", i+1, v1[i]);
    
    	}
    
    printf("Inserisci gli elementi del secondo vettore\n\n");
    
    for(i=0; i<lunghezza; i++)
    	{
    	printf("Elemento %d: ", i+1);
    	scanf("%d", &v2[i]);
    	}
    printf("Stampa gli elementi del secondo vettore\n\n");
    
    for(i=0; i<lunghezza; i++)
    	{
    	printf("Elemento %d: %d\n", i+1, v2[i]);
    
    	}
    
    
    
    
    for (i=0, a=0, b=0; i<lunghezza*2 && a<lunghezza && b<lunghezza; i++)
    	{
    	if(v1[a] <= v2[b])
    		{
    		vtot[i]=v1[a];
    		a= a + 1;
    		}
    	else
    		{
    		vtot[i]=v2[b];
    		b = b + 1;
    		}
    
    if(i<lunghezza*2)
    	{
    	if(a<lunghezza)
    		{
    		for( ; i<lunghezza*2; i++, a++)
    		vtot[i]=v1[a];
    		}
    	else
    		{
    		for( ; i<lunghezza*2; i++, b++)
    		vtot[i]=v2[b];
    		}
    	}
    
    printf("Il vettore ordinato e':\n");
    for(i=0; i<lunghezza*2; i++)
    	{
    	printf("elemento %d: %d \n", i+1, vtot[i]);
    	}
    	
    }
    
    }
    non so proprio come correggere
  • Re: Esercizi sugli array e funzioni

    Vero_vev, è la differenza tra array allocati dinamicamente e array a dimensione fissa. In genere nei primi esercizi si impiegano array a dimensione fissa, perché la gestione dinamica della memoria è più complessa. Lascia perdere (per ora) malloc(), calloc(), realloc() e free() e usa tranquillamente la notazione che hai usato tu, dichiarando gli array nella forma nome_array[20] (20 è un numero arbitrario, per fare un esempio).

    Quando si passa un array a una funzione, lo si passa nella forma di puntatore all'indirizzo del primo elemento dell'array. L'operatore per ricavare l'indirizzo di una variabile (e il primo elemento di un array è una variabile) è &, per cui passando a una funzione &nome_array[0] stai in effetti dicendo alla funzione dove incomincia lo spazio di memoria nel quale si trova l'array. Per leggere il contenuto di un indirizzo invece si usa l'operatore * . Quindi...
    void funzione( char *v, size_t dim ) {
        /* sappiamo che v e' l'indirizzo di memoria dove
           inizia il vettore, cioe' dove si trova v[0] */
    
        /* potremmo inserire un valore alla posizione v usando l'operatore * */
        *v = 'a'; /* 'a' e' una lettera qualsiasi */
    
        /* e' pero' molto piu' pratico risalire ai singoli elementi
           dell'array con l'operatore [] e l'uso di un indice zero based */
        v[0] = 'a'; /* mette 'a' nel primo elemento dell'array v[] */
        v[6] = 'c'; /* mette 'c' nel settimo elemento dell'array v[] */
    }
    
    int main() {
        char v[20]; /* dichiara un array di 20 char che si
                       trova in un certo spazio di memoria */
        
        funzione( &v[0], 20 ); /* chiama funzione(), facendole conoscere la
                                  posizione dello spazio di memoria dove si
                                  trova v[20] e le dimensioni dell'array */
       
        /* per quanto la notazione &v[0] sia valida, MOLTO piu' frequentemente
           si usa sottintendere che il nome di un array ne identifica sempre
           l'indirizzo del primo elemento, per cui e' comune trovare scritto... */
        
        funzione( v, 20 ); /* chiama funzione(), facendole conoscere la
                              posizione dello spazio di memoria dove si
                              trova v[20] e le dimensioni dell'array */
    }
    Chiedi poi come si fa a riempire un array. Il metodo più ovvio è "riempirne" un elemento alla volta con i valori che ti servono.
    Per le stringhe esiste una possibilità di inizializzazione contestuale alla dichiarazione con char stringa[] = "ciao";
    Sempre per le stringhe, usando le funzioni di libreria definite in string.h puoi "riempire" una stringa con (per esempio) strcpy(), e non solo in fase di dichiarazione e inizializzazione.
Devi accedere o registrarti per scrivere nel forum
23 risposte