Hilfe bei den ersten Schritten - Char Array

Guten Abend,

ich habe heute mithilfe von Beispielen aus dem I-Net mein erstes Programm geschrieben. Dabei habe ich auch alles, was ich davon verwende habe, verstanden (behaupte ich mal). Leider bin ich nach Stunden und unzähligen Fehlern auf ein Problem gestoßen und finde den Fehler nicht.

Das Programm liest die Zeichen von der Seriellen aus und legt diese in einem Char Array ab. Ich möchte nun bspw. alle Zeichen (bis auf das erste) aus dem Array in ein neues Array schreiben. Serial.print (receivedChars) gibt "1Test-ABCD" aus, Serial.print (zeile1) gibt aber "" aus. Das Problem scheint bei for (count=1 ; count <= ndx; ++count); { zeile1[count-1] = receivedChars[count]; } zu liegen. Was mache ich falsch?

const byte numChars = 25;
char receivedChars[numChars];   // an array to store the received data
char zeile1[25];

boolean newData = false;

void setup() {
    Serial.begin(57600);
    Serial.println("");
}

void loop() {
    recvWithEndMarker();
    showNewData();
}

void recvWithEndMarker() {
    static byte ndx = 0;
    static byte count;
    char endMarker = '\n';
    char rc;
   
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string

            if (receivedChars[0] == '1') {
              for (count=1 ; count <= ndx; ++count); {
                zeile1[count-1] = receivedChars[count];
              }
              
              newData = true;          
            }
            
            ndx = 0;
            
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print(zeile1);
        Serial.println("---");
        newData = false;
    }
}

Ziel: 1Test-ABCD ergibt Test-ABCD

Dafür gibt es fertige Funktionen wie strcpy() oder strncpy(): https://www.nongnu.org/avr-libc/user-manual/group__avr__string.html

Das erste Zeichen überspringt man einfach mit Zeigerarithmetik. z.B.:

char str1[] = "test";
char str2[10];

strncpy(str2, str1 + 1, sizeof(str2));

Hallo,

ich glaube, das Beispiel zu verstehen. Aber warum klappt es mit meinem Code nicht? Wo ist da der Fehler. Es sollte doch bei jedem Schleifendurchlauf das x-te Zeichen an die Position x-1 des Arrays zeile1 "kopiert" werden?!

Du scheinst das Array in seinen Grenzen zu überschreiben. Am Ende muss immer noch Platz für das '\0' im Array sein. Also bei 25 Nutzzeichen muss das Array 26 Zeichen groß sein.

Gruß Tommy

Das Original receivedChars hat 11 Zeichen: 1Test-ABCD + \0

Sollte also reichen...

Also char array[12];

Gruß Tommy

Tommy56: Also char array[12];

Gruß Tommy

Es können auch mal mehr Zeichen empfangen werden, aber immer weniger als 22, daher char array[25] zur Sicherheit. Oder ist da der Fehler? Ich habe erst einmal 25 (statt 21 oder 22) genommen, rein intuitiv und nur testweise. Die Abbruchbedingung der Schleife ist ja durch den Maximalwert der Zeichen im Original-Array mit ndx gegeben. Also sollte von Zeichen 1 bis Ende des Arrays (ndx) alles ins neue Array kopiert werden, inkl dem \0. Am Ende läuft wahrscheinlich alles darauf hinaus, den Code von Serenifly zu verwenden, aber ich würde schon gerne wissen, warum mein Code nicht funktioniert.

Das Original receivedChars hat 11 Zeichen: "1Test-ABCD\0"

Sollte also reichen...

Sehe ich auch so.Beim theoretisch draufgucken sehe ich deinen Fehler nicht, frage mich allerdings, ob das Umkopieren überhaupt erforderlich ist. Serial.println(receivedChars+1); // liefert "Test_ABCD"

Generell ist bei

const byte numchars=25; 
char array[numchars] {" hallo" };

der Zugriff auf array[ndx] nur erlaubt, wenn (ndx < numchars) bleibt (nicht mehr bei ndx = numchars)

Schleifen gehen also üblicherweise for (i=0; i < numchars; i++) Die abschließende '\0' muss spätestens bei array[numchars-1] stehen.

strcpy etc. hören übrigens schon nach der ersten '\0' auf.

Bevor ich es nachspiele: Was "funktioniert" bei deinem Code eigentlich nicht? Vielleicht sieht man es leichter, wenn du verrätst, was - gegen deine Erwartungen - herauskommt.

