Exercise 8
Info

This is an in-class exercise. An exercise page like this one will contain a brief description but is intended to be supplemented by discussion during our meeting time. Complete the exercise to the best of your ability in the time given. Feel free to talk with other students as you work, and do not be afraid to ask questions if you get stuck. Aim to complete as much as possible during our meeting, and submit on Gradescope to check your solution. You are encouraged to work at home to complete what you do not finish today.

Learning Objectives

Reinforces concepts learned in today's meeting:

  • Modularizing your code by writing separate functions
  • Organizing functions into separate files (function declarations in header files)
  • Using header guards
  • Using separate commands for compilation (translation to object code) and linking
  • Creating a Makefile and using make to build your program
  • Working with C-strings (from week2)

Part 1

  1. Log into an undergraduate cluster computer. Update the course public repo with a git pull command.

  2. Confirm that you can see the template files for today’s exercise by typing ls exercises/ex08 – you should see files named all_in_one.c and Makefile inside.

  3. Navigate to your personal repo for the course. Make a directory for today’s exercise and copy the starter files into it. You will not need Makefile until you get to Part 4.

Caution

Do not try to run make during this exercise until you are instructed to.

Part 2

  1. Compile your newly-copied all_in_one.c file by typing the usual compile command. You will notice that the function calls do not return anything sensible at the moment, so let’s fix that.

  2. Edit all_in_one.c so that the function named concat performs string concatenation of its first two arguments, “returning” the concatenated string via its third argument and sending 0 back as the function’s return value. However, note that the function’s third argument has limited capacity, the value of which is indicated in the fourth argument. If concatenating the first two arguments would cause an overflow of the third argument, do not modify the third argument, and return the value 1 to indicate an error situation.

    For example, if the first two arguments are “alpha” and “beta”, and the result string has capacity 10, then the value returned by the function will be 0 and, after the function call, the value inside the third argument should be “alphabeta”. However, if the first two arguments are “alpha” and “gamma”, with a fourth argument of 10, the value returned by the function will be 1, and the value inside the third argument will not be changed.

    Caution
    • You may NOT use the strcat or strcpy library functions (from string.h) in your solution. But you MAY use strlen.
    • You should NOT modify any code in the main function. Edit only the concat function, and get it to work with the existing function calls in main. At that point, if you would like to test your function further, you may add additional calls in main to do so.
  3. Once you have made your changes, re-compile the file. Test your program by executing ./a.out and reviewing the output. It is okay to add new calls in main if you wish.

Part 3

Next, we are going to split your working source code into multiple files as follows. Without changing all_in_one.c, copy the contents of your all_in_one.c program into the following files:

  1. run_concat.c - should contain the main() function, but no other functions.

  2. string_functions.c - should contain the definition for the string helper function concat (and in theory, could later include additional function definitions). It should not have a main() function.

  3. string_functions.h - should contain a prototype (i.e. declaration) for each function defined in string_functions.c (today, there is only one), and should be #include-d in both of the .c files. Make sure to include a header guard for this file to prevent being included multiple times.

Compile and link the program manually, step by step.

  1. Recall that to compile a source file only (and not link or generate an executable), you will use the regular gcc command with our usual flags and the -c flag with the .c source file as an argument. This command will create an object file.

  2. Once you have created your two object files, you can link them to create an executable named run_concat by using the gcc command with both .o files as arguments (but here, you do not need the usual flags we use for compiling). To express in the command that you want the executable file named run_concat, you will need to use the -o flag with run_concat as an argument.

  3. If your program does not compile or link properly, check that you have added the necessary #include statements in each .c file.

  4. Do not move onto the next step until you can successfully build and run the run_concat executable file.

Part 4

Create a Makefile for this program so you can build it quickly and easily.

  1. Now it is time to edit the sample Makefile file you copied over from the public repository back in Part 3.

  2. Modify Makefile so that it builds the run_concat program and creates an executable called run_concat (rather than main).

  3. Try out the following command-line commands and try to reason out what is happening at each step by reading the messages each prints: make, make clean, make string_functions.o, make run_concat.o. Look around in the folder using ls -l after each command to see what changed. Execute them in different orders (and after modifying some source file slightly) and see how the behavior changes.

  4. Finally, check that your Makefile captures the required dependencies properly:

    • Edit the string_functions.c file so that the concat function behaves noticeably differently, e.g., outputs a message on the screen. (It does not matter what it says.) Save it, but do not re-compile it.
    • At the command line, type make. Then execute your program and confirm that the output you see is due to the new behavior of the function.
Reminder

Remember to add and commit to your local repo copy as your work. Push to your remote repo when finished. Also zip your Makefile along with all your *.c and *.h files and submit to Gradescope to check your solution. Use exit to logout from your ugrad account when finished. If you continue to work on the program after class, make sure to keep your repo updated as well!