Forum: PC-Programmierung Drei Programmcode-Beispiele, welcher Stil ist gut?


von Guido C. (guidoanalog)


Lesenswert?

Hallo,

ich bin immer bestrebt mein Programmcode so verständlich wie möglich und 
somit so wartbar wie möglich zu schreiben. Ich möchte es anderen 
Personen so einfach wie möglich machen den Code zu verstehen. 
Dementsprechend füge ich auch viele Kommentare ein (habe ich in den 
unten gezeigten Beispielen jetzt ausnahmsweise nicht gemacht).

Letzte Woche habe ich ein Stück Code geschrieben, in dem untersucht 
werden sollte, ob in einem Array aus Zeichenketten eine bestimmte 
Zeichenkette enthalten ist. Dabei kamen die drei unten aufgeführten 
Beispiele heraus, bei denen ich nicht weiß welche Lösung die "bessere" 
ist. Damit die Beispiele unabhängig von der verwendeten 
Programmiersprache sind habe ich sie in (m)einem Pseudo-Code 
geschrieben. Ich denke jeder der schon einmal programmiert hat wird den 
Code verstehen.

Irgendwo am Anfang des Programms wird ein Array mit den Zeichenketten 
definiert bzw. vom Anwender angegeben. Das Array besteht aus maximal 30 
Elementen. Die Reihenfolge der Elemente ist nicht sortiert.
1
List[1] := 'Text1'
2
List[2] := 'Text2'
3
List[3] := 'Text3'
4
List[4] := 'Text4'
5
...
Im Weiteren Verlauf des Programms soll untersucht werden, ob die 
folgende Zeichenkette in dem o.g. Array enthalten ist.
1
SearchString := 'Text3'
Da das Array sehr klein ist habe ich zunächst über alle Elemente 
gesucht.
1
Index := 1
2
while Index <= length(List)
3
    if SearchString == List(Index)
4
        Found := 'true'
5
    end
6
    Index := Index + 1
7
end
Allerdings ist mir nicht ganz klar, ob es üblich bzw. guter Stil ist 
weiterzusuchen, obwohl der Text bereits gefunden wurde. Ich habe die 
Schleife daher wie folgt erweitert.
1
Index := 1
2
while Index <= length(List)
3
    if SearchString == List(Index)
4
        Found := 'true'
5
        Index := length(List)
6
    end
7
    Index := Index + 1
8
end
An der oben aufgeführten Schleife hat mir jedoch nicht gefallen, dass 
die Funktion "length(List)" zweimal aufgerufen werden muss. Daher dachte 
ich mir es ist doch möglich dies zu umgehen, wenn die Liste rückwärts 
durchsucht wird.
1
Index := length(List)
2
while Index > 0
3
    if SearchString == List(Index)
4
        Found := 'true'
5
        Index := 0
6
    end
7
    Index := Index - 1
8
end
Jetzt bin ich mir allerdings nicht mehr sicher, ob dieser Code für 
andere (auch Anfänger) noch einfach ist. Immerhin sind wir in unserem 
Kulturkreis gewohnt Listen von oben nach unten zu lesen. Welche der drei 
Vorgehensweisen würdet Ihr bevorzugen?

Mit freundlichen Grüßen
Guido

von Carsten W. (eagle38106)


Lesenswert?

Ich würde die erste Variante bevorzugen, plus ein "Break", welches die 
Suche beim Erreichen der ersten Fundstelle abbricht.
1
Index = 1;
2
Found = false;
3
while (Index <= ArrayGrenze)
4
{
5
  if (SearchString == Liste [Index])
6
  {
7
    Found = true;
8
    break;
9
  }
10
  Index ++;
11
}

Dann hat man bei gesetztem Found gleich einen Zeiger auf die Fundstelle.

von Alter Hase (Gast)


Lesenswert?

Die Suche nach dem Finden des Strings abzubrechen
halte ich für OK.

Die Frage heißt ja ob der gesuchte String enthalten ist
und nicht wie Oft enhalten. Bei wie oft muß natürlich
das gesamte Array abgesucht werden.

Ich würde also die Zeile mit dem while um "&& found == false"
ergänzen. Kann Laufzeit sparen.

