Kapitel 5
Funktioner

Kurt Nørmark
Institut for Datalogi, Aalborg Universitet


Sammendrag
Forrige lektion Næste lektion
Stikord Referencer Indhold
I denne lektion gennemgår vi funktions- og procedure begrebet, herunder lokale variable og parametre. Vi ser naturligvis også på detaljer omkring funktioner i C.


Procedurer og funktioner uden parametre

Procedurer og Funktioner
Slide Indhold Stikord
Referencer 

Vi starter med parameterløse procedurer og funktioner

Begrebet abstraktion: En abstraktion indkapsler, navngiver og parametriserer en samling af programdetaljer
Begrebet procedure: En procedure er en abstraktion over en sekvens af kommandoer
Begrebet funktion: En funktion er en abstraktion over et udtryk

  • Procedure

    • En proceduredefinition indkapsler et antal kommandoer

    • Kaldet af en procedure er selv en kommando

  • Funktion

    • En funktionsdefinition indkapsler netop ét udtryk

    • Kaldet af en funktion er selv et udtryk

Program: Illustration of grundlæggende karakteristika af procedurer og funktioner - vist i C.
#include <stdio.h>

void print_sum(int par){
  /* Do something */
  printf("par + par = %d + %d = %d\n", par, par, par+par);
}

/* Encapsulate a command */
double square_and_add(double x, double y){
  /* Calculate and return something */
  return x*x + y*y;
}

/* Encapsulate an expression */
int main(void) {
  int i = 1;
  double a = 0;

  print_sum(5);            /* The call of proc is a command */

  while(i < 5){
    print_sum(i);
    ++i;
  }

  a = square_and_add(3,4);      /* The call of func is an expression */

  if (square_and_add(5,6) < 100)
    printf("Yes\n");
  else
    printf("No\n");
}

Program: Samme program - uden brug af funktioner og procedurer.
#include <stdio.h>

int main(void) {
  int i = 1;
  double a = 0;

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

  while(i < 5){
    printf("par + par = %d + %d = %d\n", i, i, i+i);
    ++i;
  }

  a = 3*3 + 4*4;

  if (5*5 + 6*6 < 100)
    printf("Yes\n");
  else
    printf("No\n");
}

Senere i lektionen vil vi generalisere procedurer og funktioner med brug af parametre

Funktionsdefinition uden parametre i C
Slide Indhold Stikord
Referencer 

C skelner ikke skarpt mellem procedurer og funktioner

I C kaldes begge abstraktionsformer blot for funktioner

Syntax: En funktionsdefinition i C

type function_name(void)
{
  declarations
  commands
}

  • Karakteristika:

    • Procedurer angiver type som void

    • Funktioner angiver type som en ikke-void datatype, f.eks. int, char, eller double

      • Der skal være en return kommando, der returnerer en værdi af den pågældende type

    • I procedurer og funktioner med parametre erstattes void med de formelle parametre

I mange tilfælde er en C funktion en blanding af en procedure og en funktion

Kald af en funktion uden parametre
Slide Indhold Stikord
Referencer 

Syntax: Et funktionskald i C

function_name()

  • En funktion kan ikke kaldes før den er erklæret

Program: Illustration af funktionsdefinition efter funktionskald.
#include <stdio.h>
#include <math.h>

int main(void) {
  solveQuadraticEquation();   
  /* WRONG:  solveQuadraticEquation not yet defined */
  return 0;
}

/* Find the roots a * x*x + b * x + c = 0 */
void solveQuadraticEquation(void){
  /*  ... */
}   

Program: Funktionsdefinition før funktionskald.
#include <stdio.h>
#include <math.h>

/* Find the roots a * x*x + b * x + c = 0 */
void solveQuadraticEquation(void){
  /*  ... */
}   

int main(void) {
  solveQuadraticEquation();   
  /* OK: solveQuadraticEquation now known to the compile */
  return 0;
}

Program: Løsning af 'definition efter kald' med brug af en prototype.
#include <stdio.h>
#include <math.h>

void solveQuadraticEquation(void);  /* This is a PROTOTYPE */

int main(void) {
  solveQuadraticEquation();  
  return 0;
}

/* Find the roots in a * x*x + b * x + c = 0 */
void solveQuadraticEquation(void){
  /*  ... */
}   

Eksempel: Rødder i en andengradsligning
Slide Indhold Stikord
Referencer 

En simpel parameterløs funktion der finder rødderne i andengradsligning

I forlængelse af eksemplet vi studerede allerede i lektion 3

Henvisning

Program: Et program der finder rødder i en andengradsligning - uden funktioner - alt i main.
#include <stdio.h>
#include <math.h>

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

  /* ... */

  /* Solve three equations:   */
  for (i = 1; i <= 3; i++){
    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) );
  }

  /* ... */

  return 0;
}

Program: En funktion der finder rødder i en andengradsligning.
#include <stdio.h>
#include <math.h>

/* Find and print the roots in a * x*x + b * x + c = 0 */
void solveQuadraticEquation(void){
  double a, b, c, discriminant;

  printf("Enter coeficients a, b, and c (a != 0): ");
  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) );
}   

int main(void) {
  int i = 3;

  /* ... */

  /* Solve three equations:   */
  for (i = 1; i <= 3; i++)
    solveQuadraticEquation();  

  /* ... */

  return 0;
}

Henvisning

  • Observationer:

    • Indkapsling af formlen for problemløsningen er bekvem i forhold til gentagen brug.

    • Det er primitivt og ufleksibelt at indlæse koeficienterne med scanf.

    • Det er tilsvarende uheldigt at udskrive røddernes værdier med printf.

I de fleste C funktioner ønsker vi at undgå direkte dialog med brugeren af programmet

Lokale variable
Slide Indhold Stikord
Referencer 

En funktion kan have lokale variable som kun kan benyttes i denne ene funktion

  • Lokale variable opstår når funktionen kaldes, og nedlægges når funktionen returnerer

  • Værdien af en lokal variabel er udefineret med mindre den initialiseres via et assignment

    • En udefineret værdi er den tilfældige værdi, som befinder sig i lageret på variablens sted

Program: Illustration af ulovlig anvendelse af en lokal variabel.
#include <stdio.h>
#include <math.h>

