CS107 - Lab 6


Overview

In this assignment you will work on C++ functions. You will see problems that we have not explicitly discussed in class. You are expected to learn and figure out how things work by looking at the examples given throughout the lab. Before starting, make sure to review the examples and handouts discussed in class.

The lab contains two problems. In the first problem you will develop a set of functions for working with arrays, culminating with a function for selection sort.

In the second part of the lab you will work with characters, understand their representation as ASCII codes, and write functions to encrypt and decrypt messages using Caesar's cypher.

As you write your programs remember to pay attention to the following issues of style:


Functions and Arrays

In this problem you will develop a set of functions for working with arrays. Here is an example of a function that reads in an array from the user:
//************************************************************
//a function that reads an array of n elements from the user; 
//when calling the function, n is assumed to be known, while a[] is filled in 
void read_array(int a [], int n) {
  int i = 0; 
  cout << "Please enter an array of " << n << " elements: \n";
  while (i < n) {
    cout << "enter element " << i << ": "; 
    cin >> a[i];
    i = i+1;
  }
  return;
}
Note that the array parameter of the function is declared as int a[], that is, without specifying the size of the array (as we normally do).

Here is an example fragment of code that calls this function:

  const int size=10;

  //declare an array called x of size elements
  int x[size];

  //read the array from user 
  read_array(x, size); 
Note that when we call the function read_array, we specify the name of the array x and its size. After the last line above, the array x contains 10 values read from user.

In general, when we declare a function we specify the return type and the type of the parameters, while when we call a function we only specify the name of the arguments the function will work upon. A call of the same function with different arguments will have different results.

The compiler will check that the arguments of a function call and the parameter list are consistent. But it is the programmer's-- that is, your :-) --responsibility to define and call the function in such a way to get the desired output.

Problem 1

Re-write your program for selection sort using functions. Write the following functions:
//input: n is given  (that is, when calling the function, n is known) 
//function: reads n values  from the user into array a[] 
void getArray(int a[], int n) { 
  //fill in 
}

//input: array a[] of n numbers, and n are given 
//(that is, when calling the function, a and n are known)
//function: prints the n values stored in array a[]
void printArray(int a[], int n) {
  //fill in
}

//input: array a[] of n numbers and n are given; also two indices begin and end 
//between 0 and n-1
//function: finds the smallest number in a[begin]...a[end]
//return value:  the index of the position of the smallest element 
int findSmallest(int a[], int n, int begin, int end) {
  //fill in
}


//input: array a[], two indices i and j between 0 and n-1
//function: swaps a[i] with a[j]
void swap(int a[], int i, int j) {
  //fill in
}


//input:  array a[] of n numbers and n are given
//function: sorts a[] in increasing order 
void selectionSort(int a[], int n) {
 int i = 0, spos; 

 while (i < n) {
    spos = findSmallest(a, n, i, n-1);
    swap(a, i, spos);
    i = i+1; 
 }
 return;
}
Fill in the functions above to have the described behaviour. The main program should look as follows (you cannot change main()):

const int size = 10;

int main() {

    int x[size];

    getArray(x, size);
    printArray(x, size);
    selectionSort(x,size);
    cout << "The sorted array is: ";
    printArray(x,size);


    char answer = 'n';
    while (answer != 'y') {
        cout <<"Do you think using functions makes programming easier and more fun? (y/n)";
        cin >> answer; 
	if (answer =='y') {
	   cout << "great! you can go to the next problem..:)\n";
	} else {
	  cout << "then..look again at today's code for selection sort..";
	  cout << "and compare it with the code that was all in main()..\n";
	}
    }

    return 1;
}


Characters and ASCII codes

In C++ (and in general in any programming language) each character is represented as an integer value. The standard scheme is called ASCII. ASCII is an international standard for representing characters. The ASCII code of a character is an integer between 0 and 255. However, only numbers 32 to 126 have been assigned so far o printable characters. The remaining numbers are either unnassigned or are used for control characters such as tab and return.

The following code will help you understand characters and ASCII codes. Take a look at the following programs char1.cpp and char2.cpp (in EXAMPLES directory on collaboration).

//char1.cpp
//The following program gives you the ascii code of a character that you type

#include < iostream.h >

int main() {

  char c; 
  char again = 'y';
  
  while (again == 'y') {
    cout << "Type in a character and I'll tell you its ASCII code: ";
    cin >> c;
    cout << "you typed char=" << c << " it's ascii code is " << (int)c << endl;
    
    cout << "again? (y/n)" << endl;
    cin >> again;
  }

  return 1;
}

//char2.cpp
//The following program gives you the ascii conversion table
//for the numerical values 32-126

#include < iostream.h >

int main() {

  int i = 32;
  while (i <= 126) { 
    cout << "code=" << i << " char=" << (char)i << endl;
    i = i+1; 
  }

  return 1;
}

Before running them, try to understand what they do. Then load them in Xcode and run them.


Cryptology using Caesar's Cypher

Cryptology is the science of "secret codes". Messages are encoded before they are sent out to keep their content secret if they are intercepted by the wrong parties; they are decoded when they are received to retrieve the original information.

The most famous instances of cryptology occur in military history, beginning with Julius Caesar of the Roman Empire, who developed the Caesar Cypher, and certainly including the German Enigma code cracked by the Allies during World War II (by Alan Turing, a British mathematician).

Transmitting information securely has taken a modern turn with electronic commerce on the Internet and concerns over protection of consumer credit card information and other personal data.

A Caesar cypher, also called a shift cypher, involves shifting each character in the message to another character some fixed distance farther along in the alphabet. Specifically, let s be some integer between 1 and 25 that represents the amount of the shift. Each letter in the message is encoded as the letter that is s units farther along in the alphabet, with the last s letters of the alphabet shifted in a cycle to the first s letters.

For example, if s=3, then A is encoded as D, B is encoded as E, X is encoded as A, and Z is encoded as C. Decoding a message requires knowing s. For example, knowing that s=3, the code word DUPB is decoded as ARMY.

Problem 2

Write a program that reads a text from the user and encodes all lower case characters (leave all other characters unchanged) using Caesar cypher with s=3, then decodes the encoded message. The goal is to obtain the original message. Use the following skeleton for your program (crypt.cpp from the EXAMPLES directory on collaboration). The body of the main functions, encode() and decode(), is missing.
// Program skeleton to solve the cryptography problem

#include <iostream.h>

//function: read characters from the user into array a[], until the user
//enters a period. Count how many characters were entered in total
//including the period, and return this value.
int getCharArray(char a[], int maxLength) {
    int i; 
    char c = ' '; //some dummy initial value

    cout << "Enter a text character by character; end it with a period:" << endl;
    i=0;
    while (c != '.' && i < maxLength) { 
        cin >> c; 
        a[i] = c; 
        i = i+1; 
    }
    
    return i;
}


//input: array a[] of n characters given
//function: print the array
void printCharArray(char a[], int n) {
    int i = 0;
    while (i < n) { 
	cout << a[i]; 
	i=i+1; 
    }
    cout << endl; 
}


//input: array a[] of n characters 
//function: encode the n characters of a[] using the Caesar cypher and
//write them in order into b[].  That is, translate each character to
//the one that is 3 characters beyond it in the alphabet.
void encode(char a[], int n, char b[]) {
//fill in 

}


//input: array a[] of n characters (assumed encrypted with Caesar's cyper s=3)
//function: decode the n characters of a[] into b[] using the Caesar
//cypher. That is, translate each character into the one that is 3
//characters before it in the alphabet
void decode(char a[], int n, char b[]) {
//fill in

}


//input: character arrays a[] and b[] of size n 
//function: return 1 if a[] and b[] are equal, that is, every
//character matches; return 0 otherwise
int areEqual(char a[], char b[], int n) {
  //fill in

}

int main () {
  const int maxLength = 50;
  char original[maxLength], cypher[maxLength], decypher[maxLength];
  int length;
  
  //read in the text that you want to encode
  length = getCharArray(original, maxLength);
  
  //print out the text
  cout << "text length = " << length << endl; 
  cout << "This is the text that you entered: ";	
  printCharArray(original, length);

  
  //encode the text 
  encode(original, length, cypher);

  //print out the encrypted text 	
  cout << "This is the encrypted text: ";
  printCharArray(cypher, length);
 
  
  //decode it
  decode(cypher, length, decypher);
  
  //print out decoded text
  cout << "This is the decrypted text: ";
  printCharArray(decypher, length);
 
  //check to see of you decrypted correctly
  if (areEqual(original, decypher, length) == 1) {
    cout << "Great, you're done" << endl;
  } else {
    cout << "OOPS! The original text and the decrypted text do not match.."<< endl;
  }
  
  return 1;
}

Hint: Do you actually need to know the ASCII code of a character in order to encode it? Keep in mind that ASCII codes of characters that are consecutive in the alphabet are consecutive! Check this out:

char c = 'a';
char x = c+1;
cout << x;
x = c+3;
cout << x;
In order to test whether a character mychar is between b and d, you can test whether
(mychar >= 'b' && 'mychar <= 'd')
If your solution is elegant, it will not use ASCII values in the code!

Extra credit: Assume the lower case characters have been shifted with an unknown amount s. Write a decode function that tries all possible values of s and picks out the good one.



What to turn in:

Send me only the .cpp files in the XCode project. Rename the main.cpp in the XCode folder to something from which I can easily identify the author, the lab number, and the problem number (no spaces in the name, please!)

If you work in a team submit only one file per team.

Make sure you include your name on the top line of all your .cpp programs!!