Thema indholdsfortegnelse -- Tastaturgenvej: 'u'  Forrige tema i denne lektion -- Tastaturgenvej: 'p'  Næste slide i denne lektion -- Tastaturgenvej: 'n'Kontrolstrukturer
8.  Udvælgelse af kommandoer

Der er kun få programmer som slavisk følger ét enkelt spor uden forgreninger. Med andre ord er der kun få programmer der udelukkende betjener sig af sekventiel og sammensat kontrol, som beskrevet i hhv. afsnit 5.3 og afsnit 7.1.

Langt de fleste programmer skal kunne reagere forskelligt på en række hændelser. Derfor er udvælgelse - også kaldet selektion - af kommandoer et vigtigt emne. Vi studerer udvælgelse i dette kapitel.

8.1 Udvælgelse med if (1)8.4 Udvælgelse med switch
8.2 Udvælgelse med if (2)8.5 If-else kæder
8.3 'Dangling else' problemet8.6 Den betingede operator
 

8.1.  Udvælgelse med if (1)
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

Den mest basale kontrolstruktur til udvælgelse kaldes if-then-else. I den rene form, som i C afspejles af syntaks 8.1, vælges der mellem netop to muligheder. Valget styres af et logisk udtryk, som jo netop har to mulige udfald: true eller false. Som det fremgår af syntaksboken anvender C ikke nøgleordet then, og det er derfor lidt misvisende af tale om if-then-else kontrolstrukturer i C. Vi vil derfor blot tale om if-else strukturer.

En selektiv kontrolstruktur udvælger én kommando til udførelse blandt en mængde af muligheder


if (logicalExpression)
  command1
else
  command2
Syntaks 8.1    En if-else kontrolstruktur.

Bemærk parenteserne omkring logicalExpression, som altid skal være der. Parenteserne er en del af syntaksen for if-else i C. Tilsvarende forhold gør sig gældende for switch (syntaks 8.3), while (syntaks 9.1), og do (syntaks 9.2).

Som et specialtilfælde kan else-delen være tom. I så fald er det ikke nødvendig at skrive nøgleordet 'else'. Vi taler i dette tilfældet om en betinget kommando. Vi siger altså at command er betinget af det logiske udtryk logicalExpression i syntaks 8.2. Command udføres kun hvis værdien af det logiske udtryk er sandt.


if (logicalExpression)
  command
Syntaks 8.2    En betinget kommando.

Herunder viser vi en kontrol flowgraf for en if-then-else kommando, som modsvarer syntaks 8.1. Sådanne grafer er nyttige til illustration er enkelte kontrolstrukturer i isolation, men de bliver dog for det meste uoverskuelige hvis vi forsøger at anvende dem på et helt program.

Figur 8.1    Flow graf for if

 

8.2.  Udvælgelse med if (2)
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

Vi fortsætter vores diskussion af if-else i dette afsnit. Betydningen af syntaks 8.1 kan sammenfattes i følgende punkter:

  • Betydning af if-else:

    • Først beregnes det logiske udtryk

    • Hvis værdien er sand udføres command1

    • Hvis værdien er falsk udføres command2

Det er nu tid til at se på eksempler. I program 8.1 starter vi med et program, der finder og udskriver det største af to indlæste tal x og y. Bemærk hvordan vi i den røde del styrer kontrollen til enten at udføre assignmentet max = y eller max = x, afhængig af udfaldet af sammenligningen mellem x og y.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

int main(void) {

  double x, y, max;

  printf("Enter two real numbers: ");
  scanf("%lf %lf", &x, &y);

  /* find the maximum of x and y */
  if (x < y)
    max = y;
  else
    max = x;

  printf("The maximum of x and y is %12.8f\n", max);
  
  return 0;
}
Program 8.1    Et program som beregner det største af to doubles.

Hernæst følger et andet eksempel, som vi allerede har varmet op i afsnit 5.2, nærmere betegnet i program 5.1. Her er tale om en omskrivning af goto programmet til at bruge en if-else kontrolstruktur.

Sammenlign nøje med program 5.1 og overbevis dig om if-else programmets bedre struktur og større læsbarhed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

int main(void) {

  int i, j, pos, res;
  printf("Enter two integers: ");
  scanf("%d %d", &i, &j);

  if (i <= j){ 
    pos = 2; res = j;}
  else {
    pos = 1; res = i;}

  printf("pos: %d, res: %d\n", pos, res);
  
  return 0;
}
Program 8.2    Goto programmet reformuleret med en if-else kontrolstruktur.

Brug af kontrolstrukturer ala if-else er udtryk for struktureret programmering

Struktureret programmering var en af de store landvindinger inden for faget i 1970'erne.

 

8.3.  'Dangling else' problemet
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

I dette afsnit vil vi beskrive en speciel sammensætning af if og if-else kontrolstrukturer, som foranlediger et tvetydighedsproblem.

Hvis if og if-else kontrolstrukturer indlejres i hinanden kan der opstå tvetydighedsproblemer

