CATEGORII DOCUMENTE |
Asp | Autocad | C | Dot net | Excel | Fox pro | Html | Java |
Linux | Mathcad | Photoshop | Php | Sql | Visual studio | Windows | Xml |
DOCUMENTE SIMILARE |
||||||
|
||||||
Complete Programs in C
|
1. Putting it all togetherHaving considered the language and the libraries defined by the Standard, all that now remains is to demonstrate what complete programs look like. This chapter contains some example programs which illustrate how to combine these elements to build programs. However, just before these examples are presented there is one more aspect of the C language to discuss. |
2. Arguments to mainFor those writing programs which will run in a hosted environment, arguments to main provide a useful opportunity to give parameters to programs. Typically, this facility is used to direct the way the program goes about its task. It's particularly common to provide file names to a program through its arguments. The declaration of main looks like this: int main(int argc, char *argv[]);This indicates that There are at least two arguments to The declaration of the Remember too that when it is passed to a function, the name of an array is
converted to the address of its first element. This means that we can also
declare Indeed, you will often see the declaration of When a program starts, the arguments to main will have been initialized to meet the following conditions:
To illustrate these points, here is a simple program which writes the
arguments supplied to #include <stdlib.h> int main(int argc, char **argv) Example 1 If the program name is
Each time that
On the system where this program was tested, a program is run by typing
its name and then the arguments, separated by spaces. This is what happened
(the show_args abcde text hello $ |
3. Interpreting program argumentsThe loop used to examine the program arguments in the example above is a
common C idiom which you will see in many other programs. An additional
common idiom is to use 'options' to control the behaviour of the program
(these are also sometimes called switches or flags). Arguments which start
with a ' progname -a -b -x -u file1 file2 The idea is that each of the options selects a particular aspect from the
program's repertoire of features. An extension to that idea is to allow
options to take arguments; if the so that the In either of the above cases, the options routine returns the character ' To use this routine, a program must supply a list of valid option letters
in the form of a string; when a letter in this string is followed by a ' It seems to be a fact of life that functions which scan text strings looking for various combinations or patterns within them end up being hard to read; if it's any consolation they aren't all that easy to write either. The code that implements the options is definitely one of the breed, although by no means one of the worst: /** options() parses option letters and option arguments from the argv list. * Succesive calls return succesive option letters which match one of * those in the legal list. Option letters may require option arguments * as indicated by a ':' following the letter in the legal list. * for example, a legal list of 'ab:c' implies that a, b and c are * all valid options and that b takes an option argument. The option * argument is passed back to the calling function in the value * of the global OptArg pointer. The OptIndex gives the next string * in the argv[] array that has not already been processed by options(). * * options() returns -1 if there are no more option letters or if * double SwitchChar is found. Double SwitchChar forces options() * to finish processing options. * * options() returns '?' if an option not in the legal set is * encountered or an option needing an argument is found without an * argument following it. * */ #include <stdio.h> #include <string.h> static const char SwitchChar = '-'; static const char Unknown = '?'; int OptIndex = 1; /* first option should be argv[1] */ char *OptArg = NULL; /* global option argument pointer */ int options(int argc, char *argv[], const char *legal) } letter = *posn++; if(!(legal_index = strchr(legal, letter))) if(*++legal_index != ':') else else OptArg = argv[OptIndex]; posn = ''; OptIndex++; } return letter; } Example 2 |
4. A pattern matching programThis section presents a complete program which makes use of option letters as program arguments to control the way it performs its job. The program first processes any arguments that resemble options; the first argument which is not an option is remembered for use as a 'search string'. Any remaining arguments are used to specify file names which are to be read as input to the program; if no file names are provided, the program reads from its standard input instead. If a match for the search string is found in a line of input text, that whole line is printed on the standard output. The
the program prints a count of the total number of matching lines it found in the input file(s). No lines of text are printed.
when searching for a match, the case of letters in both the input lines and string is ignored.
each line of text printed on the output is prefixed with the line number being examined in the current input file.
each line of text printed on the output is prefixed with the name of the file that contained the line.
the program prints only lines which do not match the string supplied. When the program finishes, it returns an exit status to indicate one of the following situations:
at least one match was found.
no match was found, or some error occurred. The program makes extensive use of standard library functions to do all of
the hard work. For example, all of the file handling is performed by calls to
Here is the code for the whole program. Of course, to get this to work you would need to compile it together with the code for the options routine presented above. /** Simple program to print lines from a text file which contain * the 'word' supplied on the command line. * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> /* * Declarations for the pattern program * */ #define CFLAG 0x001 /* only count the number of matching lines */ #define IFLAG 0x002 /* ignore case of letters */ #define LFLAG 0x004 /* show line numbers */ #define NFLAG 0x008 /* show input file names */ #define VFLAG 0x010 /* show lines which do NOT match */ extern int OptIndex; /* current index into argv[] */ extern char *OptArg; /* global option argument pointer */ /* * Fetch command line switches from arguments to main() */ int options(int, char **, const char *); /* * Record the required options ready to control program beaviour */ unsigned set_flags(int, char **, const char *); /* * Check each line of the input file for a match */ int look_in(const char *, const char *, unsigned); /* * Print a line from the input file on the standard output * in the format specified by the command line switches */ void print_line(unsigned mask, const char *fname, int lnno, const char *text); static const char /* Legal options for pattern */ *OptString = 'cilnv', /* message when options or arguments incorrect */ *errmssg = 'usage: pattern [-cilnv] word [filename]n'; int main(int argc, char *argv[]) flags = set_flags(argc, argv, OptString); if(argv[OptIndex]) search_string = argv[OptIndex++]; else if(flags & IFLAG) if(argv[OptIndex] == NULL) else while(argv[OptIndex] != NULL) success += look_in(argv[OptIndex++], search_string, flags); if(flags & CFLAG) printf('%dn', success); exit(success ? EXIT_SUCCESS : EXIT_FAILURE); } unsigned set_flags(int argc, char **argv, const char *opts) } return flags; } int look_in(const char *infile, const char *pat, unsigned flgs) } else in = stdin; while(fgets(line[0], BUFSIZ, in)) if(strstr(line_to_use, pat)) else if(flgs & VFLAG) print_line(flgs, infile, lineno, line[0]); } fclose(in); return matches; } void print_line(unsigned mask, const char *fname, int lnno, const char *text) Example 3 |
5. A more ambitious exampleFinally here is a set of programs designed to cooperate and manipulate a single data file in a coherent, robust fashion. The programs are intended to help keep track of a ladder of players who compete against each other at some game, squash or chess perhaps. Each player has a rank from one to n, where n is the number of players who play, one being the highest rank on the ladder. Players lower down the ladder may challenge players above them and, if the lower ranked player wins, he or she moves up taking the rank of the player who loses. The loser in such a situation, and any other players between challenger and loser, are then moved down one rank. If a challenger does not win, the rankings on the ladder remain unchanged. To provide some measure of equilibrium in the rankings, a player may challenge any higher ranked player, but only wins over players ranked three (or less) higher will allow the challenger to move up the rankings. This ensures that new players added to the bottom of the ladder are forced to play more than one game to reach the top of the ladder! There are three basic tasks which are required to record all the information needed to keep such a ladder going:
The design to be used here provides a separate program to perform each of these tasks. Having made this decision it is clear that a number of operations needed by each program will be common to all three. For example, all three will need to read player records from the data file, at least two will need to write player records into the data file. This suggests that a good approach would be to design a 'library' of functions which manipulate player records and the data file which may in turn be combined to make up the programs which maintain the ladder. Before this can be done it will be necessary to define the data structure which represents player records. The minimum information necessary to record for each player consists of player name and rank. However, to allow for more interesting statistics to be compiled about the ladder let us chose to also keep a record of games won, games lost and the time when the last game was played. Clearly this disparate set of information is best collected together in a structure. The player structure declaration together with the declarations of the
player library functions are combined together in the * * Declarations and definitions for functions which manipulate player * records which form the basis of the ladder * */ #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #define NAMELEN 12 /* max. for player name length */ #define LENBUF 256 /* max. for input buffer length */ #define CHALLENGE_RANGE 3 /* number of higher ranked players who may * be challenged to move up in rank */ extern char *OptArg; typedef struct player; #define NULLPLAYER (player *)0 extern const char *LadderFile; extern const char *WrFmt; /* used when writing records */ extern const char *RdFmt; /* used when reading records */ /* * Declarations for routines used to manipulate the player records * and the ladder file which are defined in player.c * */ int valid_records(FILE *); int read_records(FILE *, int, player *); int write_records(FILE *, player *, int); player *find_by_name(char *, player *, int); player *find_by_rank(int, player *, int); void push_down(player *, int, int, int); int print_records(player *, int); void copy_player(player *, player *); int compare_name(player *, player *); int compare_rank(player *, player *); void sort_players(player *, int); Example 4 Here is the code for the Notice that to manipulate the player records, each
program is required to read the entire data file into a dynamically
allocated array. Before this array is written back to the data file, it is
assumed that the records it contains will have been sorted into rank order.
If the records do not remain sorted, the * Generic functions to manipulate the ladder data file and * player records. * */ #include 'player.h' const char *LadderFile = 'ladder'; const char *WrFmt = '%s %d %d %d %ldn'; const char *RdFmt = '%s %d %d %d %ld'; /* note use of string-joining */ const char *HeaderLine = 'Player Rank Won Lost Last Gamen' '===============================================n'; const char *PrtFmt = '%-12s%4d %4d %4d %sn'; /* return the number of records in the data file */ int valid_records(FILE *fp) /* read num player records from fp into the array them */ int read_records(FILE *fp, int num, player *them) fseek(fp, tmp, SEEK_SET); return i; } /* write num player records to the file fp from the array them */ int write_records(FILE *fp, player *them, int num) return i; } /* * return a pointer to the player in array them * whose name matches name */ player *find_by_name(char * name, player *them, int num) /* * return a pointer to the player in array them * whose rank matches rank */ player *find_by_rank(int rank, player *them, int num) /* * reduce by one the ranking of all players in array them * whose ranks are now between start and end */ void push_down(player *them, int number, int start, int end) else (pp->rank)++; } } /* pretty print num player records from the array them */ int print_records(player *them, int num) return i; } /* copy the values from player from to player to */ void copy_player(player *to, player *from) /* compare the names of player first and player second */ int compare_name(player *first, player *second) /* compare the ranks of player first and player second */ int compare_rank(player *first, player *second) /* sort num player records in the array them */ void sort_players(player *them, int num) Example 5 This code, when tested, was compiled into an object file which was then
linked (together with an object file containing the code for the Here is the code for the simplest of those utilities, This program takes a single option, The player records in the data file should be stored pre-sorted but, just
to be safe, * Program to print the current ladder status. * */ #include 'player.h' const char *ValidOpts = 'f:'; const char *Usage = 'usage: showlddr [-f ladder_file]n'; char *OtherFile; int main(int argc, char *argv[]) } } else if(argc > 1) fname = (OtherFile == 0)? LadderFile : OtherFile; fp = fopen(fname, 'r+'); if(fp == NULL) number = valid_records (fp); them = (player *)malloc((sizeof(player) * number)); if(them == NULL) if(read_records(fp, number, them) != number) fclose(fp); sort_players(them, number); if(print_records(them, number) != number) free(them); exit(EXIT_SUCCESS); } Example 6 Of course the Typically, new players are added at the bottom of the rankings but for the
odd occasion where this really may not make sense, A player may only appear once on the ladder (unless a pseudonym is used!) and there can only be one player at any one rank. Thus the program checks for duplicate entries and if the new player is to be inserted into a middling rank, moves other players already on the ladder out of the way. As with the * Program to add a new player to the ladder. * You are expected to assign a realistic * ranking value to the player. * */ #include 'player.h' const char *ValidOpts = 'n:r:f:'; char *OtherFile; static const char *Usage = 'usage: newplyr -r rank -n name [-f file]n'; /* Forward declaration of function defined in this file */ void record(player *extra); int main(int argc, char *argv[]) { char ch; player dummy, *new = &dummy; if(argc < 5) while((ch = options(argc, argv, ValidOpts)) != -1) break; case '?': fprintf(stderr, Usage); break; } } if((new->rank == 0)) if(strlen(new->name) == 0) new->wins = new->losses = 0; time(& new->last_game); /* make now the time of the 'last game' */ record(new); exit(EXIT_SUCCESS); } void record(player *extra) } number = valid_records (fp); new_number = number + 1; if((extra->rank <= 0) || (extra->rank > new_number)) them = (player *)malloc((sizeof(player) * new_number)); if(them == NULL) if(read_records(fp, number, them) != number) if(find_by_name(extra->name, them, number) != NULLPLAYER) copy_player(&them[number], extra); if(extra->rank != new_number) push_down(them, number, extra->rank, number); sort_players(them, new_number); if((fp = freopen(fname, 'w+', fp)) == NULL) if(write_records(fp, them, new_number) != new_number) fclose(fp); free(them); } Example 7 The only remaining utility required is one for recording the results of
games played. The As with the previous two utilities, Unlike the Given a valid pair of names, a check is then made to see if the loser is higher ranked than winner and whether or not the winner is ranked close enough for the victory to alter the rankings. If a change in the standings is in order, the victor takes the loser's rank and the loser (as well as any other player on an intervening rank) is demoted one rank. Here is the code for the * Program to record a result in the ladder * */ #include 'player.h' /* Forward declarations for functions defined in this file */ char *read_name(char *, char *); void move_winner(player *, player *, player *, int); const char *ValidOpts = 'f:'; const char *Usage = 'usage: result [-f file]n'; char *OtherFile; int main(int argc, char *argv[]) } } else if(argc > 1) fname = (OtherFile == 0)? LadderFile : OtherFile; fp = fopen(fname, 'r+'); if(fp == NULL) number = valid_records (fp); them = (player *)malloc((sizeof(player) * number)); if(them == NULL) if(read_records(fp, number, them) != number) fclose(fp); if((winner = find_by_name(read_name(buf, 'winner'), them, number)) == NULLPLAYER) if((loser = find_by_name(read_name(buf, 'loser'), them, number)) == NULLPLAYER) winner->wins++; loser->losses++; winner->last_game = loser->last_game = time(0); if(loser->rank < winner->rank) if((winner->rank - loser->rank) <= CHALLENGE_RANGE) move_winner(winner, loser, them, number); if((fp = freopen(fname, 'w+', fp)) == NULL) if(write_records(fp, them, number) != number) fclose(fp); free(them); exit(EXIT_SUCCESS); } void move_winner(player *ww, player *ll, player *them, int number) char *read_name(char *buf, char *whom) } Example 8 |
6. AfterwordThe programs shown in this chapter should help to to get a feel for what middle-of-the-road C programs look like, using the language and libraries defined in the Standard. What do we mean by 'middle-of-the-road'? Simply this: they have been designed, implemented, tested and documented in a way appropriate for small, self-contained programs that have no real need to show high levels of robustness and reliability. Many programs don't need to meet demanding criteria; to do more to them would be over-engineering. Clearly, it is entirely dependent on the eventual purpose for which the program is intended. There are situations which place very high demands on the software that is in use; programs to meet these requirements are very carefully engineered and have much higher amounts of effort put into reviewing, testing and the control of access to the source code than would be appropriate for simple illustrative example programs. C is also used in these application areas. The source code of programs that meet such high requirements tends to look distinctively different; the language is the same, but the amount of error checking and correction is typically much higher. We have not tried to illustrate that type of program. Whichever environment you work in, we hope that this book has helped you in your understanding of C. Good luck! |
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 1127
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved