Go Down

Topic: Umgang mit char Variablen (Read 132 times) previous topic - next topic

Jan 23, 2015, 08:52 am Last Edit: Jan 23, 2015, 08:53 am by newarduinosmith
Hallo Freunde,

wie angekündigt brauche ich reichlich Hilfe.

Erster Stolperstein: char Variablen.

Definiert man z.B.

Code: [Select]
char zeichenkette[10];

so hat man eine Variable mit den Positionen 0..9. Korrekt?

An Stelle 9 steht im Zweifelsfalle ein '\0'-Zeichen.

Also z.B. so

Code: [Select]
char zeichenkette = {'T', 'e', 's', 't', 'k', 'e', 't', 't', 'e', '\0'};

Korrekt?

Wenn ich nun hingehe und ein Zeichen durch das Null-Zeichen ersetze, ist die Variable dann dort zu ende oder ist sie ab dort leer?

Code: [Select]
char zeichenkette = {'T', 'e', 's', 't', 'k', 'e', 't', 't', 'e', '\0'};
zeichenkette[4] = '\0'; // zeichenkette = {'T', 'e', 's', 't', '\0'}
                        // oder zeichenkette = {'T', 'e', 's', 't', '\0', ' ', ' ', ' ', ' ', ' '}


Gibt also sizeof(zeichenkette) hinterher 5 zurück oder 10? Zählt sizeof das Null-Zeichen mit?

Nächste Frage, wie kann ich aus einem char das erste oder das letzte Zeichen löschen oder eins auf einer Position in der Mitte? Ich suche sowas wie "delete":

Code: [Select]
while( zeichenkette[0] != 'k')
   {
   delete[zeichenkette, 0]   zeichenkette = {'k', 'e', 't', 't', 'e', '\0'};
   }


Gibt es weitere nützliche Befehle für char? Mehrere chars vereinigen oder char aufteilen zum Beispiel?

combie

#1
Jan 23, 2015, 09:56 am Last Edit: Jan 23, 2015, 10:01 am by combie
Quote
Gibt also sizeof(zeichenkette) hinterher 5 zurück oder 10? Zählt sizeof das Null-Zeichen mit?
sizeof() sagt, wie groß das Array ist, es hat keine Ahnung davon, was da drin steht.


Quote
An Stelle 9 steht im Zweifelsfalle ein '\0'-Zeichen.
Wenn du den Inhalt des Arrays als C-Zeichenkette verarbeiten willst, dann sollte/muss da eine Null am Ende sein.
Ansonsten ist auch das wurscht.

Quote
Gibt es weitere nützliche Befehle für char?
Ja, reichlich!!

Tipp:
Schaffe dir ein C Grundlagenbuch an.

michael_x

#2
Jan 23, 2015, 10:49 am Last Edit: Jan 23, 2015, 10:53 am by michael_x
Du meinst statt char zeichenkette = {'T', 'e', 's', 't', 'k', 'e', 't', 't', 'e', '\0'};

char zeichenkette[] = {'T', 'e', 's', 't', 'k', 'e', 't', 't', 'e', '\0'};

oder

char zeichenkette[10] = {'T', 'e', 's', 't', 'k', 'e', 't', 't', 'e', '\0'};

diese beiden sind gleich, aber was ganz anderes als deins.

Es gibt viele Funktionen, dein "delete" solltest du selbst programmieren (durch umkopieren der gewünschten Zeichen nach vorne).
Und zum Vergleich zu sizeof() solltest du dir mal strlen() anschauen ;)

Du solltest verinnerlichen, dass der Name zeichenkette die Adresse des ersten Zeichens ist.
Serial.print(zeichenkette+4); ergibt "kette", weil das die Adresse des 5.Zeichens (als Anfang des Textes) ist.

Da eine 0 das Ende markiert (egal wie groß der reservierte Speicher ist),
geht auch sowas

Code: [Select]
zeichenkette[2] = 'e';
*(zeichenkette+3) = 0;  // alternative Syntax
Serial.print(zeichenkette); // ergibt "Tee"


Man kann auch Variable als
char* p = zeichenkette+4;
definieren. Die sind fast *) immer genauso wie char [] zu verwenden, da sie auch den Anfang eines Texts darstellen.
Serial.print(p); // "kette"

*) sizeof(p) ist allerdings 2 ( Die Größe eines Zeigers beim 8bit - arduino )
Und ein Zeiger kann auch mal ins Nirwana zeigen


Quote
Tipp:
Schaffe dir ein C Grundlagenbuch an.
Ja: Ob Buch oder online, c Grundlagen (auch ohne Arduino - Bezug) hilft viel weiter.

Kann man alle Befehle von www.cplusplus.com für den Arduino verwenden?

Den Tip

