mikrocontroller.net

Forum: Compiler & IDEs for-Schleife mit else Anweisung


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Firebird (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen

Ich habe eine funktionierende for-Schleife die den richtigen Case aus 18 
Cases sucht. Wird keiner gefunde, dann ist der letzte Case der default.
  for( i = 0; i < NR_CASES - 1; ++i )
  {
    if( Cases[i].InputValue == data )
    {
      caseNr = i;
      break;
    }
  }

Jetzt möchte ich den zuletzt gültigen Case verwenden Falls keiner 
gefunden wird.

Das möchte ich so realisieren indem ich die gültige Case Nummer in 
'LastCase' sichere und in 'caseNr' zurückspeichere Falls kein gültiger 
Case gefunden wird.
Das habe ich mit einer else Anweisung versucht.
  for( i = 0; i < NR_CASES - 1; ++i )
  {
    if( Cases[i].InputValue == data )
    {
      caseNr = i;
      LastCase = i;       // gültiger Case sichern
      break;
    }
    else
    {
      CaseNr = LastCase;  // zuletzt gültiger Case zurückspeichern
    }
  }

Das Problem:

Bis und mit Case 17 funktionert es einwandfrei, Case 18 wird aber nicht 
mehr ausgeführt (als ob es nicht vorhanden wäre).

Wenn ich jetzt aber die Anzahl Cases um eins erhöhe, d.h.
  #define NR_CASES 18
auf
  #define NR_CASES 19
dann funktionierts auch mit dem letzten Case 18.

Warum ist das so? Es gibt nur 18 Cases.

Danke und Gruss
Firebird

Autor: TM F. (p_richner)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich vermute wegen

i < NR_CASES - 1

dem -1

Autor: Tassilo H. (tassilo_h)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schreibst du doch auch so im for: NR_CASES - 1
Entweder i <= NR_CASES - 1 oder i < NR_CASES

Autor: Gаst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
caseNr = lastCase;
for (i = 0; i < NR_CASES; i++) {
 if (Cases[i].InputValue == data) {
  caseNr = i;
  break;
 }
}

Evtl. so?

Autor: CCC (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gаst schrieb:
> caseNr = lastCase;
> for (i = 0; i < NR_CASES; i++) {
>  if (Cases[i].InputValue == data) {
>   caseNr = i;
>   break;
>  }
> }
> Evtl. so?

Plus Zuweisung lastCase
caseNr = lastCase;
for (i = 0; i < NR_CASES; i++) {
 if (Cases[i].InputValue == data) {
  caseNr   = i;
  lastCase = caseNr;
  break;
 }
}

Autor: Joachim B. (jar)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
case 0 ist aber vermutlich ungültig, deswegen inc't er ja vorher mit ++i 
nicht i++

mit for( i = 1; statt for( i = 0; wäre es aber auch gegangen

Autor: Georg Gast 1 (Gast)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Joachim B. schrieb:
> case 0 ist aber vermutlich ungültig,
Da in C/C++ Arrays nun einmal mit 0 beginnend indiziert werden, ist das 
möglich aber sinnlos (frei nach Loriot).

Solange der OP nicht die Definitionen der Variablen preisgibt, bleibt 
alles Kaffeesatz-Leserei.

Joachim B. schrieb:
> deswegen inc't er ja vorher mit ++i nicht i++
Das ist Unsinn. An des Stelle macht das keinen Unterschied. In einer 
C/C++ for-Schleife wird der Rückgabewert des Zählausdrucks ignoriert. 
Nur die "Nebenwirkung" (hier: inkrementieren) wirkt. Deshalb könnte man 
da auch i=i+1, nicht aber nur i+1 hinschreiben.

Georg.

Autor: Joachim B. (jar)
Datum:

Bewertung
-4 lesenswert
nicht lesenswert
Georg Gast 1 schrieb:
> Solange der OP nicht die Definitionen der Variablen preisgibt, bleibt
> alles Kaffeesatz-Leserei.

da stimme ich zu

> Das ist Unsinn. An des Stelle macht das keinen Unterschied. In einer
> Georg.

da widerspreche ich, er incrementiert vor dem ersten Schleifendurchlauf, 
das macht sehr wohl einen Unterschied ob vor (++i) oder nach (i++)

element[0] sollte nie angesprochen werden.

Autor: Georg Gast 1 (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Joachim B. schrieb:
>> Das ist Unsinn. An des Stelle macht das keinen Unterschied. In einer
>> Georg.
>
> da widerspreche ich, er incrementiert vor dem ersten Schleifendurchlauf,
> das macht sehr wohl einen Unterschied ob vor (++i) oder nach (i++)
>
> element[0] sollte nie angesprochen werden.

Bitte lies die Dokumentation zur for-Schleife.

Der 3. Ausdruck wird immer nach dem Schleifendurchlauf ausgeführt.
Der Wert des 3. Ausdrucks wird ignoriert.
Nur die Nebenwirkung (hier: inkrement) ist relevant.

Autor: Joachim B. (jar)
Datum:

Bewertung
-5 lesenswert
nicht lesenswert
Georg Gast 1 schrieb:
> Bitte lies die Dokumentation zur for-Schleife.

danke, habe ich gemacht und bin erstaunt.
Bis jetzt dachte ich tatsächlich es wird vor Start incrementiert sonst 
würde es ja nicht post/pre increment heissen.

aber natürlich, auch das ist bekannt es wird von links nach rechts 
gearbeitet, also kommt das ++i erst wenn alles zu spät ist. (wenn der 
preprozessor/Compiler nicht vorher optimierend eingreift)

ist mir irgendwie entfallen zumal es auch recht ungewöhnlich für eine 
for Schleife ist vorher zu incrementieren.

: Bearbeitet durch User
Autor: Firebird (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für eure Vorschläge. Ich habe gleich programmiert und 
getestet.

Mit
  i <= NR_CASES - 1
functionieren beide Varianten:
  for( i = 0; i <= NR_CASES-1; ++i )
  {
    if( Cases[i].InputValue == data )
    {
      caseNr = i;
      LastCase = caseNr;
      break;
    }
    else
    {
      caseNr = LastCase;
    }
  }
wie auch
  caseNr = LastCase;
    
  for( i = 0; i <= NR_CASES-1; ++i )
  {
    if( Cases[i].InputValue == data )
    {
      caseNr = i;
      LastCase = caseNr;
      break;
    }
  }
Mich irritiert die Tatsache, dass der Ursprüngliche Code mit
  i < NR_CASES - 1
funktioniert und bei der Variante mit der else Anweisung nicht.

Autor: Joachim B. (jar)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
Firebird schrieb:
> Vielen Dank für eure Vorschläge. Ich habe gleich programmiert und
> getestet.

warum schmeisst du nicht das elendige ++i raus, das verwirrt nur und hat 
keinen Effekt wie wir sehen.

Es wird am Schleifenbeginn nicht vorher incrementiert!
Auch wenn es funktioniert, es bleibt doof lesbar.

Autor: Georg Gast 1 (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Joachim B. schrieb:
> Georg Gast 1 schrieb:
>> Bitte lies die Dokumentation zur for-Schleife.
>
> danke, habe ich gemacht und bin erstaunt.
Sehr gut (ernsthaft).

> Bis jetzt dachte ich tatsächlich es wird vor Start incrementiert sonst
> würde es ja nicht post/pre increment heissen.
Du vermischst hier 2 Sachen:
A: pre- / post-increment Operatoren
Natürlich sind die Ausdrücke j = i++; und j = ++i; verschieden was den 
Inhalt von j danach betrifft. Die Wirkung auf i, nachdem der Ausdruck 
abgearbeitet wurde, ist aber die gleiche (eins mehr als vorher).

B: for-Schleife
for(INITIALISIERUNG; ABBRUCHPRÜFUNG; ZÄHLAUSDRUCK) ANWEISUNG;
das bedeutet ausgeschrieben:
1. INITIALISIERUNG
2. if not ABBRUCHPRÜFUNG goto 6
3. ANWEISUNG
4. ZÄHLAUSDRUCK
5. goto 2
6. ende

Der ZÄHLAUSDRUCK wird also als eigenständige Anweisung ausgeführt, der 
Wert davon wird ignoriert/weggeworfen, und da ist es egal ob der 
ursprüngliche oder der inkrementierte Wert von i weggeworfen wird.
Nur die "Nebenwirkungen" sind wichtig.
Ein ZÄHLAUSDRUCK ohne Nebenwirkungen ist nutzlos.

>
> aber natürlich, auch das ist bekannt es wird von links nach rechts
> gearbeitet, also kommt das ++i erst wenn alles zu spät ist. (wenn der
> preprozessor/Compiler nicht vorher optimierend eingreift)

Das ist wieder eine andere Baustelle. Mit dem obigen haben weder die 
Ausführung von links nach rechts (die innerhalb eines Ausdrucks für 
gleichrangige Operatoren und für die Anweisungen in einem Block/Verbund 
gilt) noch der Präprozessor etwas zu tun.

Bitte lies ein gutes Buch über C.

Georg.

Autor: Joachim B. (jar)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Georg Gast 1 schrieb:
> Bitte lies ein gutes Buch über C.
>
> Georg.

hab ich doch schon öfter und das Meiste wieder vergessen

@TO lese was über abweisende und nicht abweisende Schleifen!

wenn du unbedingt willst mache
while(++i <= NR_CASES-1)
{
}

Autor: Georg Gast 1 (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Joachim B. schrieb:
> warum schmeisst du nicht das elendige ++i raus, das verwirrt nur und hat
> keinen Effekt wie wir sehen.

Warum sollte er das? Es ist schlicht egal ob an dieser Stelle ++i oder 
i++ steht. Es tut das gleiche. Wer C kennt weiß das.

Außerdem hat es historische Gründe, eher ++i zu schreiben. Vor ~30 
Jahren, als die Compiler noch nicht so gut optimieren konnten, hat ++i 
zu effizienteren Code geführt (der Compiter hat eine Hilfsvariable 
angelegt, im den Ausgangswert von i zur weiteren Verwendung zu 
behalten). Heute ist es auch dahingehend egal.

Georg.

Autor: Georg Gast 1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Firebird schrieb:
> Mit  i <= NR_CASES - 1 functionieren beide Varianten

Warum schreibst Du nicht i < NR_CASES wie alle anderen?

Autor: Joachim B. (jar)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
Georg Gast 1 schrieb:
> Warum sollte er das? Es ist schlicht egal ob an dieser Stelle ++i oder
> i++ steht. Es tut das gleiche. Wer C kennt weiß das.

dann tuts auch nicht weh es zu ändern :)

welches C ist denn gemeint? K&R C89 C99?
https://de.wikipedia.org/wiki/Varianten_der_Programmiersprache_C

Autor: Georg Gast 1 (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Joachim B. schrieb:
> Georg Gast 1 schrieb:
>> Warum sollte er das? Es ist schlicht egal ob an dieser Stelle ++i oder
>> i++ steht. Es tut das gleiche. Wer C kennt weiß das.
>
> welches C ist denn gemeint? K&R C89 C99?
> https://de.wikipedia.org/wiki/Varianten_der_Programmiersprache_C

Jetzt hast Du's mir aber so richtig gezeigt. Also dass Du keine Ahnung 
von C hast.

Es ist nämlich schon wieder egal. Das (und vieles andere auch) ist in 
allen C Varianten gleich.

Ich bin dann mal raus.
Georg.

Autor: Firebird (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg Gast 1 schrieb:
> Warum schreibst Du nicht i < NR_CASES wie alle anderen?

Wenn ich das so schreibe gibt's ein Durcheinander, d.h. 'data' Werte 
werden verarbeitet obwohl sie nicht in den 18 Cases vorhanden sind. Das 
Resultat sind willkürlich leuchtende LEDs.

Die Erklärung warum es
i <= NR_CASES - 1
 lauten muss weiss ich noch nicht. Die Struct sieht wie folgt aus:
struct Led Cases[NR_CASES] =
{
  { 0x03,  { 0, 5, 5, 0, 5, 0, 0, 5, 0, 0, 0, 0 } },             // case 1
  { 0x83,  { 0, PWM_MAX, 5, 0, PWM_MAX, 0, 0, 5, 0, 0, 0, 0 } }, // case 2
  { 0x07,  { 0, 5, 5, 0, 5, 0, 5, 0, 0, 0, 0, 5 } },             // case 3
  { 0x87,  { 0, PWM_MAX, 5, 0, PWM_MAX, 0, 5, 0, 0, 0, 0, 5 } }, // case 4
  { 0x0b,  { 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 5 } },             // case 5
  { 0x13,  { 0, 5, 0, 0, 5, 0, 0, 5, 0, 0, 0, 0 } },             // case 6
  { 0x23,  { 0, 5, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0 } },             // case 7
  { 0x43,  { 5, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0, 0 } },             // case 8
  { 0x01,  { 0, 5, 0, 0, 0, 0, 0, 5, 5, 0, 5, 0 } },             // case 9
  { 0x81,  { 0, 5, 0, 0, 0, 0, 0, PWM_MAX, 5, 0, PWM_MAX, 0 } }, // case 10
  { 0x05,  { 5, 0, 0, 0, 0, 5, 0, 5, 5, 0, 5, 0 } },             // case 11
  { 0x85,  { 5, 0, 0, 0, 0, 5, 0, PWM_MAX, 5, 0, PWM_MAX, 0 } }, // case 12
  { 0x09,  { 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0 } },             // case 13
  { 0x11,  { 0, 5, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0 } },             // case 14
  { 0x21,  { 0, 5, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0 } },             // case 15
  { 0x41,  { 0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0, 5 } },             // case 16
  { 0x02,  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },             // case 17
  { 0x00,  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },             // case 18
};  

Vielleicht hat jemand eine Erklärung?

Autor: René H. (Firma: Herr) (hb9frh)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Firebird schrieb:
> Mich irritiert die Tatsache, dass der Ursprüngliche Code mit

Weil Cases[NR_CASES] nicht existiert. Memory nicht initialisiert.

Grüsse,
René

Autor: Georg Gast 1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Firebird schrieb:
> Georg Gast 1 schrieb:
>> Warum schreibst Du nicht i < NR_CASES wie alle anderen?
>
> Wenn ich das so schreibe gibt's ein Durcheinander, d.h. 'data' Werte
> werden verarbeitet obwohl sie nicht in den 18 Cases vorhanden sind. Das
> Resultat sind willkürlich leuchtende LEDs.
Da hast Du wohn noch ein paar andere Fehler in deinem Programm.

>
> Die Erklärung warum es i <= NR_CASES - 1 lauten muss weiss ich noch
> nicht. Die Struct sieht wie folgt aus:
>
 struct Led Cases[NR_CASES] =
> {
>   { 0x03,  { 0, 5, 5, 0, 5, 0, 0, 5, 0, 0, 0, 0 } },             // case 1
>   ...
>   { 0x00,  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },             // case 18
> }; 
>
> Vielleicht hat jemand eine Erklärung?

Ich wiederhole mich ja ungern, aber:

Georg Gast 1 schrieb:
> Da in C/C++ Arrays nun einmal mit 0 beginnend indiziert werden ...

Noch mal im Klartext:
#define NR_CASES 18

struct Led { wasauchimmer; }; // Deklaration

struct Led Cases[NR_CASES] = {
  { 0x03,  { 0, 5, 5, 0, 5, 0, 0, 5, 0, 0, 0, 0 } },             // case 0   <-- das erste Element ist immer 0
  ...
  { 0x00,  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },             // case 17  <-- das letzte ist immer N-1
};

Auf
Cases[i]
 darf nur mit i=0...17 zugegriffen werden. Alles andere ist ein Fehler. 
Lesen außerhalb liefert beliebige Werte. Schreiben außerhalb macht 
andere Variablen kaputt.

Vielleicht hast Du ähnliche Fehler ja noch anderswo im Programm.

Georg.

Autor: Firebird (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Led Struct ist wie folgt definiert:
struct Led
{
  unsigned char InputValue;           // Welcher Wert muss 'data' haben ...    
  unsigned char Values[PWM_CHANNELS]; // ... damit die Werte auf die Leds ausgegeben werden
};

Die Struct selber bleibt gleich, ich habe die 'case' Nummerierung 
korrigiert:
  
struct Led Cases[NR_CASES] =
{
  { 0x03,  { 0, 5, 5, 0, 5, 0, 0, 5, 0, 0, 0, 0 } },         // case 0
  ...
  { 0x00,  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },         // case 17
};  
Ich habe jetzt die for Anweisung angepasst:
  // caseNr = NR_CASES - 1;             // definiert letzten Case als Default
  // for(i = 0; i < NR_CASES - 1; i++)  // Anweisung für letzten Case als Default
    
  caseNr = LastCase;                    // definiert den zuletzt gültigen Case

  for(i = 0; i < NR_CASES; i++)
  {
    if(Cases[i].InputValue == data)
    {
      caseNr = i;
      LastCase = caseNr;
      break;
    }
  }

Jetzt läuft das Programm durch ohne Fehler.

Autor: Rufus Τ. F. (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> struct Led Cases[NR_CASES] =

Hier musst Du selbst zählen und vergleichen, ob die Anzahl der 
Initialisierungen mit (dem anderswo definierten) NR_CASES übereinstimmt.

Wenn Du Dein Array so anlegst:

> struct Led Cases[] =

kann der Compiler die Arraygröße an die Anzahl der angegebenen 
Initialisierer anpassen.

Die wiederum kannst Du so bestimmen:

#define NR_CASES (sizeof Cases / sizeof Cases[0])

Das ist vielleicht etwas weniger fehlerträchtig, wenn Du irgendwann die 
Anzahl der zu behandelnden Fälle verändern möchtest

Autor: Firebird (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für den wertvollen Tipp und auch ein Dankeschön an alle die 
geholfen haben. Es freut mich, dass man so ein Code debuggen und 
optimieren kann und auch dabei lernt.

Gruss
Firebird

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mache das immer so, wenn ich etwas in einem Array suchen will:
    for (i = 0; i < N_CASES; i++)
    {
        if (array[i] == pattern)
        {
            break;          // pattern found!
        }
    }

    if (i == N_CASES)
    {
        // NOT found!
    }
    else
    {
        // found!
    }

wobei N_CASES die Anzahl der tatsächlichen vorhandenen Array-Elemente 
ist - also so, wie Rufus es exemplarisch vorgemacht hat. Ich finde es am 
lesbarsten, wenn möglichst wenig Action in der for-Schleife selbst ist.

: Bearbeitet durch Moderator
Autor: MaWin (Gast)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Frank M. schrieb:
> Ich mache das immer so, wenn ich etwas in einem Array suchen will:

In Python kann man auch dies machen:
for x in array:
  if x == pattern:
    # tue was
    break
else:
  # nicht gefunden

Das finde ich oft ganz nützlich.

Autor: Firebird (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Ich mache das immer so, wenn ich etwas in einem Array suchen will:

Ich habe das gleich probiert:
  for (i = 0; i < NR_CASES; i++)
  {
    if (Cases[i].InputValue == data)
    {
      break;               // pattern found!
    }
  }

  if (i == NR_CASES)
  {
    caseNr = LastCase;     // NOT found!
  }
  else
  {
    caseNr = i;            // found!
    LastCase = caseNr;
  }

Ich vermute, dass die for Schleife schneller abgearbeitet wird.

Autor: Eric B. (beric)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Firebird schrieb:
> Ich vermute, dass die for Schleife schneller abgearbeitet wird.

Eher nicht. Der Compiler optimiert das schon...

Autor: A. S. (achs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Ich mache das immer so, wenn ich etwas in einem Array suchen will:

Ich habe so eine diffuse (vermutlich unbegründete) Angst, den 
Schleifenzähler außerhalb zu verwerten. Z.B. weil ich die 
Abbruchbedingung zweimal getrennt konsinstent schreiben muss.

Ich mach oft sowas:
{
/* Default value setzen */
int nextCase = LastCase;

  for(i = 0; i < NR_CASES; i++)
  {
    if(Cases[i].InputValue == data)
    {
      nextCase = i;
      break;
    }
  }
  caseNr   = nextCase;
  LastCase = nextCase;
}
Das hat aber noch mehr flaws:
 A) eine zusätzliche Lokale Variable (vom Typ ... , auto wäre schön!)
 B) eine doppelt gesetzte Variable (der zuerst zugewiesene Wert wird 
nicht verwendet)
 C) LastCase wird unconditional überschrieben, auch wenn nicht nowendig
Man könnte statt C) die Zuweisung vor's break packen, aber das 
verwässert das eigentliche Ziel: die Trennung von Suche und Zuweisung.

auch mit Flag wird's nicht besser:
{
bool not_found=TRUE;

  for(i = 0; i < NR_CASES; i++)
  {
    if(Cases[i].InputValue == data)
    {
      caseNr   = i;
      LastCase = i;
      not_found= FALSE;
      break;
    }
  }
  if(not_found)
  {
     caseNr   = LastCase;
  }
}

Was ich sagen will: So ein else bei for, wie vom TO gewünscht, hätte 
m.E. wirklich was.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achim S. schrieb:
> Ich habe so eine diffuse (vermutlich unbegründete) Angst, den
> Schleifenzähler außerhalb zu verwerten.

Ja, Deine Angst ist unbegründet. Die for-Schleife
    for (START; BEDINGUNG; WIEDERHOLUNG)
    {
        ...
    }
ist ja nur eine abkürzende Schreibweise für:
    START;
    while (BEDINGUNG)
    {
        ...
        WIEDERHOLUNG;
    }

Die Schleifenvariable i hat daher denselben Stellenwert wie das Flag 
not_found in Deinem unteren Beispiel.

: Bearbeitet durch Moderator
Autor: A. S. (achs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Ja, Deine Angst ist unbegründet. Die for-Schleife
> ...
> ist ja nur eine abkürzende Schreibweise für:

schon klar. Mir ging es darum, dass die Bedingung der Schleifen zweimal 
leicht abgewandelt konsistent im Code stehen muss, während das flag 
quasi nicht damit korreliert.

Autor: 2⁵ (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Ja, Deine Angst ist unbegründet.

Jain. Wenn man bei for schleifen gerne

for (int i=0, i<MAXVALUE; i++) // bzw. besser
for (size_t i=0, i<MAXVALUE; i++)

schreibt, dann existiert i nur im "for" scope.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
2⁵ schrieb:
> Wenn man bei for schleifen gerne
>
> for (int i=0, i<MAXVALUE; i++) // bzw. besser
> for (size_t i=0, i<MAXVALUE; i++)
>
> schreibt, dann existiert i nur im "for" scope.

Tja, wenn. Aber nur dann.

Ja, ich kenne die Argumente der Scope-Minimalisten. Aber es gibt auch 
Argumente gegen die Definition innerhalb der for-Schleife. Zum Beispiel 
versehentliches Shadowing oder auch die Nicht-Weiterverwendung außerhalb 
der Schleife.

Ich sehe das als Geschmackssache an.

Autor: A. S. (achs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Firebird schrieb:
> Ich habe das gleich probiert:
>   for (i = 0; i < NR_CASES; i++)
>   {
>     if (Cases[i].InputValue == data)
>     {
>       break;               // pattern found!
>     }
>   }
>
>   if (i == NR_CASES)
>   {
>     caseNr = LastCase;     // NOT found!
>   }
>   else
>   {
>     caseNr = i;            // found!
>     LastCase = caseNr;
>   }
>
und ohne doppelten Vergleich auf NR_CASES, quasi im Vorbeigehen: ;-)
for (i = 0; i < NR_CASES||(caseNr=LastCase,0); i++)
{
  if (Cases[i].InputValue == data)
  {
    caseNr = i;            // found!
    LastCase = caseNr;
    break; 
  }
}

Autor: Gаst (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Durch solche Kniffe wird Quelltext in C aber sehr schnell genauso gut 
lesbar wie Brainfuck oder gar Perl.

Autor: A. S. (achs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gаst schrieb:
> Durch solche Kniffe wird Quelltext in C aber sehr schnell genauso gut
> lesbar wie Brainfuck oder gar Perl.

Ich weiss... Deshalb wünsche ich mir ja auch (wie der TO) ein else, 
statt eines zusätzlichen ifs mit der negierten Bedingung. Ich finde es 
immer blöd, das gleiche an 2 stellen zu pflegen, vor allem am Anfang und 
nach dem Ende eines Blocks.

Autor: Gаst (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Wenn ich es optimieren und lesbar schreiben müsste (was ich auch 
freiwillig tun würde), würde ich es so probieren:
for (size_t i = 0; i < NR_CASES; i++) {
 if (Cases[i].InputValue == data) {
  caseNr = i;
  LastCase = caseNr;
  goto found;
 }
}

// NOT found!
caseNr = LastCase;

found:
// ...

Aber goto ist ja böse und des Teufels. Ahhhhhh, wir brauchen einen 
Exorzisten...

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es steht zwar nicht explizit in der Frage, aber ich denke schon, dass es 
um C geht ... (in C++ würde man einfach einen generischen Algorithmus 
benutzen)

Trotzdem kann man einfach das Iterator-Konzept auch in C anwenden. 
Zeiger sind Iteratoren.
    const int* last = NULL;
    for(const int* it = &array[0]; it < &array[NCASES]; ++it) {
        if (*it == value) {
            last = it;
        }
    }

    if(last) {
        // *last
    }

Somit ist last entweder ungültig oder verweist auf das letzte gefundene 
Element.

: Bearbeitet durch User
Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Firebird schrieb:
> Ich habe das gleich probiert:  for (i = 0; i < NR_CASES; i++)
>   {
>     if (Cases[i].InputValue == data)
>     {
>       break;               // pattern found!
>     }
>   }
>
>   if (i == NR_CASES)
>   {
>     caseNr = LastCase;     // NOT found!
>   }
>   else
>   {
>     caseNr = i;            // found!
>     LastCase = caseNr;
>   }

Man kann die Zuweisung für not found auch einfach vorziehen:
  caseNr = LastCase;     // if NOT found!
  for (i = 0; i < NR_CASES; i++)
  {
    if (Cases[i].InputValue == data)
    {
      caseNr = i;            // found!
      LastCase = caseNr;
      break;               // pattern found!
    }
  }

Autor: A. S. (achs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zu den beiden letzten Lösungen hatte ich schon geschrieben, warum ich 
sie ebenfalls nicht optimal finde:

Peter D. schrieb:
> Man kann die Zuweisung für not found auch einfach vorziehen:

Achim S. schrieb:
> B) eine doppelt gesetzte Variable (der zuerst zugewiesene Wert wird
> nicht verwendet)

Wilhelm M. schrieb:
> Somit ist last entweder ungültig oder

Achim S. schrieb:
> auch mit Flag wird's nicht besser:

: Bearbeitet durch User
Autor: Gаst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn jemand Lust und Zeit hat, kann er ja mal die verschiedenen 
Varianten durch den gcc jagen. Ich würde wetten, dass die Variante mit 
goto am besten abschneidet, weil dort keine doppelte Zuweisung und auch 
kein doppelter Vergleich vorhanden ist. Ich kann mich natürlich 
täuschen. Compiler sind sehr schlau heutzutage.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gаst schrieb:
> Wenn jemand Lust und Zeit hat,

Nee, weder Lust noch Zeit. Lohnt sich auch nicht, s.u.

> Ich würde wetten, dass die Variante mit
> goto am besten abschneidet, weil dort keine doppelte Zuweisung und auch
> kein doppelter Vergleich vorhanden ist.

Deine Formulierung "doppelt" hört sich erstmal nach einer Steigerung um 
100% an. Das ist aber eine Milchmädchenrechnung. Tatsächlich erhöhen 
sich Vergleiche bzw. Zuweisungen lediglich um 1.

Um das vernünftig zu messen, müsstest Du erstmal NR_CASES hinreichend 
groß machen, z.B. auf 10000000. Dann ist der Unterschied von 10000000 
auf 10000001 Zuweisungen bzw. Vergleiche im Verhältnis absolut 
vernachlässigbar. Das geht im Rauschen unter.

> Compiler sind sehr schlau heutzutage.

Eben. Vermutlich kommt da spätestens ab -O2 derselbe oder adäquate Code 
raus.

: Bearbeitet durch Moderator

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.