Von mir verwendete C-Funktionen und C-Funktionalitäten in Arduino

Da ich nicht mit der Programmiersprache C vorbelastet bin, wollte ich ursprünglich meine Programme rein in Arduino, also ohne zusätzliche C-Funktionen und -Funktionalitäten, programmieren.

Bald habe ich allerdings erkannt, dass es doch ab und zu ganz nützlich sein kann, meinen Vorsatz zu brechen und auf C-Funktionen und -Funktionalitäten zurück zu greifen, wenn dadurch die Programmierung einfacher wird. Vor allem bei der Bearbeitung von Zeichenketten nütze ich vermehrt die C-Funktionen, auch wenn Arduino mit seiner "String class" recht umfangreiche Funktionen bei der String-Bearbeitung zur Verfügung gestellt hat. Manchmal kommt man aber eben mit Stringfunktionen in C besser zum Ziel, vor allem wenn man bedenkt, dass es bei der Verwendung der "String class" zur Speicherfragmentierung kommt, die im schlimmsten Fall zum Programmabsturz führen kann.

Zur Dokumentation stelle ich daher nach und nach die von mir verwendeten C-Funktionen mit ihren Prototypen und sonstige Funktionalitäten, jeweils mit einem kleinen Beispiel, hier ein. Es soll für mich zum schnellen Auffinden von Funktionen und Funktionalitäten dienen, die ich in meinen Programmen schon einmal eingesetzt habe, deren Anwendung oder Aufruf mir aber gerade entfallen ist. So gehe ich davon aus, dass die nachfolgende Auflistung weiter anwachsen wird.

Meine Informationen über die von mir eingesetzten C-Funktionen und C-Funktionalitäten habe ich, wenn nicht anders angegeben, von hier: www.cplusplus.com/


Info: In nachfolgenden Prototypen der Funktionen kommt immer wieder der Datentyp size_t vor. Das ist ein Alias (= Pseudonym oder Deckname) für die fundamentalen unsigned Interger-Datentypen, wie byte, unsigned Int, unsigned long, etc.

Funktionen zur Stringbearbeitung

(Verketten, vergleichen, kopieren, zerteilen , löschen, ...)

  • strcat
  • strncat
  • strcmp
  • strcpy
  • strncpy
  • strlen
  • strstr
  • strtok

und

  • String löschen


Mit strcat (stringcatenate) Strings verketten:

char* strcat (char* destination, const char* source);

Funktion: Verbindet source mit destination, d.h. source wird an destination angehängt (verkettet)

char text1[10] = "12345678";

char text2[10] = "absdefgh";

strcat(text1, text2);


Mit strncat (string-n-catenate) einen String um n-Zeichen erweitern:

char* strncat (char* destination, const char* source, size_t n);

Funktion: Verbindet die ersten n-Zeichen von source mit destination, d.h. die ersten n-Zeichen von source werden an destination angehängt (verkettet)

Ein einzelnes Zeichen anhängen:

char text1[10] = "abc";

char c = 'x';

strncat(text1, &c, 1);

Die ersten 2 Zeichen eines Character-Arrays anhängen:

char text1[10] = "abcd";
char text2[] = "ABCD";

strncat(text1, text2, 2);


Zwei Strings vergleichen mit strcmp (stringcompare):

int strcmp (const char* str1, const char* str2);

Funktion: Vergleicht den String str1 mit str2

char text1[] = "abcde";

char text2[] = "abcdf";

if (strcmp(text1, text2) == 0) Serial.println("Strings sind identisch");

Rückgabe:

  •   0 ... wenn die Strings identisch sind
  • >0 ... wenn das erste ungleiche Zeichen in text1 ist größer als in text2
  • <0 ... wenn das erste ungleiche Zeichen in text1 ist kleiner als in text2


Bestimmte Anzahl von Zeichen vergleichen mit strncmp (string-n-compare)

int strncmp (const char* str1, const char* str2, size_t n);

Funktion: Vergleicht den String str1 mit den ersten n-Zeichen von String str2

char text1[] = "abcde";

char text2[] = "abcdf";

int anzahl = 3;

if (strncmp(text1, text2, anzahl) == 0) Serial.println("die ersten 3 Zeichen sind identisch");

Rückgabe:

siehe strcmp


Strings kopieren mit strcpy (stringcopy):

char* strcpy (char* destination, const char* source);

Funktion: Kopiert source nach destination

char text1[5];

strcpy(text1, "ABCD");

oder

char text1[5];

char text2[5] = "EFGH";

strcpy(text1, text2);


n-Zeichen von Strings kopieren mit strncpy (string-n-copy)

char* strncpy (char* destination, const char* source, size_t n);

Funktion: Kopiert die ersten n-Zeichen von source nach destination

char text1[10] = "12345678";