Quote
dein "delete" solltest du selbst programmieren (durch umkopieren der gewünschten Zeichen nach vorne)
finde ich sehr gut. Ich probier das mal. MÜsste mit einer einfachen Schleife gehen...

Wie ist das wenn ich ein char mychar[100] definiere und  irgendwann "Testkette" reinschreibe. Vorher stand aber "Überlangetestkette" drin und davon existiert ja dann noch das Null-Zeichen am Ende. Jetzt stehen da zwei Null-Zeichen drin. Zählt strlen() dann nur bis zum, ersten Null-Zeichen? Würde ja Sinn ergeben...

Serenifly

#4
Jan 23, 2015, 01:58 pm Last Edit: Jan 23, 2015, 02:09 pm by Serenifly
Besser ist du machst es so:
Code: [Select]

char str[] = "str";

Das erzeugt ein Array der Größe 4, mit 's', 't', 'r' und NULL


Wenn du ein Array der Größe x anlegst und dass dann mittendrin mit '\0' terminierst, wird die Verarbeitung des Strings da beendet. Aber der Speicher ist natürlich noch belegt.

Wenn du weiter hinten anfangen willst mach das:
Code: [Select]

char str[] = "blahblah";
char* p_str = str + 4;

p_str gibt dann nur noch "blah" aus. Das ändert aber gar nichts am Speicher. Es ist nur ein Zeiger auf eine Stelle weiter hinten.


Kann man alle Befehle von www.cplusplus.com für den Arduino verwenden?
Mehr oder weniger. Es ist nicht genau identisch, aber die Erklärungen sind gut. Auf dem AVR fehlen ein paar Sachen (u.a. weil es weniger Datentypen gibt), aber es gibt auch ein paar GNU und AVR spezifische Funktionen mehr. Von GNU kommen z.B. die L-Versionen von strcpy() oder strcat() welche anders als die N-Versionen, den String wirklich sicher terminieren. Oder man hat dtostrf() für float -> string Konvertierung, da das in printf() standardmäßig nicht geht.

Was wirklich auf dem Arduino ist, steht hier:
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html
http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html

Auch nicht schlecht ist das hier:
http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/011_c_arrays_013.htm#mj607c824f6d89b1e3f8edb08abdc187d4
Deckt aber wirklich nur die grundlegendsten String Funktionen ab

Ich hab grad mal was gebastelt um vorne den String zu säubern:

Code: [Select]
while(cellPhoneAnswer[0] < 0x41 || cellPhoneAnswer[0] > 0x5A && cellPhoneAnswer != '\0') //solange das erste Zeichen nicht A...Z und unglöeich dem Null-Zeichen ist
{
for(int index=0; index < strlen(cellPhoneAnswer); index++)
{
cellPhoneAnswer[index]=cellPhoneAnswer[index+1]; //Zeichenkette nach links verschieben
}



Nebenbei stelle ich mehr und mehr fest, dass es mir mit C++ genauso geht wie mit Französisch und Suaheli:

Ich kanns nicht!

Naja, lang ist der Weg und steinig...

Serenifly

Beschreibe mal allgemein was du eigentlich machen willst.

Eisebaer

na, so wie es aussieht, französisch, suaheli und C++ lernen...

combie

Es gab mal eine Zeit, da wollte ich programmieren lernen....
C, Pascal, usw.
Bömische Dörfer!
Z80 und 8086 Assembler, ja, aber die Hochsprachen?
Gruselig.


Dieses Buch Thinking Forth hat mir auf die Sprünge geholfen.
Hat zwar nix mit C zu tun, aber zumindest die Bildchen darin sind sehr lehrreich.


michael_x

Was hältst du von zwei Zeigern, einer zeigt auf die Schreibstelle, einer auf die Lesestelle und überspringst erstmal alle nicht A...Z am Anfang ?
Auf jeden Fall solltest du mit nur 1 Schleife auskommen, auch wenn ich deine Aufgabenstellung falsch verstanden haben sollte ...
Das lese ich aus deinem Beispiel: "Schiebe den Text so weit nach vorn bis er mit A..Z anfängt. Oder mach einen leeren String draus."

Oder du lässt den Text so wie er ist und gibst nur den Anfangspunkt (suche das erste Zeichen A..Z im string) zurück. Das ist im allgemeinen besser, weil den Speicher hast du sowieso schon vollgemüllt und das umkopieren ist nur unnötiger Aufwand.

Was anderes wäre es, wenn du in der Mitte auch noch Zeichen entfernen willst.



Suaheli und C++ lernt man nur, wenn man es braucht, und sei es um einen Arduino blinkern zu lassen.


#10
Jan 24, 2015, 01:00 pm Last Edit: Jan 24, 2015, 01:03 pm by newarduinosmith
Beschreibe mal allgemein was du eigentlich machen willst.
Naja, mein dertig gekauftes GSM Modul ist ab Werk defekt und wird wohl nicht auf Kulanz repariert. Also baue ich selber eins...

Ich mach dafür auch noch einen Thread auf in welchem daqnn die Entstehung dokumentiert wird.

Hardware ist ein MEGA 2560 R3, ein Sony Ericsson K700i, ein paar INOR IPAQ-HX Temperaturtransmitter, Platine mit etwas Hilfs-Hardware und ein Netzteil - ggf noch Bleiakku zwecks Redundanz.

Was muss die Software können:

vorerst:

-Analog- und Digitaleingänge einlesen und auf Grenzwerte überprüfen
-Alarm SMS senden bei Grenzwertverletzung
-Befehl aus eingehender SMS erkennen und Aktion ausführen z.B. Status SMS zurücksenden
-Status auf LDC 2004 anzeigen

später zusätzlich:

-Menüführung
-Freie Eingabe von Rufnummern und Authorisierung derselben
-im Menü Aktionen vor Ort auslösen
-...

Momentan versuche ich überhaupt die Sprache zu verstehen und die mir strukturierte Denkweise anzueignen.

Das fällt schon schwer wenn man kaum Vorkenntnisse hat. Vor allem die Syntax. Manches kapier ich einfach nicht.

Beispiel:

Code: [Select]
while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


Wieso ist da ein Semikolon in einer leeren Zeile?

Oder hier, bei timzaman.com, kapier ich - trotz Überschrift - gar nicht was passiert:

Code: [Select]
//The rest of the code then is just about changing our serial info "Hello World" into neat PDU HEX format.
  for (x = 0; x < data_length; x++)
  {
    if (data[x] == '$')  data[x] = 0x02;
 
    n |= (data[x] & 0x7F) << l;
    l += 7;
 
    if (l >= 8)
    {
      hexdump_byte(n & 0xFF);
      l -= 8;
      n >>= 8;
    }
  }
 
  if (l != 0)
  {
    hexdump_byte(n & 0xFF);
  }
 
  Serial.println(0x1A, BYTE);
}
}


