C Language
Oświadczenia wyboru
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 przypadkudefaultkonieczne byłoby ręczne sprawdzenie kodu w poszukiwaniu takich przypadków) - Czytelnik nie musi odgadnąć „co jest
default:ukrytedefault:”, czy istnieją inne wartościenumlub czy jest to ochrona „na wszelki wypadek”. A jeśli istnieją inne wartościenum, to czy koder umyślnie zastosował dla nichdefaultwielkość liter, czy też jest błąd, który został wprowadzony, gdy dodał wartość? - obsługa każdej wartości
enumsprawia, ż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;
}