Passaggio di una matrice a ad una funzione. Linguaggio C

Giusyinthesky
Qualcuno può specificarmi come si passa un vettore bidimensionale ad una funzione nel C? Quindi la dichiarazione, la definizione e cosa si aspetta la funzione chiamante? e' necessario specificare tutte le dimensioni?
Ho provato a leggere l'argomento su più libri e dispense ma nessuno specifica bene questo aspetto,non so come fare:(..

Grazie in anticipo.

Risposte
yoshiharu
"Giusyinthesky":
Qualcuno può specificarmi come si passa un vettore bidimensionale ad una funzione nel C?


Secondo me il modo piu' pratico e' di passare il puntatore al primo elemento, e in altri due parametri le dimensioni...

apatriarca
Le matrici bidimensionali sono una di quelle funzionalità del C che sembrano interessanti, ma che alla fine si preferisce non usare. Una delle ragioni è proprio la difficoltà di passarle come argomento di una funzione. Come forse sai, quando un array monodimensionale viene passato come argomento di una funzione, viene passato solo il puntatore al suo primo elemento. Questo puntatore e il suo tipo sono infatti sufficienti per calcolare l'indirizzo di un qualsiasi elemento di questo array (si deve sommare all'indirizzo un multiplo della dimensione del tipo). Questa dimensione deve essere conosciuta durante la compilazione. Un array bidimensionale è di fatto un array di array di dimensione fissa. Si può cioè interpretare un array bidimensionale come l'array i cui elementi sono le righe. Dal discorso precedente avrai allora capito che è necessario conoscere la lunghezza di questa riga, cioè la dimensione dell'elemento riga, a compilazione. Quando passi un array bidimensionale si può cioè lasciare non segnata solo la seconda dimensione, mentre la prima è sempre necessaria. Se stai quindi lavorando con una matrice quadrata 4x4 avrai una funzioni del tipo:
void func(float mat[4][])

oppure
void func(float mat[4][4])

È però in pratica abbastanza raro voler lavorare su una singola dimensione per le righe e siccome è inoltre praticamente impossibile allocare una matrice bidimensionale dinamicamente, si lavora spesso con matrici monodimensionali anche quando si desidera una matrice bidimensionale e si usano poi schemi particolari di indicizzazione (non necessariamente quello usato nelle matrici bidimensionali standard) per ottenere gli oggetti della matrice.

_overflow_1
@apatriarca, avrai fatto un po' confusione ma hai sbagliato quando vuoi passare una matrice come parametro è esattamente il contrario di come hai detto ovvero quello che interessa al compilatore è sapere il numero di colonne non di righe...

quindi sarà una cosa del genere
void funzione(int mat[][5]);


inoltre ci sono anche altri modi per effettuare il passaggio ad esempio

void funzione(int **mat);


questo è solo un esempio di solito si passano anche due interi che rappresentano il numero di righe e di colonne della matrice oppure si può creare un'apposita struttura ecc. ecc.

Inoltre non è impossibile allocare una matrice dinamicamente anzi non è neanche troppo complicato basta fare una cosa de genere

int **mat;
int i;
.
.
.
    mat=(int **)malloc(sizeof(int *)*3);
    for(i=0; i<3; i++)
        mat[i]=(int *)malloc(sizeof(int)*5);
.
.
.


in pratica prima alloco un vettore di 3 puntatori e poi per ogni puntatore alloco lo spazio che serve a contenere 5 interi, in pratica 3 sono le righe e 5 le colonne, ho allocato dinamicamente una matrice $3x5$.

apatriarca
"_overflow_":
@apatriarca, avrai fatto un po' confusione ma hai sbagliato quando vuoi passare una matrice come parametro è esattamente il contrario di come hai detto ovvero quello che interessa al compilatore è sapere il numero di colonne non di righe...

quindi sarà una cosa del genere
void funzione(int mat[][5]);


Sì, hai ragione.. Mi sono confuso. Ho parlato correttamente di lunghezza di una riga (cioè il numero di colonne), ma poi mi sono confuso nel codice e ho pensato al numero di righe (cioè alla lunghezza delle colonne). Sono le dimensioni oltre la prima a dover essere segnate (anche se ho sempre pensato avesse più senso il contrario memorizzando quindi le matrici column-wise e non row-wise).

"_overflow_":

inoltre ci sono anche altri modi per effettuare il passaggio ad esempio

void funzione(int **mat);


questo è solo un esempio di solito si passano anche due interi che rappresentano il numero di righe e di colonne della matrice oppure si può creare un'apposita struttura ecc. ecc.

Come si può notare facendo un semplice test
#include <stdio.h>

