Ergänzende String-Funktionen in C

Einleitung

In C gibt es die Bibliothek „string.h“ in der sich einige Funktionen zu Stringoperationen befinden. Welche das sind, und was die machen möchte ich hier aber nicht erläutern denn dazu gibt es schon viele andere gute Erklärungen mit Beispielen im Netz. Hier möchte ich ausschließlich eigene Funktionen zeigen und bereitstellen die dazu dienen auf Mikrocontrollern mit Strings zu arbeiten.

Integer in String umwandeln

Manchmal (z.B. wenn man ein Grafisches Display verwendet) ist es sinnvoll, dass man eine Zahl ausgibt. Meist hat man sich eine Routine geschrieben (oder bekommen), um auf dem Display einen String auszugeben. Jetzt muss man aber noch eine Zahl in einen String umwandeln.

Dazu habe ich mir folgende Funktion geschrieben:

void toString(int32_t zahl, char* string, const char* pChar)
{
    char str_tmp[11]={0,0,0,0,0,0,0,0,0,0,0};
    uint8_t string_count = 0;
    uint8_t i;

    if(zahl<0)
    {
        string[string_count++] = '-';
        zahl = -zahl;
    }

    for(i = 9; i >= 1; i--)
    {
        str_tmp[i]=(zahl % 10) + '0';
        zahl /= 10;
        if(zahl==0)
            break;
    }

    for(i = 0; i < 11; i++)
    {
       if(str_tmp[i]!=0)
           string[string_count++]=str_tmp[i];
    }

    while(*pChar != 0)
    {
       string[string_count++] = *pChar;
       pChar++;
    }

    string[string_count] = 0;
}

Erklärung zur Anwendung

Als Übergabeparameter dient eine vorzeichenbehaftete 32Bit große Zahl. der Pointer auf einen String (bzw. ein Char-Array) dass groß genug ist, diese Daten aufzunehmen und ein String der mit angehangen werden soll.

Erklärung des Quelltextes

Eine 32Bit Zahl kann max 10 Zeichen als String verwenden. Mit diesem Gedanken wurde die Variable str_tmp erstellt. Diese hält temporär den erstellten String vor. Das Array ist nun aber 11 Zeichen groß! Das hängt mit dem Abschluss eines Strings zusammen der immer mit 0 bzw. ‚\0‘ enden muss damit man weiß, dass der String nun zu ende ist.

Die Variable string_count dient nun zum zählen der aktuellen Position in dem String.

Die Variable i ist eine einfache Indexvariable für die folgenden For-Schleifen. Einige Compiler können die Deklaration auch im Schleifen-header vornehmen. Da aber öfter Probleme damit auftreten habe ich das i vorgezogen.

Im ersten Teil wird nun also einfach festgestellt, ob es sich um eine Negative oder Positive Zahl handelt. Sollte die Zahl Negativ sein, wird an die erste (also Index 0) Position des Endgültigen Strings ein Minus eingebunden. Danach wird der string_count erhöht und die Zahl mit -1 Multipliziert (zahl = -zahl) damit die Konvertierung vorgenommen werden kann.

Nun beginnt die eigentliche Konvertierung. Es wird nun aber nicht in den Endgültigen String geschrieben sondern in den temporären String. Es wird ganz hinten im String angefangen und die erste Ziffer ermittelt indem man die Zahl mod 10 rechnet.

Beispiel: 12345 mod 10 = 5

Nun wird auf die 5 noch das ASCII Zeichen für 0 addiert. Dies entspricht einer 48. Man hat nun also das ASCII-Zeichen an der Stelle stehen. Nun wird die Zahl mit 10 dividiert um die bereits verwendete 5 zu entfernen. Dies wird solange wiederholt bis die Zahl 0 ist. Ist die Zahl vor Abschluss der Schleife 0 und würde die Prüfung auf 0 dort nicht stehen, würden alle übrigen Werte mit ‚0‘ aufgefüllt und der String würde so

0000012345
statt
12345

aussehen.

Nun befinden sich alle Zeichen am Ende des Char-Arrays welches mit einer 0 abschließt da die Schleife bei der 10ten Stelle begonnen hat dieses zu füllen. Das hilft uns aber nicht weiter, wenn wir den String mittels einer String Funktion bearbeiten oder auf dem Display ausgeben wollen. Zumindest nicht, wenn die Zahl nicht alle Stellen im String ausfüllt.

Dies korrigiert nun die vorletzte Schleife indem sie den temporären String durchläuft und jedes Zeichen das nicht 0 ist an die Position des string_count setzt. Wir erinnern uns, dieser sollte bei einer negativen Zahl 1 sein, und bei einer positiven 0. Nach dem einsetzen wird der string_count inkrementiert um auf die nächste Position zu zeigen. Ist diese Aufgabe abgeschlossen, wird nur noch in der letzten Schleife der String aus pChar angefügt und danach der String mit 0 abgeschlossen.

