Back to main

Prep lab 5 for C programming

Exercises:

Exercise 12: Combining variables with struct

Background

You may have noticed that functions can only return one variable. But what if want to return more information than we can hold in one variable? The answer is to pack multiple variables together into a single structure.

This creates a new type of variable which contains a number of fields. In this section's example, we create a new type of variable called struct SquareData. We can declare this just like other variables -- instead of writing int or float, we write struct SquareData.

After we have declared a variable of this type with:

struct SquareData mySquare;

we can access its fields with mySquare.side, mySquare.area or any other field name after the period.


Returning a struct is a modern addition to the language. It was not supported in the original C standard in 1972, but was added in the ANSI C standard (also sometimes known as "C89" or "C90"). Some very old compilers might not support ANSI C. We will see another way to return multiple values in a few weeks.

Technical details

Structure:

#include <stdio.h>

struct SquareData {
  float area;
  float perimeter;
  int side;
};

struct SquareData calcSquare(int x) {
    struct SquareData mySquare;

    mySquare.side = x;
    mySquare.perimeter = 4*x;
    mySquare.area = x*x;

    // we need to return this to main()
    return mySquare;
}

void printStuff(struct SquareData mySquare) {
    // this is not useful here, but it works
    float areaBAD = mySquare.area;

    printf("The square's sides are ");
    printf("%i units long, ", mySquare.side);
    printf("and thus has \nan area of ");
    printf("%f units, and ", areaBAD);
    printf("a perimeter of ");
    printf("%f units.\n", mySquare.perimeter);
}

int main() {
    struct SquareData square;
    square = calcSquare(2);
    printStuff(square);
    getchar();
}
The syntax of a struct is a bit confusing. Make sure that you follow the example carefully when you use them. Be particularly careful about the final semicolon ; after the struct definition's final }, and about adding struct in front of the structure's name.

Here's another example of struct:

#include <stdio.h>

struct TimeData {
  int total_minutes;
  int hours;
  int minutes;
};

struct TimeData calcTime(int day_minutes) {
    struct TimeData time;

    time.total_minutes = day_minutes;
    time.hours = day_minutes / 60;
    time.minutes = day_minutes % 60;

    return time;
}

void printTime(struct TimeData myTime) {
    printf("It has been ");
    printf("%i", myTime.total_minutes);
    printf(" minutes since midnight.\n");

    printf("The time is therefore ");
    printf("%02i:", myTime.hours);
    printf("%02i ", myTime.minutes);
    printf("o'clock.\n");
}

int main() {
    struct TimeData time;
    time = calcTime(123);
    printTime(time);
    time = calcTime(1234);
    printTime(time);
    getchar();
}

Your task...

Vending machines use simple programs to calculate the amount of change to return. For a machine, the coins are dispensed mechanically. In our program, we will output the numbers to the screen, looking something like this:

Customer gave 10 pence, item(s) cost 7 pence.
Give customer:
£2      £1      50      20      10      5       2        1
0       0       0       0       0       0       1        1

Customer gave 70 pence, item(s) cost 56 pence.
Give customer:
£2      £1      50      20      10      5       2        1
0       0       0       0       1       0       2        0

Customer gave 200 pence, item(s) cost 124 pence.
Give customer:
£2      £1      50      20      10      5       2        1
0       0       1       1       0       1       0        1

Customer gave 2000 pence, item(s) cost 1232 pence.
Give customer:
£2      £1      50      20      10      5       2        1
3       1       1       0       1       1       1        1

Write a program that calculates the amount of coins to return.

Before you begin, figure out the math on paper. Show your formula(s) to a lab demonstrator before you start programming.


(optional: try using float (storing pounds, not pence) to program your vending machine. Can you make it give accurate results?)

... show your work to a demonstrator


Exercise 13: Bit manipulation

Background

As engineers, you will (or should at least!) have more interest in bitwise manipulation than most other programmers. Writing software that controls lights, reacts to flipped switches, and generally anything that interacts closely with hardware will require bitwise operations. The main concepts here are flags and bitmasks (commonly known as "masks).


A flag is a particular bit with a special meaning. For example, when representing negative numbers, the 8th bit could be thought of a flag which indicated whether the remainder of the bits should be interpreted as a positive or negative number.


A bitmask is a way of accessing a particular bit (generally, but not always, a flag). The bitmask is a number which has 0 in all bits we don't care about, and a 1 for the bit(s) that we want to examine. By anding the bitmask with the original number, we can "extract" the bit(s) -- if that bit was 0, then the new number will be completely zero; if the bit was 1, then the new number will be non-zero.

The same operation is done in reverse to set a flag -- by oring a bitmask and the data variable, we can set a flag to be true. Setting a flag can be done by anding the variable with the noted bitmask.

Technical details

Various bitwise operations:

#include <stdio.h>

int main() {
    char x = 0x10; // number in hex
    char y = 63;

    printf("char is a one-byte number.  ");
    printf("Printing it with %%c will treat ");
    printf("it as\nan ASCII value, but we ");
    printf("can also print it as a number: ");
    printf("x=%i y=%i.\n", x, y);

    printf("Some operations: ");
    printf("%i\t%i\n", ~x, ~y);
    printf("%i\t%i\t%i\n", x&y, x|y, x^y);
    getchar();
}

Toggling individual bits:

#include <stdio.h>
#include <stdlib.h>  // extra includes!
#include <time.h>

float getRand() {
    return rand() / (RAND_MAX+1.0);
}

int main() {
    srand( time(NULL) ); // init random
    char x = 0;
    char bit, bitmask;
    int i;

    // Building a bitwise random number
    for (i=0; i<8; i++) {
        // set bit as 1 or 0?
        if (getRand() > 0.5) {
            bit = 1;
        } else {
            bit = 0;
        }
        // get bit ready
        bitmask = bit << i;
        // or them together
        x = x | bitmask;
        printf("After round %i, ",i);
        printf("bit is %i, and ", bit);
        printf("x is %i.\n", x);
    }
    getchar();
}

Your task...

Dougie Dog has invented an "encryption" technique to keep secrets from the Ferocious Kittens. Fortunately, cats are extremely intelligent, and have cracked the simple code:

  1. Letters are grouped into pairs. Add a space to the end of the string if necessary to give it an even number of characters (here "character" means char.
  2. Make an int from each pair by sticking the bits from the first letter in front of the bits from the second letter. You may assume that we are using 8-bit ASCII.
  3. XOR the result with 31337.

Here's two examples of encryption: "cats" and "kittens".

  1. Pairs: "ca ts"
    "ki tt en s_" (_ represents a space)
  2. into ints: 25441 29811
    27497 29812 25966 29472
  3. XOR with 31337: 6408 3610
    4352 3613 7943 2377

Decryption is performed with the same steps, but in reverse order.

... show your work to a demonstrator

Back to main


Creative Commons LicenseUnless otherwise noted, all materials on these pages are licenced under a Creative Commons Licence.