Kapitel 4
Flere 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.


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

  • Betydningen af while:

    • Værdien af 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

Henvisning

Gentagelse med while (2)
Slide Indhold Stikord
Referencer 

Som et eksempel på brugen af en while løkke ser vi på et program baseret på Euclids algoritme

Program: Euclids algoritme - største fælles divisor - programmeret med en while lø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;
  
  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;
}

Program: Talrækken udskrevet fra programmet med input 315 og 120.



          315       120       75       45       30       15        0 

Program: En mere basal udgave af Euclids algoritme.
#include <stdio.h>

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

  a = i; b = j;
  
  while (a != b)
     if (a > b)
        a = a - b;
     else
        b = b - a;   

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

Program: En mere basal udgave af Euclids algoritme - med C compound assignments.
#include <stdio.h>

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

  a = i; b = j;
  
  while (a != b)
     if (a > b)
        a -= b;
     else
        b -= a;   

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

Program: En mere basal udgave af Euclids algoritme - som printer rækken af tal.
#include <stdio.h>

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

  a = i; b = j;
  
  while (a != b)
     if (a > b){
        a = a - b;
        printf("%d ", a);
     }
     else{
        b = b - a;
        printf("%d ", b);
     }   

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

Henvisning

Opgave 4.4. 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? Og hvilken række af tal udskriver programmet (helt præcist)? 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;
}

++i tæller i en op og power *= 2 fordobler power. Men 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-løkke) således at assignments (ala *=) og increments (++) kun har en effekt på variable, men uden direkte at anvende værdierne af disse 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 4.4. Sum af tal i interval som er dividerbare med samme tal

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

Eksempler:

  • Hvis m er 5, n er 13 og k er 3 er resultatet 6 + 9 + 12 = 27.
  • 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 4.4. 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

  • 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

Gentagelse med do (2)
Slide Indhold Stikord
Referencer 

Et typisk program hvor vi benytter do-while i stedet for while

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 kan for også benyttes 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 4.5. 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). Du kan se på Wikipedia artiklen Netpbm format, som giver et godt overblik over formatet. Der findes også en video der diskuterer formatet, og videoen lægger kort op til denne opgave.

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 - antallet af gennemløb kendes før løkken starter

    • 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 på forskellige former af gentagelser
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 - Add numbers entered by user. Stop when meeting SENTINEL - 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 with do-while */

#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 - with while */

#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-NEGATIVE 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;
}   

Program: Eksempel på flag-controlled loop - Euclids algoritime igen.
/* Euclid again - now as a flag-controlled loop */

#include <stdio.h>

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

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

  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).

Flere Opgaver
Slide Indhold Stikord
Referencer 

Opgave 4.7. En simplificeret udgave af Euclids algoritme

Denne opgaver tager udgangspunkt i følgende udgave af Euclids algoritme, som vi har studeret nøje i denne lektion:

/* 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;
}   

Hvad sker der hvis vi dropper ombytningen af i og j, og således risikerer at small bliver større end large i while-løkken? Her er en sådan version af programmet:

#include <stdio.h>

int main(void) {
  int a, b, i, j, remainder;
 
  printf("Enter two non-negative integers: ");
  scanf("%d %d", &a, &b);

  i = a; j = b;  /* We don't know if i > j */  
  while (j > 0){
    remainder = i % j;
    i = j;
    j = remainder;
  }

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

Virker dette - hvorfor, eller hvorfor ikke?

Opgave 4.7. Ligefrem programmering af 'største fælles divisor'

I denne lektion har vi set at der findes fine, smarte, og effektive algoritmer til at finde den største fælles divisor af to positive heltal. Se her.

Målet med denne opgave er at træne dig i programmering med løkker, herunder at vælge gode iterative kontrolstrukturer til opgaven. Som altid er det også målet at lave et velopstillet program med god indrykning, og med brug af gode variabelnavne.

I denne opgave skal du skrive et ligefrem program, der på en simpel og intuitiv måde finder den største fælles divisor af to ikke-negative heltal a og b. Programmet skal på en systematisk måde - med brug af en løkke - afprøve om forskellig, nøje udvalgte tal er divisorer i både a og b. Overvej omhyggeligt hvordan løkken starter, og hvordan den slutter. Programmet skal finde den største sådanne divisor: altså største fælles divisor. Overvej også om der er nogle specialtilfælde vi skal tage os af, inden vi starter løkken?

Programmet skal indlæse de to heltal a og b af hvilke vi ønsker at finde den største fælles divisor. Men for ikke at starte programmet forfra hver gang vi ønsker at finde den største fælles divisor af to tal (a og b) bedes du lave programmet således at den gentager beregningen af den største fælles divisor af to indlæste tal indtil et af tallene er negativ.


Samlede referencer
Indhold Stikord
Tilsvarende if
Algoritme kontra program
Operator prioriterings og associeringstabel
Operator tabellen i C
Datatypen char - og tegntabellen
Siden med den uendelige for-løkke
Siden med goto

 

Kapitel 4: Flere 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: 9. maj 2022, 13:58:39