UWA Logo Computer Science & Software Engineering
C Programming (CITS1210) - Labsheet 1 sample solutions
   Faculty Home  |  CSSE Home  |  csentry  |  CITS1210  |  help1210

Labsheet 1 - some sample solutions

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 rot.c. The file appears below, with line numbers added to aid the discussions.

In the sample solutions 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      gcc -std=c99 -Wall -Werror -pedantic -o rot rot.c
   8   */
   9  
  10  #define ROT 13
  11  
  12  /* Post: 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  static 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 argc, char *argv[])
  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(argc != 2)
  37      {
  38          fprintf(stderr, "%s: program expected 1 argument, received %d\n", argv[0], argc-1);
  39          exit(EXIT_FAILURE);
  40      }
  41      else
  42      {
  43          // Calculate the length of the first argument
  44          int length = strlen(argv[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(argv[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  }

  1. Modify the program to perform rot-5, rotation by 5 characters (or Caesar-encoding).

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

    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.

    We only need to change line 10 to now read:

        #define   ROT   5
    
    Now the rotation will be by 5 characters (a->f, b->g, ...).
    You may have been confused by the use of 26 (as it's twice 13). The 26 appears because there as 26 letters, a..z, in our alphabet.

  2. Extend the program to print out each character of the ciphered text one per line instead of all the characters on one line.

    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:

        printf("%c\n", rotate(argv[1][i]))
    
    where the notation "%c\n" requests that a single character be printed, immediately followed by a new-line character.
  3. Extend the program to print out on each line not only the ciphered character, but also the original character too.

    This task is now not much more difficult; instead of printing just one character we need to print two - the ciphered character (as convered by our rotate() function), one the original character (the value before before it is passed to rotate). We can change line 49 to become:

        char ch = argv[1][i];
    
        printf("%c %c\n", rotate(ch), ch);
    
    where the notation "%c %c\n" requests that two characters be printed, immediately followed by a new-line character. To make our code much less verbose, we've introduced a new character variable, named 'ch', to hold a copy of the character in which we're interested.
  4. 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.

    This task is again a bit more difficult, but requires us to change the same "area" of our code - just to modify what is being printed. The position of the character in the text parallels how many charcaters we've printed out - initially we've printed out no characters, after one iteration of the loop, we've printed out 1 character, and so on (we could quibble about whether the first iteration should be labelled '0' or '1').

    The for loop at line 46 is responsible for counting how many iterations are made. Its control variable, i, conveniently starts at zero and is incremented each time, so we'll just print out i's value each time through the loop. i is an integer variable, so we'll need a slightly different specifier to print it out. You may have been able to see from line 38 that integers are printed using '%d', so we'll extend our output line from task 3, above, to:

        printf("%c %c %d\n", rotate(ch), ch, i);
    
  5. Extend the program to handle both upper-case and lower-case letters.

    Our initial program only converted lowercase characters - uppercase characters (which, by definition can not also be lowercase) were just "ignored" in our rotate function. We now need to modify our rotate function to additionally detect uppercase characters, and to convert them.

    Our rotations by 5 will also convert (A->F, B->G, ...). Two small extensions are required - we detected lowercase characters with the standard function islower. It's a reasonable guess (and a correct one) to guess that there's also a function named isupper, which determines if a character is uppercase. We also need to follow how lowercase characters were converted, and apply the same logic to uppercase ones. This time, instead of specifically considering the first lowercase character, 'a', we'll use the first uppercase one, 'A'.

    Our whole rotate function now becomes:

    
    static char rotate(char c)
    {
        if (islower(c))          // Check if c is lower-case or not
        {
            return ('a' + (c - 'a' + ROT) % 26);
        }
        else if (isupper(c))     // Check if c is upper-case or not
        {
            return ('A' + (c - 'A' + ROT) % 26);
        }
        else
        {
            return c;
        }
    }
    

    and we should modify the block comment about rotate to correctly describe what the function does.

  6. Extend the program so that it can accept multiple arguments, performing the ciphering process on each argument to the program.

    Our starting program only dealt with a single command-line argument. All through our main() function we can find references to the variable argv[1] and, if we wish to process more command-line arguments, we'll need that value '1' to become '1', '2', '3',....

    In the original program, we'll need to add a new loop "around" all lines accessing argv[1] and make them access argv[a], where a will now range from 1 up to the number of command-line arguments, argc.

    We'll use a new for loop "around" the old lines 43..50 inclusive:

    
    for (int a = 1 ; a < argc ; a++)
    {
        // Calculate the length of each argument
        int length = strlen(argv[a]);
        // Loop for every character in this argument
        for (int i = 0; i < length; i++)
        {
            // Determine and print the ciphered character
            char ch = argv[a][i];
    
            printf("%c %c %d\n", rotate(ch), ch, i);
        }
    }
    

Top of Page
CRICOS Provider Code: 00126G