Difficoltà lettura array puntatori

di il
10 risposte

Difficoltà lettura array puntatori

Bentrovati a tutti voi. Avrei bisogno di una mano per venir fuori da una situazione difficile da sgarbugliare. Sono un programmatore VB ed ho necessità di tradurre alcune routine da C a VB 6.0. La complicazione è nel interpretare l'aritmetica dei puntatori sulla cui comprensione non ho avuto difficoltà ma trovo la sintassi degli array parecchio ostica da assimilare. Qualcuno di voi potrebbe darmi indicazioni su come interpretare gli indici degli array di questa routine?

void laplacian(double *x, double *res) {
/*x and res have dimensions n x m */
int i, j;

for (i = 1; i < n - 1; i++) {
for (j = 1; j < m - 1; j++) {
// nodes not nearest the boundary: apply standard 5 point stencil
res[i*m + j] = (x[(i+1)*m+j]-2*x[i*m+j]+x[(i-1)*m+j])/deltaxsqr +
(x[i*m+j+1]-2*x[i*m+j]+x[i*m+j-1])/deltaysqr;
}
// nodes near boundary: assume zero Neumann BC's
res[i*m] = (x[(i+1)*m] -2*x[i*m]+x[(i-1)*m])/deltaxsqr +
(x[i*m+1] - x[i*m])/deltaysqr;
res[i*m+m-1] = (x[(i+1)*m+m-1]-2*x[i*m+m-1]+x[(i-1)*m+m-1])/deltaxsqr +
(-x[i*m+m-1]+x[i*m+m-2])/deltaysqr;
}
for (j = 1; j < m - 1; j++) {
res[j] = (x[m+j]-x[j])/deltaxsqr +
(x[j+1]-2*x[j]+x[j-1])/deltaysqr;
res[(n-1)*m+j] = (-x[(n-1)*m+j]+x[(n-2)*m+j])/deltaxsqr +
(x[(n-1)*m+j+1]-2*x[(n-1)*m+j]+x[(n-1)*m+j-1])/deltaysqr;
}
res[0] = (x[m] - x[0])/deltaxsqr + (x[1] - x[0])/deltaysqr;
res[(n-1)*m] = (-x[(n-1)*m] + x[(n-2)*m])/deltaxsqr +
(x[(n-1)*m+1]-x[(n-1)*m])/deltaysqr;
res[m-1] = (x[m+m-1]-x[m-1])/deltaxsqr +
(-x[m-1] + x[m-2])/deltaysqr;
res[(n-1)*m+m-1] = (-x[(n-1)*m+m-1]+x[(n-2)*m+m-1])/deltaxsqr +
(-x[(n-1)*m+m-1]+x[(n-1)*m+m-2])/deltaysqr;
}

In realtà sono queste quattro ultime equazioni che proprio non riesco a comprendere. Se res è un array bidimensionale a cosa stà puntando res[0]? E res[m]? Qual'è il corrispondente indice nella scrittura canonica degli array (array(x,y))?
Grazie infinite per quanto vorrete fare

clandestino

