Lab: Arrays

This lab introduces the array data structure, one of the fundamental ways we organize collections of values in a computer program.

To get started with this lab, download the archive file arrays.tar.gz. Run the following shell commands to unpack it:

$ cd csc161/labs
$ tar xvzf ~/Downloads/arrays.tar.gz
$ cd arrays

The .tar.gz file is a compressed archive that contains multiple files, a bit like the .zip files you may have used on other computers. The files in a .tar.gz archive will generally be contained within a directory, which in this case was named arrays.

A. One-dimensional Arrays

Open the max-min.c file you unpacked in the previous step and read through it. Once you’ve reviewed the code we will compile it, but we’ll do that a little differently this time. We’re going to use a tool called make to compile our code for this lab. Just run this command in the terminal:

$ make max-min 

Any time you edit a source file you can run make in the terminal to recompile it. The make tool will skip unnecessary compilation steps; if you run make again without editing a source file it won’t do anything. The rules that tell make how to compile code are in a file named Makefile. We’ll spend time later in the semester learning how to create Makefiles, but for now, you can trust that it will just work for your lab.

Now that you’ve compiled the code, run the max-min program in the terminal as you normally would:

$ ./max-min

Exercises

The exercises for this part will run through a series of changes you’ll need to make to the max-min.c source file. Make sure you save the changes you make in VSCode and run make in the terminal to update the build each time.

  1. What happens if you change the LENGTH constant to 5? Make a prediction, then check your prediction by compiling and running max-min.
  2. What happens if you change the LENGTH constant to 12? Make a prediction and check it by compiling and running the code.
  3. What happens if you modify the loop that prints the array to start at a negative index? Make a prediction, then check by compiling and running.
  4. What happens if you modify the loop that prints the array to read beyond the end of the array (e.g. access index LENGTH+2)? Make a prediction, then check by compiling and running.

B. Writing and Reading Arrays of Characters

For this part of the lab, you will write a program that reads a message from the user one character at a time and then prints the characters back in reverse order. Here is an example run of a completed implementation:

$ ./reverse
Enter a message: Don't get mad, get even.
The reversed message is: .neve teg ,dam teg t'noD

Your implementation should read one character at a time using the getchar() function, up until you read either a newline character ('\n') or the message reaches 100 characters. You should use a #define constant to set the message length limit to make your code clearer and easier to update. The easiest way to print the reversed message is to print one character at a time by looping over the array; reordering the characters in the array is a lot more work, and it’s not required!

Caution: the getchar function likely will not receive any characters until you hit enter. Don’t be alarmed if you need to press enter to send the input to the program. Just make sure the reversed message only includes 100 characters.

Exercises

  1. Complete your implementation in reverse.c. You can run make to compile it any time you change the code.
  2. Test your implementation. Make sure you try very short messages and very long messages (up to the limit) in addition to the common case.

C. Variable-Length Arrays

We’ll often need to store data of unknown length, but that poses a problem when we need to write down the length of an array in our code. Luckily, C allows us to create arrays with lengths determined by a variable instead of an integer constant:

// Here's an array with a length known at compile time
int arr1[10];

// And here's an array whose length is determined by a value we only know at runtime:
int n;
scanf("%d", &n);
int arr2[n];

In the example above, arr2 has a length that we can determine at runtime. This can be dangerous though; consider what could happen if the user enters a negative number. The solution is to check user inputs before using them, especially when user inputs affect the size of an array or the index of an access into an array.

Exercises

  1. Copy your implementation from reverse.c into reverse-variable.c and run make to be sure the code compiles.
  2. Update your implementation in reverse-variable.c so it first prompts the user for a message length. Create a variable-length array long enough to hold that message, read it in, and print it in reversed order.

D. Two-Dimensional Arrays

C also allows us to create multi-dimensional arrays; we’ll look specifically at two-dimensional arrays, but you can add more dimensions if you have data you want to access with more than two indices.

The face.c program includes a two-dimensional array that you should print out to the terminal. Each row of the array is a line of characters to print. When you print it exactly as the array is stored, you will see the following (slightly creepy) output:

$ ./face
                   __ooooooooo__                   
              oOOOOOOOOOOOOOOOOOOOOOo              
          oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo          
       oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo       
     oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo     
   oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo   
  oOOOOOOOOOOO*  *OOOOOOOOOOOOOO*  *OOOOOOOOOOOOo  
 oOOOOOOOOOOO      OOOOOOOOOOOO      OOOOOOOOOOOOo 
 oOOOOOOOOOOOOo  oOOOOOOOOOOOOOOo  oOOOOOOOOOOOOOo 
oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo
oOOOO     OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO     OOOOo
oOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OOOOOOo
 *OOOOO  OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO  OOOOO* 
 *OOOOOO  *OOOOOOOOOOOOOOOOOOOOOOOOOOOOO*  OOOOOO* 
  *OOOOOO  *OOOOOOOOOOOOOOOOOOOOOOOOOOO*  OOOOOO*  
   *OOOOOOo  *OOOOOOOOOOOOOOOOOOOOOOO*  oOOOOOO*   
     *OOOOOOOo  *OOOOOOOOOOOOOOOOO*  oOOOOOOO*     
       *OOOOOOOOo  *OOOOOOOOOOO*  oOOOOOOOO*       
          *OOOOOOOOo           oOOOOOOOO*          
              *OOOOOOOOOOOOOOOOOOOOO*              
                   ""ooooooooo""                    

Exercises

  1. Go to the bottom of the main function and add code to print out the face array, just as it is shown in the example above.
  2. Now, add a second loop that prints the face upside-down.
  3. Add a third loop that prints the face transposed, so the eyes are on the right and the smile is on the left. Transposition isn’t the same as rotation, but the result will look a bit like the image was rotated 90 degrees clockwise. Optional: You can print spaces in some strategic locations to account for the fact that characters in the terminal are not square.