Tutorials 3 Programming in ANSI/ISO C Week 3: Data Abstraction Up | Site Map Tutorial Exercises Objectives During this tutorial you will examine some sample solutions for a series of relatively simple problems. These solutions demonstrate good coding style and layout. Examine the question and suggested solution. Ensure that you understand how the solution works. Use this as an opportunity to clarify your understanding of C syntax and semantics. Note that the comments presented are not intended to illustrate the expected content of comments; the ones presented actually describe apparent anomalies and C language features. Even the header comment should reflect the history of the program's development and its purpose. Feel free to ask your instructor questions in the discussion forums or chat sessions about any aspect of these solutions. Example 1 "Write a program to print out a Celsius to Fahrenheit conversion table. The table will be prefixed with a simple header and will contain conversions in the range -200 to +200 degrees Celsius in steps of 25 degrees. The Fahrenheit conversions should be printed in floating-point format to an accuracy of two decimal places; columns should be left justified." Points to note about the "Model" Answer: Layout and Style conventions. Use of const rather than #define. Use of EXIT_SUCCESS. /**************************************************************** * * * Example 1: Sample Solution * * Daryl D'Souza * * * ****************************************************************/ #include /* for function prototype of printf */ #include /* for definition of EXIT_SUCCESS */ int main() { /* note that "1.8" below is of type const double. In */ /* assigning a double to a float, the precision is */ /* truncated or rounded up as necessary, as long as the */ /* double value is within the range representable by */ /* floats. If not, the result of conversion is */ /* undefined. Clearly there will be no problems in this */ /* case. */ const float CelsiusToFahrenheit = 1.8; /* One might argue that all the const ints below should */ /* in fact be floats, and that "Celsius" should be float */ /* also. Wherever "Fahrenheit" values are calculated */ /* however the integral values will be implicitly */ /* converted to floats before calculation takes place. */ /* Some would argue that these expressions should be */ /* explicitly cast to floats in the text of the */ /* program to indicate that the programmer is aware of */ /* what will be taking place anyway i.e. : */ /* Fahrenheit = (float) FahrenheitZero + */ /* (float) Celsius * CelsiusToFahrenheit; */ const int FahrenheitZero = 32; const int CelsiusMin = -200; const int CelsiusMax = 200; const int CelsiusStep = 25; int Celsius; float Fahrenheit; /* print a basic but suitable header */ printf("\n\t---------------------\n"); printf("\t| Celsius | F'heit |\n"); printf("\t---------------------\n"); /* the loop is simple enough with constant bounds and */ /* an integral step value. Because of this, the fahren- */ /* heit step value could be computed once and simply */ /* added on each iteration. This would be a poor */ /* strategy in the general case however, because any */ /* loss of precision in computing this floating point */ /* step value would be amplified "n" times on the "nth" */ /* iteration of the loop. */ for(Celsius = CelsiusMin;Celsius <= CelsiusMax; Celsius += CelsiusStep) { Fahrenheit = FahrenheitZero + Celsius * CelsiusToFahrenheit; /* oops! Had to modify the field width slightly */ /* to obtain a reasonable table format without */ /* messing around too much, e.g. */ /* computing the actual field width of the fahr- */ /* enheit value to be printed. */ printf("\t| %-6d | %-7.2f |\n",Celsius,Fahrenheit); printf("\t---------------------\n"); } return EXIT_SUCCESS; } Example 2 "Write a program to print out the powers of 2 between zero and 5000 in decimal, octal and hexadecimal format." Points to note about the "Model" Answer: Equivalence between for-loop and while-loop constructs Conversion characters for displaying in hexadecimal and octal. /**************************************************************** * * * Example 2: Sample Solution * * Daryl D'Souza * * * ****************************************************************/ #include /* for prototype of printf */ #include /* for definition of EXIT_SUCCESS */ int main() { /* Not much to say about this one. Uses a "while" loop */ /* just as a contrast to the more obvious "for" loop. */ int i = 1; const int max = 5000; while(i <= max) { printf("%6d%6o%6x\n",i,i,i); i *= 2; } /* could also have been: for (i = 1; i <= max; i*=2) { printf("%6d%6o%6x\n",i,i,i); } or, since we know that the loop body must be executed at least once : do { printf("%6d%6o%6x\n",i,i,i); i *= 2; } while (i <= max); */ return EXIT_SUCCESS; } Example 3 "Write a program to count spaces, tabs, and newlines [read from standard input]" Points to note about the "Model" Answer: Switch statement. Multi-way conditional. Can often be used in placed of a large cascaded if-statement. Arguably more readable and can sometimes be more efficiently translated by the compiler than a cascaded if-statement equivalent. /**************************************************************** * * * Example 3: Sample Solution * * Daryl D'Souza * * * ****************************************************************/ #include #include int main() { /* The simple kind of utility program with ascii text */ /* input that C does well. Note the phrasing of the */ /* test in the "while" loop which uses the side-effect */ /* of the assignment expression to assign the result of */ /* getchar() to c *before* testing the value that */ /* was returned. */ char c; int spaces = 0, tabs = 0, newlines = 0; while ((c = getchar()) != EOF) { /* a "switch" is the obvious control stucture */ /* to use here. Note of course the presence */ /* of a "break" statement after the main text of */ /* each arm of the switch, even after the case */ /* label "default". */ switch(c) { case ' ' : spaces++; break; case '\t' : tabs++; break; case '\n' : newlines++; break; default : break; } } printf("The input contained %d spaces, %d tabs and %d newlines\n", spaces,tabs,newlines); return EXIT_SUCCESS; } Example 4 Create a typedef struct named PhoneNumber which has 2 members name which is a string of maximum size 40 and number which is of type unsigned. Write two functions which have signatures: int inputPhoneNumbers (PhoneNumber addresses[], int * noOfAddresses ) where addresses is an array of structs with maximum size 50 and noOfAddresses is the actual number stored in the array. The function returns EXIT_SUCCESS or EXIT_FAILURE. The function prompts the user to enter details for each address. void displayPhoneNumbers (PhoneNumber addresses[], int noOfAddresses ) where addresses is an array of structs with maximum size 100 and noOfAddresses is the actual number stored in the array. This function displays the details of each address. Write a driver program phoneMain.c which tests the above 2 functions Example 5 Using the Date struct defined in Module 3 Course material consider: ..... Date myDate = {14,2,90,....}; int main(){ Date nextDay(Date); myDate = nextDay(myDate); .... } Date nextDay(Date d) { /* adjust d to reflect the next day's date, relative to d */ .... return d; } Adjust d to reflect the next day's date, relative to d; Write a pointer version of the above sleleton code. Example 6 Buffer Input Problems and Array Overflow Problems Consider the previous sample program from Tutorial 1: /* sampleProgram.c */ /* Import these C function libraries as we need to run some functions * from them */ #include #include . /* Defining MAX_STRING to be 21 for a string of maximum size 20 * because C always places a '\0' Nul character at the end of a string! */ #define MAX_STRING 21 /* NOTE CANNOT USE // for comments in ANSI/ISO C */ /* Just as in Java applications C has a main(...) method or function that is * called when we run the program * * * Remember that a method in Java is very similar to a function in C and that * a function is defined as "return-type name(parameters)" * i.e main returns an integer and accepts no parameters (void)
*/ int main(void) { /* Local variables for this function - local because they are * declared inside the function */ int i; /* Simple integer as in Java */ char name[MAX_STRING]; /* Simple array as in Java * maximum size is 20 with an extra space * for the Nul character */ /* We are going to do all our input and output using printf and scanf for this
program - see the Course Documents for more information on how they work */ /* Prompting for input */ printf("Enter your name: "); /* Get a string (%s) from the command line and put it in the character * array - note that scanf places a '\0' at the end of the array - it is this'\0' * that makes it a string */ scanf("%s",name); /* In C, an array is already an address - called a pointer
* - so no need for & -the address operator
* There are many problems with scanf(..) as you will see * shortly! - so never use scanf(...) in your Assignment * and Project work */ /* Get a number from the command line and put it in the address * that contains the variable i (&i means the address of i) */ /* Prompting for input */ printf("Enter a number: "); scanf("%s", &i); i = i + 1; /* output the variables with the values they currently have */ printf("%s entered one less than %d\n", name, i); /*\n - same as in Java */ return EXIT_SUCCESS; } In Java, which exception is thrown when an array overlows? In C, is there such an equivalent? In Java, when the Scanner class methods nextLine(), nextDouble(), nextInt() were used for various inputs, what phenomenon often occurs and how did you deal with it? How does scanf(....) handle the buffer input problem of the extra '\n' or Enter key ? How does scanf(....) handle the buffer overflow problem e.g in the sample program above if a user enters a name of 30 characters say? What happens in the sample program above if the user enters "Joan Smith" for name? Example 7 Using the fgets(...) Input Function scanf(...) causes many problems and it is recommended that fgets(...) should be used because you can specify the maximum size of input. Note that fgets(...) also stores the '\n" or Enter character, you must leave extra space for 2 more characters. So MAX_STRING must become 22 /* sampleProgram.c with fgets()*/ /* Import these C function libraries as we need to run some functions * from them */ #include #include . /* Defining MAX_STRING to be 22 for a string of maximum size 20 * because fgets stores '\n'; the Enter key and C always places a '\0' Nul character * at the end of a string! */ #define MAX_STRING 22 /* NOTE CANNOT USE // for comments in ANSI/ISO c */ /* Just as in Java applications C has a main(...) method or function that is * called when we run the program * * * Remember that a method in Java is very similar to a function in C and that * a function is defined as "return-type name(parameters)" * i.e main returns an integer and accepts no parameters (void) int main(void) { /* Local variables for this function - local because they are * declared inside the function */ int i; /* Simple integer as in Java */ char intString[MAX_STRING}; /* Gets number as string using fgets(...) */ char name[MAX_STRING]; /* Simple array as in Java * maximum size is 20 with an 2 extra spaces * for '\n' and the Nul character */ /* We are going to do all our input and output using printf and scanf for this program * - see the Course Documents for more information on how they work */ /* Prompting for input */ printf("Enter your name: "); /* Get a string (%s) from the command line and put it in the character * array - note that scanf places a '\0' at the end of the array - it is this'\0' * that makes it a string */ fgets(name, MAX_STRING,stdin); /* fgets(...) takes a maximum length only and there is no overflow. Note that stdin is standard input - the keyboard */ /* Get a number from the command line and put it in the address * that contains the variable i (&i means the address of i) */ /* Prompting for input */ printf("Enter a number: "); fgets(intString, MAX_STRING,stdin); /* fgets(...) takes a maximum length only and there is no overflow. Note that stdin is standard input - the keyboard. intString needs to be parsed to an int */ i = atoi(intString); /* atoi (pronounced "a-toy" means ASCII to integer and converts
the strinto an int
*/ i = i + 1; /* output the variables with the values they currently have */ printf("%s entered one less than %d\n", name, i); /*\n - same as in Java */ return EXIT_SUCCESS; } Optional Exercises: Example 1 Extend/modify the program to do the following: Tabulate results for the Celsius range -300 to +200. Tabulate results for an arbitrary Celsius range lowerBound to upperBound, where these represent values entered as input. Print the table with Fahrenheit in the first column and Celsius in the second. Print the table horizontally with Celsius figures in the first row and Fahrenheit in the second row. Example 2 Extend the program to display proper headings and to generate the decimal, octal and hexadecimal sum of values, as appropriate, for the three columns. Example 3 Extend/modify the program to account for the following: The comma operator may be used to express the loop condition without the parentheses around c = getchar() How? Rewrite the switch statement using an if with the further requirement to count white space, digits, lower-case and upper-case letters. Use the available macros from ctype.h as appropriate. Up | Site Map © 2014 RMIT University - Copyright Information - Disclaimer - Site Map