When I write labs and projects, it looks like a lot of work. But that’s because I write them like tutorials. This lab has a lot of reading because you are probably new to all of this stuff so I have to explain everything. Read and follow along, and you should be done in no time.
Your computer’s filesystem
Please head over to this page first to learn about your computer’s filesystem. You are no longer a babby CS student.
How you will do your work in this course
Normally, we would have you use a server named thoth
to do your work, but uh, the server room kinda flooded last fall. So thoth
is offline for a while.
Instead, you will set up a simple virtual machine (VM) on your own laptop in order to have a consistent platform that we will all use. A virtual machine is kinda exactly what it sounds like: an imaginary machine running as a program on your real machine (often called the “host machine”).
I’ve already set up an image, a virtual hard drive, with everything we’ll need. All you need to do is install a program, download the image, and run it.
SSH (secure shell) is a program and protocol that lets you securely connect to a computer across the internet and interact with it.
You know your command-line or terminal interface? Like how you run javac
and java
? It’s that. Except, instead of your own computer, you’ll be running commands on another computer.
1. Setting up the VM
This cannot be done on a Chromebook. If your primary school computer is still a Chromebook, I’m sorry, but it’s time to upgrade to a real laptop. Please let me know if this is a problem.
qemu is an open-source virtual machine. It’s relatively easy to get installed and running.
Windows Users
- Go here and download the
qemu-w64-setup-20241220.exe
or whatever the exact filename is, the one labeled “QEMU Installer for Windows (64 bit)”. - Run the installer, and just use the defaults for everything (i.e. hit the “Next” button several times).
- Now it’s installed, but you can’t run it from the command line easily. You have to “add it to your Path:”
- Click Start, type
environment variables
, and click Edit the system environment variables. - In the top box (User variables for <whoever>), click Path, and then click the Edit… button below the box.
- You’ll get a new dialog with a list of paths. Click
New
, then in the new row, putC:\Program Files\qemu
- Click
OK
to close the paths dialog, and clickOK
again to close the variables dialog.
- Click Start, type
-
Let’s test that it works. Start, type
powershell
, click it. Then run this command:qemu-system-x86_64.exe --version
- You should see
QEMU emulator version blah blah etc etc
. - That means qemu is installed and working!
- If you instead get an error about it not being recognized, you might have skipped or messed up the environment variable step. Get help.
- You should see
Now you can scroll down to the Everyone! section below.
Mac Users
You install qemu through something called Homebrew, a package manager for mac.
- Run
Terminal
(⌘+Space, type “terminal”, hit enter) - Type
brew
and hit enter.- If you get “command not found,” you need to install Homebrew. Do so by copying, pasting, and running this command in the terminal:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- It might take a while.
-
Once homebrew is installed, installing qemu is super easy:
brew install qemu
- it’ll take a little while again.
-
Once it’s installed, run this:
qemu-system-x86_64 --version
- You should see
QEMU emulator version blah blah etc etc
. - That means qemu is installed and working!
- You should see
Now you can scroll down to the Everyone! section below.
Linux Users
Install qemu however you do for your distro.
Everyone!
- Download this compressed image file. Warning, it’s a big one (2.2 GB).
- Make a directory for your CS0449 stuff.
- Windows users, maybe put this directory outside OneDrive. Up to you.
- Open the compressed file you downloaded, and drag the
cs0449.qcow2
file into that directory.- It’ll take a bit.
- You can delete the zip file once you’ve done that, since it’s a huge file.
- Download the appropriate script below, and put it in the same directory as
cs0449.qcow2
. - In Terminal/Powershell,
cd
into that directory.- If you
ls
, you should see both thecs0449.qcow2
andrun.bat/sh
files.
- If you
- Run the script:
- Windows:
.\run.bat
- Mac/Linux:
- first
chmod +x run.sh
(you only need to do this once) - then,
./run.sh
- first
- Windows:
At this point, a window should pop up, and after a little bit, you should start seeing a ton of text scrolling up it. That’s the VM! It’s booting up!
Eventually, you’ll see this, which means it’s fully booted:
But we won’t be logging into the VM in this window…
A couple more notes on the VM
- To shut down the VM, do Machine > Power Down.
- You’ll see a bunch of messages scroll by, and then it will close.
- Closing it other ways may cause it to freak out the next time you run it. (Like a computer losing power.)
- If you have a high-spec computer, you can get better performance in the VM by editing
run.bat/sh
.- By default, it is given 2GB of RAM and 2 cores, but the comments in that file explain how to give it more.
- But, nothing we do in this class needs a TON of performance, so 4GB and 4 cores is probably more than enough.
2. Connecting with SSH
Now you need to connect to the VM so that you can learn to use gcc
and other commands. ssh
is the command you use on your host computer to connect to the VM.
- Open another tab or window in Terminal/PowerShell.
- Run
ssh student@localhost -p 10022
- Say “yes” to the “authenticity of the host cannot be established” prompt
- you only need to do it this first time; it will be remembered from now on
- For the password, type
cs0449
- Nothing will show up when you type your password. That’s normal. Just type it and hit enter!
-
You’re in! You should see a command prompt:
3. Where are we?
When you log in, you are placed in the home directory. The home directory is where all your personal files are. The same concept applies to Windows and macOS too.
- Try using
pwd
; it’ll show you the full path of your home directory,/home/student
.- Your home directory can also be referred to as
~
in many commands as a typing shortcut. (That’s what the~
in the prompt means.)
- Your home directory can also be referred to as
- Try using
ls
. It will list the files and directories.- The
private
directory is where you will do your work. Technically no one else can see your stuff in this VM, but it’s a good habit to use this directory if/when we get thoth back. - Do
ls -a
and you’ll see a lot more files and directories.- The convention is names that start with a period
.
are hidden by default. - The
-a
option tols
means “list all things”.
- The convention is names that start with a period
- The
- Do
cd private
and you’ll move into that directory.pwd
again, and you’ll see that your directory changed.- You can use
cd ..
to move up one directory. - You can use
cd ~
to go to your home directory.
Common UNIX commands
Here’s a quick reference guide to refer back to.
pwd
– display the current directorycd dirname
– change current directory todirname
cd ..
moves up one directorycd ~
goes to your home directorycd
with nothing after it also goes to your home directorycd -
toggles back and forth between the last two directories you were in, very handy
ls
– list all files/folders in current directoryls dirname
will list files/folders in the directorydirname
mv source dest
– move or rename a filesource
is the file you want to move/renamedest
is the new place/name
cp source dest
- copy a file fromsource
todest
mkdir name
- make a new directory namedname
touch filename
- make an empty file namedfilename
cat filename
- display contents of text filefilename
(short for concatenate I guess)less filename
- view contents of text filefilename
- good for longer files- press
q
to exit!
- press
rm filename
- delete (remove)filename
rmdir dirname
- delete an EMPTY directory nameddirname
4. Getting some examples and using gcc
Let’s learn how to use gcc
by getting and compiling some of the examples I’ve given you. Refer to the commands above to follow these instructions.
- Go to your
private
directory. - Make a new directory called
cs0449
, and go into it. - Make a new directory called
examples
, and go into it.- At this point, the current directory should end in
private/cs0449/examples
.
- At this point, the current directory should end in
- Open the course materials page.
- Right-click on
1_hello_world.c
and choose “Copy link” or similar. - In your terminal connected to the VM, type
wget
, a space, and then paste the link you copied:- Windows PowerShell: hit Ctrl+V.
- macOS Terminal: hit ⌘V.
- At this point you should have this command ready to execute:
wget https://jarrettbillingsley.github.io/teaching/classes/cs0449/examples/1_hello_world.c
Hit enter to execute it.
wget
is a command that downloads a file from the internet. In this case, we are telling your VM to download a file from my site directly into your AFS space. Very convenient!- If you get the error
wgethttps://............c: No such file or directory
, you didn’t hit space after typingwget
🙃
- Use
wget
to get the1_cant_add_strings.c
and2_get_line_success.c
examples too.
If you ls
you should see the three .c
files you just downloaded. Try looking at their contents with either cat
or less
!
Now let’s compile.
- Type
gcc 1_hello_world.c
. Wait, before you type that…- Type
gcc 1_he
. Then hit the tab key. It will fill in the rest of the filename for you. - This is called tab completion and it is everywhere in programmer-oriented tools and it saves a lot of time.
- It works on your computer too. No more typing
java MyReallyLongClassName.java
orcd MyReallyLongFolderName
.
- Type
- Hit enter.
- If you did it right, it should print nothing. With UNIX, “no news is good news.” Successful commands will usually be quiet. But if you
ls
, you should now see a new file,a.out
. This is the executable thatgcc
created!
- If you did it right, it should print nothing. With UNIX, “no news is good news.” Successful commands will usually be quiet. But if you
- Run the program by doing
./a.out
(yes, you have to type a period then a slash before it)- It should print “Hello, world!”
- Repeat for the other two examples you downloaded.
- Every time you compile,
gcc
will replacea.out
with the new executable. This might not be what you want. If you want to name the output executable something other thana.out
, use the-o
option togcc
:gcc -o 1_hello_world 1_hello_world.c
The thing you put immediately after
-o
will be the executable’s filename.- Executables on UNIX typically have no file extension, so
1_hello_world
is a perfectly normal name.
- Executables on UNIX typically have no file extension, so
- Every time you compile,
5. Making your own program
- Change to your
~/private/cs0449
directory, then make alabs
directory and go into it. - Run
nano username_lab1.c
, whereusername
is your username. My username isjfb42
, so for me, but NOT for you, oh my god, put YOUR username, not MINE:- ✅
jfb42_lab1.c
- the one and only acceptable filename. - ❌
JFB42_lab1.c
- uppercase is bad. your username is lowercase. - ❌
jfb42_lab01.c
- it’slab1
, notlab01
- ❌
jfb42_rec1.c
- it’slab1
, notrec1
- ❌
jfb42_lab1
- no extension - ❌
jfb_lab1.c
- incomplete username - ❌
jarrett_lab1.c
- that’s not a username - ❌
lab1.c
- no username - ❌ literally anything other than the first thing on this list
- Please follow my lead. It’s not that hard.
- ✅
nano
is a simple text/code editor that runs in the terminal.- At the bottom you will see the key shortcuts listed in a strange way.
^O
means Ctrl+O. (macOS users, this means the key labeled control, not command!)M-U
means Alt+U. (M
is a reference to the meta key from long ago.)- macOS Terminal users: make sure Edit > Use Option as Meta Key is checked. Then you can use Option+U for
M-U
.
- macOS Terminal users: make sure Edit > Use Option as Meta Key is checked. Then you can use Option+U for
- Besides the strange key shortcuts (Ctrl+O saves the file instead of opening one? Cut and paste are Ctrl+K and Ctrl+U???),
nano
works pretty much like any other text editor. - You may be able to scroll with your trackpad/scroll wheel, or you may be forced to use arrow keys and page up/page down.
- At the bottom you will see the key shortcuts listed in a strange way.
-
Type, don’t copy-and-paste, this code into
nano
:// Fake Studentname (abc123) #include <stdio.h> int main() { printf("Hello World!\n"); return 0; }
- the first line of the file should be a comment containing your full name and username in the format shown above.
- You can actually save with Ctrl+S. It should say something like
[Wrote 7 lines]
at the bottom. - Exit with Ctrl+X.
- Compile and run that file.
And there you go.
If you don’t want to have to exit nano
…
You can ssh
into the VM multiple times simultaneously!
Make another tab/window in your Terminal/PowerShell and ssh
into the VM like you did before. cd
into your ~/private/cs0449/labs
directory. Now you can use nano
in one tab, then switch to the other to compile and run. Definitely more convenient.
6. Taking it further
Instead of just being a “Hello world” program, you are going to make your program take some text input, transform it, and then print out the transformed text. When you run your program, it should work like this (the $
lines are the command prompt, you don’t type those):
$ ./a.out
Type something in: this is what the user typed in!
Now in uppercase: THIS IS WHAT THE USER TYPED IN!
$ _
That is, it:
- asks for a line of text
- reads a line of text
- converts it to uppercase
- prints it back out in uppercase
- <that’s it, it’s done, it doesn’t loop, it just exits after one line of text>
So here’s how to accomplish that:
- Edit your lab in
nano
. Remove theprintf("Hello, world!\n");
line frommain
. - Open the
2_get_line_success.c
example file on your computer (like, download it from my site and open it in your code editor), copy theget_line
function out of it, and paste it into your lab innano
abovemain
.- You can really just hit Ctrl+V/⌘+V to paste the code into
nano
. Your terminal program handles it.
- You can really just hit Ctrl+V/⌘+V to paste the code into
- At the top of the program, add
#include <string.h>
so that you can usestrlen()
. - Write a function to uppercase a string. Name it
uppercase
. Here’s how you will implement it:- C has a function
toupper()
in<ctype.h>
, which converts a single character to uppercase. - Your
uppercase
function will take achar*
argument that is the string to uppercase. - It will uppercase the string in-place.
- (That is, it will change the values in the string, not make a new one.)
- Remember when writing your loop that that
strlen()
is aO(n)
function!- You do NOT want to call it once per loop. Otherwise, your loop will be
O(n^2)
. - Put the string’s length into a variable before the loop, and use that in your loop condition.
- You do NOT want to call it once per loop. Otherwise, your loop will be
- C has a function
- Now in
main
, useget_line()
anduppercase()
to get a line of input, uppercase it, and print it out so that your program behaves like the demonstration above.- Make the input buffer
200
characters long, and pass200
toget_line
to tell it how long the input buffer is. - Follow the lead of
2_get_line_success.c
to callget_line
properly.
- Make the input buffer
- Test your program and make sure it works correctly with:
- letters (lowercase letters should become uppercase; uppercase letters should remain the same)
- numbers (should remain the same)
- punctuation (should remain the same)
Before you submit this, let’s take a little break to learn about diagnosing segmentation faults.
7. Finding out where a segfault happened
“Segfault” is short for “segmentation fault” and is one of the more common ways for C programs to crash. C has no exceptions and cannot tell you where the program crashed or for what reason (out-of-bounds index? null pointer? stack overflow? who knows!). So, we must use a debugger to help diagnose the problem.
A debugger is a program that monitors your program as it runs, and lets you do things like:
- pause execution at a specific point so you can see what it’s doing
- step through the program one line of code (or even one assembly instruction) at a time
- look at the values of variables, objects, arrays, etc.
- find out where a crash happened
You’ll be getting much more practice with the debugger in a later lab, but for now, you need to learn how to debug a segfault.
Making a program that segfaults
- In your VM terminal, go into your
~/private/cs0449/examples
directory. - Use
nano
to edit1_cant_add_strings.c
. Changex
from5
to1000000
. - Save and exit. Do
gcc 1_cant_add_strings.c
and ignore the warnings. - Do
./a.out
. It saysSegmentation fault (core dumped)
. There we go!
Finding out where it happened
In order to find where the segfault happened, we actually need to recompile the program, but we need to tell gcc
to include debugging information. This is crucial, because by default the compilation process is “lossy” - all the information about which machine code instructions correspond to which lines of code in the original program is lost, as are variable names and types etc.
- Recompile the program with
gcc -g 1_cant_add_strings.c
. That is, add the-g
flag. - If you run
./a.out
again, nothing has changed, it still segfaults. However… - Now you can run
gdb ./a.out
.gdb
is the GNU Debugger.
It will say a bunch of stuff, and then say:
Reading symbols from ./a.out...
(gdb)
This is now waiting for you to type a command.
- Type the
run
command and hit enter to start running the program. - You will see a message like:
Program received signal SIGSEGV, Segmentation fault. __strchrnul_sse2 () at ../sysdeps/x86_64/multiarch/../strchr.S:32
Segmentation fault! There it is! But this time
gdb
caught it in the act. - Type the
where
command and hit enter.- This prints out a stack trace that shows all in-progress functions at the time the segfault occurred.
- Entries #0, #1, #2, and #3 are all inside the standard library, and aren’t very useful, but…
- Entry #4 says
in main () at 1_cant_add_strings.c:8
- there it is! That’s where, in your code, the segfault is occurring!
At this point, you can use the quit
command to exit gdb
(say y
to kill the program).
To summarize, when you get a segfault:
- Compile your program with
-g
gdb ./programname
run
- When it crashes,
where
, and look at the first entry that is inside your code to find the culprit line.
8. Downloading with scp
Alright, you’re now ready to submit. You will submit your code to Gradescope on Canvas, but right now, your code is still in the VM. To get it out of the VM, we can use the scp
(secure copy) command, which kind of does a cp
over an ssh
connection:
- On your computer, you need to open a second shell window:
- Windows PowerShell: Ctrl+Shift+T to open a new tab
- macOS Terminal: ⌘+N to open a new tab
- In that new terminal,
cd
to the directory where you want to download your lab - Then run this, but with your username instead of
username
:scp -P 10022 student@localhost:private/cs0449/labs/username_lab1.c .
- notice the space and period at the end! that is crucial!
- It will ask for the password like when you used
ssh
; typecs0449
and hit enter - If you typed the filename correctly, it will download the file to the current directory.
Submitting to Gradescope
The gradescope isn’t up yet. It will be soon.
Now your lab is downloaded to your computer, and you can submit it to gradescope:
- Go to the canvas for this course.
- Click Gradescope on the left.
- Click on Lab 1.
- Upload your
.c
file. - Wait for the autograder to run, and it will tell you if there were any issues.
If the autograder says something is wrong with your submission, fix it in the VM, re-download it to your host computer with scp
, and re-submit it as many times as needed to fix the problem.
Note that future assignments may have a limited number (or rate) of resubmissions, so do not rely on the autograder to be your only method of finding and fixing problems!