Passaggio di una matrice a ad una funzione. Linguaggio C

Messaggioda Giusyinthesky » 14/06/2011, 10:03

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.
Giusyinthesky
Junior Member
Junior Member
 
Messaggio: 46 di 196
Iscritto il: 06/01/2011, 16:28

Re: Passaggio di una matrice a ad una funzione. Linguaggio C

Messaggioda yoshiharu » 14/06/2011, 10:24

Giusyinthesky ha scritto: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...
yoshiharu
Average Member
Average Member
 
Messaggio: 39 di 970
Iscritto il: 17/01/2011, 17:11

Messaggioda apatriarca » 14/06/2011, 14:22

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:
Codice:
void func(float mat[4][])

oppure
Codice:
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.
apatriarca
Moderatore
Moderatore
 
Messaggio: 1186 di 10436
Iscritto il: 08/12/2008, 20:37
Località: Madrid

Messaggioda _overflow_ » 14/06/2011, 16:20

@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
Codice:
void funzione(int mat[][5]);


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

Codice:
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

Codice:
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$.
_overflow_
Junior Member
Junior Member
 
Messaggio: 188 di 323
Iscritto il: 09/09/2009, 11:31

Messaggioda apatriarca » 14/06/2011, 17:52

_overflow_ ha scritto:@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
Codice:
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_ ha scritto:inoltre ci sono anche altri modi per effettuare il passaggio ad esempio

Codice:
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
Codice:
#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

Codice:
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.
apatriarca
Moderatore
Moderatore
 
Messaggio: 1187 di 10436
Iscritto il: 08/12/2008, 20:37
Località: Madrid

Messaggioda _overflow_ » 14/06/2011, 18:39

apatriarca ha scritto:
_overflow_ ha scritto:inoltre ci sono anche altri modi per effettuare il passaggio ad esempio

Codice:
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
Codice:
#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.




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

Codice:

#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");
    }
}
_overflow_
Junior Member
Junior Member
 
Messaggio: 189 di 323
Iscritto il: 09/09/2009, 11:31

Messaggioda Giusyinthesky » 14/06/2011, 21:16

Grazie mille! più che esaurienti! :-) :)
Giusyinthesky
Junior Member
Junior Member
 
Messaggio: 50 di 196
Iscritto il: 06/01/2011, 16:28


Torna a Informatica

Chi c’è in linea

Visitano il forum: Google [Bot] e 1 ospite