Computer Science Assignment 5

COMP 2103X1 Assignment 5 Due Thursday, February 16 by 7:00 PM General information about assignments ( important!):

http://cs.acadiau.ca/ ~jdiamond/comp2103/assignments/General-info.html Information on passing in assignments:

http://cs.acadiau.ca/ ~jdiamond/comp2103/assignments/Pass-in-info.html Information on coding style:

http://cs.acadiau.ca/ ~jdiamond/comp2103/assignments/C-coding-style-notes [1] On planet Lightplane, the former Cessna rulers used to record time in a system called Highwings. Each year was divided into 13 months called (in order) alpha,bravo ,charlie ,delta ,echo ,foxtrot , golf ,hotel ,india ,juliet ,kilo ,lima andmike . The rst twelve months of this calendar are all 30 days long, and the thirteenth month has 20 days. The days are numbered from 0 to 29 (except the last month, whose days are numbered from 0 to 19). For example, in the Highwings calendar the 12 th day of the 3rd month of the 2103rd year would be written “2103 charlie 11”.

Recently, the Cessna rulers (having suffered greatly at the hands of the terrorist group Lawyers) were overthrown by the Pipers, who instituted the use of a different calendar, called Lowwings.

(The Pipers were also brutalized by the Lawyers, but somehow managed to survive.) Lowwings has 20 months, all of which have 12 days. (Lightplane's axis is not tilted like the earth's, so the fact that the two years have different lengths is not signi cant like it would be on this planet.) The Pipers number their months from 1 to 20, but give the days names; the names (in order from the rst day of the month to the last) are called november,oscar ,papa ,quebec ,romeo ,sierra ,tango , uniform ,victor ,whiskey ,xray andzulu . For example, in the Lowwings calendar the 12th day of the 3rd month of the 2103rd year would be written “2103 3 zulu”.

In both systems, the rst year is numbered 0. Fortunately, the Pipers agree with the Cessnas on when the very rst day was. And they both have exactly the same concept of what a “day” is.

Naturally, this change of calendar caused considerable confusion. Your job is to help the people of Lightplane by writing a C program which converts dates from Highwings to Lowwings. The input format to your program is one line containing the number Nof dates to convert. On the following N lines there are NHighwings dates, exactly one date per line. You should convert each of these dates to Lowwings and, for each input date, output a line with both dates. For example, if the input to your program is 2 0 alpha 11 1 charlie 17 then your output should look like Highwings 0 alpha 11 is Lowwings 0 1 zulu Highwings 1 charlie 17 is Lowwings 1 19 oscar Test your program on a variety of dates aside from those I gave you. Make sure you include some dates which are “boundary conditions” (last day of year or month for Highwings calendar, rst day 1 of year or month for Highwings calendar, last day of year or month for Lowwings calendar, rst day of year or month for Lowwings calendar, : : :). You should do basic checking on the input data to make sure someone hasn't entered an illegal date.

Hints:

(i) You can declare and initialize an array of strings with a statement like char * numbers[] = { "prime", "seconde", "tierce", "quarte" }; Naturally, your array will have to have more (and different) entries than what I showed here.

(ii) You can compare strings with the strcmp()function. See your C manual, textbook, or the man page for details.

(iii) You might nd the %operator useful in this assignment. (Or not, depending on your solution technique.) [2] Some people like to read left to right, and some people like to read right to left. For this problem, you will write a program which takes an input le and reverses each of its lines, writing the output to another le. Your program gets the input and output le names as command line arguments (the rst command line argument is the input le, the second is the output le).

Part of a sample terminal session could look like this (with the user input inred): %a5p2 file1 file1.rev %cat file1 This is the first line.

And this is the second line.

a dog a plan a canal: pagoda otto now I won %cat file1.rev .enil tsrif eth is sihT .enil dnoces eth is siht dnA adogap :lanac a nalp a god a otto now I won % Notice that in a valid text le everyline ends with a “ ” character, so you need to be a bit careful when reversing things. (Just because some text editors don't automagically put a newline char at the end of the le doesn't mean that the resulting le is a valid text le.) For up to three bonus points, attempt to ensure that the output le does not already exist before you (attempt to) over­write it. If you code this, you must show a test for it too!

If you think about it a bit, you should realize that if you run some text through your program twice, you should get the original le back. This helps you test the correct functioning of your program, as follows: %a5p2 file1 file1.rev %a5p2 file1.rev file1.rev.rev %diff file1 file1.rev.rev 2 If diff reports no differences, then you got back to where you started. If there are differences, diff will give you a summary of them. You might also consider using the cmpprogram to compare the original and the reversed­reversed le. When creating your script le, you should use catto show the original and reversed les for a couple of (smallish) cases, and you can use difforcmp for some “bigger” cases. To show the marker how big an input le was without catting the le into your script le, you can use the wccommand:

%wc big-honkin-file 63997 535777 3114540 big-honkin-file % Keep in mind that you can think of argv[]as an array of strings, and since fopen()takes a string argument, you can just hand the appropriate array element to fopen().

For the purposes of thisproblem, it is acceptable to make the limitation that your program will only work correctly with les whose lines are allless than 80 characters long. (Note that I do not count the line­ending character in the length of the line, but nonetheless every line must end with .)HOWEVER , your program should do something intelligent in this case; you should (at a minimum) output an error message telling the user that your program could not handle their input le. At this point your program can either exit, or it can do what it will with the long line and carry on forward. Your program comment should indicate what your code is designed to do for this case.

Are there any special cases that you should consider, code for, and test?

[3] In C you can access the command­line arguments by using argcandargv . Since arrays in C don't “know” their own size, the argcparameter to main()is required to know how many arguments there were. (Note that the name the program was called by is put in argv[0], soargc is always at least 1.) In main() ,argv is declared as char * argv[] Ž , which is an array of strings. We haven't learned much about strings yet, but you have learned that a string in C is just a block of consecutive memory locations (like an array), with the characters of the string in consecutive memory locations, followed by the all­important ASCII NUL character (“ \0”). So the statement printf("My name is %s ", argv[0]); will print out the name of the program. (Try writing a six­line (or so) C program to try this out!) We also learned in class that integers in C can not store arbitrarily big integers; on a 32­bit computer an int can store numbers from roughly 2; 000; 000 to2; 000; 000 . (Review question: what are the exact limits?) But sometimes In Real Life we must do integer arithmetic with bigger integers than will t in a 32­bit (or even 64­bit) integer. In this problem you will write a program to do arithmetic on big integers.

Speci cally, your program will act as follows (i) it will check its command line arguments to make sure it has exactly two arguments (in addition to the program name); (ii) it will con rm that both arguments are composed only of digits (so you don't need to worry Ž You may also see char ** argv, which is (arguably) deprecated.

3 about negative inputs); (iii) it will con rm that the arguments aren't too long (see below); (iv) it will then add and subtract (and, for lotsof bonus points, multiply and divide) the numbers given as command line arguments; and (v) it will nally print the results and exit.

Here is a sample terminal session of the bonus version. The non­bonus version looks the same except no products or quotients are given: $a5p3 123 456 123 + 456 = 579 123 - 456 = -333 123 * 456 = 56088 123 / 456 = 0 $ $a5p3 7654321982228 2323223 7654321982228 + 2323223 = 7654324305451 7654321982228 - 2323223 = 7654319659005 7654321982228 * 2323223 = 17782696878517680844 7654321982228 / 2323223 = 3294699 $ Addition and subtraction are relatively straightforward. Just as you would do by hand, you start at the right end and work left, keeping track of carries as you go. When you are at the last digit of either the rst or second number, you add any “carry” (or subtract any “borrow”) and you are done.

The bonus multiplication is trickier. Observe that you can multiply 123 by 456 as follows:

(i) initialize a “running sum” to 0; (ii) multiply 123 by 6 (go from right to left, keeping track of carries; (iii) add the product of 123 and 6 to the running sum (using your addition function) : : :the running sum is now 738; (iv) multiply 123 by 5 (giving 615), and add it to the running sum, but start adding into the running sum from its second rightmost digit, not the rightmost digit : : :the running sum is now 6888; (v) multiply 123 by 4 (giving 492), and add it to the running sum, but start adding into the running sum from its third rightmost digit, not the rightmost digit : : :the running sum is now 56088; (vi) you have used all the digits of the multiplier, so you are done.

The bonus division is trickier yet. Noting that the multiplication operation is very similar to the one you would use by hand, you can imagine how you would do division in an analogous way.

WARNING: division and multiplication may take you a long time to implement, do not spend too much time on the bonus parts of this problem.

Suggestions, reminders and hints.

(i) Don't forget that you subtract the smaller number from the bigger number, then make the result negative if you had to switch the numbers around. SO when performing subtraction, you have to discover a rule which tells you which number is bigger, beforeyou start subtracting.

(ii) strlen() can be used to determine how long the two arguments are.

4 (iii) Declare one array (or more, if doing bonus parts) of either type charorint to hold your result. If you want, you may declare an upper limit on the length of your numerical results and give an error message if the inputs are too long for your program to handle. But knowing that you can declare an array in your program aftercalculating how many digits are needed in the result, you really shouldn't need to do this.

(iv) If you have a char cwhich you know is a digit, you can convert that to the corresponding number with the expression c -'0 ', since the ASCII character set has the 10 digits in 10 consecutive locations. You can translate a number from 0 to 9 to a character in an analogous way.

(v) Your design is up to you, but I suggest you write functions like this: int bigadd(char result[], char num1[], char num2[] and have your function return a number less than 0 if there is any error, and otherwise it can return a number indicating how many digits are in the result.

(vi) After checking the command­line arguments and declaring an array result[]which is big enough to hold the result, you can call bigadd()as follows:

ret = bigadd(result, argv[1], argv[2]); Note that, although C arrays don't “know” how big they are, and so normally we must hand array lengths to functions, in this case the arrays hold character strings, and character strings always end with a '\0 'character, so the functions can discover the lengths for themselves.

You could hand the lengths to the functions if you want to add a couple more parameters, the choice is yours. Did you use functions in any of these questions? Should you have? Did you document them correctly?

Does you program “blow up” on unexpected input, or does it deal with bad input in a “graceful” way?

How does your program deal with boundary conditions, if there are any?

Did you remember to put all required comments in? Does your program call out for any other comments in the body of the code?

5