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 1: for the week commencing 31st July 2023

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

The tasks required you to modify and extend the file  rotate.c  This file appears below, with line numbers added to aid the discussions. In the sample solutions that follow, some text appears in red to highlight the small changes necessary to complete the tasks.

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <ctype.h> 5 6 /* Compile this program as: 7 cc -std=c11 -Wall -Werror -o rotate rotate.c 8 */ 9 10 #define ROT 13 11 12 /* Rotate c returns the character ROT positions further along the 13 alphabetic character sequence from c, or c if c is not lower-case 14 */ 15 char rotate(char c) 16 { 17 // Check if c is lower-case or not 18 if(islower(c)) 19 { 20 /* The ciphered character is ROT positions beyond c, 21 allowing for wrap-around 22 */ 23 return('a' + (c - 'a' + ROT) % 26); 24 } 25 else 26 { 27 return c; 28 } 29 } 30 31 int main(int argcount, char *argvalue[]) 32 { 33 /* Exit with an error if the the number of arguments (including 34 the name of the executable) is not precisely 2 35 */ 36 if(argcount != 2) 37 { 38 fprintf(stderr, "%s: program expected 1 argument, received %d\n", argvalue[0], argcount-1); 39 exit(EXIT_FAILURE); 40 } 41 else 42 { 43 // Calculate the length of the first argument 44 int length = strlen(argvalue[1]); 45 // Loop for every character in the text 46 for(int i = 0; i < length; i++) 47 { 48 // Determine and print the ciphered character 49 printf("%c", rotate(argvalue[1][i])); 50 } 51 // Print one final new-line character 52 printf("\n"); 53 // Exit indicating success 54 exit(EXIT_SUCCESS); 55 } 56 return 0; 57 }

Labsheet 1 Tasks

rot13

  1. Modify the program to perform rot-3, rotation by 3 characters (or Caesar-encoding).
  2. The original program performed a rotation by 13 characters (a→m, b→n, ...), and so to make the required change we only need to find all instances of 13, and change them to 3.

    It is considered good practice in C programs to identify all "magic numbers", or constants, such as our value 13 using C pre-processor tokens. That way, when we do need to change such a constant, we can expect to find it as a C pre-processor token, usually near the beginning of the file, and we can expect to not have to look through every line to find where a value such as 13 may need changing.

    Hence, we only need to change line 10 to now read:

    10 #define ROT 3

  1. Extend the program to print out each character of the ciphered text one per line instead of all the characters on one line.
  2. To do this task, we first need to locate where the ciphered text is being printed. Other than the printing of an error message, there's only 2 lines that are clearly printing something - lines 49 and 52. To have only one ciphered character per line, we need to print a new-line character after each ciphered character. We can thus change line 49 to become:

    48 // Determine and print the ciphered character 49 printf( "%c\n", rotate( argvalue[1][i] ));

    where the notation  "%c\n"  requests that a single character be printed, immediately followed by a new-line character.

  1. Extend the program to print out on each line not only the ciphered character, but also the original character too.
  2. Now we need to print out two characters using the printf function on line 49. To make it very clear that we're both printing a character, and also passing that same character to the rotate function, we'll define a new character variable, named ch, to hold a copy of the character:

    char ch = argvalue[1][i]; 48 // Determine and print the ciphered character 49 printf( "%c %c\n", ch, rotate( ch ) );

  1. Extend the program to print out on each line not only the original and ciphered characters, but also the "position" of the character in the text.
  2. The "position" within the text is actually the index into the argvalue[1] array. We will define the first character to be at position 0, the next at 1, and so on. Actually, we are already managing this position using the loop control variable i in the for loop at line 46. We can extend our call to the printf function, to also print the position as an integer - we use the format specifier "%i" for integers:

    48 // Determine and print the original and the ciphered character 49 printf( "%i: %c %c", i, ch, rotate( ch ) );

  1. Extend the program to handle both upper-case and lower-case letters.
  2. The function rotate currently detects lowercase characters, and simply ignores all others. We need to extend the function to now also detect uppercase characters. We can use the isupper function to do this:

    25 else if(isupper(c)) 26 { 27 return('A' + (c - 'A' + ROT) % 26); 28 }

  1. The program rotate.c requires 4 C-preprocessor #include directives to read the declarations of some standard C functions from C header files. Remove (and eventually replace) each #include line, in turn, to determine which required functions are declared in each file.

    • <stdio.h> - defines constants and declares functions required for (input and) output. Our program uses the fprintf and printf library functions and the stderr communication stream.
    • <stdlib.h> - defines constants and declares functions to interface C with the operating system. Our program uses the EXIT_SUCCESS and EXIT_FAILURE constants and the exit() library function.
    • <string.h> - declares a number of string handling functions; our program uses only strlen().
    • <ctype.h> - defines a number of character testing and handling functions (actually macros); our program uses only islower() and Q5 requires isupper().

  1. 🌶 Extend the program so that it can accept multiple arguments, performing the ciphering process on each argument to the program.
  2. We modify the original source code to interate over each command-line argument (skipping argvalue[0] because that is the name of the program):

    41 else 42 { for(int a = 1 ; a < argcount ; a++) { 43 // Calculate the length of each argument 44 int length = strlen(argvalue[a]); 45 // Loop for every character in the text 46 for(int i = 0; i < length; i++) 47 { 48 // Determine and print the ciphered character 49 printf("%c", rotate(argvalue[a][i])); 50 } 51 // Print one final new-line character 52 printf("\n"); } 53 // Exit indicating success 54 exit(EXIT_SUCCESS); 55 } 56 return 0; 57 }

  1. 🌶 Extend the program so that it reads the rotation amount (the amount to rotate each character by) as the first argument to the program.
    You will need to use the  atoi  function to convert the text argument into a number.
  2. We need to make two changes to the standard program. Firstly (in order of execution) we need to convert main()'s first argument to an integer; this will be the required rotation amount. We pass this new rotation amount as a parameter to the rotate() function.

    31 int main(int argcount, char *argvalue[]) 32 { 33 .... 36 if(argcount != 3) 37 { 38 fprintf(stderr, "%s: program expected 2 arguments, received %d\n", argvalue[0], argcount-1); 39 exit(EXIT_FAILURE); 40 } 41 else 42 { int new_rotation = atoi(argvalue[1]); 43 // Calculate the length of the first argument 44 int length = strlen(argvalue[2]); .... 49 printf("%c", rotate(argvalue[2][i], new_rotation)); .... 15 char rotate(char c, int rotate_by) 16 { 17 // Check if c is lower-case or not 18 if(islower(c)) 19 { 20 /* The ciphered character is rotate_by positions beyond c, 21 allowing for wrap-around 22 */ 23 return ('a' + (c - 'a' + rotate_by) % 26); 24 }

  1. 🌶 🌶 Extend the program so that all arguments to the program can be either text or numbers. If an argument is text, the text is ciphered using the current rotation amount (initialised to 13). If an argument is a number, the rotation amount changes to this value and all subsequent cipherings (up to the next number argument) use this new rotation amount.

  1. 🌶 🌶 Extend the previous version of the program so that textual arguments can represent files. If a text argument can be opened as a file (see  man fopen ) perform the ciphering on the contents of the file. Otherwise, treat the arguments as before: if an argument is text, the text is ciphered using the current rotation amount (initialised to 13), or if an argument is a number, the rotation amount changes to this value and all subsequent cipherings (up to the next number argument) use this new rotation amount.

The University of Western Australia

Computer Science and Software Engineering

CRICOS Code: 00126G
Presented by [email protected]