Anwendungsbeispiele

Hier mal ein Beispiel zur Anwendung:

char str[20] = "";
uint8_t zahl = 15;
toString(zahl, &str, "");

displayPrint(str);

// Ausgabe:
// 15

Die Zahl wird also an die Adresse von str geschrieben. Nun kann man das ganze noch ein wenig verfeinern indem man z.B. folgendes macht:

char str[20] = "Es ist ";
uint8_t zahl = 15;
toString(zahl, &str1, " Uhr");

displayPrint(str);

// Ausgabe:
// Es ist 15 Uhr

Es wird nun also die Adresse des 8ten Zeichens übergeben da dort die Zahl angefügt werden soll. Damit wird die 0 überschrieben, die Zahl angefügt und danach noch der String aus pChar.

Wichtig
Es ist natürlich darauf zu achten, dass das Char-Array für das Ziel genügend Speicherplatz hat um die Zahl aufzunehmen! Ist nicht genug Speicher vorhanden, wir einfach anderer Speicher überschrieben und dies kann zu unvorhersehbaren Fehlern führen.
Hinweis
Sollte man wissen, dass man nicht mehr als 8bit-Werte verarbeitet sollte die Funktion dementsprechend angepasst werden! So vermeidet man unnötigen Speicherverbrauch. Sollten alle Werte Positiv sein, kann man auch aus dem int32_t ein uint32_t machen und die Prüfung auf negative Werte entfernen.

Double in String umwandeln

Beim double verhält es sich nicht viel anders als bei einem Integer. Lediglich die Vorbereitung der Zahl ist etwas anders.

Hier sind die Übergabeparameter jedoch etwas anders. Zum einen die Zahl die geschrieben werden soll, wohin sie geschrieben werden soll, wie viele Nachkommastellen geschrieben werden sollen und welcher String angehangen werden soll.

Diese Funktion beginnt wie die toString() mit der Prüfung ob der Wert < 0  ist und schreibt dann ggf. ein „-“ in den endgültigen String. Danach muss der double erstmal in eine richtige Zahl umgewandelt werden um unsere schon besprochene Berechnung durchführen zu können. Dazu gibt es 2 temporäre Variablen: tempv für die Vorkommastellen und tempn für die Nachkommastellen.

Für die Vorkommastellen wird der double-Wert einfach in einen int16_t geparsed. Das führt dazu, dass die Kommastellen verschwinden und nur die Ganzzahlen über bleiben sofern die in den int16_t passen.

Bei den Nachkommastellen ziehen wir nun von double-Wert den ganzzahligen Anteil ab und erhalten nur noch die reellen Zahlen im Intervall [0,1). Für die gewünschte Anzahl an Nachkommastellen wird der Wert mit 10^x multipliziert. Für 1 Nachkommastelle also *10, für 2: *100, usw.

Danach ist eigentlich alles wie vorher, nur dass noch ein Komma mit eingesetzt wird.

Mögliche Probleme
  • Es kann sein, dass Sie die Menge der Nachkommastellen zu hoch wählen und die somit nicht in das temporäre Char-Array passen. Darauf sollte man achten.
  • Allgemein können Gleitkommazahlen sehr groß sein! Eine 32bit Gleitkommazahl hat einen Wertebereich von 1.17E-38 bis 6.80E+38. 38 Stellen sind also kein Problem und passen nicht in das 11 Zeichen große str_tmp.
Hinweis
Hier muss noch die „math.h“ eingebunden werden!
void doubleToString(double zahl, char* string, uint8_t nachkommastellen, const char* pChar)
{
    char str_tmp[11]={0,0,0,0,0,0,0,0,0,0,0};
    uint8_t string_count = 0;
    uint8_t i;
    if(zahl<0)
    {
       string[string_count++] = '-';
       zahl = -zahl;
    }
    int16_t tempv = (int16_t)zahl;
    int16_t tempn = (int16_t)((zahl-tempv)*pow(10,nachkommastellen));</pre>
    for(i = 9; i >= 1; i--)
    {
       str_tmp[i]=(tempn % 10) + '0';
       tempn /= 10;
       if(tempn==0)
          break;
    }
    i--;
    str_tmp[i--] = ',';
    for(; i >= 1; i--)
    {
       str_tmp[i]=(tempv % 10) + '0';
       tempv /= 10;
       if(tempv==0)
          break;
    }
    for(i = 0; i < 11; i++)
    {
       if(str_tmp[i]!=0)
          string[string_count++]=str_tmp[i];
    }

    while(*pChar != 0)
    {
       string[string_count++] = *pChar;
       pChar++;
    }
    string[string_count] = 0;
}

 

 

5 Kommentare

Schreib einen Kommentar