int zu char konvertieren und Null hinzufügen mit Funktion

Hallo, ich bin ganz neu in der Arduino Welt.
Ich brauche eine Funktion die ein int bekommt und ein char zurück gibt und sie soll noch eine 0 hinzufügen, also aus 1 wird 01 aus 5 wird 05

char* twodig(int zahl) {
    char* buf[2];
    sprintf (buf, "%02i", zahl);
    return buf;
  }

das ist mein Fehler:

sketch_jun10a:19: error: cannot convert 'char**' to 'char*' for argument '1' to 'int sprintf(char*, const char*, ...)'

     sprintf (buf, "%02i", zahl);

                               ^

sketch_jun10a:20: error: cannot convert 'char**' to 'char*' in return

     return buf;

               ^

exit status 1
cannot convert 'char**' to 'char*' for argument '1' to 'int sprintf(char*, const char*, ...)'

Du hast mit

char *buf[2];

kein Array mit 2 Character definiert sondern eins mit 2 Pointern auf char (also sogar 8 Byte).

Wenn du es denn richtig gemacht hättest, also

char buf[2];

kriegst du spätestens mit dem

sprintf (buf, “%02i”, zahl);

Ärger weil das sprintf im “Gut” fall (zahl zwischen 0 und 99) die beiden Ziffern in buf kopiert
und eine \0 anhängt für die aber kein Platz mehr ist (buf[2] !).
Also buf[3] wäre das mindeste !

So, zahl ist aber ein int, d.h. kann Werte zwischen -32768 und 32767 (auf dem Atmega)
annehmen. Das %02d hindert sprintf nicht daran größere Werte zu verarbeiten.
Also selbst bei buf[3] kracht es (oder es wird zumindes Speicher ungewollt überschrieben) wenn
zahl < 0 oder >99 ist.
Also entweder sicherstellen das zahl zwischen 0 und 99 ist oder char buffer[7]; deklarieren.
größte Darstellung wäre ja -32768 (6 Ziffern + \0 als Stringterminator)

Ulli

Vielen Dank, das hat schon mal geholfen.

Der neue Code gibt in der ersten if-Afrage nur eine leere Zeile aus und in der zweiten if-Abfrage ein Ausrufezeichen.

EDIT: zweite if geht jetzt, erste und dritte aber nicht:

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

void loop() {

  for (int i = 0; i < 15; i++) {
    Serial.print("i = ");
    Serial.print(i);
    Serial.print(" : ");
    Serial.println(twodig(i));
    delay(500);
  }
}

char* twodig(int zahl) {
  if (zahl >= 0 && zahl < 10) {
    Serial.print(" 1. if: ");
    char buf[12];
    buf[1] = zahl;
    buf[0] = '0';
    return buf;
  }

  else if (zahl >= 10 && zahl < 12) {
    Serial.print("2. if: ");
    char buf[12];
    sprintf (buf, "%02i", zahl);
    return buf;
  }
    else if (zahl >= 12 && zahl < 15) {
    Serial.print("3. if: ");
    char buf[12]="Test";
    return buf;
  }
}

Ausgabe:

i = 0 :  1. if: 
i = 1 :  1. if: 
i = 2 :  1. if: 
i = 3 :  1. if: 
i = 4 :  1. if: 
i = 5 :  1. if: 
i = 6 :  1. if: 
i = 7 :  1. if: 
i = 8 :  1. if: 
i = 9 :  1. if: 
i = 10 : 2. if: 10
i = 11 : 2. if: 11
i = 12 : 3. if: 
i = 13 : 3. if: 
i = 14 : 3. if:

Puhhh.

Du musst dich erst mal mit den Grundlagen der Programmiererei und von Computern
beschäftigen. Das sind ja so viel Hämmer auf einmal drinn.

Also add
a)

die Methode twodig gibt einen char * zurück.
Schön und schlecht. Das Object auf das dieser char * zeigt ist buf das erstens in
einem Block local definiert ist und zweitens innerhalb einer Funktion (Methode).
D.h. das Object liegt temporär auf dem Stack des Prozessors und ist nur gültig so lange
die Methode twodig läuft. Was du zurück gibst zeigt ins Nirwarna und klappt manchmal
zufällig !

b)
In if 1 erzeugtst du einen String in dem du zahl auf das erste Byte des Strings
schreibst und dann eine null drannhängst.

Du musst unterscheiden zwischen der binären Darstellung in dem int und der Asciiausgabe im
Buffer. Steht in Zahl der Wert 1 dann schreibst du auf buffer 0 diese 1 und gibst das als String aus.
Das geht nicht. 1 ist kein druckbares Asciizeichen ! Klappen würde buf[0] = zahl + 0x30 (Ascii '0');
Das ginge aber nur von 0 - 9 (Wert für Zahl). Bei einem Wert von Zahl von 26 würdes du auf die
Art ein "A" ausgeben. Aber warum das Theater, sprintf macht doch alles für dich ?

Noch einmal die binäre Zahlwert in einem Int passt in 2 Byte. Für die Ausgabe brauchst du je nach
Vorzeichen und führenden Nullen zwischen 1 und 6 Byte.

Noch mal eine Verdeutlichung ist der Wert im int 12593 so steht in den beiden Bytes des Ints in
Hex 0x31,0x31 oder dez 49 und 49. Gibst du diese beiden Bytes direkt aus siehst du 11 aber nicht 12593.

Na, all Klarheiten beseitig :o ?

Ulli

Vielen Dank für die Hinweise. Jetzt geht alles, ich habe aus dem Char ein String gemacht. Gibt es noch grobe Fehler?

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

void loop() {
  for (int i = 0; i < 62; i++) {
    Serial.println(twodig(i));
  }
  delay(5000);
}