/* Find the roots in a * x*x + b * x + c = 0 */
void solveQuadraticEquation(void){
  double a, b, c, discriminant;

  printf("Enter coeficients a, b, and c:\n");
  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) );
}   

int main(void) {
  solveQuadraticEquation();  
  printf("Diskriminanten var: %f",  discriminant  );  /* WRONG: discriminant does not exist here */
                                                      /* The compiler finds this error           */
  return 0;
}


Top-down programmering ved trinvis forfinelse

Lasagne al forno
Slide Indhold Stikord
Referencer 

  • Bland og ælt 500 g durum hvedemel, 5 æg, lidt salt og 2 spsk olie.

  • Kør pastaen gemmen en pastamaskine i tynde baner.

  • Smelt 3 spsk smør, og rør det sammen med 3 spsk mel.

  • Spæd med med 5 dl mælk og kog sovsen under svag varme.

  • Svits 2 hakkede løg med 500 g hakket oksekød, samt salt og pebber.

  • Tilsæt 3 spsk tomatpuré, en ds. flåede tomater og 3 fed knust hvidløg.

  • Kog kødsovsen i 10 minutter.

  • Bland nu lagvis pastabaner, kødsovs og hvid sovs. Drys med paramesanost.

  • Gratiner retten i ovnen 15 minutter ved 225 grader.

En god lasagne - en ustruktureret opskrift

Struktureret lasagne
Slide Indhold Stikord
Referencer 

I en mere struktureret opskrift indgår delopskrifter på lasagneplader, hvid sovs og kødsovs

Program: Ustruktureret lasagne.
Bland og ælt 500 g durum hvedemel, 5 æg, lidt salt og 2 spsk olie;

Kør pastaen gemmen en pastamaskine i tynde baner;

Smelt 3 spsk smør, og rør det sammen med 3 spsk mel;

Spæd med med 5 dl mælk og kog sovsen under svag varme;

Svits 2 hakkede løg med 500 g hakket oksekød, samt salt og pebber;

Tilsæt 3 spsk tomatpuré, en ds. flåede tomater og 3 fed knust hvidløg;

Kog kødsovsen i 10 minutter;

Bland nu lagvis pastabaner, kødsovs og hvid sovs. Drys med paramesanost;

Gratiner retten i ovnen 15 minutter ved 225 grader;

Program: Struktureret Lasagne.
Lasagne:

  Lav en portion Lasagneplader;

  Lav en portion Hvid sovs;

  Lav en portion Kødsovs;
 
  Bland nu lagvis pastabaner, kødsovs og hvid sovs. Drys med paramesanost;

  Gratiner retten i ovnen 15 minutter ved 225 grader;

Program: Lav en portion lasagneplader.
Lasagneplader:

  Bland og ælt 500 g durum hvedemel, 5 æg, lidt salt og 2 spsk olie;

  Kør pastaen gemmen en pastamaskine i tynde baner;

Program: Lav en portion hvid sovs.
Hvid sovs:

  Smelt 3 spsk smør, og rør det sammen med 3 spsk mel;

  Spæd med 5 dl mælk og kog sovsen under svag varme;

Program: Lav en portion kødsovs.
Kødsovs:

  Svits 2 hakkede løg med 500 g hakket oksekød, 
  samt salt og pebber;

  Tilsæt 3 spsk tomatpuré, en ds. flåede tomater
  og 3 fed knust hvidløg;

  Kog kødsovsen 10 minutter;

Anvendelser af delopskrifter højner abstraktionsniveauet og muliggør genbrug af basale opskrifter.

Delopskrifter svarer til procedurer i programmeringssprog.

Brug af parametre ville generalisere opskriften så den kan anvendes på flere portionsstørrelser.

Lasagne ala C
Slide Indhold Stikord
Referencer 

Vi skriver nu et par versioner af et C program der bager Lasagne

Program: Et pseudo C program som laver lasagne.
#include <stdio.h>
#include <stdlib.h>

void make_lasagne(void);
void make_lasagne_plates(void);
void make_white_sauce(void);
void make_meat_sauce(void);

int main(void) {
  make_lasagne();
  return 0;
}

void make_lasagne(void) {
  make_lasagne_plates();
  make_white_sauce();
  make_meat_sauce();
  
  mix plates, meat sauce, and white sauce;
  sprinkle with paramesan cheese;
  bake 15 minutes at 225 degrees;  
}

void make_lasagne_plates(void) {
  mix flour, egs, salt and oil;
  process the pasta in the pasta machine;
}

void make_white_sauce(void) {
  melt butter and stir in some flour;
  add milk and boil the sauce;
}

void make_meat_sauce(void){
  chop the onion, and add meat, salt and pebber;
  add tomatos and garlic;
  boil the sauce 10 minutes;
}

Program: Et pseudo C program som laver lasagne - funktioner med parametre.
#include <stdio.h>
#include <stdlib.h>

void make_lasagne(int portion);
void make_lasagne_plates(int portion);
void make_white_sauce(int portion);
void make_meat_sauce(int portion);

int main(void) {
  int size;
 
  // Promt for size:
  printf("How large a portion do you want? ");
  scanf("%d", &size);

  // Make some food:
  make_lasagne(size);

  return 0;
}

void make_lasagne(int portion) {
  make_lasagne_plates(portion);
  make_white_sauce(portion);
  make_meat_sauce(portion);
  
  mix plates, meat sauce, and white sauce;

  sprinkle with paramesan cheese;
  bake 15 minutes at 225 degrees;  
}

void make_lasagne_plates(int portion) {
  get appropriate amounts of ingredients according to portion;
  mix flour, egs, salt and oil;
  process the pasta in the pasta machine;
}

void make_white_sauce(int portion) {
  get appropriate amounts of ingredients according to portion;
  melt butter and stir in some flour;
  add milk and boil the sauce;
}

void make_meat_sauce(int portion){
  get appropriate amounts of ingredients according to portion;
  chop the onion, and add meat, salt and pebber;
  add tomatos and garlic;
  boil the sauce 10 minutes;
}

En tændstikpige (1)
Slide Indhold Stikord
Referencer 

Vi ønsker at tegne en tændstikpige ved brug af simpel tegngrafik

Matchgirl - Stickman ...

Program: Det ønskede output - tændstikpigen.
      *          
    *   *        
  *       *      
  *       *      
    *   *        
      *          
-------------    
     /\         
    /  \        
   /    \       
  /      \      
 /        \     
/          \    
-------------    
     /\         
    /  \        
   /    \       
  /      \      
 /        \     
/          \    

Program: Udskrivning af tændstikpige i termer af udskrivning af hoved, arme, krop og ben.
int main(void){
  prn_match_girl();
  return 0;
}

void prn_match_girl(void){
  prn_head();
  prn_arms();
  prn_body();
  prn_legs();
}

Processen udføres top-down.

Programmet forfines trin for trin.

I næste trin må vi definere, hvordan kropsdelene tegnes.

En tændstikpige (2)
Slide Indhold Stikord
Referencer 

Pigens hoved, arme, krop og ben tegnes ved kald af generelle geometriske tegne procedurer

Program: Udskrivning af hoved, arme, krop og ben i termer af generelle geometriske figurer.
void prn_head(void){
  prn_circle();
}

void prn_arms(void){
  prn_horizontal_line();
}

void prn_body(void){
  prn_reverse_v();
  prn_horizontal_line();
}

void prn_legs(void){
  prn_reverse_v();
}

I næste trin må vi definere hvordan vi tegner cirkler, linier og andre geometriske former

En tændstikpige (3)
Slide Indhold Stikord
Referencer 

Cirkler, linier og andre former tegnes ved brug af primitiv tegngrafik

Program: Udskrivning af cirkler, linier og andre geometriske figurer.
/* C file that contains a simple graphical function library */

#include <stdio.h>

void prn_circle(void){
  printf("      *          \n");
  printf("    *   *        \n");
  printf("  *       *      \n");
  printf("  *       *      \n");
  printf("    *   *        \n");
  printf("      *          \n");
}

void prn_horizontal_line(void){
  printf("-------------    \n");
}

void prn_reverse_v(void){
  printf("     /\\         \n");
  printf("    /  \\        \n");
  printf("   /    \\       \n");
  printf("  /      \\      \n");
  printf(" /        \\     \n");
  printf("/          \\    \n");
}

En tændstikpige (4)
Slide Indhold Stikord
Referencer 

Programmet er lavet top-down.

Programmering ved trinvis forfinelse.

Programmet designes og implementeres i et antal niveauer med postulering og efterfølgende realisering af et antal procedurer

Figur. En illustration of problemer og delproblemer i forbindelse med tegning af en tændstikpige

En tændstikpige (5)
Slide Indhold Stikord
Referencer 

Den samlede organisering af C programmet som tegner tændstikpigen

Program: Tændstikpige programmet.
#include "char-graphics.h"

void prn_match_girl(void);
void prn_head(void);
void prn_arms(void);
void prn_body(void);
void prn_legs(void);

int main(void){
  prn_match_girl();
  return 0;
}

void prn_match_girl(void){
  prn_head();
  prn_arms();
  prn_body();
  prn_legs();
}

void prn_head(void){
  prn_circle();
}

void prn_arms(void){
  prn_horizontal_line();
}

void prn_body(void){
  prn_reverse_v();
  prn_horizontal_line();
}

void prn_legs(void){
  prn_reverse_v();
}

Program: Filen char-graphics.h - header fil med prototyper af de grafiske funktioner.
/* Header file of very simple character-based graphical library  */


/* Print a circle */
void prn_circle(void);

/* Print a horizontal line */
void prn_horizontal_line(void);

/* Print a reverse v shape */
void prn_reverse_v(void);

Program: Filen char-graphics.c - implementationen af de grafiske funktioner.
/* C file that contains a simple graphical function library */

#include <stdio.h>

void prn_circle(void){
  printf("      *          \n");
  printf("    *   *        \n");
  printf("  *       *      \n");
  printf("  *       *      \n");
  printf("    *   *        \n");
  printf("      *          \n");
}

void prn_horizontal_line(void){
  printf("-------------    \n");
}

void prn_reverse_v(void){
  printf("     /\\         \n");
  printf("    /  \\        \n");
  printf("   /    \\       \n");
  printf("  /      \\      \n");
  printf(" /        \\     \n");
  printf("/          \\    \n");
}

Program: Oversættelse af programmerne.
* Compilation of the char-graphics.c library:

   gcc -c char-graphics.c

* Compilation of the match-girl.c program:

   gcc match-girl.c char-graphics.o  -o match-girl

Program: Oversættelse af programmerne - med mange warnings.
* Compilation of the char-graphics.c library:

   gcc -ansi -pedantic -Wall -O -c char-graphics.c

* Compilation of the match-girl.c program:

   gcc -ansi -pedantic -Wall -O match-girl.c char-graphics.o  -o match-girl

Program: Makefile - som automatiserer oversættelsen.
match-girl: match-girl.c char-graphics.o char-graphics.h
	gcc match-girl.c char-graphics.o -o match-girl

char-graphics.o: char-graphics.c char-graphics.h
	gcc -c char-graphics.c

Program: Makefile med makroer.
CC = gcc
CFLAGS = -ansi -pedantic -Wall -O

match-girl: match-girl.c char-graphics.o char-graphics.h
	$(CC) $(CFLAGS) match-girl.c char-graphics.o -o match-girl

char-graphics.o: char-graphics.c char-graphics.h
	$(CC) $(CFLAGS) -c char-graphics.c

Henvisning

Funktioner skal erklæres før brug

Genbrugelige funktioner kan organiseres i separat oversatte C filer

Prototyper af sådanne funktioner skrives i såkaldte header files

Del og hersk - del og kombiner
Slide Indhold Stikord
Referencer 

Komplekse problemer opdeles i et antal simplere delproblemer.

Delproblemernes løsninger kombineres til en løsning på det oprindelige problem.

Figur. Opdelning af et kompleks problem i delproblemer

  • Del og hersk som top down programmering ved trinvis forfinelse:

    • Hvert delproblem P løses i en funktion

    • Funktioner, som er løsninger på delproblemer af P, placeres efter funktionen som løser P

      • Kræver erklæring af funktionsprototyper i starten af programmet

      • Funktionsprototyper kan organiseres i header filer

    • I kroppen af funktionen, som løser problemet P, programmeres en kombinering af delproblemernes løsning


C funktioner med input parametre

Formelle og aktuelle parametre
Slide Indhold Stikord
Referencer 

Den primære anvendelse af parametre er at overbringe input til en funktion

Syntax: En funktionsdefinition i C

type function_name (formal_parameters){
  declarations
  commands
}

  • De formelle parametre er navne som optræder i funktionsdefinitionen, i parentes efter funktionsnavnet

  • De aktuel parametre er udtryk som optræder i funktionskaldet, i parentesen efter funktionsnavnet

  • Antallet af aktuelle parametre i et kald af en funktion skal være det samme som antallet af formelle parametre i funktionens definition

  • Rækkefølgen af aktuelle parametre og formelle parametres skal også svare til hinanden

  • Typen af en aktuel parameter skal svare til den angivne type af den tilsvarende formelle parameter

Syntax: Et funktionskald i C

function_name (actual_parameters)

Program: Illustration af formelle og aktuelle parametre.
double f(int a, char b, double c){
  ...
}


void g(void){
   int i = 6;
   char ch = 'x';
   double c = 5.6;

   ...
   ...  3.4 + f(i + 7, ch, c)  ...
   ...

   f(i * i, 'y' + 1, (double)i);
   ...
}

Henvisning

I lærebogen kaldes de aktuelle parametre for (aktuelle) argumenter

Eksempel: Rødder i en andengradsligning
Slide Indhold Stikord
Referencer 

Koeficienterne til polynomiet i en andgradsligning bør være parametre til funktionen

Henvisning

Program: En funktion der finder rødder i en andengradsligning - nu med input parametre.
#include <stdio.h>
#include <math.h>

/* Prints roots of the quadratic equation a * x*x + b * x + c = 0 */
void solveQuadraticEquation(double a, double b, double c){
  double discriminant, root1, root2;

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

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

}   

int main(void) {
  double a = 1.0, b = -8.0, c = 15.0,
         d = 2.0, e =  8.0, f =  2.0,
         g, h, i;

  /* First call - coefficents are values of variables */
  solveQuadraticEquation(a, b, c);  

  /* Second call - coefficents are values of expressions */
  solveQuadraticEquation(d - 1, -e, 7 * f + 1); 

  /* Third call - coefficents are entered by user outside solveQuadraticEquation */
  printf("Enter coeficients a, b, and c: ");
  scanf("%lf %lf %lf", &g, &h, &i);
  solveQuadraticEquation(g, h, i);  

  return 0;
}

Henvisning

  • Parameteroverførslen i eksemplet - værdiparametre - bringer input til funktionen:

    • Værdien af første aktuelle parameter kopieres over i første formelle parameter

    • Værdien af anden aktuelle parameter kopieres over i anden formelle parameter

    • Værdien af tredie aktuelle parameter kopieres over i tredie formelle parameter

Værdiparametrene har løst input problemet

Output problemet er stadig uløst!

Det er meget ufleksibelt blot at udskrive resultaterne med printf

Opgave 5.2. Trinvis forfinelse af solveQuadraticEquation

På mange måder er funktionen solveQuadraticEquation fra programmet på den tilhørende slide en god løsning på at finde rødderne i den generelle andengradsligning a x2 + b x + c = 0. Dog udestår, som omtalt på tilhørende slide en tilfredsstillende løsning på aflevering af outputtet: Antallet af rødder og rødderne selv. Men det kommer lidt senere i kurset.

I denne opgave vil vi nedbryde problemløsningen endnu mere, og vi vil på systematisk vis programmere C funktioner som løser disse delproblemer. Opgaven går altså ud på at anvende ideerne om trinvis forfinelse og top-down programmering.

Programmer hvert af følgende delproblemer som en separat funktion:

  • Beregning af diskriminanten.
  • Beregningen af første rod, under forudsætning af at den findes.
  • Beregningen af anden rod, under forudsætning af at den findes.

Hvis der kun er én rod, anses første og anden rod for at være ens. Hvis der ikke findes rødder må de to sidstenævnte funktioner ikke kaldes.

Find gode navne til funktionerne, der løser ovenstående tre delproblemer, og forsyn funktionerne med relevante input parametre. Funktionernes output skal formidles via funktionernes returværdi.

Omskriv programmet så det kalder de tre funktioner.

Programmer endvidere main således at solveQuadraticEquation kaldes i en løkke. Afslut løkken når alle de tre koeficienter a, b og c er lig med 0.

Vær sikker på at du organiserer dit C program ud fra de anbefalinger vi har set om top-down programmering ved trinvis forfinelse.

I denne opgave bedes du programmere det hele i én C fil. Der skal således ikke laves en header fil med prototyper.

Eksempel: Temperaturomregninger
Slide Indhold Stikord
Referencer 

Eksempler på ægte matematisk funktioner, som udelukkende karakteriseres af deres input og output

Program: Et program som omregner frysepunkt og kogepunkt til Fahrenheit grader - uden abstraktion.
#include <stdio.h>

int main(void){

  printf("Freezing point: %6.2f F.\n", 
         9.0 / 5.0 * 0 + 32.0);

  printf("Boiling point: %6.2f F.\n",
         9.0 / 5.0 * 100 + 32.0);
  
  return 0;
}

Program: Et program som omregner frysepunkt og kogepunkt til Fahrenheit grader.
#include <stdio.h>

double fahrenheit_temperature(double celcius_temp){
  return (9.0 / 5.0) * celcius_temp + 32.0;
}

int main(void){

  printf("Freezing point: %6.2f F.\n", 
         fahrenheit_temperature(0.0));

  printf("Boiling point: %6.2f F.\n",
         fahrenheit_temperature(100.0));
  
  return 0;
}

Figur. To kald af fahrenheit_temperature funktionen

Program: Et program som udskriver en celcius fahrenheit tabel.
#include <stdio.h>

double fahrenheit_temperature(double celcius_temp){
  return (9.0 / 5.0) * celcius_temp + 32.0;
}

int main(void){
  double c;  

  printf("%-20s %-20s\n", "Celcius degrees", "Fahrenheit degrees");

  for (c = -30; c <= 45; c++)
    printf("%-20.2f %-20.2f\n", c, fahrenheit_temperature(c));
  
  return 0;
}

Program: Output fra ovenstående program.
Celcius degrees      Fahrenheit degrees  
-30.00               -22.00              
-29.00               -20.20              
-28.00               -18.40              
-27.00               -16.60              
-26.00               -14.80              
-25.00               -13.00              
-24.00               -11.20              
-23.00               -9.40               
-22.00               -7.60               
-21.00               -5.80               
-20.00               -4.00               
-19.00               -2.20               
-18.00               -0.40               
-17.00               1.40                
-16.00               3.20                
-15.00               5.00                
-14.00               6.80                
-13.00               8.60                
-12.00               10.40               
-11.00               12.20               
-10.00               14.00               
-9.00                15.80               
-8.00                17.60               
-7.00                19.40               
-6.00                21.20               
-5.00                23.00               
-4.00                24.80               
-3.00                26.60               
-2.00                28.40               
-1.00                30.20               
0.00                 32.00               
1.00                 33.80               
2.00                 35.60               
3.00                 37.40               
4.00                 39.20               
5.00                 41.00               
6.00                 42.80               
7.00                 44.60               
8.00                 46.40               
9.00                 48.20               
10.00                50.00               
11.00                51.80               
12.00                53.60               
13.00                55.40               
14.00                57.20               
15.00                59.00               
16.00                60.80               
17.00                62.60               
18.00                64.40               
19.00                66.20               
20.00                68.00               
21.00                69.80               
22.00                71.60               
23.00                73.40               
24.00                75.20               
25.00                77.00               
26.00                78.80               
27.00                80.60               
28.00                82.40               
29.00                84.20               
30.00                86.00               
31.00                87.80               
32.00                89.60               
33.00                91.40               
34.00                93.20               
35.00                95.00               
36.00                96.80               
37.00                98.60               
38.00                100.40              
39.00                102.20              
40.00                104.00              
41.00                105.80              
42.00                107.60              
43.00                109.40              
44.00                111.20              
45.00                113.00              

Eksempel: Antal dage i en måned
Slide Indhold Stikord
Referencer 

Vi introducerer en funktion i programmet der beregner antal dage i en måned

Vi bruger eksemplet til at diskutere overførsel af parametre til funktioner

Program: Et program der beregner antal dage i en måned - helt uden funktioner.
#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;
}

Program: Et program der beregner antal dage i en måned med en funktion - uden IsLeapYear funktionen.
#include <stdio.h>
#include <stdlib.h>

int daysInMonth(int mth, int yr);

int main(void) {

  int mth, yr;

  do{
    printf("Enter a month - a number between 1 and 12: ");
    scanf("%d", &mth);
    printf("Enter a year: ");
    scanf("%d", &yr);

    if (yr != 0)
       printf("There are %d days in month %d in year %d\n",
               daysInMonth(mth, yr), mth, yr);
  } while (yr != 0);

  return 0;
}

int daysInMonth(int month, int year){
  int numberOfDays, 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 (year % 400 == 0)
        leapYear = 1;
      else if (year % 100 == 0)
        leapYear = 0;
      else if (year % 4 == 0)
        leapYear = 1;
      else leapYear = 0;

      if (leapYear) numberOfDays = 29; 
      else numberOfDays = 28; break;
    default: exit(-1);  break;
  }
  return numberOfDays;
}   

Program: Et program der beregner antal dage i en måned med en funktion.
#include <stdio.h>
#include <stdlib.h>

int daysInMonth(int mth, int yr);
int isLeapYear(int yr);

int main(void) {

  int mth, yr;

  do{
    printf("Enter a month - a number between 1 and 12: ");
    scanf("%d", &mth);
    printf("Enter a year: ");
    scanf("%d", &yr);

    if (yr != 0)
       printf("There are %d days in month %d in year %d\n",
               daysInMonth(mth, yr), mth, yr);
  } while (yr != 0);

  return 0;
}

int daysInMonth(int month, int year){
  int numberOfDays;
  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 (isLeapYear(year)) numberOfDays = 29; else numberOfDays = 28;
      break;
    default: exit(-1); 
  }
  return numberOfDays;
}   

int isLeapYear(int year){
  int res;
  if (year % 400 == 0)
    res = 1;
  else if (year % 100 == 0)
    res = 0;
  else if (year % 4 == 0)
    res = 1;
  else res = 0;
  return res;
}

Vi har øget genbrugeligheden - og dermed værdien af vort program

Vi ønsker som regel at undgå brug af scanf og printf i genbrugelige procedurer og funktioner

Eksempel: GCD
Slide Indhold Stikord
Referencer 

Vi introducerer ligeledes en funktion i programmet der beregner den største fælles divisor

Vi vil igen diskutere overførsel af parametre

Program: Et program der beregner største fælles divisor med en funktion.
#include <stdio.h>

int gcd(int, int);

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

  small = i <= j ? i : j;
  large = i <= j ? j : i;
  
  printf("GCD of %d and %d is %d\n\n", i, j, gcd(large, small));
  
  return 0;
}

int gcd(int large, int small){
  int remainder; 
  while (small > 0){
    remainder = large % small;
    large = small;
    small = remainder;
  }
  return large;
}   

Henvisning

Opgave 5.5. Find de første n primtal

Denne opgave giver dig blandt andet træning i programmering af et C program, der anvender en header file (.h fil) og en tilhørende .c fil. I denne opgaven kalder vi en funktion, som allerede er skrevet. I senere opgaver skal du selv i gang med at skrive dine funktioner.

Du skal skrive et program med en main funktion der udskriver de første n primtal. Skriv dit program i en fil der hedder test-primes.c. Der ønskes følgende output hvis n er 100:

  prime 1: 2
  prime 2: 3
  prime 3: 5
  prime 4: 7
  prime 5: 11
  prime 6: 13
  prime 7: 17
  prime 8: 19
  prime 9: 23
  prime 10: 29
  ...
  prime 99: 523
  prime 100: 541

I din main funktion skal du - ganske enkelt - gennemløbe så mange positive heltal, som det er nødvendigt, for at finde de første n primtal.

For at få alt dette til at virke skal du lave følgende primes.h fil:

/* Return if i is a prime number */
int is_prime(int i);

Endvidere skal du placere følgende programlinier i filen primes.c, og oversætte denne c fil separat.

#include "primes.h"
#include <math.h>
#include <assert.h>

/* Return if i is a prime number. 
   It is assumed as a precondition that the parameter i is non-negative */
int is_prime(int i){
   assert(i >= 0);

   if (i == 1) 
     return 0;
   else if (i == 2) 
     return 1;
   else if (i % 2 == 0)
     return 0;
   else{
     int k, limit;
     limit = (int)(ceil(sqrt(i)));
     for (k = 3; k <= limit; k += 2)
        if (i % k == 0)
           return 0;
     return 1;
   }
}

Compilering af programmet: Følg mønstret fra vores gennemgang af oversættelse af tændstikpige programmet.

Læs og forstå også funktionen is_prime.

Inspirationen til denne opgave er fra bogen C by Dissection - anvendt med tilladelse fra forlaget.

Opgave 5.5. Goldbachs Formodning

Goldbachs formodning udtrykker en påstand om at alle lige heltal større end to er summen af to primtal. Denne formodning er hverken bevist eller modbevist. I denne opgave vil vi beskæftige os med følgende variation af påstanden:

  • Ethvert lige heltal større end 6 kan udtrykkes som summen af to ulige primtal.

Skriv et program der beviser denne formodning for alle lige heltal mellem to givne grænser. Eksempelvis for alle lige heltal mellem 7 og 2.000.000. Hvis du er i stand til at finde et modeksempel, er berømmelsen måske lige om hjørnet...

Det foreslås at funktionen is_prime fra en tidligere opgave bruges ved løsningen af denne opgave.

Det er for stor en mundfuld at løse dette problem uden opdeling i mindre delproblemer. Det foreslås derfor at I skriver en funktion, som undersøger påstanden for et bestemt lige heltal, n. Denne funktion kan så kaldes for alle lige heltal n mellem f.eks. 7 og 2.000.000.

Hint: Når I skal bevise påstanden for et tal, n, anbefales det at gennemløbe alle mulige summer (n-i) + i, og dermed undersøge om I kan finde et i så både n-i og i er ulige primtal.

Hvis I bliver hurtigt færdige med denne opgave bedes I se på den variant, der på Wikipedia beskrives som Goldbach's weak conjecture.

Som en anden udfordring, kan det være interessant at se alle mulige summer- ikke kun den første. Eller denne variant: Hvilket af de testede tal har det største antal opløsninger?

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

Opgave 5.5. RGB Pixels

I en tidligere opgave har vi arbejdet med PPM grafik, hvor vi med tre kald af fputc skrev én pixel bestående af tre bytes (rød, grøn, blå) på en fil. Denne opgave forbereder vores fremtidige programmering af PPM grafik med en eksplict og relativ kompakt repræsentation af farverne i én pixel.

I denne opgave vil vi repræsentere en pixel i en unsigned int, som antages at fylde 4 bytes, på følgende måde:

  • Den mest betydende byte er i realiteten ubrugt - reserveret til fremtidige behov (til f.eks. at skelne mellem forskellige måder at repræsentere farver på). Vi vælger dog at skrive bitmønstret 00000001 i dette felt.
  • De efterfølgende tre bytes er hhv. den røde, grønne, og blå komponent (hver positive heltal mellem 0 og 255). Den blå komponent bliver således den mindst-betydende byte.

Skriv en funktion

  unsigned int make_pixel(int red, int green, int blue);

som indsætter tre heltal (som hver forudsættes at være mellem 0 og 255) i en unsigned int, og returnerer den resulterende pixels (som en unsigned int).

Skriv endvidere tre funktioner, som udtrækker hhv. den røde grønne og blå komponent af en pixel:

  int get_red(unsigned int p);
  int get_green(unsigned int p);
  int get_blue(unsigned int p);

Det skal naturligvis være således at

  • get_red(make_pixel(r, g, b)) = r
  • get_green(make_pixel(r, g, b)) = g
  • get_blue(make_pixel(r, g, b)) = b

Check at dette er tilfældet gennem en række eksempler (såkaldte test - eller 'unit tests').

Organiser de fire funktioner ovenfor i filen pixels.c, og lav en tilsvarende header fil pixels.h. Vær sikker på at du kan oversætte (compilere) filen pixels.c separat.

Det er attraktivt - men ikke strengt nødvendigt - at anvende de bitvise operatorer (eksempelvis <<, >> og &). Disse er beskrevet i appendix C, side C-3 i lærebogen (7. udgave). Du kan også overveje at se videoen De Bitvise Operatorer.

Regler for overførsel af værdiparametre i C
Slide Indhold Stikord
Referencer 

Parametre til en funktion bruges til at gøre funktionen mere generelt anvendelig

Henvisning

Begrebet formel parameter: En parameter, som optræder i en funktionsdefinition, kaldes en formel parameter. En formel parameter er et navn.
Begrebet aktuel parameter: En parameter, som optræder i et kald af en funktion, kaldes en aktuel parameter. En aktuel parameter er et udtryk, som beregnes inden det overføres.

  • Antallet af aktuelle parametre i kaldet skal modsvare antallet af formelle parametre i definitionen

  • Typen af en aktuel parameter skal modsvare den angivne type af hver formel parameter

    • Dog muligheder for visse implicitte typekonverteringer

  • Parametre til funktioner i C overføres som værdiparametre - call-by-value

    • Der overføres en kopi af den aktuelle parameters værdi

    • Kopien bindes til (assignes til) det formelle parameternavn

    • Når funktionen returnerer ophører eksistensen af de formelle parametre, på samme måde som lokale variable i funktionen.

Eksempel: Rodsøgning (1)
Slide Indhold Stikord
Referencer 

Enhver kontinuert funktion f, som har en negativ værdi i l og en positiv værdi i u (eller omvendt) vil have mindst én rod r mellem l og u.

Figur. En kontinuert funktion f med en rod mellem l og u

Ved at indsnævre intervallet [l, u], og ved hele tiden at holde roden mellem l og u, kan vi hurtigt finde frem til en værdi r for hvilken f(r) = 0.

Eksemplet svarer til bogens 'case study' side 298-306.

Eksempel: Rodsøgning (2)
Slide Indhold Stikord
Referencer 

