Ich und die c-stringe :-(

Hallo an alle.
Vorab ein gutes Neues Jahr.

Ich glaube mit den c-strings werde ich wohl nie gut Freund.
Jetzt steh ich schon wieder ne Stunde wie ein Ochs vor dem Berg.

Eigentlich will ich nur aus einem string einen Teilstring raus kopieren.

char str_t[15] = "123a456b789";

Und jetzt bräuchte ich alles zwischen 'a' und 'b'
Mit strncpy kann ich ja nur hinten was abschneiden :frowning:

Und sonst hab ich in der Reference nix passendes gefunden.

Gruß/hk007

strncpy() ist schon richtig, dabei als Start das erste Zeichen des Substrings angeben, z.B. str_t+4.

Wobei str_t ein ganz schlechter Name für einen String ist, das Suffix _t kennzeichnet normalerweise einen Typnamen.

char str_t[15] = "123a456b789";

char *a=str_t;
while ((*a!=0) && (*a!='a')) a++;
if (*a==0) break;
while ((*a!=0) && (*a!='b')) { Serial.println(*a); a++; }

IMO ist Pointer-Arithmetik das schlimmste, was man einem Anfänger empfehlen kann :frowning:

Hallo,

handelt es sich bei a und b um eine bestimmte Position oder um Trennzeichen

schau Dir mal strtok an

https://de.wikibooks.org/wiki/C-Programmierung:_Zeichenkettenfunktionen#strtok

DrDiettrich:
strncpy() ist schon richtig, dabei als Start das erste Zeichen des Substrings angeben, z.B. str_t+4.

Wobei str_t ein ganz schlechter Name für einen String ist, das Suffix _t kennzeichnet normalerweise einen Typnamen.

Ahhh... so geht das mit strncpy
(ich dachte immer mit _t bezeichnet man eine temporäre Variable...falsch gedacht)

Also mit festen Werten in der Art und Weise:

char strxyz[15] = "123a456b789";
strncpy (strxyz, strxyz+5, 4);

Jetzt wäre es halt schön, wenn man mit strchr auch ne Zahl zurück bekommen würde, um die dann als Schnittmarken verwenden zu können...

@zwieblum:
Ich kann nur erahnen, was du da machst [Schäm]

Rentner:
Hallo,

handelt es sich bei a und b um eine bestimmte Position oder um Trennzeichen

schau Dir mal strtok an

C-Programmierung: Zeichenkettenfunktionen – Wikibooks, Sammlung freier Lehr-, Sach- und Fachbücher

Auch nicht schlecht.
Weil mein string sieht de facto eher so aus:

char strxyz[15] = "A123 B456 C789";

Also immer Leerzeichen zwischen den "Blöcken". Und diese Blöcke können unterschiedlich lang sein.
Wenn ich jetzt den Block mit 'B456' brauche, dann könnte ich erst alles mit strtok zerlegen, und dann beim Durchlauf den mit B am Anfang selektieren.

Hallo,

hängt davon ab ob du A,B,C wirklich noch benötigst oder geht es um 1,2,3 Teil der Zeichenkette. Eigendlich kann mnan das gut verwenden um Zeilen die Zahlen, z.B Messwerte enthalten auszuwerten, dabei ist das Tennzeichen dann festgelegt. z.B ";"

123;456;789

erster Zahlenwert 123 usw,

zudem bietet sich sowas an um die Daten in CSV Dateien zu speichern, die kann man dann z.B mit Excell einlesen.

Also ich brauche "alles" Von dem 'B' bis zum nächsten Leerzeichen.

hk007:
Jetzt wäre es halt schön, wenn man mit strchr auch ne Zahl zurück bekommen würde, um die dann als Schnittmarken verwenden zu können...

Dafür gibt es Zeiger-Arthmetik

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

 char str1[] = "123a456b789";
 char str2[10];
 memset(str2, 0, sizeof(str2));

 char* begin = strchr(str1, 'a') + 1;
 char* end = strchr(str1, 'b');
 unsigned int len = end - begin;

 Serial.println(len);
 strncpy(str2, begin, len);
 Serial.println(str2);
}

