Lab: Pointers to Functions

Today’s lab will help you practice using pointers to functions in C, which gives us the ability to write some of the functional-style code you practiced in CSC 151.

A. Reading Code with Function Pointers

Consider the following code fragment:

int f1(int (*f)(int));
int f2(int i);

int main(void){
  printf("Answer: %d\n", f1(f2));
  return 0;
}

int f1(int (*f)(int)){
  int n = 0;
  while (f(n)) n++;
  return n;
}

int f2(int i){
	return i * i - i - 12;
}

Exercises

  1. What do you predict the code will do? Write down your prediction

  2. Verify your guess by running the code. If you got it wrong, write an explanation of where you were incorrect.

B. Writing a Function that Uses Function Pointers

Next, you’ll be implementing a function that takes a function pointer as an argument. Here is the function’s declaration:

int sum(int (*f)(int), int start, int end);

The call sum(g,i,j) should return g(i) + ... + g(j).

Exercises

  1. Write the function sum.
  2. Write a function g1 which takes in an integer and returns the integer squared. Test sum on g1, using various values for start and end so that you’re confident sum works as desired.
  3. Write a function g2 which takes in an integer and returns the integer minus 1. Test sum on g2, using various values for start and end until you’re confident that sum works as desired.

C. Running Functions Based on Arguments

Consider the problem of giving a string as an argument to a function, and depending on what the string contains, executing a particular command.

We will break this problem into two parts: First we’re going to write a suite of commands we might want to execute. Then we will write a function that will execute a given command.

The following code declares a struct type command_t, which contains a string and a function.

typedef struct {
	char* cmd_name;
	void (*cmd_pointer)();
} command_t;

Use this to declare an array of structs, which you will use from various functions you will write in the next step. For example, we might declare the following array:

command_t print_cmds[] = {
	{"smile", printSmiles},
	{"compliment", printCompliment},
	{"x", printxs}
};

The idea here is that each of printSmiles, printCompliment and printxs will be the name of a function with no parameters and with return type void (because of the type of the cmd_pointer field in the command_t struct). Your array should have at least 5 items.

Exercises

  1. Add the definition of command_t to a C source file, and then initialize a print_cmds array with at least five elements.
  2. Write the 5 (or more) functions you placed in the print_cmds array. Your functions must have the appropriate types, but other than that it is up to you to decide what they should do.
  3. Write a function that takes a string as an argument, and then searches the print_cmds array for a matching name. When it finds an entry with a matching cmd_name value, it calls the function associated with that name. You can decide what to do if the function does not find a matching command entry. Use the following declaration for this function:
    void execute_command(const char* cmd);
    
  4. Test your execute_command from the previous step by calling it from main with a variety of parameters.

A few hints to get you started on this one:

  • You will need to use the strcmp function to compare strings.
  • You will also need to know the number of elements in the print_cmds array. To compute this, you can divide sizeof(print_cmds) by sizeof(command_t); remember, this only works for fixed-size arrays.

D. Writing map in C

Finally, you’ll need to implement a map procedure like the one we saw in Racket. Because C requires us to specify types ahead of time, we need to constrain the type of our mapped function, as well as the input/output array. This map will take an array of integers and a function that takes an integer as a parameter and produces an integer as an output. Our map implementation will update the array in place, meaning it changes the array contents rather than writing the output to a new array.

Exercises

  1. Write a declaration for map. Make sure the declaration matches the description above.
  2. Implement map. You likely implemented map with recursion in CSC 151, but in C we would typically use a loop to repeatedly apply the mapped function over an array.
  3. Test your map implementation on a variety of array inputs and mapped functions.