char text2[10];

strncpy(text2, text1, 3); //3 Zeichen von text1 in text2 kopieren

text2[3] = '\0' //Ende-Zeichen setzen!!!


Länge ein Strings mit strlen (stringlength) ermitteln:

size_t strlen(const char * str);

Funktion: Ermittlung der Länge des Strings str

char string[100] = "ABCD";

int stringlaenge = strlen(string);

Ergebnis = 4

Bemerkung: Der einen String abschließenden Null-Terminator wird dabei nicht mitgezählt!!


Teilstring in String suchen mit strstr (stringstring):

const char* strstr (const char* str1, const char* str2);
char* strstr (char* str1, const char* str2);

Funktion: Vergleicht, ob String str2 in String str1 enthalten ist

char text[] = "ABCDEFG";

if (strstr(text, "CDE")) Serial.println("Teilstring gefunden");


Mit strtok (stringtoken) einen String zerteilen:

char* strtok (char* str, const char* delimiters);

Funktion: Zerteilt den String str in Teilstrings, begrenzt durch delimiters

char text[] = "Kurt,Kanns;5556;DE";

char delimiter[] = ",;"; //Teilsting-Begrenzer

char* ptr; //NULL-Pointer

ptr = strtok(text, delimiter); //Initialisieren u. erster Teilstring

while(ptr != NULL) //Weitere Teilstrings

{

  Serial.println(ptr);

  ptr = strtok(NULL, delimiter);

}

Ausgabe am Seriellen Monitor:

Kurt
Kanns
5556
DE


oder

char text[] = "Kurt,Kanns;5556;DE";

char* ptr = NULL; //NULL-Pointer

char vorname[10];

char nachname[20];

int personalnummer;

ptr = strtok(text, ","); //Initialisieren u. erster Teilstring

strcpy(vorname, ptr);

ptr = strtok(NULL, ";"); //Zweiter Teilstring
strcpy(nachname, ptr);
personalnummer = atoi(strtok(NULL, ";")); //Dritter Teilstring
Serial.println(Vorname);
Serial.println(Nachname);
Serial.println(Personalnummer);

Ausgabe am Seriellen Monitor:

Kurt
Kanns
5556


String löschen:

char text[10] = "abcdefg";

text[0] = '\0'

oder

strcpy(text, "");

Funktionen zur Array-Bearbeitung

(Vergleichen, kopiern und setzen)

  • memcmp
  • memcpy
  • memset


Arrays vergleichen mit memcmp (memory compare)

int memcmp(const void* arr1, const void* arr2, size_t n);

Funktion: Vergleicht Array arr1 mit n-Zeichen von arr2

byte array1[] = {0xA1, 0xB2, 0xC9};

byte array2[] = {0xA1, 0xB2, 0xC9, 0xD1};

if (memcmp(array1, array2, sizeof(array1)) == 0) Serial.println("Arrays stimmen überein");

else Serial.println("Arrays stimmen nicht überein");

Ergebnis: Arrays stimmen überein

if (memcmp(array1, array2, sizeof(array2)) == 0) Serial.println("Arrays stimmen überein");

else Serial.println("Arrays stimmen nicht überein");

Ergebnis: Arrays stimmen nicht überein


Arrays kopieren mit memcpy (memory copy)

void* memcpy (void * destination, const void* source, size_t n );

Funktion: Kopiert n-Bytes von source nach destination

byte array1[4];

byte array2[] = {0xA1, 0xB2, 0xC9, 0xD1};

memcpy(array1, array2, sizeof(array2));


Arrays setzen mit memset (memory set)

void* memset (void* arr, int value, size_t n);

Funktion: Ersetzt n-Zeichen des Arrays arr mit value

byte array1[] = {0xA1, 0xB2, 0xC9};

byte val = 1;

memset(array1, val, 2);

Funktionen zur Typenumwandlung

  • atof
  • atoi
  • atol
  • dtostrf und ftoa
  • itoa
  • ltoa


String in Float umwandeln mit atof (array to float)

double atof (const char* str);

Funktion: Wandelt einen String str in eine Float-Zahl um

char zahlenstring1[] = "12.345"

float num = atof(zahlenstring1);


String in Integer umwandeln mit atoi (array to integer)

int atoi (const char* str);

Funktion: Wandelt einen String str in eine Integer-Zahl um

char zahlenstring1[] = "1234";

int num = atoi(zahlenstring1);


String in Long Integer umwandeln mit atol (array to long)

long atol (const char* str);

Funktion: Wandelt einen String str in eine Long-Integer-Zahl um

char zahlenstring1[] = "12345";

long num = atol(zahlenstring1);


Float in character Array umwandeln mit dtostrf (double to string float)

char* dtostrf(double zahl, char len, char dec, char *str)