Für die Suchrichtung würde ich mal schauen was der
Compiler draus macht und wie lange der Ziel-µC benötigt.
Dann würde ich das bessere nehmen.

von Guido C. (guidoanalog)


Lesenswert?

Hallo,

vielen danke für die Rückmeldungen.

Carsten Wille schrieb:
> Ich würde die erste Variante bevorzugen, plus ein "Break", welches die
> Suche beim Erreichen der ersten Fundstelle abbricht.

Stimmt ein "break" ist sicher die eleganteste Lösung. Leider ist dieser 
Befehl nicht in jeder Programmierumgebung vorhanden. So auch nicht in 
"imc Famos" für das ich gerade eine Auswerteroutinen für meine Messdaten 
schreibe.

Alter Hase schrieb:
> Die Frage heißt ja ob der gesuchte String enthalten ist
> und nicht wie Oft enhalten.

Es muss nur untersucht werden, ob der String "überhaupt" vorhanden ist.

Alter Hase schrieb:
> Ich würde also die Zeile mit dem while um "&& found == false"
> ergänzen. Kann Laufzeit sparen.

Laufzeit ist zwar nicht so das Problem, die Idee ist dennoch gut.

Mit freundlichen Grüßen
Guido

von Karl H. (kbuchegg)


Lesenswert?

Kommt drauf an, wie 'pedantisch' man einige Regeln auslegt.

Eine Regel besagt: Eine Funktion sollte einen Einstieg und einen 
Ausstieg haben. Dagegen ist auch grundsätzlich nichts zu sagen, wenn man 
allerdings akzeptiert, dass es auch Ausnahmen geben kann. zb 
Fehlerabfragen am Anfang einer Funktion mit vorzeitigem Return.
Aber auch: kurze Funktionen, die überschaubar sind und dadurch, dass man 
diese Regel strikt einhaltet nichts gewinnen

int Search( .... )
{
  for( i = 0; i < ArrayGrenze; i++ ) {
    if( List[i] == SearchString )
      return i;
  }

  return -1;
}


Ich bevorzuge hier die for-Schleife (egal ob man das syntaxmässig so 
schreibt oder in einer anderen Sprache anders), weil
* das grundsätzlich eine Zählschleife ist
* ich vorher weiß wie oft sie maximal durchlaufen werden muss
* ich so die 3 Elemente einer Zählschleife beisammen habe
     + bei welcher Zahl gehts los
     + bei welcher Zahl ist Schluss
     + was passiert mit dem zählenden Element von einem Durchlauf
       zum nächsten


Dadurch, dass ich hier einen return mitten aus der Schleife heraus 
zulasse, verschleiere ich die Funktion noch nicht. Aber: ich brauche 
keine zusätzlichen Variablen, die in die Analyse der Funktion eingehen 
müssen.

von Guido C. (guidoanalog)


Lesenswert?

Hallo,

ich sehe schon, Ihr seid alle zu sehr mit C verseucht. "LOL"

Leider kennt imc Famos weder eine For-Schleife noch ein Befehl zum 
beenden einer (While-)Schleife. Vielleicht war mein Ansatz mit dem 
Pseudo-Code nicht so gut. Ich dachte mir jedoch, wenn ich von FAMOS 
schreibe liest es sowieso keiner, da dieses Programm unter den µC.net 
Benutzern nicht sehr weit verbreitet zu sein scheint. FAMOS-Foren sind 
leider alle wie ausgestorben.

Vermutlich wäre es dann so am besten, oder?
1
Index := length(List)
2
while (Index > 0) and not(Found)
3
    if SearchString == List(Index)
4
        Found := 'true'
5
    end
6
    Index := Index - 1
7
end

Mit freundlichen Grüßen
Guido

von Yalu X. (yalu) (Moderator)


Lesenswert?

Meiner Meinung nach sollte man Breaks und erst recht Returns mitten im
Code vermeiden, allerdings nur dann, wenn deren Vermeidung nicht durch
irgendwelche Verrenkungen erkauft wird.