Problemet illustreres i eksempel program 8.3 herunder.

I den røde del signalerer indrykningen at else delen hører til den inderste if. I situationen hvor a er 3 og b er 4 bliver der ikke printet noget som helst i den røde del.

På trods af indrykningen i den blå del, er den blå del helt ækvivalent med den røde del. Som opsummeret herunder gælder der, at en else del altid knytter sig til den nærmeste if. Der skrives altså heller ikke noget ud i den blå del.

I den lilla del har vi indlejret if (b==2) print(...) i en blok, som er angivet med brune brackets. Dermed knyttes else delen til den yderste if. I denne situation udskrives et stort F.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>

int main(void) {

  int a = 3, b = 4;

  if (a == 1)
    if (b == 2)
      printf("A\n");
    else 
      printf("B\n"); 

  if (a == 1) 
    if (b == 2)
      printf("C\n");
  else 
    printf("D\n"); 

  if (a == 1){ 
    if (b == 2)
      printf("E\n");} 
  else 
    printf("F\n"); 
  
  return 0;
}
Program 8.3    Illustration af dangling else problemet.

Som beskrevet ovenfor vil program 8.3 blot udskrive et stort F.

En else knytter sig altid til den inderste if.

Det kan anbefales at bruge sammensætning med {...} hvis man er i tvivl om fortolkningen.

 

8.4.  Udvælgelse med switch
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

Switch er en anden kontrolstruktur til udvælgelse. Med switch vælger man mellem et vilkårligt antal muligheder. Valget foregår på basis af en heltallig værdi. Derfor er en switch ikke så kraftfuld som evt. indlejrede if-else konstruktioner. Mere om dette i afsnit 8.5.


switch (expression) {
  case const1: command-list1
  case const2: command-list2
  ...
  default: command-list  
}
Syntaks 8.3    Opbygningen af en switch kontrolstruktur.

Vi beskriver betydningen af switch i de følgende punkter

  • Udtrykket beregnes - skal være et heltal eller heltalsagtigt

  • Hvis værdien svarer til en af konstanterne, flyttes kontrollen til den tilsvarende kommando. De efterfølgende cases udføres.

  • Hvis værdien ikke svarer til en af konstanterne, og hvis der er et default tilfælde, flyttes kontrollen til default kommandoen

  • Hvis værdien ikke svarer til en af konstanterne, og hvis der ikke er et default tilfælde, flyttes kontrollen til afslutningen af switchen

Der er ét væsentlig forhold, som skal bemærkes. Når et af 'casene' i en switch er udført, hopper man ikke automatisk til enden af switch konstruktionen. Derimod fortsætter udførelsen af de efterfølgende cases i switchen. Som regel er dette ikke hvad vi ønsker. Som illustreret i program 8.4 kan man afbryde dette 'gennemfald' med en break i hvert case. Dette er de blå dele i program 8.4.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>

int main(void) {

  int month, numberOfDays, leapYear;

  printf("Enter a month - a number between 1 and 12: ");
  scanf("%d", &month);
  printf("Is it a leap year (1) or not (0): ");
  scanf("%d", &leapYear);

  switch(month){
    case 1: case 3: case 5: case 7: case 8: case 10: case 12: 
      numberOfDays = 31; break;
    case 4: case 6: case 9: case 11: 
      numberOfDays = 30; break;
    case 2:
      if (leapYear) numberOfDays = 29; 
      else numberOfDays = 28; break;
    default: exit(-1);  break;
  } 

  printf("There are %d days in month %d\n", numberOfDays, month);

  return 0;
}
Program 8.4    Et program der beregner antal dage i en måned.

Programmet ovenfor finder antallet af dage i en given måned. Hvis måneden er 1, 3, 5, 7, 8, 10 eller 12 er der altid 31 dage. Hvis måneden er 4, 6, 9 eller 11 er der 30 dage. I februar, den 2. måned, er der 28 eller 29 dage afhængig af om året er et skudår eller ej.

Vi har mere at sige om break i afsnit 9.7.

Vi ønsker næsten altid at afslutte et tilfælde i en switch med en break

 

8.5.  If-else kæder
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

Vi kan kun bruge switch til multivejsudvælgelse i det tilfælde at valget kan foretages på baggrund af en simpel, heltallig værdi.

I mange tilfælde er det nødvendigt at foretage en multivejsudvælgelse ud fra evaluering af en række betingelser. Når der er behov for dette kan vi bruge if-else kæder. Bemærk, at if-else kæder laves ved at indlejre en if-else kontrolstruktur i else-delen af en anden if-else struktur.

En if-else kæde er en if-else kontrolstruktur, hvor else-delen igen kan være en if-else struktur

Som et eksempel viser vi et program som omregner procentpoint til en karakter på 13-skalaen. Omregningen svarer til den officielle omregningstabel for skriftligt arbejde inden for naturvidenskab.

