Forum: Compiler & IDEs Code funktioniert- Verbesserungsvorschlag?


von Stephan (Gast)


Lesenswert?

Hallo!

Ich möchte, dass der Controller die Werte eines Strings einem Variablen- 
Array korrekt zuweist.

Der String setzt sich aus Teistrings zusammen, die mit Semikolon 
getrennt sind. Ein Teilstring ist mit Doppelpunkt getrennt.

Stringbeispiel: 1:54;3:23;8:45

Daraus soll folgen, dass
receive_value[1] 54,
receive_value[3] 23 und
receive_value[8] 45 annimmt.

Mein Code dazu funktioniert, allerdings habe ich das Gefühl dass der 
ziemlich aufgebläht ist- Stringfunktionen sollen ja recht mühsam sein. 
Ich weiss aber nicht wie ich ihn optimieren kann. Weiß wer Rat?
1
char receive_string[20][20];
2
char receive_value[20];
3
char temp_string[20];
4
5
void readout_string(void)
6
{  
7
  volatile unsigned char *ptr;
8
  int i = 0;
9
  int k = 0;
10
  int l = 0;
11
  ptr = strtok(uart0_string, ";");
12
13
  while(ptr != NULL) 
14
  {
15
    strcpy(receive_string[i], ptr);
16
    ptr = strtok(NULL, ";");
17
    i++;
18
  }
19
  
20
  for (k = 0; k < i; k++)
21
  {
22
    ptr = strtok(receive_string[k], ":");
23
    strcpy(temp_string, ptr);
24
    l = atoi(temp_string);
25
    ptr = strtok(NULL, ":");    
26
    strcpy(temp_string, ptr);    
27
    receive_value[l] = atoi(ptr);
28
  }  
29
}

von Karl H. (kbuchegg)


Lesenswert?

mach alles in einem Aufwasch, ohne zuerst die Teilstrings in ein 
getrenntes String Array umzukopieren.

Du darfst bei strtok durchaus auch abwechselnd verschiedene Trenner 
benutzen
1
...
2
3
  ptr = strtok( uart_string, ":" );
4
  while( ptr )
5
  {
6
     // jetzt haben wir den "Index" -> in eine Zahlumwandeln
7
     index = atoi( ptr );
8
     ptr = strtok( NULL, ";" );
9
     if( ptr )
10
     {
11
       // und jetzte auch noch den zugehörigen Wert
12
       wert = atoi( ptr );
13
       receive_value[index] = wert;
14
     }
15
16
     ptr = strtok( NULL, ":" );
17
   }
18
 }


sieht doch schon gleich viel kürzer aus und ist auch sicherer, weil du 
nicht gefahr läufst, bei den strcpy die Zielstrings zu überlaufen.
Und 400 Bytes SRAM sparst du obendrein :-)

von Stephan (Gast)


Lesenswert?

Cool. Funktioniert immernoch.

von Tom K. (ez81)


Lesenswert?

Ene kleine Fehlerquelle:
1
i = atoi(ein_string_von_aussen);
2
foo[i] = atoi(ein_anderer_string);
verlagert die Verantwortung für das Einhalten der Arraygrenzen auf das 
Programm, das die Strings sendet. Geht da irgendetwas daneben, wird 
irgendwo wild in den RAM geschrieben.

von Stephan (Gast)


Lesenswert?

Tom K. schrieb:
> Geht da irgendetwas daneben...


D.h., wenn StringvonAussen = "100", foo aber nur 50 Elemente groß ist, 
schwappts über, gell?
Wie umgehen? Einfache if-Abfrage?

von chris (Gast)


Lesenswert?

nur mit strtol

Stephan schrieb:
> Stringbeispiel: 1:54;3:23;8:45
>
> Daraus soll folgen, dass
> receive_value[1] 54,
> receive_value[3] 23 und
> receive_value[8] 45 annimmt.
1
unsigned char
2
parse(char*str) { unsigned char ret;
3
 do {
4
     idx=strtol(str,&str,0); // oder 10 fuer dec
5
     while(*str++==':') {
6
       val=strtol(str,&str,0); // oder 10 fuer dec
7
       if(idx>=0&&idx<sizeof(receive_value)/sizeof(receive_value[0]))
8
         receive_value[idx++]=val,ret++;
9
     }
10
    } while(*str++==';');
11
 return ret;
12
}
> Stringbeispiel: 1:54:33:44;13:23;8:45
>
> Daraus soll folgen, dass
> receive_value[1] 54,
> receive_value[2] 33,
> receive_value[3] 44,
> receive_value[13] 23 und
> receive_value[8] 45 annimmt.

von chris (Gast)


Lesenswert?

ret sollte mit 0 initialisiert sein.

von Stephan (Gast)


Lesenswert?

chris schrieb:
> unsigned char
> parse(char*str) { unsigned char ret;
>  do {
>      idx=strtol(str,&str,0); // oder 10 fuer dec
>      while(*str++==':') {
>        val=strtol(str,&str,0); // oder 10 fuer dec
>        if(idx>=0&&idx<sizeof(receive_value)/sizeof(receive_value[0]))
>          receive_value[idx++]=val,ret++;
>      }
>     } while(*str++==';');
>  return ret;
> }

Da muss man erstmal hinterkommen.....

von Karl H. (kbuchegg)


Lesenswert?

Stephan schrieb:
> Tom K. schrieb:
>> Geht da irgendetwas daneben...
>
>
> D.h., wenn StringvonAussen = "100", foo aber nur 50 Elemente groß ist,
> schwappts über, gell?
> Wie umgehen? Einfache if-Abfrage?

:-)
Ja, die einfachsten Dinge sind oft die besten.

von Karl H. (kbuchegg)


Lesenswert?

Stephan schrieb:
> chris schrieb:
>> unsigned char
>> parse(char*str) { unsigned char ret;
>>  do {
>>      idx=strtol(str,&str,0); // oder 10 fuer dec
>>      while(*str++==':') {
>>        val=strtol(str,&str,0); // oder 10 fuer dec
>>        if(idx>=0&&idx<sizeof(receive_value)/sizeof(receive_value[0]))
>>          receive_value[idx++]=val,ret++;
>>      }
>>     } while(*str++==';');
>>  return ret;
>> }
>
> Da muss man erstmal hinterkommen.....

halb so wild.
strtol vereint mehr oder weniger ein atoi und das strtok in einer 
Funktion.

atoi würde selbsttätig mit dem Konsumieren des Strings aufhören, sobald 
etwas nicht mehr zur Zahl gehört.
D.h. wirfst du atoi das hier vor
"123:56"
dann konsumiert atoi alles bis zum ':'.
Soweit so gut. Nur weißt du nicht, wo im String diese Aufhören 
stattfindet, so dass du das nächste atoi 1 Zeichen dahinter ansetzen 
könntest.

und genau da kommt strtol ins Spiel. Es liefert dir genau diese 
Position, bis zu der es aus dem String Zeichen konsumiert hat. Mit 
dieser Position (nach Prüfung natürlich) kannst du dann den nächsten 
strtol dahinter ansetzen, der wieder alles was nach Zahl aussieht 
konsumiert und dir mit dem Pointer bekannt gibt, wo dieses Ende war. 
Woraufhin du dort den nächsten strtol ansetzt, etc. etc.

von Tom K. (ez81)


Lesenswert?

Stephan schrieb:
> schwappts über,

Programme werden zuverlässiger, wenn man solche Eingaben von Anfang an 
als potentiell falsch oder bösartig betrachtet ;)

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.