Newsgroup: it.comp.lang.c
Titolo: Array Multidimensionali (di char)

Ciao a tutti,
poniamo che io abbia bisogno di un array di stringhe (per es. 10
stringhe di lunghezza 50 carattarei ciascuna).
Ho pensato di definirla cosi':
char s[10][50];
A) e' corretto?
B) dovrei forse usare char *s=malloc(500) ?
il problema non e' tanto questo (perche' in realta' cosi funziona), ma
se io voglio snellire il corpo della funzione di elaborazione (e' un
programmino di test) e quindi compiere parte della elaborazione in
un'altra funzione non riesco a passare s (o un suo elemento) e ad
ottenere s modificata.
Ho provato con funz(*s) e con funz(**s) passando s come lvalue, come
puntatore ecc. ecc.
ma se riesco a definire la funzione non riesco a trattarla e se riesco a
compilare senza warning ottengo un Segmentation Fault.
Ho provato sia con gcc (Linux) che Djgpp (dos).
Questa cosa riesco a farla tranquillamente con una stringa definendo la
funzione:
void *tr(char *s);
int main()
{
  ...
  char *s=malloc(100);
  tr(&s)
  ...
}
void tr(char **s)
{
  char *s1;
  ...
  *s=s1;
}
Grazie fin da adesso.
--== Sent via Deja.com 
http://www.deja.com/
 ==--
---Share what you know. Learn what you don't.---

**********************************************
***************PROVA CON:***************
 void *tr(char *s);
 int main()
 {
   ...
   char *s=malloc(100);
   tr(s);//<---
   ...
 }
 void tr(char& *s)//<---
 {
   char *s1;
   ...
   *s=s1;
 }
**********************************************

 B) dovrei forse usare char *s=malloc(500) ?
Non necessariamnete devi usare malloc().Dipende da che vuoi fare.
int main()
{
  extern void tr(char **);
  char *s[10];
 
  tr(s);
 
}
void tr(char **s)
{
  char **s1=s;
 
 
}
CiauZ!

ottenere s modificata.
La soluzione e' semplice :
#include <stdio.h>
#include <stdlib.h>
typedef char string_array[10][51] ;
void accetta_vettore_stringhe ( string_array * sa )
{
     int i ;
     for (i = 0; i < 10; i++)
     {
         printf ( "stringa n.%d = ", i ) ;
         fgets ( (*sa)[i], 50, stdin ) ;
     }
}
void stampa_vettore_stringhe ( string_array sa )
{
     int i ;
     for (i = 0; i < 10; i++)
         printf ( "stringa n.%d = %s", i, sa[i] ) ;
}
int main()
{
    string_array MioArray ;
    accetta_vettore_stringhe ( &MioArray ) ;
    stampa_vettore_stringhe ( MioArray ) ;
    return 0 ;
}
La soluzione dei problemi deve essere sempre la piu' semplice
possibile.
Che cos'e' l'oggetto su cui vuoi lavorare ? un array di stringhe ?
E' questo, allora, l'elemento base su cui operare.

No.
Certo che e' corretto !!!

 possibile.
Parole sante... peccato che il mercato dell'informatica di oggi se le
sia dimenticate... :-(
EMG

 possibile.
E' quello a cui vorrei arrivare :)
Grazie di nuovo per la disponibilita'.
Sent via Deja.com 
http://www.deja.com/


, 
andrea_...@bigfoot.com
 
says...

Si,si ho toppato. :-)
Intendevo dire che e' preferibile char*s[10].
Ciaoi!

Intendevo dire che e' preferibile char*s[10].
E che, tra l'altro, non e' vero.

dimensione) non sarebbe piu' "riutilizzabile"?.
Ci sono molti modi per fare cio' che dici ed alcuni di essi, tuttavia,
non sono molto sicuri.
Ad esempio si potrebbe utilizzare :
void funz ( char (*s)[LENGTH], int nrighe, int ncolonne ) ;
oppure
void funz ( char * s, int nrighe, int ncolonne ) ;
In questo secondo caso si maschera l'array bidimensionale con uno
monoddimensionale.
Ci sono due o tre sezioni delle FAQ che sto traducendo proprio a
questo riguardo e che saranno pronte tra breve, con tutta la sezione
dedicata ai vettori e puntatori.