Det vil være meget akavet at skulle udtrykke omregningen med en switch. Dette vil nemlig kræve en case for hvert heltal, hvilket naturligvis er helt uacceptabelt. Det er langt mere naturligt at formulere logiske udtryk for de forskellige udfald.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>

int main(void) {

  int percent, grade;

  printf("How many percent? ");
  scanf("%d",&percent);

  if (percent >= 90)
    grade = 11;
  else if (percent >= 82)
    grade = 10;
  else if (percent >= 74)
    grade = 9;
  else if (percent >= 66)
    grade = 8;
  else if (percent >= 58)
    grade = 7;
  else if (percent >= 50)
    grade = 6;
  else if (percent >= 40)
    grade = 5;
  else if (percent >= 10)
    grade = 3;
  else grade = 0; 

  printf("%d percent corresponds to the Danish grade %d\n\n", 
          percent, grade);
  
  return 0;
}
Program 8.5    Et program med en if-else kæde der beregner beregner en karakter ud fra et antal procentpoint.

Vi har i program 8.5 anvendt en speciel indrykning af if-else strukturerne. En mere almindelig indrykning, som understreger måden hvorpå if-else er indlejret i else dele, er vist i program 8.6 herunder. Med denne indrykning havner vi dog hurtigt uden for den højre margin, og af denne årsag foretrækkes den flade indrykning i program 8.5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>

int main(void) {

  int percent, grade;

  printf("How many percent? ");
  scanf("%d",&percent);

  if (percent >= 90)
   grade = 11;
  else if (percent >= 82)
        grade = 10;
       else if (percent >= 74)
             grade = 9;
            else if (percent >= 66)
                  grade = 8;
                 else if (percent >= 58)
                       grade = 7;
                      else if (percent >= 50)
                            grade = 6;
                           else if (percent >= 40)
                                 grade = 5;
                                else if (percent >= 10)
                                      grade = 3;
                                     else grade = 0; 

  printf("%d percent corresponds to the Danish grade %d\n\n", 
          percent, grade);
  
  return 0;
}
Program 8.6    Alternativt og uønsket layout af if-else kæde.

Læs mere om indrykning og 'style' i afsnit 3.20 side 106-108 i C by Dissection.

En if-else kæde kan generelt ikke programmeres med en switch kontrolstruktur

 

8.6.  Den betingede operator
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

If-else og switch er kontrolstrukturer, som styrer udførelsen af kommandoer. I mange engelske bøger bruges betegnelsen statements for kommandoer. I dette afsnit vender vi tilbage til udtryk, som vi studerede allerede i afsnit 2.1. Helt konkret ser vi på en if-then-else konstruktion som har status af et udtryk i C.

I C findes en betinget operator med med tre operander som modsvarer en if-else kontrol struktur.

En forekomst af en betinget operator er et udtryk, hvorimod en forekomst af if-else er en kommando.

Syntaksen af operatoren, som kaldes ?:, er vist herunder. Ligesom if-else har den tre bestanddele, nemlig et logisk udtryk og to andre betanddele, som her begge er vilkårlige udtryk. Begge disse udtryk skal dog være af samme type.


logicalExpression ? expression1 : expression2
Syntaks 8.4    Opbygningen af den betingede operator i C.

Bemærk at den betingede operator tager tre operander i modsætning til de fleste andre operatorer, som enten er unære eller binære.

Her giver vi betydningen af ?: operatoren relativ til syntaks 8.4.

  • Først beregnes logicalExpresssion

  • Hvis værdien er sand beregnes expression1 ellers expression2, hvorefter den pågældende værdi returneres af ?: operatoren

Vi viser herunder et eksempel på brug af den betingede operator. Givet et indlæst heltal i variablen x bestemmer det røde udtryk fortegnet af x. Det er enten strengen "negativ", "neutral", eller "positiv".

Ifølge tabel 2.3 associerer den betingede operator fra højre mod venstre. (Du finder den på prioritetsniveau 3 i tabellen). Det betyder at strukturen i udtrykket er følgende:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main(void) {

  int x;

  printf("Enter an integer: ");
  scanf("%d", &x);

  printf("The sign of %d is %s\n\n", 
         x,
         x < 0 ? "negative" : x == 0 ? "neutral" : "positive");
  
  return 0;
}
Program 8.7    Et program der bestemmer fortegnet af et tal.

Bemærk at det ikke ville have været muligt at have en if-else konstruktion inden i kaldet af printf. Kun udtryk kan optræde som parametre til funktioner. Og den røde del af program 8.7 er netop et udtryk.

Hermed slutter vores behandling af kontrolstrukturer og udtryk til udvælgelse. I næste afsnit ser vi på gentagelse.

Genereret: Onsdag 7. Juli 2010, 15:10:24
Thema indholdsfortegnelse -- Tastaturgenvej: 'u'  Forrige tema i denne lektion -- Tastaturgenvej: 'p'  Næste slide i denne lektion -- Tastaturgenvej: 'n'