C Introductory Lab 2

Table of Contents

This assignment is to be done individually. You can talk to other people in the class, me (Dave), and any of the course staff (graders, lab assistants, teaching assistants, prefects) for ideas and to gain assistance. You can help each other debug programs, if you wish. The code that you write should be your own, however, and you shouldn't directly share your code with others. See the course syllabus for more details or just ask me if I can clarify.

1 Get started

1.1 Use GitHub classroom to create a repository for your assignment

The first thing you'll need to do is to create a repository for your project using GitHub classroom. Visit this GitHub classroom link (which I've placed in Moodle). Log into GitHub if need to. GitHub should then hopefully respond with a screen that says "You're ready to go!" and will supply you with a link for the repository that you are creating. Click on that link, and you should be taken to the repository.

1.2 Clone your repository into Repl.it

Since this is an individual assignment, you'll again use the my-work repl in Repl.it that you created. In Repl.it, start up your my-work repl, and then make sure that you are in your home directory in the terminal window. You can always navigate there by typing

cd ~

in the terminal window. To further confirm, type pwd (which is short for "print working directory.") You should see /home/runner. If you see something different, you're not in the home directory, so try again or ask for help.

In a different browser tab (leave the one with Repl.it open), visit our our class GitHub organization page online. Once you've landed there, you should see the GitHub repository you created in the GitHub Classroom step above. It should be named c-lab2-username (where username is your username). Contact us for help if the repository isn't there. Click on that repository title. This should take you to the home page for that repository. There is a green box on the page that says "Clone or download." Click that box, and make sure it says "Clone with HTTPS." Highlight the https link shown, and copy it to the clipboard. The link that you're copying should look something like

https://github.com/carleton251-term/c-lab2-username.git

… though your username and term will be different.

Then navigate back to the Repl.it tab with the repl that you created above, and click on the terminal window within your new repl. Your next step is to clone the repository from GitHub. To do that, type git clone, then a space, then paste in the URL from the github page that you copied from above. (To paste, you might need to right-click in the terminal window and choose paste rather than using a keyboard shortcut.)

For example, I would type the following, though your username and term will be different:

git clone https://github.com/carleton251-term/c-lab2-username.git

You'll be prompted to enter your GitHub username and password.

If all goes well, you should receive a directory, titled c-lab2-username. If you type ls at the prompt, you should be able to see it. It will also appear in your file browser window with Repl.it on the left. Then navigate into that directory by typing in:

cd c-lab2-username

… and you should be all set to work.

2 Your tasks

2.1 Guess a number

EXERCISE 1: Write a program guess.c that picks a random number between 1 and 100 and has the user repeatedly guess the number in a while loop. For random numbers, use the random function. Here is a sample usage:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

...
unsigned int seed;
scanf("%u", &seed);
srandom(seed);
//srandom((unsigned int)time(NULL));
int randNum = random()%100 + 1;

Note that with the above approach, you'll produce the same random number every time you run your program, based on the seed. That's good, as it allows our testing code to work reliably. That said, I've shown commented code above that you can use just for fun that lets you pull the random number seed from the system clock, rather than based on user input.

A run of your program might look like this:

Enter a random seed: 112233
Guess a number: 50
Too high!
Guess a number: 37
Too low!
Guess a number: 43
Too high!
Guess a number: 40
Too high!
Guess a number: 39
Correct! Total guesses = 5

Add, commit, and push to GitHub when complete.

2.2 Arrays

You can declare an array in C by giving the type and size of the array. See arrays.c for a sample program: an explanation of some of it follows here.

int array[10];

This allocates space (on the stack) for an array containing 10 integers.

Like Java, you can read and write elements of the array using [] notation.

for (int i = 0; i < 10; i++) {
    array[i] = i;
}

Unlike Java, there's no reasonable way to find out the length of an array, so you need to keep track of an array's length yourself. And if you write past the end of an array, there's no check or "out of bounds error" - it will just modify whatever happens to be next in memory! Try uncommenting the line:

array[10] = 5;

in arrays.c and observe how the value of x changes. Note that clang issues a warning that you're doing a bad thing, which you are, but the program should still run. What does this imply about the layout of the variables in memory? (Make sure that you are executing this on Repl.it; if you're using a Mac and compiling it locally somehow, you won't see the issue. This is forcing a bug to happen in a way that's platform dependent.)

EXERCISE 2: Add code to arrays.c to calculate the sum of the array and print it. Add, commit, and push to GitHub when complete.

2.3 Pointers

The variable array is actually a pointer to the first element of the array. A pointer is a special type containing the address in memory of some data. You can use pointer arithmetic to access the elements in the array.

printf("Array address: %p\n", array);
for (int i = 0; i < 10; i++) {
    printf("Array element at address %p: %i\n", array + i, *(array + i));
}

Here the expression array + i gives the address of the i-th element in the array. The expression *(array + i) retrieves the integer value stored at that address.

Here's a quick summary of C's basic pointer operations (we'll discuss more). &E evaluates to the address of an expression E. *p gives the value stored at the location pointed to by p. p must have a pointer type, indicated by a * in the type declaration. For example, int * is the type representing a pointer to an int. So if p has type T *, then *p has type T.

As an example, read and then run the program pointers.c. Try drawing the execution of the program on paper, with boxes for memory locations and arrows for pointers. Can you see how we end up with the final values for a and b? Hopefully it also makes more sense why we pass arguments to scanf using the & operator.

EXERCISE 3: If you declare two variables in a row, i.e. a and b, does the second one have a higher memory address, or a lower one? Add an "if" to your code to determine if the memory address for b is higher or lower than the one for a. If it is higher, print "higher" to the screen; otherwise, print "lower".

Add, commit, and push to GitHub when complete.

2.4 Structs

C does not have classes or objects. However, you'll often run into situations where you want to group related values together. For this purpose, you can create a struct, a special kind of user-defined type.

Structs are defined using the keyword struct, a name for the struct, and a list of member variables within curly braces. For example, here's a struct to represent a student (see student.c for the full code listing):

struct Student {
    char *first_name;
    char *last_name;
    int id;
};

You can create an instance of a struct type by declaring it with the struct keyword, and access member variables using the dot (.) operator. See student.c for details.

EXERCISE 4: Create a new file complex.c. In this file, add a struct type struct Complex containing two doubles representing the real and imaginary parts of a complex number. Invite the user to enter in two complex numbers, and then display their product. Note that if you have two complex numbers \(c_1\) and \(c_2\) whose real parts are \(a_1\) and \(a_2\) and whose imaginary parts are \(b_1\) and \(b_2\), respectively, then the real part of their product is \(a_1 * a_2 - b_1 * b_2\), and their imaginary part is \(a_1 * b_2 + a_2 * b_1\). Include code testing your multiplication function in main. Here is a sample run, which you should match to make sure you pass the tests:

Enter real part of c1: 2
Enter imaginary part of c1: 5
Enter real part of c2: 3
Enter imaginary part of c2: 4
Answer =     -14.00 +      23.00 i

To get the output looking like I did with two decimal places, here's how I did it:

Complex c3 = multiplyComplex(c1,c2);
printf("Answer = %10.2f + %10.2f i\n", c3.real, c3.imaginary);

Commit and push to GitHub when complete.

3 How to test and submit your work

Go back and look at the sections at the end of Scheme Lab 2 labeled "How to test your work" and "How to submit your work." Those should apply identically here, with the single change that you have multiple files that you have added, and you have been committing them as you go. Follow those instructions, and you should hopefully be all set.