problema conversione stringa to char*

Salvea tutti, sono un vecchio utente e non scrivo da tanto.
Avrei da sottoporre un quesito e spero in un aiuto.

Situazione.
Devo stampare una stringa su un lcd usando questa libreria.

La funzione di stampa è semplice, : My595.DisplayWrite(char*,int);//L’int è il numero dello shift register.

Dunque io mi sono creato una funzione che accetta un int (valore di una sonda), ci mette lo zero davamti se è minore di 10 e la restituisce come char*.

Eccola :

char* convert_and_double(int val){
  String str;
  String pre="0";
  char* buf;
  if(val<10){
   str = pre+val;
  }else{
   str = String(val);
  }
  str.toCharArray(buf,2);
  Serial.println(str);
  return buf;
}

La chiamo così , per esempio : ,convert_and_double(2);

Ebbene il risultato è sulla seriale // 02, ma sul display dei numeri strani…
mi sto perdendo in un bicchier d’acqua o sono neipaticci ?
Grazie

Cioè questi:

Serial.println( convert_and_double(2) );
My595.DisplayWrite( convert_and_double(2)  , <tuonumero>);

Ti danno risultati diversi ?

Comunque, non puoi usare quel codice, è errato.

  1. buf è solo un puntatore, non hai nessuna zona di memoria dove scrivere. Un puntatore DEVE puntare a qualcosa e a te serve una zona di memoria con almeno 3 celle char (2 cifre più fine stringa ‘\0’)
    OCCHIO stringa alla C ovvero vettore/array di char terminato da fine stringa ‘\0’ mentre String è una classe che nasconde un vettore di char.
  2. anche se buf fosse un array di 3 char tu NON puoi metterlo nel return perchè quella variabile/array è locale alla funzione e “muore” all’uscita della funzione. Dovresti usare allocazione dinamica.

Secondo me ti converrebbe aggiungere a quella libreria una nuova funzione DisplayWrite che accetta un int da stampare.

Oppure fai una funzione che non ritorna nulla ma cambia un buffer passato come parametro (buffer globale abbastanza grande) e poi stampi quel buffer e ti sconsiglio usare la String, io uso snprintf() ma puoi usare itoa():

char tmpval[8];   // buffer temporaneo globale, va messo tra le variabili all'inizio

void convert_and_double(char * buf, byte dimbuf, int val)
{ snprintf(buf,dimbuf,"%05d",val);      // snprintf scrive dentro a buf il val, mette 0 davanti fino a 5 valori
}

void loop() {
...
convert_and_double(tmpval, sizeof(tmpbuf) , 2);
My595.DisplayWrite(  tmpval, <tuonumero>);
...
convert_and_double(tmpval, sizeof(tmpbuf) , 123);
My595.DisplayWrite(  tmpval, <tuonumero>);
...

Grazie nid ho capito la questione del puntatore..quindi non posso e va bene. La seconda soluzione, cioè quella di istanziare una variabile globale non mi piace per niente. Sto cercando di programmare con microfunzioni che fanno poche cose, in questo caso formatta e converti e vorrei finalizzare lo scopo. Continuerò con le ricerche magari riesco a trovare la soluzione, spero. Resta l'alternativa della funzione dentro la libreria che accetta un int lo trasforma e magari lo stampa ma comunque la libreria passa per lo shift register quindi non è così facile, inoltre io di C non ne so una mazza...lavoro in js e php figurati.

Intanto grazie per le spiegazioni, sei stato molto gentile ;)

Guarda, va bene "l'eleganza" ma non sei su PC e stai programmando su MCU con 2K di SRAM. Si fa in fretta a finirla (e quando capita il micro si riavvia). La libreria String alloca dinamicamente lo spazio, quando fai una riassegnazione a una String esistente rialloca e c'e' da sperare che la memoria liberata venga recuperata. Ma non siamo in Java con garbage collection, qui con il c/C++ l'allocazione, disallocazione devi farla tu. La funzione di cui sopra può fare allocazione di quel buffer con la malloc() e a quel punto puoi fare return del puntatore. Però chi la distrugge quella zona? Nessuno. Ripeto, non c'e' un gestore di garbage come in Java. Se chiami la funzione 10 volte, hai 10 volte l'allocazione dinamica senza liberazione di memoria. Si potrebbe passare da un oggetto di una classe con distruttore, ma poi quella libreria dovrebbe accettare un parametro di quell'oggetto.

Scusa, ma quella libreria ha anche il comando DisplayChar(char,sr); per stampare un singolo comando.
Puoi sfruttare quello per fare una funzione che converte in in buffer locale alla funzione stessa e stampa 1 carattere per volta.

E quella libreria da estendere non è difficile. Guarda cosa fa la DisplayWrite()

void hc595::DisplayWrite(const char *buff,unsigned char display)
{ int ln=strlen(buff);
  for(int i=0;i<ln;i++) {DisplayChar(buff[i],display);}
}

Ovvero sfrutta la DisplayChar per stampare 1 char alla volta. Perciò:

void hc595::DisplayWriteInt(int val,unsigned char display)
{ char buff[6];     // int max 5 char + '\0'
  int ln;
  ln=snprintf(buff,6,"%d",val);
  for(int i=0;i<ln;i++) {DisplayChar(buff[i],display);}
}

Si hai ragione circa l’eleganza e il limite memoria, am mi capita che poi se rimetto mano al codice dopo 6 mesi mi tocca praticamente riscriverlo se non uso uno pseudo sistema ad eventi e funzioni.
Cmq…aspetta ti mostro la soluzione che fa al caso mio ( un po cafona…) ma fa il suo porco lavoro :smiley:

Secondo me ti conviene estendere quella libreria aggiungendo la DisplayWriteInt() come ti ho scritto sopra. Elegante, semplice.

void print_converted(int x, int y, int val){
  //Converte il numero da stampare in char 
  //Se minore di 10 stampa prima 0 e alla x successiva val convertito
  //Se maggiore di 10 stampa all x il val convertito
}

e magari non ci pensiamo più!

Giusto per i posteri…
non sia mai dovesse servire codice impeccabile :fearful:

void print_converted(int x, int y, int val){
  char sval[3];
  itoa(val, sval,10);
  if(val<10){
    lcd_testo((x+1),y,sval);
    lcd_testo(x,y,"0");
  }else{
    lcd_testo(x,y,sval);
  }
}

…vabbè sputatemi pure ma io ho risolto!! tiè! :grin:

un int può essere a 5 cifre, almeno fai un controllo nella funzione che il valore non superi 99 :grin:

nid69ita: un int può essere a 5 cifre, almeno fai un controllo nella funzione che il valore non superi 99 :grin:

... SEI caratteri ... c'è il segno (-32768) ]:D ]:D ]:D

Guglielmo

gpb01:

nid69ita: un int può essere a 5 cifre, almeno fai un controllo nella funzione che il valore non superi 99 :grin:

... SEI caratteri ... c'è il segno (-32768) ]:D ]:D ]:D

Guglielmo

Io penso positivo :grin: :grin: :grin:

nid69ita: Io penso positivo :grin: :grin: :grin:

... quindi sei un unsigned int ... :grin: XD :grin: XD

Guglielmo

gpb01:

nid69ita: Io penso positivo :grin: :grin: :grin:

... quindi sei un unsigned int ... :grin: XD :grin: XD Guglielmo

E mò non posso che andare OT e risponderti che mi sento molto più un [u]unsigned short[/u] essendo h. 158 cm :grin:

@nid69ita ups!..trovato un essere umano meno alto di me (163) ..e io che credevo di essere l'ultimo gollum sul pianeta terra!