ExerciseFocus
0. printingprintf format specifiers, arithmetic expressions, and writing a complete C program from scratch.
1. printf-widthWidth fields in printf and controlling minimum field widths for formatted output.
2. printf-precisionPrecision fields in printf and formatting integer and floating-point output.
3. Coupon DiscountBuilding a multi-step calculation using integer arithmetic.
4. Image Effect 1Applying conditionals and integer arithmetic to transform RGB pixel values.

Getting Started

0. printing

Focus

printf format specifiers, arithmetic expressions, and writing a complete C program from scratch.

Introduction

In the lecture, we went through examples of writing program output using the printf function. To print the value of a variable, we use format specifiers, such as %d for integers and %f for floating-point values.

For example:

#include <stdio.h>
 
int main(void) {
    double a = 1.4;
    int b = 5;
 
    printf("a: %f\n", a);
    printf("b: %d\n", b);
}

This exercise also gives you practice with arithmetic expressions and integer division.

Your Task

student.c is empty. Write the whole program from scratch. Print each result on its own line, in this order:

  • 1.0 + (1.0 / 3.0) as a floating-point value
  • 1.0 + (1 / 3) as a floating-point value
  • 19283745 using %d
  • 19283745 using %x
  • 19283745 using %b

The %b conversion specifier requires the newer C library environment provided by the course WebTop. Your program should produce five lines of output.

Pay particular attention to the difference between 1 / 3 and 1.0 / 3.0, and to the last three representations of the integer. You can refer to the man pages if you want to investigate the format specifiers further.

Running

  • To compile, run make
  • To run, run ./printer
  • To test, run make test

Intent

This exercise is intended to help you get used to writing small programs from scratch, including importing headers, defining main, and writing the required program behaviour. Later in the course, you will often modify parts of larger programs, but writing complete small programs is still a useful skill.


1. printf-width

Focus

Width fields in printf and controlling minimum field widths for formatted output.

Introduction

In the lecture, we showed a few basic ways to print integers and floating-point values. There is a lot more that we can do with printf, so let’s explore the width modifier.

Recall that to print an integer of type int and a floating-point value of type double, we can write:

#include <stdio.h>
 
int main(void) {
    int a = 5;
    double b = 3.141;
 
    printf("%d\n", a);
    printf("%f\n", b);
}

Think of d and f as conversion specifiers. To specify a minimum field width, write the width between % and the conversion specifier. For example, printf("%5d", a); uses a minimum width of 5 for an integer, while printf("%2f", b); uses a minimum width of 2 for a floating-point value.

Padding With Spaces on the Left

If a has value 123 and you write printf("%5d", a);, printf adds two spaces on the left so that the field is at least five characters wide. The width is a minimum, so a value wider than the requested width is not truncated.

By default, values are padded with spaces on the left. The left-adjustment flag can be used to pad with spaces on the right, but that is not required for this exercise.

Your Task

In student.c, define and declare a variable a with value 12345. Print two lines, each ending with a newline:

  • The first line should print a without any other specifiers
  • The second line should print a with a width of 10

Running

  • To compile, run make
  • To run, run ./printer
  • To test, run make test

2. printf-precision

Focus

Precision fields in printf and formatting integer and floating-point output.

Introduction

In the lecture, we showed a few basic ways to print integers and floating-point values. There is a lot more that we can do with printf, so let’s explore one of its many features.

The precision modifier tells printf how to print numbers. For integer values, it sets the minimum number of digits. For floating-point values, it sets the number of digits after the decimal point.

Recall that to print an integer of type int and a floating-point value of type double, we can write:

#include <stdio.h>
 
int main(void) {
    int a = 5;
    double b = 3.141;
 
    printf("%d\n", a);
    printf("%f\n", b);
}

Think of d and f as conversion specifiers. To specify precision, write a period followed by a number between % and the conversion specifier. For example, printf("%.5d", a); uses a precision of 5 for an integer, while printf("%.2f", b); uses a precision of 2 for a floating-point value.

According to man 3 printf, precision gives the minimum number of digits for integer conversions and the number of digits after the decimal point for f conversions. Thus, printf("%.3d", 15); prints 015, while printf("%.2f", 3.141); prints 3.14.

Variable Precision

You can also store the precision in a variable. To print a floating-point value with a precision stored in prec, write:

#include <stdio.h>
 
int main(void) {
    int prec = 5;
    double pi = 3.141;
 
    printf("%.*f\n", prec, pi);
}

The * tells printf to read the precision from the argument before the value itself.

Your Task

In student.c, define and declare these two variables:

  • a, a double with value 3.141
  • b, an int with value 5

Your program should print five lines, ending with a newline:

  • The value of a without a precision specifier
  • The value of a with precision 2, using an explicitly written precision
  • The value of a with precision 5, using variable precision syntax
  • The value of b without a precision specifier
  • The value of b with precision 2

Running

  • To compile, run make
  • To run, run ./printer
  • To test, run make test

Note

The bonus exploration in the source exercise asks you to investigate what happens when a variable precision is used with an incompatible argument. It is not part of the submission requirements.


3. Coupon Discount

Focus

Applying specifications step by step

Introduction

Let’s try writing a simple program that does some computations about coupon applications (as a follow up to the first lecture).

Your Task

Note

We’ve set up a program that reads one integer price from $0 to $1,000,000. Apply the following rules to the price:

  1. Apply a voucher whose min-spend is $50, which applies a discount of 20% of the price of the product, but this discount is capped at $20.
  2. The discount amount should be based on integer arithmetic.
  3. After subtracting the discount from the original price, apply 19% GST (woah!) to the discounted price using integer arithmetic.
  4. Print the final price.