lit...@my-deja.com
 wrote:
[ snip ]
lmdc>Cioe', se la funzione che deve trattare l'array di stringhe potesse
lmdc>trattare array di dimensioni diverse (passandogli per esempio altri due
lmdc>parametri corrispondenti agli elementi dell'array e alla loro
lmdc>dimensione) non sarebbe piu' "riutilizzabile"?.
Si.
Modificando il codice di ALF, una possibilita' potrebbe essere:
-------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
void accetta_vettore_stringhe(char *v, int num, int len)
{
        int i;
        for (i = 0; i < num; i++) {
                printf("stringa n.%d = ", i + 1);
                fgets(v + i * len, len, stdin);
        }
}
void stampa_vettore_stringhe(char *v, int num, int len)
{
        int i;
        for (i = 0; i < num; i++)
                printf("stringa n.%d = %s", i + 1, v + i * len);
}
#define NUM 10
#define LEN 50
int main()
{
        char *vettore = malloc(NUM * LEN);
        accetta_vettore_stringhe(vettore, NUM, LEN);
        puts("---- Separatore ----");
        stampa_vettore_stringhe(vettore, NUM, LEN);
        return 0;
}
-------------------------------------------------------------------
Ciao ciao,
Andrea
-- 
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and 
 the Ugly)."
(by Matt Welsh)

 E che, tra l'altro, non e' vero.
Dunque no.Io non ho idea di che volesse precisamemnte fare l'amico
visto che ho notato tre "..." e altri nel seguito del file ho scritto 
quel che di solito uso io per gli array di stringhe.Nel sesno che per me
è più leggibile,magari per altri no.Ma come no? Un array di puntatori
*ar[] e' più bello di ar[][] :-)E pure più efficiente in quanto usa 
un'operazione di addizione,che è più veloce,invece di moltiplicazione per 
spostarsi all'interno dell'array,non credi?
Saluti Egregio 

spostarsi all'interno dell'array,non credi?
scrivere *ar[] significa scrivere un vettore di puntatori.
scrivere a[][] significa scrivere un vettore di vettori.
Nel primo caso l'accesso a [2][3] e' dato da :
elemento [2][3] = *(*(ar + 2 * sizeof * ar)+3) ;
Nel secondo :
elemento [2][3] = 

spostarsi all'interno dell'array,non credi?
Non credo proprio.
Supponiamo di accedere all'elemento [i][j] :
Con *ar[] si ha 
- B = puntatore al primo elemento di ar
- p = *(B + i * sizeof (dimensione puntatore))
- [i][j] = *(p + j)
Con ar[][NCOLONNE] si ha
- B = puntatore al primo elemento di ar
- p = B + i * NCOLONNE + j
- [i][j] = *p

 - p = B + i * NCOLONNE + j
Aspe',guarda che se vuoi accedere ad un array bidimensionale(quindi con 
due colonne)la precedente formula è errata;se fosse int ar[2][3]con int 
di 4 byte e volessimo accedere ad ar[1][0]:
 ar+1*2+0 non funge.
