Problema con i vettori e le definizioni di tipo in C

di il
5 risposte

Problema con i vettori e le definizioni di tipo in C

Salve a tutti, ultimamente sto imparando a programmare in C per l'università, mi sembrava andasse tutto liscio, eppure ho un problema nel trattare i vettori e vettori definiti con la “typedef” all'interno di un programma e di funzioni. 

Più in particolare non comprendo bene quando vadano utilizzati dei puntatori o meno e in generale come trattare questo tipo di dato all'interno delle funzioni. 

Una cosa che non comprendo bene è se il tipo definito all'interno dei parametri formali della funzione mio caso, “vettore”, abbia in qualche modo implicitamente la definizione di puntatore. 

Dico questo perché mi è stato spiegato che nelle funzioni, una volta terminata l'esecuzione, il record di attivazione e tutto ciò che contiene viene cancellato e solo attraverso pointer è possibile modificare effettivamente i valori della variabile del main.

Vi allego di seguito un esercizio in cui appunto senza utilizzare “*” il programma funziona perfettamente. 

Ringrazio di cuore chiunque si offra di darmi una mano.

5 Risposte

  • Re: Problema con i vettori e le definizioni di tipo in C

    Ciao, dal momento che non ho capito quale sia il problema nello specifico, faccio una breve ricapitolazione degli argomenti in gioco, poi se qualcosa non ti è chiaro fammi sapere:

    • un puntatore è una variabile che contiene l'indirizzo di memoria di un'altra variabile di un determinato tipo (chiamiamolo TIPO_VARIABILE). Di seguito riporto la dichiarazione di una variabile a e di una variabile puntatore p_a che punta ad a (dove & rappresenta l'operatore di indirizzo, il quale restituisce l'indirizzo di memoria della variabile che lo segue):
    	TIPO_VARIABILE a;
    	TIPO_VARIABILE *p_a = &a;
    • come si evince dal precedente frammento di codice, per la dichiarazione di un puntatore si utilizza il simbolo *, ma per chiarire meglio il concetto si considerino i seguenti esempi:
      • con int *p_1 si dichiara la variabile puntatore p_1 di tipo int*, la quale potrà contenere l'indirizzo di memoria di una variabile di tipo int;
      • con int **p_2 si dichiara la variabile puntatore p_2 di tipo int**, la quale potrà contenere l'indirizzo di memoria di una variabile di tipo int*;
      • con int ***p_3 si dichiara la variabile puntatore p_3 di tipo int***, la quale potrà contenere l'indirizzo di memoria di una variabile di tipo int**;
    • al di fuori delle dichiarazioni, il simbolo * ha un altro significato, ovvero rappresenta l'operatore di dereferenziazione, il quale restituisce la variabile a cui punta il puntatore che lo segue. Per esempio il seguente codice stampa il contenuto attuale di b, ossia il valore 6:
    	int b = 5;
    	int *p_b = &b;
    	*p_b = 6;
    	printf("%d", b);
    • nell'ambito della programmazione C il termine “array” sarebbe da preferire al termine “vettore”;
    • un array v di N elementi di tipo TIPO_VARIABILE si dichiara come:
    	TIPO_VARIABILE v[N];
    • quando si utilizza l'identificatore di un array, tranne alcuni casi particolari che al momento puoi ignorare, esso viene convertito in un puntatore al suo primo elemento (si dice che l'array "decade" a puntatore al suo primo elemento). Per esempio il seguente codice stampa rispettivamente l'indirizzo di memoria del primo elemento dell'array e il valore del primo elemento dell'array (ossia 7):
    	int w[4] = {7, 8, 9, 10};
    	printf("%x\n", w);
    	printf("%d", *w);
    • lo stesso discorso vale anche nel momento in cui si passa un array come parametro ad una funzione, anche in questo caso infatti quello che si passa non è "l'array" nella sua interezza, ma solo il puntatore al suo primo elemento. All'interno della funzione (considerando nota la dimensione dell'array) sarà poi possibile scorrere l'intero array sfruttando l'aritmetica dei puntatori e il fatto che gli elementi di un array sono allocati in zone di memoria contigue, ma per il momento lasciamo stare;
    • da quanto appena detto si evince che se una funziona deve ricevere un array come parametro, è sufficiente impostare il relativo argomento come semplice puntatore e non per forza come array (con tanto di dimensione annessa). Per esempio la funzione
    	void fun(int w[4])
    	{
    		...
    	}

             può essere tranquillamente scritta come

    	void fun(int *w)
    	{
    		...
    	}
    • nel tuo caso l'utilizzo di quel typedef fa sì che
    	void print_vettore(vettore v)

            equivalga a 

    	void print_vettore(int v[N])
    • in ogni caso a questi livelli, per una questione di chiarezza, ma anche didattica, ti sconsiglio vivamente di utilizzare i typedef;
    • infine in C il passaggio di parametri ad una funzione avviene sempre per copia, quindi ovviamente l'unico modo di modificare variabili esterne alla funzione passa per la conoscenza dei loro indirizzi di memoria, e qui appunto entrano in gioco i puntatori.

    P.S.
    La prossima volta inserisci il codice in forma testuale utilizzando l'apposito pulsante.
    Inoltre sei sicuro che la funzione inverso() faccia quello che dovrebbe fare? A me sembra ci sia qualcosa che non va dal punto di vista logico…

  • Re: Problema con i vettori e le definizioni di tipo in C

    Ciao, ti ringrazio molto per la risposta, sicuramente mi hai aiutato a chiarire alcune cose.

    Il mio principale dubbio era il motivo per cui, nella funzione inverso, w[i] riuscisse a cambiare direttamente il contenuto delle variabili senza aver bisogno del simbolo * di dereferenziazione.

    E sinceramente questo punto è l'unico che ancora non mi è chiaro, dato che nel caso delle variabili una volta passato l'indirizzo di memoria, ad esempio &a, per accedere al suo contenuto nel main bisogna utilizzare appunto *a. 

    P.S. la funzione inverso posso assicurarti che funziona, nel caso ti interessasse verificare ti copio il codice qui sotto.

    #include <stdio.h>
    #define N 5
    
    typedef int vettore[N];
    
    void inverso(vettore, vettore);
    void print_vettore(vettore);
    
    int main() {
        vettore v ={1, 2,3,4,5};
        vettore w;
    
        inverso(v, w);
    
        printf("Il vettore originale e':");
        print_vettore(v);
        printf("Il vettore inverso e':");
        print_vettore(w);
        return 0;
    }
    
    void inverso(vettore v, vettore w){
        int i;
        for(i=0; i<N; i++){
            w[i]=v[N-1-i];
        }
        return;
    }
    
    void print_vettore(vettore v){
        int i;
        for(i=0; i<N; i++){
            printf(" %d\t", v[i]);
        }
        printf("\n");
    }
  • Re: Problema con i vettori e le definizioni di tipo in C

    14/07/2024 - BabboNataleacaso ha scritto:


    Il mio principale dubbio era il motivo per cui, nella funzione inverso, w[i] riuscisse a cambiare direttamente il contenuto delle variabili senza aver bisogno del simbolo * di dereferenziazione.

    Questo e' facile: scrivere

    int *pa;
    *pa = 10;

    e' EQUIVALENTE allo scrivere

    pa[0] = 10;

    Il C e' ‘stupido’: non conosce la differenza tra un array ed un puntatore ad un oggetto.
    Per lui sono ENTRAMBI array, o se vuoi, ENTRAMBI puntatori ad oggetti.

    Ed e' altrettanto EQUIVALENTE, scrivere

    pa[3] = 33;

    oppure

    *(pa+3)=33;

    .

    Ora l' “aritmetica dei puntatori”, tanto cara ai programmatori in erba perche' pensano sia piu' efficiente, puo' tranquillamente essere sostituita, nel 99% dei casi, con la normale sintassi per accedere all'i-esimo elemento di un vettore ("pa[i]", INFINITAMENTE piu' chiaro!) perche' si arrangia il compilatore a fare la conversione.

    E' responsabilita' del programmatore sapere se un puntatore e' relativo ad un array, nel qual caso e' meglio usare “pa[i]” OPPURE ad un oggetto, nel qual caso si usa “*pa”. Ricordando che “*pa” e' EQUIVALENTE a “pa[0]”.

    MA, al'atto pratico, NON CI SONO DIFFERENZE: il codice fa SEMPRE la stessa cosa.

  • Re: Problema con i vettori e le definizioni di tipo in C

    14/07/2024 - migliorabile ha scritto:


    Il C e' ‘stupido’: non conosce la differenza tra un array ed un puntatore ad un oggetto.
    Per lui sono ENTRAMBI array, o se vuoi, ENTRAMBI puntatori ad oggetti.

    Ti ringrazio tantissimo, era proprio questo che non capivo, ora mi è tutto chiaro, grazie.

  • Re: Problema con i vettori e le definizioni di tipo in C

    14/07/2024 - BabboNataleacaso ha scritto:


    P.S. la funzione inverso posso assicurarti che funziona, nel caso ti interessasse verificare ti copio il codice qui sotto.

    Non avevo letto bene, credevo andassi a modificare lo stesso array, invece ne utilizzi due.

Devi accedere o registrarti per scrivere nel forum
5 risposte