Newsgroup: it.comp.lang.c
Titolo: Accesso a matrice bidimensionale

Buongiorno a tutti, volevo capire se dichiarata una matrice 
bidimensionale, l'accesso a tutti gli elementi di una riga possa 
avvenire specificando per esempio, data
int matr [20] [20];
matr [10].
Ovvero: l'istruzione appena scritta è errata o restituisce un puntatore 
alla riga 11, come l'istruzione matr restituisce un puntatore all'inizio 
dell'array?
Grazie
Gian Leonardo



MMmmhh ... non sono sicuro che scrivere solo matr[10] sia corretto ... mi
sa di no ...
cmq, se proprio ti serve il puntatore alla riga 11, puoi scrivere
int *p = &(matr[10][0]);
che e' sicuramente corretta e funzionante.

 sa di no ...
Certo, questa è la soluzione lineare, mi chiedevo se esistano 
"abbreviazioni" del C che permettano, specificando solo la riga, di 
ottenere l'indirizzo, grazie mille comunque.
Gian Leonardo



Il McGraw-Hill, "Linguaggio C++", cita (quasi) testualmente a pagina 91:
"
.....
.....
Un array bidimensionale puo' essere ridotto a puntatore a un array di
array monodimensionali. [...] La funzione stampa il contenuto della riga
specificata per l'array di interi globale num:
int num[10][10];
void pr_row(int j)
{
  int *p, t;
  p = &(num[j][0]);
.....
.....
"
Anche il manuale riporta questa tecnica, quindi ti confermerei il fatto
che non si possa fare con un solo indice. Tuttavia, con un piccolo
esperimento, si potrebbe dimostrare questo mistero della fede.

 esperimento, si potrebbe dimostrare questo mistero della fede.
Indovina indovinello, cosa stampa il seguente codice?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
   int matr [20][20], ex;
   printf ("%d\n", matr);
   printf ("%d\n%d\n%d", matr [0], matr [1], matr [2]);
   scanf ("%d", ex);	
   return 0;
}
Stampa proprio le posizioni di memoria, tanto quanto matr!
ciao
Gian Leonardo



E allora vuol dire che si puo' fare ...
occhio alla scanf, c'e' un errore di probabile GPF ...
non passi l'indirizzo di ex ...

 non passi l'indirizzo di ex ...
Sě, lo so, č il modo brutale per farmi rimanere su la schermata :-)
Ciao
Gian Leonardo

 Stampa proprio le posizioni di memoria, tanto quanto matr!
Ma anche no: vedi sopra.
Attivando tutti i warning del compilatore (e soprattutto invocandolo in 
maniera standard-compliant) si possono talvolta scoprire gli errori:
[~]$ gcc -W -Wall -pedantic -ansi -o test test.c
test.c: In function `main':
test.c:8: warning: int format, pointer arg (arg 2)
test.c:9: warning: int format, pointer arg (arg 2)
test.c:9: warning: int format, pointer arg (arg 3)
test.c:9: warning: int format, pointer arg (arg 4)
test.c:10: warning: format argument is not a pointer (arg 2)
test.c:4: warning: unused parameter `argc'
test.c:4: warning: unused parameter `argv'
(Notare che un compilatore non e` pero` tenuto a emettere warning per 
gli argomenti passati alle funzioni che ne accettano un numero 
variabile: questa e` un'estensione del gcc).
Il programma corretto che stampa quello che tu vuoi stampare e` il seguente:
#include <stdio.h>
int main(void)
{
     int matr[20][20];
     printf("%p\n", (void *) matr);
     printf("%p\n%p\n%p\n", (void *) matr[0],
            (void *) matr[1], (void *) matr[2]);
     return 0;
}
Questo e` uno dei pochissimi casi in cui un cast e` necessario: infatti 
printf() con il formato "%p" (che e` l'*unico* adatto a stampare 
puntatori) si aspetta un puntatore a void. Non essendo garantito che il 
puntatore all'array di int abbia la stessa dimensione del puntatore a 
void, e` necessario convertirlo (un void* infatti puo` contenere 
qualsiasi indirizzo).

 leggere il documento dello standard
Mai sentita la frase "espressione ironica"?


