Forum: Mikrocontroller und Digitale Elektronik Parameter string


von Marwin (Gast)


Lesenswert?

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?

von Joachim B. (jar)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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...

von Dr. Sommer (Gast)


Lesenswert?

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...
1
void wandleString (const char* str) {
2
  for (const char* p = str; *p; ++p) {
3
    // Hier ist *p das aktuelle Zeichen
4
  }
5
}

von Marwin (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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.

von Marwin (Gast)


Lesenswert?

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++;
  }

}

von Dr. Sommer (Gast)


Lesenswert?

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
void wandleString (const char* str) {
2
  for (const char* p = str; *p; ++p) {
3
    uint8_t digit;
4
    if (*p >= '0' && *p <= '9') {
5
      digit = *p - '0';
6
    } else if (*p >= 'a' && *p <= 'f') {
7
      digit = *p - 'a';
8
    } else if (*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.

von Bru (Gast)


Lesenswert?

Marwin schrieb:
> Ich habe da mal etwas versucht.
> Funktioniert das so oder ist das kompletter Unsinn?

Probiere es aus.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Marwin schrieb:
> oder ist das kompletter Unsinn?

Es ist kompletter Unsinn, da Du atoi wie folgt verwendest:
1
atoi("string");
2
atoi("tring");
3
atoi("ring");
4
atoi("ing");
5
atoi("ng");
6
atoi("g");

von Marwin (Gast)


Lesenswert?

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?

von Bru (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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
1
char   *quelle = "C99";
2
uint8_t ziel[3]; // <<< muss gross genug sein
3
4
5
void wandel(char *quelle,uint8_t *ziel,int base)
6
{
7
  char temp[2] = {0,0};
8
  while(*quelle)
9
  {
10
    temp[0] = *quelle;
11
    *ziel = strtol(temp,nullptr,base);
12
    quelle++;
13
    ziel++;
14
  }
15
}
16
17
18
void setup() 
19
{
20
 Serial.begin(9600);
21
 Serial.println("Start");
22
 wandel(quelle,ziel,16);
23
 for(uint8_t t:ziel)Serial.println(t);
24
}
25
26
void loop()
27
{
28
29
}

von Axel S. (a-za-z0-9)


Lesenswert?

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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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.

von Marwin (Gast)


Lesenswert?

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?

von Bru (Gast)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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?

von Joachim B. (jar)


Lesenswert?

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

von Marwin (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.