void print(int **mat, int m, int n)
{
    int i, j;
    for (i = 0; i < m; ++i) {
        for (j = 0; j < n; ++j) {
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
}

int main()
{
    int m[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

    print(m, 3, 3);

    return 0;
}

non è possibile usare quel metodo. Sono in effetti riuscito a compilare, ma con un warning abbastanza chiaro:

Compiling: main.c
C:\...\main.c: In function 'main':
C:\...\main.c:18:5: warning: passing argument 1 of 'print' from incompatible pointer type
C:\...\main.c:3:6: note: expected 'int **' but argument is of type 'int (*)[3]'
Linking console executable: bin\Debug\ioProgrammo.exe
Output size is 28,24 KB
Process terminated with status 0 (0 minutes, 0 seconds)
1 errors, 1 warnings

Provando però a far girare il programma, questo va in crash appena il programma tenta di accedere alla matrice. La motivazione è che m non è un puntatore a puntatore e quando quindi il programma cerca di usarlo come tale, cerca di accedere alla locazione di memoria 0x0 che non è accessibile dal programma.



Inoltre non è impossibile allocare una matrice dinamicamente anzi non è neanche troppo complicato basta fare una cosa de genere

int **mat;
int i;
.
.
.
    mat=(int **)malloc(sizeof(int *)*3);
    for(i=0; i<3; i++)
        mat[i]=(int *)malloc(sizeof(int)*5);
.
.
.


in pratica prima alloco un vettore di 3 puntatori e poi per ogni puntatore alloco lo spazio che serve a contenere 5 interi, in pratica 3 sono le righe e 5 le colonne, ho allocato dinamicamente una matrice $3x5$.

Questa NON ha la stessa rappresentazione in memoria di una matrice bidimensionale allocata nello stack e non ne condivide molte caratteristiche a livello di performance. Inoltre, anche se non è impossibile, è senza dubbio più complicato dell'allocazione dinamica di un array monodimensionale ed è difficile gestire gli errori di allocazione (si possono certamente ignorare ma è di certo sconsigliato in un programma serio). Io non credo che possa essere considerata una valida alternativa all'allocazione di un array mono-dimensionale tranne nei casi in cui sia effettivamente necessario ricorrere a righe di lunghezza diversa (un file di testo forse?). In particolare se si sta lavorando in C++ con l'opportunità di fare l'overloading degli operatori. Ma facendo in questo modo si riesce certamente ad ottenere una notazione equivalente a quella degli array bidimensionale, se è questa l'intenzione.

_overflow_1
"apatriarca":

[quote="_overflow_"]
inoltre ci sono anche altri modi per effettuare il passaggio ad esempio

void funzione(int **mat);


questo è solo un esempio di solito si passano anche due interi che rappresentano il numero di righe e di colonne della matrice oppure si può creare un'apposita struttura ecc. ecc.

Come si può notare facendo un semplice test
#include <stdio.h>

void print(int **mat, int m, int n)
{
    int i, j;
    for (i = 0; i < m; ++i) {
        for (j = 0; j < n; ++j) {
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
}

int main()
{
    int m[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

    print(m, 3, 3);

    return 0;
}

non è possibile usare quel metodo. Sono in effetti riuscito a compilare, ma con un warning abbastanza chiaro:

Compiling: main.c
C:\...\main.c: In function 'main':
C:\...\main.c:18:5: warning: passing argument 1 of 'print' from incompatible pointer type
C:\...\main.c:3:6: note: expected 'int **' but argument is of type 'int (*)[3]'
Linking console executable: bin\Debug\ioProgrammo.exe
Output size is 28,24 KB
Process terminated with status 0 (0 minutes, 0 seconds)
1 errors, 1 warnings

Provando però a far girare il programma, questo va in crash appena il programma tenta di accedere alla matrice. La motivazione è che m non è un puntatore a puntatore e quando quindi il programma cerca di usarlo come tale, cerca di accedere alla locazione di memoria 0x0 che non è accessibile dal programma.


[/quote]

naturalmente, anche se non l'ho specificato, quando ho dichiarato quel prototipo avevo in mente una cosa del genere:


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

void print(int **mat, int m, int n);

int main()
{
    int **m, i, j;

    m=(int **)malloc(sizeof(int *)*3);
    for(i=0; i<3; i++)
        m[i]=(int *)malloc(sizeof(int)*3);

    for(i=0; i<3; i++)
        for(j=0; j<3; j++)
            m[i][j]=i+j;

    print(m, 3, 3);

    return 0;
}

void print(int **mat, int m, int n)
{
    int i, j;
    for (i = 0; i < m; ++i) {
        for (j = 0; j < n; ++j) {
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
}

Giusyinthesky
Grazie mille! più che esaurienti! :-) :)

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.