LevSelector.com |
C programming language | Other pages | |
• intro
• books • tutorials • misc |
• C-tutorial
part1
• C-tutorial part2 • C-tutorial part3 • C-tutorial part4 • C-tutorial part5 |
• C++
• C++ tutorial #1 • C++ tutorial #2 |
intro | home - top of the page - |
Dennis Richie shaking
hands with President Clinton
the day he received the National Medal of Technology for creating C. • youtube video - Ken Thomson and Dennis Riche receiving the award - 1998 • http://directory.google.com/Top/Computers/Programming/Languages/C/ - google directory of links |
books | home - top of the page - |
Books:
- C Programming Language - by Brian W.
Kernighan, Dennis Ritchie (1978 - 1st, 1983, 1988 - 2nd ed.)
- The C Answer Book (2nd Edition) - by
Clovis Tondo, Scott Gimpel, Brian Kernighan (1988)
- C: A Reference Manual (5th Edition)-
by: Samuel P., III Harbison, Guy L., Jr. Steele (2002)
- TheUNIX Programming Environment - by
Brian W. Kernighan, Rob Pike (1984)
tutorials | home - top of the page - |
• http://www.cyberdiem.com/vin/learn.html
- C / C++ tutorial
• http://www.kulichki.com/moshkow/CTOTOR/
- Moshkov's library - programming, C/C++/Unix
misc | home - top of the page - |
• http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html -
Calling C++ from C and vice versa
• www.parasoft.com/products/insure/index.htm - Insure++ Automatic Runtime Error Detection
• www.progsource.com/c_windows.html - The Programmer's Source - Windows Development C Resources
• /www.lysator.liu.se/c/c-www.html - Other Sources
• www2.iro.umontreal.ca/~ratib/code/ - Codepage 2.3 - Subject index of C programming resources on the WWW
• www.cprogramming.com -
Programming in C and C++ - to help beginner 'coders'
• www.europa.com/~viper - Viper's C/C++ Web Page - Network,windows,graphics,sound
• www.programmersheaven.com - Programmers Heaven - C / C++ Zone
• www.nerdworld.com/nw93.html - C Programming Resources From Nerd World Media
• www.cast.msstate.edu/~billy/c-prog.html - C Programming Resources
• www.redrival.com/bigt - Big T's C/C++ Resource Center.
• www.prineas.com/Links/C/index.html - Essential C/C++ Links
• www.strangecreations.com/library/c/index.htm - Virtual Library - C and C++
• www.infopoll.com/infopoll/surveys/s4598.htm - Borland C++ Survey
• www.geocities.com/SiliconValley/Vista/7336/robcstf.htm - Robin's C Programming
• www.softpanorama.org/Lang/c.shtml - Softpanorama Universitys Annotated C Webliography
• www.angelfire.com/tx2/cplus/index.html - The C/C++ webpage for all levels
• http://members.tripod.com/codist - The Codist - a survey of source code comprehension tools
• www.tek-tips.com/gthreadminder.cfm/lev2/4/lev3/32/pid/205 - C Language forum at Tek-Tips - forums and mutual help system for computer
professionals.
• ttp://jvcpp.8m.com - The All-New
C Programmer's Paradise (also C++ and JavaScript)
. • www.geocities.com/SiliconValley/Haven/5601 - C N Stuff Home Page - Links, code examples and lots of other stuff.
• www.qb45.com/c - Future Software
- files, links, tutorials, message board; all automatically updated by
visitors.
• http://homestead.juno.com/hawraned/index.html - Two Bit Software - Translates C software to Java, Applesoft BASIC software
to ANSI C with extensions.
• www.allexperts.com/getExpert.asp?Category=1587 - Allexperts C Programming Q&A - Volunteer experts answer your detailed
one-on-one questions.
• www.angelfire.com/sc/electron - The C Coders Home Page - A collection of resources including support
for unix/dos systems,win32,sockets, and game programming.
• http://lclint.cs.virginia.edu - LCLint - Tool for statically checking C programs, GPL.
• www.flamingolingo.com/programming.c/ - Programming.c Directory of programming sites (C, C++, Java, COBOL, Basic,
COM, Pascal, etc.)
• www.genitor.com/resources - Genitor Corporation Developer Resources
• http://hermetic.nofadz.com/cfunlib.htm - C/C++ Programming and C function libraries for calendar date conversion
and multidimensional dynamic array allocation; links.
• http://anubis.dkuug.dk/JTC1/SC22/WG14 - Home of the C standard group
• http://www.cs.wisc.edu/csl/doc/info/unix-software/programming/debuggers/ - debuggers
• dbx is the Berkeley UNIX symbolic
debugger. It is available on Solaris and some other Unix-es. Not supported
on Linux. Convenient primarily because it is not X-Windows based. Installed
Location: /usr/bin/dbx . Running the code: Compile and link your
code with the -g flag to incorporate debugging information. Then, run your
code under the debugger. For example, dbx a.out . Core dumps
can also be probed using dbx to determine the cause of the crash.
• gdb is the standard GNU debugger.
Although originally designed to operate with the GNU C compiler (gcc),
gdb can be used to debug programs compiled from a variety of different
compilers, including vendor-supplied C and Fortran compilers on several
platforms (if compiled with debugger symbol information). Emacs includes
a GDB mode for simultaneously debugging and editing programs.
• ddd is a wrapper around the GDB,
DBX, or XDB debuggers. In addition to the command-line interface of the
dependent debugger, DDD provides a common graphical user interface to support
debugging tasks. The DDD graphical data display allows for interactive
exploration of data structures.
C-tutorial part 1 | home - top of the page - |
The 'C' programming language was designed and developed by Brian Kernighan, and Dennis Ritchie at The Bell Research Labs. It was first implemented in assembler on a Digital Equipment Corporation PDP-7. Once a simple assembler version was working it was possible to rewrite the compiler in 'C' itself. This was done in short order and therefore as soon as the PDP-11 was introduced by DEC it was only necessary to change the code generator section of the compiler and the new machine had a compiler in just a few weeks. 'C' was then used to implement the UNIX o/s. This means, that a complete UNIX can be ported to a new machine in literally just a few months by a small team of competent programmers.
Create file hello.c:
#include <stdio.h>
char *format = "%s",
main() {
|
Although we did everything with one command, in fact the compilation process consisted of several stages (pre-processing, compiling, assembling, linking). We can go through them step-by-step:
Pre-processor - replaces the line #include
<stdio.h> with the file stdio.h
(standard input/output headers) from the include files library (from directory
/usr/include/). To see just this step - use the following commands:
cc -E hello.c view hello.i You will see that a number of lines of text have been added at the front of the hello.c program from the file called /usr/include/stdio.h : view /usr/include/stdio.h Next stage - compile into an assembler code program. Use the following commands cc -S hello.c view hello.s You will see some recognizable symbols and lots of assembler code. To finally turn this into machine instructions use the following command: cc -g -c hello.s view hello.o This new file with suffix ".o" is called the object file. It contains the machine instructions corresponding exactly to the mnemonic codes in the .s file. If you wish you can look at these machine codes using one of the commands available to examine object files. dis -L -t .data hello.o >hello.dis The next stage is "linking" this binary code with libraries - use the command: cc -o hello hello.o |
The single command we use to compile was
cc -o hello hello.c
The word after the -o option is the name of the executable file (default - "a.out"). The source file MUST have the ".c" extension.
Note: the compiler name may be bcc (Borland), gcc (GNU),
CC, or something else.
Note: 'C' compilers have option to optimize (for speed
or memory usage).
Note: here are some common compielr options:
-c - compile only (do not link)
-S - stop after making assempler code -E - stop after preprocessing stage -o file - define the output file -v - verbouse (print commands executed on STDERR, also print compiler version, etc.) -l - to specify libraries to link -L - to specify directories to search for libraries -I - to specify directories to search for include files -static - tells compiler to include shared libraries into the executable (thus making it larger) - even though the libraries are available (usually in /lib) and can be linked dynamically during execution (on systems that support dynamic linking) -shared - produce a shared object which can then be linked with other objects to form an executable. Only a few systems support this option. -symbolic - bind references to global symbols when building a shared object, warn about any unresolved references - only if supported. -On, where n=0,1,2,or 3 - sets level of optimization -b machine - to specify the type of machine for which to compile -V version - to specify which version of compiler to run |
=============================================================================================
All information (code or data) is stored in a computer in binary formats.
Data types:
Character:
#include <stdio.h>
main() { char a; unsigned char b; a = b = 128;
|
Integers:
int i;
short int smaller_number; /* usually 2 bytes */
long int big_number; /* usually 4 bytes */
Real Numbers:
float length_of_water_line; /* in meters
*/
double displacement;
/* in grammes */
file /usr/include/values.h defines some usefule values:
MAXFLOAT 3.40282346638528860e+38
MINFLOAT 1.40129846432481707e-45
MAXDOUBLE 1.79769313486231470e+308
MINDOUBLE 4.94065645841246544e-324
Practically, float - 6, double - 12 significant digits.
Signed and unsigned prefixes.
(for both char and integer types the declaration can be preceded by
the word "unsigned").
arrays:
char client_surname[31];
This declaration reserves storage for a string of 30 characters plus the NULL character of value zero which terminates the string.
Structures:
/* Define the template for 'ship' structure type: */:
struct ship { char name[30]; double displacement; /* in grammes */ float length_of_water_line; /* in meters */ unsigned short int number_of_passengers; unsigned short int number_of_crew; }; /* Now we can create the structure in memory: */
|
Here is a short test program:
#include <stdio.h>
struct ship
char *format = "\
main()
cunarder.name = "Queen Mary";
/* This is the bad line. */
printf ( format,
|
Now let's compile and execute it:
$ cc demo1a.c
$ a.out
Name of Vessel: Queen Mary
Displacement: 97500000000.0 grammes
Water Line: 750.0 metres
Passengers: 3575
Crew: 4592
Three special allocation methods, 'static' and 'register', and
'const':
'static' - will be placed in the main storage to live all the execution
time.
'register' - tells compiler that you will be using this a lot - for
optimal storage
'comst' - means constant
Pointers.
pointer - a variable which contain the address of a data element.
char c; /* normal variable */
char *ch_p; /* pointer to a char variable
*/
Unary operator '&' gives the address of the variable:
ch_p = &c;
Input/output:
"printf" - print formatted output
"scanf" - read data into the program
On unix use manpages to read the options.
man printf
man scanf
#include <stdio.h>
int printf ( format [ , arg ] ... )
int fprintf ( stream, format [ , arg ] ... )
int sprintf ( s, format [ , arg ] ... )
|
Test program:
#include <stdio.h>
char *verse[] = {
main() {
/* This will print the data left justified. */ for ( ch_pp = verse; *ch_pp;
ch_pp++ ) printf ( "%s\n", *ch_pp );
/* This will print the data right justified. */ for ( ch_pp = verse; *ch_pp;
ch_pp++ )
/* This will centre the data. */ for ( ch_pp = verse; *ch_pp;
ch_pp++ ) {
length = 40 + strlen ( *ch_pp ) / 2;
|
scanf() - family of functions used to input from the outside world,
note that arguments to the function are all POINTERS. The format
string has to be passed in to the function using a pointer, simply because
this is the way 'C' passes strings.
C-tutorial part 2 | home - top of the page - |
Arrays and Pointers.
char name[30];
/* An array of 30 signed characters. */
char *strings[50];
/* 50 pointers to strings. */
unsigned long int *(*func)()[20];/* An
array of pointers to functions which */
/* return pointers to unsigned long ints. */
struct ship *vessel_p;
struct ship fleet[5];
/* This allocates enough storage for 5 ships' info.*/
vessel_p = fleet; /*point at the first
vessel in the fleet.*/
vessel_p++;
/* point a the next ship in the fleet array. */
vessel_p = fleet + 3;
i = vessel_p - fleet; /* the index of
the ship in the fleet at which we are pointing */
d = vessel_p - another_vessel_p; /* This
gives the separation in elements. */
Note: the result of pointer arithmetic is ALWAYS expressed in elements rather than bytes.
/* Using a pointer to reference a structure: */
vessel_p = fleet; vessel_p->name = "Queen Mary";
|
Initialisation of arrays.
char *qbf = "The quick brown fox jumped over the lazy dogs back";
int tic_tac_toe[3][3] =
struct ship fleet[2] =
char *verse[] = /* array of pointers */
|
The other way is to calculate the size of the table by using the sizeof operator - Note that although use of sizeof looks like a function call it is in fact an intrinsic operator of the language. The result is available at compile time. So one can say:-
#define SIZE_OF_VERSE sizeof verse
enum:
enum spectrum { red, orange, yellow, green,
blue, indigo, violet } colour;
In this construct the first symbol is given the value of 0 and for each
following symbol the value is incremented.
It is however possible to assign specific values to the symbols like
this:
enum tub
{ anorexic = 65,
slim = 70,
normal = 80,
fat = 95,
obese = 135
};
Here is another trivial program which demonstrates the use of enum and a pre-initialised array.
#include <stdio.h>
enum spectrum { red, orange, yellow, green, blue, indigo, violet } colour; char *rainbow[] = { "red", "orange", "yellow", "green",
main() {
|
red orange yellow green blue indigo violet
Yet another example program:
char *ident = "@(#) tellme.c - An example of using a pointer to a function.";
#include <stdio.h>
/*
extern double sin ();
struct table_entry
typedef struct table_entry TABLE; double help ( tp )
/*
TABLE interpretation_table [ ] =
char *output_format = { "\n %s %s = %g\n" };
main( argc, argv )
if ( argc > 3 )
for (;;)
/* This is the way to set up a continuous loop. */
if ( tp -> function == help ) (*tp -> function )(
interpretation_table );
x = atof ( argv[2] );
/* Convert the character string to a double. */
|
Precedence.
First up come what are called
the primary-expression operators:
() Function.
The unary operators:
* Indirection via a Pointer.
Now the binary operators: Arithmetic Operators.
* Multiply.
My
The Shifting Operators.
>> Bit-wise Shift to the Right.
Logical Relation Operators.
< Less Than.
Bit-wise Boolean Operators.
& Bit-wise And.
The Logical Operators.
&& Logical And.
The Assignment Operators. ( They all have the same priority. ) = The normal assignment operator. The Self-referencing Assignment Operators.
+=
|
a = 8;
a += 2;
/* The result is 10 */
a = 7;
a ^= 2;
/* Now a is 5 */
a ^= 2;
/* and back to 7. */
Note: with old compiler you may have problems that
can be cured by putting spaces on either side of the '=' sign or bracketing
the unary minus to the operand.
a=(-2);
a = -2;
Note: >> If you shift a signed integer
to the right when the sign bit is set then in all probability the sign
will be extended.
#include <stdio.h>
#define WORD_SIZE ( sizeof ( INTEGER int ) * 8 )
char *title[] ={ " Signed
Unsigned",
main () {
a = b = SIGN_BIT;
for ( line_counter = 0; line_counter
< WORD_SIZE; line_counter++ ) {
|
This program may behave differently for short and long integers because compiler issuing a Logical Shift instruction, when it should issue a Arithmetic Shift instruction for signed integers and a Logical Shift instructon for unsigned ones. Here are the compiler invocation lines.
cc -olong.shifts -DFIX_COMPILER_BUG -DINTEGER=long
shifts.c
and
cc -oshort.shifts -DINTEGER=short shifts.c
Experiment with the "-DFIX_COMPILER_BUG" and see what your compiler
does.
C-tutorial part 3 | home - top of the page - |
The Pre-processor and Header Files.
The pre-processor is activated by a '#' character in column one of the source code. There are several statements vis:
#include
#define
#undef
#if
#else
#endif
#ifdef
#ifndef
#pragma
#include.
Examples:
#include <stdio.h>
#if ( FLAG )
# include "true.h"
#else
# include "false.h"
#endif
If the file name is < .. > -
then it comes from /usr/include directory ( or its /sys/
subdirectory ).
If the file name is in " .. " -
then it comes from the current working drectory (or you can extend search
path using command-line switches).
extern struct tm *gmtime(), *localtime();
extern char *ctime(), *asctime(); int cftime(), ascftime(); extern void tzset(); extern long timezone, altzone; extern int daylight; extern char *tzname[]; |
hw_uc.h
#define HELLO_MESSAGE "HELLO WORLD...\n"; |
hello.c
#include <stdio.h>
#include HW_H #if !defined( HELLO_MESSAGE )
char *format = "%s",
main() { printf ( format, hello ); } |
cc -DHW_H="\"hw_uc.h\"" hello.c
The compiler output is placed, by default, in the file a.out, so to
execute it issue the command:
a.out
Which, fairly obviously, produces the output:
HELLO WORLD...
As we are going to generate another version of the program we had better
move the executable image file to another file name:
mv a.out hello_uc
Now to produce the other version issue the command line:
cc -DHW_H="\"hw_lc.h\"" hello.c; mv a.out
hello_lc; hello_lc
Which compiles the lower-case version of the hello.c program, using
this version of the include file:
hw_lc.h
#define HELLO_MESSAGE "Hello World...\n"; |
commands included in a shell file:
# @(#) Shell file to do the compilations.
cc -o hello_uc -DHW_H="\"hw_uc.h\"" hello.c
|
#define
- to set up macro definitions. See many exampels in
/usr/include/sys/file.h .
For example:
#define FAPPEND
0x08
#define min(a, b) ((a<b) ? a : b )
NOTE:
1) There isn't a space between the last character of the symbol
being defined and the opening parenthesis enclosing the arguments, and
there MUST NOT BE one.
2) The code into which the macro is expanded MUST always be
enclosed in parentheses and for safety always use parentheses to get the
arithmetic right.
3) Never EVER define a macro, and use it with a side effect.
e.g.
c = min ( a++, b);
/* DON'T _EVER_ DO THIS!!! */
Do you think that the value of 'a' will get
advanced after the macro is used? Well it WON'T. It gets incremented after
the less than test and before the values get assigned! Generate the output
from the pre-processor of the code below to see what's going on:
#include <stdio.h>
main() { int a,b,c; a = 1; b = 2; c = min ( a++, b); /* DON'T _EVER_ DO THIS!!! */ printf ( "a: %d, b: %d, c: %d\n", a, b, c ); } |
4) You can continue a macro on the next line by putting a \ (
back-slash ) as THE VERY LAST character on the line.
#undef:
- this preprocessor command removes a symbol WHICH IS BEING USED
BY THE PRE-PROCESSOR.
#if ( FLAG )
/* Code in
here is sent on to the compiler if FLAG is true. */
#else
/* Code in
here is sent on to the compiler if FLAG is false. */
#endif
You are also allowed to say:
#if defined( FLAG )
#if !defined( FLAG )
Here is an old way of doing the same:
#ifdef FLAG
#ifndef FLAG
By convention all pre-processor symbols are in UPPER_CASE.
#pragma
- used to alter the way in which the compiler works on a block
of code, it is implementation dependent.
The "stringizing" operator
- will discuss later
C-tutorial part 4 | home - top of the page - |
Libraries.
If the function returns a value which is other than of type int, you
have to tell the compiler the type of the returned value. For example,
if you want to use library functions strcmp, and qsort. Let's
look manpage for qsort(3C) , where the 3C in parenthesis is the cryptic
code which is the unix apology for a reference to section 3C in the Manual.
In SYNOPSIS there is no mention of a header file to #include, and also
notice that qsort returns a void, not an int. This means that there is
no header file /usr/include/qsort.h
and you have to declare qsort yourself as an external function. Now look
manpage for string(3C) - the SYNOPSIS here includes the line #include <string.h>
so you have to put it in your program text.
#ident "@(#) qsort-demo.c"
#include <stdio.h> #include <string.h> #include <assert.h> extern void qsort ();
char names[22][25] =
/* Here are some names to sort. */
#define NUMBER_OF_NAMES sizeof ( names ) / sizeof ( names[0] ) main()
/*
printf ( "The Unsorted Names.\n"
);
/*
printf ( "Press RETURN to
continue: " );
/*
qsort (( char * ) names, NUMBER_OF_NAMES, sizeof ( *names ), strcmp ); assert ( names[0][0] <
names[1][0] ); /* Quick check to see it's done
/*
printf ( "The Sorted Names.\n"
);
|
This example shows also that you can the name of a function (strcmp) to another function (qsort) for execution.
The 'C' compilation system will load library functions from the library
/lib/libc.a as a default. All others have to be indicated to the linking
loader by a
switch on the shell interactive command line.
$ cc -o prog prog.c -L /usr/local/lib -lgdbm -lmalloc
You might use this command
line to compile and link a program which uses both the GNU gdbm data-base
manager library, which is installed in the directory /usr/local/lib, and
the
enhanced malloc library. Note that having a #include <whatever.h>
line in the source text will NOT automagically tell the linking loader
to get the functions from the appropriate library. The -lwhatever flag
on the shell command line which initiates execution of "cc" or "ld" is
the only way to tell the loader where to look for the required library.
De-bugging Strategies.
1) Document what you are going to do before (yes BEFORE) you
write any code.
2) Make sure that you keep each file as small as is sensible.
3) Always use names for the objects in your program which are
fully descriptive.
4) ALWAYS take great care with the layout of your code. You
may consider to always put the opening brace of ALL program structures
on a new line. Also if you put them in the leftmost column for structs,
enums, and initialised tables, as well as functions, then the 'find function'
keystrokes ( "[[" and "]]" ) in vi will find them as well as the functions
themselves. Make sure you have the "showmatch" facility in vi turned on.
( And watch the cursor jump when you enter the right hand brace, bracket,
or parenthesis. )
5) Try as hard as you can to have as few global variables as
possible. If you absolutely have to have several globals - then confine
the scope of the globals to just the one file by marking the defining declaration
"static". This stops the compiler producing a symbol which the linking
loader will make available to all the files in your source.
6) Never EVER put 'magic numbers' in you source code. Always
define constants in a header file with #define lines or enum statements.
Here is an example:-
#include <stdio.h>
enum status_input_names
char *stats[] =
#define NUMBER_OF_INPUTS ( sizeof ( stats ) / sizeof ( stats[0])) main()
printf ( "Number of Inputs is: %d\n", NUMBER_OF_INPUTS );
|
Note that as a side effect we have available the meaningful symbols radiator_temperature etc. as indices into the array of status input names and the symbol NUMBER_OF_INPUTS available for use as a terminator in the 'for' loop. This is quite legal because sizeof is a pseudo-function and the value is evaluated at the time of compilation and not when the program is executed. This means that the result of the division in the macro is calculated at the time of compilation and this result is used as a literal in the 'for' loop.
Some advice:
1) Don't get confused between
== - the logical equality operator, and
= - the assignment to a variable operator.
2) Make sure that you are aware of the difference between the logical and bit operators.
&&
This is the logical AND function.
||
This is the logical OR function.
The result is ALWAYS either a 0 or a 1.
&
This is the bitwise AND function used for masks etc.
The result is expressed in all the bits of the word.
3) Similarly to 2 be aware of the difference between the logical complementation and the bitwise one's complement operators.
!
This is the logical NOT operator.
~
This is the bitwise ones complement op.
NOTE: a LOGICAL variable is said to be TRUE when it is non-zero, and FALSE when it is zero.
4) Make sure that you use an editor which tells you the matching symbol.
Example 1.
function_type function_name ( a, b )
type a; type b; { type variable_one, variable_two; if ( logical_expression )
|
set showmode autoindent autowrite tabstop=2 shiftwidth=2 showmatch wm=1
Example 2.
void printUandG()
{ char *format = "\n\ User is: %s\n\ Group is: %s\n\n\ Effective User is: %s\n\ Effective Group is: %s\n\n"; ( void ) fprintf ( tty,
|
- put the opening brace on a new line,
- set the tabs to just 2 spaces
- break long lists of argumants into several lines
/*
** Put all the cursor positions to zero. */ for ( i = 0;
/*
for ( i = edit_mode = current_element = 0;
/*
while ( s[i].element_name != ( char *) NULL &&
/*
} |
The null statement:
";" - a no-operation statement.
The assert macro:
#ident "@(#) assert-demo.c"
#include <stdio.h>
#define TOP_ROW 10
main()
for ( row = 1; row <= TOP_ROW; row++);
|
Which produces the output:-
Assertion failed: row <= TOP_ROW
, file assert-demo.c, line 15
ABORT instruction (core dumped)
It does this because the varable "row" is incremented to one greater than The value of TOP_ROW.
Note two things:
1) The sense of the logical condition. The assert is asserted as soon as the result of the logical condition is FALSE. Have a look at the file /usr/include/assert. Where is the ";" being used as an empty program statement?
2) The unix operating system has dumped out an image of the executing
program for examination using a symbolic debugger. Have a play with "sdb"
in preparation for the lesson which deals with it in more detail.
C-tutorial part 5 | home - top of the page - |
Looping structures:
do ... while ( ... );
/* executed at least once, there is no `until' test at the end of a loop
*/
while ( ... ) repeated_statement;
/* if false - then repeated_statement is NEVER executed */
Associated with the looping structures are the control words:
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 ( init; test; increment ) repeated_statement;
Some examples.
A do loop program.
#ident "@(#) do_demo.c - An example of the do loop"
#include <stdio.h> main()
character = 'a'; do printf ( "%c", character ); while ( character++ < 'z' );
Fairly obviously it prints: abcdefghijklmnopqrstuvwxyz A while loop example. #ident "@(#) while_demo.c - An example of the while loop" #include <stdio.h> main()
character = 'a'; while ( character <= 'z' ) printf ( "%c", character++ );
|
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()
for ( character = 'a'; character <= 'z' ; character++ )
|
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()
for ( character = 'a', character_pointer = alphabets; /*
Start conditions */
for ( character = 'A'; /* character_pointer is at the right
place already */
*character_pointer = (char) '\000'; /* NULL character to terminate string. */ printf ( "%s\n\n", alphabets );
|
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
switch
if
if ... else
#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> /*
char *messages[] =
#if defined( FRANCAIS )
put the French translation in here so that we are ready to export
to
#endif
/*
#define USAGE 0
#define SUCCESS 0
/*
void usage()
/*
int main ( argc, argv )
if ( argc != 3 ) usage();
/* have we been given the right */
/*
message_index = ( i == j ) ? EQUAL : ( i > j ) ? BIGGER : SMALLER; /*
(void) printf ( "\n%s%s%s\n\n", /* Format
string specifying 3 strings. */
|
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" );
|
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>
jmp_buf save; main()
for ( ;; )
/* This is how you set up a continuous loop.
case 1:
case 2:
case 3:
default:
process ()
printf ( "Input a number to simulate an error condition: " );
|
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.
----