CITS2002 Systems Programming

# Department of Computer Science and Software Engineering

## CITS2002 Systems Programming

### 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.

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. Write a program which accepts exactly 3 command-line arguments, converts each to an integer value, and prints the maximum of the 3 values.

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 *argvalue[])
{
//  CHECK THE NUMBER OF COMMAND-LINE ARGUMENTS
if(argcount != 4) {
fprintf(stderr, "Usage: %s value1 value2 value3\n", argvalue[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(argvalue[1]);
int value2  =  atoi(argvalue[2]);
int value3  =  atoi(argvalue[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....

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", argvalue[0]);
exit(EXIT_FAILURE);             // Exit indicating failure
}
else {
//  ASSUME THAT THE FIRST ARGUMENT PROVIDES THE MAXIMUM VALUE
int maximum = atoi(argvalue[1]);

//  LOOP OVER ANY REMAINING ARGUMENTS (THERE MAY BE NONE!)
for(int a = 2 ; a < argcount ; a = a + 1) {
int thisvalue = atoi(argvalue[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....

```#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 *argvalue[])
{
//  ITERATE OVER EACH COMMAND-LINE ARGUMENT
for(int a=1 ; a<argcount ; ++a) {
if(luhn(argvalue[a])) {
printf("%16s\t%s\n", argvalue[a], "OK");
}
else {
printf("%16s\t%s\n", argvalue[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

```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 *argvalue[])
{
for(int a=1 ; a<argcount ; a = a+1) {
ordinal( atoi(argvalue[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!):

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

```// Q6b)
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");
}
```

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

```// Q6d)
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");
}
```

# The University of Western Australia

## University information

CRICOS Code: 00126G