Forse qui non ho ben capito cosa intendi. 
Io farei:  int *p=ar; *(p+(1*3*4))
oppure e piu' semplicemente:  *(*(ar+1)) 
Eppoi tu sei sei troppo in gamba te l'ho detto che no mi ci voglio 
mettere a discutere con te semai imparo leggendo da te e dagli altri sul 
news ;-)
Cmq il mio metodo funge!Ti allego sto esercizio che preferii fare coi 
puntatori piuttosto che con gli array è un bubble vabbe':
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define FALSE 0
#define TRUE 1
void main(){
 
    extern void ordina(char **, int);
    static char 
*str[]={"ciccio","bene","abaco","abucu","amico","ciccia","okay","abico","
marinaro","aAa"};
    char  c=0;
	ordina(str,sizeof(str)/sizeof(str[0]));
 
	while(c < (sizeof(str)/sizeof(str[0])))
	     printf("%s\n",str[c++]);
 
	exit(0);
}
 
void ordina(char **str,int i){
  char cond=FALSE;
  char *ar[1];
  char j=0,c=0,**temp=ar,**punt=str;
 
 
	while(!cond){
	    cond=TRUE;
	    for(j=0,punt=str;j < i-1;j++,punt++){
           if((strcmp(*punt,*(punt+1)) > 0)){
	          cond=FALSE;
	         *temp=*punt;
	         *punt=*(punt+1);
			 *(punt+1)=*temp;
 
			}
	   }
	}
}

 ar+1*2+0 non funge.
Ci risiamo, a parte il fatto che anche questa formula e' sbagliata, in
quanto dovrebbe essere ar+1*3+0, con B io intendo il puntatore al
primo elemento non vettore, ma singolo.
ar = &ar[0][0]
In questo caso la formula e' corretta. 

 moltiplicazione aggiuntiva.
Almeno concettualmente (come è anche scritto sulle FAQ), l'accesso ad un
elemento di un'array tramite un puntatore dovrebbe richiedere
un'indirezione in più rispetto all'accesso diretto tramite indice.
Questo perché, mentre il nome dell'array è l'indirizzo dell'oggetto
stesso, il nome del puntatore è l'indirizzo dell'indirizzo dell'oggetto.
In realtà poi le cose possono cambiare a causa del decadimento in
puntatore del nome dell'array e quindi i due accessi possono diventare
equivalenti.
EMG



Pero' stiamo attenti : il decadimento in questione avviene a tempo di
compilazione.
Nel senso che, a differenza di un puntatore, il nome di un vettore non
identifica una variabile.
Essendo il nome di un vettore un lvalue non modificabile, esso puo'
essere tradotto direttamente come indirizzo, evitando l'indirezione
intermedia tipica dei puntatori.
Quindi l'espressione "i due accessi possono diventare equivalenti" e'
discutibile in termini di efficienza.

 discutibile in termini di efficienza.
Questo è un estratto dell'ASM generato dal programmino che segue
(TurboC++ 1.01):
;        c = a[ 5 ];
;
     mov     al,byte ptr [bp-5]
     mov     byte ptr [bp-11],al
;
;        d = p[ 5 ];
;
     mov     al,byte ptr [si+5]
     mov     byte ptr [bp-12],al
#include <stdlib.h>
int main()
{
    char a[ 10 ];
    char *p = malloc( 10 );
    char c, d;
    c = a[ 5 ];
    d = p[ 5 ];
    return 0;
}
Non ti sembra che i due accessi siano identici?
EMG

 In questo caso la formula e' corretta. 
Si inmfatti ho toppato ancora grazie a un mio costrutto mentale:
immaginavo l'array cosi:
[0][0] 
[0][1]
[0][2]
[1][0]
...
invece che correttamente:
ar[2][3]={{1,2,3},
          {4,5,6}
          };
INfatti cosi è corretta.Scusa ancora #:-)                                

che l'accesso tramite i puntatori è più veloce.
E' evidente che si sbaglia.
Anzi, si e' portati a pensare che sia l'esatto contrario.

 il testo ripete cmq che l'accesso tramite i puntatori è più veloce.
Forse perché ci stiamo riferendo a due cose diverse. L'accesso
indicizzato dovrebbe essere più veloce in generale per l'array dato che
c'è un indirezione in meno ma forse questo non vale per l'accesso
tramite l'operatore di dereferenziazione e quindi la scansione di un
array tramite l'incremento del puntatore e l'accesso all'elemento
puntato potrebbe essere più veloce della scansione tramite indice. Es.:
int a[ 10 ];
int *p = malloc( 10 * sizeof( int ) );
int i;
int *q = p;
...
for ( i = 0; i < 10; ++i )
{
    printf( "%d\n", a[ i ] );     /* Di queste due dovrebbe essere più
veloce la prima */
    printf( "%d\n", p[ i ] );
    printf( "%d\n", *q++ );       /* Ma cosa si può dire di questa? */
}
Secondo me i compilatori moderni trasformano tutto nelle stesse
istruzioni ASM.
EMG

Non ti sembra che i due accessi siano identici?
Prova a scrivere :
c = *(a + 5) ;
d = *(p + 5) ;
Il DJGPP produce un codice piu' lungo per il secondo accesso.

 istruzioni ASM.
Puo darsi...non saprei proprio mi interessererebbe saperlo.
Credo cmq che ogni costruttore di compilatori tenti di fare in modo
che il prprio prodotto sia migliore,in qualche modo,rispetto alla 
cocnorrenza.E fino a che ci sarà concorrenza si troverà sicuramente 
qualcosa di buono anche se non sicuramente per le mie tasche :-)
Ma ora che scrivo rammento di aver sentito che il compilatore GNU è 
migliore di altri compilatori commerciali sotto molti aspetti;per contro 
è difficile da installare settare e utilizzare.Ci hanno fatto il gioco 
Quake,il primo se ben ricordo.