Program: Rodsøgningsfunktionen.
/* Precondition: The signs of f(a) and f(b) are different */
double findRootBetween(double a, double b){
  double l = a, u = b;
  while (!isSmallNumber(f(middleOf(l,u)))){ 
    if(sameSign(f(middleOf(l,u)), f(u)))
      u = middleOf(l,u);
    else 
      l = middleOf(l,u);
  }
  return middleOf(l,u);
}  

Program: Funktionerne sameSign, middleOf og isSmallNumber.
int sameSign(double x, double y){
  return (x > 0 && y > 0) || (x < 0 && y < 0);
}

double middleOf(double x, double y){
  return x + (y - x)/2;
}

int isSmallNumber(double x){
  return (fabs(x) < 0.0000001);
}   

Program: Hele rodsøgningsprogrammet.
#include <stdio.h>
#include <math.h>

int sameSign(double x, double y);
double middleOf(double x, double y);
int isSmallNumber(double x);
double findRootBetween(double a, double b);
 
double f(double x){
  /* (x - 5.0) * (x - 3.0) * (x + 7.0) */
  return (x*x*x - x*x - 41.0 * x + 105.0);
}

int main(void){
  double x, y;
  int numbers; 

  do{
    printf("%s","Find a ROOT between two number: ");
    numbers = scanf("%lf%lf", &x, &y);

    if (numbers == 2 && !sameSign(f(x),f(y))){
      double solution = findRootBetween(x,y);
      printf("\nThere is a root in %lf\n", solution);
    }
    else if (numbers == 2 && sameSign(f(x),f(y)))
      printf("\nf must have different signs in %lf and %lf\n",
                x, y);
    else if (numbers != 2)
      printf("\nBye\n\n");
  }
  while (numbers == 2);

  return 0;
}

/* Precondition: The signs of f(a) and f(b) are different */
double findRootBetween(double a, double b){
  double l = a, u = b;
  while (!isSmallNumber(f(middleOf(l,u)))){ 
    if(sameSign(f(middleOf(l,u)), f(u)))
      u = middleOf(l,u);
    else 
      l = middleOf(l,u);
  }
  return middleOf(l,u);
}  

int sameSign(double x, double y){
  return (x > 0 && y > 0) || (x < 0 && y < 0);
}

double middleOf(double x, double y){
  return x + (y - x)/2;
}

int isSmallNumber(double x){
  return (fabs(x) < 0.0000001);
}   

Funktionen findRootBetween bør også modtage funktionen f som input - side om side med intervallet [a,b]

Forskellige problemer med input parametre og returværdi
Slide Indhold Stikord
Referencer 

Vi viser forskellige elementære problemer med input parametre og returværdien fra en funktion

Program: En double funktion som glemmer at bruge return.
/* Forget return in the function hypotenuse */

#include <stdio.h>
#include <math.h>

double hypotenuse (double katete1, double katete2){
  sqrt(katete1 * katete1 + katete2 * katete2);
}

int main(void) {
  double k1, k2;
  printf("Indlaes to kateter: ");
  scanf("%lf %lf", &k1, &k2);

  printf("Katete1: %f, katete2: %f, hypotenuse: %f\n",
         k1, k2, hypotenuse(k1, k2));
}

Program: En void funktion som printer - burde returnere sit resultat.
/* Void function som printer i stedet for blot at returnere */

#include <stdio.h>
#include <math.h>

void hypotenuse (double katete1, double katete2){
  printf("Hypotenuse: %f", sqrt(katete1 * katete1 + katete2 * katete2));
}

int main(void) {
  double k1, k2;
  printf("Indlaes to kateter: ");
  scanf("%lf %lf", &k1, &k2);

  printf("Katete1: %f, katete2: %f, hypotenuse: %f\n",
         k1, k2, hypotenuse(k1, k2));        /* Problem with call of hypotenuse */
}

Program: En funktion hypotenuse kan ikke se en anden funktions lokale variable.
/* hypotenuse cannot see local variables in main */

#include <stdio.h>
#include <math.h>

double hypotenuse (void){
  return sqrt(katete1 * katete1 + katete2 * katete2);    /* katete1 and katete2 undeclared */
}

int main(void) {
  double katete1, katete2;
  printf("Indlaes to kateter: ");
  scanf("%lf %lf", &katete1, &katete2);

  printf("Katete1: %f, katete2: %f, hypotenuse: %f\n",
         katete1, katete2, hypotenuse());
}

Program: Brug af globale variable til input i stedet for parametre.
/* Communication via global variables - Works - NOT GOOD */

#include <stdio.h>
#include <math.h>

double katete1, katete2;

double hypotenuse (void){
  return sqrt(katete1 * katete1 + katete2 * katete2);  
}

int main(void) {
  printf("Indlaes to kateter: ");
  scanf("%lf %lf", &katete1, &katete2);

  printf("Katete1: %f, katete2: %f, hypotenuse: %f\n",
         katete1, katete2, hypotenuse());
}

Program: Brug af globale variable til input og output.
/* Communication via global variables - works - EVEN WORSE */

#include <stdio.h>
#include <math.h>

double katete1, katete2, result;

void hypotenuse (void){
  result = sqrt(katete1 * katete1 + katete2 * katete2); 
}

int main(void) {
  printf("Indlaes to kateter: ");
  scanf("%lf %lf", &katete1, &katete2);

  hypotenuse();

  printf("Katete1: %f, katete2: %f, hypotenuse: %f\n",
         katete1, katete2, result);
}

Program: Det gode program.
/* OK - The good and natural solution - with use of parameters and return value */

#include <stdio.h>
#include <math.h>

double hypotenuse (double katete1, double katete2){
  return sqrt(katete1 * katete1 + katete2 * katete2);
}

int main(void) {
  double k1, k2;
  printf("Indlaes to kateter: ");
  scanf("%lf %lf", &k1, &k2);

  printf("Katete1: %f, katete2: %f, hypotenuse: %f\n",
         k1, k2, hypotenuse(k1, k2));
}


Programmer og Algoritmer

Programmer og Algoritmer
Slide Indhold Stikord
Referencer 

