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.
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
-
Log into an undergraduate cluster computer. Update the course public repo with a
git pull
command. -
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. -
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.
Do not try to run make during this exercise until you are instructed to.
Part 2
-
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.
-
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 value1
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 be1
, and the value inside the third argument will not be changed.Caution- You may NOT use the
strcat
orstrcpy
library functions (fromstring.h
) in your solution. But you MAY usestrlen
. - 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.
- You may NOT use the
-
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:
-
run_concat.c - should contain the
main()
function, but no other functions. -
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. -
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.
-
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. -
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. -
If your program does not compile or link properly, check that you have added the necessary
#include
statements in each.c
file. -
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.
-
Now it is time to edit the sample Makefile file you copied over from the public repository back in Part 3.
-
Modify Makefile so that it builds the run_concat program and creates an executable called run_concat (rather than main).
-
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 usingls -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. -
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.
- Edit the string_functions.c file so that the
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!