Spiegazione codice

Salve a tutti!

float parsenumber(char code,float val) {
  char *ptr=buffer;
  while(ptr && *ptr && ptr<buffer+sofar) {
    if(*ptr==code) {
      return atof(ptr+1);
    }
    ptr=strchr(ptr,' ')+1;
  }
  return val;
}

Qualche anima buona può spiegarmi le precedenti righe di codice? Ho cercato di capire come funzionano i puntatori e più o meno li ho capiti. Ma in questo caso, nella seconda riga di codice al puntatore “ptr” assegna l’indirizzo del primo elemento di buffer (array di caratteri)? Poi non ho capito bene le condizioni del while (“sofar” è l’indice dell’array di caratteri “buffer”). Spero che qualcuno gentilmente mi spieghi come funzionino queste poche righe di codice. Grazie in anticipo a chi risponderà. Buona domenica!

Manca del codice per capire cosa fa quella funzione. La tua è una domanda troppo generica che richiede troppe risposte. Posta tutto il codice e spiega cosa fa la funzione e dove l'hai presa, in questo modo ci sono più possibilità che un utente si interessi al post.

Quando ci sono di mezzo i puntatori, spesso la confusione è determinata dall'operatore *, il quale ha un significato differente a secondo del contesto.

Il contesto può essere: Una dichiarazione, riferimento al dato.

Inoltre come in questo caso, il nome di una variabile array è di per se un puntatore, nel senso che se stampo array viene fuori un indirizzo grande due byte, per risalire al dato presente a quell'indirizzo devo stampare *array. Quindi l'operatore * in questo caso svolge la funzione di riferimento al dato. Il sugo si allunga se consideriamo gli operatori [] che è un riferimento al dato, inoltre l'aritmetica dei puntatori array++ e altre poche cose che è necessario sapere per capire qualunque codice faccia uso di puntatori.

Considera che anche un programmatore navigato quando usa i puntatori è a rischio di errore, quindi bisogna prestare la massima attenzione. Quindi trovati un buon libro sul C e sperimenta i puntatori array ecc sul pc più che su arduino.

PS: Se cerchi nel forum questo argomento troverai più di un post.

Ciao.

MauroTec:
Manca del codice per capire cosa fa quella funzione. La tua è una domanda troppo generica che richiede troppe risposte. Posta tutto il codice e spiega cosa fa la funzione e dove l’hai presa, in questo modo ci sono più possibilità che un utente si interessi al post.

Quando ci sono di mezzo i puntatori, spesso la confusione è determinata dall’operatore *, il quale ha un significato differente a secondo del contesto.

Il contesto può essere:
Una dichiarazione, riferimento al dato.

Inoltre come in questo caso, il nome di una variabile array è di per se un puntatore, nel senso che se stampo array viene fuori un indirizzo grande due byte, per risalire al dato presente a quell’indirizzo devo stampare *array. Quindi l’operatore * in questo caso svolge la funzione di riferimento al dato. Il sugo si allunga se consideriamo gli operatori che è un riferimento al dato, inoltre l’aritmetica dei puntatori array++ e altre poche cose che è necessario sapere per capire qualunque codice faccia uso di puntatori.

Considera che anche un programmatore navigato quando usa i puntatori è a rischio di errore, quindi bisogna prestare la massima attenzione. Quindi trovati un buon libro sul C e sperimenta i puntatori array ecc sul pc più che su arduino.

PS: Se cerchi nel forum questo argomento troverai più di un post.

Ciao.

Innanzitutto grazie per la risposta. Ecco altre parti di codice per capire meglio questa funzione. Il contesto è quello di un interprete per il G-Code.

Le variabili:

char buffer[MAX_BUF];
int sofar;

Il setup:

void setup() {
  Serial.begin(BAUD);
  sofar=0;
}

Il loop:

void loop() {
  while(Serial.available() > 0) {
    char c=Serial.read();
    if(c=='\r') continue;
    Serial.print(c);
    if(sofar<MAX_BUF) buffer[sofar++]=c;  
    if(c=='\n') { 
      buffer[sofar]=0; 
      processCommand(); 
      sofar=0;
    }
  }
}

La funzione processCommand():

void processCommand() {
  long cmd;
  
  cmd=parsenumber('N',-1);
  if(cmd!=-1 && buffer[0]=='N') {  
  [..]
  }

  cmd = parsenumber('G',-1);
  switch(cmd) {
  [..]
  }

  cmd = parsenumber('M',-1);
  switch(cmd) {
  [..]
  }
}

La funzione parsenumber();

float parsenumber(char code,float val) {
  char *ptr=buffer;
  while(ptr && *ptr && ptr<buffer+sofar) {
    if(*ptr==code) {
      return atof(ptr+1);
    }
    ptr=strchr(ptr,' ')+1;
  }
  return val;
}

Mi sono accorto ora di aver risposto a tutti è 3 i topic aperti da te.

Ora è più chiaro il funzionamento di quel codice.

"Dovrebbe" restituire il numero dopo la lettera del GCode, N, G, ecc. Esempio con G1 restituisce 1.0.

return atof(ptr+1);

atof prende un puntatore char (es un buffer) e restituisce un float. Esempio: se ptr punta al primo carattere di "G1", ptr+1 punta al secondo che è la rappresentazione ASCII del numero 1. Nota atof richiede un puntatore a char in cui ci sia il terminatore di stringa '\0'. atof può anche restituire un numero costante NaN, cioè Not a Number, questo ovviamente in caso di fallimento.

char *ptr=buffer;

Visto che buffer è dichiarato come un array, il nome buffer equivale ad un puntatore. Se scrivessi buffer+1 modificherei buffer per puntare più avanti, dato che si vuole navigare nel buffer senza modificare il puntatore buffer si fa una copia in ptr.

Non mi sembra ci sia nient'altro da dire.

Ciao.

MauroTec:
Mi sono accorto ora di aver risposto a tutti è 3 i topic aperti da te.

Ora è più chiaro il funzionamento di quel codice.

“Dovrebbe” restituire il numero dopo la lettera del GCode, N, G, ecc.
Esempio con G1 restituisce 1.0.

return atof(ptr+1);

atof prende un puntatore char (es un buffer) e restituisce un float.
Esempio: se ptr punta al primo carattere di “G1”, ptr+1 punta al secondo che è la rappresentazione ASCII del numero 1. Nota atof richiede un puntatore a char in cui ci sia il terminatore di stringa ‘\0’. atof può anche restituire un numero costante NaN, cioè Not a Number, questo ovviamente in caso di fallimento.

char *ptr=buffer;

Visto che buffer è dichiarato come un array, il nome buffer equivale ad un puntatore.
Se scrivessi buffer+1 modificherei buffer per puntare più avanti, dato che si vuole navigare nel buffer senza modificare il puntatore buffer si fa una copia in ptr.

Non mi sembra ci sia nient’altro da dire.

Ciao.

Innanzitutto ti ringrazio per l’aiuto che mi stai offrendo. Ho provato a fare delle prove con la funzione atof

void setup() {                
  Serial.begin(9600);
}

char array[10] = "a23 b4.56";
float numero;

void loop() {
    numero=atof(array+x);
    Serial.println(numero);
}

Variando il valore di x nella funzione atof ho dedotto che restituisce un numero float solo se si punta a un numero. Mi spiego meglio con degli esempi:
x=0 (corrispondente ad “a”) → numero=0.00
x=1 (corrispondente ad “2”) → numero=23.00
x=2 (corrispondente ad “3”) → numero=3.00
x=3 (corrispondente ad " ") → numero=0.00
…e così via
Altra cosa che non avevo capito della funzione atof era che la conversione terminava quando nell’array non trovava più un numero. Ora è tutto molto più chiaro.
Ritornando alla funzione per ottenere il numero, ho pensato che può essere modificata nel seguente modo:

float parsenumber(char code,float val) {
  for(int i=0; i<sofar; i++)
  {
    if(buffer[i]==code)
    {
      return atof(buffer+(i+1));
    }
  }
  return val;
}

Senza l’utilizzo dei puntatori non si ottiene lo stesso risultato?

Nel while con puntatore, esce se la cella puntata contiene un valore nullo, ovvero fine stringa.

while(... && *ptr && ...

Lo fa in maniera un pò “grossolana” ovvero non verifica esattamente ptr!=’\0’ ma si basa sul fatto (mica sempre vero per tutti i sistemi) che la fine stringa ovvero ‘\0’ sia il valore 0 ovvero falso.
Quindi nel tuo for devi anche uscire se buffer
==’\0’*

nid69ita:
Nel while con puntatore, esce se la cella puntata contiene un valore nullo, ovvero fine stringa.

while(... && *ptr && ...

Lo fa in maniera un pò “grossolana” ovvero non verifica esattamente ptr!=’\0’ ma si basa sul fatto (mica sempre vero per tutti i sistemi) che la fine stringa ovvero ‘\0’ sia il valore 0 ovvero falso.
Quindi nel tuo for devi anche uscire se buffer
==’\0’*
[/quote]
Il controllo sulla stringa lo eseguo prima del parsing. Quindi penso non ci sia bisogno di mettere la condizione del fine stringa.