Main

Lecture 5

Today we will continue working with C, focusing on function arguments and continue working with pointers. We will also introduce some simple Bash commands and take a look at a Makefile. Code from lecture can be cloned with

git clone https://brnorris03@bitbucket.org/brnorris03/cis330exercises.git

or just git pull in your copy if you cloned it previously. More code will be added later in the day based on what we actually did in class.

1. Function arguments -- passing by value vs passing by reference.

Suppose we are required to provide a function that doesn't return a value (void) and which takes a single integer argument and adds 1 to it.

First version:

  1. #include <stdio.h>
  2. void increment (int x) {
  3.     x++;
  4. }
  5. int main() {
  6.     int y = 2;
  7.     printf("y = %d\n", y);
  8.     increment (y);
  9.     printf("After increment: y = %d\n", y);
  10.     return 0;
  11. }

This compiles and runs, but the value of y does not change because it is passed by value, i.e., its value, 2, is copied into x, leaving y unmodified. In C, function parameters are always passed by value. Pass-by-reference is simulated in C by explicitly passing pointer values.

Another try:

  1. #include <stdio.h>
  2. void increment (int *x) {
  3.     (*x)++;
  4. }
  5. int main() {
  6.     int y = 2;
  7.     printf("y = %d\n", y);
  8.     increment (&y);
  9.     printf("After increment: y = %d\n", y);
  10.     return 0;
  11. }

This time y is incremented because instead of copying its value (2) to the increment function's argument x, we simulated passing it by reference, i.e., we passed the address of y, so that inside the increment function, the value of x is the address of y and it can be used to modify whatever memory location x points to (in this case, y) by dereferencing it with *x.

2. Passing more complex data types as arguments.

In C you can define a struct datatype which consists of a list of fields, each of which can have almost any type. The total memory required for a struct is the sum of the storage requirements of all the fields, plus any internal padding.

In this exercise we will define a struct Point, which will store two integer coordinates, x and y. Then we will implement a function to "move" the point by adding an integer distance to both the x and y fields of the struct.

See the complete implementation, including a Makefile in the lecture5 subdirectory of the repository.

  • C also has enum types (similar to Python and Java) and union types. Here is an example of a union type used inside a struct, which contains a somewhat arbitrary collection of fields, just for illustration purposes (and also assumes that the struct Point type is defined).
  1. struct TableItem {
  2.     int row;
  3.     char label[20];
  4.     union {
  5.         char c;
  6.         int i;
  7.         char *s;
  8.         double d;
  9.         struct Point *p;
  10.     } value;
  11. };
What this means is that you can define a variable of type TableItem and store values that match any of the union components. For example
  1. TableItem t;
  2. t.row = 0;
  3. strcpy(t.label, "An integer");
  4. t.value.i = 100;

3. Separate compilation and makefiles (a very initial look, much more later)

  1. SOURCES = square1.c square2.c diamond.c main.c
  2. HEADERS = square1.h square2.h diamond.h
  3. OBJECTS = $(SOURCES:.c=.o)
  4.  
  5. CC = gcc
  6. CFLAGS = -std=c99 -g
  7.  
  8. %.o: %.c
  9.     $(CC) -c $(CFLAGS) $<
  10.  
  11. main: $(OBJECTS)
  12.     $(CC) -o $@ $(OBJECTS)
  13.  
  14.  
  15. clean:
  16.     $(RM) main $(OBJECTS)

Green Marinee theme adapted by David Gilbert, powered by PmWiki