CSCI 2400: C Programming Exercises


Welcome to C programming! Over the next few days you will have time in class to work on a variety of programming exercises. These exercises will count towards your in-class participation grade. You are expected to turn in all programs from category A, one program from category B, and one program from category C. These will be due the class day before Homework 3 is assigned.

    Category A

  1. "Hello, world!" Program
  2. Basic input/output

    Category B

  3. Approximate pi with a partial sum
  4. Random integers: compute min, max, average

    Category C

  5. Dice Simulator
  6. Bitfield FizzBuzz

Exercises

Create a .tgz archive of your C programs and email it to dferry_submit@slu.edu. Please include your name and the names of any partners in the body of your email.

The simple syntax for creating a .tgz archive is as follows:

tar -zvcf archive_name.tgz your_directory

The syntax for unpacking a .tgz archive is:

tar -zvxf archive.tgz

Note that your archive must not include any binary executable files, meaning any compiled programs or intermediate build objects (.o files, for example). This will cause your email to be rejected by most services.


Exercises

  1. Hello, world!
  2. In this exercise you will create a program that does simple output to the console.

    First we need a Linux environment, so we will remotely connect to the department server at hopper.slu.edu. Alternatively, you can login locally to the classroom machines and do work there. In general you will only ever need Linux terminal access for these exercises, though you're welcome to use NoMachine if you'd like the GUI desktop. If you're using one of the classroom machines and would like to login to Hopper, you can login by typing at a terminal:

    ssh username@hopper.slu.edu

    Make a new directory for this class with the command mkdir 2400, then change to that directory with the command cd 2400

    First, open a new file called 'hello.c' in the text editor of your choice. At the top of your file include some comments indicating your authorship and the purpose of the program. Then, include the standard input/output header file with the line:

    #include <stdio.h>

    Next, create the entry point for your program, which is a function called main, your main function should almost always look like this:

    int main( int argc, char* argv[] ){
       //Your code goes here
    
       return 0;
    }
    

    The argc and argv parameters are used to get program arguments from the command line. We'll use them in a bit. Also notice that your program returns an integer. This is the return value of the program- returning zero indicates the program terminated normally, while a non-zero value indicates the program quit because of an error.

    Next, insert the output statement inside your main function:

    printf("Hello, world!\n");

    You can now compile and run your program with the commands:

    gcc hello.c -o hello

    ./hello

    Your program should print the string "Hello, world!" to the console. If it doesn't, ask the instructor for help.

    Next, modify your program so that it prints out the array called argv. To do so, you will need to use a for loop. The input argument argc tells you how many elements are in argv, and recall that in C that arrays are zero-indexed. Also, beware that the first element of argv is always the name of the program that is being run. Thus, if you executed your program as such:

    ./hello abcd 123 45.5

    Then argv would have the string values:

    argv[0] = "hello"
    argv[1] = "abcd"
    argv[2] = "123"
    argv[3] = "45.5"
    

    For now, we just want to print out each argument in turn. For example, if you ran your program with the above arguments it should print out something like:

    Hello, world!
    Argument 0 is 'hello'
    Argument 1 is 'abcd'
    Argument 2 is '123'
    Argument 3 is '45.5'
    

    You can do this by calling the printf() function like so:

    printf("Argument %d is %s\n", index, argv[index]);

    The "%d" and "%s" are called format specifiers, and the first one specifies that an integer is going to be printed at that location, while the second one specifies that a string is going to be printed at its location. The second parameter to printf (which is index above) matches the first format specifier, the %d, while the second parameter matches the second specifier. You can see the full documentation by typing man 3 printf at a terminal, but it's probably easier to look up examples online.

    Write a for loop that prints out all arguments of your program. Then run your program a few times with different sets of arguments to make sure that it runs the way you think it should.


  3. Basic input
  4. Write a program that takes a single argument, converts it to an integer with the strtol() function, and casts that value to an unsigned char. Then, print out both the signed and unsigned values. The output should look something like:

    Signed representation: -1, unsigned representation: 255

    The function strtol() converts a string to an integer, and can be used by calling:

    int input = strtol(argv[1], NULL, 10);

    Which specifies that the string to convert is argv[1], and to use a base-10 number system. The second parameter is for extra functionality we don't need for this program.

    You can cast an integer to an unsigned char simply by assignment. E.g.:

    unsigned char output = input;

    Remember that an unsigned char is an 8-bit data type. What happens when you pass a negative number to your program? What happens when you pass a number above 255 to your program? Can you confirm that this is what should happen by looking at the numbers binary representation?


  5. Approximate pi
  6. The value of pi can be approximated by evaluating a partial sum of the form:

    Write a program that sums up the first N places of this expression, where N is given as a command line input. Use strtol() to convert the input to an integer as in the previous exercise.

    Be careful of the difference between integer division and floating point division:

    double x = 1/5;           //Integer division, value of x is 0
    double x = 1.0/(double)5; //Floating point division, value of x is 0.2
    

    In the second statement the one is explictly given to be a floating point number by including the decimal point, and the integer five is cast to be of type double.

    You can print out a floating point number with the statement:

    printf("My value of Pi: %0.5f\n", myPi);

    Note that the format specifier for floating point numbers is %f, and the 0.5 specifies that the function will print five places after the decimal point.

    Run your program for values of N equal to 1, 10, 100, 1000, etc. You should see the value converging to pi, which is:

    3.141592653589793...


  7. Random array: min, max, average
  8. The rand() function will generate random non-negative integers. Write a program that takes as command line arguments an integer N and S, seeds the random number generator with the value S, generates N random integers, and then prints the minimum, maximum, and average of all values generated.

    You can seed the random number generator with the function srand(), which determines the sequence of random numbers generated. Be sure to include the header file stdlib.h for both rand() and srand(). See the man pages (man 3 rand and man 3 srand) for details.

    Be careful of floating point division versus integer division! You can print out a floating point number with the statement:

    printf("Average: %0.5f\n", avg);

    Hint: If you'd like a sequence to test your code, you can use the following numbers:

    1 1 2 3 5 7 9 16 25
    min:     1
    max:     25
    average: 7.666 repeating
    

  9. Dice simulator
  10. If you roll a six-sided dice the probability of any value between 1 and 6 coming up is exactly 1/6. If you roll a pair of six sided dice then the odds of getting a combined two is not the same as getting a combined ten- there's a 1/36 chance of rolling a two, but there's a 3/36 chance of rolling a combined 10. This is a situation that's not obvious to analyze but easy to simulate!

    Write a program that takes two command line inputs, N and D. Your program should simulate N throws of D dice, and then print the experimentally observed probability of each combination. For example, if N=50 and D=5 then you would simulate 50 throws of 5 dice. If you saw the number 14 show up 3 times, then the observed probability of 14 would be 3/50.

    In general, the observed probability of a number X is:

    (number of times you saw X)/N

    Hint: The maximum possible value from thowing D dice is D*6. You can declare an array of length D*6 with the line:

    int *array = malloc( D*6*sizeof(int) );
    

    Hint: The rand() function generates non-negative integers. Use the modulus operator (%) with rand() to generate a single random dice roll like so:

    one_dice = rand()%6 + 1;


  11. Bitwise FizzBuzz
  12. FizzBuzz is a miraculous and/or awful test of programming proficiency. (Look it up and read the internet comments... trust me.) This is FizzBuzz with a twist.

    Write a program that takes a 32-bit integer N, and for each bit in N do the following (starting with the least significant bit):

    Also, separate every four bits by a space, to make the output readable. As an example, if you gave your program the number 16405, which has the binary representation

    0000 0000 0000 0000 0100 0000 0001 0101
    

    Your program should print

    0000 0000 0000 0000 0FB00 0000 000B 0F01
    

    Notice that the bit in place 1 is printed as a 1 because place 1 is not divisible by either 3 or 5. However, the bit in place 3 is printed as F, because 3 is divisible by 3. Note also that the bit in place 15 prints FB because 15 is divisble by 3 and 5.

    Hint: You can get the value of the first place by doing a bitwise AND with 1, or the value of the last place by doing a bitwise AND with 0x80000000 (or 2147483648 in decimal) e.g.:

    int X = input;
    printf("%d", X&0x1); //Prints 1 if first bit is 1, 0 if first bit is 0
    printf("%d", X&0x8000000); //Prints 1 if last bit is 1, 0 if last bit is 0
    

    Hint: Also consider using bit shifts. First write a program that prints out each bit of the input correctly, then add the FizzBuzz functionality.