Begrebet algoritme: En algoritme er endelig liste af instruktioner til løsning af problem, som karakteriseres af nul, en eller flere input og ét output. Hver instruktion skal være klar, utvetydig, og praktisk gennemførbar for en person som ønsker at følge algoritmen.

  • Algoritme

    • Knytter sig primært til den formelle og matematiske del af faget

    • En trinvis beregningsmæssig opskrift

    • Kan udtrykkes som et pseudoprogram

      • I et ikke-formaliseret programmeringssprog.

  • Program

    • Knytter sig til den praktiske del af faget

    • Kan implementerer en algoritme i et bestemt programmeringssprog

    • Insisterer ikke på nul, en eller flere input og ét output

Henvisninger

Program: Algoritme for løsning af andengradsligning.
Algorime der løser andengradsligningen  a*x*x + b*x + c = 0.
For konstante tal a, b og c find de x-værdier for hvilke a*x*x + b*x + c = 0.

1. Indlæs koeficienterne a, b og c.

2. Beregn diskriminant = b*b - 4*a*c

3. Hvis diskriminant er negativ:
   Print at der ikke er rødder.

3. Hvis diskriminant er nul:
   Print at der er én rod: -b / (2*a)

4. Hvis diskriminant er positiv:
   Print at der er to rødder:
      (-b + sqrt(diskriminant)) / (2*a)  og
      (-b - sqrt(diskriminant)) / (2*a)

Program: Algoritme som finder største fælles divisor af to ikke-negative heltal - Euclids algoritme.
Euclids algoritme.
Find det største heltal der går op i to givne ikke-negative heltal a og b.

1. Indlæs a og b.

2. Ombyt om nødvendig a og b, således at a >= b.

3. Beregn remainder = a modulo b (hvor modulo er resten ved heltalsdivision).

4. Hvis b er lig med 0, så er resultatet a, som printes, hvorefter algoritmen er afsluttet.

5. Tildel a værdien af b.

6. Tildel b værdien af remainder.

7. Gå til trin 4.

Programbeskrivelse og programudførelse
Slide Indhold Stikord
Referencer 

Ordet 'program' bruges ofte i tvetydigt for både programbeskrivelsen og programudførelsen

  • Programbeskrivelse:

    • Kildeprogrammet (engelsk: source program)

    • En statisk tekst eller struktur, som skabes af programmøren

    • Oversættes til en lavniveau beskrivelse, som kan fortolkes af computeren

  • Programudførelse:

    • Det kørende program (engelsk: program execution)

    • En dynamisk process som defineres og begrænses af programbeskrivelsen

    • Mange begreber, som knytter sig til programudførelsen, har et direkte modstykke i programbeskrivelsen

Ekstra Opgaver
Slide Indhold Stikord
Referencer 

Opgave 5.8. Skudårsfunktionen

Vi har tidligere i denne lektion mødt skudårsfunktionen

int isLeapYear(int year){
  int res;
  if (year % 400 == 0)
    res = 1;
  else if (year % 100 == 0)
    res = 0;
  else if (year % 4 == 0)
    res = 1;
  else res = 0;
  return res;
}

Programmer en ny skudårsfunktion med brug af && og ||, og uden brug af if-else og uden brug af betingede udtryk.

Kald begge skudårsfunktioner for alle årstal mellem år 1900 og år 2100. Giver de to funktioner samme resultat på alle årstal?

Opgave 5.8. Programmering af en kvadratrodsfunktion

Bibliotektet math.h indholder som bekendt funktionen sqrt, som beregner kvadratroden af et tal i typen double.

Programmer din egen kvadratrodsfunktion my_sqrt med brug af Newtons metode. Kvadratroden af a kan findes som en rod af funktionen f(x) = x * x - a. Newtons metode gør det muligt for os at finde denne rod. Se f.eks. denne video (lavet Oscar Veliz) om hvordan dette virker. (Se formlen for rækkeudviklingen ved tid 2:23)

Vær sikker på at du programmerer en funktion, som tager en double som parameter, og som returnerer en double som resultat.

Hvordan vil du håndtere en situation, hvor der overføres et negativt input?

Udskriv en table over a, my_sqrt(a) og sqrt(a) for alle heltal a mellem 0.0 og 25.0, og check dermed om din nye funktion leverer gode resultater.

Opgave 5.8. Nye funktioner i gamle opgaver

I lektionen om iterative kontrolstrukturer arbejde vi med to opgaver, som vi nu vil tage op igen med det formål at indføre abstraktion med funktioner.

I opgave programmeringsopgave 1 side 267 (i Problem Solving and Program Design in C, eighth edition) summerede vi alle heltal fra 1 til n, og vi sammenlignede værdien af denne sum med (n + 1)* n / 2. Skriv nu følgende to funktioner:

  • En funktion sum-iter med én int parameter n. Funktionen skal addere alle heltal fra 1 til n. Funktionen skal returnere denne sum.
  • En funktion sum-formula med én int parameter n som indkapsler beregningen af (n + 1)* n / 2, og som returnerer værdien af dette udtryk.

I skal kalde disse to funktioner på passende input og sammenligne deres resultater (ligesom i den oprindelige opgave).

I lektionen om iterative kontrolstrukturer arbejde vi også med opgave 1 side 181 i bogen. Vi har en befolkning på 9870 personer som vokser med 10% per år. Spørgsmålet var hvor mange år der går inden befolkningstallet er mere end 30000.

Skriv nu en funktion som generaliserer denne opgave. Mere specifikt:

  • En funktion population-projection med tre double parametre: start-befolkningstallet, vækstprocent pr år, og den øvre grænse af befolkningstallet. Funktionen skal returnere det antal år (af typen int) det tager for befolkningen at vokse fra start-befolkningstlalet til mere end slut-befolkningstallet.

Kald derefter funktionen så den løser opgaven fra side 181 i bogen (med de tre givne tal 9870, 10% og 30000).


Samlede referencer
Indhold Stikord
Tidligere udgave med problemløsning i main
Senere udgave med input parametre
Notes about GCC
Regler for parameteroverførsel
Tidligere udgave uden parametre
Senere udgave med output parametre
Programmet der beregner største fælles divisor
Aktuelle og formelle parametre
Program for Euclids Algoritme
Program der løser andengradsligning

 

Kapitel 5: Funktioner
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: 13. oktober 2017, 09:26:55