Funktion: Wandelt eine Float-Zahl "zahl" in einen String (Character-Array) "str" mit der Länge "len" und der Anzahl von Dezimalstellen "dec" um.

char str[10];
float zahl = 23.2345;

dtostrf(zahl, 1, 3, str);

Bemerkung:

len: Anzahl der Gesamtlänge des umgewandelten Strings, einschließlich Dezimalpunkt, Vor- und Nachkommastellen.

Sollte der umgewandelte String kürzer als "len" sein, dann wird links mit Leerzeichen aufgefüllt.

Sollte "len" kleiner als die notwendige Stringlänge sein, so wird der String trotzdem in seiner vollen Länge erzeugt.


Float in character Array umwandeln mit ftoa (float to array)

Um eine Float-Zahlen in ein Character-Array umzuwandeln, verwende ich auch meine eigene Funktion ftoa(), die zwar geringfügig mehr SRAM-Speicher aber weniger Flash-Speicher benötigt, was mir besonders bei Verwendung eines Attiny45/84 schon geholfen hat. Eine Beschreibung meiner Funktion ftoa() ist hier zu finden: Float to Array


Integer in String umwandeln mit itoa (integer to array)

char* itoa (int zahl, char * str, int base);

Funktion: Wandelt eine Interger-Zahl "zahl" in einen String "str" mit der Basis "base" um.

(Basis: Numerische Basis, die verwendet wird, um den Wert als eine Zeichenfolge zwischen 2 und 36 darzustellen, wobei 10 Dezimalbasis, 16 Hexadezimalwert, 8 Oktalwert und 2 Binärwert bedeutet.)

int zahl = 1245;

char str[17];

itoa(zahl, str, 10);


Long in String umwandeln mit ltoa (long to array)

char* ltoa (long zahl, char * str, int base);

Funktion: Wandelt eine Long-Interger-Zahl "zahl" in einen String "str" mit der Basis "base" um.

(Basis: Numerische Basis, die verwendet wird, um den Wert als eine Zeichenfolge zwischen 2 und 36 darzustellen, wobei 10 Dezimalbasis, 16 Hexadezimalwert, 8 Oktalwert und 2 Binärwert bedeutet.)

long zahl = 1245344;

char str[17];

ltoa(zahl, str, 10);

Sonstige Funktionalitäten

  • Bedingungsoperator
  • Bereichsbasierte for-Schleife


Bedingungsoperator "bedingung ? ausdruck1 : ausdruck2":

int x;

int y = 100;

int z = 1000;

x = (y > z) ? 0 : 1;

Ergebnis: x = 1

entspricht:

if (y > z) x = 0;

else x = 1;


Bereichsbasierte for-Schleife (Range-based-for-loop)

Die "Bereichsbasierte for-Schleife" ist eine alternative zur üblichen for-Schleife, bei der die Elemente eines Arrays durchlaufen werden.

Duchlaufen eines Arrays:

int x[5] = {1, 2, 3, 4, 5};

for (int y : x) Serial.print(y);

Ausgabe: 12345

Bemerkung:

  • Die Schleifenvariable y ist kein Index, sondern bereits das gewünschte Array-Element. D.h. im ersten Schleifendurchgang steht y für das erste Element im Array (mit Index 0) und so weiter.
  • Es werden immer alle Elemente des Arrays durchlaufen, daher müssen keine Indexgrenzen angegeben werden. Allerdings können dafür keine Teilbereiche eines Arrays durchlaufen werden.


Mit Schlüsselwort "auto":

"auto" bewirkt, dass Typinferenz verwendet wird.

(Typinferenz bedeutet Typrückschluss. In der Informatik versteht man unter Typinferenz das Folgern eines bestimmten Typs für einen gegebenen Ausdruck, obwohl der Typ nicht explizit angegeben wurde. Stattdessen wird unter Zuhilfenahme eines Algorithmus auf den richtigen Typen rückgeschlossen.)

int x[5] = {1, 2, 3, 4, 5};

for (auto y : x) Serial.print(y);

Ausgabe: 12345


Mit Typinferenz "by reference":

int x[5] = {1, 2, 3, 4, 5};

for (auto& y : x) y++;

Durch die Variablenübergabe "by referenz" wirken sich Änderungen der Schleifenvariable y auf das Array x aus. Im Beispiel ist nach dem Durchlauf der for-Schleife der Inhalt des Array x[5] = {2, 3, 4, 5, 6}.


Quellen "Bereichsbasierte for-Schleife":

Dirk Louis, 2018, C++, Hanser Verlag;

https://docs.microsoft.com/de-de/cpp/cpp/range-based-for-statement-cpp?view=vs-2019

https://intern.fh-wedel.de/~si/seminare/ws04/Ausarbeitung/4.Typcheck/staTyp4.htm