Avevo capito benissimo che la tua era un'espressione ironica (non 
intendevo essere offensivo, sarcastico o saccente - solo pignolo).
La mia non era tanto una risposta a te, quanto una considerazione 
riguardo molta altra gente che invece crede davvero che esistano 
`misteri della fede' riguardanti il C (conosco molte persone di questo 
tipo, studenti in particolare).
Ad esempio, scrivo un programma in C che alloca memoria con malloc(). La 
sintassi e` perfetta, l'algoritmo corretto, ma misteriosamente ogni 
tanto il programma crasha in maniera clamorosa.
Il motivo e`: non ho controllato il valore di ritorno di malloc(), e a 
volte questa fallisce. Il mancato controllo puo` essere dovuto a molti 
fattori: non so che malloc() puo` fallire, oppure a scuola non me 
l'hanno insegnato, oppure `tanto la mia macchina ha 256 Gigabyte di Ram, 
figurati se puo` finire', oppure `ma in Java non c'e` bisogno di farlo', 
o semplicemente mi sono dimenticato.
Fatto sta che non so di aver commesso un errore.
Allora mi convinco del fatto che talvolta Kernighan e Ritchie dall'alto 
dei cieli sfoghino la loro collera scagliando fulmini su di me e sul mio 
software, oppure penso che i programmatori del compilatore siano degli 
imbecilli e abbiano scritto un programma inzuppato di bug fino al midollo.
O, peggio ancora, arrivo a sospettare che tutta questa faccenda del 
`Linguaggio Ci' sia frutto di una cospirazione del KGB con lo scopo di 
distruggere la sanita` mentale dei programmatori. Allora lascio perdere 
il C e mi metto a studiare Visual Basic che non ha questi problemi (non 
so se questo sia vero, ho semplicemente sparato il nome di un linguaggio 
che di solito e` ritenuto `facile').
Lo stesso problema si ha con il codice postato in questo stesso thread: 
a me non funziona. A colui che l'ha scritto si`. Purtroppo questo non 
basta a renderlo corretto, perche` nel momento che cambiera` macchina o 
compilatore forse non funzionera` piu`. Sono questi i seri problemi di 
portabilita` del quale il C e` accusato. Ma la colpa non e` del C, che 
e` fatto cosi` per essere efficiente. La colpa e` del programmatore che 
non lo sa.
Poi, se il tuo programma deve girare solo su una macchina ben precisa, 
sotto un certo sistema operativo etc etc, allora tutto ok, chi se ne 
frega della portabilita`. Ma se ci vuole cosi` poco per rendere un 
programma portabile, perche` non farlo?

 
Ok, grazie dell'aiuto. Cmq il tono della discussione era abbastanza 
allegro e mi sembra che tu non abbia messo alcuna faccina nella risposta :-(
Cmq, a me interessava capire se la logica da me assunta aveva un 
fondamento e pare che almeno sulla mia macchina funzioni. Il codice che 
ho postato l'ho scritto in 30 secondi senza pormi tutti i problemi che 
correttamente tu hai affrontato.
grazie
Gian Leonardo

Hai perfettamente ragione. Infatti, nel dubbio, io avevo consigliato
all'autore del thread di scrivere &(matr[10][0]), in modo da fugare
ogni dubbio ...
Figurati che uso sempre piu' parentesi di quelle dovute perche' non
ricordo mai la precedenza di tale operatore rispetto all'altro ...
Un conto e' "attaccarsi alla teoria" per divertimento, e allora, sai
com'e', possiamo inventarci le cose piu' assurde, tenendo sempre presente
che e' la documentazione dello standard a regolare e a mettere ordine in
tutto ...
Invece quando si scrive codice, soprattutto nella portabilita', mettere
qualche carattere in piu' che permette pero' sonni tranquilli e', a mio
avviso, d'obbligo ...
Ecco perche' li chiamo "misteri della fede" :-) ... sono al di fuori della
mia "pazienza di apprendimento" .. eh eh ..

 fondamento e pare che almeno sulla mia macchina funzioni.
Si` la logica e` corretta, era la forma ad essere sbagliata.

 avviso, d'obbligo ...
Sono pienamente d'accordo.
Soprattutto considerando che (come gli stessi K&R ammettono nella 
seconda edizione del libro) in C la precedenza di alcuni operatori e` 
sbagliata. Ad esempio, per controllare dei bit con una maschera, scrivere:
unsigned a = 0;
if (a & 0x1 == 0) {
     /* ... */
}
e` sbagliato, in quanto == ha precedenza piu` alta di &. Il test sarebbe 
quindi falso. Occorre scrivere:
if ((a & 0x1) == 0) {
     /* ... */
}

 }
L'esempio che hai appena riportato mi da' la possibilita', anche se non ti
conosco, di parlare anche per te con questa frase:
"Vogliamo arrivare all'eta' pensionabile possibilmente con il cervello che
va ancora a 4 cilindri!"
Giusto? :-D