10 Risposte

  • Re: Difficoltà lettura array puntatori

    Ciao,

    Il programmatore in questo caso ha preferito utilizzare array monodimensionali del tipo a[m*n] (più performanti e frammentano meno la memoria) al posto di array bidimensionali a[m][n].

    Le migliori performance si traducono in un certo lavoro in più per l'accesso agli elementi... dato a[m*n] l'elemento in posizione i,j si troverà in a[j*m+i] (o, se si vuole usare una memorizzazione per colonne anziché per righe, in a[i*n+j]). Dove vedi il * sta calcolando la riga (o colonna) a cui accedere, il + indica l'altra coordinata.

    Per quanto riguarda le domande... res[0] punta a res[0*m+0] ovverosia l'elemento (0,0)
    res[m] punta a res[1*m+0] ovverosia l'elemento in posizione (1,0), oppure a res[0*m+m] (sarebbe l'elemento 0,m che però, in questo caso, è lo stesso elemento, visto che la colonna non può essere >=m).

    Se non ti è sufficientemente chiaro, prova a disegnare graficamente una griglia (l'array bidimensionale) e immagina di numerare le caselle della prima riga 0...m-1, quelle della seconda m...2m-1, quelle della terza 2m...3m-1 e così via... in questo modo ti appare abbastanza chiaro quello che succede.

    In casi come questo è talvolta utile definire una macro di questo tipo:
    #define POS(i,j) (((j)*m)+i)

    In modo da poter scrivere res[POS(i,j)]... ovviamente la macro fa riferimento ad un parametro m implicito che non è bellissimo da vedere... in alternativa si può scrivere una macro a tre parametri che tenga conto anche della dimensione:
    #define POS(x,y,dim) (((y)*(dim))+x)
    E l'accesso avviene con res[POS(i,j,m)];

    Ciaociao
  • Re: Difficoltà lettura array puntatori

    Grazie infinite bottomap. Vedrò di fare come mi hai detto. A buon rendere

    clandestino
  • Re: Difficoltà lettura array puntatori

    Perdonami ancora bottomap ma vorrei approfondire quanto gentilmente mi hai comunicato:

    "res[m] punta a res[1*m+0] ovverosia l'elemento in posizione (1,0), oppure a res[0*m+m] (sarebbe l'elemento 0,m che però, in questo caso, è lo stesso elemento, visto che la colonna non può essere >=m). "

    Quindi mi sembra di capire che i valori a cui punta res[m] sono diversi! Potresti indicarmi come faccio a capire senza commettere errore a quali dei due valori punta realmente, se a (1,0) o (0,m)?

    Grazie per quanto vorrai fare

    clandestino
  • Re: Difficoltà lettura array puntatori

    Forse ho capito bottomap. Devo leggere i valori come se fossero ordinati in fila indiana; se faccio così il valore assoluto di m coinciderebbe con il primo elemento della riga successiva. E' Cosi?

    Grazie

    clandestino
  • Re: Difficoltà lettura array puntatori

    In particolar modo potreste essere così gentili da tradurmi in modo convenzionale queste due espressioni?

    res[(n-1)*m] = (-x[(n-1)*m] + x[(n-2)*m])/deltaxsqr +
    (x[(n-1)*m+1]-x[(n-1)*m])/deltaysqr;

    res[m-1] = (x[m+m-1]-x[m-1])/deltaxsqr +
    (-x[m-1] + x[m-2])/deltaysqr;

    Grazie mille

    clandestino
  • Re: Difficoltà lettura array puntatori

    Ciao,

    Si... hai intuito bene... c'è una sovrapposizione di elementi dovuta al fatto che l'insieme righe/colonne sono classi di resto (modulo m ed n) rispetto agli indici dell'array (se mastichi un po'di matematica non è difficile immaginarlo).

    res[1*m+0] e res[0*m+m] puntano allo stesso elemento perché (1,0) ed (0,m) sono effettivamente lo stesso elemento... 0,m non esiste logicamente (visto che gli indici sono nel range 0...m-1), fisicamente però è l'elemento 0 della riga sottostante, visto che l'array è un unico lungo vettore monodimensionale...

    Per il codice che hai proposto, la cosa dipende dal tipo di memorizzazione (per righe o per colonne), ad ogni modo può essere qualcosa del tipo:

    res(n-1,0)=( -x(n-1,0) + x(n-2,0) ) / deltaxsqr + ( x(n-1,1) - x(n-1,0) ) / deltaysqr;

    res(0,m-1) = ( x(1,m-1) - x(0,m-1) ) / deltaxsqr + ( -x(0,m-1) + x(0,m-2) ) /deltaysqr;

    Non so se l'indicazione degli indici è corretta... in caso vanno ribaltate le x con le y... dipende da quale senso vuoi dare al primo e quale al secondo.

    Ciaociao
  • Re: Difficoltà lettura array puntatori

    Dio ti benedica bottomap. Grazie infinite. Non sai quanto mi sei stato utile. Se posso esserti utile sono a tua disposizione.
    Comunque volevo farti notare una cosa, giusto per un aspetto didattico.

    Supponiamo che n sia un indice di colonna ed m un indice di riga, che sia n=m e che il programmatore C abbia scelto di impostare una matrice letta per colonne (n,m).

    Secondo queste scelte risulta chiaro da quanto mi hai spiegato che res[n-1*m] corrisponde all'elemento res[n-1,0] quindi leggo l'ultimo elemento della riga 0.
    Secondo le stesse scelte però se decido di leggere gli elementi sfruttando l'array monodimensionale ho solo un modo per interpretare la scrittura res[m-1] e cioè devo leggere gli elementi come se fossero in fila indiana e troverei che questo elemento corrisponderebbe all'ultimo elemento della riga 0 poichè m per il compilatore è solo un intero.
    Ma a questo punto troverei che l'elemento letto è esattamente quello di prima!!
    Allora l'unica possibilità è che esista un modo di dire al compilatore che se "vede" m si tratta di righe invece se vede n si tratta di colonne.
    Ma è così?
    Ti prego abbi pazienza e chiariscimi anche questa cosa.
    Grazie comunque

    clandestino
  • Re: Difficoltà lettura array puntatori

    Ciao,

    Uellalla'... non farmi così tanti complimenti che arrossisco

    Veniamo alla domanda che hai posto:
    Secondo queste scelte risulta chiaro da quanto mi hai spiegato che res[n-1*m] corrisponde all'elemento res[n-1,0] quindi leggo l'ultimo elemento della riga 0
    In realtà secondo quanto abbiamo detto stiamo leggendo l'elemento della riga n-1, colonna 0... quello che moltiplichi è la riga (se organizzi righe per colonne - purtroppo è sempre una questione di come si interpretano le cose, l'importante è che se scrivi in un modo rileggi nello stesso modo).
    La prima riga in fatti va da 0*m+0..0*m+(m-1), la seconda da 1*m+0..1*m+(m-1), ecc...
    Come detto se per (a,b) indichi la coppia (colonna,riga) gli indici nell'esempio che ho postato vanno ribaltati...

    In sostanza, se m è la dimensione di una riga, quello che moltiplichi per m è sempre l'indice della riga... e quello che aggiungi è l'indice della colonna. Se hai bisogno dal numero intero di ricavare gli indici l'operazione è abbastanza semplice (esattamente l'inverso di quello che fai per ottenere l'indice):
    - Il numero della riga si ottiene dividendo (NB:deve essere una divisione intera) il numero per m.
    - Il numero della colonna si ottiene mettendo a modulo (%) il numero con m, ovvero ottenendo il resto della divisione intera.

    Immagina, con la moltiplicazione per m, di spostarti sulla riga necessaria (in "verticale" sulla nostra immaginaria griglia), e poi da li di spostarti "in orizzontale" di un certo numero di posizioni (che saranno strettamente minori di m - se sono maggiori o uguali l'effetto è quello di continuare a spostarsi sulla riga sottostante).

    Ciaociao
  • Re: Difficoltà lettura array puntatori

    Grazie bottomap. Per la generosità e la competenza. Avrei piacere se potessi consigliarmi un buon testo su cui poter approfondire questi argomenti.
    A buon rendere amico

    clandestino
  • Re: Difficoltà lettura array puntatori

    Ciao,

    Purtroppo non so consigliarti granché... non tocco un libro sul C ormai da diversi anni e quelli che conoscevo (tra cui il vecchio Kernigham-Ritchie ANSI C) affrontano, un po'come tutti, solamente le basi...
    Il resto delle conoscenze le ho fatte "sul campo" (trattando spesso la grafica - con gli amici programmiamo, amatorialmente, videogiochi - queste operazioni sono talmente comuni che dopo un po' vengono spontanee e non rappresentano più un problema).

    Per il resto ho sentito parlare bene sia dello Stroustroup (per quanto riguarda il C++ stretto - d'altronde è uno dei fondatori del linguaggio) che del Thinking in C di Bruce Eckel (ne esiste, mi pare, anche una versione online)... ma non so darti una recensione di prima mano, né dirti se affrontano approfonditamente le operazioni sui vettori. Sicuramente sono entrambi ottimi testi di base, almeno per quanto ho potuto sentire.

    Ciaociao
Devi accedere o registrarti per scrivere nel forum
10 risposte