From 7e0f021a9aec35fd8e6725e87e3313b101d26f5e Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 27 Jan 2008 11:37:44 +0100 Subject: Initial import (2.0.2-6) --- reference/C/CONTRIB/SAWTELL/c-lesson.9 | 433 +++++++++++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100755 reference/C/CONTRIB/SAWTELL/c-lesson.9 (limited to 'reference/C/CONTRIB/SAWTELL/c-lesson.9') diff --git a/reference/C/CONTRIB/SAWTELL/c-lesson.9 b/reference/C/CONTRIB/SAWTELL/c-lesson.9 new file mode 100755 index 0000000..5d03e3b --- /dev/null +++ b/reference/C/CONTRIB/SAWTELL/c-lesson.9 @@ -0,0 +1,433 @@ + + Lesson 8. + + This lesson and the following one will examine how to use the program +structure - as opposed to data structure - reserved words. + + Lets start with the looping structures: + + do repeated_statement while ( logical_expression ); + + repeated_statement, which may be a block of code, will be executed +repetitively until the logical_expression, becomes false. If you have been +exposed to ( corrupted by? ) another language remember that there is no +`until' test at the end of a loop. Note that the repeated_statement is always +executed once irrespective of the state of the logical_expression. + + while ( logical_expression ) repeated_statement; + + repeated_statement is executed repetitively while the logical_expression +is true. Once again statement may be a block of code. Note that if the +logical_expression evaluates to FALSE then the repeated_statement is NEVER +executed. + + Associated with the looping structures are the control words: + + break; + continue; + + break; allows you to leave a loop in the middle of a block, and + continue; allows you to re-start it from the top. + + Finally we must not forget the most common and useful looping construct: + + for ( initialising statement; logical_expression; incremental_statement ) + repeated_statement; + + Some further explanation is needed. The initialising statement is +executed once, but to allow for the need to initialise several separate +variables the assignment statements may be separated by commas. The +logical_expression must be true for the loop to run, and the +incremental_statement is executed once each time the loop is run. +The for statement is completely general and may, for example, be used to +manipulate a set of pointers to operate on a linked list. + +Some examples. + + A do loop program. + +#ident "@(#) do_demo.c - An example of the do loop" + +#include + +main() +{ + char character; + + character = 'a'; + + do printf ( "%c", character ); while ( character++ < 'z' ); + printf ( "\n" ); + } + + Fairly obviously it prints: + +abcdefghijklmnopqrstuvwxyz + + A while loop example. + +#ident "@(#) while_demo.c - An example of the while loop" + +#include + +main() +{ + char character; + + character = 'a'; + + while ( character <= 'z' ) printf ( "%c", character++ ); + printf ( "\n" ); + } + + Its output is exactly the same as the previous example: + +abcdefghijklmnopqrstuvwxyz + + In this totally trivial case it is irrelevant which program structure + you use, however you should note that in the `do' program structure the + repeated statement is always executed at least once. + A for loop example. + + The `for' looping structure. + +#ident "@(#) for_demo.c - An example of the for loop" + +#include + +main() +{ + char character; + + for ( character = 'a'; character <= 'z' ; character++ ) + { + printf ( "%c", character ); + } + printf ( "\n" ); + } + + Surprise, Surprise! + +abcdefghijklmnopqrstuvwxyz + + You should be aware that in all the looping program structures, the +repeated statement can be a null statement ( either just a `;' or the +reserved word `continue;' ). This means that it is possible to - for +example - position a pointer, or count up some items of something or other. +It isn't particularly easy to think up a trivial little program which +demonstrates this concept, however the two `for' loops give some indication +of the idea. + +#ident "@(#) pointer_demo.c - Pointer operations with the for loop" + +#include + +main() +{ + char character, *character_pointer, alphabets [ 53 ]; + + for ( character = 'a', character_pointer = alphabets; /* Start conditions */ + character <= 'z'; /* Run while true */ + *character_pointer++ = character++ /* All the work */ + )TRUE continue; + + for ( character = 'A'; /* character_pointer is at the right place already */ + character <= 'Z'; + *character_pointer++ = character++ + ) continue; + + *character_pointer = (char) '\000'; /* NULL character to terminate string. */ + + printf ( "%s\n\n", alphabets ); + } + + Another Surprise! + +abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + + So much for the looping structures provided by the `C' language. The +other main structures required to program a computer are the ones which +alter the program flow. These are the switch, and the if and its extension +the if ... else combination. More demo programs are much the best way of +getting the message across to you, so here they are, first the if construct. + +#ident "if_demo.c" + +#include + +main(argc, argv) +int argc; +char **argv; +{ + if ( argc > 1 ) printf ( "You have initiated execution with arguments."}; + } + + And the if ... else demo. + +#ident "if_else_demo.c" +/* +** The Language #define could go in the compiler invocation line if desired. +*/ + +#define ENGLISH + +#include + +/* +** The message and text fragments output by the program. +*/ + +char *messages[] = +{ +#if defined( ENGLISH ) +#ident "@(#)ENGLISH Version" + "\nUsage: if_else_demo \n\n", + "The first argument is ", + "the second", + "equal to ", + "bigger than ", + "smaller than " +#endif + +#if defined( FRANCAIS ) +#ident "@(#)FRENCH Version" + + put the French translation in here so that we are ready to export to + French speaking Countries. I'd be grateful if a French speaker could + make the translation for me. + +#endif + }; + +/* +** Meaningful words defined to constants +*/ + +#define USAGE 0 +#define FIRST 1 +#define SECOND 2 +#define EQUAL 3 +#define BIGGER 4 +#define SMALLER 5 + +#define SUCCESS 0 +#define FAILURE 1 + +/* +** We need this more than once so it can be put in a function. +*/ + +void usage() +{ + printf ( messages[USAGE]); + exit ( FAILURE ); + } + +/* +** Main program function starts here. ( At the top of a page no less! ) +*/ + +int main ( argc, argv ) +int argc; +char **argv; +{ + int message_index; + double i, j, strtod(); + char *ptr; + + if ( argc != 3 ) usage(); /* have we been given the right */ + /* number of arguments. */ + i = strtod ( argv[1], &ptr); /* Convert to a double float. */ + if ( ptr == argv[1] ) usage(); /* Successful conversion? */ + j = strtod ( argv[2], &ptr); /* Convert to a double float. */ + if ( ptr == argv[2] ) usage(); /* Successful conversion? */ + +/* +** This statement uses the "ternary conditional assignment" language +** construction to assign the value required to the message indexing variable. +** Note that this concept is efficient in both the generation of machine code +** output ( compile the program with a -S switch and have a look ) and in the +** ease with which it can be understood. The assignment is obvious instead of +** being buried under a litter of `if' and `else' keywords. +*/ + + message_index = ( i == j ) ? EQUAL : ( i > j ) ? BIGGER : SMALLER; + +/* +** Now print the message. +*/ + + (void) printf ( "\n%s%s%s\n\n", /* Format string specifying 3 strings. */ + messages[ FIRST ], /* Address of string. */ + messages[ message_index ], /* ditto. */ + messages[ SECOND ] /* ditto. */ + ); + return ( SUCCESS ); + } + + Well as you can no doubt gather it simply compares two numbers on the +command line and ejects a little message depending on the relative magnitude +of the numbers. In the UNIX tradition the help message is perhaps somewhat +terse, but it serves the purpose of getting you - the student - to think +about the importance of creating programs which always cope with nonsensical +input in a civilised way. Here are the lines of output. + +Usage: if_else_demo + +The first argument is equal to the second + +The first argument is smaller than the second + +The first argument is bigger than the second + + Now that the international community is shrinking with vastly improved +telecommunications, it is perhaps a good idea to think carefully about +creating programs which can talk in many languages to the users. The method +of choice is - I believe - that presented above. The #if defined( LANGUAGE ) +gives us an easy method of changing the source code to suit the new sales +area. Another possibility is to put all the text output needed from a program +into a file. The file would have to have a defined layout and some consistent +way of `getting at' the message strings. + + From a commercial point of view this may or may not be a good business plan. +Quite definitely it is an absolute no no to scatter a mass of string literals +containing the messages and message fragments all over your program script. + + There are two more methods of altering the program flow. + + 1 ) The goto a label. + 2 ) The setjump / longjmp library routines. + + The concept of the go to a label construction has had reams of literary +verbiage written about it and this author does not intend to add to the pile. +Suffice it to say that a goto is a necessary language construct. There are a +few situations which require the language to have ( in practice ) some form of +unconditional jump. Treat this statement with great caution if you wish your +code to be readable by others. An example of legitimate use. + + for ( a = 0; a < MATRIX_SIZE; a++ ) + { + for ( b = 0; b < MATRIX_SIZE; b++ ) + { + if ( process ( matrix, a, b )) goto bad_matrix; + } + } + return ( OK ); + +bad_matrix: + + perror ( progname, "The data in the matrix seems to have been corrupted" ); + return ( BAD ); + + This is one of the very few "legitimate" uses of goto, as there is no +"break_to_outer_loop" in `C'. Note that some compilers complain if the label +is not immediately followed by a statement. If your compiler is one of these +naughty ones, you can put either a `;' or a pair of braces `{}' after the +`:' as a null statement. + + An example of a program package which makes extensive use of the goto is the +rz and sz modem communications protocol implementation by Chuck Forsberg of +Omen Technology. You should download it and study the code, but do remember +that the proof of the pudding argument must apply as the rz & sz system has +become extremely popular in its application because it works so well. + + The other method of changing program flow is the setjump and longjmp pair of +library functions. The idea is to provide a method of recovery from errors +which might be detected anywhere within a large program - perhaps a compiler, +interpreter or large data acquisition system. Here is the trivial example: + +#ident "set_jmp_demo.c" + +#include +#include + +jmp_buf save; + +main() +{ + char c; + + for ( ;; ) /* This is how you set up a continuous loop. +*/ + { + switch ( setjmp( save )) + { +case 0: + printf ( "We get a zero returned from setjmp on setup.\n\n"); + break; /* This is the result from setting up. */ + +case 1: + printf ( "NORMAL PROGRAM OPERATION\n\n" ); + break; + +case 2: + printf ( "WARNING\n\n" ); + break; + +case 3: + printf ( "FATAL ERROR PROGRAM TERMINATED\n\nReally Terminate? y/n: " ); + fflush ( stdout ); + scanf ( "%1s", &c ); + c = tolower ( c ); + if ( c == 'y' ) return ( 1 ); + printf ( "\n" ); + break; + +default: + printf ( "Should never return here.\n" ); + break; + } + process (); + } + } + +process () +{ + int i; + + printf ( "Input a number to simulate an error condition: " ); + fflush ( stdout ); + scanf ( "%d", &i ); + i %= 3; + i++; /* So that we call longjmp with 0 < i < 4 */ + longjmp ( save, i); + } + + Although in this silly little demo the call to longjmp is in the same file +as the call to setjmp, this does not have to be the case, and in the practical +situation the call to longjmp will be a long way from the call to setjmp. The +mechanism is that setjmp saves the entire state of the computer's CPU in a +buffer declared in the jmp_buf save; statement and longjmp restores it exactly +with the exception of the register which carries the return value from longjmp. +This value is the same as the second argument in the longjmp call - i in our +little demo. This means, of course, that the stack and frame pointer registers +are reset to the old values and all the local variables being used at the time +of the longjmp call are going to be lost forever. One consequence of this is +that any pointer to memory allocated from the heap will also be lost, and +you will be unable to access the data stored in the buffer. This is what the +jargonauts call "memory leakage", and is really very difficult bug to find. +Your program runs out of dynamic memory long before it should. Take care. +So you have to keep a record of the buffers' addresses and free them +before the call to longjmp. + +More details later on when we learn about the heap memory allocation routines. + +Copyright notice:- + +(c) 1993 Christopher Sawtell. + +I assert the right to be known as the author, and owner of the +intellectual property rights of all the files in this material, +except for the quoted examples which have their individual +copyright notices. Permission is granted for onward copying, +but not modification, of this course and its use for personal +study only, provided all the copyright notices are left in the +text and are printed in full on any subsequent paper reproduction. + +-- + +----------------------------------------------------------------------+ + | NAME Christopher Sawtell | + | SMAIL 215 Ollivier's Road, Linwood, Christchurch, 8001. New Zealand.| + | EMAIL chris@gerty.equinox.gen.nz | + | PHONE +64-3-389-3200 ( gmt +13 - your discretion is requested ) | + +----------------------------------------------------------------------+ -- cgit v1.2.3-54-g00ecf