In diesem Fall geht es ohne Verrenkungen, indem man das Ergebnis des
Stringvergleichs einfach mit zur Abbruchbedingung hinzufügt. In C sieht
das folgendermaßen aus:
1
#include <stdio.h>
2
#include <string.h>
3
4
char *List[] = { "Text1", "Text2", "Text3", "Text4" };
5
#define LSIZE (sizeof List / sizeof List[0])
6
7
int main(void) {
8
  char SearchString[] = "Text3";
9
  int i;
10
11
  // Suchschleife
12
  for (i=0; i<LSIZE && strcmp(List[i], SearchString); i++);
13
14
  // Ausgabe
15
  if (i<LSIZE)
16
    printf("gefunden an Index %d\n", i);
17
  else
18
    printf("nicht gefunden\n");
19
20
  return 0;
21
}

Manch einer wird jetzt anmerken, dass in die Zeile mit dem "for" zu viel
Code hineingepackt wurde. Ich finde, die Zeile ist mit 57 Zeichen (ohne
die Einrückung) für einen geübteren C-Programmierer noch gut mit einem
Blick erfassbar, aber da gehen die Geschmäcker eben etwas auseinander :)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Guido C. schrieb:
> Leider kennt imc Famos weder eine For-Schleife noch ein Befehl zum
> beenden einer (While-)Schleife.

Wei wär's so:
1
Index := length(List)
2
while (Index > 0) and SearchString <> List(Index)
3
    Index := Index - 1
4
end

von Sven P. (Gast)


Lesenswert?

Guido C. schrieb:
> Hallo,
>
> ich sehe schon, Ihr seid alle zu sehr mit C verseucht. "LOL"
>
> Leider kennt imc Famos weder eine For-Schleife noch ein Befehl zum
> beenden einer (While-)Schleife.
Nunja, du kämpfst wohl mit demselbem Mist, wie ich damals mit Simplorer 
unt Matlab gekämpft habe: Programme, bei denen man sich fragt, wie sich 
solche ergonomischen Katastrophen so lange halten können...


> Vermutlich wäre es dann so am besten, oder?
> [...]
Das ist sehr schwierig zu beurteilen.
Wenn ich mal ganz dreist annehme, dass der Skript-Interpreter (also das, 
was dein Programm ausführt) gewohnt mies konstruiert ist, dann solltest 
du möglichst wenig Programmtext bei jeder Iteration ausführen.

Das bedeutet vorallem, dass du die Schleifenbedingung kurz halten musst. 
Beschränke dich da auf 'Index > 0' oder 'Index < N', wobei du 'N' vorher 
als Variable eingeführt hast. Das vermeidet, dass die 
'length()'-Funktion bei jeder Runde gerufen wird.
Als Abbruch würde ich dann, wie du ja auch schon vorgeschlagen hast, den 
Index in der Schleife so versetzen, dass die Schleife abbricht. Sofern 
du die Fundstelle brauchst, merk dir den Index nochmal in einer 
separaten Variablen:
1
I := 0
2
Index := -1
3
N := length(List)
4
5
while I < N
6
    if SearchString == List(I)
7
        Index := I
8
        I := N
9
    end
10
    I := I + 1
11
end

So würde ich das in diesem Fall formulieren. Wohl gemerkt: Unter der 
(leider recht wahrscheinlich zutreffenden) Voraussetzung, dass der 
Interpreter Schrott ist.
Die Iteration beschränkt sich dann auf drei kurze Zeilen (Vergleich im 
Schleifenkopf, Vergleich auf Suchstring und Inkrement von I). Ob du die 
drei dann noch zusammenziehst, wie Yalu zuvor es vorschlägt, spielt dann 
keine Rolle mehr.

von Guido C. (guidoanalog)


Lesenswert?

Hallo,

Yalu X. schrieb:
> Wei wär's so:
> Index := length(List)
> while (Index > 0) and SearchString <> List(Index)
>     Index := Index - 1
> end

Das gefällt mit sehr gut. Kurz und knackig :-)

Sven P. schrieb:
> Nunja, du kämpfst wohl mit demselbem Mist, wie ich damals mit Simplorer
> unt Matlab gekämpft habe: Programme, bei denen man sich fragt, wie sich
> solche ergonomischen Katastrophen so lange halten können...

Ich hoffe immer, dass mit der nächsten Version alles besser wird.

Sven P. schrieb:
> Das bedeutet vorallem, dass du die Schleifenbedingung kurz halten musst.