Schön wäre, wenn quasi jede Zeile kommentiert wäre. Das versuche ich einzuhalten - auch damit ich es selber besser verstehe. Für Anfänger gibt es keine Lapalien...

Dann das mitgeben von Variablen in Funktionen als "mychar" oder *mychar" oder mit "&" davor. Bestimmt alles nicht so schwer aber im Moment doch sehr viel auf einmal.

Ich will aber von vornherein alles total zergliedern um später leichter weiterentwickeln zu können.

Eine der ersten Antworten die ich hier im Forum erhielt lautete:

"Divide et impera."

Ich glaub, das hab ich jetzt verstanden.


Quote from: michael_x
Suaheli und C++ lernt man nur, wenn man es braucht, und sei es um einen Arduino blinkern zu lassen.
Brauchen ist relativ aber ich wollte das immer mal gerne ausprobieren. Bloß früher musste man Compiler kaufen und irgendwelche Hardware zum Brennen von Prozessoren haben. Das ist mit dem Arduino unvergleichlich einfacher geworden.

michael_x

Quote
Wieso ist da ein Semikolon in einer leeren Zeile?
Sehr gute Frage:  Nur so, stört nicht.

Es geht genausogut:
while (! Serial ) {} // warten bis Serial bereit ist
oder
while (! Serial ) ;  // hier ist das eine Semikolon wichtig

Die interessantere Frage ist eigentlich: wieso kann man Serial negieren, oder wieso ist Serial eine boolean Variable ?  Das kriegen wir später ... ;)

Quote
Bestimmt alles nicht so schwer aber im Moment doch sehr viel auf einmal.
Zu Beginn am Wichtigsten ist der Unterschied bei diesen 3 Zeilen:
Code: [Select]
char text[] = "ein Text";
char c = text[5];
char* pt = & text[4];

Die 3 Variablen können natürlich auch andere Namen haben, sonst ist bis auf Zeilentrenner und manche Leerzeichen alles wichtig!

Serenifly

Ich meinte was du speziell mit Strings machen willst :)


Einen String an eine Funktion zu übergeben ist ganz einfach. In C sind Array Variablen automatisch Zeiger auf das erste Element. Wenn du als das hast:
Code: [Select]

char str[] = "test";


Dann ist str ein char*. Zeiger auf char. Genau ist str das gleiche wie &str[0]. Die Adresse des ersten Elements.

Mann muss also eine Funktion nur so schreiben:
Code: [Select]

void func(char* str)
{
}

Und so aufrufen:
Code: [Select]

func(str);

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy