Szukaj…


Instrukcje if ()

Jednym z najprostszych sposobów kontrolowania przebiegu programu jest użycie instrukcji if if. To, czy ma zostać wykonany blok kodu, czy nie, może zostać określone w tej instrukcji.

Składnia instrukcji if select w C może wyglądać następująco:

if(cond) 
{
  statement(s);  /*to be executed, on condition being true*/
}

Na przykład,

if (a > 1) {
    puts("a is larger than 1");
}

Gdzie a > 1 jest warunkiem, który musi być true , aby wykonać instrukcje wewnątrz bloku if . W tym przykładzie „a jest większe niż 1” jest drukowane tylko wtedy, gdy a > 1 jest prawdziwe.

if instrukcje wyboru mogą pominąć nawiasy klamrowe { i } jeśli w bloku jest tylko jedna instrukcja. Powyższy przykład można przepisać na

if (a > 1)
    puts("a is larger than 1");

Jednak do wykonania wielu instrukcji w bloku muszą być użyte nawiasy klamrowe.

Warunek if może zawierać wiele wyrażeń. if wykona akcję tylko wtedy, gdy końcowy wynik wyrażenia jest prawdziwy.

Na przykład

if ((a > 1) && (b > 1)) {
    puts("a is larger than 1");
    a++;
}

będzie wykonywał tylko printf i a++ , gdy oba i a b jest większa niż 1 .

if () ... instrukcje i składnia else

Podczas gdy if wykonuje akcję tylko wtedy, gdy jej warunek ma wartość true , if / else pozwala określić różne akcje, gdy warunek jest true a warunek jest false .

Przykład:

if (a > 1)
    puts("a is larger than 1");
else 
    puts("a is not larger than 1");

Podobnie jak w if instrukcji if , gdy blok wewnątrz instrukcji if lub else składa się tylko z jednej instrukcji, nawiasy klamrowe można pominąć (ale nie jest to zalecane, ponieważ może łatwo wprowadzić problemy bezwiednie). Jeśli jednak w bloku if lub else znajduje się więcej niż jedna instrukcja, nawiasy klamrowe muszą być użyte w tym konkretnym bloku.

if (a > 1) 
{
    puts("a is larger than 1");
    a--;
}
else 
{
    puts("a is not larger than 1");
    a++;
}

instrukcje switch ()

instrukcje switch są przydatne, gdy chcesz, aby Twój program wykonywał wiele różnych czynności w zależności od wartości konkretnej zmiennej testowej.

Przykład użycia instrukcji switch wygląda następująco:

int a = 1;

switch (a) {
case 1:
    puts("a is 1");
    break;
case 2:
    puts("a is 2");
    break;
default:
    puts("a is neither 1 nor 2");
    break;
}

Ten przykład jest równoważny z

int a = 1;

if (a == 1) {
    puts("a is 1");
} else if (a == 2) {
    puts("a is 2");
} else {
    puts("a is neither 1 nor 2");
}

Jeśli wartość a wynosi 1, gdy używana jest instrukcja switch , a is 1 zostanie wydrukowane. Jeśli wartość a wynosi 2, a is 2 drukowane 2. W przeciwnym razie, a is neither 1 nor 2 zostaną wydrukowane.

case n: służy do opisania, gdzie wskoczy przepływ wykonania, gdy wartość przekazana do instrukcji switch to n . n musi być stałą czasową kompilacji i to samo n może istnieć najwyżej raz w jednej instrukcji switch .

default: służy do opisania, że gdy wartość nie zgadzała się z żadnym wyborem dla case n: Dobrą praktyką jest dołączanie default przypadku do każdej instrukcji switch, aby wychwycić nieoczekiwane zachowanie.

break; instrukcja jest wymagana, aby wyskoczyć z bloku switch .

Uwaga: jeśli przypadkowo zapomnisz dodać break po zakończeniu case , kompilator przyjmie, że zamierzasz „przewrócić się” i wszystkie kolejne instrukcje spraw zostaną wykonane (chyba że instrukcja break zostanie znaleziona w którykolwiek z kolejnych przypadków), bez względu na to, czy kolejne oświadczenia są zgodne, czy nie. Ta konkretna właściwość służy do implementacji Urządzenia Duffa . Takie zachowanie jest często uważane za wadę w specyfikacji języka C.

Poniżej znajduje się przykład, który pokazuje skutki braku break; :

int a = 1;

switch (a) {
case 1:
case 2:
    puts("a is 1 or 2");
case 3:
    puts("a is 1, 2 or 3");
    break;
default:
    puts("a is neither 1, 2 nor 3");
    break;
}

Gdy wartość a wynosi 1 lub 2, a is 1 or 2 a a is 1, 2 or 3 zostaną wydrukowane oba. Gdy a wynosi 3, wydrukowane zostaną tylko a is 1, 2 or 3 . W przeciwnym razie, a is neither 1, 2 nor 3 zostaną wydrukowane.

