Decision-making in C Squeezing Digits out of an Integer Assignment For part of this assignment, you will use very basic C techniques to implement a C function to remove from a given nonnegative integer all the even (or odd) digits, and return the resulting integer. For example: squeeze even digits from 1961316882: 19131 squeeze odd digits from 1205714786: 20486 squeeze odd digits from 7911359: 0 You will provide an implementation for a C function that performs this calculation: /** Pre: N is initialized * Action is EVEN or ODD * Returns: integer obtained by removing all EVEN (or all ODD) digits * from N; 0 if no digits of N remain * * Restrictions: * - uses only its parameters and local automatic variables * - does not make any use of character variables or arrays * - does not read any input or write any output */ unsigned int SqzInteger(unsigned int N, enum Process_Choice Action); For the rest of the assignment, you will finish the implementation of the short C program that is supplied later in this specification (and on the course website). The completed program provides a means of testing your implementation of the function SqzInteger() described above, and is what you will submit to the Curator for grading. The supplied program provides some code and comments indicating how it can be completed. The supplied program will compile, but you must add code in the indicated places in order for it to work correctly. The restrictions stated in the header comment for the function are not enforced by the autograding system, but they will be checked by a TA after the project is closed. Violating the restrictions will result in a score of 0. The completed program will read test data from an input file, that will be named on the command line when the program is executed. Here is a sample file: odd 92488844 even 137557 odd 135791593 even 86188243 even 46010890 odd 398402673 even 91560820 odd 65724 Each line will contain a string ("even" or "odd"), followed by one or more spaces, followed by a nonnegative integer. There is no limit on the number of lines of test data that may occur in the file, so the program that reads the file must be designed so that it works correctly by detecting the end of the input data. The input file is guaranteed to follow the specified format, so you don't have to check for errors of that sort. This is a purely individual assignment! 1
The program will write results to a file, that will be named on the command line when the program is run. Here is a sample output file that corresponds to the input file shown above: 92488844(no_odds) 2488844 137557(no_evens) 137557 135791593(no_odds) 0 86188243(no_evens) 13 46010890(no_evens) 19 398402673(no_odds) 84026 91560820(no_evens) 915 65724(no_odds) 624 For each input line, there is one output line, displaying the given nonnegative integer, followed by a string inside parentheses indicating how the integer was "squeezed", followed by one or more spaces, followed by the "squeezed" integer value returned by your implementation of the function SqzInteger(). The values should be neatly aligned, as shown above. You might take advantage of the fact that an unsigned int in C won't have more than 10 digits in its base-10 representation. You should test your solution thoroughly; there is no guarantee that the supplied test data covers all cases. You may assume that the supplied data will be logically correct. You should not make any other assumptions about the test data values. Make useful comments in your implementation of SqzInteger(). The same general guidelines for commenting that you have been taught in your Java courses should provide sufficient guidance. Testing You should begin by downloading the posted C source file, SqzInteger.c, from the course website, and editing it to satisfy the requirements given above. To compile the program, you should use the following command: CentOS> gcc o SqzInteger std=c99 Wall SqzInteger.c Once you've eliminated compile-time errors (and ideally warnings as well), you should download test files from the course website. Say the first input file is named DataIn01.txt; then you could execute the program by using the following command: CentOS>./SqzInteger DataIn01.txt DataOut.txt Next, you should compare the output file your program writes to the corresponding posted output file. If there are differences, analyze the reason for them and fix your code. Repeat as necessary. You should not submit your solution to the Curator until you can correctly process all the posted test files. Even then, the posted data files are not guaranteed to include all the possible logical cases, so you should consider writing additional test files. It is perfectly OK to share test data files with other students, including on the course Forum board. What to Submit Submit your completed version of SqzInteger.c, after making changes and testing. Your submission will be compiled, tested and graded according to the formatting of your output and how many cases your solution handles correctly. You will be allowed a limited number of submissions for this assignment (at least 10). Use them wisely. Test your program thoroughly before submitting it. Make sure that your program produces correct results for every test case you can think of. If you do not get a perfect score, analyze the problem carefully and test your fix with the test data shown in the Curator grade report, before submitting again. The highest score you achieve will be counted. This is a purely individual assignment! 2
The Student Guide and other pertinent information, such as the link to the proper submit page, can be found at: http:www.cs.vt.edu/curator/ Pledge: Each of your program submissions must be pledged to conform to the Honor Code requirements for this course. Specifically, you must include the following pledge statement in the submitted file: On my honor: - I have not discussed the C language code in my program with anyone other than my instructor or the teaching assistants assigned to this course. - I have not used C language code obtained from another student, or any other unauthorized source, either modified or unmodified. - If any C language code or documentation used in my program was obtained from an authorized source, such as a text book or course notes, that has been clearly noted with a proper citation in the comments of my program. - I have not designed this program in such a way as to defeat or interfere with the normal operation of the Curator System. <Student Name> Failure to include this pledge in a submission may result in a score of zero being assigned. This is a purely individual assignment! 3
Supplied code: The following code is supplied on the course website. You should use this file as your starting point. Feel free to modify the design used here, but your solution must conform to the requirements stated above, and the SqzInteger() function must retain the specified interface. The code contains numerous comments that explain what is being done (or should be done) when the program is executed. Since the comments also serve as a tutorial for some aspects of C coding, you should read them carefully. /** CS 2505 Summer 2015 * Supplied framework for "squeeze out digits" project. Your task is to * complete the supplied code to satisfy the posted specification for this * assignment. Comments at various places in the code below indicate where * you must complete the implementation. * * Student: <ENTER YOUR NAME HERE> * PID: <ENTER YOUR VT EMAIL PID HERE> */ #include <stdio.h> #include <stdlib.h> #include <string.h> We will expect the longest line in the input file to contain no more than 100 characters (which is generous in this case). const unsigned int MAX_LINE_LENGTH = 101; Rather than use a nondescriptive label, or none at all, we will use an enumerated type to make the logic of the code clearer: enum Process_Choice {EVEN, ODD; SqzInteger() removes all digits from N that do meet the specified Action (ODD or EVEN), and returns the resulting integer. If all the digits of N are removes, 0 is returned. unsigned int SqzInteger(unsigned int N, enum Process_Choice Action); int main(int argc, char* argv[]) { This program expects the user to supply the names of an input file and an output file on the command line. Therefore, it checks for that and exits with a diagnostic message if the number of command line tokens is incorrect: if ( argc!= 3 ) { printf("invocation: squeezeint inputfilename outputfilename\n"); return 1; Attempt to open the specified input file; exit with a diagnostic if it cannot be opened for reading: FILE* Input = fopen(argv[1], "r"); if ( Input == NULL ) { printf("could not open input file: %s\n", argv[1]); return 2; This is a purely individual assignment! 4
Attempt to open the specified output file; exit with a diagnostic if it cannot be opened for writing: FILE* Output = fopen(argv[2], "w"); if ( Output == NULL ) { printf("could not open output file: %s\n", argv[2]); fclose(input); return 3; Note that we use different exit values for different errors; that's good practice. char Line[MAX_LINE_LENGTH]; char actionflag[max_line_length]; unsigned int N = 0, squeezedn = 0; holds the current input line holds the current Action holds the integer to be "squeezed" holds the "squeezed" integer The loop uses the read-to-input-failure pattern. That is, we will attempt to read the next expected input from the file, and then validate that reading, before we attempt to process any data. In the loop test, we take advantage of the fact that fgets() will return NULL If it fails to read any input. That will force the loop to terminate when the end of the input file is reached. while ( fgets(line, MAX_LINE_LENGTH, Input)!= NULL ) { Try to read the actionflag from the input line that was just read into Line; sscanf() will return 0 if nothing was read. In that case, write a diagnostic message, skip the remainder of the loop body and look for another line of input. if ( sscanf(line, "%s", actionflag) /*?? TEST?? */ ) { printf("failed to read an actionflag value from %s\n", Line); continue; Try to read an integer value from the input line that was just read into Line. Here, we encounter one limitation of sscanf(); it does not maintain any knowledge of previous calls, so it resumes reading from the beginning of Line. We could sidestep that issue by reading both the actionflag and the integer in a single call to sscanf(); but that makes checking the results of the two read operations clumsy. Instead, we take advantage of a C format specifier feature; if we follow the '%' with an asterisk, a value is read and then discarded. In this case we reread the action flag value but don't save it. if ( sscanf(line, "%*s %d", &N) /*?? TEST?? */ ) { printf("failed to read an integer value from %s\n", Line); continue; Determine whether the actionflag indicates we should squeeze out the even digits, or the odd digits, or that there was something wrong with the actionflag. strcmp() compares two (C-style) character strings; it returns zero if the strings match, something negative if the first This is a purely individual assignment! 5
string precedes the second string, and something positive if the first string follows the second string. if ( strcmp(actionflag, "even") == 0 ) { squeezedn = 0; CALL THE FUNCTION!! WRITE RESULTS TO THE OUTPUT FILE!! else if ( strcmp(actionflag, "odd") == 0 ) { squeezedn = 0; CALL THE FUNCTION!! WRITE RESULTS TO THE OUTPUT FILE!! else { This should NEVER happen... fprintf(output, "Unrecognized action flag: %s\n", actionflag); It's important to explicitly close files when we are finished with them, because: - the OS needs to know the files are no longer in use - output written to a file is buffered and may not actually reach the file unless it is properly closed fclose(input); fclose(output); Traditionally, return 0 on successful termination. return 0; /** Pre: N is initialized * Action is EVEN or ODD * Returns: integer obtained by removing all EVEN (or all ODD) digits * from N; 0 if no digits of N remain * * Restrictions: * - uses only its parameters and local automatic variables * - does not make any use of character variables or arrays * - does not read any input or write any output */ unsigned int SqzInteger(unsigned int N, enum Process_Choice Action) { unsigned int Squeezed = 0; IMPLEMENT THIS!! return Squeezed; This is a purely individual assignment! 6