Open student.c. Implement the required behaviour by writing the code indicated below the line.

Running

  • To compile, run make
  • To run, run ./coupon
  • To test, run make test

Inputs are validated for you. To add test cases, create a file named [your file name here].in in test/test_cases. The file should contain an input value you want to use to test your program:

[input value here]

For example, to test the program with an input price of 888, create a.in with:

888

Create a matching a.out containing the expected result:

1032

Only add code in the area specified

Only add code below the comment that says to add code below the line. If you somehow mess up this file, you can use the menus within the cs1010 command to reset just this exercise.

4. Image Effect 1

Focus

Just a little bit of fun with what you already know after week 1.

Introduction

Have you ever wondered how certain image effects (or “filters”) are computed?

Your Task

Here’s an interesting idea that you’re going to be a part of. We’re going to have you write a small snippet of code which happens to be the core logic for a simple image effect.

Pixels

Have you ever wondered how images are represented? You can think of an image as a rectangular grid of RGB values (red green blue). It’s actually a little more complicated than that but a good enough explanation for our purposes.

Basically, for a screen display, any colour is just a blend of some amount of Red, Green, and Blue colours. So, typically, a pixel is represented as a triplet where the values range between 0 and 255. Think of 255 as full brightness at 100%, and 0 as 0%. So something like means full brightness from all 3 colour channels, which turns out to give us white. This also means the three pixels , , and just give you the “purest” possible red, green, and blue. Any other pixel like or is just a blend of the three colours.

It turns out it’s actually really complicated IRL but essentially that’s what it boils down to.

Effect and Design

Let’s look at the before and after of this image.

Before:

After:

…maybe I shouldn’t have used the Mona Lisa as an example image…

We’re going to try to figure out the exact step-by-step process behind the pixel transformations above, and then reproduce it. Don’t worry about how to read or parse image files, we’ll do that for you. All you have to understand is what a pixel is.

You might notice that the brighter pixels get turned a blue-ish colour, and the darker ones turned black. So at least right now, the first thought might be:

“If a pixel is bright enough, we will set it to some blue RGB value. Otherwise, we will set it to black.”

For the sake of simplicity, let’s just pick some RGB values right now.

“If a pixel is bright enough, we will set it to . Otherwise, we will set it to .”

The next step is to figure out how “bright” a pixel is based on its RGB values. Intuitively, being “pure white”, should be the brightest. And being “pure black” should be the darkest. But what about other colours in between?

We’ll use one possible measure for this idea that we’ll call luminance ():

Source

Since and the values for range from 0 to 255, this means also takes on a value within the range to .

Great! We now have a measure of “brightness” to use. So let’s try to refine our condition to be a little more precise. Our rule is now: if a pixel is 50% or brighter, then we will set it to our coloured pixel . Otherwise, set it to black.

Since the luminance ranges from 0 to 255, we could say as long as the luminance is 127 or below, then we will set the pixel to black. Otherwise, set it to .

You can now look back at the image and see how this might give us the effect we want.

Code Structure

We’ve set up a simple program for you in student.c that reads three comma separated numbers within the range 0 to 255 and treats them as the RGB values for a single pixel.

If you implement the logic correctly, the program will decide based on the luminance of the input pixel value, whether to make it a black pixel or a blue pixel, then output the resulting pixel value.

What You Should Do

Open student.c and write your code where specified to implement the rule above.

Running

  • To compile, run make pixel
  • To run, run ./pixel
  • To test, run make test

Inputs are validated for you. To add test cases, create a file named [your file name here].in in test/test_cases. The file should contain three comma-separated RGB values:

[r value],[g value],[b value]

For example, to test pixel with an input pixel of 127,50,200, create a.in with:

127,50,200

Create a matching a.out containing the expected result:

0,0,0

Explanation: The pixel is too dark to be turned into a blue pixel, so it’ll be set as black.

Bonus (Ungraded)

When you’re ready, you can then open up pixel_effect.h instead and write the same code you just did into the location shown in the file. You will then have a program that applies the effect to entire uncompressed 24-bit .bmp images.

Why BMP

Why .bmp? Because other image formats are hard to parse. 😭

Opening the Included Sample Image

The exercise already includes mona-lisa.bmp, an uncompressed 24-bit BMP. In the WebTop terminal, first change to the 4-image-effect-1 exercise directory, then open the image with WebTop’s default image viewer:

open ./mona-lisa.bmp

This opens the image using feh, the image viewer installed in WebTop. Press q while the image viewer is focused to close it and return to the terminal. You can also invoke the viewer directly with feh ./mona-lisa.bmp.

Applying and Viewing the Effect

Compile the full-image program, apply the effect, and open the result:

make effect
./effect mona-lisa.bmp my-effect.bmp
open ./my-effect.bmp

The input and output filenames must be different. To use another image, place an uncompressed 24-bit BMP in the exercise directory and replace mona-lisa.bmp with its filename.

Downloading More Images

For more images to experiment with, download these files from John Burkardt’s BMP sample collection:

wget -O three-colours.bmp https://people.math.sc.edu/Burkardt/data/bmp/bmp_24.bmp
wget -O snail.bmp https://people.math.sc.edu/Burkardt/data/bmp/snail.bmp

Both are uncompressed 24-bit BMPs that work with the provided full-image program. For example:

./effect snail.bmp snail-effect.bmp
open ./snail-effect.bmp

This is ungraded, so feel free to experiment with manipulating pixels however you like. You could try creating a negative, converting the image to grayscale, or accentuating one colour more than the others.1

Footnotes

  1. (Instagram filters are kind of like this) ↩