Todi2019: ... aber ich würde schon gerne wissen, warum mein Code nicht funktioniert.

Ein Semikolon ist zu viel:

for (count=1 ; count <= ndx; ++count); {
                                     ^

agmue:
Ein Semikolon ist zu viel

Irgendwas hat mir nicht gefallen, aber dank
for (count=1 ; count <= ndx;
war mir sofort klar, dass das nicht schön ist.

agmue, du bist der Held der Nacht. Bringst Licht in die dunkelsten Ecken.

michael_x: Bringst Licht in die dunkelsten Ecken.

Danke, jetzt werde ich etwas verlegen :blush:

Ich habe die Stelle aber auch erst entdeckt, als ich das Programm habe laufen lassen ::)

agmue: Ein Semikolon ist zu viel:

ERNSTHAFT??? Und deswegen habe ich kaum schlafen können? Weil ein verd... ";" zuviel war? Vielen Dank - es läuft jetzt (soweit).

michael_x: frage mich allerdings, ob das Umkopieren überhaupt erforderlich ist. Serial.println(receivedChars+1); // liefert "Test_ABCD"

Das ist mir schon klar gewesen, ich benötige den empfangenen Text allerdings in einer Variable, um damit weitere Dinge anzustellen, wie ein Vergleich mit einem anderen Char Array - gibt es da einen Befehl, um zwei Char Arrays zu vergleichen oder muss man den Weg zu Fuß gehen?

Du suchst strcmp.

Gruß Tommy

Tommy56: Du suchst strcmp.

Ich bevorzuge strncmp wegen der "Maximum number of characters to compare.", was die Feldgrenzen schützt.

Todi2019:
gibt es da einen Befehl, um zwei Char Arrays zu vergleichen

Es gibt keine “Befehle”. Es gibt Funktionen. Du hast die ganzen Standard String Funktionen aus C zu Verfügung. Und noch weitere Funktionen aus dem GNU Projekt. Den Link dazu hatte ich dir schon gegeben

Siehe auch hier, aber die Seite ist nicht 100% mit dem AVR identisch:
http://www.cplusplus.com/reference/cstring/

ich benötige den empfangenen Text allerdings in einer Variable, um damit weitere Dinge anzustellen

Dazu muss man den Text aber eigentlich nicht in noch ein Array kopieren. Man kann i.d.R. direkt mit dem Array arbeiten in das man einliest

Es gibt keine "Befehle". Es gibt Funktionen.

Richtig. Und es gibt Operatoren, wie z.B. == Der geht allerdings hier nicht, aber das ist eine komplizierte Erklärung :)

strcmp/strncmp liefert übrigens 0 bei Gleichheit, was auch gerne als false interpretiert wird. Eine beliebte Falle, in die jeder schonmal getappt ist.

Würde

char *neueVariable= receivedChars+1;

nicht reichen?

Wenn nacheinander

1ABCD
2XYZ

gesendet wird und man dann zwei Texte "ABCD" und "XYZ" gleichzeitig zur Verfügung haben will, braucht man (der Einfachheit halber) separate char arrays.

Wenn man über "die ersten Schritte" hinausgewachsen ist, kann man aus Spaß natürlich Optimierungen vornehmen:

Variante 1) Alles empfangene wird gespeichert, '\n' wird in '\0' gewandelt (Text Ende), und die Positionen hinter den Kennziffern werden als char* gemerkt.

Variante 2) Direkt beim Empfang der Kennziffer wird festgestellt, in welchem char array die folgenden Zeichen abgelegt werden, der gemeinsame char receivedChars[25] ist überflüssig.

Hi

Dann würde ich doch einen Ringspeicher nehmen, statt mehrere einzelne Arrays. So muß ich mir nur merken, an welcher Stelle ich Lese, an welcher Stelle ich Schreibe und an welcher Stelle ich die Pointer wieder auf Anfang des Speicher umbreche. Selber nehme ich einen Ringspeicher aus struct's - meine Daten sind allerdings bereits formatiert (CAN) und zwei normale byte-Variablen, Die mir die Indexe mithalten, also wo ich als Nächstes lesen oder schreiben will - der Schreiber 'nimmt den Leser mit', sollte Er Diesen überholen (ich die Nachrichten nicht schnell genug auslese) - dadurch verliere ich zwar die älteste Nachricht, habe aber die Aktuellen noch im Speicher.

MfG