Programming in C

Functions

Gerald Senarclens de Grancy

Terminology

Code Reuse

  • A single copy of code can be used elsewhere
  • Important for maintenance
  • Basis of any library

Case Sensitivity

  • Uppercase and lowercase letters are treated as distinct
  • C, Bash and Linux are case sensitive

DRY - Don't Repeat Yourself

Formulated by Andy Hunt and Dave Thomas in "The Pragmatic Programmer"

  • Fundamental programming principle
  • Every piece of knowledge [...] should have a single representation
  • Duplication is waste (=> maintenance!!)
  • There should be only one obvious [...] way to accomplish a task

Steve Smith in [Henney (2010), p. 60f]

Scope

  • Region of code in which a name is known (or visible) and accessible
  • In scope/ out of scope
  • Functions create a new scope
    (variables declared in a function are limited to the function)
  • Don't use global variables
  • Global constants (all caps) are ok

Functions

A function gives a name to a block of code

The named block of code can be executed by "calling" the function name

Function names should state what the function does or what it returns

  • Snippets of code usable from the rest of the program
  • Separate out common actions
  • Package up and parameterize functionality
  • Avoid code duplication and allow reusing code
  • Maintenance becomes easier
  • kloc/ sloc is a dangerous metric

When using appropriate function names, code becomes easier to read

// ...delta_x, delta_y are defined, `sqrt` is available
delta_x2 = delta_x * delta_x;
delta_y2 = delta_y * delta_y;
distance = sqrt(delta_x2 + delta_y2);
// vs. (requires `hypot` function to be available)
distance = hypot(delta_x, delta_y);

C Functions

We can use standard library functions that others defined for us

math.h
sin(.), cos(.), sqrt(.), hypot(.), ...
stdio.h
fgets(.), printf(.), puts(.), sscanf(.), ...

For example

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

int main() {
  double result = sin(3.14159265359);
  printf("The sin of 3.14159265359 is %lf.\n", result);
  return 0;
}

Visualize execution

Create Your Own Functions - Syntax

returnType functionName(parameter1, parameter2,...) {
  // function body
}

For example, we've already defined main in each of our programs

int main() {
  return 0;
}

Minimalistic Example

#include <stdio.h>

void print_usage() {  // `void` means that nothing is returend
  puts("This function prints two lines of");
  puts("static text.");
}

int main() {
  puts("Before calling our function.");
  print_usage();  // Call a function without arguments
  puts("After calling our function.");
  return 0;
}

Visualize execution

Arguments and Parameters

  • Functions can be parameterized to make them more generic
  • Parameters are available to functions as variables
  • Arguments are values passed to a function
  • Argument values are accessed through parameters
  • In C, arguments are passed by value

() after a function name calls (executes) that function

(.) indicates that a function expects one or more arguments

Example With One Parameter / Argument

#include <stdio.h>

void print_grade(int i) {  // `i` is a parameter to `print_grade`
  printf("The student's grade is %d.\n", i);
}

int main() {
  puts("Before first function call.");
  print_grade(5);  // `print_grade` gets called with the argument `5`
  puts("Before second function call.");
  print_grade(1);  // `print_grade` gets called with the argument `1`
  puts("After function calls.");
  return 0;
}

Visualize execution

Example With Two Parameters / Arguments

#include <stdio.h>

void print_grade(char name[], int i) {  // function with two parameters
  printf("%s's grade is %d.\n", name, i);
}

int main() {
  puts("Before first function call.");
  print_grade("Banana Joe", 5);
  puts("Before second function call.");
  print_grade("Peppa Pig", 1);
  puts("After function calls.");
  return 0;
}

Visualize execution

Pass by Value

By default, C copies argument values to function parameters

#include <stdio.h>

void pass_by_value(int i) {
  i = 5;
  printf("i: %d (at the end of the called function)\n", i);
}

int main() {
   int i = 3;
   printf("i: %d\n", i);
   pass_by_value(i);
   printf("i: %d (after returning from function)\n", i);
   return 0;
}

Visualize execution

Return Statement

  • Causes execution to leave the current function
  • Execution is resumed where the function was called
  • Return statements allow a function to specify a return value
  • A return value is passed back to the code that called the function

Example: Calculate a Sum

#include <stdio.h>

int sum(int first, int second) {
  int result = first + second;
  return result;
}

int main() {
  int total = sum(1, 2);
  printf("The calculated total is %d.\n", total);
  int price = sum(2, 3);
  printf("The calculated price is %d.\n", price);
  return 0;
}

Visualize execution

What does this code do?

#include <stdio.h>
int calculate_years(double investment, double goal, double interest_rate) {
  int years = 0;
  while (investment < goal) {
    years++;
    investment = investment * (1 + interest_rate);
  }
  return years;
}

int main() {
  printf("To turn 200 into 300 euros at 4%% interest, wait %d years.\n",
    calculate_years(200, 300, 0.04));
  printf("To turn 500 into 700 euros at 8%% interest, wait %d years.\n",
    calculate_years(500, 700, 0.08));
  return 0;
}

Visualize execution

Exercise

  1. Write a function double min(double first, double second) that takes returns the smaller of the two given numbers.
  2. Write a function double max(double first, double second) that returns the larger of the two given numbers.
  3. Write int main() that calls your functions multiple times to test them if they work properly.

Solution

#include <stdio.h>

double min(double first, double second) {
  return first < second ? first : second;
}
double max(double first, double second) {
  return first > second ? first : second;
}
int main() {
  printf("min(-3,  2) -> %lf\n", min(-3, 2));
  printf("min( 4, -5) -> %lf\n", min(4, -5));
  printf("min( 4,  5) -> %lf\n", min(4, 5));
  printf("max(-3,  2) -> %lf\n", max(-3, 2));
  printf("max( 4, -5) -> %lf\n", max(4, -5));
  printf("max( 4,  5) -> %lf\n", max(4, 5));
  return 0;
}

Visualize execution

Questions
and feedback...

Literature

Andrew Hunt and David Thomas The Pragmatic Programmer, 20th Anniversary Edition Addison Wesley (2019) buy on Amazon
Kevlin Henney 97 Things Every Programmer Should Know O'Reilly and Associates (March 18, 2010) buy on Amazon