home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / clesson / clesson.exe / clesson.DXR / 00057.txt < prev    next >
Encoding:
Text File  |  1995-04-04  |  12.7 KB  |  460 lines

  1.  
  2.                                           Lesson 8
  3.  
  4.   This lesson and the following one will examine how to use the program
  5. structure - as opposed to data structure - reserved words.
  6.  
  7.   Lets start with the looping structures:
  8.  
  9.   do repeated_statement while ( logical_expression );
  10.  
  11.   repeated_statement, which may be a block of code, will be executed
  12. repetitively until the logical_expression, becomes false. If you have been
  13. 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.
  14.  
  15.   while ( logical_expression ) repeated_statement;
  16.  
  17.  
  18.   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.
  19.  
  20.   Associated with the looping structures are the control words:
  21.  
  22.   break;
  23.   continue;
  24.  
  25.   break; allows you to leave a loop in the middle of a block, and
  26.   continue; allows you to re-start it from the top.
  27.  
  28.   Finally we must not forget the most common and useful looping construct:
  29.  
  30.  
  31.  
  32.  
  33.  
  34.   for ( initialising statement; logical_expression; incremental_statement )
  35.   repeated_statement;
  36.  
  37.   Some further explanation is needed. The initialising statement is
  38. executed once, but to allow for the need to initialise several separate
  39. variables the assignment statements may be separated by commas. The
  40. logical_expression must be true for the loop to run, and the
  41. incremental_statement is executed once each time the loop is run.
  42. The for statement is completely general and may, for example, be used to
  43. manipulate a set of pointers to operate on a linked list.
  44.  
  45. Some examples.
  46.  
  47.   A do loop program.
  48.  
  49.  
  50.  
  51.  
  52. #ident "@(#) do_demo.c - An example of the do loop"
  53.  
  54. #include <stdio.h>
  55.  
  56. main()
  57. {
  58.   char character;
  59.  
  60.   character = 'a';
  61.  
  62.   do printf ( "%c", character ); while ( character++ < 'z' );
  63.   printf ( "\n" );
  64.   }
  65.  
  66.  
  67.  
  68.  
  69.  
  70.   Fairly obviously it prints:
  71.  
  72. abcdefghijklmnopqrstuvwxyz
  73.  
  74.   A while loop example.
  75.  
  76. #ident "@(#) while_demo.c - An example of the while loop"
  77.  
  78. #include <stdio.h>
  79.  
  80. main()
  81. {
  82.   char character;
  83.  
  84.   character = 'a';
  85.  
  86.  
  87.  
  88.  
  89.   while ( character <= 'z' ) printf ( "%c", character++ );
  90.   printf ( "\n" );
  91.   }
  92.  
  93.   Its output is exactly the same as the previous example:
  94.  
  95. abcdefghijklmnopqrstuvwxyz
  96.  
  97.   In this totally trivial case it is irrelevant which program structure
  98.   you use, however you should note that in the `do' program structure the
  99.   repeated statement is always executed at least once.
  100.   A for loop example.
  101.  
  102.   The `for' looping structure.
  103.  
  104.  
  105.  
  106. #ident "@(#) for_demo.c - An example of the for loop"
  107.  
  108. #include <stdio.h>
  109.  
  110. main()
  111. {
  112.   char character;
  113.  
  114.   for ( character = 'a'; character <= 'z' ; character++ )
  115.   {
  116.     printf ( "%c", character );
  117.     }
  118.   printf ( "\n" );
  119.   }
  120.  
  121.   Surprise, Surprise!
  122.  
  123. abcdefghijklmnopqrstuvwxyz
  124.  
  125.  
  126.   You should be aware that in all the looping program structures, the
  127. repeated statement can be a null statement ( either just a `;' or the
  128. reserved word `continue;' ). This means that it is possible to - for
  129. example - position a pointer, or count up some items of something or other.
  130. It isn't particularly easy to think up a trivial little program which
  131. demonstrates this concept, however the two `for' loops give some indication
  132. of the idea.
  133.  
  134. #ident "@(#) pointer_demo.c - Pointer operations with the for loop"
  135.  
  136. #include <stdio.h>
  137.  
  138. main()
  139. {
  140.   char character, *character_pointer, alphabets [ 53 ];
  141.  
  142.  
  143.  
  144.  
  145.   for ( character = 'a', character_pointer = alphabets;  
  146.                                                                                 /* Start conditions */
  147.         character <= 'z';                                               /* Run while true   */
  148.         *character_pointer++ = character++               /* All the work     */
  149.         )TRUE continue;
  150.  
  151.   for ( character = 'A';  /* character_pointer is at the right place already */
  152.         character <= 'Z';
  153.         *character_pointer++ = character++
  154.         ) continue;
  155.  
  156.   *character_pointer = (char) '\000'; /* NULL character to terminate string. */
  157.  
  158.   printf ( "%s\n\n", alphabets );
  159.   }
  160.  
  161.  
  162.  
  163.  
  164.   Another Surprise!
  165.  
  166. abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
  167.  
  168.   So much for the looping structures provided by the `C' language. The
  169. 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.
  170.  
  171. #ident "if_demo.c"
  172.  
  173. #include <stdio.h>
  174.  
  175.  
  176.  
  177.  
  178.  
  179. main(argc, argv)
  180. int argc;
  181. char **argv;
  182. {
  183.   if ( argc > 1 ) printf ( "You have initiated execution with arguments."};
  184.   }
  185.  
  186.   And the if ... else demo.
  187.  
  188. #ident "if_else_demo.c"
  189. /*
  190. ** The Language #define could go in the compiler invocation line if desired.
  191. */
  192.  
  193.  
  194.  
  195.  
  196. #define ENGLISH
  197.  
  198. #include <stdio.h>
  199.  
  200. /*
  201. ** The message and text fragments output by the program.
  202. */
  203.  
  204. char *messages[] =
  205. {
  206. #if defined( ENGLISH )
  207. #ident "@(#)ENGLISH Version"
  208.   "\nUsage: if_else_demo <numeric argument 1> <numeric argument 2>\n\n",
  209.   "The first argument is ",
  210.   "the second",
  211.  
  212.  
  213.  
  214.   "equal to ",
  215.   "bigger than ",
  216.   "smaller than "
  217. #endif
  218.  
  219. #if defined( FRANCAIS )
  220. #ident "@(#)FRENCH Version"
  221.  
  222.   put the French translation in here so that we are ready to 
  223.   export to French speaking Countries. I'd be grateful if a French 
  224.   speaker could make the translation for me.
  225.  
  226. #endif
  227.   };
  228.  
  229. /*
  230. ** Meaningful words defined to constants
  231. */
  232.  
  233.  
  234.  
  235. #define USAGE 0
  236. #define FIRST 1
  237. #define SECOND 2
  238. #define EQUAL 3
  239. #define BIGGER 4
  240. #define SMALLER 5
  241.  
  242. #define SUCCESS 0
  243. #define FAILURE 1
  244.  
  245. /*
  246. ** We need this more than once so it can be put in a function.
  247. */
  248.  
  249. void usage()
  250.  
  251.  
  252.  
  253.  
  254. {
  255.   printf ( messages[USAGE]);
  256.   exit ( FAILURE );
  257.   }
  258.  
  259. /*
  260. ** Main program function starts here. ( At the top of a page no less! )
  261. */
  262.  
  263. int main ( argc, argv )
  264. int argc;
  265. char **argv;
  266. {
  267.   int message_index;
  268.   double i, j, strtod();
  269.   char *ptr;
  270.  
  271.  
  272.  
  273.  
  274.   if ( argc != 3 ) usage();                  /* have we been given the right */
  275.                                              /* number of arguments. */
  276.   i = strtod ( argv[1], &ptr);               /* Convert to a double float. */
  277.   if ( ptr == argv[1] ) usage();             /* Successful conversion? */
  278.   j = strtod ( argv[2], &ptr);               /* Convert to a double float. */
  279.   if ( ptr == argv[2] ) usage();             /* Successful conversion? */
  280.  
  281. /*
  282. ** This statement uses the "ternary conditional assignment" language
  283. ** construction to assign the value required to the message indexing 
  284. ** variable.
  285. ** Note that this concept is efficient in the generation of machine code
  286. ** output ( compile the program with a -S switch and have a look ) and in
  287. ** ease with which it can be understood. The assignment is obvious
  288. ** instead of being buried under a litter of `if' and `else' keywords.
  289. */
  290.  
  291.  
  292.  
  293.  
  294.   message_index = ( i == j ) ? EQUAL : ( i > j ) ? BIGGER : SMALLER;
  295.  
  296. /*
  297. ** Now print the message.
  298. */
  299.  
  300.   (void) printf ( "\n%s%s%s\n\n",     /* Format string specifying 3 strings. */
  301.                   messages[ FIRST ],                   /* Address of string. */
  302.                   messages[ message_index ],           /*        ditto.      */
  303.                   messages[ SECOND ]                   /*        ditto.      */
  304.                   );
  305.   return ( SUCCESS );
  306.   }
  307.  
  308.  
  309.  
  310.  
  311.   Well as you can no doubt gather it simply compares two numbers on 
  312. 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.
  313.  
  314. Usage: if_else_demo <numeric argument 1> <numeric argument 2>
  315.  
  316. The first argument is equal to the second
  317.  
  318. The first argument is smaller than the second
  319.  
  320. The first argument is bigger than the second
  321.  
  322.  
  323.  
  324.  
  325.   Now that the international community is shrinking with vastly improved
  326. telecommunications, it is perhaps a good idea to think carefully about
  327. 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.
  328.  
  329.   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.
  330.  
  331.   There are two more methods of altering the program flow.
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.   1 ) The goto a label.
  339.   2 ) The setjump / longjmp library routines.
  340.  
  341.   The concept of the go to a label construction has had reams of literary
  342. 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.
  343.  
  344.   for ( a = 0; a < MATRIX_SIZE; a++ )
  345.   {
  346.     for ( b = 0; b < MATRIX_SIZE; b++ )
  347.  
  348.  
  349.  
  350.  
  351.     {
  352.       if ( process ( matrix, a, b )) goto bad_matrix;
  353.       }
  354.      }
  355.    return ( OK );
  356.  
  357. bad_matrix:
  358.  
  359.    perror ( progname, "The data in the matrix seems to have been corrupted" );
  360.    return ( BAD );
  361.  
  362.   This is one of the very few "legitimate" uses of goto, as there is no
  363. "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 `{}'
  364.  
  365.  
  366.  
  367.  after the ':' as a null statement.
  368.  
  369.   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.
  370.  
  371.   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:
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378. #ident "set_jmp_demo.c"
  379.  
  380. #include <stdio.h>
  381. #include <setjmp.h>
  382.  
  383. jmp_buf save;
  384.  
  385. main()
  386. {
  387.   char c;
  388.  
  389.   for ( ;; )              /* This is how you set up a continuous loop.*/
  390.   {
  391.     switch ( setjmp( save ))
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.     {
  399. case 0:
  400.       printf ( "We get a zero returned from setjmp on setup.\n\n");
  401.       break;                   /* This is the result from setting up. */
  402.  
  403. case 1:
  404.       printf ( "NORMAL PROGRAM OPERATION\n\n" );
  405.       break;
  406.  
  407. case 2:
  408.       printf ( "WARNING\n\n" );
  409.       break;
  410.  
  411.  
  412.  
  413.  
  414.  
  415. case 3:
  416.       printf ( "FATAL ERROR PROGRAM TERMINATED\n\nReally Terminate? y/n: " );
  417.       fflush ( stdout );
  418.       scanf ( "%1s", &c );
  419.       c = tolower ( c );
  420.       if ( c == 'y' ) return ( 1 );
  421.       printf ( "\n" );
  422.       break;
  423.  
  424. default:
  425.       printf ( "Should never return here.\n" );
  426.       break;
  427.       }
  428.     process ();
  429.     }
  430.   }
  431.  
  432.  
  433.  
  434. process ()
  435. {
  436.   int i;
  437.  
  438.   printf ( "Input a number to simulate an error condition: " );
  439.   fflush ( stdout );
  440.   scanf ( "%d", &i );
  441.   i %= 3;
  442.   i++;                /* So that we call longjmp with  0 < i < 4 */
  443.   longjmp ( save, i);
  444.   }
  445.  
  446.   Although in this silly little demo the call to longjmp is in the same file
  447. 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
  448.  
  449.  
  450.  
  451.  
  452. 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 
  453. 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, 
  454. of course, that the stack and frame pointer registers
  455. 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 
  456. 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
  457.  long before it should. Take care.So you have to keep a record of the buffers' addresses and free them
  458. before the call to longjmp.
  459.  
  460.