Da hast Du sicher recht. In Matlab versuche ich immer auf Schleifen 
komplett zu verzichten. In FAMOS gelingt dies leider nicht. Hierfür 
fehlen dort einfach ein paar Syntaxelemente.

Danke nochmals an ALLE für die Unterstützung. Ich werde mir den Inhalt 
des ganzen Thread noch einmal in Ruhe durch den Kopf gehen lassen. Wobei 
ich denke der Ansatz von Yalu ist schon optimal.

Mit freundlichen Grüßen
Guido

von Karl H. (kbuchegg)


Lesenswert?

Yalu X. schrieb:

> Wei wär's so:
>
>
1
> Index := length(List)
2
> while (Index > 0) and SearchString <> List(Index)
3
>     Index := Index - 1
4
> end
5
>


Auch schön.

Ich bin allerdings kein Freund von Schleifen die runterzählen, ichmag 
hochzählende Schleifen lieber. Das eröffnet dann noch eine Variante, 
wenn es erlaubt ist temporär an die Liste/das Array noch ein Element 
anzuhängen
1
  lastIndex := length(List)
2
  append( List, SearchString )
3
4
  Index := 0;
5
  while SearchString <> List(Index)
6
    Index++
7
8
  if Index = lastIndex then
9
    nicht gefunden
10
11
  ev. letztes Element wieder aus der Liste rausnehmen falls notwendig.

Hauptvorteil: es drückt die Schritte in der Schleife runter, weil sicher 
gestellt ist, dass der Suchstring auch tatsächlich gefunden wird.

von Programmierer (Gast)


Lesenswert?

Wie wäre es mit einer sortieren Liste und binärer Suche. Bei 1000 
Listenelementen ist man dann so nach 10 Vergleichen am Ziel.

von J.-u. G. (juwe)


Lesenswert?

Sven P. schrieb:
>> Leider kennt imc Famos weder eine For-Schleife noch ein Befehl zum
>> beenden einer (While-)Schleife.
> Nunja, du kämpfst wohl mit demselbem Mist, wie ich damals mit Simplorer
> unt Matlab gekämpft habe

Matlab kennt doch sowohl for-Schleifen (die zugegebenermaßen den Ablauf 
oft ziemlich ausbremsen) als auch "break" zum Abbruch von 
While-Schleifen. Oder meinst Du was anderes?

Guido C. schrieb:
> In Matlab versuche ich immer auf Schleifen
> komplett zu verzichten.

Das ist ja gerade eine der Spezialitäten von Matlab, dass man meistens 
ohne die relativ langsamen for-Schleifen auskommen kann.

von Guido C. (guidoanalog)


Lesenswert?

Hallo,

J.-u. G. schrieb:
> Matlab kennt doch sowohl for-Schleifen (die zugegebenermaßen den Ablauf
> oft ziemlich ausbremsen) als auch "break" zum Abbruch von
> While-Schleifen. Oder meinst Du was anderes?

Ich arbeite derzeit mit Matlab und Famos.
Matlab => "For"-Schleifen und "break"
Famos => Keine "For"-Schleifen und Kein "break"

Sorry falls ich hier für Verwirrung gesorgt habe. Die Frage in diesem 
Thread bezog sich auf FAMOS. In Matlab hätte ich das Problem wohl ohne 
Schleife gelöst.

Mit freundlichen Grüßen
Guido

von Georg A. (georga)


Lesenswert?

> indem man das Ergebnis des Stringvergleichs einfach mit zur
> Abbruchbedingung hinzufügt.

...was wiederum ein Stil ist, den ich nicht so mag, weil man zwei nicht 
zusammenhängende Bedingungen in eine Zeile bringt. Das eine ist der rein 
formale Teil, weil man einfach nicht mehr Elemente als LSIZE untersuchen 
kann, das andere ist der Vergleich auf irgendwas, was man finden will. 
Gerade wenn man für den zweiten Teil noch komplexere Bedingungen 
überprüfen will, wirds unübersichtlich und mit Pech noch so, dass der 
Index-Check aus Versehen deaktiviert wird (OR an der falschen Stelle, 
Klammerung verpennt, ...).

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.