, 
e.m.gi...@flashnet.it
 
says:
Qui da me col tuo programmino:
8:        c = a[ 5 ];
00401035   mov         al,byte ptr [ebp-7]
00401038   mov         byte ptr [ebp-14h],al
9:        d = p[ 5 ];
0040103B   mov         ecx,dword ptr [ebp-10h]
0040103E   mov         dl,byte ptr [ecx+5]
00401041   mov         byte ptr [ebp-18h],dl
dereferenziando p viene uguale.
 

 
Qui da me vengono identici,ma non uso il DJGPP:
8:        c = *(a+5);
00401035   mov         al,byte ptr [ebp-7]
00401038   mov         byte ptr [ebp-14h],al
9:        d = *(p+5);


 Il DJGPP produce un codice piu' lungo per il secondo accesso.
Ma non si stava parlando dell'accesso tramite indice?
EMG

 Ci hanno fatto il gioco Quake,il primo se ben ricordo.
Ecco perché Quake II è molto più lento. :-)
EMG

 dereferenziando p viene uguale.
Sicuramente non hai attivato tutte le ottimizzazioni. Controlla e
ripeti. Dicci anche quale compilatore hai utilizzato, in modo tale da
poter fare la controprova.
EMG

00401041   mov         byte ptr [ebp-18h],dl
Non sono identici, nel secondo caso c'e' un evidente indirezione in
piu' !!!



No, si stava parlando se fosse piu' efficiente un puntatore o un
vettore...

se usati opportunamente al posto dell'indicizazzione tramite array.
Ahhhh ! ecco spiegato tutto ! 
Usi il testo di Herbert Schildt che tutto puo' conoscere, all'infuori
del C !!!
Ti do' un consiglio : buttalo e compra un "vero" libro sul C.

Ecco perché Quake II è molto più lento. :-)
Io invece ricordo che i giochi in questione sono stati creati col
Watcom C.

 vettore...
Boh, allora devo aver perso il filo del discorso...
EMG

 Watcom C.
Allora la colpa non è del compilatore ma del fatto che Quake II è a 32
bit...
EMG

bit...
Non saprei, ma forse la lentezza dipende dal fatto che e' realmente un
"programmone" e sarebbe adeguata una piattaforma molto veloce.
Non mi avventuro, comunque, in altre ipotesi ... ;)

 
Si scusa!#:-)
E' che ho fatto un copia/incolla.Intendevo dire sono identici sia che uso 
dereferenzizaione o indici.

 poter fare la controprova.
