COMP1511 17s1 Introduction to Programming
  1. Tuts from now on will start with code reviews.

    This week your tutor will show you how it is to be done in future weeks.

    Your tutor will nominate this week a lab pair to do next week's code review.

  2. Discuss the errors in these while loops
    int i;
    
    while (i < 100) {
        printf("%d\n", i);
        i = i + 1;
    }
    
    Explanation of error: i is not initialized. dcc should warn you about this (or gcc -O -Wall if you are using gcc on your own machine).
    int i = 0;
    int j = 0;
    
    while (j = 1 || i < 100) {
        printf("%d\n", i);
        i = i + 1;
    }
    
    Explanation of error: j = 1 is an assignment statement, not a comparison.

    dcc should warn you about accidental uses of assignment in if/while conditions.

    int i = 0;
    int n = 10;
    while (i < n) {
        printf("%d\n", i);
        n = n + i;
        i = i + 1;
    }
    
    Explanation of error: loop does not terminate because the assignment n = n + i results in n growing faster than i.
    int i = 0;
    while (i < 10)
        printf("%d\n", i);
        i = i + 1;
    
    Explanation of error: missing braces mean the update statement, i = i + 1, is not part of the loop regardless of the indentation, and the loop is an infinite loop.
  3. Write a program that reads in an integer and prints out that many asterisks, each on a new line.
    ./asterisks
    Please enter an integer: 5
    *
    *
    *
    *
    *
    
    Sample solution for asterisks.c
    #include <stdio.h>
    
    int main(void) {
        int i, n;
    
        printf("Please enter an integer: ");
        scanf("%d", &n);
    
        i = 0;
        while (i < n) {
            printf("*\n");
            i =  i + 1;
        }
    
        return 0;
    }
    
    
  4. Write a C program multiple_of_ten.c which reads 2 integers and then prints all of the multiples of ten between those numbers.
    ./multiple_of_ten
    Enter start: 12
    Enter finish: 42
    20
    30
    40
    ./multiple_of_ten
    Enter start: -1
    Enter finish: 7
    0
    
    Sample solution for multiple_of_ten.c
    #include <stdio.h>
    
    int main(void) {
        int i, start, finish;
        printf("Enter start: ");
        scanf("%d", &start);
        printf("Enter finish: ");
        scanf("%d", &finish);
        i = start;
        while (i <= finish) {
            if (i % 10 == 0) {
                printf("%d\n", i);
            }
            i = i + 1;
        }
        return 0;
    }
    
    
  5. Your lab partner worked too late last night and wrote some unusual C statements:
    #include <stdio.h>
    
    int main(void) {
        printf("%d\n", 13 < 42);
        printf("%d\n", 13 < 42 || 42 > 50);
        printf("%d\n", 13 < 42 && 42 > 50);
        printf("%d\n", 13 && 42);
        printf("%d\n", 13 || 42);
        return 0;
    }
    
    
    Obviously your partner's code has to be completely rewritten, but first figure out what it will print and why?
    It prints:
    1
    1
    0
    1
    1
    
    Remember C logical and comparison operators actually return an int, 0 for false, for true.
  6. Write a C program cm2feet.c which reads a height in centimetres and prints it in feet.

    Reminder: there 2.54 centimetres in an inch and 12 inches in a foot.

    Use only int variables.

    Your program should behave like this:

    ./cm2feet
    Enter your height in centimetres: 183
    Your height in feet is 6
    

    Sample solution for cm2feet.c
    // Author: anonymous
    // Date created: ?
    // Convert height from centimetres to feet.
    
    #include <stdio.h>
    
    #define INCHES_IN_FOOT  12
    #define CM_IN_INCH      2.54
    
    int main (void) {
        int heightCentimetres;
        int heightFeet;
    
        printf("Enter your height in centimetres: ");
        scanf("%d", &heightCentimetres);
    
        heightFeet = (heightCentimetres / CM_IN_INCH) / INCHES_IN_FOOT;
    
        printf("Your height in feet is %d\n", heightFeet);
    
        return 0;
    }
    
    
    

    Would double variables have been a better choice?

    Double variables would probably be a better choice because we lose a lot of precision representing height as feet.
  7. Write a C program fahrenheit2celsius.c which reads a US temperature in Fahrenheit and prints it in Celsius . Reminder:
    Celsius = 5/9 (Fahrenheit - 32)
    
    Sample solution for fahrenheit2celsius.c
    #include <stdio.h>
    
    int main(void) {
        double fahrenheit, celsius;
    
        printf("Enter Fahrenheit temperature: ");
        scanf("%lf", &fahrenheit);
        celsius = 5.0 / 9.0 * (fahrenheit - 32);
        printf("%f Fahrenheit = %f Celsius\n", fahrenheit, celsius);
        return 0;
    }
    
    
    Note in C: 5/9 == 0

    Revision questions

    The remaining tutorial questions are primarily intended for revision - either this week or later in session.

    Your tutor may still choose to cover some of the questions time permitting.

  8. Write a C program decompose.c that prompts the user to enter an integer, reads it from the input and prints out the number in individual digits. Allow the program to work for input numbers up to 5 digits, i.e. up to 99999. You should be able to write this program using some divisions and remainder (modulo '%') operations, if statements and simple comparisons.

    Your program should behave as follows:

    ./decompose
    Please enter an integer:
    25
    You entered 25 which is decomposed: 2 5
    ./decompose
    Please enter an integer:
    2825
    You entered 2825 which is decomposed: 2 8 2 5
    ./decompose
    Please enter an integer:
    2
    You entered 2 which is decomposed: 2
    

    Your program should handle all integers in range (0 to 99999).

    Hint use if divide (/) and mod (%).

    Sample solution for decompose.c
    #include <stdio.h>
    
    int main(void) {
         int val, origVal;
    
         scanf("%d", &val);
         printf("You entered %d which is decomposed: ", val);
         origVal = val;
    
         if (origVal > 9999) {
             printf(" %d", val/10000);
             val = val % 10000;
         }
         if (origVal > 999) {
             printf(" %d", val/1000);
             val = val % 1000;
         }
         if (origVal > 99) {
             printf(" %d", val/100);
             val = val % 100;
         }
         if (origVal > 9) {
             printf(" %d", val/10);
             val = val % 10;
         }
         printf(" %d\n", val);
    
         return 0;
    }
    
    
  9. Discuss the concept of short-circuit evaluation for the C logical operators || and &&. Give examples. Why is this feature useful?

    Short-circuit evaluation means that the operators || and && perform the minimum amount of work required to establish their return value. In particular, if the LHS of || evaluates to true then the RHS is not examined and if the LHS of && evaluates to false then the RHS is not examined. This features means that we can safely write the following: if ((x != 0) && ((y / x) > 10)) {

    If x happens to have the value 0 then the illegal divide by 0 operation will not be performed!

  10. Consider the following expressions:

    • (x == 4) && (y == 4)
      (5 == 4) && (5 == 4); 0 && 0; 0
      (5 == 4) && (4 == 4); 0 && 1; 0
      (4 == 4) && (3 == 4); 1 && 0; 0
      (4 == 4) && (4 == 4); 1 && 1; 1
      
    • (x == 4) || (y == 4)
      (5 == 4) || (5 == 4); 0 || 0; 0
      (5 == 4) || (4 == 4); 0 || 1; 1
      (4 == 4) || (3 == 4); 1 || 0; 1
      (4 == 4) || (4 == 4); 1 || 1; 1
      
    • !((x == 4) || (y == 4))
      !((5 == 4) || (5 == 4)); !(0 || 0); !0; 1
      !((5 == 4) || (4 == 4)); !(0 || 1); !1; 0
      !((4 == 4) || (3 == 4)); !(1 || 0); !1; 0
      !((4 == 4) || (4 == 4)); !(1 || 1); !1; 0
      
    • (!(x == 4)) && (!(y == 4))
      (!(5 == 4)) && (!(5 == 4)); !0 && !0; 1 && 1; 1
      (!(5 == 4)) && (!(4 == 4)); !0 && !1; 1 && 0; 0
      (!(4 == 4)) && (!(3 == 4)); !1 && !0; 0 && 1; 0
      (!(4 == 4)) && (!(4 == 4)); !1 && !1; 0 && 0; 0
      

    What do each of the expressions evaluate to given the following values of x and y

    • x = 5; y = 5;
    • x = 5; y = 4;
    • x = 4; y = 3;
    • x = 4; y = 4;

    Compare the evaluation of the last 2 expressions on the given inputs. What do you notice?

    The output is the same for the last 2 expressions. This is because they are logically equivalent. This is called De Morgan's law - assume we have conditions P and Q
    ! (P || Q) is the same as !P && !Q
    ! (P && Q) is the same as !P || !Q
    

  11. What is output by the following C program? Why? Make sure you compile the program and run it to confirm your answer.

    #include <stdio.h>
    
    #define FIRST_NUMBER     10
    #define SECOND_NUMBER    20
    #define TOTAL   FIRST_NUMBER + SECOND_NUMBER
    #define AVERAGE TOTAL / 2
    
    int main(void) {
        printf("The average of %d and %d is %d\n",
               FIRST_NUMBER, SECOND_NUMBER, AVERAGE);
    
        return 0;
    }
    

    The average of 10 and 20 is 20

    Notes: Average is not 15, because the compiler replaces AVERAGE with TOTAL/2, then replace this TOTAL by FIRSTNUMBER + SECONDNUMBER and the printf line turns out to be
    printf("...",FIRSTNUMBER,SECONDNUMBER, FIRSTNUMBER + SECONDNUMBER/2);

    We need to fix it for this situation by putting brackets around the expression (FIRST_NUMBER + SECOND_NUMBER) and to be safe in general around (TOTAL / 2) also eg:

    #include <stdio.h>
    
    #define FIRST_NUMBER     10
    #define SECOND_NUMBER    20
    #define TOTAL   (FIRST_NUMBER + SECOND_NUMBER)
    #define AVERAGE (TOTAL / 2)
    
    int main(void) {
        printf("The average of %d and %d is %d\n",
               FIRST_NUMBER, SECOND_NUMBER, AVERAGE);
    
        return 0;
    }
    
  12. The value of C  arithmetic operations depends on the types of the operand. If the types of the operands differ, C automatically converts the types as appropriate.

    Determine the value of each expression and sub-expression:

    1. 1 / 2 * 500
      1 / 2 = 0; 0 * 500 = 0
    2. 1 / 2.0 * 500
      1/2.0 = 0.5; 0.5 * 500 = 250.0
    3. (17 / 5) * 5 + (17 % 5)
      17 / 5 = 3; 17 % 5 = 2; 3 * 5 = 15; 15 + 2 = 17
    4. (12 - 17) % 6 - 4
      12 - 17 = -5; -5 % 6 = -5; -5 - 4 = -9
  13. What does precedence of an operator mean? Make the precedence explicit in the following expressions by adding parentheses:
    1. 3 + 5 * 10 - 12
      ( ( 3 + (5 * 10) ) - 12 )
    2. a > 5 || b < 3
      ( (a > 5) || (b < 3) )
    3. a = b > c && b || d
      a = ( ( (b > c) && b ) || (d) )
    4. !a || a && c
      ( (!a) || (a && c) )

    Figuring this out can be a bit tedious and prone to errors. The moral? In complex expressions make your intention explicit by using parentheses.

    Note: The precedence rules of arithmetic operators in C follow the conventions used in mathematics.

  14. This is a revision question, to make the difference between if and while statements clear. Consider the two code snippets below, what will be the output after execution of each of the programs for input_num = 3.
    int input_num, i; 
    
    printf("Enter a number: "); 
    scanf("%d", &input_num); 
    
    i = input_num; 
    
    if(i <= 5){
      printf("%d\n", i * i); 
      i++; 
    }
    
    
    int input_num, i; 
    
    printf("Enter a number: "); 
    scanf("%d", &input_num); 
    
    i = input_num; 
    
    while(i <= 5){
      printf("%d\n", i * i); 
      i++; 
    }
    
    
    The output of the first program:
    9

    The output of the second program:
    9
    16
    25

    Therefore, remember the instructions in the if statements are executed just once, given the condition in the round brackets is true. Whereas, instructions can execute more than once in a while statement (hence the term loop, iteration, repetition...).