Wenn ich jetzt den Block mit 'B456' brauche, dann könnte ich erst alles mit strtok zerlegen, und dann beim Durchlauf den mit B am Anfang selektieren.

Du kannst doch mitzählen wie viele Blöcke du hast. Oder Teil-Strings vergleichen. z.B. aktuellen Teil-String ansehen und überprüfen ob er mit einem 'B' anfängt.

hk007:

char strxyz[15] = "A123 B456 C789";

Also immer Leerzeichen zwischen den "Blöcken". Und diese Blöcke können unterschiedlich lang sein.
Wenn ich jetzt den Block mit 'B456' brauche, dann könnte ich erst alles mit strtok zerlegen, und dann beim Durchlauf den mit B am Anfang selektieren.

Ja, eigentlich ist strtok genau für so eine zerlegung gedacht. Könnte z.B. so aussehen:

char testStr[] = " D34    B123 A4567 C78";
char *strPtr = NULL;
int varA;
int varB;
int varC;

void setup() {
  // put your setup code here, to run once:
  Serial.begin( 115200 );
  while(!Serial);       // nur dür Arduino Micro/Leonardo (Mega 32u4)

  Serial.println( "Test String zerlegen" );
  strPtr = strtok( testStr, " \n\r\0");                     // Zeiger auf das erste 'Token' setzen
                                                            // ein Token endet bei Leerzeichen, Newline,CR odr Stringende
  while ( strPtr != NULL ) {                                // Schleife, solange ein gültiges 'Token' gefunden wurde
    Serial.print( "strPtr="); Serial.println(strPtr);
    switch ( strPtr[0] ) {                                  // Verzweigen entsprechend dem ersten Zeichen im Token
      case 'A':
        varA = atoi( &strPtr[1] );   // alternativ: strPtr+1) In Zahl wandeln ( die Zahl beginnt eins hinter dem ersten zeichen )
        break;
      case 'B':
        varB = atoi( strPtr+1 );                           // In Zahl wandeln ( die Zahl beginnt eins hinter dem ersten zeichen )
        break;
      case 'C':
        varC = atoi( &strPtr[1] );                          // In Zahl wandeln ( die Zahl beginnt eins hinter dem ersten zeichen )
        break;
      default:
        Serial.println("unbekannte Kennung ( nicht A,B oder C )");
    }
    strPtr = strtok( NULL, " \n\r\0");                      // Zeiger auf nächstes Token setzen
  }
  Serial.print("varA = "); Serial.println( varA );
  Serial.print("varB = "); Serial.println( varB );
  Serial.print("varC = "); Serial.println( varC );

}

void loop() {
  // put your main code here, to run repeatedly:

}

Da bist Du unabhängig von der Reihenfolge und Länge der Blöcke, und kannst dir jeden beliebigen Block rauspicken - oder eben auch mehrere auf einmal in Zahlen wandeln.
Allerdings kommst Du mit strtok nicht ganz ohne Pointer aus, denn strtok liefert einen Zeiger auf den entsprechenden Substring(Block). Er macht dir auch deinen Input-String 'kaputt', da er hinter jedes token ein Stringendezeichen '\0' schreibt. Wenn Du den String hinterher noch im 'Original' brauchst, musst Du ihn also zuerst in einen temprären String umkopieren.

Hallo mochmal.

Kurzes Feedback:
ich habe mich dann für die Version mit strtok entschieden. Sieht am elegantesten sowie verständlichsten aus, und macht wegen dem gleichen Separator (Leerzeichen) am meisten Sinn. Allerdings ohne Switch/Case, weil ich ja nur einen der Teiltstringe brauche. Da reicht für mich eine If-Abfrage nach dem 'B'.

Super. Läuft.
Danke an alle für eure Comments. Hab ich wieder einiges gelernt.

(Und wenn ich es richtig sehe, setzt strtok auch gleich das '\0' automatisch ans Ende der Teilstringe.)
Hat ja mein Vorredner schon geschrieben. :wink: