Newsgroup: it.hobby.elettronica.digitale
Titolo: Puntatori e array...

Ciao,
anche se la domanda è più da NG C/C++ preferisco scrivere qua perché il 
codice andrà compilato con WinAVR.
Ho scritto una semplice funzione e l'ho compilata con il DevC++ per 
verificare di aver fatto giusto:
int8_t miafunc(char *s, char *fields[], uint8_t max_fields) {
	uint8_t i;
	char **token = fields;
	*token++ = s;
	i = 0;
	while(*s && i < max_fields) {
		if (*s == ',' || *s == '*') {
			*s++ = '\0';
			*token++ = s;
			i++;
		} else s++;
	}
	*token++ = '\0';
	return i;
}
Funziona come desiderato. Eseguendola sull'AVR invece ho risultati 
inaspettati. In particolare, sotto DevC++ scrivevo:
char rx[64];
char *fields[10];
i = miafunc(rx, fields, 10);
Nel caso dell'AVR ho cambiato le dichiarazioni in:
char fields[10][8];
int8_t miafunc(char *s, char fields[10][8], uint8_t max_fields);
Ma non mi riesce di trovare l'indirizzo base dell'array di array di char:
char **token = fields;
Mi sarei aspettato un **token = &fields[0][0]; ma il compilatore non è 
d'accordo con me...
Ci ho ragionato su un po', ma quando i livelli di "puntamento" diventano 
due mi perdo ancora :(
Riuscite a darmi una mano per favore?
--
Marco / iw2nzm

 due mi perdo ancora :(
Ok, ho risolto così:
int miafunc(char *s, char fields[][8], int max_fields) {
   int i, j;
   i = j = 0;
   fields[0][0] = *s;
   while(*s && i < max_fields) {
     if(*s == ',' || *s == '*') {
         *s++ = '\0';
         fields[i][j] = '\0';
         j = 0;
         i++;
     } else {
         fields[i][j] = *s++;
         j++;
     }
   }
   return i;
}
Anche se l'approccio è completamente diverso e meno elegante...
--
Marco / iw2nzm

 due mi perdo ancora :(
Non è che il problema è ancora a monte? Sei sicuro che char *fileds[] sia
correttamente allocato?

 correttamente allocato?
Sono quasi sicuro che non lo sia per nulla :)
Il punto è che char *fields[10] è un array di puntatori a char (come 
desiderato) ma ciascun elemento puntato (array di char) non è stato 
allocato.
Non so se il motivo per cui funziona sul DevC++ è dato dal fatto 
(fortuito) che la RAM del PC è vasta e non sono andato a sovrascrivere 
nulla.
Nel caso degli AVR ho riscritto la seconda versione del programma (vedi 
altro post) con gli array di dimensioni fisse e tutto funziona 
perfettamente. Non penso si possa fare diversamente, ma se qualcuno 
avesse altre idee benvengano!
--
Marco


Cosa ti dice il compilatore in particolare? Senza è un po' difficile 
capire :-)
In ogni caso io cambierei il prototipo in questo modo:
int8_t miafunc(char *s, char **fields, uint8_t max_fields);
E dovrebbe funzionare :-)
-- 
  _|/ Francesco Sacchi - Develer S.r.l., R&D dept.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org

 Marco / iw2nzm
Azzardo un'ipotesi: non è che il primo sia un compilatore
C++ e l'altro un C semplice?
La dichiarazione con inizializzazione
char **token = fields;
è valida solo in C++. Comunque dovresti dire se hai
un problema in fase di compilazione o di esecuzione.

 è valida solo in C++.
Sei sicuro? Non è una di quelle cose, come il "void", i prototipi delle
funzioni con dichiarazione del tipo degli argomenti, i commenti in-line
("//") e mi pare anche le "enum", che sono state "retroereditate" nel C
ANSI dal C++?
Almeno per i tipi di base, l'inizializzazione contestuale alla
dichiarazione è contemplarta dal K&R seconda edizione.

 dichiarazione è contemplarta dal K&R seconda edizione.
Sono abbastanza sicuro che l'inizializzazione di una
variabile auto con il valore di un parametro non sia
consentita nel C K&R e anche ANSI. Ad ogni modo
basta fare un'assegnazione nel corpo della funzione
e si aggira il problema.

 int8_t miafunc(char *s, char **fields, uint8_t max_fields);
In realtà ho già risolto e consegnato al cliente :)
Però appena ho tempo ci riprovo a seguire il primo metodo e il tuo 
consiglio....
Ciao!
Marco

 int8_t miafunc(char *s, char **fields, uint8_t max_fields);
Dunque parliamo di questa nuova e compattata versione:
int8_t mia_func(char *s, char *fields[], uint8_t max_fields) {
     uint8_t i = 0;
     *fields++ = s;
     while(*s && (i < max_fields)) {
         if (*s == ',' || *s == '*') {
             *s++ = '\0';
             *fields++ = s;
         } else s++;
     }
     return i;
}
Passare il parametro come **fields o *fields[] sembra essere indifferente.
A livello di compilazione non ho alcun warning.
In fase di esecuzione ho verificato che i token (',' e '*') sono 
correttamente sostituiti con '\0' e che la stringa s sia effettivamente 
quella ricevuta.
Il contenuto di fields (visualizzato con una printf("%s", fields[i])) è 
invece variabile ad ogni chiamata della funzione... quasi che puntasse 
chissà dove nella RAM.
In realtà la funzioncina è di una semplicità disarmante: ogni elemento 
dell'array di puntatori a char (fields) punta a un elemento della 
stringa iniziale. In particolare, fields[0] punta a s[0], mentre gli 
altri ai carattere successivi i token.
La cosa più strana è che in DevC++ va che è una meraviglia. Sto 
scaricando il MinGw per avere un compilatore ansi C ma ci sta mettendo 
ore...
Marco