Si,avrei voluto farlo subito,ma uso VC6 e l'assemblato è troppo 
avanzato(win32)per me.Per ora ho solo conoscenze di base assembly e in 
dos(linguaggio assembly di Norton consci?).
Cmq ci ho tentato non proprio ottimizzato al max perchè non conosco tutte 
le opzioni del compilatore e ne ha parecchie;ho tentato di ottimizzarlo a 
livello di release e dovrei esserci riuscito,cmq le istruzioni che 
cerchiamo dovrebbero essere qui in mezzo:
00401098   push        ebp
00401099   mov         ebp,esp
0040109B   push        0FFh
0040109D   push        offset string "runtime error "+0FFFFFFF4h 
(00406020)
004010A2   push        offset __except_handler3 (00402ba0)
004010A7   mov         eax,fs:[00000000]
004010AD   push        eax
004010AE   mov         dword ptr fs:[0],esp
004010B5   sub         esp,10h
004010B8   push        ebx
004010B9   push        esi
004010BA   push        edi
004010BB   mov         dword ptr [ebp-18h],esp
004010BE   call        dword ptr [__imp__GetVersion@0 (00409108)]
004010C4   xor         edx,edx
004010C6   mov         dl,ah
004010C8   mov         dword ptr [__winminor (00407d10)],edx  ;forse sono
004010CE   mov         ecx,eax                                ;qui   
004010D0   and         ecx,0FFh
004010D6   mov         dword ptr [__winmajor (00407d0c)],ecx
004010DC   shl         ecx,8
004010DF   add         ecx,edx
004010E1   mov         dword ptr [__winver (00407d08)],ecx
004010E7   shr         eax,10h
004010EA   mov         [__osver (00407d04)],eax
004010EF   push        0
004010F1   call        __heap_init (004011f1)
004010F6   pop         ecx
004010F7   test        eax,eax
004010F9   jne         _mainCRTStartup+6Bh (00401103)
004010FB   push        1Ch
004010FD   call        __amsg_exit+25h (0040119c)
00401102   pop         ecx
00401103   and         dword ptr [ebp-4],0
00401107   call        __ioinit (004028da)
0040110C   call        dword ptr [__imp__GetCommandLineA@0 (00409104)]
00401112   mov         [__acmdln (004082d0)],eax
00401117   call        ___crtGetEnvironmentStringsA (004027a8)
0040111C   mov         [__aenvptr (00407ce4)],eax
00401121   call        __setargv (0040255b)
00401126   call        __setenvp (004024a2)
0040112B   call        __cinit (004021fe)
00401130   mov         eax,[__environ (00407d20)]
00401135   mov         [___initenv (00407d24)],eax
0040113A   push        eax
0040113B   push        dword ptr [___argv (00407d18)]
00401141   push        dword ptr [___argc (00407d14)]
00401147   call        @ILT+0(_main) (00401005)
0040114C   add         esp,0Ch
0040114F   mov         dword ptr [ebp-1Ch],eax
00401152   push        eax
00401153   call        _exit (0040222b)
00401158   mov         eax,dword ptr [ebp-14h]
0040115B   mov         ecx,dword ptr [eax]
0040115D   mov         ecx,dword ptr [ecx]
0040115F   mov         dword ptr [ebp-20h],ecx
00401162   push        eax
00401163   push        ecx
00401164   call        __XcptFilter (0040231e)
00401169   pop         ecx
0040116A   pop         ecx
0040116B   ret
0040116C   mov         esp,dword ptr [ebp-18h]
0040116F   push        dword ptr [ebp-20h]
00401172   call        __exit (0040223c)
Ciao.

 Ti do' un consiglio : buttalo e compra un "vero" libro sul C.
Anche ho detto anche...
Possibile che sia cosi come dici?
Dammene una prova!
DSi ho notato che a volte è un po' diciamo ambiguo,ma non credo che sia 
cosi male. :-(
Plz definisci quanto sopra!
Ciao!

 (Anche volendolo trasformare in ambiente di sviluppo tramite RHIDE).
Mai visto ne provato.Solo voci di corridoio.

 "programmone" e sarebbe adeguata una piattaforma molto veloce.
Quake II non è poi così diverso da Quake I e quindi quella differenza di
velocità è ingiustificata, secondo me. Solo il fatto che sia stato
scritto per WIN32 e non per DOS fa capire come stanno le cose... :-(
EMG

 Intendevo dire sono identici sia che uso dereferenzizaione o indici.
Allora, se č veramente cosě, la mia ipotesi č sbagliata.
EMG

 le opzioni del compilatore e ne ha parecchie;
Allora provale tutte. :-)
EMG

cosi male. :-(
http://www.lysator.liu.se/c/schildt.html
 

scritto per WIN32 e non per DOS fa capire come stanno le cose... :-(
Ecco perche'... :)

, 
andrea_...@bigfoot.com
 says...
ARGH!!!!
Mi faccio restituire i soldi?E' possibile?
Cmq..son  Dannazione!
..
..........
Ciao e grazie.

 Allora provale tutte. :-)
Si,si,ma per ora mi basta quel che conosco del compilatore.Altrimenti mai 
più finisco di leggere:Algoritmi in C,C guida completa(di Schildt
8-),pero' voglio leggerlo mi è costato un patrimonio!)rileggere principi 
di ingegneria del software(sono solo una qinquantina di pagg.),strutture 
dati in C(a propo conosci Horowitz,Sahani e Freed sono gli scrittori e 
il libro deve arrivarmi a giorni)e magari principi di ingegnerizzazione 
del software.
E quando mi passa? :-)
Ciao.