CITS2002 Systems Programming | |
|
Solutions for Labsheet 1: for the week commencing 29th July 2024This 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
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
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.
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 ) );
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 ) );
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 }
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 }
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 }
|