Zauważ, że default przypadek nie jest konieczny, szczególnie gdy zestaw wartości otrzymanych w switch jest zakończony i znany w czasie kompilacji.

Najlepszym przykładem jest użycie switch na enum .

enum msg_type { ACK, PING, ERROR };
void f(enum msg_type t)
{
  switch (t) {
  case ACK:
    // do nothing
    break;
  case PING:
    // do something
    break;
  case ERROR:
    // do something else
    break;
  }
}

Istnieje wiele zalet:

  • większość kompilatorów zgłosi ostrzeżenie, jeśli nie obsłużysz wartości (nie zostanie to zgłoszone, jeśli wystąpi przypadek default )
  • z tego samego powodu, jeśli dodasz nową wartość do enum , zostaniesz powiadomiony o wszystkich miejscach, w których zapomniałeś obsługiwać nową wartość (w przypadku default konieczne byłoby ręczne sprawdzenie kodu w poszukiwaniu takich przypadków)
  • Czytelnik nie musi odgadnąć „co jest default: ukryte default: ”, czy istnieją inne wartości enum lub czy jest to ochrona „na wszelki wypadek”. A jeśli istnieją inne wartości enum , to czy koder umyślnie zastosował dla nich default wielkość liter, czy też jest błąd, który został wprowadzony, gdy dodał wartość?
  • obsługa każdej wartości enum sprawia, że kod jest oczywisty, ponieważ nie można ukryć się za dziką kartą, należy jawnie obsłużyć każdą z nich.

Niemniej jednak nie można uniemożliwić komuś napisania złego kodu, takiego jak:

enum msg_type t = (enum msg_type)666; // I'm evil

Dlatego możesz dodać dodatkową kontrolę przed przełącznikiem, aby ją wykryć, jeśli naprawdę jej potrzebujesz.

void f(enum msg_type t)
{
   if (!is_msg_type_valid(t)) {
      // Handle this unlikely error
   }

   switch(t) { 
    // Same code than before
   }
}

if () ... else Ladder Łączenie dwóch lub więcej instrukcji if () ... else

Podczas gdy instrukcja if ()... else pozwala zdefiniować tylko jedno (domyślne) zachowanie, które występuje, gdy warunek w if () nie jest spełniony, łańcuchowanie dwóch lub więcej instrukcji if () ... else pozwala zdefiniować parę więcej zachowań przed pójściem do ostatniej else oddziału działającego jako „default”, jeśli w ogóle.

Przykład:

int a = ... /* initialise to some value. */

if (a >= 1) 
{
    printf("a is greater than or equals 1.\n");
} 
else if (a == 0) //we already know that a is smaller than 1
{
    printf("a equals 0.\n");
}
else /* a is smaller than 1 and not equals 0, hence: */
{ 
    printf("a is negative.\n");
}

Zagnieżdżone if () ... else VS if () .. else Drabina

Zagnieżdżone instrukcje if()...else zajmują więcej czasu (są wolniejsze) w porównaniu do drabiny if()...else ponieważ zagnieżdżone instrukcje if()...else sprawdzają wszystkie wewnętrzne instrukcje warunkowe po zewnętrznej warunkowa instrukcja if() jest spełniona, podczas if()..else drabina if()..else zatrzyma testowanie warunku, gdy dowolna z instrukcji warunkowych if() lub else if() będzie prawdziwa.

Drabina if()...else :

#include <stdio.h>

int main(int argc, char *argv[])
{
  int a, b, c;
  printf("\nEnter Three numbers = ");
  scanf("%d%d%d", &a, &b, &c);
  if ((a < b) && (a < c))
  {
    printf("\na = %d is the smallest.", a);
  }
  else if ((b < a) && (b < c))
  {
    printf("\nb = %d is the smallest.", b);
  }
  else if ((c < a) && (c < b))
  {
    printf("\nc = %d is the smallest.", c);
  }
  else
  {
    printf("\nImprove your coding logic");
  }
  return 0;
}

W ogólnym przypadku jest uważany za lepszy niż równoważny zagnieżdżony, if()...else :

#include <stdio.h>

int main(int argc, char *argv[])
{
  int a, b, c;
  printf("\nEnter Three numbers = ");
  scanf("%d%d%d", &a, &b, &c);
  if (a < b)
  {
    if (a < c)
      {
        printf("\na = %d is the smallest.", a);
      }
    else
      {
        printf("\nc = %d is the smallest.", c);
      }
  }
  else
  {
    if(b < c)
    {
      printf("\nb = %d is the smallest.", b);
    }
    else
    {
      printf("\nc = %d is the smallest.", c);
    }
  }
  return 0;  
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow