Kapitel 3
Kontrolstrukturer

Kurt Nørmark
Institut for Datalogi, Aalborg Universitet


Sammendrag
Forrige lektion Næste lektion
Stikord Referencer Indhold
I denne lektion gennemgår vi forskellige former for konstrolstrukturer, i hovedsagen forskellige former for selektion og iteration. Som en vigtig og relevant detalje, ser vi også på logiske udtryk, som styrer de fleste kontrolstrukturer.


Kontrolstrukturer - Motivation og oversigt

Oversigt over basale kommandoer
Slide Indhold Stikord
Referencer 

Vi starter med en oversigt over de kommandoer vi har mødt indtil nu

  • Assignment

    • Udtryk med en assignment operator efterfulgt af semicolon

  • Printf og scanf kommandoerne

    • Disse bruges typisk som funktionskald efterfulgt af semicolon

  • Den tomme kommando

    • Blot et semicolon

Henvisning

Motivation: Primitiv kontrol med hop
Slide Indhold Stikord
Referencer 

Programmering med goto - før indførelsen af struktureret programmering

Program: Et uddrag af et C program med gotos.
  if (i <= j) goto p1;
  res = i;
  goto p2;
  p1: res = j;

  p2: printf("res: %d\n", res);

Program: Et helt C program med to goto kommandoer.
#include <stdio.h>

int main(void) {

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

  if (i <= j) goto p1;
  res = i;
  goto p2;
  p1: res = j;

  p2: printf("res: %d\n", res);
  
  return 0;
}

Program: Goto programmet reformuleret med en if-else kontrolstruktur.
#include <stdio.h>

int main(void) {

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

  if (i <= j)
    res = j;
  else 
    res = i;

  printf("res: %d\n", res);
  
  return 0;
}

Programmer med goto kommandoer kan være meget vanskelige af forstå.

Goto kommandoer er kun acceptable i undtagelsessituationer, eksempelvis for at komme ud af en 'dyb løkke'.

Oversigt over konstrolstrukturer
Slide Indhold Stikord
Referencer 

Begrebet kontrolstruktur: En kontrolstruktur styrer og kontrollerer rækkefølgen af udførelsen af et antal kommandoer

  • Udvælgelse

    • Én kommando udvælges blandt flere mulige.

    • Udvælgelsen foretages typisk ud fra værdien af et logisk udtryk.

    • if (logiskUdtryk) kommando1; else kommando2;

  • Gentagelse

    • En kommando gentages et antal gange.

    • Antallet af gentagelser styres typisk af et logisk udtryk

    • while (logiskUdtryk) kommando;

  • Sekventiel kontrol

    • Kommandoer følger efter hinanden i den angivne rækkefølge

    • kommando1; kommando2;

  • Sammensætning

    • En antal kommandoer sammensættes til én enkelt kommando

    • {kommando1; kommando2;}


Logiske udtryk

Logiske udtryk
Slide Indhold Stikord
Referencer 

Begrebet logisk udtryk: Et logisk udtryk beregnes til en værdi i datatypen boolean.
Begrebet boolean: Datatypen boolean indeholder værdierne true og false.

Program: Et uddrag af et C program med logiske udtryk.
  int n = 6, result;
  
  n == 5
  n >= 5
  n != 5
  n >= 5 && n < 10
  result = n >= 5 && n < 10
  !(n >= 5 && n < 10)
  n < 5 || n >= 10

Henvisning

Program: De boolske udtryk vist i realistiske sammenhænge i et C program.
#include <stdio.h>

int main(void) {

  int n = 6, b, result;

  printf("%d\n", n == 5);

  if (n >= 5) printf("stor\n"); else printf("lille\n");

  b = n != 5; printf("%d\n", b);

  while (n >= 5 && n < 10) n++;
  printf("%d\n", n);

  /* n is 10: */
  result = (n >= 5 && n < 10);             /* LOGISK ASSIGNMENT */
  printf("the result is %d\n %d", result, n);

  if ( !(n >= 5 && n < 10) == (n < 5 || n >= 10))
    printf("OK\n"); 
  else printf("Problems\n");
  
  return 0;
}

Program: Misforståede logiske udtryk.
  int a = 7, b = 8, c = 6;
  
  /* Both a and b are greater than c */
  a && b > c;        /* WRONG. */

  a > c && b > c;    /* Correct */



  /* The value of a is in between c and b */
  c <= a <= b;       /* WRONG. */

  c <= a && a <= b;  /* Correct */
  
  return 0;
}

I C repræsenteres false af en nulværdi, og true af en vilkårlig ikke-nulværdi

Opgave 3.2. Inden i eller uden for en cirkel

Det er ofte nyttigt at kunne afgøre, om et punkt i et koordinatsystem er placeret inden i eller udenfor en bestemt cirkel.

Skriv et program med tre doubles r, x og y. r fortolkes som radius af en cirkel omkring punktet (0,0). x og y er koordinaterne (x, y) af et punkt.

Programmet skal afgøre om punktet ( x, y) er placeret inden i cirklen med radius r og centrum i (0,0).

Sandhedstabeller
Slide Indhold Stikord
Referencer 

Tabel. Sandhedstabel for not operatoren
A!A
truefalse
falsetrue
 

Tabel. Sandhedstabel for and operatoren
ABA && BA || B
truetruetruetrue
truefalsefalsetrue
falsetruefalsetrue
false falsefalsefalse
 

Tabel. Sandhedstabel for or operatoren
AB!(A && B)!A || !B
truetruefalsefalse
truefalsetruetrue
falsetruetruetrue
false falsetruetrue
 

Henvisninger

Prioriteter af logiske operatorer
Slide Indhold Stikord
Referencer 

Tabel.
NiveauOperatorerAssociativitet
15()      []      ->      .      ++postfix      --postfix left to right
14++prefix      --prefix      !      ~      sizeof(type)      +unary      -unary      &      * right to left
13*      /      %left to right
12+      -left to right
11<<      >>left to right
10<      <=      >      >=left to right
9==      !=left to right
8&left to right
7^left to right
6|left to right
5&&left to right
4||left to right
3?:right to left
2=      +=      -=      *=      /=      >>=      <<=      &=      ^=      |=right to left
1, left to right
 

Short Circuit evaluering
Slide Indhold Stikord
Referencer 

Direkte oversat 'kortsluttet beregning'

Begrebet short circuit evaluering: Short circuit evaluering betegner en beregning hvor visse operander ikke evalueres, idet deres værdi er uden betydning for resultatet

  • x && y

    • y beregnes kun hvis x er true

  • x || y

    • y beregnes kun hvis x er false

Henvisning

Short Circuit evaluering: eksempler
Slide Indhold Stikord
Referencer 

Vi viser eksempler på C programmer med short circuit evaluering

Program: Short circuit beregning i kombination med assignments.
#include <stdio.h>

int main(void) {

  int i = 0, j = 0;

  (i = 1) && (j = 2);
  printf("%d %d\n", i, j);

  (i = 0) && (j = 3);
  printf("%d %d\n", i, j);

  i = 0 || (j = 4);     
  printf("%d %d\n", i, j); 

  (i = 2) || (j = 5);
  printf("%d %d\n", i, j);

  return 0;
}

Program: Et ækvivalent program.
#include <stdio.h>

int main(void) {

  int i = 0, j = 0;

  (i = 1) && (j = 2);
  printf("%d %d\n", i, j);

  (i = 0);
  printf("%d %d\n", i, j);

  i = 0 || (j = 4);     
  printf("%d %d\n", i, j); 

  (i = 2);
  printf("%d %d\n", i, j);

  return 0;
}

Program: Output fra ovenstående programmer.
1 2
0 2
1 4
2 4

Program: Short circuit beregning som beskyttelse mod fejlberegning.
#include <math.h>
#include <stdio.h>

double sqrt(double);

int main(void) {

  double x;

  printf("Enter a number: ");
  scanf("%lf", &x);

  if (x >= 0 && sqrt(x) <= 10)
    printf("x is positive, but less than or equal to 100.0\n");
  else printf("x is negative or greater than 100.0\n");

  return 0;
}

De øverste programmer er kunstige og konstruerede

Mønstret i det nederste program forekommer ofte i rigtige programmer

Opgave 3.3. Operator prioriteter i logiske udtryk

Denne opgaver giver dig træning i at anvende operator prioritering i logiske udtryk. Det er ikke nødvendigt at beregne værdierne af udtrykkene. Lad blot computeren foretage de faktiske beregninger.

Se på følgende C program:

#include <stdio.h>

int main(void){

  int a = 1, b = 2, c = 3;
  double x = 1.0;

  int res1, res2, res3, res4;

  res1 = a > b && c < x;
  res2 = a < ! b || ! ! a;
  res3 = a + b < ! c + c;
  res4 = a - x || b * c && b / a;

  printf("res1 = %d, res2 = %d, res3 = %d,  res4 = %d \n", 
	 res1, res2, res3, res4);

}

Sæt parenteres i de fire sammensatte, logiske udtryk, hvis værdier assignes til variablene res1, ..., res4. Ved at sætte parenteser bliver det klart, hvorledes de sammensatte udtryk beregnes. Vær sikker på at du anvender operator prioriteringerne i C, for at sætte parenteserne korrekt.

Check at overstående program, og dit modificerede program, er ækvivalente (giver det samme output når værdierne af res1, ..., res4 udskrives).


Sammensætning af kommandoer

Sammensætning
Slide Indhold Stikord
Referencer 

Begrebet blok: En sammensat kommando, også kaldet en blok, er en gruppering af kommandoer til én kommando, hvori der i starten kan forekomme erklæringer af variable

Syntax: En blok

{declaration-or-command-list}

Blokke er ofte nødvendige i forbindelse med udvælgende og gentagende kontrolstrukturer i C.

Blokke kan indlejres i hinanden.

Program: Tre indlejrede blokke med lokale erklæringer af heltal.
#include <stdio.h>

int main(void) {  

  int a = 5, b = 7, c;

  c = a + b;

  { 
    int a = 15, b = 17, c;

    {
      int a = 25, b = 27, c;
      c = a + b;  
      printf("Inner: c er %d\n", c);
    }

    c = a + b;  
    printf("Middle: c er %d\n", c);
  }   

  c = a + b;  
  printf("Outer: c er %d\n", c);
  
  return 0;
}   

Program: Program output.
Inner: c er 52
Middle: c er 32
Outer: c er 12

Henvisning


Udvælgelse af kommandoer

Udvælgelse med if (1)
Slide Indhold Stikord
Referencer 

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

Syntax: En if-else kontrolstruktur.

if (logicalExpression)
  command1
else
  command2

Figur. Flow graf for if

Udvælgelse med if (2)
Slide Indhold Stikord
Referencer 

Else delen kan udelades, hvilket svarer til at command2 er tom på forrige side

Betinget udførelse af kommendo

Syntax: En if kontrolstruktur uden else

if (logicalExpression)
  command1

Figur. Flow graf for if uden else

Udvælgelse med if (3)
Slide Indhold Stikord
Referencer 

  • 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

Program: Et program som beregner det største af to doubles.
#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: En variant med blokke.
#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: Endnu en variant med blokke.
#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;
}

Henvisning

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

'Sekvens af if' kontra if-else
Slide Indhold Stikord
Referencer 

Det frarådes generelt at udtrykke en if-else med to if statements i sekvens

Program: Sekvenser af if kontra if-else.
#include <stdio.h>

int main(void) {

  int i = 7, j = 7;

  if (i < j) 
    printf("(1) i is less than j");
  else
    printf("(2) i is greater than or equal to j\n"); 

  if (i < j)  
    printf("(3) i is less than j\n");
  if (i >= j)
    printf("(4) i is greater than or equal to j\n");  

  if (i <= j)   
    printf("(5) i is less than j\n");
  if (i >= j)
    printf("(6) i is greater than or equal to j\n");   

  if (i < j)   
    printf("(7) i is less than j\n");
  if (i > j)
    printf("(8) i is greater than or equal to j\n");    
  
  return 0;
}

Program: Sekvenser af if kontra if-else med markering af de forgreninger der udføres.
#include <stdio.h>

int main(void) {

  int i = 7, j = 7;

  if (i < j) 
    printf("(1) i is less than j");
  else
    printf("(2) i is greater than or equal to j\n"); 

  if (i < j)  
    printf("(3) i is less than j\n");
  if (i >= j)
    printf("(4) i is greater than or equal to j\n");  

  if (i <= j)   
    printf("(5) i is less than j\n");
  if (i >= j)
    printf("(6) i is greater than or equal to j\n");   

  if (i < j)   
    printf("(7) i is less than j\n");
  if (i > j)
    printf("(8) i is greater than or equal to j\n");    
  
  return 0;
}

Program: Sekvenser af if kontra if-else - med forklarende kommentarer.
#include <stdio.h>

int main(void) {

  int i = 7, j = 7;

  /* We know that exactly one of the printf statements will be executed */
  /* The best alternative for this example                              */
  if (i < j) 
    printf("(1) i is less than j");
  else
    printf("(2) i is greater than or equal to j\n"); 

  /* Both logical expressions must be studied and evaluated to find out */
  /* which printf statements will be executed                           */
  if (i < j)  
    printf("(3) i is less than j\n");
  if (i >= j)
    printf("(4) i is greater than or equal to j\n");  

  /* For some i and j both printf statements will be executed           */
  /* Most likely, this is an error                                      */
  if (i <= j)   
    printf("(5) i is less than j\n");
  if (i >= j)
    printf("(6) i is greater than or equal to j\n");   

  /* For some i and j none of the printf statements will be execute     */
  /* Most likely, this is also an error                                 */
  if (i < j)   
    printf("(7) i is less than j\n");
  if (i > j)
    printf("(8) i is greater than or equal to j\n");    
  
  return 0;
}

Program: Program output.
(2) i is greater than or equal to j
(4) i is greater than or equal to j
(5) i is less than j
(6) i is greater than or equal to j

I en if-else ved vi at netop en af grenene udføres

En if-else er generelt mere effektiv end to if statements i sekvens

'Dangling else' problemet
Slide Indhold Stikord
Referencer 

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

Program: Illustration af dangling else problemet.
#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: Output fra ovenstående program.
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.

Udvælgelse med switch (1)
Slide Indhold Stikord
Referencer 

Syntax: Opbygningen af en switch kontrolstruktur.

switch (expression) {
  case const1: command-list1
  case const2: command-list2
  ...
  default: command-list  
}

  • Betydning:

    • 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

  • Begrænsning:

    • En bestemt case må højst optræde én gang i en switch

Udvælgelse med switch (2)
Slide Indhold Stikord
Referencer 

Programeksempler med switch

Program: Et program der udskriver en ECTS karakter fra en dansk 7-trins karakter.
#include <stdio.h>

int main(void) {
  int grade7;
  
  /* Prompt for input */
  printf("Enter Danish 7 step grade: ");
  scanf("%d", &grade7);

  /* Find and print the corresponding ECTS grade */
  printf("The corresponding ECTS grade is: ");
  switch(grade7){
    case 12: 
      printf("A"); break;
    case 10: 
      printf("B"); break;
    case 7: 
      printf("C"); break;
    case 4: 
      printf("D"); break;
    case 2: 
      printf("E"); break;
    case 0: 
      printf("Fx"); break;
    case -3: 
      printf("F"); break;
    default: 
      printf("Illegal");
  }
  printf("\n");
  
  return 0;
}

Program: Et program konverterer en 13 skala karakter til 7-trin skalaen.
#include <stdio.h>

int main(void) {
  int grade7, grade13, legal13;
  
  /* Prompt for input */
  printf("Enter Danish 13 scale grade: ");
  scanf("%d", &grade13);

  /* Find the corresponding 7 step grade */
  legal13 = 1;
  switch(grade13){
    case 13: case 11: 
      grade7 = 12; break;
    case 10: 
      grade7 = 10; break;
    case 9: case 8: 
      grade7 = 7; break;
    case 7: 
      grade7 = 4; break;
    case 6: 
      grade7 = 2; break;
    case 5: case 3: 
      grade7 = 0; break;
    case 0: 
      grade7 = -3; break;
    default: 
      legal13 = 0;
  }

  /* Print the result */
  if (legal13)
    printf("The 13 scale grade %d corresponds "  
           "to the 7 step grade %d\n",
           grade13, grade7);
  else
    printf("The 13 scale grade %d is illegal\n");

  
  return 0;
}

Program: Et program der beregner antal dage i en måned.
#include <stdio.h>
#include <stdlib.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);  /* Stop the program */
  } 

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

  return 0;
}

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

If-else kæder
Slide Indhold Stikord
Referencer 

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

Program: Et program med en if-else kæde der løser en andengradsligning.
#include <stdio.h>
#include <math.h>

int main(void) {
  
  double a, b, c, discriminant;

  printf("Enter coeficients a, b, and c: ");
  scanf("%lf %lf %lf", &a, &b, &c);

  discriminant = b * b - 4 * a * c;

  if (discriminant < 0)
    printf("No roots\n");
  else if (discriminant == 0)
    printf("One root: %f\n", -b/(2*a));
  else 
    printf("Two roots: %f and %f\n",
           (-b + sqrt(discriminant))/(2*a), 
           (-b - sqrt(discriminant))/(2*a) );  
}

Henvisning

Program: Et program med en if-else kæde der beregner beregner en 13-skala karakter ud fra et antal procentpoint.
#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: Alternativt og uønsket layout af if-else kæde.
#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;
}

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

Opgave 3.4. pH værdier

I denne opgave antages det, at du lige har løst self-check opgave 3 side 236 i lærebogen Problem Solving and Program Design in C, seventh edition.

Sammenlign din løsning med følgende if-else kæde (som bogen kalder en multiple-alternative if):

  if (ph <= 2)
     printf("Very acidic");  
  else if (ph < 7) 
     printf("Acidic");       
  else if (ph == 7)
     printf("Neutral");      
  else if (ph < 12)
     printf("Alkaline");     
  else 
     printf("Very alkaline");

Er ovenstående if-else kæde ækvivalent med din løsning på bogens opgave? Som en hjælp til afgørelsen, skriv en kommentar efter hvert printf kald som viser, for hvilke pH værdier udskriften er gældende.

Observationer om if-else kæder
Slide Indhold Stikord
Referencer 

  • En if-else kæde i forhold til switch:

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

    • En switch kan altid programmeres med en if-else kæde, men if-else kæden vil som regel være mindre effektiv

  • Rækkefølge af tilfældene i en if-else kæde:

    • De mest specielle tilfælde kommer før de mere generelle tilfælde

  • Viden som oparbejdes i en if-else kæde:

    • I en given udvalgt kommando vides at det tilhørende udtryk er beregnet til true, og at alle foregående udtryk er beregnede til false

Betingede udtryk
Slide Indhold Stikord
Referencer 

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, hvor imod en forekomst af if-else er en kommando.

Syntax: Opbygningen af den betingede operator i C.

logicalExpression ? expression1 : expression2

  • Betydning af et betinget udtryk:

    • Først beregnes logicalExpresssion

    • Hvis værdien er sand beregnes expression1 ellers beregnes expression2, hvorefter den udregnede værdi returneres

Program: Et program der bestemmer fortegnet af et tal.
#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: Et ækvivalet program - med parenteser i udtrykket.
#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;
}

Henvisninger

Opgave 3.5. Timer, minutter og sekunder - Igen

Denne opgave er en fortsættelse af en tidligere opgave, hvor vi konverterede hele sekunder til timer, minutter og sekunder efter sædvanlige principper.

Det er sjusket og utilfredsstillende når det oprindelige program giver følgende output:

  • 75 sekunder svarer til 0 timer, 1 minutter og 15 sekunder
  • 3700 sekunder svarer til 1 timer, 1 minutter og 40 sekunder
  • 55 sekunder svarer til 0 timer, 0 minutter og 55 sekunder
  • 3661 sekunder svarer til 1 timer, 1 minutter og 1 sekunder

Vi ønsker at blive fri for '0 timer' og '0 minutter'. Endvidere ønsker vi korrekt angivelse af ental og flertal. Derfor foretrækker vi et program der giver følgende output:

  • 75 sekunder svarer til 1 minut og 15 sekunder
  • 3700 sekunder svarer til 1 time, 1 minut og 40 sekunder
  • 55 sekunder svarer til 55 sekunder
  • 3661 sekunder svarer til 1 time, 1 minut og 1 sekund

Skriv en ny version af programmet, som opfylder disse krav.

Overvej ombyggelig brugen af if-else kæder kontra sekvenser af if kontra betingede udtryk med brug af den ternære operator ?:


Gentagelse af kommandoer

Gentagelse med while (1)
Slide Indhold Stikord
Referencer 

I en løkke er det muligt at gentage en kommando nul, én eller flere gange.

I en while løkke er det ubestemt hvor mange gange kommandoen udføres.

Syntax: Syntaksen af en while løkke i C.

while (logicalExpression)
  command

Figur. Flow graf for en while løkke

Henvisning

Gentagelse med while (2)
Slide Indhold Stikord
Referencer 

  • Betydningen af while:

    • Det logiske udtryk beregnes

    • Hvis værdien er true udføres kommandoen, og while løkken startes forfra

    • Hvis værdien er false afsluttes while løkken

Program: Euclids algoritme - største fælles divisor - programmeret med en while løkke.
/* General condition loop - Euclid again*/

#include <stdio.h>

int main(void) {
  int i, j, small, large, remainder;
 
  printf("Enter two positive integers: ");
  scanf("%d %d", &i, &j);

  small = i <= j ? i : j;
  large = i <= j ? j : i;
  
  while (small > 0){
    remainder = large % small;
    large = small;
    small = remainder;
  }

  printf("GCD of %d and %d is %d\n\n", i, j, large);
  
  return 0;
}

Program: En udgave af Euclids algoritme som udskriver den beregnede talrække.
#include <stdio.h>

int main(void) {
  int i, j, small, large, remainder;
 
  printf("Enter two positive integers: ");
  scanf("%d %d", &i, &j);

  small = i <= j ? i : j;
  large = i <= j ? j : i;

  printf("%d %d ", large, small);
  
  while (small > 0){
    remainder = large % small;
    large = small;
    small = remainder;
    printf("%d ", small);
  }

  printf("\n\nGCD of %d and %d is %d\n\n", i, j, large);
  
  return 0;
}

Henvisning

Opgave 3.8. Forklaring af et program med while løkke og udtryk med assignments

Forklar hvad der udskrives af følgende program. Hvor mange gange udføres kroppen af while-løkken? Forudsig først resultatet, og kør dernæst programmet.

#include <stdio.h>
int main(void){
   int i = 0, power = 1;

   while (++i <= 10)
      printf("%5d", power *= 2);
   printf("\n");

   return 0;
}

Vær sikker på at du forstår værdierne af de to udtryk ++i og power *= 2.

Hvad sker der hvis ++i erstattes af i++?

Det viste program er skrevet i typisk, koncis C-stil, og er på denne måde en typisk repræsentant for den programmeringsstil, som dyrkes af mange C programmører.

Omskriv programmet (stadig med brug af en while-økke) således at assignments (ala *=) og increments (++) kun har en effekt på variable, men uden direkte at anvende disse i udtryk, som det er gjort i ovenstående program.

Det er også interessant at omskrive programmet, så det bruger en for-løkke i stedet for en while-løkke. Prøv dette!

Vurder selv hvilken udgave af programmet du foretrækker.

Opgave 3.8. Sum af tal i interval som er dividerbare med samme tal

I denne opgave gives tre heltal m, n og k, hvor k er større end 1. Skriv en funktion der adderer alle heltal mellem m og n (inklusive) hvor i k går op.

Eksempler:

  • Hvis m er 5, n er 10 og k er 3 er resultatet 6 + 9 = 15.
  • Hvis m er 5, n er 10 og k er 5 er resultatet 5 + 10 = 15.
  • Hvis m er 10, n er 5 og k er 3 ønsker vi at resultatet er 0, idet m er større end n.

Denne opgave stammer fra bogen C by Dissection - anvendt med tilladelse fra forlaget.

Opgave 3.8. Endnu en sum af tal i et interval

Skriv et program som læser et heltal n. Programmet skal addere alle tal i intervallet fra n til 2 * n hvis n er ikke negativ. Hvis n er negativ, skal programmet addere tallene fra 2 * n til n.

Skriv først en version med for-løkker. Dernæst en version med while løkker.

Denne opgave stammer fra bogen C by Dissection - anvendt med tilladelse fra forlaget.

Gentagelse med do (1)
Slide Indhold Stikord
Referencer 

En do-løkke sikrer altid mindst ét gennemløb af løkken

Syntax: Syntaksen af en do-løkke i C

do
  command
while (logicalExpression)

Figur. Flow graf for en do løkke

Gentagelse med do (2)
Slide Indhold Stikord
Referencer 

  • Betydningen af do:

    • Kommandoen udføres

    • Det logiske udtryk beregnes

    • Hvis værdien er true overføres kontrollen til starten af do

    • Hvis værdien er false afsluttes do løkken

Program: Et program som ønsker et 'yes/no' svar.
#include <stdio.h>

int main(void) {

  char answer;

  do {
    printf("Answer yes or no (y/n): ");
    scanf(" %c", &answer);
  } while (answer != 'y' && answer != 'n');

  printf("The answer is %s\n\n", 
          answer == 'y'? "yes" : "no");
  
  return 0;
}

Gentagelse med for (1)
Slide Indhold Stikord
Referencer 

I mange sprog benyttes for kontrolstrukturen hvis man på forhånd kender antallet af gentagelser

I C benyttes for også ofte mere generelt

Syntax: Opbygningen af en for-løkke i C.

for(initExpression; continueExpression; updateExpression)
  command

Program: En typisk for-løkke med et forudbestemt antal gentagelser.
#include <stdio.h>

int main(void) {

  int upper, lower, k;

  printf("Enter two integers, lower and upper: ");
  scanf("%d %d", &lower, &upper);

  for (k = lower; k <= upper; k++)
    printf("k = %d\n", k);
  
  return 0;
}

  • Betydning af en for-løkke:

    • Trin 1: initExpression beregnes af hensyn til sideeffekter

    • Trin 2: continueExpression beregnes og hvis den er false (0) er for løkken færdig

    • Trin 3: for løkkens command udføres

    • Trin 4: updateExpression beregnes af hensyn til sideeffekter, og der fortsættes med trin 2

Gentagelse med for (2)
Slide Indhold Stikord
Referencer 

Det er muligt at styre en kompleks gentagelse som anvender flere kontrolvariable ved brug af en for løkke

Program: En for løkke med to kontrol variable.
#include <stdio.h>

int main(void) {

  int upper, lower, k, m;

  printf("Enter two integers, lower and upper: ");
  scanf("%d %d", &lower, &upper);

  for (k = lower, m = upper; k <= upper; k++, m--)
    printf("k = %3d, m = %3d, k + m = %3d\n", k, m, k + m);
  
  return 0;
}

Program: Euclids algoritme - største fælles divisor - programmeret med en for-løkke 'uden krop'.
#include <stdio.h>

int main(void) {
  int i, j, sml, lg, rem;
 
  printf("Enter two positive integers: ");
  scanf("%d %d", &i, &j);

  for(sml = i<=j?i:j , lg = i<=j?j:i;
      sml > 0;
      rem = lg % sml , lg = sml, sml = rem);

  printf("GCD of %d and %d is %d\n\n", i, j, lg);
  
  return 0;
}

Alle udtryk kan udelades, hvilket afstedkommer en uendelig løkke

Program: En for løkke, der optæller en variabel uendeligt.
#include <stdio.h>

int main(void) {

  long i = 0;

  for( ; ; ++i)
    printf("%ld: Hi there...\n", i);
  
  return 0;
}

Henvisning

Opgave 3.9. Generering af grafik-filer

I denne opgave vil vi generere grafik filer med flotte mønstre. Vi vil benytte et meget simpelt fil-format, Portable Pixmap (PPM), som du kan læse om i notatet Simple Image File Formats på nettet. Se også Wikipedia artiklen Netpbm format, som giver et godt overblik over formatet.

Her følger et velkommenteret C program, som genererer et 500 x 500 rødt rektangel:

#include <stdio.h>

int main(void) {

  FILE *image_file;                               // The file on which to write the image
  int i, j;

  image_file = fopen("image-file-1.pnm", "wb");   // Open a file for writing.

  fputs("P6\n", image_file);                      // Write the header, including the 
                                                  // so-called magic number P6
  fputs("500 500\n", image_file);                 // Width: 500, Height: 500
  fputs("255\n", image_file);                     // 255 colors per byte.

  for(i = 0; i < 500; i++)              
    for (j = 0; j < 500; j++){
      fputc(255, image_file);                     // Writing the red byte
      fputc(0, image_file);                       // Write the green byte
      fputc(0, image_file);                       // Write the blue byte
    }

  fclose(image_file);                             // Close the file.
  return 0;
}

Her er en variation af programmet, som genererer et lidt mere spændende resultat:

#include <stdlib.h>
#include <stdio.h>

int main(void) {

  FILE *image_file;
  int i, j;
  int r, g, b;

  image_file = fopen("image-file-4.pnm", "wb"); 

  fputs("P6\n", image_file); 
  fputs("500 500\n", image_file);
  fputs("255\n", image_file);

  for(i = 0; i < 500; i++)
    for (j = 0; j < 500; j++){
      r = i % 256; g = j % 256; b = (i+j) % 256;
      fputc(r, image_file);  fputc(g, image_file); fputc(b, image_file);
    }

  fclose(image_file);
  return 0;
}

Begge programmer udskriver, via den ydre for-løkke, RGB bytes (red, green, blue) række for række.

Den kreative udfordringen består i at lave flotte mønstre ved at variere programmerne ovenfor. I denne opgave er det dog en betingelse at de to for-løkker, som kontrollerer hhv. række og søjler i bitmønstret, bibeholdes. Du skal ikke forsøge at lave et stort array af RGB værdier, og ændre i dette. Senere i kurset vil vi udvikle varianter af programmet, som gør det meget mere fleksibelt at tegne forskellige geometriske figurer i en stor tabel (array) af pixels.

Det er naturligvis vigtigt, at du kan se den grafik som genereres af dit program. Her er et antal muligheder, som jeg ved virker:

  • Hvis du åbner en Portable Pixmax fil med Emacs, vises grafikken. Både PPM og PNM extension virker.
  • GIMP (GNU Image Manipulation Program) kan præsentere billederne.
  • Image Magick kan konvertere PPM og PNM filer til andre grafik formater, f.eks. GIF og JPG. I en Windows command prompt skrives: convert fil.pnm fil.jpg, efter at ImageMagick er installeret på din maskine.

Komma operatoren
Slide Indhold Stikord
Referencer 

Komma operatoren anvendes til sekventiel beregning af et udtryk

Værdien af udtrykket E1, E2 svarer til værdien af E2

Udtrykket E1 beregnes kun af hensyn til sideeffekter (gennem assignments)

Komma operatoren har den laveste prioritet - lavere end assignment operatorerne

Henvisning

Program: Eksempler på brug af komma operatoren - gode og dårlige.
#include <stdio.h>
#define MAX 13

int main(void) {
  int v = 0, i = 1, m, n;
 
  /* Three bad examples */
  v = 5, 7;
  printf("v = %d\n", v);

  v = (5, 7);
  printf("v = %d\n", v);

  v = (i++, v + i);
  printf("i = %d, v = %d\n\n", i, v);


  /* One fine example */
  for (m = 1, n = MAX; m <= n; m++, n--)
    printf("m = %d, n = %d\n", m, n);
    
  return 0;
}

Program: Output fra programmet.
v = 5
v = 7
i = 2, v = 9

m = 1, n = 13
m = 2, n = 12
m = 3, n = 11
m = 4, n = 10
m = 5, n = 9
m = 6, n = 8
m = 7, n = 7

for løkker er én af de få steder, hvor komma operatoren bør anvendes i C

Komma tegnet anvendes andre steder i C, hvor kommaet ikke er en operator

Klassificering af gentagelser
Slide Indhold Stikord
Referencer 

Lærebogen klassificerer forskellige anvendelsen af løkker

  • Counter-controlled loop

    • En (heltallig) kontrol variabel tælles op for hvert gennemløb

    • Brug for

  • Sentinel-controlled loop

    • Indlæs data indtil vi møder en særlig "stop værdi" - sentinel

    • Kræver altid mindst ét gennemløb

    • Bogen anviser brug af while

  • Input validation loop

    • Læs input data, og gentag dette indtil input kan accepteres

    • Brug do-while

  • General conditional loop

    • Gentag sålænge en betingelse er opfyldt

    • Brug while

  • Flag controlled loop

    • Betingelsen, der styrer gentagelsen, håndteres gennem en variabel (flag) hvortil der assignes

Eksempler
Slide Indhold Stikord
Referencer 

Vi viser her eksempler på de vigtigste klasser af gentagelser fra forrige slide

Program: Eksempel på counter controlled loop.
/* Counter controlled loop */

#include <stdio.h>
#define MIN 1
#define MAX 20

int main(void) {
  int counter, sum = 0;

  /* Sum of all integers from MIN to MAX */  
  for(counter = MIN; counter <= MAX; counter++){
     sum += counter;
  }

  /* Report the output */
  printf("The sum of integers between %d and %d is %d\n", 
         MIN, MAX, sum);

  return 0;
}

Program: Eksempel på sentinel-controlled loop.
/* Sentinel controlled loop - OK */

#include <stdio.h>
#define SENTINEL -1

int main(void) {
  int sum, number;

  /* Initialization */
  sum = 0;

  /* Get first number */
  printf("Enter number (-1 terminates): ");
  scanf("%d", &number);

  while (number != SENTINEL){
    /* Add number to sum */
    sum += number;
    
    /* Get next number */
    printf("Enter number (-1 terminates): ");
    scanf("%d", &number);
  }

  /* Report the output */
  printf("The sum is %d\n", 
         sum);

  return 0;
}

Program: Eksempel på sentinel-controlled loop - med typisk fejl.
/* Sentinel controlled loop - SEVERAL PROBLEMS */

#include <stdio.h>
#define SENTINEL -1

int main(void) {
  int sum, number;

  /* Initialization */
  sum = 0;

  while (number != SENTINEL){
    /* Get a number */
    printf("Enter number (-1 terminates): ");
    scanf("%d", &number);

    /* Add number to sum */
    sum += number;
  }

  /* Report the output */
  printf("The sum is %d\n", 
         sum);

  return 0;
}

Program: Eksempel på sentinel-controlled loop - med typisk fejl og forklaring.
/* Sentinel controlled loop - SEVERAL PROBLEMS - now explained */

#include <stdio.h>
#define SENTINEL -1

int main(void) {
  int sum, number;

  /* Initialization */
  sum = 0;

  while (number != SENTINEL){          /* number is not initialized! */
    /* Get a number */
    printf("Enter number (-1 terminates): ");
    scanf("%d", &number);

    /* Add number to sum */            /* sentinel is added to sum  */
    sum += number;
  }

  /* Report the output */
  printf("The sum is %d\n", 
         sum);

  return 0;
}

Program: Et forsøg på at lave sentinel controlled loop med do-while - med fejl.
/* Sentinel controlled loop - with do while - BAD */

#include <stdio.h>
#define SENTINEL -1

int main(void) {
  int sum, number;

  /* Initialization */
  sum = 0;

  do{
    /* Get number */
    printf("Enter number (-1 terminates): ");
    scanf("%d", &number);

    /* Add number to sum */
    sum += number;

  } while (number != SENTINEL);

  /* Report the output */
  printf("The sum is %d\n", 
         sum);

  return 0;
}

Program: Et forsøg på at lave sentinel controlled loop med do-while - med fejl og forklaring.
/* Sentinel controlled loop - BAD - explained */

#include <stdio.h>
#define SENTINEL -1

int main(void) {
  int sum, number;

  /* Initialization */
  sum = 0;

  do{
    /* Get number */
    printf("Enter number (-1 terminates): ");
    scanf("%d", &number);

    /* Add number to sum - SENTINEL is added to sum as well! */
    sum += number;

  } while (number != SENTINEL);

  /* Report the output */
  printf("The sum is %d\n", 
         sum);

  return 0;
}

Program: Et forsøg på at lave sentinel controlled loop med do-while - nu OK.
/* Sentinel controlled loop - with do while - now OK, but a little complicated */

#include <stdio.h>
#define SENTINEL -1

int main(void) {
  int sum, number;

  /* Initialization */
  sum = 0;

  do{
    /* Get number */
    printf("Enter number (-1 terminates): ");
    scanf("%d", &number);

    /* Add number to sum */
    if (number != SENTINEL)
        sum += number;

  } while (number != SENTINEL);

  /* Report the output */
  printf("The sum is %d\n", 
         sum);

  return 0;
}

Program: Eksempel på input validation loop.
/* An input validation loop */

#include <stdio.h>

int main(void) {
  int number;

  /* Repeated prompting with input validation */
  do {
    printf("Enter a non-negative integer: ");
    scanf("%d", &number);
  } while (number < 0);

  /* Printing the result */
  printf("Here it is: %d\n", number);
 
  return 0;
}

Program: Eksempel på input validation loop - med særlig håndtering af første prompt.
/* An input validation loop */

#include <stdio.h>

int main(void) {
  int number;

  /* First prompt */
  printf("Enter a non-negative integer: ");
  scanf("%d", &number);

  /* Additional prompts if needed */
  while (number < 0) {
    printf("A *NON-NEGATE NUMBER* - Try again: ");
    scanf("%d", &number);
  }

  /* Printing the result */
  printf("Here it is: %d\n", number);
 
  return 0;
}

Program: Eksempel på general condition loop - Euclids algoritime igen.
/* General condition loop - Euclid again*/

#include <stdio.h>

int main(void) {
  int i, j, small, large, remainder;
 
  printf("Enter two positive integers: ");
  scanf("%d %d", &i, &j);

  small = i <= j ? i : j;
  large = i <= j ? j : i;
  
  while (small > 0){
    remainder = large % small;
    large = small;
    small = remainder;
  }

  printf("GCD of %d and %d is %d\n\n", i, j, large);
  
  return 0;
}

Nestede gentagelser
Slide Indhold Stikord
Referencer 

Når en løkke placeres i kroppen af en anden løkke har vi nestede gentagelser (indlejrede gentagelser)

Program: Et eksempel på indlejrede gentagelser.
#include <stdio.h>
#define MAX 20

int main(void) {
  int i, j, sum;

  for(i = 1; i <= MAX; i++){
    sum = 0;

    for(j = 1; j <= i; j++){
      sum += j;
    }

    printf("Sum of 1 to %d: %d\n", i, sum);
  }
   
  
  return 0;
}

Program: Program output.
Sum of 1 to 1: 1
Sum of 1 to 2: 3
Sum of 1 to 3: 6
Sum of 1 to 4: 10
Sum of 1 to 5: 15
Sum of 1 to 6: 21
Sum of 1 to 7: 28
Sum of 1 to 8: 36
Sum of 1 to 9: 45
Sum of 1 to 10: 55
Sum of 1 to 11: 66
Sum of 1 to 12: 78
Sum of 1 to 13: 91
Sum of 1 to 14: 105
Sum of 1 to 15: 120
Sum of 1 to 16: 136
Sum of 1 to 17: 153
Sum of 1 to 18: 171
Sum of 1 to 19: 190
Sum of 1 to 20: 210

Henvisning

Program: Et andet eksempel på indlejrede gentagelser - et kvadrat af bogstaver fra A - Z.
#include <stdio.h>
#define MAX 26

int main(void) {
  int i, j, ch;

  for(i = 0; i < MAX; i++){
    for(j = 0; j < MAX; j++){
      ch = 'A' + (i + j) % MAX;
      printf("%c", ch);
    }

    printf("\n");
  }
  
  return 0;
}

Program: Program output.
ABCDEFGHIJKLMNOPQRSTUVWXYZ
BCDEFGHIJKLMNOPQRSTUVWXYZA
CDEFGHIJKLMNOPQRSTUVWXYZAB
DEFGHIJKLMNOPQRSTUVWXYZABC
EFGHIJKLMNOPQRSTUVWXYZABCD
FGHIJKLMNOPQRSTUVWXYZABCDE
GHIJKLMNOPQRSTUVWXYZABCDEF
HIJKLMNOPQRSTUVWXYZABCDEFG
IJKLMNOPQRSTUVWXYZABCDEFGH
JKLMNOPQRSTUVWXYZABCDEFGHI
KLMNOPQRSTUVWXYZABCDEFGHIJ
LMNOPQRSTUVWXYZABCDEFGHIJK
MNOPQRSTUVWXYZABCDEFGHIJKL
NOPQRSTUVWXYZABCDEFGHIJKLM
OPQRSTUVWXYZABCDEFGHIJKLMN
PQRSTUVWXYZABCDEFGHIJKLMNO
QRSTUVWXYZABCDEFGHIJKLMNOP
RSTUVWXYZABCDEFGHIJKLMNOPQ
STUVWXYZABCDEFGHIJKLMNOPQR
TUVWXYZABCDEFGHIJKLMNOPQRS
UVWXYZABCDEFGHIJKLMNOPQRST
VWXYZABCDEFGHIJKLMNOPQRSTU
WXYZABCDEFGHIJKLMNOPQRSTUV
XYZABCDEFGHIJKLMNOPQRSTUVW
YZABCDEFGHIJKLMNOPQRSTUVWX
ZABCDEFGHIJKLMNOPQRSTUVWXY

Break, continue og return
Slide Indhold Stikord
Referencer 

Anvendelse af generelle hop - goto - anses for meget dårlig programmeringsstil.

Brug af 'mere specialiserede hop' bruges oftere.

  • break

    • anvendes til at springe ud af (den inderste) switch, while, do, eller for

  • continue

    • anvendes til at afslutte kommandoen i en while, do eller for løkke

  • return

    • anvendes til at afbryde, og returnere et resultat fra en funktion

Program: Illustration af break og continue i en for-løkke.
#include <stdio.h>

int main(void) {

  long i = 1;

  for( ; ; ++i){
    if (i % 2 == 0) continue;
    if (i > 1000) break;
    printf("%ld: Hi there...\n", i);
  }
  
  return 0;
}

Henvisninger

Konvertering af do og for løkker til while
Slide Indhold Stikord
Referencer 

Ethvert program med do og for løkker kan let omskrives til kun at bruge while løkker

Tabel.
OriginalTransformation
for (expr1; expr2; expr3)
  command


expr1;
while (expr2) {
  command;
  expr3;
}
do
  command
while (expr)
command;
while (expr)
  command;
 

Læg mærke til, at der for alle gentagende kontrolstrukturer gælder, at kontrol udtrykket er en fortsættelsesbetingelse.

Med andre ord afbrydes alle former slags løkker i C når kontroludtrykkets værdi bliver false (0).

Den næste afleveringsopgave
Slide Indhold Stikord
Referencer 

En anderledes afleveringsopgave

Lav den en små grupper

Her er opgaven

Dagens Gruppeopgaver
Slide Indhold Stikord
Referencer 

  • En programmeringsopgave

    • Berening af sum fra 1 .. n

  • Endu en programmeringsopgave

    • Fremskrivning af befolkningstal i en by

  • Program forklaringsopgave - 3.5

    • Increment og compound assignment i while løkke

  • En opgave om compound assignments

    • Ikke relateret til løkke - lav den hvis I har behov og lyst

  • Endnu en lille programmeringsopgave på et interval

    • Summation af tal, hvori et andet tal går op

  • Sjov programmeringsopgave (også hjemmeopgave).

    • Lav et bestemt trekantsmønster af tal (side 292 nederst)

  • Programforklaringsopgave

    • Forklare nestede for-løkker


Samlede referencer
Indhold Stikord
Assignment fra lektion 1
Operator prioriteringer i C
Video om kortsluttende operatorer
Operator tabellen i C
Sandhedstabeller
En senere diskussion af 'scope' ud fra dette eksempel
Goto og motivation for kontrolstrukturer
Senere udgave som løser andengradsligningen i en parameterløs funktion
Video om betingede udtryk
Operator prioriterings og associeringstabel
Tilsvarende if
Algoritme kontra program
Datatypen char - og tegntabellen
Siden med den uendelige for-løkke
Siden med goto

 

Kapitel 3: Kontrolstrukturer
Kursets hjemmeside     Forfatteren's hjemmeside     Om frembringelsen af disse sider     Forrige lektion (top)     Næste lektion (top)     Forrige lektion (bund)     Næste lektion (bund)     
Genereret: 11. oktober 2012, 08:57:43