CSE240 C CPP1 Assn3
CSE240 C CPP1 Assn3
50 points
Topics:
Create and use variables
Use printf and scanf / cin and cout to work with input and output
Use simple File I/O
Use control structures to control the flow of logic
Work with math and random numbers
Create these things from scratch
Create some basic void and value returning functions
Description
This assignment is going to get you used to working with the Unix/Linux compiler
through some exercises and create a simplified version of the infamous Enigma
Machine with a “2 Rotor” Encryption.
Important Note:
All submitted assignments must begin with the descriptive comment block. To avoid
losing trivial points, make sure this comment header is included in every
assignment you submit, and that it is updated accordingly from assignment to
assignment.
/*
Author: <your name here>
Date: <date>
Description: <short description of code file>
Usage: <usage syntax>
*/
October 2023
Programming Assignment:
Instructions:
This assignment has three parts:
The first two parts are there to help you through understanding how to connect
with and use Unix/Linux on general.asu.edu.
For these exercises you should use an SSH client to connect to general.asu.edu
and text editor on general.asu.edu.
Specifications:
Set-Up
If you are on Windows:
Download an SSH client of your choosing. I recommend Putty (www.putty.org).
The code provided is clearly incorrect. It has Semantic errors – such as the
missing break statements in the switch. Repair the semantic errors, compile and
run the code again.
while(<conditional>)
{
//do stuff
}
int c;
for(c = 0; …)
Warning – remember you can leave a \n character in the input buffer. You
might need to sanitize your inputs. The scanf command as given will read
only one character.
The easiest way to do this is with scanf(“% c”, &ch); but that’s not always
reliable as not every compiler seems to accept it. It should be fine
though.
Transfer the edited .c file to your computer via an FTP client, WinSCP or
https://webapp4.asu.edu/myfiles/app
Using command line debugger (important to learn)
You are given a file “gdbChallenge.c”
You will get nothing but 0’s in your output. Clearly this code has problems!
Time to find the error and fix it.
This will load the executable into Gnu Debugger (gdb). Gdb is a command line
debugger, but it’s still quite powerful.
You can look at the code for the executable by entering the command “list”. List
will show you code listings sequentially, to start over from the top or a line
number enter the command: list <line number>
(gdb) next
12 int value = (int)frand() * 10000;
Let’s get some information about what’s going on… value and i are both
meaningful to us. So enter the commands:
display i
display value
13 printf("%d\n",value);
2: value = 0
1: i = 0
Keep hitting enter for a while – this will repeat your “next” command
automatically
(gdb)
0
10 for(i = 0; i < 10000; i++)
1: i = 0
(gdb)
12 int value = (int)frand() * 10000;
2: value = 0
1: i = 1
(gdb)
13 printf("%d\n",value);
2: value = 0
1: i = 1
(gdb)
0
10 for(i = 0; i < 10000; i++)
1: i = 1
(gdb)
12 int value = (int)frand() * 10000;
2: value = 0
1: i = 2
(gdb)
13 printf("%d\n",value);
2: value = 0
1: i = 2
(gdb)
0
10 for(i = 0; i < 10000; i++)
1: i = 2
(gdb)
12 int value = (int)frand() * 10000;
2: value = 0
1: i = 3
(gdb)
13 printf("%d\n",value);
2: value = 0
1: i = 3
(gdb)
0
10 for(i = 0; i < 10000; i++)
1: i = 3
(gdb)
12 int value = (int)frand() * 10000;
2: value = 0
1: i = 4
(gdb)
13 printf("%d\n",value);
2: value = 0
1: i = 4
(gdb)
0
10 for(i = 0; i < 10000; i++)
1: i = 4
(gdb)
12 int value = (int)frand() * 10000;
2: value = 0
1: i = 5
What can we notice? Value is remaining as 0 while i is incrementing properly
through the for-loop.
Edit the code to repair this error. Hint: I’m missing some parentheses.
Redo the gdb process to demonstrate to yourself that the code is working properly
now.
Yes, I realize you can fix this code through visual debugging … that’s not
the point, the point is to familiarize you with GDB – don’t cheat yourself
out of the process
Ungraded B) – Getting used to strtok()
The function strtok() comes from the library <string.h> which is a C-String
library. It tokenizes a string into substrings based on a delimeter.
Function signature:
1. A source string
a. Since this is a character pointer, any character array can be
passed here.
b. Remember to be a C-String though it needs a ‘\0’ at the end
2. A string literal that describes the delimiters
a. There is no special syntax here, just put them right next to each
other with no white-space (unless you want space to be a
delimiter)
The function returns a character pointer (i.e. a string). The function should
be called repeatedly until it returns NULL. Each time it is called it returns
the next token.
When tokenizing a single string – the first time strtok() is called, you provide
the source string. To keep tokenizing that string you pass NULL as the first
parameter.
Type in this code (don’t just copy paste, MS Word might add non-code characters),
you should be able to copy/paste the Lorem text from the previous page though.
#include <string.h>
#include <iostream>
using namespace std;
printf("Splitting string...");
while(token != NULL)
{
printf("%s\n", token);
token = strtok(NULL, " "); //keep tokenizing notice NULL
}
return 0;
}
Output:
Splitting string...Lorem
ipsum
dolor
sit
amet
consectetur
adipiscing
elit
Integer
tempor
posuere
nibh
quis
tempor
Sed
eu
turpis
nulla
Suspendisse
vestibulum
blandit
enim
vitae
feugiat
Nulla
malesuada
orci
ut
nisi
blandit
congue
Maecenas
vulputate
magna
in
tellus
eros
Here’s a modification of that code that processes a character at a time and uses
a function, once again, don’t just copy/paste:
#include <string.h>
#include <iostream>
using namespace std;
int charToInt(char);
printf("Splitting string...");
while(token != NULL)
{
printf("%s\n", token);
for(int i = 0; i < strlen(token); i++)
{
printf("Character value of %c = %d\n", token[i], charToInt(token[i]));
}
token = strtok(NULL, " ");
}
return 0;
}
Partial output:
Splitting string...Lorem
Character value of L = 76
Character value of o = 111
Character value of r = 114
Character value of e = 101
Character value of m = 109
ipsum
Character value of i = 105
Character value of p = 112
Character value of s = 115
Character value of u = 117
Character value of m = 109
dolor
Character value of d = 100
Character value of o = 111
Character value of l = 108
Character value of o = 111
Character value of r = 114
Ungraded C) Getting lines from files
There’s a couple of different ways to read lines from a file. Here is one you
can do in C.
fgets() reads a line from a specified source into a string. It will read all
characters in a line until it sees a newline character. It, however, ALSO reads
that newline character.
a b c d e f \n
The character array getting that input would include the \n character!
Sample Code:
#include <stdio.h>
int main(int argc, char** argv)
{
FILE* file;
file = fopen("lorem.txt", "r");
char line[255];
Sample output:
Read: Lorem ipsum dolor sit amet consectetur adipiscing elit Nulla ex nulla eleifend
congue commodo at condimentum sed dui Suspendisse potenti Nullam eu erat mollis vulputate
augue eu sodales nulla Fusce posuere lacus at ante condimentum luctus lectus
Read: Mauris vestibulum bibendum gravida Nulla venenatis lorem ac dictum imperdiet ligula
massa rutrum turpis sed efficitur magna velit a lacus Nam porta elit et mauris dapibus
dictum Maecenas quam arcu scelerisque ac nibh convallis mattis interdum leo
Read: Aenean cursus lacus vitae sem feugiat quis congue augue fringilla In mollis tortor
mattis aliquam efficitur Mauris pretium et ante id pulvinar Cras ultricies euismod
tincidunt Donec neque risus egestas vitae varius in gravida nec diam Aenean odio
Read: Vivamus eget ante ipsum Quisque tincidunt metus sit amet vulputate dapibus Vivamus
imperdiet diam massa eu porttitor felis egestas nec Aliquam quis justo tellus Donec vel
ex ut dui facilisis varius at quis sem Sed sit amet lacus ornare eleifend eu
(notice things are double spaced … that’s due to the \n character being put in the line
array and the printf having a \n)
Here’s a way to do it in C++ with ifstream getline. Unlike fgets(), getline()
does not read the \n with the input. NOTE: The end of file won’t trigger until
it’s read … so be careful how you write your loops and reads.
#include <iostream>
#include <fstream>
char line[255];
do
{
infile.getline(line,255);
cout << "READ: " << line << endl;
}while(!infile.eof());
return 0;
}
Sample output:
g++ -g -Wall cpplines.cpp
~/CSE240/c_cpp/assnWork/a1$ ./a.out
READ: Lorem ipsum dolor sit amet consectetur adipiscing elit Nulla ex nulla
eleifend congue commodo at condimentum sed dui Suspendisse potenti Nullam eu erat
mollis vulputate augue eu sodales nulla Fusce posuere lacus at ante condimentum
luctus lectus
READ: Mauris vestibulum bibendum gravida Nulla venenatis lorem ac dictum
imperdiet ligula massa rutrum turpis sed efficitur magna velit a lacus Nam porta
elit et mauris dapibus dictum Maecenas quam arcu scelerisque ac nibh convallis
mattis interdum leo
READ: Aenean cursus lacus vitae sem feugiat quis congue augue fringilla In mollis
tortor mattis aliquam efficitur Mauris pretium et ante id pulvinar Cras ultricies
euismod tincidunt Donec neque risus egestas vitae varius in gravida nec diam
Aenean odio
READ: Vivamus eget ante ipsum Quisque tincidunt metus sit amet vulputate dapibus
Vivamus imperdiet diam massa eu porttitor felis egestas nec Aliquam quis justo
tellus Donec vel ex ut dui facilisis varius at quis sem Sed sit amet lacus ornare
eleifend eu
Graded Portion – Programming Assignment [graded portion]
You are going to create a simplified version of the Enigma Machine in C/C++. You
may use either C or C++ for this assignment.
usage
./exe -i <configuration file>
./exe -e <in file> <out file> -r <rotor 1 start> <rotor 2 start>
./exe -d <in file> <out file> -r <rotor 1 start> <rotor 2 start>
./exe -e <in file> <out file> -r <rotor 1 start> <rotor 2 start> -i <config file>
./exe -d <in file> <out file> -r <rotor 1 start> <rotor 2 start> -i <config file>
When the user runs the program incorrectly you should give a usage error.
Build a library file called rotorMachine.h and a parallel file rotorMachine.c (or
.cpp). All required function prototypes go in rotorMachine.h and the definitions
for those functions go in rotorMachine.c/.cpp.
Part A – Building the rotors.ini file
For our Rotor Machine to work, the rotors need to be established.
What is a Rotor?
The rotor basically establishes a substitution cipher for text. It’s a 1D array
where the indexes line up with the alphabet, and the contents of the array give
an integer.
Required Function:
Prototype: void buildIni(char *)
Definition: void buildIni(char *filename)
With some simple math we can convert the ASCII value of a character to a matching
array index (int)‘A’ – 65 = 0.
To ensure the Rotor Machine works correctly every time, the rotors need to be
consistent. We will store the rotor configuration in a file called rotors.ini.
This file will be built from another file that will be provided to the Rotor
Machine through the -i <config file> syntax.
Rotors.ini will be encrypted through a simple XOR encryption with the value 42.
Pipeline:
Open the configuration file
Read an integer value
XOR it with the value 42
o value = value ^ 42
Write encrypted value to rotors.ini
int rotor1[28];
int rotor2[28];
These two lines will build two integer arrays size 28 (26 letters + space + ‘.’)
on the Stack.
These arrays will need to be passed to several functions. Because these arrays
“act as their own reference” we can change the contents of them in a function
like how we can do that in java.
Required Function:
Prototype: void buildRotors(int[28], int[28])
Definition: void buildRotors(int rotor1[28], int rotor2[28])
This function takes the two rotor arrays and populates them from the rotors.ini
file.
Read each value from rotors.ini and decrypt them with XOR 42 again.
value = value ^ 42
The first 28 values populate rotor1, the second 28 values populate rotor2.
This function will be called before you encrypt or decrypt any files.
NOTE: if the rotors.ini file doesn’t exist, give the error to the user:
Error: Rotor machine not initialized. Run with -i option and provide an
appropriate configuration file.
Part C – Setting the Rotors their initial positions
Encryption algorithms usually require a ‘key’ to encrypt and decrypt data. If
your key matches, then you can decrypt a message.
The ‘key’ in a rotor machine is the initial setting of the rotors. For the sake
of our machine, rotor1 will rotate right and rotor2 will rotate left.
Required Functions
Prototypes:
o void rotateRotorRight(int[28])
o void rotateRotorLeft(int[28])
Definitions:
o void rotateRotorRight(int rotor[28]);
o void rotateRotorLeft(int rotor[28]);
Rotate Right will move every value down 1 index to the right and move the last
index into the first index.
Before:
18 13 2 12 27 9 19 20 22 11 10 14 1 3 24 15 16 23 8 6 0 17 25 7 5 26 21 4
After:
4 18 13 2 12 27 9 19 20 22 11 10 14 1 3 24 15 16 23 8 6 0 17 25 7 5 26 21
Rotate Left will move every value down 1 index to the left and move the first
index into the last index.
Before:
18 13 2 12 27 9 19 20 22 11 10 14 1 3 24 15 16 23 8 6 0 17 25 7 5 26 21 4
After:
13 2 12 27 9 19 20 22 11 10 14 1 3 24 15 16 23 8 6 0 17 25 7 5 26 21 4 18
With these two functions in place you can create two functions to set the initial
positions of these rotors.
Required Functions:
Prototypes:
o void setRotor1(int[28], int);
o void setRotor2(int[28], int);
Definitions:
o void setRotor1(int rotor[28], int rotations);
o void setRotor2(int rotor[28], int rotations);
These will simply loop the appropriate rotation functions on each rotor.
Remember Rotor1 rotates RIGHT and Rotor2 rotates LEFT.
The initial positions will be provided by the -r <rotations 1> <rotations 2>
part of the usage.
Part D – Do yourself a favor (character conversions)
One way to make all of this easier is to write functions that you can feed
values to and get converted values back.
Required Functions:
Prototypes:
o int charToIndex(char);
o char indexToChar(int);
Definitions
o int charToIndex(char convert);
o char indexToChar(int convert);
These functions simply do the math to convert a character into an array index
and an array index into a character.
charToIndex
Use the toupper(char) function from #include <ctype.h> to convert all characters
to upper case.
The index can be calculated as the ASCII value – 65. You can cast a character
to an integer to get it’s ASCII value. On the alphabet this will translate to the
values 0 – 25.
However, if the character is a SPACE return 26, and if it’s a period return 27.
indexToChar
Take the value in and do the reverse calculation. If it’s a 26 return a ‘ ‘ and
if it’s a 27 return ‘.’; otherwise add 65 to the value and cast it to a
character to be returned.
Part E – Process your command line arguments
In your main, you have a lot of logic to do. To keep our live easier, we’re
going to keep the usage to a very fixed set of syntaxes.
usage
./exe -i <file>
./exe -e <file1> <file2> -r <r1> <r2>
./exe -d <file1> <file2> -r <r1> <r2>
./exe -e <file1> <file2> -r <r1> <r2> -i <file>
./exe -d <file1> <file2> -r <r1> <r2> -i <file>
The user can simply set up the rotors.ini file through ./exe -i <file>
The user can encrypt a file with ./exe -e <in> <out> -r <r1> <r2> using the
current rotors.ini configuration
The user can decrypt a file with ./exe -e <in> <out> -r <r1> <r2> using the
current rotors.ini configuration
The user can encrypt a file and set up the rotors.ini with the syntax:
./exe -e <file1> <file2> -r <r1> <r2> -i <file>
The user can decrypt a file and set up the rotors.ini with the syntax:
./exe -d <file1> <file2> -r <r1> <r2> -i <file>
Like the BASH assignment ANYTHING outside of these syntax patterns should throw
a usage error to the user. Feel free to use the usage above for this error
message.
Part F – Encrypt & Decrypt
Now for the fun part: Encryption and Decryption.
If I want to encrypt A: I start at Rotor 1 and look up the value for ‘A’ which
would be 18, then I search Rotor 2 for the value 18 and get the matching
character, in this case ‘S’.
Decrypting goes the other way around. You take the cipher character and start
from Rotor 2 and match to Rotor 1. So ‘S’ turns back into ‘A’.
If you have the correct rotor configuration and the correct stating positions,
you’ll be able to encode and decode a file.
Required Functions:
C++
Prototypes:
o void encryptFile(ifstream &, ofstream &, int[28], int[28])
o void decryptFile(ifstream &, ofstream &, int[28], int[28])
Definitions:
o void encryptFile(ifstream &infile, ofstream &outfile, int rotor1[28], int rotor2[28]);
o void decryptFile(ifstream &infile, ofstream &outfile, int rotor1[28], int rotor2[28]);
Prototypes:
o void encryptFile(FILE*, FILE*, int rotor1[28], int rotor2[28]);
o void decryptFile(FILE*, FILE*, int rotor1[28], int rotor2[28]);
Definitions:
o void encryptFile(FILE* infile, FILE* outfile, int rotor1[28], int rotor2[28]);
o void decryptFile(FILE* infile, FILE* outfile, int rotor1[28], int rotor2[28]);
The input file will consist of several lines of words with the maximum length of
a line being 255 characters (including spaces). There can be any number of
lines in a file. char buffer[256];
General Notes/Requirements:
Your program should translate all characters to upper-case. Your output
file should be all upper-case letters.
o Space and periods should be maintained.
o File structure (newlines) should be maintained.
If the user doesn’t run the program with proper command-line syntax,
you should report an error and give them proper usage
You should not be doing the file I/O one character at a time, you should be
reading a whole line and processing that line one character at a time.
If there is something that would cause a crash error, then test for it and
crash the program with an appropriate message such as “file not found” you
can use exit(int code); to kill the program
Overall pipeline:
1. Figure out if you have a valid command line syntax
a. NO – usage error
2. Find out if you’re just setting the rotors.ini file
a. YES – process the configuration into the rotors.ini
3. Figure if you’re doing both encryption/decryption AND setting the
rotors.ini file
a. YES – process the configuration into the rotors.ini
b. Run encryption/decryption
4. Encryption/Decryption
a. Setup rotors from rotors.ini
b. Set rotors to initial positions
c. Run encryption/decryption
i. Read a line
ii. Process a character
iii. Rotate rotors
iv. Continue while there are more characters
v. Continue until there are no more lines
d. Close files
Code Hints:
switch does exist in C & C++ if you feel you need it
Even though there is a set of required functions, consider writing other
functions that might help you out. If they are semantically linked to the
Rotor Machine, then add them to your .h/.c(cpp) files
#include <string.h> is OK to use for functions such as strlen(), strcmp(),
etc.
Don’t get too fancy with your data conversions, it’s just simple ASCII math
Much of this assignment is very straight forward assignment involving
if- statements, loops and file I/O …
o If you’re getting all messed up, ask yourself “Am I over-
complicating this?” chances are you are
o The encryption/decryption routines take some thinking, but
are practically identical once you figure them out
You might consider writing your routines without command-line
arguments stuff first
o Get your core algorithms working with hard-coded file names
o Once you know that your algorithms are working, deal with the
command line arguments portion
Don’t forget to torture your code a little. Make sure it works with upper-
case and lower-case. We will possibly use VERY large files in testing your
code.
Sample Output
Example rotor configuration (config.rtr has blue border) 18 56
13 39
./rotormachine -i config.rtr 2 40
12 38
Configuration output (rotors.ini has red border) 27 49
9 35
19 57
Example File (test.txt):
20 62
ABCDEFGHIJKLMNOPQRSTUVWXYZ 22 60
ABC DEF GHI JKL MNO PQR STU VWX YZ 11 33
10 32
ABC.DEF.GHI.JKL.MNO.PQR.STU.VWX.YZ 14 36
1 43
3 41
Encryption command: 24 50
./rotormachine -e test.txt test.enc -r 5 5 15 37
16 58
23 61
Encrypted File contents (test.enc): 8 34
6 44
MLKJIHGFEDCBA. ZYXWVUTSRQP 0 42
ZYRMLKFGFEGSRQSCBAWA. U. ZRYXWRYX 17 59
25 51
RQPQONM ONMMWVUNDCBLBA.NHGFSLKJQBA 7 45
5 47
26 48
Decryption command: 21 63
./rotormachine -d test.enc test.dec -r 5 5 4 46
37
15 48
Encrypted File contents (test.dec): 26 50
24 61
ABCDEFGHIJKLMNOPQRSTUVWXYZ 23 62
ABC DEF GHI JKL MNO PQR STU VWX YZ 20 51
25 40
ABC.DEF.GHI.JKL.MNO.PQR.STU.VWX.YZ 2 39
13 60
22 38
12 32
10 46
4 41
3 33
11 36
14 58
16 49
27 45
7 56
18 47
5 43
1 59
17 35
9 42
0 63
21 57
19 44
6 34
8
Extra Credit Opportunities
TBD
Grading of Programming Assignment
The TA will grade your program following these steps:
(1) Compile the code. If it does not compile a U or F will be given in
the Specifications section. This will probably also affect the
Efficiency/Stability section.
(2) The TA will read your program and give points based on the points allocated
to each component, the readability of your code (organization of the code and
comments), logic, inclusion of the required functions, and correctness of the
implementations of each function.
Rubric:
What to Submit?
Submit these files to Gradescope:
Makefile
rotorMachine.h
rotorMachine.c (or .cpp)
<lastname>_<fistname>_assn3.c (or .cpp)
o For example:
doe_john_assn3.c
doe_john_assn3.cpp
If multiple submissions are made, the most recent submission will be graded,
even if the assignment is submitted late.
Where to Submit?
All submissions must be electronically submitted to the respected homework link in
the course web page where you downloaded the assignment.
Academic Integrity and Honor Code.
You are encouraged to cooperate in study group on learning the course materials. However, you may not
cooperate on preparing the individual assignments. Anything that you turn in must be your own work: You must
write up your own solution with your own understanding. If you use an idea that is found in a book or from other
sources, or that was developed by someone else or jointly with some group, make sure you acknowledge the
source and/or the names of the persons in the write-up for each problem. When you help your peers, you should
never show your work to them. All assignment questions must be asked in the course discussion board. Asking
assignment questions or making your assignment available in the public websites before the assignment due will
be considered cheating.
The instructor and the TA will CAREFULLY check any possible proliferation or plagiarism. We will use the
document/program comparison tools like MOSS (Measure Of Software Similarity: http://moss.stanford.edu/) to
check any assignment that you submitted for grading. The Ira A. Fulton Schools of Engineering expect all
students to adhere to ASU's policy on Academic Dishonesty. These policies can be found in the Code of Student
Conduct:
http://www.asu.edu/studentaffairs/studentlife/judicial/academic_integrity.h
tm
ALL cases of cheating or plagiarism will be handed to the Dean's office. Penalties include a failing grade in the
class, a note on your official transcript that shows you were punished for cheating, suspension, expulsion and
revocation of already awarded degrees.