CITS2002 Systems Programming  
 

Unit home

Final exam

help2002

Lecture & Workshop
recordings on LMS

Schedule

FAQ

C textbooks

OS textbooks

Information resources


Extra reading

Past projects

Recent feedback


Working effectively

Look after yourself!

Solutions for Labsheet 2 - for the week commencing 7th August 2023

This page provides some sample solutions and discussion on some of the tasks of Labsheet-2.

Exercises

  1. A year is a leap year if it is divisible by 400, or if it is divisible by 4 and not divisible by 100. For example - 1996, 2000, and 2012 were leap years, while 1899, 1900, and 2013 were not. Write a program that determines if the year, supplied as a command-line argument, is a leap year or not.

  2. Any challenge in this question is addressed by using additional parentheses to make your solution readable. There is no penalty for using an "excessive" number of parentheses, and (after correctness) readability of your code is the most important issue.

    // (a multiple of 400) OR ((a multiple of 4) AND (NOT a multiple of 100)) if((year%400 == 0) || (((year%4 == 0) && (year%100 != 0))) { printf("YES\n"); } else { printf("NO\n"); }

  1. Incorporate your support for leap years from the previous task, into your solution to the calendar printing program from Workshop-2.
  2. The solution to this exercise can directly use the solutions from task 1 and Workshop-2. Only in February do we need to calculate whether we're in a leap year or not, and, if so, to set the number of days in the month to 29 instead of 28.

    switch (month) { case 1: printf(" January %i\n", year); daysinmonth = 31; break; case 2: printf(" February %i\n", year); if(is_leap_year(year)) { daysinmonth = 29; } else { daysinmonth = 28; } break; .....

  1. Write a program which accepts exactly 3 command-line arguments, converts each to an integer value, and prints the maximum of the 3 values.
  2. The solution to this exercise forms a very standard "pattern" of writing our introductory programs - the main() function should check the number of command-line arguments; if incorrect, a helpful error message should be printed, and the program should exit indicating failure; otherwise, the rest of rest of main() processes the command-line arguments.

    This program's command-line arguments are strings of characters, and each needs to be converted to an integer value using the standard atoi() function. We first assume that the first value is the maximum value, and then check to see if the second, and then the third, are greater. Note how we've had to use a fixed number of if tests to find the maximum of all values:

    #include <stdio.h> #include <stdlib.h> int main(int argcount, char *argv[]) { // CHECK THE NUMBER OF COMMAND-LINE ARGUMENTS if(argcount != 4) { fprintf(stderr, "Usage: %s value1 value2 value3\n", argv[0]); exit(EXIT_FAILURE); // Exit indicating failure } // CORRECT NUMBER OF COMMAND-LINE ARGUMENTS, PROCESS THEIR VALUES else { // CONVERT EACH COMMAND-LINE ARGUMENT TO AN INTEGER VALUE int value1 = atoi(argv[1]); int value2 = atoi(argv[2]); int value3 = atoi(argv[3]); // ASSUME THAT THE FIRST ARGUMENT PROVIDES THE MAXIMUM VALUE int maximum = value1; // COMPARE OUR ASSUMED MAXIMUM AGAINST THE OTHER TWO VALUES if(maximum < value2) { maximum = value2; } if(maximum < value3) { maximum = value3; } // PRINT THE MAXIMUM VALUE FOUND printf("maximum is %i\n", maximum); exit(EXIT_SUCCESS); // Exit indicating success } return 0; }

  1. Rewrite your solution to the previous exercise so that it now prints the maximum of an arbitrary number of command-line arguments, perhaps 3, or 10, or 50....

  2. In this question we do not require a fixed number of command-line arguments, just at least one. We again assume that the first command-line argument (its integer value) provides the maximum value, and then loop over all remaining values looking for a new maximum:

    .... // CHECK THE NUMBER OF COMMAND-LINE ARGUMENTS if(argcount < 2) { fprintf(stderr, "Usage: %s value1 [value2 ...]\n", argv[0]); exit(EXIT_FAILURE); // Exit indicating failure } else { // ASSUME THAT THE FIRST ARGUMENT PROVIDES THE MAXIMUM VALUE int maximum = atoi(argv[1]); // LOOP OVER ANY REMAINING ARGUMENTS (THERE MAY BE NONE!) for(int a = 2 ; a < argcount ; a = a + 1) { int thisvalue = atoi(argv[a]); // COMPARE OUR ASSUMED MAXIMUM AGAINST ANY OTHER VALUES if(maximum < thisvalue) { maximum = thisvalue; } } // PRINT THE MAXIMUM VALUE FOUND .... }

  1. The Luhn credit card algorithm....
  2. #include <stdio.h> #include <stdlib.h> #include <stdbool.h> // THE FUNCTION RECEIVES AN ARRAY OF CHARACTERS, WITHOUT SPECIFYING ITS LENGTH bool Luhn(char creditcard[]) { int s1 = 0; int s2 = 0; bool odd = true; // ITERATE OVER THE STRING BACKWARDS for(int i = strlen(creditcard)-1 ; i >= 0 ; i = i-1) { char digit = creditcard[i] - '0'; if(odd) { s1 += digit; } else { int mult = digit*2; s2 += (mult/10) + (mult%10); } odd = !odd; } return ((s1+s2) % 10) == 0; } int main(int argcount, char *argv[]) { // ITERATE OVER EACH COMMAND-LINE ARGUMENT for(int a=1 ; a<argcount ; ++a) { if(Luhn(argv[a])) { printf("%16s\t%s\n", argv[a], "OK"); } else { printf("%16s\t%s\n", argv[a], "not OK"); } } return 0; }

  1. Write a program that prints out the ordinal description of the (assumed to be numerical) arguments supplied to the program. For example:

    prompt> ./ordinal 1 6 11 12 21 22 23 1st 6th 11th 12th 21st 22nd 23rd

  2. void ordinal(int i) { int lastdigit = i % 10; // keep the remainder after dividing by 10 if(lastdigit == 1 && i != 11) { printf("%ist\n", i); } else if(lastdigit == 2 && i != 12) { printf("%ind\n", i); } else if(lastdigit == 3 && i != 13) { printf("%ird\n", i); } else { printf("%ith\n", i); } } int main(int argcount, char *argv[]) { for(int a=1 ; a<argcount ; a = a+1) { ordinal( atoi(argv[a]) ); } return 0; }

  1. Write programs to print each of these shapes (refer to the Labsheet). Use C's for loops to control your printing, rather than just 'fixed' calls to printf (imagine if a command-line argument indicated how big the Christmas tree should be!):
  2. // Q7a) for(int row = 1 ; row <= 5 ; ++row) { for(int col = 1 ; col <= row ; col = col+1) { printf("*"); } printf("\n"); }

    // Q7b) for(int row = 1 ; row <= 5 ; ++row) { for(int col = 1 ; col <= (5-row) ; col = col+1) { printf(" "); } for(int col = 1 ; col <= row ; col = col+1) { printf("*"); } printf("\n"); }

    // Q7c) for(int row = 5 ; row >= 1 ; --row) { for(int col = 1 ; col <= row ; col = col+1) { printf("*"); } printf("\n"); }

    // Q7d) for(int row = 1 ; row <= 5 ; ++row) { for(int col = 1 ; col <= 5-row ; col = col+1) { printf(" "); } for(int col = 1 ; col <= row*2 - 1 ; col = col+1) { printf("*"); } printf("\n"); }

  1. Ackermann's function ...
    • Trivially implement Ackermann's function.
    • int Ackermann(int m, int n) { if(m == 0) return n + 1; if(n == 0) return Ackermann(m - 1, 1); return Ackermann(m - 1, Ackermann(m, n - 1)); }

    • Extend your implementation to count the number of recursive calls and the maximum recursive depth required for, say, A(1, 2) and A(3, 3).

      static int Acalls, Amaxdepth; static int Ackermann0(int m, int n, int depth) { ++Acalls; if(Amaxdepth < depth) { Amaxdepth = depth; } if(m == 0) return n + 1; if(n == 0) return Ackermann0(m - 1, 1, depth+1); return Ackermann0(m - 1, Ackermann0(m, n - 1, depth+1), depth+1); } int Ackermann(int m, int n) { Acalls = 0; Amaxdepth = 0; int result = Ackermann0(m, n, 1); printf("result = %i, ncalls = %i, maxdepth = %i\n", result, Acalls, Amaxdepth); }
    • 🌶 🌶 Redesign your implementation so that it doesn't require any global variables to maintain the counts of recursive calls and maximum recursive depth.

The University of Western Australia

Computer Science and Software Engineering

CRICOS Code: 00126G
Presented by [email protected]