Hi
Ich möchte zB einen String "AAA" an eine Funktion übergeben.
Dann habe ich mir gedacht, diesen String in einem Array abzuspeichern
und den Array durchzuiterieren und dabei immer die atoi Funktion zu
benutzen.
Jetzt habe ich das versucht zu realisieren, aber irgendwie habe ich
Probleme dabei, die richtige Länge des Arrays anzugeben. Ich habe 2
Dinge versucht.
void wandleString(uint8_t *string)
{
uint8_t code[] = "string";
}
funktioniert ja nicht, weil ich immer wissen muss, wie lang ich den
Array mache. Wenn ich jetzt eine Länge angebe als Parameter, kann man ja
auch irgendetwas eingeben, was dann zu einem Fehler führen kann.
void sendErrorCode(uint8_t *string)
{
uint8_t code[];
strcpy(code, string);
}
hier habe ich das Problem wieder mit der Länge.
wie macht man so etwas?
Marwin schrieb:> void sendErrorCode(uint8_t *string)> {
es wird ein Pointer auf "string" übergeben
dessen Länge kann mit strlen(string); ermittelt werden. (ggffs. casten)
strlen((char*)string);
uint8_t laenge=strlen(string); // oder uint16_t oder uint32_t wie lang
darfs werden?
// dann Speicher reservieren
malloc // nachlesen laenge+1 für Ende NULL
> char* code= der reservierte Speicher aus malloc> strcpy(code, string);>> }
wieso void?
> void sendErrorCode(uint8_t *string)
willst du code nicht zurückgeben?
evtl. kannst du nach der Verarbeitung auch den reservierten Speicher von
malloc freigeben.
Marwin schrieb:> wie macht man so etwas?
Wenn du den Pointer übergibst und das ein String ist, dann wird ja
direkt auf dem String gearbeitet und der ist (wie alle Strings in C) mit
einer 0 terminiert.
> wie macht man so etwas?
Man fragt mit strlen() die Stringlänge ab und weiß dann, wie viele
Zeichen bis zur ersten 0 (Stringende) da drin sind...
Marwin schrieb:> Dann habe ich mir gedacht, diesen String in einem Array abzuspeichern
String und Array ist fast das gleiche. Du kannst den String auch direkt
iterieren. Aber warum möchtest du atoi auf jedem Zeichen einzeln
anwenden? Was soll atoi() auf einem String wie "AAA" bewirken? Das ist
keine Zahl...
Dr. Sommer schrieb:> Marwin schrieb:>> Dann habe ich mir gedacht, diesen String in einem Array abzuspeichern>> String und Array ist fast das gleiche. Du kannst den String auch direkt> iterieren. Aber warum möchtest du atoi auf jedem Zeichen einzeln> anwenden? Was soll atoi() auf einem String wie "AAA" bewirken? Das ist> keine Zahl...void wandleString (const char* str) {> for (const char* p = str; *p; ++p) {> // Hier ist *p das aktuelle Zeichen> }> }
Hallo miteinander
Ich habe mich vllt. etwas unverständlich ausgedrückt, weil ich direkt in
der Aufgabe vertieft war.
Ich möchte zB ein Text 0-F, also 0-15 in einzelne Ziffern wandeln.
zB AAA, BBB, B10 etc.
Das möchte ich aber so direkt an eine Funktion übergeben zB "C99".
Joachim B. schrieb:> Marwin schrieb:>> void sendErrorCode(uint8_t *string)>> {>> es wird ein Pointer auf "string" übergeben> dessen Länge kann mit strlen(string); ermittelt werden. (ggffs. casten)> strlen((char*)string);>> uint8_t laenge=strlen(string); // oder uint16_t oder uint32_t wie lang> darfs werden?> // dann Speicher reservieren> malloc // nachlesen laenge+1 für Ende NULL>>> char* code= der reservierte Speicher aus malloc>> strcpy(code, string);>>>> }>> wieso void?>> void sendErrorCode(uint8_t *string)>> willst du code nicht zurückgeben?
Nein, ich will vorerst nur eine Umwandlung erreichen.
Das ist die Aufgabe.
Marwin schrieb:> Ich möchte zB ein Text 0-F, also 0-15 in einzelne Ziffern wandeln.> zB AAA, BBB, B10 etc.
atoi() ist hier nicht geeignet
Eher schon strtol(), oder einer seiner Brüder, denn dort kann man die
Zahlenbasis (hier 16) angeben.
Ich habe da mal etwas versucht.
Funktioniert das so oder ist das kompletter Unsinn?
Bitte um Hilfe
void wandleUm(char *string)
{
uint8_t str_length;
char str[10];
uint8_t code[10];
strcpy(str, string);
uint8_t i=0;
while(str[i] != '0')
{
code[i] = atoi(&str[i]);
i++;
}
}
Marwin schrieb:> strcpy(str, string);
Hier kann ein Buffer Overflow eintreten. Dein Kopieren ist komplett
überflüssig, du kannst atoi auch direkt auf "string" anwenden.
Allerdings funktioniert atoi so grundsätzlich nicht, da es immer gleich
den ganzen String und nicht nur ein Zeichen verarbeitet.
Wie wäre es so:
1
voidwandleString(constchar*str){
2
for(constchar*p=str;*p;++p){
3
uint8_tdigit;
4
if(*p>='0'&&*p<='9'){
5
digit=*p-'0';
6
}elseif(*p>='a'&&*p<='f'){
7
digit=*p-'a';
8
}elseif(*p>='A'&&*p<='F'){
9
digit=*p-'A';
10
}else{
11
puts("Fehler: Ungültiges Zeichen in Eingabestring");
12
digit=0;
13
}
14
// Hier mit "digit" weiter rechnen
15
}
16
}
So entfällt jegliches Kopieren und du kannst jede Ziffer direkt
verarbeiten.
Dr. Sommer schrieb:> Marwin schrieb:>> strcpy(str, string);>> Hier kann ein Buffer Overflow eintreten. Dein Kopieren ist komplett> überflüssig, du kannst atoi auch direkt auf "string" anwenden.> Allerdings funktioniert atoi so grundsätzlich nicht, da es immer gleich> den ganzen String und nicht nur ein Zeichen verarbeitet.>> Wie wäre es so:void wandleString (const char* str) {> for (const char* p = str; *p; ++p) {> uint8_t digit;> if (*p >= '0' && *p <= '9') {> digit = *p - '0';> } else if (*p >= 'a' && *p <= 'f') {> digit = *p - 'a';> } else if (*p >= 'A' && *p <= 'F') {> digit = *p - 'A';> } else {> puts ("Fehler: Ungültiges Zeichen in Eingabestring");> digit = 0;> }> // Hier mit "digit" weiter rechnen> }> }> So entfällt jegliches Kopieren und du kannst jede Ziffer direkt> verarbeiten.
Hallo Dr. Sommer
Genau das brauche ich. Jetzt muss ich es nur noch verstehen.
for (const char* p = str; *p; ++p)
Als Startwert gibst du die Anfangsadresse von str an den pointer p.
Warum ist aber der Wert, bei dem die Schleife beendet werden soll gleich
dem aktuellen Wert vom pointer p? Und weshalb inkrementierst du schon
vorher?
Marwin schrieb:> Warum ist aber der Wert, bei dem die Schleife beendet werden soll gleich> dem aktuellen Wert vom pointer p?
Ein String endet mit einem 0x00. Die Ausführungsbedingung der
For-Schleife ist solange erfüllt, wie das Zeichen unter dem Zeiger p
(also *p) ungleich 0x00 ist.
Und weshalb inkrementierst du schon
> vorher?
Wie vorher?
++p wird am Ende des Schleifenrumpfes aufgeführt.
Marwin schrieb:> Und weshalb inkrementierst du schon> vorher?
Macht er nicht.
Bitte einmal For Schleife lernen.
Vielleicht ist dieses einfacher zu verstehen:
Effektiver ist es wohl kaum.
Aber etwas flexibler ist es, denn es arbeitet zur Zahlenbasis 2 bis 36
Marwin schrieb:> Ich möchte zB einen String "AAA" an eine Funktion übergeben.>> Dann habe ich mir gedacht, diesen String in einem Array abzuspeichern> und den Array durchzuiterieren und dabei immer die atoi Funktion zu> benutzen.
Warum? Warum willst du den String erst kopieren und dann über die Kopie
iterieren? Du kannst doch direkt über den übergebenen String laufen?
Und was willst du mit atoi() und einzelnen Zeichen aus dem String?
> Jetzt habe ich das versucht zu realisieren, aber irgendwie habe ich> Probleme dabei, die richtige Länge des Arrays anzugeben.
Wenn du einen String kopieren willst, dann verwende unbedingt eine der
Standardfunktionen dafür. Und zwar im Idealfall nicht strcpy(), sondern
strncpy(). Geh jetzt los und lies die Beschreibung dieser Funktionen.
Hinweis: du wirst auch strlen(), malloc() und Kenntnis über Zeiger
brauchen, um damit etwas anfangen zu können. Ja, Strings in C sind
kompliziert. Vor allem fehlerträchtig.
> wie macht man so etwas?
Wie macht man was? Du hast bis jetzt nicht deine eigentliche Aufgabe
beschrieben. Was willst du mit dem Inhalt des Strings anstellen?
Es ergibt auf jeden Fall schon mal gar keinen Sinn, den String überhaupt
zu kopieren.
Axel S. schrieb:> Und zwar im Idealfall nicht strcpy(), sondern strncpy().
Besser noch wäre strlcpy, aber das hat es leider immer noch nicht in den
Standard geschafft.
strncpy hat nämlich eine unappetitliche Eigenschaft, die man nicht
erwartet; ist der zu kopierende String länger als die Anzahl der zu
kopierenden Zeichen, wird kein abschließendes '\0' angehängt.
Arduino Fanboy D. schrieb:> Marwin schrieb:>>> {> temp[0] = *quelle;> *ziel = strtol(temp,nullptr,base);> quelle++;> ziel++;> }> }>> void setup()> {> Serial.begin(9600);> Serial.println("Start");> wandel(quelle,ziel,16);> for(uint8_t t:ziel)Serial.println(t);> }>> void loop()> {>> }
Hallo arduino fan
Ja das habe ich schon, aber die for-loop wird nirgends mit pointern
erklärt, leider. Deshalb auch die Frage.
Zählt bei *p als Abbruchbedingung wieder das Prinzip, dass die Schleife
bei einer '0' abgebrochen wird?
Marwin schrieb:> Zählt bei *p als Abbruchbedingung wieder das Prinzip, dass die Schleife> bei einer '0' abgebrochen wird?
Der Schleifenrumpf wird ausgeführt, solange die Bedingung erfüllt ist.
Erfüllt heißt, das Ergebnis der Bedingung muss ungleich 0 sein.
Da wird nichts abgebrochen.
Marwin schrieb:> Ich möchte zB ein Text 0-F, also 0-15 in einzelne Ziffern wandeln.> zB AAA, BBB, B10 etc.> Das möchte ich aber so direkt an eine Funktion übergeben zB "C99".
Und was soll die Funktion in diesem/n Fall/Fällen dann zurückgeben?
Marwin schrieb:> Ich habe da mal etwas versucht.
merkt man aber ohne Verständnis
> Funktioniert das so oder ist das kompletter Unsinn?>> void wandleUm(char *string)> {> uint8_t str_length;
ohne init, das geht zwar meist gut ABER
uint8_t str_length=0; //wäre besser
> char str[10];> uint8_t code[10];
warum 2x?
> strcpy(str, string);
ohne Überlaufprüfung?
wenn schon nach Prüfung ob der Platz reicht
> uint8_t str_length;
dann doch strncpy(str, string, str_length);
wenn sichergestellt ist das es passt ohne Überlauf
Joachim B. schrieb:> Marwin schrieb:>> Ich habe da mal etwas versucht.>> merkt man aber ohne Verständnis
Hallo Joachim
Ja stimmt, ich habe da an die Ascii Tabelle auch nicht gedacht.
Auch wenn es mit atoi funktioniert hätte, hätte ich falsche ascii Werte
gehabt. Aber ich habe durch eure Tipps jetzt dazugelernt. Das glaube ich
zumindest.
Ich muss die vorgeschlagenen Dinge hier nochmals selbst ausprobieren.
>>> Funktioniert das so oder ist das kompletter Unsinn?>>>> void wandleUm(char *string)>> {>> uint8_t str_length;>> ohne init, das geht zwar meist gut ABER> uint8_t str_length=0; //wäre besser>>> char str[10];>> uint8_t code[10];>> warum 2x?>>> strcpy(str, string);>> ohne Überlaufprüfung?> wenn schon nach Prüfung ob der Platz reicht>>> uint8_t str_length;>> dann doch strncpy(str, string, str_length);> wenn sichergestellt ist das es passt ohne Überlauf
Muss ich eben mal ausprobieren, sobald ich Zeit finde.
Vielen Dank euch allen
Marwin schrieb:> void sendErrorCode(uint8_t *string)> {> uint8_t code[];> strcpy(code, string);>> }
Die Frage ist aber, warum Du überhaupt eine Kopie anlegen willst?
Alle C-Operationen funktionieren genauso gut auf dem Original.