summaryrefslogtreecommitdiff
path: root/reference/C/CONTRIB/SAWTELL/c-lesson.9
diff options
context:
space:
mode:
Diffstat (limited to 'reference/C/CONTRIB/SAWTELL/c-lesson.9')
-rwxr-xr-xreference/C/CONTRIB/SAWTELL/c-lesson.9433
1 files changed, 433 insertions, 0 deletions
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 <stdio.h>
+
+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 <stdio.h>
+
+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 <stdio.h>
+
+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 <stdio.h>
+
+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 <stdio.h>
+
+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 <stdio.h>
+
+/*
+** The message and text fragments output by the program.
+*/
+
+char *messages[] =
+{
+#if defined( ENGLISH )
+#ident "@(#)ENGLISH Version"
+ "\nUsage: if_else_demo <numeric argument 1> <numeric argument 2>\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 <numeric argument 1> <numeric argument 2>
+
+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 <stdio.h>
+#include <setjmp.h>
+
+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 ) |
+ +----------------------------------------------------------------------+