String twodig(int zahl) {
  if (zahl >= 0 && zahl < 10) {
    char buf1[3];
    buf1[0] = '0';
    buf1[1] = '0' + zahl;
    buf1[2] = '\0';
    return buf1;
  }
  else if (zahl >= 10 && zahl < 61) {
    char buf2[3];
    sprintf (buf2, "%1i", zahl);
    return buf2;
  }
  return "NULL";
}

Das mit %02i (besser %02d) hat schon gepasst. Das formatiert eine Zahl auf minimal Stellen mit führenden Nullen. Wieso machst du das jetzt per Hand? Das ist Blödsinn

Normal würde man das so machen:

void setup() 
{
  Serial.begin(9600);
  char buffer[10];
  Serial.println(formatNumber(buffer, 5));
  Serial.println(formatNumber(buffer, 10));
  Serial.println(formatNumber(buffer, 100));
}

void loop() 
{
}

char* formatNumber(char* buffer, int value)
{
  sprintf(buffer, "%02d", value);
  return buffer;
}

Also den Puffer in der aufrufenden Funktion erstellen und als Parameter übergeben. Dann kann man den Zeiger wieder zurück geben, da er nicht auf lokalen Speicher zeigt. So funktionieren praktisch alle C String Funktionen dieser Art. Die Arduino String Klasse ist völlig überflüssig.

Der Sinn einer Funktion an der Stelle ist aber zweifelhaft.

elmarduino:
Vielen Dank für die Hinweise. Jetzt geht alles, ich habe aus dem Char ein String gemacht. Gibt es noch grobe Fehler?

void setup() {

Serial.begin(9600);
}

void loop() {
  for (int i = 0; i < 62; i++) {
    Serial.println(twodig(i));
  }
  delay(5000);
}

String twodig(int zahl) {
  if (zahl >= 0 && zahl < 10) {
    char buf1[3];
    buf1[0] = ‘0’;
    buf1[1] = ‘0’ + zahl;
    buf1[2] = ‘\0’;
    return buf1;
  }
  else if (zahl >= 10 && zahl < 61) {
    char buf2[3];
    sprintf (buf2, “%1i”, zahl);
    return buf2;
  }
  return “NULL”;
}

In diesem Beispiel hast du denn String wieder lokal in der Funktion !
Das funktioniert nur rein zufällig !!!

Mein Vorschreiber hat es dir richtig gezeigt !

Ulli

beeblebrox:
In diesem Beispiel hast du denn String wieder lokal in der Funktion

Es geht. Es ist lediglich umständlicher Unsinn. String ist ein Objekt! Das kann man zurück geben. return buf1 erstellt automatisch ein String Objekt und kopiert das Array da rein. Der Compiler kann da sogar etwas Optimierung mit dem Speicher betreiben und einige Kopien unterdrücken, so dass es in der Praxis gar nicht mal so schlimm ist wie es auf den ersten Blick aussieht (die Kopie vom Array in das String Objekt findest natürlich trotzdem statt).

Der normale Weg ist eben den Puffer außerhalb zu erstellen und als Parameter zu übergeben. Dann kann man auch einen Zeiger zurück geben da er auf gültigen Speicher zeigt.

elmarduino:
Ich brauche eine Funktion die ein int bekommt und ein char zurück gibt und sie soll noch eine 0 hinzufügen, ...

Serenifly:

  sprintf(buffer, "%02d", value);

Mag sein, ich verstehe die Aufgabenstellung falsch, aber ich würde

sprintf(buffer, "0%d", value);

mit der Ausgabe

05
010
0100

als treffender ansehen, da immer eine führende "0" hinzugefügt wird.

 sprintf(buffer, "%03d", value);

mit der Ausgabe

005
010
100

wäre rechtsbündig mit drei Stellen.

Serenifly:
Es geht. Es ist lediglich umständlicher Unsinn. String ist ein Objekt! Das kann man zurück geben. return buf1 erstellt automatisch ein String Objekt und kopiert das Array da rein. Der Compiler kann da sogar etwas Optimierung mit dem Speicher betreiben und einige Kopien unterdrücken, so dass es in der Praxis gar nicht mal so schlimm ist wie es auf den ersten Blick aussieht (die Kopie vom Array in das String Objekt findest natürlich trotzdem statt).

Der normale Weg ist eben den Puffer außerhalb zu erstellen und als Parameter zu übergeben. Dann kann man auch einen Zeiger zurück geben da er auf gültigen Speicher zeigt.

Oh Pardon !!! Ich habe übersehen das die Funktion vom Type String ist :frowning: .

Ich dachte sie wäre char * gewesen. Dann hätte es höchstwahrscheinlich gerummst !

Ulli

Ich frage mich auch gerade was der Unterschied zwischen 'char* name' und 'char *name' ist?

const char* host = "text";

const char *host = "text";

elmarduino fragt nach char*

char* twodig()

beeblebrox antwortet mit char *buff..

char *buf[2]; 2 Pointern auf char

sind beide schreibweisen Pointer?
const char* host = "text"; const char *host = "text";

Ich werd auch mit google nicht so richtig schlau :confused:

Ich frage mich auch gerade was der Unterschied zwischen 'char* name' und 'char *name' ist?

Nichts.
Auchchar * nameoder char*name wären erlaubt und dasselbe.

microco:
Ich frage mich auch gerade was der Unterschied zwischen 'char* name' und 'char *name' ist?

Die Position des Leerzeichens :wink: :wink:

Ich frage mich auch gerade was der Unterschied zwischen 'char* name' und 'char *name' ist?

Ich schreibe meist 'char * name'.
Weil ich mich da nicht entscheiden kann, was schöner ist.
Ist aber auch egal.