This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
haas:fall2015:cprog:projects:sam0 [2015/10/27 16:43] – created wedge | haas:fall2015:cprog:projects:sam0 [2015/10/29 12:26] (current) – [Sample execution: encode] wedge | ||
---|---|---|---|
Line 12: | Line 12: | ||
=====Background===== | =====Background===== | ||
- | This trick' | + | A cipher |
- | For starters, let us try it out: | + | In the realm of secrecy (think elementary school secret agent), obfuscation is key. If we can remove direct accessibility to the message (encode), yet still preserve its intent, it can be transmit to a recipient who has the ability to retrieve the message (decode). |
- | < | + | The caesar cipher (or shift cipher) is a relatively simple cipher, where each letter of the alphabet is shifted by a fixed amount, enabling a once legible message to appear unrecognizeable (at least directly). |
- | | + | |
- | - 941 | + | |
- | | + | |
- | 059 | + | |
- | </ | + | |
- | The thing is, we aren't going to be solving this the usual way. We're going to do it from left to right. So, a walkthrough of what just happened: | + | Further background information can be found here: |
- | * We start with the left-most digit to digit subtraction (the 0 - 9). As this isn't the last (right-most) subtraction, | + | * https://en.wikipedia.org/ |
- | * Move one place to the right (0 - 4)... how much to add to 4 to get 9? **5**. Bam. | + | |
- | * Move one place to the right-- we're now at the last digit. And last is from 10. So, how much to add to 1 to get 10? **9**. | + | |
- | * We see our answer is **059**. | + | |
- | Clearly, there are some prerequisites that need to be met in order to use this trick: | + | There are two processes related |
- | * the top number needs to be 1 followed | + | * encoding - taking |
- | * the number we're subtracting is smaller than the number we're subtracting from. | + | * decoding - taking the obfuscated text and making it readable, |
+ | =====Program===== | ||
+ | You are to implement two programs (or at least a program with two fundamental modes of operation): | ||
+ | * encode program: takes plain text message as input, along with a cipher | ||
+ | * key should be provided via command-line argument (or, if present, a file in the current directory called ' | ||
+ | * decode program: takes the encoded (obfuscated) message, along with a cipher key, and outputs the decoded (readable, plain text) result | ||
+ | * key should be provided via command-line argument (or, if present, a file in the current directory called | ||
- | Try your hand at another: | + | The key should be a **signed char**, allowing for a cipher shift of -128 to +127 (your shift can be left or right, depending on the sign of the number). |
- | < | + | You can implement this as two separate programs, or as one program that behaves fundamentally different depending on how it is named (ie **encode-sam0** operates in encode mode, **decode-sam0** operates in decode mode). |
- | | + | |
- | - 928573956013453 | + | |
- | | + | |
- | </ | + | |
- | Go ahead and try it (work it out on paper). | + | Your program(s) should: |
+ | * load the provided input (via STDIN) into an array for processing (you may want to check for an EOF character to terminate input) | ||
+ | * you may assume a maximum input size of 4096 bytes | ||
+ | * use the **fgetc()** function instead of **fscanf()** for reading input from STDIN | ||
+ | * obtain the signed char key value from the command-line, | ||
+ | * if neither command-line nor key file are available, display error and exit | ||
+ | * appropriately " | ||
+ | * for encoding, display the resultant enciphered string to STDOUT | ||
+ | * for decoding, display the resultant deciphered string to STDOUT | ||
- | The answer is: **071426043986547** | + | ====Sample execution: encode==== |
+ | Via positive command-line key: | ||
+ | <cli> | ||
+ | lab46: | ||
+ | hello | ||
+ | jgnnq | ||
+ | ^D | ||
+ | lab46: | ||
+ | </ | ||
- | =====Task===== | + | Via negative command-line key: |
- | The task at hand can benefit from loop and array assistance. | + | |
- | For instance, taking the number input and processing it so each digit occupies its own array element would facilate your efforts in the overall task-- a process strongly resembling some of the work you had to do in the **mbe1** project to get your input ready for the multiply by 11 activity. | + | < |
+ | lab46: | ||
+ | hello there | ||
+ | ebiil qebob | ||
+ | ^D | ||
+ | lab46: | ||
+ | </ | ||
- | =====Functions===== | + | Without command-line nor cipher.key file: |
- | As indicated, this task shares many attributes with the **mbe1** project; in fact, the mental math process itself may be slightly simpler. That affords us the opportunity to introduce and learn about further programming optimizations, | + | |
- | Specifically, | + | < |
+ | lab46: | ||
+ | ERROR: key not found | ||
+ | lab46: | ||
+ | </ | ||
- | We've been using functions all along (everytime you use **fprintf()** or **fscanf()**, | + | With 4 in the cipher.key file: |
- | ====Function prototype==== | + | <cli> |
- | Like variables, functions need to be declared. | + | lab46: |
+ | hello there | ||
+ | lipps xlivi | ||
+ | ^D | ||
+ | lab46: | ||
+ | </ | ||
- | We can declare them at various scopes (file/global, block/ | + | With 4 in the cipher.key |
- | If a particular function is only to be used by a specific function, and no others, you can opt to declare it local scope (ie within the function that will be calling it). | + | < |
+ | lab46: | ||
+ | lipps xlivi | ||
+ | hello there | ||
+ | ^D | ||
+ | lab46: | ||
+ | </ | ||
- | A function is basically a module or subroutine. It is a mini-program, focusing on the performing of a particular process. | + | Via positive command-line key, decoding: |
- | Like a program, it takes input, does processing, and provides output. | + | < |
+ | lab46: | ||
+ | jgnnq | ||
+ | hello | ||
+ | ^D | ||
+ | lab46: | ||
+ | </ | ||
- | Unlike a program, its input may not come from the keyboard, but instead from particular variables, and may not send output to the screen, but instead channel output in a way that it can be stored into a variable. | + | You can also save typing, by providing your input via a here string |
- | + | ||
- | This distinctions aside, a function can in many ways be viewed as a micro- or sub-program/ | + | |
- | + | ||
- | Keeping everything in ONE file, ONE big function in that one file, is rather monolithic. In time, with sufficiently large programs, such an arrangement would become a tad unwieldy. So functions help to keep our focus short yet attentive. | + | |
- | + | ||
- | To create a function we must first declare (or prototype) it. This needs to happen BEFORE said function is ever used (just as with variables- you must declare a variable before it is first used, otherwise the compiler yells). | + | |
- | + | ||
- | A function, in many ways, is like a programmable variable (or is a variable with programming attached). | + | |
- | + | ||
- | As such, it has a return value of a type (the function' | + | |
- | + | ||
- | We see this with main()... here are two variations of a **main()** function declaration (technically | + | |
- | + | ||
- | ===Parameterless function=== | + | |
- | + | ||
- | <code c> | + | |
- | int main() | + | |
- | </ | + | |
- | + | ||
- | In this example, we see the declaration of main() where it has a return value of **int**, meaning, upon completion, main() will return a value corresponding with an int data type (also in main()' | + | |
- | + | ||
- | main(), in this case, takes no parameters (just an empty set of parenthesis)... due to this, we refer to this function as a parameterless function. A function without parameters. Without input. | + | |
- | + | ||
- | Now: this is technically a different form of input and output than you are used to. Input doesn' | + | |
- | + | ||
- | Additionally, | + | |
- | + | ||
- | ===Parametered function=== | + | |
- | + | ||
- | <code c> | + | |
- | int main(int argc, char **argv) | + | |
- | </ | + | |
- | + | ||
- | In this case, our **main()** function actually takes parameters- two, in fact: | + | |
- | + | ||
- | - an integer, we are calling **argc** | + | |
- | - a double pointer, we are calling **argv** | + | |
- | + | ||
- | This function takes two parameters, two pieces of input, available to us in the form of variables, by those names, of those types. We make use of them as we need to in accomplishing the program at hand. | + | |
- | + | ||
- | So, when we wish to create functions of our own, we need: | + | |
- | + | ||
- | * the return type | + | |
- | * the function name | + | |
- | * 0 or more parameters, identifying their order and type | + | |
- | + | ||
- | For example, let us make a sum() function. Here would be a likely prototype (we'd place it above main()): | + | |
- | + | ||
- | < | + | |
- | int sum(int *, int); | + | |
- | </ | + | |
- | + | ||
- | A function prototype (vs. its definition) will have a terminating semi-colon, as you see above. | + | |
- | + | ||
- | In our case, our sum() function has the following: | + | |
- | + | ||
- | * a return type of **int** (particular variable name doesn' | + | |
- | * the function' | + | |
- | * a comma-separated list of types corresponding to the parameters (again, variable names do not matter, but the type is important). | + | |
- | + | ||
- | Our sum() function will take an integer array (denoted by the int pointer above), and a size (the second, regular int). | + | |
- | + | ||
- | Now, parameter order very much matters. In our case, an "int *" came first, followed by an " | + | |
- | + | ||
- | ====Function definition==== | + | |
- | While a function prototype is technically optional (you can put the definition in place of the prototype-- we just often use prototypes to further allow organization), | + | |
- | + | ||
- | Our sum() function will be defined (below the main() function) as follows: | + | |
- | + | ||
- | <code c> | + | |
- | int sum(int *array, int size) | + | |
- | { | + | |
- | int result = 0; | + | |
- | int i = 0; | + | |
- | + | ||
- | for (i = 0; i < size; i++) | + | |
- | result = result + array[i]; | + | |
- | + | ||
- | return(result); | + | |
- | } | + | |
- | </ | + | |
- | + | ||
- | ====function calling==== | + | |
- | Once we've declared (prototyped) and defined our function, now all we have to do is use it! When you make use of a function, we refer to it as // | + | |
- | + | ||
- | Here would be an example of calling the above-mentioned **sum()** function: | + | |
- | + | ||
- | <code c> | + | |
- | int scores[4]; | + | |
- | int tally = 0; | + | |
- | + | ||
- | scores[0] = 88; | + | |
- | scores[1] = 47; | + | |
- | scores[2] = 96; | + | |
- | scores[3] = 73; | + | |
- | + | ||
- | tally = sum(scores, 4); | + | |
- | </ | + | |
- | + | ||
- | Note, that it is rather important to match the type and order of parameters. Due to the nature of the array (especially the form of array declaration) used, certain pointer-related details are being hidden from us, giving somewhat of a false impression. Further discussion about pointers will begin to shed light on that. | + | |
- | + | ||
- | + | ||
- | =====Program===== | + | |
- | It is your task to write a program that obtains a long integer value from the user, and processes that single value into separate array elements (one digit per array element). Determining the number of digits, you are to perform this "all from nine, last from ten" subtraction method on the number using array transactions, | + | |
- | + | ||
- | Your program should: | + | |
- | * obtain its input from STDIN. | + | |
- | * input should be in the form of a single | + | |
- | * determine the number of digits of the inputted value (store this in a variable) | + | |
- | * process that input long integer into separate array elements- one digit per element. | + | |
- | * you may assume a maximum array size of the maximum number of digits you're theoretically able to input that can be stored in a 64-bit value. | + | |
- | * perform the "all from nine, the last from ten" operation on the array, storing the result in another array. | + | |
- | * display the problem being solved, along with the answer | + | |
- | * use functions to modularize your code: | + | |
- | * have an **longint2array()** function that takes the long int, and returns an array (the function itself handles the processing of splitting up the long int into individual digits). | + | |
- | * have a **printarray()** function, whose responsibility it is to display the indicated array to STDOUT. | + | |
- | * have a **allfromnine()** function that takes the source array, does the processing, and returns ther result array. | + | |
- | + | ||
- | I might suggest the following function prototypes: | + | |
- | + | ||
- | <code c> | + | |
- | unsigned char *longint2array(unsigned long int); | + | |
- | void printarray(unsigned char *, unsigned char); | + | |
- | unsigned char *allfromnine(unsigned char *); | + | |
- | </ | + | |
- | + | ||
- | Some questions to contemplate: | + | |
- | + | ||
- | * Why an array of unsigned chars when we're starting with a long (long) int? | + | |
- | * Why is that the "best fit" size-wise? | + | |
- | * Why will that not result in lost data? | + | |
- | * Why unsigned? | + | |
- | * What impact will that have on our input value' | + | |
- | * Why represent the size of the usable array as an unsigned char? | + | |
- | * Why is this the "best fit" size-wise? | + | |
- | =====Execution===== | + | |
- | An example of your program in action: | + | |
<cli> | <cli> | ||
- | lab46: | + | lab46: |
- | Enter value: 31415926535897 | + | hello |
- | Digits detected: 14 | + | |
- | + | ||
- | | + | |
- | - 31415926535897 | + | |
- | | + | |
- | 68584073464102 | + | |
lab46: | lab46: | ||
</ | </ | ||
- | |||
=====Submission===== | =====Submission===== | ||
To successfully complete this project, the following criteria must be met: | To successfully complete this project, the following criteria must be met: |