home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft_Programmers_Library.7z / MPL / msc / qcpgmr.txt < prev    next >
Encoding:
Text File  |  2013-11-08  |  1.2 MB  |  30,854 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1.  Microsoft QuickC Programming
  2.  
  3.  
  4.  ════════════════════════════════════════════════════════════════════════════
  5.  
  6.  
  7.  Microsoft(R) QuickC(TM) Programming
  8.  
  9.  The Microsoft(R) Guide to Using the QuickC Compiler
  10.  
  11.  By The Waite Group
  12.     Mitchell Waite, Stephen Prata, Bryan Costales, and Harry Henderson
  13.  
  14.  
  15.  ════════════════════════════════════════════════════════════════════════════
  16.  
  17.  
  18.  PUBLISHED BY
  19.  Microsoft Press
  20.  A Division of Microsoft Corporation
  21.  16011 NE 36th Way, Box 97017, Redmond, Washington 98073-9717
  22.  
  23.  Copyright (c) 1988 by The Waite Group, Inc.
  24.  All rights reserved. No part of the contents of this book may be reproduced
  25.  or transmitted in any form or by any means without the written permission of
  26.  the publisher.
  27.  
  28.  Library of Congress Cataloging in Publication Data
  29.  
  30.  Microsoft QuickC programming.
  31.  Includes index.
  32.  1. C (Computer program language)  2. Microsoft QuickC (Computer program)
  33.  I. Waite, Mitchell.  II. Title: Microsoft Quick C programming.
  34.  QA76.73.C15M53    1988    005.13'3    88-5203
  35.  ISBN 1-55615-048-2
  36.  
  37.  Printed and bound in the United States of America.
  38.  
  39.  1 2 3 4 5 6 7 8 9  MLML  3 2 1 0 9 8
  40.  
  41.  Distributed to the book trade in the United States by Harper & Row.
  42.  
  43.  Distributed to the book trade in Canada by General Publishing Company, Ltd.
  44.  
  45.  Distributed to the book trade outside the United States and Canada by
  46.  Penguin Books Ltd.
  47.  
  48.  Penguin Books Ltd., Harmondsworth, Middlesex, England
  49.  Penguin Books Australia Ltd., Ringwood, Victoria, Australia
  50.  Penguin Books N.Z. Ltd., 182-190 Wairau Road, Auckland 10, New Zealand
  51.  
  52.  British Cataloging in Publication Data available
  53.  
  54.  IBM(R) is a registered trademark, and PC/AT(TM) and PC/XT(TM) are trademarks
  55.  of International Business Machines Corporation.
  56.  
  57.  Microsoft(R) and MS-DOS(R) are registered trademarks, and QuickC(TM) is a
  58.  trademark of Microsoft Corporation.
  59.  
  60.  ────────────────────────────────────────────────────────────────────────────
  61.  Acquisitions editor: Claudette Moore
  62.  Project editor: Eric Stroo
  63.  Copy editor: Gary Masters
  64.  Technical reviewer: Doug Henderson
  65.  ────────────────────────────────────────────────────────────────────────────
  66.  
  67.  
  68.  
  69.  ────────────────────────────────────────────────────────────────────────────
  70.  Contents
  71.  
  72.  
  73.  Preface
  74.  
  75.  Acknowledgments
  76.  
  77.  PART 1  INTRODUCTION TO C
  78.  
  79.  Chapter 1  Introduction
  80.             Why Learn C?
  81.             Why QuickC?
  82.             Hardware Requirements
  83.             Knowledge Requirements
  84.             Conventions and Style
  85.  
  86.  Chapter 2  Starting with QuickC
  87.             Our Book and Their Book
  88.             Directories and Files Used by QuickC
  89.             Running the QuickC SETUP Program
  90.             Setting Up QuickC
  91.             Starting QuickC
  92.             Getting Help
  93.             Fixing Errors
  94.             Preparing for the Next Chapter
  95.  
  96.  PART 2  CORE OF C
  97.  
  98.  Chapter 3  C Fundamentals
  99.             Basic Elements of C Programs
  100.             Punctuation and Spacing in C Programs
  101.             Using Comments in C
  102.             Data Types and Declarations of Variables
  103.             The Power of printf()
  104.             Arithmetic Operators
  105.             Getting Input with scanf()
  106.             Shortcut Assignments, Increments, and Decrements
  107.             Relational Operators
  108.             Logical Operators
  109.  
  110.  Chapter 4  Repetition and Looping
  111.             The for Loop
  112.             The while Loop
  113.             The do Loop
  114.             Debugging and Loops
  115.  
  116.  Chapter 5  Decisions and Branching
  117.             The if Statement
  118.             The Conditional Assignment Statement ?
  119.             Multipath Branching
  120.             The switch Statement
  121.             The break Statement
  122.             The continue Statement
  123.             The goto Statement
  124.             More Complex Conditions for Branching
  125.  
  126.  Chapter 6  Functions and Function Calls
  127.             Functions and Program Design
  128.             Declaring and Defining a Function
  129.             Local and Automatic Variables
  130.             Static Variables
  131.             External Variables
  132.             Register Variables
  133.             Passing Information to a Function
  134.             Functions with Many Parameters
  135.             Functions That Return Information
  136.             Recursion
  137.             Noninteger Functions
  138.             Function Prototypes
  139.             Putting It All Together: A Larger Program
  140.  
  141.  PART 3  ADVANCED C TOPICS
  142.  
  143.  Chapter 7  Arrays
  144.             How Arrays Are Stored in Memory
  145.             How to Declare Arrays
  146.             Referencing and Using Array Items
  147.             Bounds Checking Arrays in Your Code
  148.             How to Initialize Arrays
  149.             Arrays and Functions
  150.             How Array Offsets Advance
  151.             Multidimensional Arrays
  152.             Advanced Topics and Tricks
  153.             The Bitwise Operators, Tiny Arrays
  154.  
  155.  Chapter 8  Addresses and Pointers
  156.             Addresses Reviewed
  157.             What Is a Pointer?
  158.             Accessing Variables with Pointers
  159.             Passing Pointers to Functions
  160.             Pointers and Arrays
  161.             Pointer Arithmetic
  162.             The Interchangeability of *amts and amts[]
  163.             lvalue vs rvalue
  164.             Type Casting Pointers and Addresses
  165.             far Pointers
  166.             Functions That Return Addresses
  167.             Dynamic Arrays
  168.             Advanced Pointer Techniques
  169.  
  170.  Chapter 9  Strings
  171.             Declaring and Initializing Strings
  172.             The String Pool and String Addresses
  173.             Pointers and Initialized Strings
  174.             Formatting Strings with printf()
  175.             String Input and Output
  176.             String Manipulation Routines
  177.             Arrays and Strings
  178.             The Arguments to main()──argv and argc
  179.             Character Classification and Transformation
  180.  
  181.  Chapter 10 Managing Files
  182.             Top-level I/O
  183.             Mid-Level (Unbuffered) File I/O
  184.             The File System
  185.             Advanced Error Handling
  186.  
  187.  Chapter 11 Advanced Data Types
  188.             Structure──An Array of Different Types
  189.             Union──Multiple Types in the Same Space
  190.             Enumerated Data with enum
  191.             Bit Fields
  192.             Advanced typedef
  193.  
  194.  Chapter 12 Large Projects
  195.             Advanced C Preprocessor
  196.             Using QuickC for Large Projects
  197.  
  198.  PART 4  C AND THE HARDWARE
  199.  
  200.  Chapter 13 Keyboard and Cursor Control
  201.             Keyboard Input Functions
  202.             Reading Non-ASCII Keys
  203.             Console I/O Functions
  204.             Keyboard Control with ANSI.SYS
  205.             Using QuickC to Access the BIOS
  206.             Cursor and Screen Control with BIOS Calls
  207.  
  208.  Chapter 14 Monitors and Text Modes
  209.             Monitors and Controllers
  210.             Text Modes and Portability
  211.             Device-independent Programming
  212.             Direct Memory Access
  213.             Paging
  214.             Ports
  215.             The EGA and VGA
  216.  
  217.  Chapter 15 Graphics and QuickC
  218.             The Graphics Modes
  219.             CGA Graphics
  220.             EGA Graphics
  221.             VGA Graphics
  222.  
  223.  Chapter 16 Debugging
  224.             Keyboard-Entry Errors
  225.             Syntax Errors
  226.             Run-Time Errors
  227.             Common Run-Time Errors
  228.             Design Errors
  229.  
  230.  Appendix A  Some Resources for C Programmers
  231.  
  232.  Appendix B  Built-in QuickC Functions
  233.  
  234.  Index
  235.  
  236.  
  237.  
  238.  ────────────────────────────────────────────────────────────────────────────
  239.  Preface
  240.  
  241.    The Waite Group has written books on all aspects of the C language, from
  242.    primers to advanced texts that mix C with assembly language But when
  243.    Microsoft Press suggested we write a book on Microsoft's then unreleased
  244.    QuickC compiler, we were skeptical. Having spent years trying to teach C
  245.    both in the classroom and through our books, we were painfully aware of
  246.    how difficult a language it is to learn. Despite its power, the Microsoft
  247.    C Compiler has confounded many an eager student. Daunted by the cryptic
  248.    syntax of its command-line interface, they slipped from C's learning curve
  249.    and disappeared beneath its power curve.
  250.  
  251.    Our first look at the QuickC beta version sparked our attention──this was
  252.    no standard C compiler. QuickC's interface was profoundly different: The
  253.    editor completely integrated into the compiler, optional mouse
  254.    compatibility, drop-down menus, full color display, the list went on and
  255.    on. Finally we had point-and-click compiling. To us, all this meant a
  256.    radical shift in the way we could teach C──we could take a friendly
  257.    approach that would make C accessible to a much larger group of people.
  258.  
  259.    But was QuickC really a performance program? Were we talking fast object
  260.    code or code more suited to timing traffic signals at snail races? Well,
  261.    after creating hundreds of examples for this book, we can report that
  262.    QuickC lives up to its speedy expectations. A product that can compile
  263.    more than 10,000 lines per minute should satisfy all but the most jaded of
  264.    hackers.
  265.  
  266.    There was more. QuickC was fully compatible with the libraries of version
  267.    5.0 of the Microsoft C Optimizing Compiler. We could develop our C code in
  268.    QuickC's fast and friendly interface, get the errors out quickly with its
  269.    integrated debugger and tracer, and then optimize our program for
  270.    execution time by compiling it under the standard optimizing compiler.
  271.    With the introduction of QuickC, we felt that C had finally reached the
  272.    point of rivaling BASIC in ease of use. We saw in QuickC a product that
  273.    could vitalize the learning of C and reinforce its dominance in
  274.    professional program development.
  275.  
  276.    As educators, we saw that QuickC was an opportunity to build a complete
  277.    course in the C language, one that could be pursued without an instructor
  278.    and that would be attractive to beginners and professionals alike. The
  279.    seductive interface made QuickC a breeze to run──we could focus on the
  280.    syntax rather than on complicated command-line options and batch files. On
  281.    top of this, QuickC's large and comprehensive Graphics Library meant that
  282.    we could make our examples visually appealing and challenging. By assuming
  283.    an IBM personal computer running MS-DOS or PC-DOS, we could tackle the
  284.    sensitive issues of the interface between MS-DOS and C while at the same
  285.    time flexing the keyboard, text, and bitmapped displays.
  286.  
  287.    After all these grandiose thoughts, the next thing we did was very
  288.    natural──we gulped loudly. In the time available, no single author could
  289.    possibly master a product as rich as QuickC with the aim of writing a book
  290.    that examines thoroughly its vast repertoire. The solution was to pool the
  291.    energies of four experienced C authors with over 25 years of combined
  292.    programming and teaching experience, each writer focusing on a different
  293.    section of the book. We think you will find that this book goes beyond
  294.    most C books on the market (including our own). If you have any questions
  295.    or comments, please address them to: The Waite Group, 3220 Sacramento
  296.    Street, San Francisco, California 94115.
  297.  
  298.    Mitchell Waite
  299.    Stephen Prata
  300.    Bryan Costales
  301.    Harry Henderson
  302.  
  303.  
  304.  
  305.  ────────────────────────────────────────────────────────────────────────────
  306.  Acknowledgments
  307.  
  308.    The authors would like to take this opportunity to thank the people at
  309.    Microsoft Press for helping to make this book a success: Claudette Moore,
  310.    for acquiring this title and putting up with the authors' numerous
  311.    requests throughout the project; Gary Masters, for editing and blending
  312.    the different styles into one clear message; Doug Henderson, for his
  313.    technical review; Eric Stroo, for coordinating the progress of the final
  314.    manuscript through the production process and for being so diligent about
  315.    the final look of the book; Alison Conn, for her review of the book's
  316.    technical coverage; and Greg Lobdell, for providing a continual flow of
  317.    alpha and beta copies of the QuickC compiler. Also, thanks to Reed Koch
  318.    for his many hours of explaining QuickC's internals to the authors.
  319.  
  320.  
  321.  
  322.  
  323.  
  324.                                    Dedication
  325.                                  To Bobbie Lee,
  326.                      who touched me in a way no one ever has
  327.                                     Mitchell
  328.  
  329.  
  330.  
  331.  ────────────────────────────────────────────────────────────────────────────
  332.  PART 1  INTRODUCTION TO C
  333.  ────────────────────────────────────────────────────────────────────────────
  334.  
  335.  
  336.  
  337.  ────────────────────────────────────────────────────────────────────────────
  338.  Chapter 1  Introduction
  339.  
  340.  
  341.  Why Learn C?
  342.  
  343.    If you have experience with C, you are probably familiar with its
  344.    advantages over alternatives such as BASIC or Pascal, and you may want to
  345.    skip to the next section, which discusses the specific advantages of
  346.    QuickC for C programmers. Here we compare C with two other popular
  347.    languages, BASIC and Pascal.
  348.  
  349.    Although Pascal has its enthusiasts, and our old friend BASIC certainly
  350.    has been improved in many ways (Microsoft's QuickBASIC for example), C has
  351.    quickly become the premier language for professional programming both on
  352.    micros, such as the IBM PC family, and on larger machines, such as those
  353.    running the UNIX/XENIX operating system. Why is C so popular?
  354.  
  355.  Portability and Standards
  356.  
  357.    One reason is portability. The core of standard C is so designed that the
  358.    same program runs on an IBM PC, a VAX mini, and an IBM mainframe.
  359.    Portability comes about from adhering to standards that guarantee common
  360.    features and functions regardless of the vendor, implementation, or
  361.    hardware environment. The first, informal C standard was proclaimed by the
  362.    famous "white book," Brian W. Kernighan and Dennis M. Ritchie's The C
  363.    Programming Language (New Jersey: Prentice-Hall, 1978). The specifications
  364.    in this book have been widely adopted in the design of C compilers, but
  365.    the definitions are not comprehensive and specific enough to provide a
  366.    true standard. Therefore, the American National Standards Institute (ANSI)
  367.    has proposed a draft standard for the C language. (At the time of this
  368.    writing, the standard has not been officially adopted, but most of its
  369.    features seem stable.) Most current and future C compilers will be written
  370.    to conform with the ANSI standard. QuickC is compatible with the ANSI
  371.    standard. It also permits you to verify that your code uses only
  372.    ANSI-compatible functions and definitions or to identify nonstandard
  373.    features, such as those needed to support functions specific to MS-DOS and
  374.    to IBM hardware.
  375.  
  376.    Another reason for the popularity of C is its close ties to the UNIX
  377.    operating system. UNIX was written in C, and a variety of standards
  378.    support the use of C in the UNIX environment. QuickC is functionally
  379.    compatible with the UNIX System V standard library specifications.
  380.  
  381.    But what does all of this mean to you, the QuickC programmer?
  382.  
  383.    A C program written under QuickC on an IBM PC can, if it uses only
  384.    ANSI-standard features, be moved to an Apple Macintosh, and you can
  385.    compile it with an ANSI-standard Macintosh C compiler and run it in the
  386.    new environment.
  387.  
  388.    This level of standardization is not common in programming languages.
  389.    Pascal is only partially standardized: A Turbo Pascal program for the IBM
  390.    PC, for example, cannot run under standard IBM Pascal without
  391.    modification. In the IBM PC world, the ubiquitous BASICA program has
  392.    offered a kind of standard, but other models of computers are provided
  393.    with quite different dialects of BASIC, and you must do an extensive
  394.    conversion to get a BASIC program written on one machine to run on another
  395.    manufacturer's hardware.
  396.  
  397.    Notice that this discussion applies specifically to the "core" of C: the
  398.    control structures, data structures, and basic input/output functions.
  399.    Outside of this standard core, however, a number of areas of a C
  400.    implementation are machine-dependent, such as the size of various kinds of
  401.    numbers, keyboard codes, the video screen, graphics, and features of the
  402.    operating system that handle files. To be worth its salt, a C compiler
  403.    that runs on the IBM PC must include functions that give programs access
  404.    to MS-DOS features, the underlying BIOS, and the hardware. Similarly, a C
  405.    compiler for the Macintosh must include functions that give a program
  406.    access to such elements as the machine's system toolbox. These functions
  407.    are hardware-dependent and implementation-specific──by definition, they
  408.    are not portable, but they are essential to getting the most out of your
  409.    machine. C, as you will discover, provides a way to gather the
  410.    machine-dependent parts in an organized manner, something other languages
  411.    can't do.
  412.  
  413.    BASIC and, to a lesser extent, Pascal approach hardware dependence by
  414.    customizing the language itself to include commands or functions that take
  415.    care of the machine-dependent features. For example, a BASIC statement to
  416.    control the speaker might be called PLAY. Another version of BASIC might
  417.    call it MUSIC. The problem with this approach is apparent when you try to
  418.    convert a program to run on a different machine; you cannot easily find
  419.    the parts of the program that you must change to manipulate proprietary
  420.    features. Also, such hardware-dependent statements may work differently on
  421.    computers with different hardware configurations.
  422.  
  423.  A Modular Approach
  424.  
  425.    The programmer's task is more manageable with C. Each C compiler includes
  426.    files of definitions, called include files, and collections of precompiled
  427.    functions, called function libraries, which you can use to supplement the
  428.    core of C to take full advantage of the features of a given machine. Your
  429.    QuickC function library includes a rich collection of definitions and
  430.    functions for MDA, CGA, EGA, MCGA, and VGA graphics (as well as Hercules
  431.    graphics, starting with version 1.01); the whole set of MS-DOS function
  432.    calls; and much more.
  433.  
  434.    The result is that a C programmer has several choices. If you don't need
  435.    graphics or machine-specific features, you can write an ANSI-standard
  436.    text-only C program and easily move it to other machines and operating
  437.    systems. If you do need machine-dependent features in your program, you
  438.    can use the "no-frills" version of the program and then add graphics and
  439.    other hardware-dependent features in easily identified include files and
  440.    libraries. For a particular hardware environment, you can then merge the
  441.    appropriate include files and libraries into your program. Figure 1-1 on
  442.    the following page illustrates the concept of portability.
  443.  
  444.    Portability requires many trade-offs. In general, the less portable (in
  445.    other words, the more hardware-dependent) a program is, the faster it
  446.    runs, and the more it takes advantage of graphics and other special
  447.    hardware features. On the other hand, the more portable a program is, the
  448.    easier it is to maintain, modify, or convert it to work with new hardware.
  449.  
  450.    Throughout this book, we point out portability issues and suggest ways to
  451.    deal with them. For example, we note those features of QuickC that are
  452.    compatible with ANSI and UNIX System V. We also look at portability versus
  453.    performance in the MS-DOS world. For example, we discuss alternative ways
  454.    for dealing with devices such as the keyboard and video display on MS-DOS
  455.    machines (standard I/O, console I/O, and BIOS) and point out the
  456.    portability trade-offs involved with each.
  457.  
  458.    ┌────────────────────────────┐
  459.    │                            │  Not
  460.    │    Customized statements   │  portable
  461.    │                            │
  462.    │┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │
  463.    ├┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┤
  464.    │                            │
  465.    │      MS-DOS and BIOS       │
  466.    │                            │
  467.    ├────────────────────────────┤
  468.    │          Hardware          │
  469.    └────────────────────────────┘
  470.  
  471.    (A)  BASIC--A SNUG FIT BUT NOT PORTABLE
  472.  
  473.  
  474.              ANSI/UNIX
  475.    ┌────────────────────────────┐  Can run on
  476.    │     Standard functions     │  IBM PC, VAX,
  477.    └─────────┐        ┌─────────┘  Macintosh,
  478.              │        │            and others.
  479.              ├────────┤
  480.              └────────┘
  481.                  │
  482.    ┌─────────┐       ┌─────────┐  Implementation
  483.    │         │        │         │  of C, such as
  484.    │         │        │         │  Microsoft C or
  485.    │         └────────┘         │  Quick C.
  486.    │ Machine-specific libraries │
  487.    │┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │
  488.    └┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘
  489.                  │
  490.                  
  491.     ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐
  492.    ┌┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┐  Specific
  493.    │                            │  machine-
  494.    │      MS-DOS and BIOS       │  IBM PC,
  495.    │                            │  for example.
  496.    ├────────────────────────────┤
  497.    │          Hardware          │
  498.    └────────────────────────────┘
  499.  
  500.    (B)  C--A PORTABLE CORE
  501.  
  502.    Figure 1-1.  Portability in C.
  503.  
  504.  C Is Powerful
  505.  
  506.    Portability is desirable, but you also want to write code that takes full
  507.    advantage of the hardware. In this age of drop-down menus, windows, mice,
  508.    and help screens, users expect a lot more out of software than they did
  509.    only a few years ago. As a programmer you are often pushing the limits of
  510.    the hardware, whether in processing speed, I/O, or graphics.
  511.  
  512.    When it comes to harnessing the hardware, C really shines. For example,
  513.    other languages try to hide the fact that you are manipulating the
  514.    contents of memory when you write code; with C pointers, you can easily
  515.    manipulate memory directly. With Pascal, you can also directly manipulate
  516.    memory with pointers, but the syntax is not as simple or as powerful as
  517.    that of C. And in BASIC, you can use a PEEK and a POKE to access memory,
  518.    but they lack the flexibility of pointers.
  519.  
  520.    Another important indicator of the power of a language is its ability to
  521.    use machine resources efficiently. All high-level compiled languages
  522.    translate program statements into machine instructions. With most
  523.    languages you have little control over the efficiency of the resulting
  524.    machine instructions. You are at the mercy of the assumptions the compiler
  525.    or interpreter makes about your program and how it will be used. Suppose,
  526.    for example, that your program uses one or two variables frequently in a
  527.    loop that will be executed many times. In C, you declare register
  528.    variables that are stored, if possible, in internal CPU registers; thus,
  529.    delays in loading or retrieving their values in memory are avoided. The
  530.    result is faster execution speed.
  531.  
  532.    Another important feature of C is its ability to create a variety of
  533.    memory models. A memory model describes the way RAM is used during
  534.    compilation and the way program code and data are shared in RAM. With most
  535.    older BASICs you can use only 64 KB of memory to hold program code and
  536.    data. Today, most MS-DOS machines have at least 256 KB (and often 640 KB
  537.    of memory or more). Thus, newer compilers for BASIC, Pascal, and other
  538.    languages often allow access to a larger amount of RAM. But C compilers go
  539.    a step further: You──the programmer──decide how the computer will allocate
  540.    memory. Depending on the needs of your program, you can choose to use most
  541.    of the machine's memory for storing compiled instructions, you can use
  542.    most of the memory to store data (such as arrays, structures, or lists),
  543.    or you can allocate varying numbers of 64 KB memory segments to both.
  544.    Figure 1-2 on the following page shows the concepts of register
  545.    variables, pointers, and memory models.
  546.  
  547.    Pointers, register variables, and memory models are only some of the
  548.    options C gives you for controlling the machine. In addition, most C
  549.    compilers let you improve, or "optimize," the machine code generated from
  550.    your program. You can optimize for program size (a smaller .EXE file) or
  551.    for faster execution or for a combination of these. For example, QuickC
  552.    performs some optimization for you and lets you choose other features as
  553.    appropriate. In addition, you can use QuickC in combination with Microsoft
  554.    C (the professional, industrial-strength C compiler) to provide
  555.    optimization that is truly state of the art.
  556.  
  557.    Pointers   ┌──────────────────┐              ┌────────────────┐
  558.    for direct │ main ()          │              ├────────────────┤
  559.    access to  │ int * ptr; ──────┼──────┐       ├────────────────┤
  560.    memory     │ ptr ++; ─────────┼───┐  │       ├────────────────┤
  561.               │ ...              │   │  │       ├────────────────┤
  562.               │                  │   │  │       ├────────────────┤
  563.               │                  │   │  │       ├────────────────┤
  564.               └──────────────────┘   │  │       ├────────────────┤
  565.                     Program          │  └──────├────────────────┤
  566.                                      │          ├────────────────┤
  567.                                      └─────────├────────────────┤
  568.                                                 └────────────────┘
  569.                                                       Memory
  570.  
  571.    (A)                         POINTERS
  572.  
  573.  
  574.    Fast       ┌──────────────────┐              ┌────────────────┐
  575.    register   │ main ()          │───── CPU    ├────────────────┤
  576.    access     │ register int i;  │─────        ├────────────────┤
  577.               │ ...              │              ├────────────────┤
  578.    Regular    │                  │─ ─ ─ ─ ─ ─  ├────────────────┤
  579.    memory     │ int regular_varn │  ─ ─ ─ ─ ─  ├────────────────┤
  580.    access     │ ...              │              ├────────────────┤
  581.               └──────────────────┘              ├────────────────┤
  582.                     Program                     ├────────────────┤
  583.                                                 ├────────────────┤
  584.                                                 ├────────────────┤
  585.                                                 └────────────────┘
  586.                                                       Memory
  587.  
  588.    (B)                     REGISTER VARIABLES
  589.  
  590.  
  591.                                     ┌──────┐
  592.                                     │      │
  593.                    ┌──────┐         │ Code │          ┌──────┐
  594.                    │ Code │         │      │          │      │
  595.    ┌──────┐        ├──────┤         ├──────┤          │ Code │
  596.    │ Code │        │      │         │      │          │      │
  597.    ├──────┤        │ Data │         │ Data │          ├──────┤
  598.    │ Data │        │      │         │      │          │ Data │
  599.    └──────┘        └──────┘         └──────┘          └──────┘
  600.  
  601.    (C)                        MEMORY MODELS
  602.  
  603.    Figure 1-2.  C gives you control of the machine.
  604.  
  605.  C Is Extensible
  606.  
  607.    C also lets you customize the contents of include files and libraries so
  608.    that they contain only the definitions and functions your program needs.
  609.    These custom files can contain functions for anything from manipulating a
  610.    database to formatting text. After you write and test these definitions
  611.    and functions, your main program can use them as easily as it can use the
  612.    standard include files and libraries provided with your compiler. On large
  613.    real-world programming projects, teams of programmers can receive
  614.    specifications for each set of routines needed, and each team can create
  615.    resources that can be used anywhere in the project. Although most
  616.    languages offer a version of this building-block methodology, the C
  617.    approach is the simplest, the most flexible, and the easiest to use.
  618.  
  619.    The very popularity of C enhances the value of such language extensions.
  620.    Hundreds of vendors have created C function libraries for almost every
  621.    imaginable task. Figure 1-3 shows conceptually how you can use function
  622.    libraries from both QuickC and other vendors in your programs. You can
  623.    easily integrate vendor libraries into your own code, and because they are
  624.    the products of professional C programmers, they are likely to be fast and
  625.    efficient. You can almost always avoid the age-old problem of reinventing
  626.    the wheel.
  627.  
  628.                               ┌──────────┐
  629.                               │  MS-DOS  │
  630.                               │     ┌──────────┐
  631.                               │     │   I/O    │
  632.                               │     │     ┌──────────┐
  633.                               └─────│     │ Graphics │
  634.      ┌─────────────┐                │     │          │
  635.      │             │                └─────│          │
  636.      │ Included  ─┼──────────────────────│          │
  637.      │ definitions │                      └──────────┘
  638.      │ ─────────── │
  639.      │ Your code   │                              Third-           Your
  640.      │ main ()     │           Microsoft          party            custom
  641.      │ ...         │           libraries          libraries        library
  642.      └─────────────┘           ┌─┐┌─┐┌─┐          ┌─┐┌─┐           ┌─┐
  643.             │ Compile          │ ││ ││ │          │ ││ │           │ │
  644.    ┌──────────────────┐       └─┘└─┘└─┘          └─┘└─┘           └─┘
  645.    │ Compiled Modules  │───────────┘  │               │             │
  646.    ├───────────────────┤              │               │             │
  647.    │ Standard Library  │──────────────┘               │             │
  648.    ├───────────────────┤                              │             │
  649.    │ Graphics          │──────────────────────────────┘             │
  650.    ├───────────────────┤                                            │
  651.    │ Database          │────────────────────────────────────────────┘
  652.    ├───────────────────┤
  653.    │ Special functions │
  654.    └───────────────────┘
  655.             │ Link
  656.    ┌──────────────────┐
  657.    │   Ready-to-run    │
  658.    │      program      │
  659.    └───────────────────┘
  660.  
  661.    Figure 1-3.  Using include files and libraries.
  662.  
  663.  C Is Structured
  664.  
  665.    The syntax of the C language itself supports structured programming. C
  666.    provides the control structures of a modern structured language, such as
  667.    if/then/else, for, while, while...do, and switch. (The last is like
  668.    Pascal's case statement.) If you are experienced in Pascal or in one of
  669.    the newer BASICs (such as Microsoft QuickBASIC), you will find these
  670.    control structures conceptually familiar. However, you will have to learn
  671.    syntax differences for C, and boxes in the text point these out. If you
  672.    are used to one of the older BASICs, you will be pleasantly surprised at
  673.    how these structures enable you to avoid nearly all goto statements that
  674.    lead to disorganized "spaghetti code."
  675.  
  676.  C Is Concise
  677.  
  678.    Although C is a well-structured language, it encourages concise rather
  679.    than verbose statements. For example, it uses braces to begin and end
  680.    blocks of code, rather than Pascal's begin and end. C provides shorthand
  681.    operators for assigning values to variables and for incrementing
  682.    variables. To show the flavor of C, the following table presents a few
  683.    comparisons of C, Pascal, and BASIC assignment statements:
  684.  
  685.    Some Comparisons of BASIC, Pascal, and C
  686.                             BASIC           Pascal           C
  687.    ──────────────────────────────────────────────────────────────────────────
  688.    1. Set a, b, and c to 0  a = 0           a := 0;          a = b = c = 0;
  689.                             b = 0           b := 0;
  690.                             c = 0           c := 0;
  691.    2. Set i to i + 1        i = i + 1       i := i + 1;      i++;
  692.    3. Set a to a + 5        a = a + 5       a := a + 5;      a += 5;
  693.    ──────────────────────────────────────────────────────────────────────────
  694.  
  695.    Such conciseness speeds the typing of programs and makes C source files
  696.    more compact and easier to edit. C functions are more accessible than
  697.    their Pascal counterparts and much more efficient than the awkward
  698.    subroutine mechanism of BASIC. With the C preprocessor, you can create
  699.    your own shorthand, or macro, definitions with which you insert
  700.    expressions or whole blocks of code in text by typing the name of the
  701.    definition.
  702.  
  703.    This brief overview of the general features of C should suggest why the
  704.    language is so popular. Let's now look more closely at the product with
  705.    which this book is concerned, Microsoft QuickC, and see how its particular
  706.    features and advantages make programming in C even more attractive.
  707.  
  708.  
  709.  Why QuickC?
  710.  
  711.    Traditionally, C has had one big drawback compared with interpreted
  712.    languages such as BASIC──a complex compilation and debugging process. You
  713.    probably know that C is a compiled language, and MS-DOS─based compiled
  714.    languages traditionally have required that you go through a lengthy series
  715.    of steps to produce an executable file.
  716.  
  717.    The steps to compiling a traditional C program are the following:
  718.  
  719.    1.  Start a text editor or word processor and write a program.
  720.  
  721.    2.  Save the program to disk and exit the editor.
  722.  
  723.    3.  Run the compiler program by issuing a command line from the DOS
  724.        prompt, usually with several filenames and options included, that tell
  725.        it, for example, what memory model to use and whether to generate a
  726.        listing file.
  727.  
  728.    4.  Look at the listing produced by the compiler, and study every error
  729.        message.
  730.  
  731.    5.  Print out this error list for reference.
  732.  
  733.    6.  Start the editor again, open your C program file, and for each error
  734.        try to find the exact line in which the error occurred and correct the
  735.        program.
  736.  
  737.    7.  Go back to step 3 and try again until the program compiles without
  738.        errors into an object code file.
  739.  
  740.    8.  Now run the linker, and tell it what libraries to combine with your
  741.        object code file to produce an executable program (an MS-DOS .EXE
  742.        file). If you used an incorrect function name or failed to specify the
  743.        correct libraries, you will now get a new batch of error messages,
  744.        this time from the linker. (They may, for example, report an
  745.        "unresolved external," which probably means the name you used for a
  746.        function in your code did not match the name of the function defined
  747.        in the library.) To fix these errors, you may need to look at listings
  748.        of include files. Or you may have to go back to the editor and correct
  749.        your program. In any case, you must recompile and then try to link
  750.        again.
  751.  
  752.    9.  When the code links without errors, you can finally run the program.
  753.        Did it execute as you expected? No? Do you want to make some changes?
  754.        Well, go back to the editor and try again.
  755.  
  756.    Just reading through these steps suggests how tedious a traditional
  757.    compiled language can be. With interpreted languages, such as BASIC, LOGO,
  758.    or HyperTalk, you can type a line or two of code, execute it immediately,
  759.    and see the results. If your line of code contains errors or if you want
  760.    to add or change something, the interpreter usually provides a simple text
  761.    editor or line editor you can use immediately.
  762.  
  763.    But interpreted languages have one critical drawback──they're slow. Each
  764.    line in a program in an interpreted language has to be translated into
  765.    machine-executable instructions each time it is encountered. Therefore,
  766.    only the simplest interpreted-language applications run fast enough for
  767.    use in the real world.
  768.  
  769.    The philosophy behind QuickC is to provide a programming environment that
  770.    is as easy to use as an interpreter, but with the execution speed
  771.    obtainable only through a compiler. With QuickC, writing and testing
  772.    programs is so easy that C can be a beginning programmer's first language.
  773.  
  774.  The QuickC Programming Environment
  775.  
  776.    With QuickC, you do all of your program development in and from the same
  777.    place──the QuickC integrated programming environment. (Figure 1-4 shows
  778.    the way your screen looks when you start QuickC.) This environment offers
  779.    many advantages:
  780.  
  781.    1.  You can open a file for editing by using the Open command on the File
  782.        menu, or you can simply start typing a new program. The QuickC
  783.        full-screen editor is immediately available, with insert/delete,
  784.        cut/paste, indention──all the features you need to type a program as
  785.        easily as you type a letter with a word processor. And you never
  786.        really "leave" this editor. You merely select whatever service you
  787.        need from the menus.
  788.  
  789.    ┌────────────────────────────────────────────────────────────────────────┐
  790.    │ Figure 1-4 can be found on p.12 of the printed version of the book.    │
  791.    └────────────────────────────────────────────────────────────────────────┘
  792.  
  793.    Figure 1-4.  The initial QuickC screen.
  794.  
  795.    2.  To run the program you can click on the mouse or type a command. When
  796.        you work with a program that has not yet been compiled, the compiler
  797.        and linker are called as needed. There are no complex command-line
  798.        options to type. If your program is error free, the program runs in
  799.        seconds on the output screen.
  800.  
  801.        The main reason your programs compile, link, and run so quickly with
  802.        QuickC is that, unlike traditional C compilers that compile and link
  803.        to disk, QuickC by default compiles to memory. Thus, it can compile
  804.        10,000 lines a minute on a standard IBM PC/AT. Another reason is that
  805.        some of the most commonly needed functions are held in memory. You
  806.        also can create libraries that can be loaded into memory. The result
  807.        is that QuickC uses available memory very efficiently.
  808.  
  809.    3.  As you view an error message, the cursor follows along through your
  810.        program text; you can instantly correct each error with the built-in
  811.        editor. No printed listings to pore over; no error numbers to look up!
  812.  
  813.    4.  Suppose your program compiles correctly but doesn't work as you
  814.        expected. Without leaving QuickC, you can turn on the debugging and
  815.        trace features, rerun your program, and then watch the changing values
  816.        of selected variables, follow the flow of execution, and check the
  817.        values being passed to and from functions called by your program.
  818.  
  819.        What about multiple-module programs──C programs that have several
  820.        separately compiled libraries and code files? Traditionally, you had
  821.        to run a special "make" program and give it a file with a unique
  822.        syntax that told the compiler how to rebuild such a complex program
  823.        after any change was made. With QuickC's program list feature, you
  824.        simply tell QuickC what libraries and source code files you want to
  825.        use. QuickC keeps track of all the other details, such as the
  826.        relationship between modules and the date each module was last
  827.        compiled.
  828.  
  829.    5.  Do you need access to MS-DOS? Need to make a new directory or back up
  830.        some programs? Maybe you want to run some previously compiled C
  831.        programs from MS-DOS. With a traditional, command-line-driven C
  832.        compiler, you exit the compiler, work in MS-DOS, and then run the
  833.        compiler again and figure out where you left off. With QuickC, you
  834.        never leave the integrated programming environment. Using QuickC's DOS
  835.        Shell feature, you exit to MS-DOS, take care of your business, and
  836.        return to QuickC where you left off.
  837.  
  838.    You can select many other features from the QuickC programming environment
  839.    in the same easy way. With a command-line compiler, most features require
  840.    that you type obscure flags or option switches on the command line or
  841.    create batch files to simplify complicated compiler commands. With QuickC,
  842.    you select with a mouse click or keystroke such features as the error
  843.    warning level, language extensions, and optimization. But don't let the
  844.    convenience deceive you──underneath the covers, QuickC is constructing the
  845.    proper list of options so that you can use the same linker. (QuickC also
  846.    includes a command-line-driven compiler for those times you have a special
  847.    need, such as compiling under certain memory models, or when you want to
  848.    work outside the QuickC environment.)
  849.  
  850.  QuickC Performs
  851.  
  852.    QuickC is faster in almost all cases than its nearest competitors, and it
  853.    beats them hands down in floating-point operation.
  854.  
  855.    QuickC also is fully compatible with its "big brother," the Microsoft C
  856.    Optimizing Compiler, versions 5.0 and later. Any program that compiles
  857.    under QuickC compiles under Microsoft C, version 5.0. Therefore, you can
  858.    develop programs with QuickC and then effortlessly recompile them under
  859.    Microsoft C for fine tuning, using a variety of optimization techniques.
  860.  
  861.  QuickC: Standard and Comprehensive
  862.  
  863.    Earlier we discussed ANSI and other official standards for C. There are
  864.    also unofficial industry standards that are almost as important. When you
  865.    use QuickC, you have the benefits of using a compiler that has become the
  866.    industry standard for PCs: Microsoft C. QuickC is fully compatible with
  867.    that standard. Thus, dozens of third-party C code libraries work with your
  868.    programs because the programs you write are compatible with the ANSI or
  869.    UNIX System V standards or with the MS-DOS─specific features of
  870.    Microsoft C.
  871.  
  872.    The extras that come with the QuickC product are also impressive. Each
  873.    standard-model library (small, medium, compact, large) supports the 8087
  874.    coprocessor. There are libraries for every kind of PC graphics from
  875.    monochrome and CGA to the latest VGA graphics for the IBM PS/2. The QuickC
  876.    Graphics Library routines feature easy-to-use routines for drawing points
  877.    and lines and manipulating complete images, including filling and
  878.    animation, all with impressive speed. QuickC also has libraries that allow
  879.    your programs complete access to MS-DOS and BIOS calls. And, because of
  880.    QuickC's UNIX compatibility, you can also use UNIX System V functions for
  881.    writing programs that can be ported to work in the UNIX environment.
  882.  
  883.  
  884.  Hardware Requirements
  885.  
  886.    To run QuickC you need an IBM PC/XT, PC/AT, PS/2, or compatible computer
  887.    with at least 448 KB of RAM and at least two floppy-disk drives. We
  888.    suggest, however, that you develop QuickC programs on a hard disk.
  889.    Compiling or linking to disk with floppy disks is time-consuming compared
  890.    with hard disks. Also, fitting all the files you need for developing
  891.    programs onto two disks can be tricky. But because some of you will be
  892.    using floppy-disk-based systems, we will give you some tips later that
  893.    should help you make the best of the situation. (And the situation is
  894.    anything but grim: You can certainly develop programs that run great under
  895.    QuickC on a floppy-based system.)
  896.  
  897.    We also recommend (but don't presuppose) that you use QuickC with a
  898.    compatible mouse. You can handle all QuickC functions from the keyboard,
  899.    but why get bogged down learning the keystroke combinations? With a mouse
  900.    in hand, you simply point at what you want and select it.
  901.  
  902.    On the other hand, many people don't have (or choose not to use) a mouse.
  903.    With QuickC, you can use short keystroke combinations. For example,
  904.    Alt-r-s selects the Run menu's Start option to compile and run a program.
  905.    (Even if you have a mouse, typing is sometimes faster.)
  906.  
  907.    Graphics capability is optional for most of this book. Chapter 15, which
  908.    deals with graphics, requires a CGA, of course; for advanced graphics, you
  909.    need an EGA; and the VGA section requires a PS/2, or a VGA board for older
  910.    PCs. (If you have the new VGA, you also have CGA and EGA capability.) Even
  911.    if you have only the basic monochrome adapter, you can create many
  912.    interesting QuickC programs with the built-in IBM graphics character set.
  913.  
  914.    Finally, we recommend that you have a printer (although a printer is not
  915.    required for this book).
  916.  
  917.  
  918.  Knowledge Requirements
  919.  
  920.    Some programming experience──with BASIC or Pascal, for example──will help.
  921.    But thanks to the ease of use of QuickC, C can be your first programming
  922.    language, although you may have to work a bit harder than more experienced
  923.    programmers.
  924.  
  925.    Because many of you have programmed in BASIC (such as Microsoft's BASICA
  926.    or QuickBASIC) or Pascal (Borland's Turbo Pascal, for example), we scatter
  927.    "asides" throughout the text for BASIC and Pascal programmers. These point
  928.    out the ways in which C is similar to and different from those languages.
  929.    Familiarity with another language is a two-edged sword when it comes to
  930.    learning C. On the one hand, you already know many programming concepts
  931.    used in C. On the other hand, differences in syntax and usage can trip you
  932.    up if you aren't careful.
  933.  
  934.    If you are a UNIX programmer, you will feel right at home──as soon as you
  935.    get used to QuickC's much more comfortable living room! The QuickC
  936.    environment is far easier to use than the UNIX cc compiler and ln linker,
  937.    and you won't have to write any make scripts. You probably already know
  938.    the fundamentals of C, but watch out for features that are different in
  939.    the IBM PC/MS-DOS environment, especially graphics and MS-DOS system
  940.    calls. But as we noted, with a few minor exceptions, Microsoft C supports
  941.    the standard I/O and other library functions used on UNIX systems.
  942.    Occasional boxes point out matters of interest to UNIX programmers.
  943.  
  944.  
  945.  Conventions and Style
  946.  
  947.    We have chosen the following typographical conventions for the
  948.    descriptions of a C program in the text:
  949.  
  950.    ■  Names of ordinary (local) variables are lowercase italic. Example:
  951.       count, sum
  952.  
  953.    ■  Names of external or global variables are also italic, but the first
  954.       letter is capitalized. Example: Model
  955.  
  956.    ■  Underscores join the words of multiple-word variable names. Example:
  957.       Grand_total (an external variable) or line_count (an ordinary variable)
  958.  
  959.    ■  Constants created with #define are uppercase italic. Example: PI
  960.  
  961.    ■  Macro definitions are uppercase italic. Example: PRINT_ERROR(MSG)
  962.  
  963.    ■  Function names are lowercase italic. Underscores join multiple-word
  964.       function names. Examples: main(), count_lines(), printf()
  965.  
  966.       You'll also notice that names of Microsoft library functions that are
  967.       non-ANSI-standard (such as the graphics functions) are lowercase italic
  968.       and preceded by an underscore. Example: _getvideoconfig() (a Graphics
  969.       Library function)
  970.  
  971.    ■  In #include statements, names of header files that we create are in
  972.       double quotation marks. Example: #include "chr_graphics"
  973.  
  974.       Names of header files provided by Microsoft are in angle brackets.
  975.       Example: #include <graphics.h> (This convention affects the way in
  976.       which the compiler searches for header files on disk.)
  977.  
  978.    ■  Built-in "keywords," or reserved words, of the C language are lowercase
  979.       italic. Examples: int, do, while
  980.  
  981.    ■  Program names are uppercase roman. Example: HELLO.C
  982.  
  983.    ■  Filenames and pathnames are uppercase roman. Examples:
  984.       \LIB\GRAPHICS.LIB, SCREEN.DAT
  985.  
  986.    ■  Names of special keys are spelled as they appear on the standard IBM PC
  987.       extended keyboard. Examples: Enter (not Return), Ctrl-C, the Esc key
  988.  
  989.  Program Listings
  990.  
  991.    Program listings are set off from the text in a monospace font. Constants,
  992.    variables, and function names are capitalized as indicated in the
  993.    preceding list but are not italicized.
  994.  
  995.    In many cases, we provide a sample session that demonstrates how a program
  996.    interacts with the user. In these listings, user input is italic.
  997.  
  998.      guess────────────────────────────────────────────Run the guess.c program
  999.      What number am I thinking of?───────────────────────────Program response
  1000.      7─────────────────────────────────────────────────────────────User input
  1001.      Wrong! Try Again?
  1002.      3
  1003.      Right! You win!
  1004.  
  1005.    NOTE: The comments at the right in the sample session above are not part
  1006.    of actual program dialogue.
  1007.  
  1008.  Program Style Conventions
  1009.  
  1010.    A clear, consistent typographical style makes programs easier to read. No
  1011.    single style is universally accepted for C program listings. Ultimately,
  1012.    you fashion your own, based on your judgment and the prevailing usage. In
  1013.    some cases, more than one kind of syntax can be used. Although C itself
  1014.    doesn't care about spacing between the elements of a statement or an
  1015.    expression, we use a space between elements unless removing the space is
  1016.    clearer. Also, we use a 4-space indention for nested statements and the
  1017.    braces that enclose them.
  1018.  
  1019.    We always align braces ({ and }) vertically──a major stylistic departure
  1020.    from Kernighan and Ritchie. That is, we put
  1021.  
  1022.      function_name()
  1023.      {
  1024.      <body of function>
  1025.      }
  1026.  
  1027.    rather than
  1028.  
  1029.      function_name() {
  1030.      <body of function>
  1031.      }
  1032.  
  1033.    We believe this style enables you to read the listings and identify blocks
  1034.    of code more easily. Be warned, however, that you will find lots of C
  1035.    listings that contain the second style.
  1036.  
  1037.    Finally, because experienced C programmers often make a virtue of saying a
  1038.    lot with a little, we point out concise, idiomatic coding styles that you
  1039.    are likely to see in program listings from various sources, and we
  1040.    sometimes show two or more ways to code a statement.
  1041.  
  1042.  
  1043.  
  1044.  ────────────────────────────────────────────────────────────────────────────
  1045.  Chapter 2  Starting with QuickC
  1046.  
  1047.    You are now ready to explore the QuickC environment. In this chapter we
  1048.    describe the environment, show how to set up QuickC on your computer
  1049.    system, present an overview of the QuickC menus and dialog boxes, and help
  1050.    you create and run your first QuickC program. We also show how to get help
  1051.    from QuickC and how to fix program errors. When you finish this chapter,
  1052.    you will be comfortable with QuickC and ready to learn the C language
  1053.    itself.
  1054.  
  1055.  
  1056.  Our Book and Their Book
  1057.  
  1058.    QuickC comes with an excellent user manual that details the mechanics of
  1059.    using QuickC. It explains how to configure the system, how to use the
  1060.    menus, the meaning of the options in each menu and dialog box, and how to
  1061.    use the programs that comprise the QuickC programming tools. The QuickC
  1062.    package also includes two reference guides, the Microsoft QuickC Language
  1063.    Reference and the Microsoft QuickC Run-Time Library Reference. The first
  1064.    guide describes the rudiments of the C language; the second provides
  1065.    specific information for using each of the more than 350 C library
  1066.    routines.
  1067.  
  1068.    Our book is designed to complement the QuickC user manual by focusing on
  1069.    teaching C programming with QuickC rather than rehashing operational
  1070.    details from the manual. However, because you need to master QuickC's
  1071.    features to write effective C code, we sometimes present a brief overview
  1072.    of a procedure or subject and then refer you to the manual for a complete
  1073.    discussion. We use this approach particularly when we discuss system setup
  1074.    and configuration, for which the manual provides extensive and detailed
  1075.    guidance.
  1076.  
  1077.    We also do not discuss all the editor commands and keystrokes. You can
  1078.    learn these from the QuickC manual and through one of QuickC's excellent
  1079.    help screens. However, when we know of some useful tricks that aren't
  1080.    covered in the manual, we pass them along immediately.
  1081.  
  1082.  
  1083.  Directories and Files Used by QuickC
  1084.  
  1085.    Programming in C usually involves combining several files to eventually
  1086.    form an executable program. These files include definitions of data
  1087.    structures and functions (header files), libraries of precompiled
  1088.    functions, and your own program code. The QuickC environment uses several
  1089.    directories to organize the files into distinct groups, according to
  1090.    purpose, such as function libraries, include files, and so on. QuickC also
  1091.    uses distinctive filename extensions to identify files that are used or
  1092.    created in the compiling and linking process.
  1093.  
  1094.  Why So Many Files?
  1095.  
  1096.    If you use languages such as BASIC or some versions of Pascal, you might
  1097.    wonder why QuickC needs such an elaborate system of files and directories.
  1098.    With most versions of BASIC, for example, you need only two files: the
  1099.    BASIC interpreter program that creates and runs your programs, and the
  1100.    file that contains your BASIC program. Although the QuickC environment can
  1101.    look quite complicated by comparison, QuickC sets up most of the
  1102.    directories and files for you (especially if you have a hard disk) and
  1103.    makes it easy for you to move among all the files of a programming
  1104.    project. Nevertheless, it is important to understand how QuickC organizes
  1105.    files, especially if you need to modify the default organization to avoid
  1106.    conflicts with existing directories or for some similar reason.
  1107.  
  1108.    To explain the "environment" you work in, we must examine QuickC's
  1109.    directories and the files they contain. We use the QuickC default names in
  1110.    our discussion, because the actual name and location of the directories
  1111.    depend on how you invoke the SETUP program and whether you use a
  1112.    floppy-disk or hard-disk system.
  1113.  
  1114.  Base Directory and Subdirectories
  1115.  
  1116.    QuickC installs directories as subdirectories of a "base" directory. If
  1117.    you use QuickC by itself, the base directory usually is c:\qc; if you use
  1118.    QuickC as part of the Microsoft C 5.0 Optimizing Compiler package, the
  1119.    command is usually c:\c5\qc. Thus the actual pathname for the \BIN, or
  1120.    base, directory probably is C:\QC\BIN or C:\C5\QC\BIN.
  1121.  
  1122.    The most important QuickC directories are \BIN, \INCLUDE, and \LIB. Let's
  1123.    look at these and some optional directories that you might find useful.
  1124.  
  1125.  The \BIN Directory, Compiler, and Linker Programs
  1126.  
  1127.    The \BIN directory contains the program QC.EXE, which runs QuickC,
  1128.    provides the integrated programming environment, and lets you write,
  1129.    compile, link, and execute QuickC programs. (The name "BIN," by the way,
  1130.    is short for "binary." The \BIN directory is usually reserved for "binary
  1131.    files," or files containing executable programs.)
  1132.  
  1133.    The QuickC package actually contains two compiler programs: QC.EXE, which
  1134.    comprises the integrated programming environment with its editor, menus,
  1135.    and so on; and QCL.EXE, a much shorter program, which generates a
  1136.    "command-line" version of the QuickC compiler. (To help you distinguish
  1137.    between the programs, think of QCL as "QuickC Line-oriented.") QCL is much
  1138.    like the traditional C compiler we described in the Introduction. Rather
  1139.    than using menus and dialog boxes, you can compile a program only by going
  1140.    to the MS-DOS prompt and typing a command line with options. Another
  1141.    program in the \BIN directory, called LINK.EXE, combines your compiled
  1142.    programs and stand-alone libraries into a single executable program.
  1143.    QuickC usually performs this linking as an invisible process, although
  1144.    you can specify linker options when necessary. When you use QCL, you
  1145.    control the linker directly with a series of command-line options.
  1146.  
  1147.    QC.EXE, with its integrated programming environment, is more convenient to
  1148.    use, and we assume in most parts of this book that you will use it to
  1149.    compile and run your programs. However, the command-line compiler QCL.EXE
  1150.    is very useful for doing what are called batch compilations, for setting
  1151.    specific combinations of compile options, for compiling with alternate
  1152.    memory models, or for using an alternative program editor with QuickC. QCL
  1153.    also lets you use "make" files created with the Microsoft C Optimizing
  1154.    Compiler, version 4.0 or 5.0. (Make files are files that keep track of the
  1155.    compilation of multiple program modules. QuickC offers an easy-to-use
  1156.    alternative called "program lists," which we discuss in Chapter 6.)
  1157.  
  1158.  The \INCLUDE Directory and Header Files
  1159.  
  1160.    The "core" of C is greatly extended by compiler vendors who develop new
  1161.    sets of predefined constants, macros, data structures, and functions for
  1162.    such areas as graphics, device I/O, and DOS. Some of these are standard
  1163.    (proposed ANSI standard or UNIX System V standard) and are found in
  1164.    virtually all compilers; others are specific to the IBM PC or to
  1165.    Microsoft. The QuickC \INCLUDE directory contains many text files of both
  1166.    types. These are known as "include files" because your program can include
  1167.    definitions from one or more of these files. (They are also known as
  1168.    "header files," because their names must be specified at the beginning, or
  1169.    head, of a program.) This is also where you'll put any third-party
  1170.    libraries you obtain.
  1171.  
  1172.    Include files are not executable files or complete C source programs; they
  1173.    are ordinary text files that contain useful function definitions; they
  1174.    provide an interface between your program and the compiled code in
  1175.    stand-alone libraries. When a program references an include file, the code
  1176.    in the include file is inserted into and compiled with the code you
  1177.    actually typed in.
  1178.  
  1179.    For example, the include file stdio.h contains many of the most commonly
  1180.    used input and output functions, and graphics.h contains definitions for
  1181.    data structures and functions in the Graphics Library. The following table
  1182.    lists the standard QuickC include files. Note that include files have
  1183.    filenames with the .h extension. (Don't worry about understanding this
  1184.    comprehensive list yet; we will discuss many of them in detail as we use
  1185.    them in programs throughout the book.)
  1186.  
  1187.    QuickC Include Files
  1188. ╓┌─┌──────────┌──────────────────────────────────────────────────────────────╖
  1189.    File       Main Purpose
  1190.    ──────────────────────────────────────────────────────────────────────────
  1191.    assert.h   Debugging expressions
  1192.    conio.h    PC-specific console (keyboard) and port (device) I/O
  1193.    ctype.h    Character testing and conversion
  1194.    direct.h   Creating, removing, and changing MS-DOS directories
  1195.    dos.h      Setting and reading 8086 registers for MS-DOS calls
  1196.    errno.h    System-wide error numbers
  1197.    fcntl.h    Opening MS-DOS files with various modes
  1198.    float.h    Implementation-dependent values for advanced floating-point
  1199.    File       Main Purpose
  1200.    ──────────────────────────────────────────────────────────────────────────
  1201.   float.h    Implementation-dependent values for advanced floating-point
  1202.               operations
  1203.    graph.h    Microsoft-specific data structures and functions for monochrome
  1204.               (MDA), CGA, EGA, MCGA, and VGA graphics
  1205.    io.h       Low-level file-handling and I/O routines
  1206.    limits.h   Implementation-dependent values for sizes and ranges for data
  1207.               types, etc.
  1208.    malloc.h   Memory allocation functions
  1209.    math.h     Definitions used by math library
  1210.    memory.h   Memory manipulation routines (buffer setup, etc.)
  1211.    process.h  Used with routines that allow a program to "spawn" (run)
  1212.               another program as a "child process"
  1213.    search.h   Sorting and searching routines
  1214.    setjmp.h   Used for saving and restoring the program state during a "long
  1215.               jump" (jump to a different memory segment)
  1216.    share.h    Flags controlling sharing of a file among several users (i.e.
  1217.               on a network)
  1218.    signal.h   Values for "signals" that can be sent to interrupt handlers,
  1219.               etc.
  1220.    File       Main Purpose
  1221.    ──────────────────────────────────────────────────────────────────────────
  1222.              etc.
  1223.    stdarg.h   Allows a function to use a variable number of arguments (ANSI
  1224.               style)
  1225.    stddef.h   Miscellaneous constants, types, and variables
  1226.    stdio.h    UNIX-compatible standard I/O, such as functions to get and put
  1227.               characters to the console or a file
  1228.    stdlib.h   Definitions for miscellaneous library functions
  1229.    string.h   Definitions for string manipulation functions
  1230.    time.h     Data structures used for accessing system time
  1231.    varargs.h  Allows a function to use a variable number of arguments
  1232.               (XENIX-style)
  1233.  
  1234.    The \SYS subdirectory of \INCLUDE contains:
  1235.    locking.h  Flags for locking files (for networks)
  1236.    stat.h     Defines structure used to return status of an MS-DOS file or
  1237.               directory
  1238.    timeb.h    Types used by ftime() (used to get current time)
  1239.    types.h    Types used in values returned by functions for time and file
  1240.               status information
  1241.    File       Main Purpose
  1242.    ──────────────────────────────────────────────────────────────────────────
  1243.              status information
  1244.    utime.h    Used by utime() to update access and modification times for
  1245.               MS-DOS files
  1246.    ──────────────────────────────────────────────────────────────────────────
  1247.  
  1248.  
  1249.    In QuickC, the \INCLUDE directory also contains a subdirectory called
  1250.    \SYS. This subdirectory contains "system specific" include files for IBM
  1251.    personal computers and compatibles.
  1252.  
  1253.  The \LIB Directory and Libraries
  1254.  
  1255.    Much of C programming involves writing code that uses standard C functions
  1256.    to perform such tasks as getting a character from the keyboard or sending
  1257.    a text string to the screen. Microsoft has already compiled these
  1258.    functions for you and has placed them in files called "libraries." The
  1259.    \LIB directory contains these library files, which have either the
  1260.    filename extension .LIB or .QLB. As noted earlier, when QuickC starts, it
  1261.    includes in memory the code for a considerable number of commonly used
  1262.    functions. In addition, Microsoft provides "Quick Library" versions of
  1263.    some libraries, and you can specify that these be loaded as well to
  1264.    provide fast, in-memory access. You can also create your own custom Quick
  1265.    Libraries. Quick Libraries all have the same extension .QLB.
  1266.  
  1267.    If you examine the PACKING.LST file on the QuickC Product disk, you will
  1268.    see many libraries with similar names, such as SLIBC.LIB, SLIBFP.LIB, or
  1269.    MLIBC.LIB. Why are there so many libraries? The architecture of the Intel
  1270.    8086 and 80286 processors used by the IBM PC family requires that memory
  1271.    be divided into 64 KB segments. As a result, special instructions are
  1272.    needed to access program instructions or data that go beyond a single
  1273.    segment. The designers of C compilers address this problem by providing
  1274.    programmers with multiple memory models, each containing a different
  1275.    allocation of segments for code and data. (QuickC uses compact, small,
  1276.    medium, and large memory models. Microsoft C 5.0 adds a "huge" model.)
  1277.    Additional libraries handle floating-point (decimal) calculations: Some
  1278.    use the 8087 floating-point coprocessor chip, others use software that
  1279.    emulates its functions. Also included is an optional graphics library,
  1280.    GRAPHICS.LIB.
  1281.  
  1282.    Combined Libraries
  1283.  
  1284.    You can use libraries in two ways. When you compile, you can tell the
  1285.    linker to include specified libraries (a memory-model library, a
  1286.    floating-point library, a graphics library, and so on). Although this is
  1287.    most easily done using a "program list," it can involve a bit of
  1288.    bookkeeping. The easier way to use libraries is to use the SETUP program
  1289.    (discussed later in this chapter), to build one or more combined
  1290.    libraries. A combined library is a package that contains one library for
  1291.    the floating-point option, one standard library for the specified memory
  1292.    model, some general purpose "helper" libraries, and possibly the optional
  1293.    GRAPHICS.LIB. The advantage of creating a combined library is that QuickC
  1294.    uses it by default, so you don't have to specify library names when you
  1295.    compile and link. The \LIB directory contains any combined libraries you
  1296.    create with the setup process.
  1297.  
  1298.    Note: If you intend to write graphics programs, use SETUP to combine the
  1299.    Graphics Library with your standard library. That way, QuickC always
  1300.    includes this library in compilations.
  1301.  
  1302.  The \TMP Directory
  1303.  
  1304.    QuickC uses the \TMP directory to store temporary files created during
  1305.    compilation. Normally, QuickC removes these files when it finishes with
  1306.    them. However, if something "hangs" the system during a compile, you might
  1307.    want to check the \TMP library and delete any vestigial files.
  1308.  
  1309.  The \SAMPLE Directory
  1310.  
  1311.    If your computer has a hard disk, the QuickC SETUP program creates a
  1312.    \SAMPLE directory and stores in it several example programs. You can use
  1313.    these to practice loading, editing, compiling, and running QuickC
  1314.    programs.
  1315.  
  1316.  The \PROG or \SOURCE Directory
  1317.  
  1318.    By default, QuickC stores your programs in the current directory when you
  1319.    invoke the compiler. All other files created by the compiling and linking
  1320.    process are also stored there. You also can create directories to store
  1321.    the source code (the actual program text) for the C programs you write and
  1322.    the various files made from your program by QuickC. Although this is
  1323.    entirely optional, it makes for a more orderly directory and helps you
  1324.    organize and find your programs more easily.
  1325.  
  1326.    Whatever your current directory, compiling programs creates the following
  1327.    kinds of files, depending on the compiler and linker options you select:
  1328.  
  1329.    NAME.C──Source code for the C program name
  1330.  
  1331.    NAME.OBJ──Object code produced by the compiler for the C program name
  1332.  
  1333.    NAME.MAP──A "map" file showing the addresses used by the linker when it
  1334.    linked the program name
  1335.  
  1336.    NAME.EXE──The compiled and linked object code for the program name, which
  1337.    can be executed by typing name at the MS-DOS prompt
  1338.  
  1339.    NAME.MAK──A "make" file containing instructions that QuickC uses to
  1340.    recompile or "rebuild" your program if you change it
  1341.  
  1342.    Figure 2-1 summarizes our tour of QuickC directories and files. Without
  1343.    listing all the QuickC files, the chart shows a typical directory
  1344.    structure for QuickC on a hard disk. (The structure of directories on a
  1345.    floppy-disk system has several modifications that we will describe in the
  1346.    section "Setting Up QuickC for Floppy-Disk Systems" on page 32.)
  1347.  
  1348.                                                   C:\
  1349.                                                  ──┬──
  1350.                                                    │
  1351.                                                    │
  1352.                                                  c:\qc
  1353.                     ┌─────────────────────┬─────────────────────┬─────────────
  1354.                     │                     │                     │
  1355.                 c:\qc\bin             c:\qc\lib           c:\qc\include
  1356.           ┌─────────────────┐         ────┬────         ┌────────────────┐
  1357.           │                 │             │             │                │
  1358.    c:\qc\bin\sample       qc.exe      mlibce.lib     assert.h    c:\qc\include
  1359.    ───────┬────────      qcl.exe      slibc7.lib      bios.h     ────────┬────
  1360.           │               qc.hlp     graphics.lib    conio.h             │
  1361.        cflow.c          link.exe     graphics.qlb     (etc.)         locking.h
  1362.      new-conf.sys        lib.exe        (etc.)                        stat.h
  1363.      new-vars.bat                                                     (etc.)
  1364.  
  1365.    Figure 2-1. Typical directory structure for QuickC.
  1366.  
  1367.  From Source to Object: An Overview
  1368.  
  1369.    Now that we've surveyed the compiler, linker, include files, and
  1370.    libraries, let's see how they work together when you run a program with
  1371.    QuickC. Let's assume your program uses two include files, stdio.h and
  1372.    graph.h. When you "run" or "start" the QuickC compile/link phase, the
  1373.    compiler starts by "reading" your source code in the editor buffer. First,
  1374.    it sees the instructions to add the include files. The compiler then loads
  1375.    the stdio.h file and compiles the code found there. (The code in an
  1376.    include file is not already compiled.) Next it loads and compiles graph.h.
  1377.    These include files contain, among other things, definitions of functions
  1378.    whose compiled code resides in libraries. (The standard library for each
  1379.    memory model contains the code corresponding to standard header files such
  1380.    as stdio.h; GRAPHICS.LIB contains graph.h.) As it compiles the include
  1381.    file, the compiler notes these references to library code and passes them
  1382.    to the linker.
  1383.  
  1384.    After the compiler generates the object code for the part of the program
  1385.    you wrote yourself, the linker "resolves" all library references: It
  1386.    extracts the "modules" that contain the necessary code from the
  1387.    appropriate libraries and combines them with the rest of the code. The
  1388.    result is a compiled object program. QuickC's default creates an object
  1389.    program that runs from within the QuickC environment. This enables you to
  1390.    run the program immediately after you link it and lets you quickly test
  1391.    programs without leaving the QuickC environment. However, you can also
  1392.    create a .EXE file, or executable MS-DOS file, that you can run from the
  1393.    MS-DOS prompt. Figure 2-2 on the next page summarizes this process
  1394.    graphically.
  1395.  
  1396.                    Editor
  1397.               ┌───────────────────┐
  1398.    Program    │ #include stdio.h  │
  1399.    references │ #include graph.h  │
  1400.    include    │ ────────────      │
  1401.    files      │ ────────────      │
  1402.               │ ────────────      │
  1403.               │ ────────────      │
  1404.               └───────────────────┘
  1405.                         │
  1406.                         │     Preprocessor     ┌──────────┐
  1407.               ┌──────────────────┐            │stdio.h   │
  1408.    Included ▒ │ ───────────       │     ┌───── │ ─────    │
  1409.    source   ▒ │ ───────────       │     │      │ ─────    │
  1410.    code ─── ▒ │ ───────────       │────┘      └──────────┘
  1411.               │                   │────┐      ┌──────────┐
  1412.    Your ─── ▒ │ ───────────       │     │      │graph.h   │
  1413.    source   ▒ │ ───────────       │     └───── │ ─────    │
  1414.    code       └───────────────────┘            │ ─────    │
  1415.                         │                      └──────────┘
  1416.                         │     Compiler
  1417.               ┌──────────────────┐
  1418.    Compiled ▒ │ ---------───?     │
  1419.    library  ▒ │ ---------───?     │
  1420.    references │                   │
  1421.               │                   │
  1422.    Your ─── ▒ │ ------------      │
  1423.    compiled ▒ │ ------------      │
  1424.    code       └───────────────────┘
  1425.                         │
  1426.                         │     Linker
  1427.               ┌──────────────────┐          ┌─────────────┐
  1428.    Final      │ -----------       │          │ Libraries   │
  1429.    object     │ -----------       │─────────│ (combined   │
  1430.    program    │ -----------       │          │     or      │
  1431.    (in memory │ -----------       │          │ separate)   │
  1432.    or .EXE)   │ -----------       │          └─────────────┘
  1433.               │ -----------       │
  1434.               └───────────────────┘
  1435.  
  1436.    Figure 2-2. Compiling and linking with include files and libraries.
  1437.  
  1438.  
  1439.  Running the QuickC SETUP Program
  1440.  
  1441.    Microsoft distributes QuickC on five floppy disks. These disks and their
  1442.    hundreds of files contain the two compilers (integrated-environment and
  1443.    command-line), a full set of libraries for each memory model with a choice
  1444.    of 8087 hardware or emulation, a rich assortment of more than 30 include
  1445.    files, several utility programs, and many other goodies. The QuickC SETUP
  1446.    program lets you set up a working QuickC environment with directories
  1447.    containing only those files that you need and provides automatic access to
  1448.    directories as you specify.
  1449.  
  1450.    SETUP performs the following operations:
  1451.  
  1452.    ■  Sets up variables and commands in the MS-DOS environment that tell the
  1453.       operating system where to find all QuickC programs and files
  1454.  
  1455.    ■  Sets up a home directory for QuickC, creates the \BIN, \INCLUDE, \LIB,
  1456.       and \TMP subdirectories, and moves files from the floppy disks to these
  1457.       directories
  1458.  
  1459.    ■  Creates one or more combined libraries, depending on the memory
  1460.       model(s) and form of floating-point support you specify
  1461.  
  1462.    Note: SETUP for a floppy-disk system creates only the combined library.
  1463.    You must do the rest partly "by hand." See the section "Setting Up QuickC
  1464.    for Floppy-Disk Systems" on page 32.
  1465.  
  1466.  MS-DOS Variables and QuickC
  1467.  
  1468.    As we mentioned above, QuickC sets up and uses some MS-DOS commands and
  1469.    variables. MS-DOS uses variables (sometimes called MS-DOS "environmental"
  1470.    variables) to specify the location of system resources. When you boot an
  1471.    MS-DOS disk, the operating system calls on two files to configure the
  1472.    system: AUTOEXEC.BAT and CONFIG.SYS. Commands in these files control the
  1473.    environment that QuickC uses when you run it.
  1474.  
  1475.    When you run the SETUP program for a hard-disk system, QuickC sets
  1476.    environmental MS-DOS variables in two files: NEW-VARS.BAT and
  1477.    NEW-CONF.SYS. You can use these files as is or insert their contents into
  1478.    the AUTOEXEC.BAT and CONFIG.SYS files respectively. We recommend the
  1479.    latter procedure unless there are serious conflicts with your existing
  1480.    settings.
  1481.  
  1482.    You can use any editor (such as SideKick or EDLIN) to insert NEW-VARS.BAT
  1483.    in your AUTOEXEC.BAT file. If you have no AUTOEXEC.BAT, use MS-DOS to
  1484.    rename NEW-VARS.BAT as AUTOEXEC.BAT. The resulting file might look like
  1485.    this:
  1486.  
  1487.      setclock────────────────────────────────────────────────Set system clock
  1488.      fastopen c:────────────────────────────────────Install file access cache
  1489.      sk──────────────────────────────────────────────────────────Run SideKick
  1490.      set PATH=c:\;c:\wp;c:\c5\bin;c:\qc\bin;a:\───Combined with your old path
  1491.      set INCLUDE=c:\qc\include
  1492.      set LIB=c:\qc\lib
  1493.      set TMP=c:\qc\tmp
  1494.  
  1495.    After you insert the SET commands found in NEW-VARS.BAT, you will probably
  1496.    have two PATH= commands in your AUTOEXEC.BAT file. Combine the directories
  1497.    in the path provided by SETUP with your existing path, as shown in Figure
  1498.    2-3. You can usually use the rest of the SET commands without
  1499.    modification. (By default, MS-DOS permits only 128 bytes of space for
  1500.    storing MS-DOS variable values.) If this amount proves insufficient,
  1501.    modify it as described in the sidebar on the next page.
  1502.  
  1503.       AUTOEXEC.BAT               NEW-VARS.BAT
  1504.    ┌──────────────────┐     ┌──────────────────────┐
  1505.    │ ─────────        │     │set PATH=c:\qc\bin    │
  1506.    │ ─────────        │     │set INCLUDE...        │
  1507.    │ set PATH=c:\     │     │set LIB...            │
  1508.    │                  │     │set TMP...            │
  1509.    │                  │     │                      │
  1510.    └──────────────────┘     └──────────────────────┘
  1511.             │                          │
  1512.             └────────────┬─────────────┘
  1513.                          │
  1514.            ┌───────────────────────────┐
  1515.            │ ───────────                │
  1516.            │ ───────────                │
  1517.            │ set PATH=c:\; c:qc\bin ───┼──── Combined paths from
  1518.            │ set INCLUDE=c:\qc\include  │▒    AUTOEXEC.BAT and NEW-VARS
  1519.            │ set LIB=c:\qc\lib          │▒─── As is, from
  1520.            │ set TMP=c:\qc\tmp          │▒    NEW-VARS.BAT
  1521.            └────────────────────────────┘
  1522.  
  1523.  
  1524.        CONFIG.SYS               NEW-CONF.SYS
  1525.    ┌──────────────────┐     ┌──────────────────┐
  1526.    │ ─────────        │     │ FILES=20 ───────┼── This is larger, so
  1527.    │ ─────────        │     │ BUFFERS=10       │   replace existing FILES
  1528.    │ ─────────        │     │                  │   command
  1529.    │ FILES=10         │     │                  │
  1530.    │ BUFFERS=10       │     │                  │
  1531.    └──────────────────┘     └──────────────────┘
  1532.             │                          │
  1533.             └────────────┬─────────────┘
  1534.                          │
  1535.            ┌───────────────────────────┐
  1536.            │ ───────────                │
  1537.            │ ───────────                │
  1538.            │ ───────────                │
  1539.            │ ───────────                │
  1540.            │ FILES=20                   │
  1541.            │ BUFFERS=10                 │
  1542.            └────────────────────────────┘
  1543.  
  1544.    Figure 2-3. Editing AUTOEXEC.BAT and CONFIG.SYS.
  1545.  
  1546.    Here's what the NEW-VARS.BAT commands do. PATH is an MS-DOS command that
  1547.    specifies the directories that MS-DOS searches to execute a program.
  1548.    Whenever you tell MS-DOS to execute a program on your hard disk (such as
  1549.    the QuickC linker or library manager), it first looks in the root
  1550.    directory of drive C:, and then checks the specified directories in the
  1551.    order they are listed. The next command tells QuickC that include files
  1552.    are in the \INCLUDE subdirectory of the main QuickC directory. Similarly,
  1553.    the other variables show that libraries are found in \QC\LIB and temporary
  1554.    files are in \QC\TMP.
  1555.  
  1556.  
  1557.  Setting Up QuickC
  1558.  
  1559.    Now let's set up the QuickC working environment. The QuickC manual should
  1560.    be your source for detailed information about setup procedures and the
  1561.    various options involved, but here are "quick start" instructions that can
  1562.    simplify the process and probably save you time.
  1563.  
  1564.    The basic steps you should follow are:
  1565.  
  1566.    ■  Check the PACKING.LST file on the first QuickC distribution disk. Be
  1567.       sure you have a complete set of disks and manuals.
  1568.  
  1569.    ■  Back up the QuickC disks to floppy disks (use the MS-DOS DISKCOPY
  1570.       command to ensure you have an exact copy). Then use the backups during
  1571.       the setup process.
  1572.  
  1573.    ■  Run the SETUP program.
  1574.  
  1575.    Before you run SETUP and before you use QuickC to develop programs, be
  1576.    sure that you have at least 448 KB of free memory. QuickC may appear to
  1577.    run fine with somewhat less than 448 KB until you try to compile certain
  1578.    programs.
  1579.  
  1580.    To verify the amount of free memory, type the CHKDSK command at the MS-DOS
  1581.    prompt. To increase the amount of free memory, you might be able to change
  1582.    your AUTOEXEC.BAT file so that some memory-resident programs are not
  1583.    loaded. Then, reboot to free the memory those programs were reserving.
  1584.  
  1585.    ──────────────────────────────────────────────────────────────────────────
  1586.    Out of Environment Space?
  1587.    If your current AUTOEXEC.BAT has many SET commands or a long PATH=
  1588.    statement, you might get an MS-DOS "out of environment space" error when
  1589.    you add the QuickC variables. If this happens, expand the available
  1590.    environment space by putting this command in your CONFIG.SYS file:
  1591.  
  1592.      shell=c:\command.com /e:<size>/p
  1593.  
  1594.    For MS-DOS versions 3.0 and 3.1, size is the number of 16-byte
  1595.    "paragraphs" you want to reserve for the MS-DOS environmental variables;
  1596.    for MS-DOS versions 3.2 and later it is the actual number of bytes. The
  1597.    default size is 10 paragraphs, or 160 bytes. To set the environment to 256
  1598.    bytes, use:
  1599.  
  1600.      shell=command.com /e:16/p──────────────────────MS-DOS version 3.0 or 3.1
  1601.      shell=command.com /e:256/p───────────────────MS-DOS version 3.2 or later
  1602.  
  1603.    ──────────────────────────────────────────────────────────────────────────
  1604.  
  1605.    If you normally use memory-resident programs or a RAM disk, we recommend
  1606.    that you reboot without installing them before running SETUP. The SETUP
  1607.    program will fail without at least 385 KB of available RAM. After you set
  1608.    up the QuickC environment, experiment with memory-resident programs or RAM
  1609.    disks if you wish.
  1610.  
  1611.    Setting up a hard-disk system for QuickC differs from setting up a
  1612.    floppy-disk system. Therefore, we have developed separate walkthroughs for
  1613.    hard-disk and floppy-disk users. If you have a floppy-disk system, skip
  1614.    the next section and read "Setting Up QuickC for Floppy-Disk Systems" on
  1615.    page 32.
  1616.  
  1617.  Setting Up QuickC for Hard-Disk Systems
  1618.  
  1619.    First, put Libraries Disk #1 in drive A and type the SETUP command. The
  1620.    following line is a typical SETUP command:
  1621.  
  1622.      C>SETUP H C:\QC M EM GR
  1623.  
  1624.    The H specifies that your system has a hard disk.
  1625.  
  1626.    C:\QC is the pathname of your QuickC "base" directory. By default, QuickC
  1627.    creates the following subdirectories under the base directory:
  1628.  
  1629.    C:\QC\BIN                     Compiler, linker, and other executable
  1630.                                  programs
  1631.    C:QC\BIN\SAMPLE               Sample C programs
  1632.    C:\QC\INCLUDE                 Include (header) files
  1633.    C:\QCINCLUDE\SYS              System-specific include files
  1634.    C:\QC\LIB                     Libraries
  1635.    C:\QC\TMP                     Temporary files
  1636.    ──────────────────────────────────────────────────────────────────────────
  1637.  
  1638.    ──────────────────────────────────────────────────────────────────────────
  1639.    Are You Using both QuickC and Microsoft C 5.0?
  1640.    If you use both QuickC and the Microsoft C Optimizing Compiler 5.0, you
  1641.    can install both compilers on your hard disk without causing any conflict.
  1642.    Because both compilers use the same library and include files, and because
  1643.    both compilers use the same environment variable names to locate these
  1644.    files, you won't have to create separate directories for each compiler's
  1645.    library and include files. The only planning and organizational work
  1646.    you'll need to do is to organize the compiler files and the source code
  1647.    files.
  1648.  
  1649.    Any program that you can compile with QuickC can be recompiled without
  1650.    change by Microsoft C 5.0. QuickC's fast compiler can save time in program
  1651.    development, and then the sophisticated optimizations of Microsoft C 5.0
  1652.    can speed the execution of your program. Furthermore, QuickC provides
  1653.    syntax checking for features unique to Microsoft C 5.0. If a program is
  1654.    syntactically correct but uses features of the larger compiler (the huge
  1655.    memory model, for instance), QuickC simply ignores those features when you
  1656.    run the program.
  1657.    ──────────────────────────────────────────────────────────────────────────
  1658.  
  1659.    Note that SETUP overwrites any file with the same name as a QuickC
  1660.    distribution file. If you follow our recommendation to create a new
  1661.    directory for QuickC, \QC, in your root directory, you eliminate this
  1662.    problem.
  1663.  
  1664.    The M option in the SETUP command lets you use the "medium memory model"
  1665.    to compile programs. Note that you can specify other or additional memory
  1666.    models when you run SETUP. (See the manual for details.) Although we will
  1667.    explain all memory models in later chapters, we use the medium model
  1668.    throughout this book because it is the only supported model for programs
  1669.    compiled in the QuickC environment. (If you use the command-line compiler,
  1670.    which assumes a small model, you might want to create a small model
  1671.    combined library that conveniently collects all of the functions you
  1672.    normally use with QCL. You can create new combined libraries without
  1673.    running SETUP again.)
  1674.  
  1675.    The EM in the SETUP command specifies that all floating-point arithmetic
  1676.    be performed by software "emulation" of the 8087 math coprocessor chip. If
  1677.    you have an 8087/80287/80387 chip in your PC, you might prefer to use the
  1678.    87 option which directs floating-point calculations to the coprocessor.
  1679.    When QuickC builds your core library, it uses this specification to select
  1680.    the appropriate floating-point library. Note, however, that any .EXE file
  1681.    you create with the 87 option will not run on machines without a math
  1682.    coprocessor. If you are concerned about portability, use EM when you set
  1683.    up QuickC. The QuickC environment uses only the emulator; if a coprocessor
  1684.    is present the emulator detects that fact and uses it.
  1685.  
  1686.    Finally, the GR option specifies that QuickC's Graphics Library functions
  1687.    be included in your combined libraries. We recommend that you use this
  1688.    option so that you can run the graphics programs in this book without
  1689.    specifying the GRAPHICS.LIB every time you link. (Of course, if your
  1690.    computer has only a monochrome text display, you should not use this
  1691.    option. This installation will proceed, but programs that you subsequently
  1692.    create that use graphics will not work.)
  1693.  
  1694.    After you enter the initial SETUP command, the program asks you if you
  1695.    want to delete the "library subcomponents," or parts of libraries that are
  1696.    not needed for the configuration you chose. Unless you plan to use memory
  1697.    models or floating-point packages other than those specified in the SETUP
  1698.    command, you can save a lot of disk space by typing y at this prompt. The
  1699.    SETUP program then prompts you to insert the appropriate distribution
  1700.    disks in drive A.
  1701.  
  1702.    Without any further input, SETUP creates the QuickC directories, places
  1703.    header files in the \INCLUDE subdirectory, creates a "combined library"
  1704.    for each specified memory model using the floating-point option you
  1705.    selected, and places the combined libraries in the \LIB subdirectory. This
  1706.    library is called your "standard library" because it contains compiled
  1707.    versions of all the standard C routines (with specified options, such as
  1708.    graphics).
  1709.  
  1710.    If you have already edited your MS-DOS AUTOEXEC.BAT and CONFIG.SYS files,
  1711.    your QuickC environment is now set up and ready to use. Please skip the
  1712.    next section, which is for floppy-disk users.
  1713.  
  1714.  Setting Up QuickC for Floppy-Disk Systems
  1715.  
  1716.    Setting up QuickC for a floppy-disk system differs from hard-disk setup in
  1717.    two principal ways: First, the floppy-disk setup does not create the
  1718.    NEW-VARS.BAT and NEW-CONF.SYS files, so you have to set your own MS-DOS
  1719.    variables; second, because you have only 720 KB of disk space on two
  1720.    floppy drives, you must be more choosy about which files to install. (If
  1721.    you have two 1.4 MB 3.5-inch disk drives, as found in the IBM PS/2 line,
  1722.    you need not be so constrained.)
  1723.  
  1724.    As explained in the Microsoft QuickC Programmer's Guide, you need to
  1725.    format at least two floppy disks: one disk for each memory model and one
  1726.    "scratch" disk to hold temporary files created during the setup process.
  1727.  
  1728.    Insert your copy of the Libraries Disk #1 in drive A and a blank formatted
  1729.    disk in drive B. You are now ready to run SETUP. We recommend that you
  1730.    type the following command:
  1731.  
  1732.      setup f b: m em gr
  1733.  
  1734.    This specifies a floppy-disk setup that places the combined library on
  1735.    drive B. The M option lets you use the "medium memory model" to compile
  1736.    programs. Although we will explain all memory models in later chapters, we
  1737.    use the medium model throughout this book because it is the only model
  1738.    supported for programs compiled in the QuickC environment.
  1739.  
  1740.    The EM in the setup command specifies that all floating-point arithmetic
  1741.    be performed by software "emulation" of the 8087 math coprocessor chip. If
  1742.    you have an 8087/80287/80387 chip in your PC, you might want to use the 87
  1743.    option instead. When QuickC builds your core library, it uses this
  1744.    specification to select the appropriate floating-point library. Note,
  1745.    however, that any .EXE file you create with the 87 option will not run on
  1746.    machines without a math coprocessor. If you are concerned about
  1747.    portability, use EM when you set up QuickC.
  1748.  
  1749.    Finally, the GR option specifies that QuickC's Graphics Library functions
  1750.    be included in your combined libraries. We recommend that you use this
  1751.    option so that you can run the graphics programs in this book without
  1752.    specifying the library GRAPHICS.LIB every time you link. (Of course, if
  1753.    your computer has only a monochrome text display, you should not use this
  1754.    option. The installation will proceed, but programs that you subsequently
  1755.    create that use graphics will not work.)
  1756.  
  1757.    As it builds the QuickC combined library, SETUP prompts you for the
  1758.    necessary disks. The setup process on floppy disks can take as long as 15
  1759.    minutes, so don't be alarmed at the seemingly interminable grinding of the
  1760.    disk drives. To create library disks for additional memory models or other
  1761.    floating-point options, run the SETUP program again.
  1762.  
  1763.    Setting Up the MS-DOS Environment
  1764.  
  1765.    Because the floppy-disk setup procedure does not create the NEW-VARS.BAT
  1766.    and NEW-CONFIG.SYS files, you need to set the MS-DOS variables yourself.
  1767.    To do this, add the following two variables to your AUTOEXEC.BAT file:
  1768.  
  1769.      set include=a:\include
  1770.      set lib=b:
  1771.  
  1772.    (If you do not have an AUTOEXEC.BAT, create one and type in the preceding
  1773.    variables.)
  1774.  
  1775.    This tells QuickC to look for include files in A:\INCLUDE and for
  1776.    libraries on drive B.
  1777.  
  1778.    Also, edit your CONFIG.SYS so that it assigns values of at least:
  1779.  
  1780.      files=15
  1781.      buffers=20
  1782.  
  1783.    Note that you will have to reboot your system if you are planning on
  1784.    running QuickC right away, so the new setting will take effect. Figure
  1785.    2-4 summarizes how QuickC is set up and run on floppy disks.
  1786.  
  1787.              Drive A                      Drive B
  1788.       ┌──────────────────┐          ┌──────────────────┐
  1789.       │ QC.EXE           │          │ MLIBCE.LIB       │ ───── Libraries
  1790.       │                  │          │                  │
  1791.       │                  │          │ QCHELLO.C        │ ▒──── Your source
  1792.       │                  │ ────── │ CIRCLE.C         │ ▒     files
  1793.       │                  │          │                  │
  1794.       │                  │          │ QCHELLO.EXE      │ ▒──── Temporary
  1795.    ┌──│                  ──┐       │ ────────         │ ▒     and object
  1796.    │  └──────────────────┘  │       └──────────────────┘       files
  1797.    │                        │
  1798.    │  Swapped after startup │
  1799.    │  ┌──────────────────┐  │
  1800.    └──                  ├──┘
  1801.       │ \INCLUDE         │───── Include files
  1802.       │                  │
  1803.       │ QC.OVL           │───── Overlay file
  1804.       │                  │
  1805.       │ QC.HLP           │───── Help screens
  1806.       │                  │
  1807.       │ LINK.EXE         │───── Linker
  1808.       └──────────────────┘
  1809.  
  1810.    Figure 2-4. Floppy-disk setup for QuickC.
  1811.  
  1812.    Differences for Floppy-Disk Users
  1813.  
  1814.    The examples in this book assume you have a hard disk with QuickC residing
  1815.    in a directory on drive C. Floppy-disk users can use these examples by
  1816.    substituting references as follows:
  1817.  
  1818.    Hard Disk                            Floppy Disks
  1819.    ──────────────────────────────────────────────────────────────────────────
  1820.    c:\qc\bin                            a:
  1821.    c:\qc\include                        a:\include
  1822.    c:\qc\lib                            b:
  1823.    ──────────────────────────────────────────────────────────────────────────
  1824.  
  1825.  
  1826.  Starting QuickC
  1827.  
  1828.    Now we're ready to start using QuickC.
  1829.  
  1830.    If you have QuickC on a hard disk and have correctly included \QC\BIN in
  1831.    the PATH variable in the AUTOEXEC.BAT file, run QuickC by typing
  1832.  
  1833.      qc
  1834.  
  1835.    at the C> prompt. (If you haven't changed your PATH variable to include
  1836.    \QC\BIN, you must change to this directory before you can run QuickC.)
  1837.  
  1838.    To use QuickC on a floppy-disk system:
  1839.  
  1840.    1.  Boot your system with an MS-DOS disk that contains the new QuickC
  1841.        AUTOEXEC.BAT and CONFIG.SYS files
  1842.  
  1843.    2.  Put your copy of the Product Disk in drive A
  1844.  
  1845.    3.  Start QuickC by typing qc at the A> prompt
  1846.  
  1847.    4.  When the QuickC screen appears, replace the disk in drive A with a
  1848.        copy of the Work Disk
  1849.  
  1850.    Drive A now contains an "overlay" file (this lets QuickC access files
  1851.    without further disk swapping), the Help menus, the linker, and the
  1852.    \INCLUDE directory.
  1853.  
  1854.  Improving the QuickC Display
  1855.  
  1856.    When you type qc on the MS-DOS command line, QuickC assumes you have a
  1857.    color monitor. If you have a monochrome monitor, this default setting can
  1858.    reduce the contrast of the characters on your screen and make them hard to
  1859.    read. To fix this, exit QuickC by selecting Exit from the File menu, and
  1860.    start QuickC in its "black-and-white" mode by typing qc /b.
  1861.  
  1862.    If you use a computer that refreshes the screen at a faster rate than
  1863.    standard ATs, such as some higher-performance models of COMPAQ computers,
  1864.    you can speed screen displays by using the command qc /g to start QuickC.
  1865.  
  1866.    If your computer has an EGA card, you can set the screen to display 43
  1867.    lines, instead of the normal 25, by starting QuickC with the qc /h
  1868.    command. Note that unless you have a high-resolution monitor, text can be
  1869.    very hard to read in this mode.
  1870.  
  1871.    You can combine these modes by separating them with a space. For example,
  1872.    qc /b /g starts QuickC in monochrome mode and accelerates the screen
  1873.    refresh rate. You can also put the qc command and options in a batch file
  1874.    so you don't have to type them each time you start.
  1875.  
  1876.  Overview of the QuickC Screen
  1877.  
  1878.    If you've used menu-based integrated programming environments such as
  1879.    Turbo Pascal and Microsoft QuickBASIC before, the QuickC screen should
  1880.    look familiar. (See Figure 2-5.)
  1881.  
  1882.    ┌────────────────────────────────────────────────────────────────────────┐
  1883.    │ Figure 2-5 can be found on p.35 of the printed version of the book.    │
  1884.    └────────────────────────────────────────────────────────────────────────┘
  1885.  
  1886.    Figure 2-5. QuickC startup screen.
  1887.  
  1888.    Notice the following screen elements:
  1889.  
  1890.    ■  The menu bar across the top of the screen lists the following options:
  1891.       File, Edit, View, Search, Run, Debug, Calls, and Help.
  1892.  
  1893.    ■  The "title bar" displays the name of the program currently loaded into
  1894.       the editor. (Because we haven't written a program yet, it now reads
  1895.       untitled.c.)
  1896.  
  1897.    ■  The main area of the screen, now blank, is the workspace for your
  1898.       program.
  1899.  
  1900.    ■  Two "scroll bars," a vertical one on the right side of the screen and a
  1901.       horizontal one near the bottom of the screen, let you use an optional
  1902.       mouse to scroll text up and down or side to side.
  1903.  
  1904.    ■  The status line at the bottom of the screen keeps track of the name of
  1905.       the current program, the status of your program, and the current cursor
  1906.       position. Note the Context section of the line. QuickC uses this area
  1907.       to remind you of your current stage of program development. Because no
  1908.       program is loaded, it reads <Program not compiled>.
  1909.  
  1910.  Making Selections
  1911.  
  1912.    The Microsoft QuickC Programmer's Guide gives exhaustive information on
  1913.    how to select menu items, move among parts of a dialog box, accept or
  1914.    cancel selections, and so on. Following is a brief and convenient summary
  1915.    of this material, explaining both keyboard and mouse commands. The QuickC
  1916.    manual also discusses several alternative selection methods you might want
  1917.    to explore. To save space and time we show only one method each for mouse
  1918.    and keyboard.
  1919.  
  1920.    Keyboard Shortcuts ("Hot Keys")
  1921.  
  1922.    QuickC lets you select certain frequently used menu items without opening
  1923.    the menu first. These "shortcut" or "hot" keys are particularly handy when
  1924.    you use the editor. Here are some of the most useful ones:
  1925.  
  1926.    Key                      Function
  1927.    ──────────────────────────────────────────────────────────────────────────
  1928.    F2                       Open last file used
  1929.    Alt-Backspace            Undo last edit
  1930.    Shift-Del                Cut marked text
  1931.    Ctrl-Ins                 Copy marked text
  1932.    Del                      Clear editor buffer
  1933.    F4                       View output screen
  1934.    Ctrl-/                   Search for selected text
  1935.    F3                       Repeat last search
  1936.    Shift-F3                 Find next error
  1937.    Shift-F4                 Find previous error
  1938.    Shift-F5                 Start program
  1939.    F5                       Continue stopped program
  1940.    ──────────────────────────────────────────────────────────────────────────
  1941.  
  1942.    (The Microsoft QuickC Programmer's Guide contains additional
  1943.    combinations.)
  1944.  
  1945.    The Mouse
  1946.  
  1947.    Although you can select all QuickC functions from the keyboard, you might
  1948.    want to try using a mouse if you have one. With a mouse, you need only to
  1949.    point and click to select anything on the screen. Because you don't have
  1950.    to learn all the keystroke combinations for making selections or using the
  1951.    editor, you can concentrate on learning C right away. Further, the mouse
  1952.    makes it easier to select items from a dialog box. You might want to learn
  1953.    both the mouse and keyboard methods and see which one best suits you. Or
  1954.    you can mix them, using the keyboard for making menu selections and the
  1955.    mouse for making selections in dialog boxes, for example.
  1956.  
  1957.    You must use a Microsoft mouse or a compatible mouse (such as the IBM PS/2
  1958.    mouse or the Logitech serial mouse) with QuickC. Before you can use any
  1959.    mouse with QuickC, however, you must install a "mouse driver," either in
  1960.    your CONFIG.SYS file or as a .COM file in your AUTOEXEC.BAT. (See your
  1961.    mouse documentation for instructions.) The driver is the software that
  1962.    lets QuickC recognize the mouse and respond to its movements as though
  1963.    they were commands. If you currently use a mouse for other programs, your
  1964.    system is probably set up correctly already.
  1965.  
  1966.  Writing a Program
  1967.  
  1968.    Now we're ready to write a simple C program, which we will call QCHELLO.C.
  1969.    First, select the File menu. If you have a mouse, move the mouse until the
  1970.    pointer on the screen is on the File menu, and click the left button. This
  1971.    reveals the menu, as shown in Figure 2-6. Now, move the pointer to the
  1972.    Open option, and click the left button again. To reveal the File menu
  1973.    using the keyboard, press the Alt key and then press the f key. Notice
  1974.    that each menu item has a highlighted letter (often, but not always, the
  1975.    first letter in the word or phrase). Type this letter to select the menu
  1976.    item. Select the Open option by typing o.
  1977.  
  1978.    Note the Exit option in the File menu. Choose this option when you're
  1979.    ready to end your QuickC session. If you select Exit after changing your
  1980.    current program, QuickC first asks if you want to save the changed
  1981.    program. When you exit QuickC, you return to the MS-DOS prompt.
  1982.  
  1983.    ┌────────────────────────────────────────────────────────────────────────┐
  1984.    │ Figure 2-6 can be found on p.37 of the printed version of the book.    │
  1985.    └────────────────────────────────────────────────────────────────────────┘
  1986.  
  1987.    Figure 2-6. QuickC File menu.
  1988.  
  1989.  Selecting a File
  1990.  
  1991.    When you select the Open option on the File menu, a dialog box appears.
  1992.    (See Figure 2-7.) QuickC uses dialog boxes to obtain the information it
  1993.    needs to carry out your request.
  1994.  
  1995.    You can select a file from a dialog box in two ways. Notice the long
  1996.    rectangle near the top of the dialog box with a cursor blinking in it.
  1997.    Typing a filename in this rectangle is the most straightforward method of
  1998.    selecting a file. Below is a larger rectangle with some names in it. This
  1999.    box lists the contents of the current directory. Names in ALL CAPS are
  2000.    directories; names in lowercase are files. (The contents of the current
  2001.    directory in your system may vary from those in the example.)
  2002.  
  2003.    To make a selection from a dialog box:
  2004.  
  2005.    ■  With a mouse, move the pointer to the item you want. Click the left
  2006.       button to select the item.
  2007.  
  2008.    ■  With the keyboard, use the Tab or back-Tab (shifted tab) key to move
  2009.       from one section of the dialog box to another. Press Enter to select
  2010.       the item.
  2011.  
  2012.    When you select a directory, QuickC lists all files and subdirectories in
  2013.    that directory. Each list you display also has a .. entry. Selecting this
  2014.    entry moves you back to the parent directory of the directory shown. Thus
  2015.    you can easily browse through the file system with only a few keystrokes.
  2016.  
  2017.    With the back-Tab or your mouse, move the cursor to the File Name text
  2018.    box. Type qchello.c and then press the Enter key. Another small dialog box
  2019.    appears to inform you that this file does not exist. Accept the default of
  2020.    Yes to create it.
  2021.  
  2022.    ┌────────────────────────────────────────────────────────────────────────┐
  2023.    │ Figure 2-7 can be found on p.38 of the printed version of the book.    │
  2024.    └────────────────────────────────────────────────────────────────────────┘
  2025.  
  2026.    Figure 2-7. File "Open" dialog box.
  2027.  
  2028.  Typing in the Program
  2029.  
  2030.    You are now ready to type in a program. QuickC's default mode is in fact
  2031.    "edit mode," and the large area of the screen with the cursor in it is the
  2032.    Edit window. As you type the listing below, use the arrow keys to move the
  2033.    cursor, the Backspace key to make corrections, and press Enter at the end
  2034.    of each line. After you enter the text shown in Listing 2-1, your screen
  2035.    should look like Figure 2-8.
  2036.  
  2037.    ──────────────────────────────────────────────────────────────────────────
  2038.    /* qchello.c -- a simple C program */
  2039.  
  2040.    main()
  2041.    {
  2042.        printf("Hello, and welcome to QuickC!\n");
  2043.    }
  2044.    ──────────────────────────────────────────────────────────────────────────
  2045.  
  2046.    Listing 2-1.  The QCHELLO.C program.
  2047.  
  2048.  What Does It Do?
  2049.  
  2050.    Although we won't look at the structure and anatomy of C until the next
  2051.    chapter, this program gives you a hint of C style. The first line
  2052.    (enclosed by the characters /* and */) is a comment that briefly describes
  2053.    the program. It is optional but highly recommended. The word main()
  2054.    indicates the beginning of the main function or related group of
  2055.    statements in the program. (Most C programs have many functions in
  2056.    addition to the main one.) As the name suggests, printf() prints the
  2057.    string in the parentheses that follow. The braces, { and }, set off the
  2058.    group of statements (only one in this case) that make up the main
  2059.    function. So, it's easy to see what this program does: It prints Hello,
  2060.    and welcome to QuickC! on the screen. (The \n at the end of the string
  2061.    simply moves the cursor to the beginning of a new line.)
  2062.  
  2063.    ┌────────────────────────────────────────────────────────────────────────┐
  2064.    │ Figure 2-8 can be found on p.39 of the printed version of the book.    │
  2065.    └────────────────────────────────────────────────────────────────────────┘
  2066.  
  2067.    Figure 2-8. QCHELLO.C as typed into the edit window.
  2068.  
  2069.  Running QCHELLO.C
  2070.  
  2071.    Running the program is simple. Select the Run menu. As you probably know,
  2072.    before we can run our program we must first compile and link it. The Start
  2073.    option in the Run menu executes all of these steps for you.
  2074.  
  2075.    When you select Start, a dialog box tells you that the program has been
  2076.    "modified" and asks if you want to "rebuild" (compile and link) it.
  2077.    Whenever you change a program, you must recompile. QuickC treats this new
  2078.    program as a changed program, so press Enter or click on Yes to compile
  2079.    it.
  2080.  
  2081.    Before you can blink an eye, QuickC compiles and runs the program. QuickC
  2082.    is fast, as you will see when you write longer programs, and because this
  2083.    little program doesn't use any include files or libraries, it compiles
  2084.    instantaneously.
  2085.  
  2086.    After the program runs, the screen displays the following:
  2087.  
  2088.      Hello, and welcome to QuickC!
  2089.      Program returned (13). Press any key
  2090.  
  2091.    You are now looking at the "output screen." QuickC keeps track of the
  2092.    output screen, which always holds the results of your programs, so you can
  2093.    switch back and forth between it and the QuickC environment screen. Press
  2094.    any key to return to QuickC. For now, don't worry about the return value
  2095.    mentioned in the second output line.
  2096.  
  2097.  Saving the Program
  2098.  
  2099.    To save this program to disk for future reference, open the File menu
  2100.    again. Notice the Save and Save As options. Select Save to write the
  2101.    program to disk. If you want to save the program with a new name, select
  2102.    Save As. When the dialog box appears, type the new name and press Enter.
  2103.    (You might try QCHELLO2.C.)
  2104.  
  2105.  Compiling to a .EXE File
  2106.  
  2107.    QuickC compiles programs to memory by default. Because it is fast, this is
  2108.    often the best way to compile while developing a new program. However, the
  2109.    compiled version of a program compiled to memory disappears when you
  2110.    compile another program or quit QuickC. Eventually you need a compiled
  2111.    version of the program on disk, so you can run it without recompiling.
  2112.    Also, you eventually want to create programs that a user can run directly
  2113.    from MS-DOS without QuickC available. To produce an MS-DOS-executable
  2114.    file, we need to "compile to .EXE."
  2115.  
  2116.    Select the Run menu. Now select the Compile item. The dialog box shown in
  2117.    Figure 2-9 appears.
  2118.  
  2119.    This large dialog box lets you select many options. (We will explain the
  2120.    options later as we use them.) Notice the center column, Output Options.
  2121.    The small black dot in the parentheses next to the word Memory indicates
  2122.    that it is the currently selected output option. We want to change this
  2123.    option to Exe. If you have a mouse, move the pointer between the
  2124.    parentheses next to Exe and click. From the keyboard, you can move the
  2125.    cursor to this position with the Tab and Down Arrow keys and press Enter.
  2126.    But there's an even faster way. Note that the letter x in Exe is
  2127.    highlighted. To select this item, you need only type the letter x.
  2128.  
  2129.    Now you can compile the program. Note the four small rectangles at the
  2130.    bottom of the dialog box. The first one, Build Program, has a double
  2131.    border, which signifies that it is the default. You can select it in one
  2132.    of three ways: tab to it and press Enter, click on it with a mouse, or
  2133.    type b.
  2134.  
  2135.    The Compile box displays the numbers of the program lines being processed
  2136.    as the program is compiled. Because this program is being compiled as a
  2137.    stand-alone .EXE file, it must be linked to various disk files.
  2138.  
  2139.    Very quickly, the program returns you to the familiar QuickC environment
  2140.    screen. Note that the program didn't run and produce output as it did when
  2141.    you compiled it earlier. This compile created a .EXE file, and these
  2142.    executable files cannot be run directly from QuickC. However, QuickC
  2143.    provides an easy way to run it.
  2144.  
  2145.    ┌────────────────────────────────────────────────────────────────────────┐
  2146.    │ Figure 2-9 can be found on p.41 of the printed version of the book.    │
  2147.    └────────────────────────────────────────────────────────────────────────┘
  2148.  
  2149.    Figure 2-9. Compile dialog box.
  2150.  
  2151.  Escaping to MS-DOS
  2152.  
  2153.    At the File menu, select the item DOS Shell. This option switches the
  2154.    display to the output screen where the MS-DOS sign-on message and prompt
  2155.    appear. You can now run any MS-DOS command, as well as most programs and
  2156.    batch files.
  2157.  
  2158.    To run QCHELLO.EXE, type:
  2159.  
  2160.      C>qchello
  2161.  
  2162.    The screen displays the expected output. (No instruction to press a key
  2163.    appears, of course, because QuickC is not running. We are at the MS-DOS
  2164.    level.)
  2165.  
  2166.    Now type:
  2167.  
  2168.      C>exit
  2169.  
  2170.    to return to QuickC exactly where you left off.
  2171.  
  2172.  
  2173.  Getting Help
  2174.  
  2175.    We will not cover every feature of QuickC in this book so that we can
  2176.    devote more time to C itself. Although we occasionally refer you to the
  2177.    QuickC manual, there's another source of help as near as your keyboard──
  2178.    the QuickC Help facility. In fact, you can select from three levels of
  2179.    help: general, topic, and keyword.
  2180.  
  2181.  General Help Screens
  2182.  
  2183.    Press the F1 key to select the General help option (or use the mouse to
  2184.    make the selection). The first screen you see is shown in Figure 2-10.
  2185.    Notice that it displays a summary of some editor commands as well as some
  2186.    other frequently used commands. The small rectangles at the bottom of the
  2187.    dialog box let you select the Next or Previous help screen. Next, with its
  2188.    double border, is the default. Press Enter or click on the box with the
  2189.    mouse to display the next screen. Don't try to memorize or even understand
  2190.    these screens. Just get an idea of the general information that is
  2191.    available for future reference.
  2192.  
  2193.  Topic Help
  2194.  
  2195.    If you select Topic help, you can page through lists of topics until you
  2196.    find the information you are looking for. (See Figure 2-11.) For example,
  2197.    you could select "preprocessor directives," and then select the particular
  2198.    directive for which you want help. To choose Topic help directly from the
  2199.    editor window, press Shift-F1.
  2200.  
  2201.    ┌────────────────────────────────────────────────────────────────────────┐
  2202.    │ Figure 2-10 can be found on p.43 of the printed version of the book.   │
  2203.    └────────────────────────────────────────────────────────────────────────┘
  2204.  
  2205.    Figure 2-10. A QuickC help box.
  2206.  
  2207.    ┌────────────────────────────────────────────────────────────────────────┐
  2208.    │ Figure 2-11 can be found on p.43 of the printed version of the book.   │
  2209.    └────────────────────────────────────────────────────────────────────────┘
  2210.  
  2211.    Figure 2-11. Topic help.
  2212.  
  2213.  Keyword Help
  2214.  
  2215.    Return to the editor window, and move the cursor to the word printf.
  2216.    Suppose you are writing a program and you are not sure how this C function
  2217.    works. By pressing Shift-F1, you can retrieve information about the C
  2218.    keyword or standard function currently marked by the cursor. (See Figure
  2219.    2-12.)
  2220.  
  2221.    ┌────────────────────────────────────────────────────────────────────────┐
  2222.    │ Figure 2-12 can be found on p.44 of the printed version of the book.   │
  2223.    └────────────────────────────────────────────────────────────────────────┘
  2224.  
  2225.    Figure 2-12. Keyword Help screen.
  2226.  
  2227.  
  2228.  Fixing Errors
  2229.  
  2230.    The last section of this chapter discusses how to fix errors in a C
  2231.    program. The QCHELLO.C program should still be in the Edit window. Let's
  2232.    make some changes in the program so we can practice fixing errors.
  2233.    (Normally, we programmers don't have to manufacture errors; we run into
  2234.    enough of them on our own!)
  2235.  
  2236.    Use the arrow keys or the mouse to move the cursor to the word printf.
  2237.    Change it to primtf. Next, go to the end of the line and delete the
  2238.    semicolon.
  2239.  
  2240.    Now select Run and Start to compile and run the program. QuickC soon
  2241.    displays a rectangular error window at the bottom of the screen as shown
  2242.    in Figure 2-13.
  2243.  
  2244.    The error message tells you that a semicolon is missing before the closing
  2245.    }. Notice on your screen that the cursor in the edit window is on the
  2246.    character immediately following the error. This makes it easy to find and
  2247.    correct the error. (In this case, the next character is on the next line,
  2248.    however, so you have to move the cursor to the end of the preceding line
  2249.    to insert the semicolon after the ).
  2250.  
  2251.    ┌────────────────────────────────────────────────────────────────────────┐
  2252.    │ Figure 2-13 can be found on p.45 of the printed version of the book.   │
  2253.    └────────────────────────────────────────────────────────────────────────┘
  2254.  
  2255.    Figure 2-13. Error window.
  2256.  
  2257.    Now run the program again. The next error message, `primtf' : unresolved
  2258.    external, is less clear than the preceding one. Simply stated, it means
  2259.    that primtf is not one of the standard QuickC functions. When you change
  2260.    the m back to an n, the program again runs correctly.
  2261.  
  2262.  
  2263.  Preparing for the Next Chapter
  2264.  
  2265.    In the next chapter we begin our study of the elements of the C language.
  2266.    Although we discuss additional QuickC features as needed, we will not
  2267.    concentrate on using the QuickC environment. So now is a good time to get
  2268.    comfortable with your new QuickC environment.
  2269.  
  2270.    We recommend that you try the following:
  2271.  
  2272.    ■  Save QCHELLO.C under another name, and then use the Open option in the
  2273.       File menu to load it into the editor.
  2274.  
  2275.    ■  Practice compiling and running the program to memory and to a .EXE
  2276.       file.
  2277.  
  2278.    ■  Use the DOS Shell item of the File menu to exit to MS-DOS, run a .EXE
  2279.       program, and then use Exit to return to QuickC.
  2280.  
  2281.    ■  Make some errors in QCHELLO.C and try running the program. Observe the
  2282.       error messages, fix the errors, and run the program again. What happens
  2283.       if the last } is missing? What happens if you change the word "Hello"
  2284.       to "Hi"?
  2285.  
  2286.    ■  Read Chapter 6 in the Microsoft QuickC Programmer's Guide to learn
  2287.       about the advanced features of the editor. We suggest you study them
  2288.       when you want a break from reading this book. None of these editor
  2289.       features are needed for you to use this book, but they make it easier
  2290.       to enter and modify long programs. Remember to use the Help screen to
  2291.       remind you of common editing functions.
  2292.  
  2293.  
  2294.  
  2295.  ────────────────────────────────────────────────────────────────────────────
  2296.  PART 2  CORE OF C
  2297.  ────────────────────────────────────────────────────────────────────────────
  2298.  
  2299.  
  2300.  
  2301.  ────────────────────────────────────────────────────────────────────────────
  2302.  Chapter 3  C Fundamentals
  2303.  
  2304.    Now that you feel comfortable in the QuickC environment, we can turn our
  2305.    attention to the fundamentals of C. First, let's look at the basic
  2306.    elements of a C program.
  2307.  
  2308.  
  2309.  Basic Elements of C Programs
  2310.  
  2311.    The simplest possible C program, which we call TINY.C, is shown in Listing
  2312.    3-1 on the following page. Type this program into the QuickC editor; then
  2313.    run it with the Start option from the Run menu. (We recommend that you
  2314.    enter and run all sample programs in this book──we believe this will help
  2315.    you better understand and remember the concepts we discuss.)
  2316.  
  2317.    As you probably suspected, this program doesn't actually do anything when
  2318.    you run it. QuickC generated the message Program returned 1. Press any
  2319.    key, but the program produced no output at all. The main() function
  2320.    returns the value 1, in this sample, to the operating system. (The actual
  2321.    value might be different on your machine.) This value is significant only
  2322.    if you control it deliberately, as you might want to do when you call a C
  2323.    program from another program, for example.
  2324.  
  2325.    ──────────────────────────────────────────────────────────────────────────
  2326.    /* tiny.c -- the smallest possible C */
  2327.    /*           program with comments   */
  2328.  
  2329.    main() /* function name and argument list */
  2330.    {
  2331.           /* function definition in braces */
  2332.    }
  2333.    ──────────────────────────────────────────────────────────────────────────
  2334.  
  2335.    Listing 3-1.  The TINY.C program.
  2336.  
  2337.  A Program Consists of Function Definitions
  2338.  
  2339.    As simple as it is, however, this program illustrates a basic element of
  2340.    C──A C program is essentially a set of function definitions. A function
  2341.    contains statements (instructions) that the program "calls" to perform
  2342.    specific tasks. A function definition must contain at least the following
  2343.    elements:
  2344.  
  2345.    ■  The function name
  2346.  
  2347.    ■  An "argument list" enclosed in parentheses
  2348.  
  2349.    ■  A group of statements that define the function
  2350.  
  2351.    In practice, and especially with programs written in the new ANSI C
  2352.    standard, function definitions can be more complicated than this. But this
  2353.    simplest definition is all we need until we look at functions in more
  2354.    detail in Chapter 6.
  2355.  
  2356.    TINY.C has only one function, main(). The argument list, which follows the
  2357.    function and is enclosed in parentheses, often contains "parameters," or
  2358.    formal descriptions of information, that the function uses when it is
  2359.    called (executed). Although an argument list can also be empty, as it is
  2360.    in main(), the parentheses are still required. Because main() contains no
  2361.    function definition statements, the program does nothing when you run it.
  2362.  
  2363.    The QCHELLO.C program we developed in the last chapter is an even better
  2364.    example of the elements of a C program. Figure 3-1 identifies the parts
  2365.    of QCHELLO.C.
  2366.  
  2367.               Function name               Argument list
  2368.                     │                         │
  2369.                     └──────────┐   ┌──────────┘
  2370.                              main ( )
  2371.                            ┌─
  2372.                            │ {
  2373.    Function definition  ───┤     printf("Hello, and welcome to QuickC!\n");
  2374.    enclosed in braces      │ }   │                                        │
  2375.                            └─    └──────────────────┬─────────────────────┘
  2376.                                                     │
  2377.                                       Statement in function definition
  2378.  
  2379.    Figure 3-1. Parts of the QCHELLO.C program.
  2380.  
  2381.  A Function Definition Consists of a Group of Statements
  2382.  
  2383.    In C, a pair of braces ({ and }) encloses a group of statements. Notice
  2384.    the part of the program between the braces in Figure 3-1. The statement
  2385.    here defines the function main(). All stand-alone C programs begin with
  2386.    main(). The statements within braces are sometimes called the "function
  2387.    body," to distinguish them from the function name and argument list, which
  2388.    together form the "function header."
  2389.  
  2390.    The function body can consist of any number of program statements. Note,
  2391.    however, that the braces are still required even if the definition
  2392.    contains no statements. Think of braces as symbols that delimit
  2393.    "paragraphs" of C code.
  2394.  
  2395.    A Statement Is like a Sentence
  2396.  
  2397.    A statement in C consists of keywords, variable and function names, and
  2398.    operators, and, like an English sentence, describes a complete action.
  2399.    Statements always end with a semicolon. Below are some example C
  2400.    statements and their meanings:
  2401.  
  2402.      printf("This is a statement");─────────────────Print This is a statement
  2403.      count = 1;───────────────────────────────────Set the variable count to 1
  2404.      getche(ch);───────────────────────────Wait for user to type a character,
  2405.                                            assign it to the variable ch, and
  2406.                                            echo (display) it on the screen
  2407.  
  2408.    QCHELLO.C has only one statement, printf("Hello, and welcome to
  2409.    QuickC!\n"); this statement translates as "Print the string `Hello, and
  2410.    welcome to QuickC!' and then go to the next line." (The \n specifies a
  2411.    newline character that moves the cursor to the next line.) This statement
  2412.    completely defines the function main() and describes what happens when the
  2413.    program executes the function.
  2414.  
  2415.    A Statement Can Contain Expressions
  2416.  
  2417.    Can an expression, such as count + 2, be a statement? Well, it doesn't end
  2418.    with a semicolon. But more importantly, it is not a complete statement.
  2419.    The word and number merely express a quantity ("two more than the value of
  2420.    the variable count"): They don't do anything with the quantity.
  2421.  
  2422.    Although an expression by itself is not a statement, it can be an
  2423.    important element of a C statement. For example, count = count + 2; is a
  2424.    complete C statement that assigns the quantity of the expression to the
  2425.    variable count.
  2426.  
  2427.    A Statement Can Call Functions
  2428.  
  2429.    Let's look at QCHELLO.C in more detail. (See Figure 3-2 on the following
  2430.    page.) What exactly is the printf() function at the start of the statement
  2431.    that defines the main() function? If you know BASIC, you might say, "It's
  2432.    the command you use to print in C." This isn't really correct, however. In
  2433.    BASIC, PRINT is a built-in BASIC command (or keyword) that prints a string
  2434.    or number. In C, printf doesn't execute a built-in command; it calls a
  2435.    function named printf() and gives ("passes") it an argument (or parameter)
  2436.    that tells it what to print.
  2437.  
  2438.               Function name               Argument list
  2439.                     │                         │
  2440.                     └──────────┐   ┌──────────┘
  2441.                              main ( )
  2442.                            ┌─
  2443.                            │ {
  2444.    Definition of main() ───┤     printf ("Hello, and welcome to QuickC!\n");
  2445.    function in braces      │ }     │     │                                 │
  2446.                            └─      │     └───────────┬─────────────────────┘
  2447.                                    │                 │
  2448.                                 Name of    Argument list (string to print)
  2449.                                 function
  2450.                                 being called
  2451.  
  2452.    Figure 3-2. Parts of QCHELLO.C revisited.
  2453.  
  2454.    Compare the printf() statement with the line containing main(). Both
  2455.    consist of a name followed by parentheses: that is, a function name and an
  2456.    argument list──the list for main() is empty. (Note that when we show
  2457.    function names in text, we use a trailing set of parentheses to
  2458.    distinguish them from other C elements.)
  2459.  
  2460.    The main() function name with its empty argument list are followed by a
  2461.    pair of braces that enclose the function definition. (You'll notice in
  2462.    QCHELLO.C that no semicolon follows main() because the line isn't a
  2463.    complete statement: It's the header for the function definition that
  2464.    follows.) The line with printf(), however, needs no defining group of
  2465.    statements because we are not defining printf() here; we're merely using,
  2466.    or "calling," the function in a statement. To call a function, simply use
  2467.    its name and argument list in a statement. We refer to statements such as
  2468.    the printf() line as "function calls."
  2469.  
  2470.    Always remember that every function must be defined before you can call
  2471.    it, otherwise QuickC would not know what statements to use when it tries
  2472.    to compile the function name. So where is the definition of the printf()
  2473.    function we called in Figure 3-2? The printf() function is a "core
  2474.    library function." Its definition is built into QuickC so that your
  2475.    program always has access to it. When you link your program, QuickC
  2476.    inserts the appropriate machine code for printing.
  2477.  
  2478.    ──────────────────────────────────────────────────────────────────────────
  2479.    Quick Tip
  2480.    If you know Pascal, you recognize the use of the semicolon to end
  2481.    statements in C. However, there is one important difference between its
  2482.    use in C and in Pascal. In Pascal, the semicolon can be omitted if the
  2483.    statement is the last statement in a group (the statement before the word
  2484.    END). In C, every statement ends with a semicolon.
  2485.  
  2486.    Also notice that the braces in C serve the same function as the Pascal
  2487.    keywords BEGIN and END: They delimit a group of statements.
  2488.    ──────────────────────────────────────────────────────────────────────────
  2489.  
  2490.    We stress the difference between C's library functions and the built-in
  2491.    commands of some other languages to emphasize the all-important role that
  2492.    functions play in C. C makes no distinction in syntax between QuickC
  2493.    library functions, such as printf(); functions that you define yourself,
  2494.    such as main(); and C header files developed by Microsoft or other
  2495.    vendors.
  2496.  
  2497.  The Flow of Execution Starts with main()
  2498.  
  2499.    When you run a C program, execution always begins with the function named
  2500.    main(), which must be present. What QuickC executes next depends on the
  2501.    functions that main() calls in its definition. In QCHELLO.C, execution
  2502.    starts with main(). In the definition of main(), QuickC encounters the
  2503.    name printf() and executes that function.
  2504.  
  2505.  
  2506.  Punctuation and Spacing in C Programs
  2507.  
  2508.    Generally speaking, QuickC lets you break lines of code almost anywhere or
  2509.    insert many spaces (or none) between program elements. For example, you
  2510.    could rewrite the QCHELLO.C program as:
  2511.  
  2512.      main(){printf("Hello, and welcome to QuickC!\n");}
  2513.  
  2514.    or, at the other extreme, you could add line breaks to produce the
  2515.    NARROW.C program shown in Listing 3-2. There are, however, some
  2516.    exceptions to C's tolerance of white space and "free-form" syntax. You
  2517.    can't split a function name across two lines because the compiler reads
  2518.    the newline character at the end of the line as part of the function name.
  2519.    Also, you can't break a quoted string, such as the "Hello, and welcome to
  2520.    QuickC!" in our printf() statement, between two lines because the compiler
  2521.    won't let you use the newline character in a "string constant" (although
  2522.    you can specify a newline with the escape sequence \n, as we have seen).
  2523.  
  2524.    Because C is a somewhat cryptic language, you should use spacing and
  2525.    alignment of code to make it easier for other programmers to read and
  2526.    revise your programs. (Remember, after a few weeks you, too, are "another
  2527.    programmer" when you look at your code.) You'll also find that aligning
  2528.    braces vertically helps you avoid errors: The vertical alignment lets you
  2529.    easily match beginning and ending braces.
  2530.  
  2531.    ──────────────────────────────────────────────────────────────────────────
  2532.    /* narrow.c -- a choppy c program */
  2533.  
  2534.    main
  2535.    (
  2536.    )
  2537.    {
  2538.    printf
  2539.    ("Hello, and welcome to QuickC!\n");
  2540.    }
  2541.    ──────────────────────────────────────────────────────────────────────────
  2542.  
  2543.    Listing 3-2.  The NARROW.C program.
  2544.  
  2545.  
  2546.  Using Comments in C
  2547.  
  2548.    Listing 3-1 on p. 50 contains several lines or parts of lines that begin
  2549.    with /* and end with */; for example:
  2550.  
  2551.      /* tiny.c ── the smallest possible C program */
  2552.  
  2553.    These lines are comments, or nonexecuting remarks, that explain how a
  2554.    program works. We strongly encourage you to use comments in your programs;
  2555.    they make the program much easier for a reader to understand. Because
  2556.    QuickC ignores comments, they can follow a program statement on the same
  2557.    line or cover many separate lines. The program examples in this book have
  2558.    an introductory comment, and we insert other comments where appropriate.
  2559.  
  2560.    Below are several different styles you can use for comments:
  2561.  
  2562.      /* Comment line one */
  2563.      /* Comment line two */
  2564.  
  2565.    or
  2566.  
  2567.      /* Comment line one
  2568.      comment line two */
  2569.  
  2570.    or
  2571.  
  2572.      /* Comment line one
  2573.      /* Comment line two
  2574.      /* Comment line three */
  2575.  
  2576.    However, you can't insert a comment within a comment as follows:
  2577.  
  2578.      /* Comment line one
  2579.      /* Nested comment line two */
  2580.      Comment line three */
  2581.  
  2582.    The reason you can't "nest" comments is that once the compiler sees the
  2583.    beginning of a comment (the /*), it considers everything that follows
  2584.    (including another /*) to be part of the comment until it sees */. In the
  2585.    nested comment above, the compiler considers the comment ended at the */
  2586.    after the word two. It then treats the word Comment on the next line as an
  2587.    undefined function or variable name.
  2588.  
  2589.    ──────────────────────────────────────────────────────────────────────────
  2590.    Quick Tip
  2591.    Many versions of Pascal use both /*...*/ and {...} to enclose comments. In
  2592.    C, you can never use braces for comments: They serve only to begin and end
  2593.    groups of statements.
  2594.    ──────────────────────────────────────────────────────────────────────────
  2595.  
  2596.  
  2597.  Data Types and Declarations of Variables
  2598.  
  2599.    Variables are names for memory storage areas used by a program. Variables
  2600.    come in many shapes and sizes. Many BASIC programmers get along reasonably
  2601.    well using only two types of variables: numeric (representing a number)
  2602.    and string (representing a series of characters). A BASIC programmer might
  2603.    write:
  2604.  
  2605.      ITEM$="WIDGET"
  2606.      SERIAL=32767
  2607.  
  2608.    to define two variables. The $ at the end of ITEM signifies a string
  2609.    variable; its absence in SERIAL specifies a numeric variable. A BASIC
  2610.    interpreter sets up these variables "on the fly" as it analyzes the lines
  2611.    of code, without storing them in a particularly efficient way.
  2612.  
  2613.    With C, the situation is more complicated. In order to use computer memory
  2614.    more efficiently, the C compiler reserves a specific location in memory
  2615.    for each variable. To do this efficiently, it needs to know exactly how
  2616.    many bytes of storage to use and how to store the data in those bytes.
  2617.    Therefore, C uses many "data types" to specify such things as the range of
  2618.    numbers that a variable can hold, whether negative values should be
  2619.    accommodated, whether values can be integers only or include decimal
  2620.    fractions, and so on. If you are a BASIC programmer, this constant
  2621.    attention to data types takes a little getting used to. However, by the
  2622.    end of this chapter, you will know all the available types and when each
  2623.    should be used.
  2624.  
  2625.    Let's begin our survey of data types by considering some different types
  2626.    of data we might store in variables:
  2627.  
  2628.    ■  30 (the number of students in a class)
  2629.  
  2630.    ■  557,617,814 (number of seconds since a date in 1970)
  2631.  
  2632.    ■  22.95 (price of a computer book?)
  2633.  
  2634.    ■  1,000,000,000,000.00 (future U.S. budget?)
  2635.  
  2636.    ■  a (the letter a)
  2637.  
  2638.    As you probably know, data is stored in a computer as patterns of bits: 1s
  2639.    and 0s, "ons" and "offs." In the IBM PC family of computers, bits are
  2640.    organized in groups of eight (called bytes), or in groups of two bytes
  2641.    (called words), or in groups of four bytes (double words), depending on
  2642.    the operation involved and the processor used. Figure 3-3 on the
  2643.    following page shows how many bytes are needed to store the different
  2644.    sizes and kinds of numbers in the above list. The figure also shows the
  2645.    name of the data type that describes the storage involved. The addresses
  2646.    shown are arbitrary, but they demonstrate how successive items are stored
  2647.    with lower addresses.
  2648.  
  2649.    The QuickC sizeof operator returns the number of bytes that a given data
  2650.    type uses. The program VARSIZE.C (see Listing 3-3 on the following page)
  2651.    uses this operator and a series of printf() statements to print out the
  2652.    sizes (in bytes) of the following data types: char, int, long, float, and
  2653.    double.
  2654.  
  2655.                                       ADDRESSES   DATA                  TYPE
  2656.      Stored          ┌──────────────┐
  2657.    "downward"        │              │ 5003
  2658.    in memory         ├──────────────┤                                   char
  2659.        │      1 ─── ▒│              │ 5002 ▒ ──── a
  2660.        │     byte    └──────────────┘
  2661.        │             ┌──────────────┐
  2662.        │            ▒│              │ 5001 ▒
  2663.        │      2 ─── ▒├──────────────┤      ▒ ──── 30                    int
  2664.        │    bytes   ▒│              │ 5000 ▒
  2665.                     └──────────────┘
  2666.                      ┌──────────────┐
  2667.                     ▒│              │ 4999 ▒
  2668.                     ▒├──────────────┤      ▒
  2669.                     ▒│              │ 4998 ▒
  2670.               4 ─── ▒├──────────────┤      ▒ ──── 557,617,814           long
  2671.             bytes   ▒│              │ 4997 ▒
  2672.                     ▒├──────────────┤      ▒
  2673.                     ▒│              │ 4996 ▒
  2674.                      └──────────────┘
  2675.                      ┌──────────────┐
  2676.                     ▒│              │ 4995 ▒
  2677.                     ▒├──────────────┤      ▒
  2678.                     ▒│              │ 4994 ▒
  2679.               4 ─── ▒├──────────────┤      ▒ ──── 22.95                 float
  2680.             bytes   ▒│              │ 4993 ▒
  2681.                     ▒├──────────────┤      ▒
  2682.                     ▒│              │ 4992 ▒
  2683.                      └──────────────┘
  2684.                      ┌──────────────┐
  2685.                     ▒│              │ 4991 ▒
  2686.                     ▒├──────────────┤      ▒
  2687.                     ▒│              │ 4990 ▒
  2688.                     ▒├──────────────┤      ▒
  2689.                     ▒│              │ 4989 ▒
  2690.                     ▒├──────────────┤      ▒
  2691.                     ▒│              │ 4988 ▒
  2692.               8 ─── ▒├──────────────┤      ▒ ──── 1,000,000,000,000.00  double
  2693.             bytes   ▒│              │ 4987 ▒
  2694.                     ▒├──────────────┤      ▒
  2695.                     ▒│              │ 4986 ▒
  2696.                     ▒├──────────────┤      ▒
  2697.                     ▒│              │ 4985 ▒
  2698.                     ▒├──────────────┤      ▒
  2699.                     ▒│              │ 4984 ▒
  2700.                      └──────────────┘
  2701.  
  2702.    Figure 3-3. Storing information in memory.
  2703.  
  2704.    ──────────────────────────────────────────────────────────────────────────
  2705.    /* varsize.c -- shows amount of memory */
  2706.    /*              by various types       */
  2707.  
  2708.    main()
  2709.    {
  2710.        printf("Size of a char in bytes is %d\n", sizeof(char));
  2711.        printf("Size of an int in bytes is %d\n", sizeof(int));
  2712.        printf("Size of a long in bytes is %d\n", sizeof(long));
  2713.        printf("Size of a float in bytes is %d\n", sizeof(float));
  2714.        printf("Size of a double in bytes is %d\n", sizeof(double));
  2715.    }
  2716.    ──────────────────────────────────────────────────────────────────────────
  2717.  
  2718.    Listing 3-3.  The VARSIZE.C program.
  2719.  
  2720.    Here's the output of VARSIZE.C:
  2721.  
  2722.      Size of a char in bytes is 1
  2723.      Size of an int in bytes is 2
  2724.      Size of a long in bytes is 4
  2725.      Size of a float in bytes is 4
  2726.      Size of a double in bytes is 8
  2727.  
  2728.  Declaring Variables
  2729.  
  2730.    To declare a variable, specify the data type and then the variable name.
  2731.    Here are some examples:
  2732.  
  2733.      int account_no;
  2734.      float balance;
  2735.      double budget;
  2736.      char acct_type;
  2737.  
  2738.    The first statement declares account_no as an integer (int) variable. The
  2739.    remaining statements declare variables as floating-point decimal (using
  2740.    the keyword float), "jumbo" 8-byte floating-point (double), and 1-byte
  2741.    character (char) data types.
  2742.  
  2743.    When you declare a variable, QuickC sets aside the appropriate number of
  2744.    bytes and notes the variable's starting address. The next program,
  2745.    VARADDRS.C (Listing 3-4), declares several types of variables and then
  2746.    prints out their starting addresses.
  2747.  
  2748.    ──────────────────────────────────────────────────────────────────────────
  2749.    /* varaddrs.c -- uses & operator to get   */
  2750.    /*               addresses of variables   */
  2751.  
  2752.    main()
  2753.    {
  2754.        char c1, c2;
  2755.        int i;
  2756.        long l;
  2757.        float f;
  2758.        double d;
  2759.  
  2760.        printf("Address of c1 %d\n", &c1);
  2761.        printf("Address of c2 %d\n", &c2);
  2762.        printf("Address of i  %d\n", &i);
  2763.        printf("Address of l  %d\n", &l);
  2764.        printf("Address of f  %d\n", &f);
  2765.        printf("Address of d  %d\n", &d);
  2766.    }
  2767.    ──────────────────────────────────────────────────────────────────────────
  2768.  
  2769.    Listing 3-4.  The VARADDRS.C program.
  2770.  
  2771.    Although the output of this program varies with different system
  2772.    configurations, it should look something like this:
  2773.  
  2774.      Address of c1 6146
  2775.      Address of c2 6144
  2776.      Address of i  6142
  2777.      Address of l  6138
  2778.      Address of f  6134
  2779.      Address of d  6126
  2780.  
  2781.    VARADDRS.C obtains the addresses of the variables by using an ampersand
  2782.    (&) prefix with each variable name. The ampersand is the "address
  2783.    operator," and it returns the starting address for each variable
  2784.    specified. Compare the output of VARADDRS.C with Figure 3-3 to see how
  2785.    variables declared with different data types require different amounts of
  2786.    memory. When QuickC allocates the required number of bytes for a declared
  2787.    data type, the last byte allocated (moving downward in memory) is the
  2788.    variable's starting address. For example, the integer variable i has an
  2789.    address of 6142, indicating that it uses two bytes (6144 - 6142 = 2); the
  2790.    double type variable d uses eight bytes (6134 - 6126 = 8). Note that the
  2791.    compiler allocates two bytes for char values c1 and c2, although each
  2792.    value requires only one byte. The extra byte is convenient for
  2793.    manipulating (2-byte) words in memory.
  2794.  
  2795.  Rules for Naming Variables
  2796.  
  2797.    In C, the names of variables and functions are called "identifiers." An
  2798.    identifier can contain any uppercase or lowercase alphabetic characters
  2799.    (A-Z or a-z), digits (0-9), and the underscore character (_). However, the
  2800.    name must begin with a letter or underscore. Below are some examples of
  2801.    legal and illegal names:
  2802.  
  2803.      bignum─────────────────────────────────────────────────────────────Legal
  2804.      BigNum───────────────────────────────────Legal, and distinct from bignum
  2805.      _video───────────────────────────────Legal, can begin with an underscore
  2806.      bal_due─────────────────────────Legal, underscore used to separate words
  2807.      player2───────────────────────────────────Legal, number in variable name
  2808.      8ball─────────────────────────────────Illegal, can't begin with a number
  2809.      tally-ho!─────────────────Illegal, contains hyphen and exclamation point
  2810.      int───────────────────Illegal, keyword reserved for name of integer type
  2811.  
  2812.    As you can see, you have considerable flexibility in choosing names for
  2813.    your variables. Because QuickC can distinguish the first 31 characters of
  2814.    a variable name, you can use long, descriptive names that help make the
  2815.    program easier to understand and modify. (You might want to use shorter
  2816.    names if your program must run a compiler that does not support long
  2817.    names.) C distinguishes between uppercase and lowercase characters, so
  2818.    that BigNum and bignum are different variables. Note that you can't begin
  2819.    a variable name with a number, use punctuation marks such as ! or $, or
  2820.    use C-language keywords as variable names. (You can embed a keyword in a
  2821.    variable name, however: interest is a legal name even though it contains
  2822.    the keyword int.) Fortunately, C has few keywords compared to languages
  2823.    such as BASIC: Most specify data types (such as int) or control and
  2824.    decision-branching operations (such as while and if).
  2825.  
  2826.    We use specific conventions for naming variables and functions. (See
  2827.    "Conventions and Style" in Chapter 1.) These are not required by QuickC,
  2828.    but are used here to differentiate among types of variables and functions.
  2829.    We also begin our variable names with a character other than an
  2830.    underscore──Microsoft uses the underscore as the initial character for its
  2831.    QuickC library functions.
  2832.  
  2833.  Assignment Statements
  2834.  
  2835.    How do you assign values to variables? In C, the simplest assignment
  2836.    statement consists of a variable name followed by an equal sign (=) and
  2837.    the value to be assigned. Below are some examples:
  2838.  
  2839.      a = 5;
  2840.      b = a + 5;
  2841.      c = a + b;
  2842.  
  2843.    In these assignment statements, the value to the right of the equal sign
  2844.    is assigned to the variable on the left. The value can be a number or an
  2845.    expression involving variables and/or numbers, such as a + 5 or a + b. If
  2846.    the value is an expression, QuickC determines the result and then assigns
  2847.    it to the variable.
  2848.  
  2849.    You can also assign the same value to several variables at once. Usually,
  2850.    you do this to initialize variables by setting them all to 0 or 1:
  2851.  
  2852.      line_count = word_count = 0;
  2853.      line_no = page_no = 1;
  2854.  
  2855.  Initializing Variables
  2856.  
  2857.    Many languages (including most versions of BASIC) automatically initialize
  2858.    numeric variables to 0 and character variables to blank or, perhaps,
  2859.    "null." C does not. For example, if your program has the following two
  2860.    lines:
  2861.  
  2862.      int length;
  2863.      printf("The length is %d\n", length);
  2864.  
  2865.    and you do not initialize length, it might produce the following output:
  2866.  
  2867.      The length is -25480
  2868.  
  2869.    The default value of a C variable is whatever pattern of bits happens to
  2870.    be in the memory locations of the variable when the compiler assigns them.
  2871.    Therefore, if you want to use a variable called total, for example, in a
  2872.    program that keeps track of some quantity, you should assign that variable
  2873.    an initial value of 0. You might modify the declaration above as follows:
  2874.  
  2875.      int length = 0;
  2876.  
  2877.    Because C is a concise language, it lets you combine the declaration and
  2878.    assignment of a variable. That is, you can declare the data type, the
  2879.    variables, and their values in the same statement:
  2880.  
  2881.      int a = 10, b = 50, c = 100;
  2882.  
  2883.  Type int
  2884.  
  2885.    Now that you know how to declare numeric variables and assign values to
  2886.    them, let's look at the int, or integer, data type more closely. An
  2887.    integer is a whole number, such as 30, -5, or 93,000,000. In QuickC, an
  2888.    int variable can hold numbers in the range of -32,768 through 32,767. This
  2889.    rather odd-looking range is established because the int type uses two
  2890.    bytes (16 bits) of memory. Two bytes can actually hold a range of 0
  2891.    through 65,535. But, in the regular int type, the high (leftmost) bit of
  2892.    the 2-byte combination stores the integer's sign (positive or negative),
  2893.    leaving only 15 bits for the number.
  2894.  
  2895.    If your variable will never store negative integers, use the unsigned int
  2896.    type. Because the sign bit is not used, you can use the full two bytes to
  2897.    store values from 0 through 65,535.
  2898.  
  2899.    Now let's look at the INTVARS.C program (Listing 3-5), which declares
  2900.    three integer variables, assigns values to them, and then prints out
  2901.    values that describe the World War II German battleship Bismarck.
  2902.  
  2903.    We declare the variables length and beam as int types because the length
  2904.    and beam (width) of the ship are less than 32,767 feet. For the
  2905.    displacement variable (the "weight" of the ship), we use the unsigned int
  2906.    type because we need a larger number (41,676) than 32,767 (the int limit)
  2907.    but a smaller number than 65,535 (the unsigned int type limit).
  2908.  
  2909.    The next three lines assign the values to the variables, and the three
  2910.    printf() statements print the values out. Notice that the printf()
  2911.    statements use two arguments within the parentheses: a string, such as
  2912.    "The battleship Bismarck was %d feet long", followed by a comma and the
  2913.    variable name whose value is to be printed. The %d in the string is a
  2914.    printf() "format specifier," and the value of the variable is printed in
  2915.    its place. (The %d specifier denotes a decimal [base 10] integer. C uses a
  2916.    variety of specifiers for different types and formats of numbers and
  2917.    characters. We'll discuss them when we look at printf().) When you run
  2918.    INTVARS.C, it generates the output that appears below the listing (on the
  2919.    following page).
  2920.  
  2921.    ──────────────────────────────────────────────────────────────────────────
  2922.    Quick Tip
  2923.    ANSI C lets you specify any basic variable type as unsigned. It also lets
  2924.    you specify signed types. Therefore, although QuickC considers the int
  2925.    type to be signed by default, the C language doesn't guarantee that all C
  2926.    compilers do so. To write portable programs, you need to specify all
  2927.    variables as either signed or unsigned types.
  2928.    ──────────────────────────────────────────────────────────────────────────
  2929.  
  2930.    ──────────────────────────────────────────────────────────────────────────
  2931.    /* intvars.c -- declares, defines, and prints */
  2932.    /*              some integer variables        */
  2933.  
  2934.    main()
  2935.    {
  2936.        /* declare variables */
  2937.        int length, beam;
  2938.        unsigned int displacement;
  2939.        /* assign values to variables */
  2940.        length = 824;
  2941.        beam = 118;
  2942.        displacement = 41676;
  2943.  
  2944.        /* print out values */
  2945.        printf("The battleship Bismarck was %d feet long",
  2946.                length);
  2947.        printf(" with a beam of %d feet,\n", beam);
  2948.        printf("and displaced %u tons.\n", displacement);
  2949.    }
  2950.    ──────────────────────────────────────────────────────────────────────────
  2951.  
  2952.    Listing 3-5.  The INTVARS.C program.
  2953.  
  2954.      The battleship Bismarck was 824 feet long with a beam of 118 feet,
  2955.      and displaced 41676 tons.
  2956.  
  2957.  Long Integer Type
  2958.  
  2959.    We've seen that unsigned int variables can hold values to 65,535. But what
  2960.    if you must use larger numbers? Type long uses four bytes (32 bits) of
  2961.    memory (1 bit is reserved for the sign), and can store numbers from -2^31
  2962.    to +2^31, or -2,147,483,648 to 2,147,483,647 in base 10. Once again, if
  2963.    your variable will contain only positive numbers, you can double the high
  2964.    end of this range by specifying unsigned long. This lets you assign your
  2965.    variable a whole number value in the range 0 through 4,294,967,295.
  2966.  
  2967.    The SCORE.C program (Listing 3-6 on the following page) combines the
  2968.    declaration and assignment of the int variables home, visitors, inning,
  2969.    and attendance. Because total_attendance is a different data type, long,
  2970.    you must declare it in a separate statement. Again, the printf()
  2971.    statements display the values assigned to the variables and produce the
  2972.    following output:
  2973.  
  2974.      The score after 7 innings is
  2975.      Home team 5, Visitors 2.
  2976.  
  2977.      The attendance today is 31300.
  2978.      Attendance this year to date is 1135477.
  2979.  
  2980.    ──────────────────────────────────────────────────────────────────────────
  2981.    /* score.c -- defines and prints   */
  2982.    /*            int and long vars    */
  2983.    main()
  2984.    {
  2985.        /* declare some int variables and assign values */
  2986.        /* to them in the same statement                */
  2987.  
  2988.        int home = 5, visitors = 2, inning = 7, attendance = 31300;
  2989.        long total_attendance = 1135477;  /* long int */
  2990.  
  2991.        /* print out the values */
  2992.  
  2993.        printf("The score after %d innings is \n", inning);
  2994.        printf("Home team %d, Visitors %d.\n\n", home, visitors);
  2995.        printf("The attendance today is %d.\n", attendance);
  2996.        printf("Attendance this year to date is %ld.",
  2997.                total_attendance);
  2998.    }
  2999.    ──────────────────────────────────────────────────────────────────────────
  3000.  
  3001.    Listing 3-6.  The SCORE.C program.
  3002.  
  3003.  Floating-Point Types
  3004.  
  3005.    You should store whole numbers as integers wherever possible──integers use
  3006.    the least amount of memory and integer arithmetic is fast. However, many
  3007.    numbers (such as dollars-and-cents amounts) require decimal fractions. In
  3008.    computers, these types of numbers are stored in "floating-point format."
  3009.  
  3010.    Consider the number 22.95. This number can be stored by dividing it into
  3011.    two parts: the digits themselves and an exponent showing the magnitude of
  3012.    the number in terms of powers of ten. Thus, 22.95 could be represented as
  3013.    22.95 * 10^0. For uniformity in performing operations, however, C always
  3014.    expresses the digits with only one digit to the left of the decimal point.
  3015.    Therefore, the above number is actually stored as 2.295 * 10^1 (the same
  3016.    as 22.95 * 10^0). C represents this notation with the expression
  3017.    2.295e+001. The first element, 2.295, is the number's digits (the
  3018.    "mantissa"), and the e+001 represents "exponent 1," or 10^1.
  3019.  
  3020.  Type float
  3021.  
  3022.    The most commonly used floating-point type in C is float. In QuickC, type
  3023.    float uses three bytes to store digits (the mantissa) and one byte to
  3024.    store the exponent. Because exponents can be negative (for example,
  3025.    1.4e-002 = .014), one bit of the exponent byte stores the sign. Converted
  3026.    into decimal terms, this means you can store a mantissa with seven
  3027.    significant digits and an exponent ranging from -38 to +38. In fact, with
  3028.    QuickC's float type, you can store numbers as large as 3.4e+038, or 34
  3029.    with 37 zeros after it.
  3030.  
  3031.    The FLOATS.C program (Listing 3-7) displays three float values, each
  3032.    printed in both traditional decimal and exponential notation.
  3033.  
  3034.    ──────────────────────────────────────────────────────────────────────────
  3035.    /* floats.c  -- shows floating values in regular */
  3036.    /*              and exponential format           */
  3037.  
  3038.    main()
  3039.    {
  3040.        float f1 = 2500.125, f2 = 0.0033, f3 = -50.99;
  3041.  
  3042.        printf("%f\t %e\n\n", f1, f1);
  3043.        printf("%f\t %e\n\n", f2, f2);
  3044.        printf("%f\t %e\n", f3, f3);
  3045.    }
  3046.    ──────────────────────────────────────────────────────────────────────────
  3047.  
  3048.    Listing 3-7.  The FLOATS.C program.
  3049.  
  3050.    The following is the output of the FLOATS.C program:
  3051.  
  3052.      2500.125000      2.500125e+003
  3053.      0.003300         3.300000e-003
  3054.      -50.990002       -5.099000e+001
  3055.  
  3056.    Notice that because 0.0033 is less than 1, it has a negative exponent
  3057.    (represented by the minus sign after the e). -50.99, on the other hand, is
  3058.    a negative number, but because its absolute (unsigned) magnitude is
  3059.    greater than 1, it has a positive exponent. FLOATS.C prints each variable
  3060.    first in decimal notation and then in exponential notation by varying the
  3061.    format specifier in the printf() statement: The %f produces traditional
  3062.    decimal format, and the %e produces exponential format.
  3063.  
  3064.  Type double
  3065.  
  3066.    For numbers larger than
  3067.  
  3068.      340,000,000,000,000,000,000,000,000,000,000,000,000
  3069.  
  3070.    QuickC provides a "jumbo" floating-point type called double (double
  3071.    float). It uses eight bytes of storage and has a range of (plus or minus)
  3072.    1.7e-308 to 1.7e+308. That's 308 decimal places before or after the
  3073.    decimal point, thus accommodating even the most expansive physicist or
  3074.    astronomer.
  3075.  
  3076.    ──────────────────────────────────────────────────────────────────────────
  3077.    Type Variations on Different Machines
  3078.    The C language doesn't define the number of bytes used by the int and
  3079.    unsigned int types. Instead, the number of bytes is based on the size of
  3080.    number a particular processor can handle in a single operation. This way,
  3081.    C compilers can always take advantage of a machine's architecture. Because
  3082.    the IBM PC uses the Intel 8086, 8088, or 80286 processor, an int uses two
  3083.    bytes, or 16 bits, and this is the implementation QuickC uses. However, on
  3084.    larger personal computers, such as those using the Intel 80386 processor,
  3085.    and on many minicomputers and mainframes, an int uses four bytes, or 32
  3086.    bits. Even if you write your program in "standard" C, you must be aware of
  3087.    these differences in implementation and machine architecture when you
  3088.    "port" the program to another machine.
  3089.    ──────────────────────────────────────────────────────────────────────────
  3090.  
  3091.  Precision for Floating-Point Numbers
  3092.  
  3093.    You must consider more than size, however, when storing numbers in a
  3094.    computer. We referred to a trillion-dollar budget ($1,000,000,000,000.00)
  3095.    earlier in the chapter. If size were the only consideration, we could use
  3096.    float to store this number. (A float can handle about 10^38, and a
  3097.    trillion is merely 10^12.)
  3098.  
  3099.    However, you also must consider the precision available to each data type
  3100.    in order to choose the right type for a given variable. Precision refers
  3101.    to the number of digits guaranteed to be exactly correct after a
  3102.    calculation. The float type has a precision of seven digits. Consider the
  3103.    following statements and the resulting output:
  3104.  
  3105.      float trillion = 1000000000000.00;
  3106.      printf("%f\n", trillion);
  3107.  
  3108.      999999995904.000000
  3109.  
  3110.    We lost $4,096.00 in this operation. Although we might be happy if the
  3111.    government lost only that much of a trillion-dollar budget, we must expect
  3112.    full precision in financial calculations and probably an even higher
  3113.    precision in most scientific calculations. With its seven-digit precision,
  3114.    float can't accurately represent a trillion dollars. We attain the
  3115.    required precision by declaring:
  3116.  
  3117.      double trillion = 1000000000000.00;
  3118.  
  3119.    Because double has 15-digit precision, the result is completely accurate.
  3120.  
  3121.  Type char
  3122.  
  3123.    Let's look at one last data type, char (character). Characters include the
  3124.    uppercase and lowercase letters, numerals, punctuation marks, and
  3125.    nonprinting control characters. Characters on most computers, including
  3126.    the IBM PC, are represented by numbers between 0 and 127, according to the
  3127.    ASCII code. The CHARS.C program (Listing 3-8) shows some examples.
  3128.  
  3129.    Running CHARS.C produces the following output:
  3130.  
  3131.      The character A has ASCII code 65
  3132.      If you add ten, you get K
  3133.      The character a has ASCII code 97
  3134.  
  3135.    The first line of the main() function declares two char type variables,
  3136.    ch1 and ch2, and assigns them the values of `A' and `a' respectively. The
  3137.    `A' and `a' are called "character constants" or "character literals," and
  3138.    you assign them to char variables the same way you assign numeric
  3139.    constants. (Note that you must use single quotes around the character
  3140.    constant.)
  3141.  
  3142.    Consider the first printf() statement in the program:
  3143.  
  3144.      printf("The character %c has ASCII code %d\n", ch1, ch1);
  3145.  
  3146.    The variable ch1 is specified twice at the end of the argument list. The
  3147.    first format specifier, %c, prints the value of ch1 as a character. Then
  3148.    the %d specifier prints ch1 as an integer. A character is actually stored
  3149.    as a 1-byte version of int, and unless you specify that QuickC treat it as
  3150.    a character, it is treated as an integer. This enables us to use the
  3151.    expression ch1 + 10 in the second printf() statement. The variable ch1
  3152.    contains an integer value (the ASCII code for `A', or 65), so adding 10 to
  3153.    it produces 75. When the %c specifier then prints this value, it displays
  3154.    the character with the ASCII value of 75, or `K'.
  3155.  
  3156.    ──────────────────────────────────────────────────────────────────────────
  3157.    /* chars.c -- shows some variables of type char */
  3158.    /*            as both characters and integers   */
  3159.  
  3160.    main()
  3161.    {
  3162.        char ch1 = 'A', ch2 = 'a';
  3163.  
  3164.        printf("The character %c has ASCII code %d\n", ch1, ch1);
  3165.        printf("If you add ten, you get %c\n", ch1 + 10);
  3166.        printf("The character %c has ASCII code %d\n", ch2, ch2);
  3167.    }
  3168.    ──────────────────────────────────────────────────────────────────────────
  3169.  
  3170.    Listing 3-8.  The CHARS.C program.
  3171.  
  3172.  Type unsigned char
  3173.  
  3174.    A char value is a signed, 1-byte value that stores values in the range of
  3175.    -128 to +127. However, the IBM PC's version of ASCII uses the values 0 to
  3176.    255 as character codes. The first half of extended ASCII contains the
  3177.    regular ASCII character set. Codes from 128 to 255, however, consist of
  3178.    special characters and graphics shapes, which together are called the
  3179.    "extended character set." You can use the extended character set by
  3180.    declaring variables as the unsigned char type. For example:
  3181.  
  3182.      unsigned char box = 178;
  3183.      printf("%c\n", box);
  3184.  
  3185.    displays a rectangular box, or extended ASCII character number 178. (Note
  3186.    that two QuickC general help screens show the complete extended ASCII
  3187.    character set.)
  3188.  
  3189.  Using typedef
  3190.  
  3191.    C lets you rename any data type with the typedef statement. For example,
  3192.    if you use unsigned char type variables to hold characters from the full
  3193.    256-character extended set, you could define an easily remembered
  3194.    mnemonic:
  3195.  
  3196.      typedef xchar unsigned char;
  3197.      xchar highlight_char, border_char;
  3198.  
  3199.    The typedef statement tells QuickC that the word xchar now represents
  3200.    unsigned char. Next, we declare two variables as type xchar. Note that you
  3201.    can still declare variables as unsigned char at any time. Also note that
  3202.    typedef does not create new data types, it merely provides synonyms for
  3203.    existing ones.
  3204.  
  3205.    The HARDWARE.C program (Listing 3-9) ends our survey of QuickC data
  3206.    types.
  3207.  
  3208.    ──────────────────────────────────────────────────────────────────────────
  3209.    /* hardware.c -- shows a mixture of int, */
  3210.    /*               float, and char types   */
  3211.  
  3212.    main()
  3213.    {
  3214.        int threads    = 8;       /* threads per inch */
  3215.        float length   = 1.25,    /* length in inches */
  3216.              diameter = 0.425,   /* diameter in inches */
  3217.              price    = 0.89;    /* price per hundred */
  3218.        char bin = 'A';           /* kept in bin A */
  3219.        long quantity = 42300;    /* number in bin */
  3220.  
  3221.        printf("Screws: %d threads/inch\n %f inches long\n",
  3222.                threads, length);
  3223.        printf ("%f diameter\n\n", diameter);
  3224.        printf("Price per 100: %f\n", price);
  3225.        printf("Stored in bin: %c\n Quantity on hand: %ld",
  3226.                bin, quantity);
  3227.    }
  3228.    ──────────────────────────────────────────────────────────────────────────
  3229.  
  3230.    Listing 3-9.  The HARDWARE.C program.
  3231.  
  3232.    Be sure you understand why we declared the different types. The printf()
  3233.    statements display the values of the variables and some descriptive text:
  3234.  
  3235.      Screws: eight threads/inch
  3236.      1.250000 inches long
  3237.      0.425000 diameter
  3238.  
  3239.      Price per 100: 0.890000
  3240.      Stored in bin: A
  3241.      Quantity on hand: 42300
  3242.  
  3243.    Although the program works correctly, it would look better if the output
  3244.    were formatted more neatly. Also, QuickC printed several extra decimal
  3245.    places and filled them with zeros. To gain more control over the
  3246.    appearance of program output, we need to study printf() in more detail.
  3247.  
  3248.  Summary of Data Types
  3249.  
  3250.    You don't need to memorize the precise numbers associated with each data
  3251.    type; one of QuickC's help screens lets you check which data type you
  3252.    should use in a given situation. Display this summary of QuickC data types
  3253.    by pressing the F1 key and then proceeding to the appropriate screen. As
  3254.    you work with various data types in this chapter, you can always consult
  3255.    this chart, shown in Figure 3-4, to refresh your memory.
  3256.  
  3257.    ┌────────────────────────────────────────────────────────────────────────┐
  3258.    │ Figure 3-4 can be found on p.67 of the printed version of the book.    │
  3259.    └────────────────────────────────────────────────────────────────────────┘
  3260.  
  3261.    Figure 3-4. Data types help screen.
  3262.  
  3263.  
  3264.  The Power of printf()
  3265.  
  3266.    Thus far we've used printf() statements merely to display values. But
  3267.    printf() is actually quite versatile for formatting numbers and character
  3268.    strings.
  3269.  
  3270.  Using Escape Sequences
  3271.  
  3272.    Let's look at the parts of the printf() statement from our first program,
  3273.    QCHELLO.C:
  3274.  
  3275.      printf ("Hello, and welcome to QuickC!\n");
  3276.  
  3277.    This is the simplest printf() statement: It merely prints out a string; no
  3278.    variables are involved. Earlier, we briefly discussed the one unusual
  3279.    feature of this printf() statement, the \n at the end of the string. This
  3280.    combination of backslash and following character is called an "escape
  3281.    sequence." Escape sequences tell printf() to print special characters as
  3282.    part of the given string. The \n, for example, adds the newline character,
  3283.    which moves the cursor or printer head to the beginning of the next line.
  3284.    Many languages use two kinds of statements for printing: one to print some
  3285.    information, and one to print some information and then start a new line.
  3286.    With typical conciseness and versatility, C lets you use one function to
  3287.    print any ASCII character, including newline, Tab, and carriage-return
  3288.    characters, giving you complete control of the position of the cursor or
  3289.    printer head.
  3290.  
  3291.    One QuickC help screen, shown in Figure 3-5 on the following page, lists
  3292.    all of the escape sequences. The newline \n and tab \t sequences are the
  3293.    most frequently used. The \a escape sequence causes an "alert," or beep,
  3294.    at the terminal.
  3295.  
  3296.    ┌────────────────────────────────────────────────────────────────────────┐
  3297.    │ Figure 3-5 can be found on p.68 of the printed version of the book.    │
  3298.    └────────────────────────────────────────────────────────────────────────┘
  3299.  
  3300.    Figure 3-5. Character escape sequences.
  3301.  
  3302.    The ONELINE.C program (Listing 3-10) shows what happens when you don't
  3303.    use the newline escape sequence. When you run the program, the output is
  3304.    all on one line as follows:
  3305.  
  3306.      All displayed onthe same line, with no space unless specified.
  3307.  
  3308.    Not only do the strings from all three printf() statements end up on the
  3309.    same line, the word "on" at the end of the first string runs into the word
  3310.    "the" at the start of the second string. To print two strings on the same
  3311.    line with a space between them, you must include the space in the string.
  3312.    In the third string of ONELINE.C, we added a space before the word
  3313.    "unless."
  3314.  
  3315.    ──────────────────────────────────────────────────────────────────────────
  3316.    /* oneline.c -- shows how printf() continues */
  3317.    /*              on the same line             */
  3318.  
  3319.    main ()
  3320.    {
  3321.        printf("All displayed on");
  3322.        printf("the same line, with no space");
  3323.        printf(" unless specified.");
  3324.                /* note added space in line above */
  3325.    }
  3326.    ──────────────────────────────────────────────────────────────────────────
  3327.  
  3328.    Listing 3-10.  The ONELINE.C program.
  3329.  
  3330.    The program STRINGS.C (Listing 3-11) demonstrates the two basic ways to
  3331.    print strings with printf().
  3332.  
  3333.    The first printf() statement has only one argument, the string to be
  3334.    printed, and the newline escape sequence. The second statement has two
  3335.    arguments, the format specifier %s (for "string") and the string to be
  3336.    printed. It replaces the specifier with the string and prints it. This is
  3337.    the same procedure we used to print numeric variables and literals with
  3338.    specifiers such as %d. The STRINGS.C program produces the following
  3339.    output:
  3340.  
  3341.      This uses a string literal by itself
  3342.      This plugs the literal into %s
  3343.  
  3344.    TABS.C (Listing 3-12) illustrates the use of the tab escape sequence \t.
  3345.  
  3346.    ──────────────────────────────────────────────────────────────────────────
  3347.    /* strings.c -- shows two ways to print */
  3348.    /*              a string with printf()  */
  3349.  
  3350.    main()
  3351.    {
  3352.        printf("This uses a string literal by itself\n");
  3353.        printf("%s", "This plugs the literal into %s\n");
  3354.    }
  3355.    ──────────────────────────────────────────────────────────────────────────
  3356.  
  3357.    Listing 3-11.  The STRINGS.C program.
  3358.  
  3359.    ──────────────────────────────────────────────────────────────────────────
  3360.    /* tabs.c -- shows formatting with the \t */
  3361.    /*           tab escape sequence          */
  3362.  
  3363.    main()
  3364.    {
  3365.        int    q1 = 338, q2 = 57, q3 = 1048, q4 = 778,
  3366.               /* quantity in bin */
  3367.               t1 = 6, t2 = 8, t3 = 12, t4 = 16;
  3368.               /* threads per inch */
  3369.  
  3370.        float  s1 = 0.250, s2 = 0.500, s3 = 0.750, s4 = 1.0;
  3371.               /* size in inches */
  3372.  
  3373.        /* print table header */
  3374.        printf("number\t\t size\t\t threads\n");
  3375.        printf("in bin\t\t (inches)\t per inch\n\n");
  3376.  
  3377.        /* print lines of table */
  3378.        printf("%d\t\t %f\t %d\n", q1, s1, t1);
  3379.        printf("%d\t\t %f\t %d\n", q2, s2, t2);
  3380.        printf("%d\t\t %f\t %d\n", q3, s3, t3);
  3381.        printf("%d\t\t %f\t %d\n", q4, s4, t4);
  3382.    }
  3383.    ──────────────────────────────────────────────────────────────────────────
  3384.  
  3385.    Listing 3-12.  The TABS.C program.
  3386.  
  3387.    This program prints four sets of data in a neat table. The program prints
  3388.    the table headers first, using \t to tab to the next field. Using \t to
  3389.    position each item at the next tab stop causes the output to be left-
  3390.    justified in each field. To make the table easier to read, we added a
  3391.    blank line between the header and the data by including an extra \n in the
  3392.    second printf() statement. The program then prints the values of the
  3393.    variables in the same tab fields as the headers. The result of all this is
  3394.    as follows:
  3395.  
  3396.      number          size             threads
  3397.      in bin          (inches)         per inch
  3398.  
  3399.      338             0.250000         6
  3400.      57              0.500000         8
  3401.      1048            0.750000         12
  3402.      778             1.000000         16
  3403.  
  3404.  Formatting Numbers with printf()
  3405.  
  3406.    The printf() function can also print numbers in a variety of formats.
  3407.    Let's look at a printf() statement from SCORE.C, which is analyzed in
  3408.    Figure 3-6.
  3409.  
  3410.    String to print is
  3411.    enclosed in quotes         ┌─────────────────────────────┐
  3412.            │                  │                             │
  3413.            │                ┌───┐            ┌────┐    ┌───────┐
  3414.    printf ("The score after │ %d │ innings is │ \n │ ", │ inning │ );
  3415.                             └────┘            └────┘    └────────┘
  3416.                               │                 │           │
  3417.                               │                 │           │
  3418.                       Format specifier       Newline     Variable whose
  3419.                       for an int value       escape      value is to be
  3420.                                              sequence    printed
  3421.  
  3422.    Figure 3-6. The printf() statement from SCORE.C.
  3423.  
  3424.    ──────────────────────────────────────────────────────────────────────────
  3425.    Return and Newline Are Different
  3426.    If you program in other languages on MS-DOS machines, you might expect \r
  3427.    (carriage return) to move the cursor to the start of a new line. Change
  3428.    the \n in TABS.C to \r and run the program again. What happens? Each line
  3429.    prints over the preceding one. Although many languages on MS-DOS machines
  3430.    incorporate a line feed in a carriage return, C treats newline and return
  3431.    as distinct operations. Return moves the cursor to the beginning of the
  3432.    current line but does not advance it to a new line. Newline causes output
  3433.    to start on the next line. It commences with output at the beginning of
  3434.    the next line (rather than directly below the old position) because MS-DOS
  3435.    interprets it as though it contains a carriage return as well.
  3436.    ──────────────────────────────────────────────────────────────────────────
  3437.  
  3438.    Notice the %d in our example, SCORE.C. This, as we have already mentioned,
  3439.    is the format specifier for a decimal integer. The string "The score after
  3440.    %d innings is" is followed by a comma and the variable inning. Thus, when
  3441.    the printf() statement executes, the string is printed with the value of
  3442.    inning. You can also print more than one value in the same string. For
  3443.    example, if you define int apples = 12, oranges = 9, pears = 3;, then
  3444.    execute the following printf() statement:
  3445.  
  3446.      printf("I have %d apples, %d oranges, and %d pears. \n", apples, oranges,
  3447.  
  3448.    you see the following output:
  3449.  
  3450.      I have 12 apples, 9 oranges, and 3 pears.
  3451.  
  3452.  Specifying Formats with printf()
  3453.  
  3454.    Variables are printed according to their type and the format specifiers
  3455.    used. One of the QuickC General help screens (Figure 3-7) shows format
  3456.    specifiers and additional symbols that can specify formats.
  3457.  
  3458.    The program SPECS.C (Listing 3-13 on the following page) prints different
  3459.    types of variables with their appropriate specifiers.
  3460.  
  3461.    ┌────────────────────────────────────────────────────────────────────────┐
  3462.    │ Figure 3-7 can be found on p.71 of the printed version of the book.    │
  3463.    └────────────────────────────────────────────────────────────────────────┘
  3464.  
  3465.    Figure 3-7. Format specifiers.
  3466.  
  3467.    ──────────────────────────────────────────────────────────────────────────
  3468.    /* specs.c -- shows printf()format   */
  3469.    /*            specifiers for numbers */
  3470.  
  3471.    main()
  3472.    {
  3473.        int    i = 122;       /* ASCII code for 'z' */
  3474.        long   l = 93000000;  /* distance to Sun (miles) */
  3475.        float  f = 192450.88; /* someone's bottom line */
  3476.        double d = 2.0e+030;  /* mass of Sun (kg.) */
  3477.  
  3478.        printf("%d\n", i);  /* integer as decimal */
  3479.        printf("%x\n", i);  /* integer as hex */
  3480.        printf("%ld\n", l); /* long */
  3481.        printf("%f\n", f);  /* float as decimal */
  3482.        printf("%e\n", f);  /* float as exponential */
  3483.        printf("%f\n", d);  /* double as decimal */
  3484.        printf("%e\n", d);  /* double as exponential */
  3485.    }
  3486.    ──────────────────────────────────────────────────────────────────────────
  3487.  
  3488.    Listing 3-13.  The SPECS.C program.
  3489.  
  3490.    Compare the following output with the printf() statements in the SPECS.C
  3491.    program:
  3492.  
  3493.      122
  3494.      7a
  3495.      93000000
  3496.      192450.875000
  3497.      1.924509e+005
  3498.      2000000000000000000000000000000.000000
  3499.      2.000000e+030
  3500.  
  3501.    The first printf() statement prints the value of the int variable i, 122,
  3502.    as an ordinary decimal integer, using the now familiar %d specifier. The
  3503.    next statement prints the same value with the %x specifier, which prints
  3504.    values in hexadecimal. Next, we print the long integer value 93000000.
  3505.    Notice that this specifier, %ld, combines the %l (long) and %d (integer)
  3506.    specifiers.
  3507.  
  3508.    The SPECS.C program then prints the value of the variable f, 192450.88,
  3509.    using the %f floating-point specifier. In the next statement, we use %e to
  3510.    print the same number in exponential notation. Which is better? If the
  3511.    value represents money, the regular decimal format is more appropriate,
  3512.    but remember that both representations are slightly inaccurate because the
  3513.    original value, 192450.88, has eight places and float has a maximum
  3514.    precision of seven places. (If you want absolute accuracy, use the double
  3515.    specifier.)
  3516.  
  3517.    We print the final value, 2,000,000,000,000,000,000,000,000,000,000, two
  3518.    ways: as a double (note that you can use %f for double as well as for
  3519.    float) and as exponential notation with %e. Clearly, the latter is easier
  3520.    to read and understand.
  3521.  
  3522.  Format Specifiers and Data Types
  3523.  
  3524.    Remember, the format specifier merely controls how a value is displayed.
  3525.    The data type of the value represents how it is actually stored in the
  3526.    computer. The program FORMATS.C (Listing 3-14) displays the comedy of
  3527.    errors that can occur if you carelessly use the wrong format specifier
  3528.    with a data type. The following is the output of the program; compare it
  3529.    with the printf() statements in the program.
  3530.  
  3531.      As integer:      5
  3532.      As long integer: 8519685
  3533.      As exponential:  7.084198e-309
  3534.      As float:        0.000000
  3535.  
  3536.    The program uses four different specifiers to print the value of the int
  3537.    variable i, which we set to 5. Only the first representation, using %d, is
  3538.    correct. The other results vary widely (even from one run to another). How
  3539.    can the last three methods be so far off the mark? Consider the second
  3540.    printf() statement, in which we told QuickC to print the value of i as a
  3541.    long integer %ld. A long integer uses four bytes of memory, but this
  3542.    variable, as an int type, uses only two. When you specify a long integer,
  3543.    QuickC takes four bytes starting at the address of i and converts them
  3544.    into a long integer. Two of these bytes, however, have nothing to do with
  3545.    the variable i. You can see how similar problems arise when we try to
  3546.    interpret an integer variable as a float. All of this demonstrates that
  3547.    the format specifier must be compatible with the data type being handled.
  3548.    Table 3-1 correlates the most commonly encountered specifiers and data
  3549.    types.
  3550.  
  3551.    ──────────────────────────────────────────────────────────────────────────
  3552.    /* formats.c -- shows what happens when format */
  3553.    /*              doesn't match data type        */
  3554.  
  3555.    main()
  3556.    {
  3557.        int i = 5;
  3558.        printf("As integer:      %d\n", i);
  3559.        printf("As long integer: %ld\n", i);
  3560.        printf("As exponential:  %e\n", i);
  3561.        printf("As float:        %f\n", i);
  3562.    }
  3563.    ──────────────────────────────────────────────────────────────────────────
  3564.  
  3565.    Listing 3-14.  The FORMATS.C program.
  3566.  
  3567.    Table 3-1. Compatibility of Specifiers and Data Types
  3568.    Specifier          Types
  3569.    ──────────────────────────────────────────────────────────────────────────
  3570.    %d                 int (signed or unsigned); char (ASCII value)
  3571.    %ld                long
  3572.    %f                 float or double (decimal format)
  3573.    %e                 float or double (exponential format)
  3574.    %c                 char (as character)
  3575.    ──────────────────────────────────────────────────────────────────────────
  3576.  
  3577.  Field Width Specifiers
  3578.  
  3579.    We can also improve the appearance of printf() output by controlling how
  3580.    many decimal places are printed and how the number is aligned in the
  3581.    output field. To do this, C lets us precede the format specifier with a
  3582.    "field specifier." The field specifier takes the following form:
  3583.  
  3584.      <field width>.<decimal places>
  3585.  
  3586.    The "field width" is the total number of character positions that will be
  3587.    printed, and "decimal places" is the number of places printed after the
  3588.    decimal point. (Use the decimal place specifier only for float and double
  3589.    values.) Following are two examples of field specifiers:
  3590.  
  3591.      "5.2f"────────────────────float; 5 places, 2 of which are decimal places
  3592.      "8d"───────────────────────────────integer; 8 places (no decimal places)
  3593.  
  3594.    The program FIELDS.C (Listing 3-15) shows how field width specifiers
  3595.    work.
  3596.  
  3597.    The program prints a single variable with varying field specifiers:
  3598.  
  3599.         123.456001────────────────────────────────────12.6f (field specifier)
  3600.      123.4560────────────────────────────────────────────────────────────8.4f
  3601.       123.456────────────────────────────────────────────────────────────8.3f
  3602.        123.46────────────────────────────────────────────────────────────8.2f
  3603.  
  3604.    In the first printf() statement, the field specifier %12.6f sets up a
  3605.    12-character-wide field, 6 characters of which are decimal places. Because
  3606.    the variable has only 10 characters to be printed (9 digits and a decimal
  3607.    point), printf() indents the number two spaces. By default, numbers are
  3608.    right-justified (printed starting in the rightmost position of the
  3609.    specified field width). To print numbers that start at the left side of
  3610.    the field (left-justified), put a minus sign in front of the field width
  3611.    specifier, "%-4.2f".
  3612.  
  3613.    ──────────────────────────────────────────────────────────────────────────
  3614.    /* fields.c -- shows the same number with different */
  3615.    /*             field widths and number of decimals  */
  3616.  
  3617.    main()
  3618.    {
  3619.        float f = 123.4560;
  3620.  
  3621.        printf("%12.6f\n", f);
  3622.        printf("%8.4f\n", f);
  3623.        printf("%8.3f\n", f);
  3624.        printf("%8.2f\n", f);
  3625.    }
  3626.    ──────────────────────────────────────────────────────────────────────────
  3627.  
  3628.    Listing 3-15.  The FIELDS.C program.
  3629.  
  3630.    Note also in the first printf() statement that we asked for six decimal
  3631.    places, even though the variable number contained only the first four
  3632.    places. Although printf() prints these extra places, they add nothing to
  3633.    the precision of the number, and, in fact, give a misleading impression of
  3634.    precision. You should specify decimal places only to the expected
  3635.    precision of the value. For example, if you know that a value will range
  3636.    between 0 and 9999 with decimal places, you might specify %4.3f because
  3637.    the value can have as many as four places to the left of the decimal
  3638.    point, and a float has only seven places of precision. Thus, a total of
  3639.    seven places (4.3) displays an accurate value. Specifying %8.6 for this
  3640.    example would give a false impression of precision.
  3641.  
  3642.    In the second statement, the specifier establishes a field width of 8
  3643.    (with 4 decimal places). The third statement specifies the same field
  3644.    width of 8, but with only 3 decimal places. Notice that the variable's
  3645.    fourth decimal place, the zero, is dropped, and that the number is
  3646.    indented one space because the variable has only 7 characters. The last
  3647.    statement specifies the same field width of 8, but with only 2 decimal
  3648.    places. The printf() function not only drops the third decimal place, it
  3649.    also rounds up the second decimal place to 6. Also, because the number has
  3650.    one fewer digit to fit in the 8-character field, printf() indents the
  3651.    number another space.
  3652.  
  3653.  
  3654.  Arithmetic Operators
  3655.  
  3656.    Like most languages, C offers a complete set of arithmetic operators: +
  3657.    (addition), - (subtraction), * (multiplication), and / (division). C also
  3658.    provides a fifth operator that is not quite as common in other languages──
  3659.    %, the remainder operator, sometimes called the "modulus" operator. This
  3660.    operator returns only the remainder of a division operation. For example,
  3661.    5 % 2 is 1 (5 divided by 2 has a remainder of 1), and 9 % 3 is 0 (9
  3662.    divided by 3 has no remainder).
  3663.  
  3664.    The modulus operator has many uses: You can use it for creating counters
  3665.    that cycle within counters or for resetting variables such as line counts
  3666.    by checking for a remainder of zero (if line_cnt % page_length = 0, then
  3667.    you know that you must start a new page).
  3668.  
  3669.    Operators are used with values to form expressions that yield new values.
  3670.    Below are some examples:
  3671.  
  3672.      10 * 5─────────────────────────────────────────────Multiply two literals
  3673.      a / 5─────────────────────────────────────────────Divide value of a by 5
  3674.      count + 1────────────────────────────────────────Add 1 to value of count
  3675.      (a * 80) + b──────────────Multiply value of a by 80, then add value of b
  3676.  
  3677.    In a program, you combine expressions with other elements to form
  3678.    statements. The MATH.C program (Listing 3-16 on the following page)
  3679.    contains statements that use expressions involving arithmetic operators.
  3680.  
  3681.    ──────────────────────────────────────────────────────────────────────────
  3682.    /* math.c -- shows arithmetic and       */
  3683.    /*           precedence via expressions */
  3684.  
  3685.    main()
  3686.    {
  3687.        int a = 10, b = 4, c = 2;
  3688.  
  3689.        /* simple arithmetic expressions */
  3690.        printf("99 + 2 = %d\n", 99 + 2);  /* ints */
  3691.        printf("5 - 12 = %d\n", 5 - 12);
  3692.        printf("7.25 + 3.5 = %f\n", 7.25 + 3.5);
  3693.                                            /* floats */
  3694.  
  3695.        /* compare precedence on these */
  3696.        printf("20 * 20 + 40 = %d\n", 20 * 20 + 40);
  3697.        printf("20 * (20 + 40) = %d\n", 20 * (20 + 40));
  3698.        printf("a * a - c + b =  %d\n", a * a - c + b);
  3699.        printf("a * (a - (c + b)) = %d\n",
  3700.                a * (a - (c + b)));
  3701.  
  3702.        /* compare integer and float division */
  3703.  
  3704.        printf("Integers: 5 / 2 = %d\n", 5 / 2);
  3705.        printf("Floats: 5.0 / 2.0 = %f\n", 5.0 / 2.0);
  3706.    }
  3707.    ──────────────────────────────────────────────────────────────────────────
  3708.  
  3709.    Listing 3-16.  The MATH.C program.
  3710.  
  3711.    Each printf() statement prints the expression and then its value, as
  3712.    follows:
  3713.  
  3714.      99 + 2 = 101
  3715.      5 - 12 = -7
  3716.      7.25 + 3.5 = 10.750000
  3717.      20 * 20 + 40 = 440
  3718.      20 * (20 + 40) = 1200
  3719.      a * a - c + b =  102
  3720.      a * (a - (c + b)) = 40
  3721.      Integers: 5 / 2 = 2
  3722.      Floats: 5.0 / 2.0 = 2.500000
  3723.  
  3724.    The first three statements simply add and subtract literal numbers and
  3725.    print the results. Notice in the third statement that when QuickC sees a
  3726.    number with a decimal point, it assumes a float type and prints the answer
  3727.    accordingly (10.750000).
  3728.  
  3729.  Operator Precedence
  3730.  
  3731.    The next set of statements in MATH.C illustrates "precedence," or the
  3732.    rules that determine the order in which operators are applied. Generally,
  3733.    QuickC performs multiplication and division first, then addition and
  3734.    subtraction. When operators have equal precedence (such as division and
  3735.    multiplication), QuickC performs them from left to right. The following
  3736.    QuickC help screen, Figure 3-8, lists all the operators in the language
  3737.    (including many covered in later chapters) and arranges them in groups
  3738.    from highest to lowest precedence.
  3739.  
  3740.    Thus, in Listing 3-16 the first printf() statement in the second group of
  3741.    statements multiplies 20 by 20, then adds 40, resulting in 440. However,
  3742.    you can use parentheses to impose a different order of precedence, as
  3743.    shown in the next statement. To evaluate the expression 20 * (20 + 40),
  3744.    QuickC performs the addition first (resulting in 60) and then multiplies
  3745.    20 by 60 to produce a value of 1200.
  3746.  
  3747.    The next two statements use combinations of variables. As an exercise,
  3748.    perform the calculations on paper before you run the program. Remember to
  3749.    observe the rules of precedence. Did your answers agree with QuickC's?
  3750.  
  3751.    The final two statements in MATH.C illustrate a common problem for the
  3752.    unwary beginning C programmer. QuickC divides integer and floating-point
  3753.    types differently. When you specify numbers as integers, as in the first
  3754.    statement, integer division is performed. Accordingly, 5 divided by 2 is 2
  3755.    because this type of division discards any remainder. (A remainder in
  3756.    division is a fraction, and int types cannot represent fractions.)
  3757.    However, when you specify numbers with decimal points, QuickC treats them
  3758.    as float types, resulting in the expected answer of 2.5. Variables of int
  3759.    and float types are handled the same way as the literals above.
  3760.  
  3761.    The RECEIPTS.C program (Listing 3-17 on the following page) performs
  3762.    practical calculations with QuickC's math operators. Notice that we
  3763.    declare the units variable as an int type (you can't sell half a unit!)
  3764.    and the price and tax rates as float types.
  3765.  
  3766.    ┌────────────────────────────────────────────────────────────────────────┐
  3767.    │ Figure 3-8 can be found on p.77 of the printed version of the book.    │
  3768.    └────────────────────────────────────────────────────────────────────────┘
  3769.  
  3770.    Figure 3-8. Operator precedence help screen.
  3771.  
  3772.    ──────────────────────────────────────────────────────────────────────────
  3773.    /* receipts.c -- calculates gross and net */
  3774.    /*               receipts on sales        */
  3775.  
  3776.    main()
  3777.    {
  3778.        int units = 38;       /* number sold */
  3779.        float price = 149.99, /* price per item */
  3780.        rate = 0.06;          /* sales tax rate */
  3781.  
  3782.        /* variables to hold calculated totals */
  3783.        float gross, tax, net;
  3784.  
  3785.        /* perform calculations */
  3786.        net = units * price;
  3787.        tax = net * rate;
  3788.        gross = net + tax;
  3789.  
  3790.        /* print results */
  3791.        printf("\tSales Report\n");
  3792.        printf("Net sales: \t%6.2f\n", net);
  3793.        printf("Tax:\t\t %5.2f\n", tax);
  3794.        printf("Gross sales:\t%6.2f\n", gross);
  3795.    }
  3796.    ──────────────────────────────────────────────────────────────────────────
  3797.  
  3798.    Listing 3-17.  The RECEIPTS.C program.
  3799.  
  3800.    The "calculations" section uses expressions to generate values for the
  3801.    variables net, tax, and gross. The printf() statements combine tab escape
  3802.    sequences \t and field width specifiers to align the output. Specify only
  3803.    two decimal places for money amounts. (Makes cents, doesn't it?) The
  3804.    program produces the following report:
  3805.  
  3806.              Sales Report
  3807.      Net sales:      5699.62
  3808.      Tax:             341.98
  3809.      Gross sales:    6041.60
  3810.  
  3811.  Arithmetic with Mixed Types
  3812.  
  3813.    The accuracy of a number generated by QuickC depends on its data type and
  3814.    the format in which it is printed. An additional problem arises when you
  3815.    perform arithmetic operations on literals (constants) or variables of
  3816.    different data types: For example, what happens when you divide an int by
  3817.    a float?
  3818.  
  3819.    For calculations with mixed data types, C ranks data types roughly
  3820.    according to the number of bytes of storage they require. From highest to
  3821.    lowest, they are:
  3822.  
  3823.      double  8 bytes
  3824.      float   4 bytes
  3825.      long    4 bytes
  3826.      int     2 bytes
  3827.      char    1 byte
  3828.  
  3829.    Generally, QuickC converts the lower-ranking type to the higher-ranking
  3830.    one before it performs the calculation. Thus, when QuickC divides 49 by
  3831.    12.5, it first converts 49 to 49.0 (a float), then performs the division.
  3832.    (If QuickC chose a lower-ranking type, the calculation would lose
  3833.    precision. The above calculation, for example, would be 49 / 12 = 4 in
  3834.    integer division.) Although the long and float types both use four bytes,
  3835.    a float can contain a fractional part that would be lost when converted
  3836.    "down" to a long: Therefore, float is ranked as the "higher" type.
  3837.    Finally, QuickC converts float types to double types before it calculates
  3838.    the result.
  3839.  
  3840.    Although it's convenient that QuickC performs conversions for you, some
  3841.    real problems can occur if you assign the results of a calculation to a
  3842.    variable of an incorrect data type. The following example illustrates such
  3843.    a mistake:
  3844.  
  3845.      int sales, units = 50;
  3846.      float price = 1.99;
  3847.      sales = units * price;
  3848.      printf("Total sales are %d\n", sales);
  3849.  
  3850.    QuickC calculates price * units correctly by converting units from 50 to
  3851.    50.0 (to make it a float), and then multiplying it by the float value of
  3852.    price (1.99). The value of the expression is now the float value of 99.50.
  3853.    So far, so good. However, we assigned this value to the variable sales,
  3854.    which we declared as an int type. As a result, the fractional part of the
  3855.    value (.50) is dropped, making the value of sales an incorrect 99.00. The
  3856.    solution to this problem is simple──consider all of the potential values
  3857.    for a variable before you declare it. In this case, you need to declare
  3858.    the variable sales as a float.
  3859.  
  3860.    QuickC can help remind you of potential problems with data type
  3861.    conversions. When you select the Compile option from the Run menu, the
  3862.    left side of the dialog box lists four levels of compiler warning messages
  3863.    (levels 0 through 3). If you select level 2 before you compile programs,
  3864.    QuickC sends a warning message for each program statement that causes a
  3865.    data type conversion. A typical message follows:
  3866.  
  3867.      warning C4051: (1 of 4)
  3868.      data conversion
  3869.  
  3870.    When you see this type of message, note the statement the cursor is on,
  3871.    examine the data types involved, and look up the meaning of warning (4051)
  3872.    in the Microsoft QuickC Programmer's Guide. There you will note that this
  3873.    is an advisory message, and QuickC issues it for perfectly legitimate
  3874.    conversions, such as the int to float conversion in our earlier division
  3875.    example.
  3876.  
  3877.    The MIXED.C program (Listing 3-18 on the following page) shows more
  3878.    examples of operations with mixed data types.
  3879.  
  3880.    ──────────────────────────────────────────────────────────────────────────
  3881.    /* mixed.c -- shows the effects of mixing */
  3882.    /*            data types in an expression */
  3883.  
  3884.    main()
  3885.    {
  3886.        int     i = 50, iresult;
  3887.        long    l = 1000000, lresult;
  3888.        float   f = 10.5, fresult;
  3889.        double  d = 1000.005, dresult;
  3890.  
  3891.        fresult = i + f;         /* int + float to float */
  3892.        printf("%f\n", fresult);
  3893.  
  3894.        fresult = i * f;         /* int * float to float */
  3895.        printf("%f\n", fresult);
  3896.  
  3897.        lresult = l + i;         /* long + int to long */
  3898.        printf("%ld\n", lresult);
  3899.  
  3900.        printf("%f\n", d * f);   /* double * float */
  3901.                                     /* to double */
  3902.        fresult = d * f;         /* assigned to a float */
  3903.        printf("%f\n", fresult); /* loses some precision */
  3904.  
  3905.        /* debugging a division problem */
  3906.  
  3907.        iresult = i / l;          /* int / long to int*/
  3908.        printf("%d\n", iresult);  /* whoops! loses result */
  3909.        printf("%ld\n", iresult); /* this won't fix it */
  3910.        fresult = i / l;          /* store in float result */
  3911.        printf("%f\n", fresult);  /* doesn't work */
  3912.        dresult = i / l;          /* try a double */
  3913.        printf("%f\n", dresult);  /* doesn't work */
  3914.        fresult = (float) i / l;  /* try type cast */
  3915.        printf("%f\n", fresult);  /* correct result */
  3916.    }
  3917.    ──────────────────────────────────────────────────────────────────────────
  3918.  
  3919.    Listing 3-18.  The MIXED.C program.
  3920.  
  3921.    Compare this output to the program statements:
  3922.  
  3923.      60.500000
  3924.      525.000000
  3925.      1000050
  3926.      10500.052500
  3927.      10500.052734
  3928.      0
  3929.      8519680
  3930.      0.000000
  3931.      0.000000
  3932.      0.000050
  3933.  
  3934.    The first set of statements adds an int and a float value and prints the
  3935.    result, which is 60.5, a float value. This shows QuickC's default type
  3936.    conversion at work. The second set of statements shows the same conversion
  3937.    with a multiplication operation. The third pair of statements adds a long
  3938.    to an int. Note that the result is correct (100,000 + 50 = 100,050), and,
  3939.    from its size, you can guess that it must be a long. QuickC converts the
  3940.    value 50 to a long before it does the calculation.
  3941.  
  3942.    Next, the program works with double and float types. When we specify d * f
  3943.    in the printf() statement, QuickC converts the float value f to a double
  3944.    and calculates a double result, which we print. (Remember, you can use the
  3945.    %f format specifier with either float or double types.) Because the answer
  3946.    requires nine places of precision, converting from float to double
  3947.    preserves the accuracy of the value.
  3948.  
  3949.    Next, we perform the same calculation, but we assign the result to a float
  3950.    value, f. Notice that the result, 10,500.052734, becomes inaccurate
  3951.    starting at the fourth decimal place. Converting from double to float can
  3952.    produce both large and subtle errors, depending on the numbers involved.
  3953.    To be safe, use a double variable to hold the result of this type of
  3954.    calculation.
  3955.  
  3956.    The last lengthy set of statements illustrates various approaches for
  3957.    dividing an int value i by a long value l. Only the last method produces
  3958.    the correct result.
  3959.  
  3960.    Assigning the result of the division to an int variable returns a 0,
  3961.    because the result is a very small decimal fraction (50 / 1,000,000), and
  3962.    integer division does not recognize remainders.
  3963.  
  3964.    In the next statement we assume that the result of the division is a
  3965.    decimal fraction and that we can store it in a float. But this doesn't
  3966.    work either. When we add more decimal places by using a double variable
  3967.    for the result, we still get a result of 0. The problem here is that when
  3968.    the two integer variables i and l are divided, the integer portion of the
  3969.    result, 0.000050, is 0. At this point, we can't retrieve the decimal
  3970.    fraction. Assigning it to a float or a double merely gives you a
  3971.    floating-point representation of 0!
  3972.  
  3973.  Type Casting
  3974.  
  3975.    C provides a solution to our division dilemma with a construction called a
  3976.    "type cast." A type cast explicitly converts a value to a specified type
  3977.    before any operations are done on that value. Consider the following
  3978.    example:
  3979.  
  3980.      int i1 = 10, i2 = 3;
  3981.      printf("%d\n", i1 / i2);
  3982.      printf("%f\n", (float) i1 / i2);
  3983.  
  3984.    In the first printf() statement, we divide the two integers and produce
  3985.    the integer result of 3. In the second printf() statement, we add (float)
  3986.    before i1. This is the type cast: It converts the value of i1 to a float.
  3987.    Because a type cast has a higher precedence than the arithmetic operators,
  3988.    it converts i1 to a float before the division operation. Now the division
  3989.    operation contains a float and an int! QuickC's default type conversion
  3990.    then converts i2 to a float as well, and the result is the float value
  3991.    3.33333. If you look at the last two statements of the MIXED.C program,
  3992.    you can see we used a type cast in the same way, with the correct result
  3993.    of 0.000050.
  3994.  
  3995.    Type casts are useful for handling variables of lower-ranking data types
  3996.    (int, for example) that must occasionally be used in calculations to
  3997.    produce a result of a "higher" type (such as float). It is more efficient
  3998.    in terms of both storage and processing time to declare such variables as
  3999.    the lower type and to use type casts when necessary. Later, you will find
  4000.    type casts valuable when you must convert values to a specific type.
  4001.  
  4002.  
  4003.  Getting Input with scanf()
  4004.  
  4005.    In order to write programs that have real-world utility, we must first
  4006.    understand how a C program gets input from the user. The all-purpose C
  4007.    function for getting input and storing it in a variable is called scanf().
  4008.    (Like printf(), scanf() is a "built-in" QuickC core library function.)
  4009.    Figure 3-9 shows how it works.
  4010.  
  4011.    Let's assume we have a program with a declared integer variable named
  4012.    acct_no. When the scanf() statement executes, the program waits for input
  4013.    from the user. After the user types the number and a carriage return, the
  4014.    input is stored in the variable acct_no, as if it had been assigned by an
  4015.    assignment statement. Notice that the acct_no variable in the scanf()
  4016.    argument list is preceded by an ampersand (&). Do you remember when we
  4017.    placed ampersands in front of variable names in the VARADDRS.C program
  4018.    (Listing 3-4 on p. 57) to retrieve the storage addresses of the
  4019.    variables? The scanf() function requires as its second argument an address
  4020.    at which it can store the input. The & returns the address of the
  4021.    following variable. If you omit the address operator from the front of the
  4022.    variable name, the value of the variable is interpreted as though it were
  4023.    an address, and the input is stored at that address. This can produce
  4024.    frightful results if it overwrites information that your program needs!
  4025.  
  4026.     Format specifier for
  4027.     type of value wanted
  4028.             │
  4029.            ┌┴┐
  4030.    scanf ("%d", &acct_no);
  4031.                 │└────┬─┘
  4032.                 │     │
  4033.        "address of"   Variable name
  4034.       └─────────────┬──────────────┘
  4035.                     │
  4036.         Variable to store input in
  4037.  
  4038.    Figure 3-9. Parts of a scanf() statement.
  4039.  
  4040.    The first argument in the scanf() statement in Figure 3-9 is "%d". This
  4041.    looks and works like the format specifiers we used with printf()──it
  4042.    specifies the type of the value that the program expects. As with
  4043.    printf(), the "%d" specifies an integer. You can also use most of the
  4044.    other specifiers you used with printf(). For example:
  4045.  
  4046.      scanf("%f", &deposit);
  4047.  
  4048.    gets a value for the float variable deposit.
  4049.  
  4050.    Notice that scanf(), by itself, does not print a prompt for the user; it
  4051.    merely presents the user with a blinking cursor. Therefore, you should
  4052.    precede a scanf() statement with a printf() statement that tells the user
  4053.    what information to supply. In the example above, we might precede the
  4054.    scanf() statement with:
  4055.  
  4056.      printf("How much is your deposit?");
  4057.  
  4058.    The cursor now appears following a space after the prompt. You don't need
  4059.    to include a newline character: The cursor will move to the next line when
  4060.    the user presses Enter after typing the input.
  4061.  
  4062.    You can also use scanf() to get values for more than one variable at a
  4063.    time:
  4064.  
  4065.      printf("What is your age and weight?");
  4066.      scanf("%d %d", &age &weight);
  4067.  
  4068.    In this example, the user types an age, a space (to separate the values),
  4069.    and then a weight. Note that the user can substitute an Enter or a Tab for
  4070.    the space.
  4071.  
  4072.    The CONVERT.C program (Listing 3-19) uses scanf() to prompt a user for a
  4073.    temperature in Fahrenheit and then converts the temperature to Centigrade.
  4074.  
  4075.    ──────────────────────────────────────────────────────────────────────────
  4076.    /* convert.c  -- converts Fahrenheit temperature     */
  4077.    /*               to Centigrade; gets value from user */
  4078.  
  4079.    main()
  4080.    {
  4081.        float ftemp, ctemp;
  4082.  
  4083.        printf("What is the temperature in Fahrenheit? ");
  4084.        scanf("%f", &ftemp);
  4085.        ctemp = (ftemp - 32.0) * 5 / 9.0;
  4086.  
  4087.        printf("The temperature in Centigrade is %5.2f", ctemp);
  4088.    }
  4089.    ──────────────────────────────────────────────────────────────────────────
  4090.  
  4091.    Listing 3-19.  The CONVERT.C program.
  4092.  
  4093.    A sample user dialog with CONVERT.C follows:
  4094.  
  4095.      What is the temperature in Fahrenheit? 87
  4096.      The temperature in Centigrade is 30.56
  4097.  
  4098.    We print the prompt with a printf() statement, then use a scanf()
  4099.    statement with a floating-point specifier %f to get the input value for
  4100.    the float variable ftemp.
  4101.  
  4102.    The AVGTEMP.C program (Listing 3-20) averages the daily high temperatures
  4103.    for a week. When you run the program, it prompts for the high temperature
  4104.    for each day of the week, beginning with Monday.
  4105.  
  4106.    ──────────────────────────────────────────────────────────────────────────
  4107.    /* avgtemp.c -- finds average temperature */
  4108.    /*              for the week              */
  4109.  
  4110.    main()
  4111.    {
  4112.        int t1, t2, t3, t4, t5, t6, t7;
  4113.        float avg;
  4114.  
  4115.        printf("Enter the high temperature for:\n");
  4116.        printf("Monday: ");
  4117.        scanf("%d", &t1);
  4118.        printf("Tuesday: ");
  4119.        scanf("%d", &t2);
  4120.        printf("Wednesday: ");
  4121.        scanf("%d", &t3);
  4122.        printf("Thursday: ");
  4123.        scanf("%d", &t4);
  4124.        printf("Friday: ");
  4125.        scanf("%d", &t5);
  4126.        printf("Saturday: ");
  4127.        scanf("%d", &t6);
  4128.        printf("Sunday: ");
  4129.        scanf("%d", &t7);
  4130.  
  4131.        /* calculate and display average */
  4132.        avg = (t1 + t2 + t3 + t4 + t5 + t6 + t7) / 7.0;
  4133.              /* divide by 7.0 to ensure float result */
  4134.        printf("The average high temperature for");
  4135.        printf(" this week was %5.2f degrees.\n", avg);
  4136.    }
  4137.    ──────────────────────────────────────────────────────────────────────────
  4138.  
  4139.    Listing 3-20.  The AVGTEMP.C program.
  4140.  
  4141.    The int variables t1 through t7 store the daily high temperatures, which
  4142.    are obtained by a series of scanf() statements. The program then
  4143.    calculates an average and prints it out. A sample dialog with this program
  4144.    might look as follows:
  4145.  
  4146.      Enter the high temperature for:
  4147.      Monday: 82
  4148.      Tuesday: 91
  4149.      Wednesday: 97
  4150.      Thursday: 104
  4151.      Friday: 95
  4152.      Saturday: 88
  4153.      Sunday: 78
  4154.      The average high temperature for this week was 90.71 degrees.
  4155.  
  4156.    Note: It is important to note that scanf() does not check to make certain
  4157.    that the input is compatible with the data type of the variable in which
  4158.    it is stored.
  4159.  
  4160.  
  4161.  Shortcut Assignments, Increments, and Decrements
  4162.  
  4163.    Now that you know how to assign a value to a variable with the assignment
  4164.    operator = and how to use arithmetic operators to calculate new values, we
  4165.    can show you a few tricks and shortcuts. In the course of a program, it is
  4166.    often useful to add a value to a variable repeatedly or to subtract a
  4167.    value from a variable repeatedly. For example, a program that counts lines
  4168.    needs to add one to a variable (such as total_lines) each time it counts a
  4169.    new line. We could do this as follows:
  4170.  
  4171.      total_lines = total_lines + 1;
  4172.  
  4173.    That's the way most languages do it. However, because changing the value
  4174.    of a variable is such a common occurrence in programming, C provides
  4175.    special, concise "arithmetic assignment operators" for the purpose.
  4176.  
  4177.  Arithmetic Assignment Operators
  4178.  
  4179.    The arithmetic operators are the +, -, *, /, and %, and the assignment
  4180.    operator is the =. The arithmetic assignment operator, as the name
  4181.    suggests, is a combination of an arithmetic operator and the assignment
  4182.    operator: for example, +=. When a statement executes, QuickC performs the
  4183.    specified arithmetic on the variable's value and then assigns the result
  4184.    of the calculation to the variable as its new value. Using an arithmetic
  4185.    assignment operator, we can write a shorter version of the statement that
  4186.    increases the value of total_lines by one:
  4187.  
  4188.      total_lines += 1;
  4189.  
  4190.    Below are more examples that use arithmetic assignment operators:
  4191.  
  4192.      count -= 1;───────────────────────────Subtract 1 from the value of count
  4193.      fare += 0.75;──────────────────────────────────Add 0.75 to value of fare
  4194.      value *= 10;────────────────────────────────────────Multiply value by 10
  4195.  
  4196.    You can use any arithmetic operator in an arithmetic assignment operation.
  4197.    Table 3-2 lists the five possible arithmetic assignment operators. The
  4198.    addition and subtraction assignment operators are the most commonly used.
  4199.  
  4200.    The OPEQUAL.C program (Listing 3-21) demonstrates the use of arithmetic
  4201.    assignment statements. The printf() statements print several arithmetic
  4202.    assignment expressions and their results.
  4203.  
  4204.    Be sure that when you read the printf() statements in the program you can
  4205.    correctly predict the following output:
  4206.  
  4207.      Starting values: m = 10 n = 5
  4208.      m += 2 makes m 12
  4209.      m -= n makes m 7
  4210.      m *= 2 makes m 14
  4211.      m = m + 1 makes m 15
  4212.      m += 1 makes m 16
  4213.  
  4214.    Table 3-2. Arithmetic Assignment Operators
  4215.    Operator           Meaning
  4216.    ──────────────────────────────────────────────────────────────────────────
  4217.    +=                 Add to value and assign
  4218.    -=                 Subtract from value and assign
  4219.    *=                 Multiply by value and assign
  4220.    /=                 Divide by value and assign
  4221.    %=                 Get remainder from division and assign
  4222.    ──────────────────────────────────────────────────────────────────────────
  4223.  
  4224.    ──────────────────────────────────────────────────────────────────────────
  4225.    /* opequal.c -- shows combination math/assignment */
  4226.    /*              operators and increment operators */
  4227.    main()
  4228.    {
  4229.        int m = 10, n = 5;
  4230.        printf("Starting values: m = %d n = %d\n",
  4231.                m, n);
  4232.  
  4233.        /* combination of arithmetic and assignment */
  4234.        printf("m += 2 makes m %d\n", m += 2);
  4235.        printf("m -= n makes m %d\n", m -= n);
  4236.        printf("m *= 2 makes m %d\n", m *= 2);
  4237.  
  4238.        /* two ways to increment m */
  4239.        printf("m = m + 1 makes m %d\n",
  4240.                m = m + 1);
  4241.        printf("m += 1 makes m %d\n",
  4242.                m += 1);
  4243.    }
  4244.    ──────────────────────────────────────────────────────────────────────────
  4245.  
  4246.    Listing 3-21.  The OPEQUAL.C program.
  4247.  
  4248.  Increment and Decrement Operators
  4249.  
  4250.    As the last program demonstrated, both m = m + 1 and m += 1 added one to
  4251.    the value of m. If you've done any programming, you know how frequently
  4252.    the value of a variable must be increased or decreased by one. This is
  4253.    especially true when you create a "counter" variable that keeps track of
  4254.    the number of times a statement in a loop executes. C provides an
  4255.    ultra-concise operator, the increment operator ++, to add one to the value
  4256.    of a variable. Similarly, --, the decrement operator, subtracts one from
  4257.    the value of a variable. Consider the following examples:
  4258.  
  4259.      count++ ;────────────────────────────────────────Add 1 to value of count
  4260.      index-- ;─────────────────────────────────Subtract 1 from value of index
  4261.  
  4262.    Note that these increment and decrement operators are really arithmetic
  4263.    assignment statements. They add (or subtract) one and assign the resulting
  4264.    value to the variable.
  4265.  
  4266.      count++;──────────────────is equivalent to───────────────────count += 1;
  4267.      index--;──────────────────is equivalent to───────────────────index -= 1;
  4268.  
  4269.    (Most programmers do not use a space between the increment [or decrement]
  4270.    operator and the variable name. However, in C it is perfectly legal to use
  4271.    intervening spaces, as in count + +.) INCDEC.C (Listing 3-22) shows how
  4272.    the increment and decrement operators change the value of a variable.
  4273.    Compare the program statements to the following output:
  4274.  
  4275.      a is 10
  4276.      ++a is 11
  4277.      --a sets a back to 10
  4278.  
  4279.    ──────────────────────────────────────────────────────────────────────────
  4280.    /* incdec.c -- shows effect of            */
  4281.    /*             increments and decrements  */
  4282.  
  4283.    main()
  4284.    {
  4285.        int a = 10;
  4286.  
  4287.        printf("a is %d\n", a);
  4288.        printf("++a is %d\n", ++a);
  4289.        printf("--a sets a back to %d\n", --a);
  4290.    }
  4291.    ──────────────────────────────────────────────────────────────────────────
  4292.  
  4293.    Listing 3-22.  The INCDEC.C program.
  4294.  
  4295.  Pre-increment vs Post-increment
  4296.  
  4297.    In the INCDEC.C program we put the increment or decrement operator in
  4298.    front of the variable name. However, you also can use it after the
  4299.    variable name. In either case the variable is incremented or decremented;
  4300.    but there is one important difference. When you use the operator in front
  4301.    of a variable name, the incrementing or decrementing is done immediately.
  4302.    When you use the operator after the variable name, the incrementing or
  4303.    decrementing is not done until the next use of the variable. The PREPOST.C
  4304.    program (Listing 3-23) shows how this works. The output of the program
  4305.    illustrates how incrementing is delayed:
  4306.  
  4307.      b is 100
  4308.      b++ is still 100
  4309.      but after it's used, b is incremented to 101
  4310.  
  4311.      ++b, on the other hand, is immediately 102
  4312.  
  4313.    Notice what happens to b when we use the increment operator after it,
  4314.    rather than before it. The first printf() statement with the value b++
  4315.    prints the original value of 100, showing that it has not yet been
  4316.    incremented. The next printf() statement, however, prints 101.
  4317.  
  4318.    As a practical matter, the distinction between pre-increments and
  4319.    post-increments (or decrements) is usually important only when the
  4320.    variable is incremented or decremented while it is being used with other
  4321.    operators in a single expression. For example, suppose you want to
  4322.    increment counter and also assign it to total in the same statement.
  4323.    Assuming counter is currently 10:
  4324.  
  4325.      total = counter++;
  4326.  
  4327.    assigns 10 to total, because counter is assigned to total but not
  4328.    incremented until the next time it is used. On the other hand:
  4329.  
  4330.      total = ++counter;
  4331.  
  4332.    assigns 11 to total, because counter is incremented immediately and then
  4333.    assigned.
  4334.  
  4335.    ──────────────────────────────────────────────────────────────────────────
  4336.    /* prepost.c -- shows effect of pre- */
  4337.    /*              and post-increments  */
  4338.    /*              and decrements       */
  4339.  
  4340.    main()
  4341.    {
  4342.        int b = 100;
  4343.  
  4344.        printf("b is %d\n", b);
  4345.        printf("b++ is still %d\n", b++);
  4346.        printf("but after it's used, ");
  4347.        printf("b is incremented to %d\n\n", b);
  4348.  
  4349.        printf("++b, on the other hand, ");
  4350.        printf("is immediately %d\n", ++b);
  4351.    }
  4352.    ──────────────────────────────────────────────────────────────────────────
  4353.  
  4354.    Listing 3-23.  The PREPOST.C program.
  4355.  
  4356.  
  4357.  Relational Operators
  4358.  
  4359.    If you have some programming experience, you know that most programs must
  4360.    make decisions based on the values of certain variables. Variables are
  4361.    tested or compared, and the result of the test determines which program
  4362.    statement will execute next. The next two chapters cover the variety of
  4363.    "control structures" that C provides for this purpose. Let's build the
  4364.    foundation for those discussions by looking at the operators that C uses
  4365.    for testing or comparing values.
  4366.  
  4367.    A relational operator compares two values, which can be variables, literal
  4368.    numbers, or whole expressions. A combination of relational operators and
  4369.    values is called a relational expression. An example is count > 10, which
  4370.    translates as "is the value of count greater than 10?" The > in this
  4371.    expression is the "greater than" relational operator. The expression is
  4372.    true or false depending on the current value of the variable count. If
  4373.    count is 8, for example, the expression is false.
  4374.  
  4375.    Table 3-3 illustrates the ways we can compare two values, a and b. In
  4376.    reality, the values can be constants, variables, or expressions──anything
  4377.    that expresses a numeric value. (Remember from our discussion of ASCII
  4378.    that characters, too, are essentially numeric values.)
  4379.  
  4380.    We described the value of a relational expression as being "true" or
  4381.    "false." These terms are useful ways for us to follow the logic of a
  4382.    program, but the actual value of a relational statement, like everything
  4383.    else in the computer, is numeric. When a statement is true, its value is
  4384.    1; when a statement is false, its value is 0. On the following page, the
  4385.    RELATION.C program (Listing 3-24) uses printf() statements to show the
  4386.    values of some statements that use relational operators.
  4387.  
  4388.    The program generates the following output:
  4389.  
  4390.      a = 5    b = 3   c = 4
  4391.      Expression a > b has a value of 1
  4392.      Expression a == c has a value of 0
  4393.      Expression a > (b + c) has a value of 0
  4394.  
  4395.    Because a is 5 and b is 3, the expression a > b has a value of 1, or true.
  4396.    Because c is 4, a == c has a value of 0, or false. The third expression
  4397.    combines relational and arithmetic operators: It first calculates the
  4398.    quantity (b + c), and then it compares the value to a.
  4399.  
  4400.    Table 3-3. Relational Operators
  4401.    Expression               Meaning
  4402.    ──────────────────────────────────────────────────────────────────────────
  4403.    a < b                    Is a less than b?
  4404.    a > b                    Is a greater than b?
  4405.    a == b                   Is a equal to b?
  4406.    a != b                   Is a not equal to b?
  4407.    a <= b                   Is a less than or equal to b?
  4408.    a >= b                   Is a greater than or equal to b?
  4409.    ──────────────────────────────────────────────────────────────────────────
  4410.  
  4411.    ──────────────────────────────────────────────────────────────────────────
  4412.    /* relation.c  -- shows effect of      */
  4413.    /*                relational operators */
  4414.  
  4415.    main()
  4416.    {
  4417.        int a = 5, b = 3, c = 4;
  4418.        printf("a = %d\t b = %d\t c = %d\n", a, b, c);
  4419.  
  4420.        printf("Expression a > b has a value of %d\n",
  4421.                a > b);
  4422.        printf("Expression a == c has a value of %d\n",
  4423.                a == c);
  4424.        printf("Expression a > (b + c) has a value of %d\n",
  4425.                a > (b + c));
  4426.        printf("Expression a = b has a value of %d\n",
  4427.                a = b); /* what happened here? */
  4428.    }
  4429.    ──────────────────────────────────────────────────────────────────────────
  4430.  
  4431.    Listing 3-24.   The RELATION.C program.
  4432.  
  4433.  Relational == vs Assignment =
  4434.  
  4435.    Here's a pitfall to watch out for: In C, a single equal sign = is the
  4436.    assignment operator, but a double equal sign == is the relational "equals"
  4437.    operator. In some languages (such as BASIC), a single operator, =, serves
  4438.    both purposes. So, if you are familiar with the BASIC usage, you might
  4439.    make errors with these operators until you get used to the difference. A
  4440.    common symptom of this error is a test that always appears to be either
  4441.    true or false. For example, if you type the assignment count = 10 instead
  4442.    of the relational count == 10 and then use the result in a control
  4443.    structure (such as a loop or if statement), QuickC always sees the result
  4444.    of the test as "true." Why? Because although relational expressions return
  4445.    a value of 1 for "true," QuickC considers any nonzero value to be "true"
  4446.    in this type of test. Because the sample statement with = is actually an
  4447.    assignment, its value is 10 (the number assigned), which QuickC interprets
  4448.    as "true" during a relational test.
  4449.  
  4450.    ──────────────────────────────────────────────────────────────────────────
  4451.    Assignment and "Equals" Relation
  4452.    The following table lets you compare the assignment and relational
  4453.    "equals" operators in C to those in other common languages:
  4454.  
  4455.      Language               Assignment              Relation
  4456.      ──────────────────────────────────────────────────────────────────────
  4457.      C
  4458.      =
  4459.      ==
  4460.      BASIC                  =                       =
  4461.      Pascal                 :=                      =
  4462.      FORTRAN                =                       .EQ.
  4463.      Logo                   make                    =
  4464.      COBOL                  MOVE                    EQUAL TO
  4465.      ──────────────────────────────────────────────────────────────────────
  4466.  
  4467.      ────────────────────────────────────────────────────────────────────────
  4468.  
  4469.  Precedence of Relational Operators
  4470.  
  4471.    In RELATION.C, we used parentheses in the expression a > (b + c). If you
  4472.    check QuickC's operator precedence help screen (Figure 3-8 on p. 77), you
  4473.    will see that relational operators have a lower precedence than arithmetic
  4474.    operators. Therefore, even if you don't use parentheses, b + c is
  4475.    calculated first, and only then is the result compared to a. Nevertheless,
  4476.    it is a good programming practice to use parentheses to visually clarify
  4477.    an expression.
  4478.  
  4479.  
  4480.  Logical Operators
  4481.  
  4482.    Sometimes it is necessary or useful to test for more than one thing in the
  4483.    same expression or statement. For example, you might want to test to see
  4484.    if either the temperature or pressure in a boiler has exceeded the safety
  4485.    limit. Let's assume the test for temperature is (temp < 900) and the test
  4486.    for pressure is (pressure < 5000). We can combine the two tests as
  4487.    follows:
  4488.  
  4489.      (temp < 900) && (pressure < 5000)
  4490.  
  4491.    The && is called the AND logical operator. It compares the results of two
  4492.    relational values and returns a value of true (1) only if both are true.
  4493.    QuickC first makes the temp test, then it makes the pressure test (testing
  4494.    is from left to right). Then the && operator checks to see if both tests
  4495.    were true.
  4496.  
  4497.    The OR logical operator, ||, works like the AND operator, except that it
  4498.    returns a value of true (1) if either or both of the tests are true. Thus,
  4499.    the statement
  4500.  
  4501.      (ch == 'q') || (turn > last_turn)
  4502.  
  4503.    is true if either the current value of ch is `q' or the current value of
  4504.    turn is greater than that of last_turn, or both. You could use this
  4505.    statement to check if a game is over.
  4506.  
  4507.    Using two relational operators, && and ||, and two possible results of a
  4508.    test (true and false), there are four possible results for a relational
  4509.    statement involving two tests. The TRUTH.C program (Listing 3-25 on the
  4510.    following page) prints these out by making comparisons using ones and
  4511.    zeros that represent the result of already completed relational tests.
  4512.    Recall that QuickC regards a value of 1 to be "true" and a value of 0 to
  4513.    be "false." Thus, 1 AND 1 is 1 means "True and true is true."
  4514.  
  4515.      1 AND 1 is 1
  4516.      1 AND 0 is 0
  4517.      0 AND 0 is 0
  4518.      1 OR 1 is 1
  4519.      1 OR 0 is 1
  4520.      0 OR 0 is 0
  4521.  
  4522.    ──────────────────────────────────────────────────────────────────────────
  4523.    /* truth.c -- shows logical operators */
  4524.    main()
  4525.    {
  4526.        printf("1 AND 1 is %d\n", 1 && 1);
  4527.        printf("1 AND 0 is %d\n", 1 && 0);
  4528.        printf("0 AND 0 is %d\n", 0 && 0);
  4529.        printf("1 OR 1 is %d\n",  1 || 1);
  4530.        printf("1 OR 0 is %d\n",  1 || 0);
  4531.        printf("0 OR 0 is %d\n",  0 || 0);
  4532.    }
  4533.    ──────────────────────────────────────────────────────────────────────────
  4534.  
  4535.    Listing 3-25.  The TRUTH.C program.
  4536.  
  4537.    Once again, if you check the QuickC operator precedence help screen, you
  4538.    will notice that logical operators, such as && and ||, have a lower
  4539.    precedence than the relational operators, such as < or ==. Therefore, we
  4540.    didn't need parentheses around the relational expressions in our examples
  4541.    because QuickC evaluated them before it checked the logical operators.
  4542.    Again, we used parentheses because they make these complex expressions
  4543.    easier to read.
  4544.  
  4545.    The last operator we need to discuss is the !, or "not" operator. Its
  4546.    function is simple enough──it reverses the truth value of a relational
  4547.    expression. For example, if a is 10, a > 5 is true, but !(a > 5) is false.
  4548.  
  4549.  
  4550.  
  4551.  ────────────────────────────────────────────────────────────────────────────
  4552.  Chapter 4  Repetition and Looping
  4553.  
  4554.    In all of our programs so far, QuickC has executed the program statements
  4555.    sequentially, from the first statement to the end of the program. However,
  4556.    most of a program's important work involves controlled repetition, in
  4557.    which a group of statements repeatedly does a particular job until the
  4558.    work is done. For example, consider the data-entry routine of a database
  4559.    program. This group of statements (used to receive, validate, and store
  4560.    data) must be repeated as long as the user wants to enter new data
  4561.    records. This set of repeating statements is called a loop because it is
  4562.    executed as though the statements were arranged in a circle. However, when
  4563.    the user wants to stop entering data, the program must be able to
  4564.    recognize a "quit" command and stop repeating the data-entry statements.
  4565.  
  4566.    As you study C, you will find many other examples of the need for
  4567.    controlled repetition. For example, a program that retrieves data from a
  4568.    file must repeatedly read and process data items until it reaches the end
  4569.    of the file. If you program in another language, you probably use loops
  4570.    regularly to initialize and access elements of an array or a set of
  4571.    variables.
  4572.  
  4573.    C uses three types of loops: the for loop, the while loop, and the do
  4574.    loop. Although these loops are fundamentally similar, they let you control
  4575.    the looping action in different ways to suit different needs. This chapter
  4576.    focuses on how to use these three types of loops and some of their common
  4577.    variations.
  4578.  
  4579.  
  4580.  The for Loop
  4581.  
  4582.    The for loop repeats a group of program statements as long as a specified
  4583.    condition is true. Generally, you use it to specify a fixed number of
  4584.    repetitions: for example, processing the accounts for each month of the
  4585.    year.
  4586.  
  4587.    The anatomy of a for loop is as follows:
  4588.  
  4589.      for (start; condition; update)
  4590.          {
  4591.          statements;
  4592.          }
  4593.  
  4594.    In this generalized for loop, start is one or more statements that
  4595.    initialize the variables used by the loop; condition is a relational
  4596.    expression that is tested to see whether the loop should continue to run;
  4597.    and update is one or more statements that change the values of variables
  4598.    in the loop. The group of statements between the braces that follow the
  4599.    for line is called the "body" of the loop. These statements execute as
  4600.    long as the condition in the parentheses is true. (The body can also
  4601.    consist of only one statement, in which case the braces are optional. We
  4602.    tend to use braces for even a single statement, however, because they make
  4603.    the body of the loop easier to distinguish.)
  4604.  
  4605.    The FORLOOP.C program (Listing 4-1) uses a for loop to count from 1 to
  4606.    10. After we declare the variable i, we begin the loop structure with the
  4607.    keyword for. The parentheses that follow the for contain the control
  4608.    statements for the loop. Note that semicolons separate the control
  4609.    statements.
  4610.  
  4611.    ──────────────────────────────────────────────────────────────────────────
  4612.    /* forloop.c -- a simple for loop that   */
  4613.    /*              counts to ten            */
  4614.  
  4615.    main()
  4616.    {
  4617.         int i;
  4618.         for (i = 1; i <= 10; i++)
  4619.              {
  4620.              printf("%d\n", i); /* body of loop */
  4621.              }
  4622.         printf("All done!\n");  /* executed when i > 10 */
  4623.    }
  4624.    ──────────────────────────────────────────────────────────────────────────
  4625.  
  4626.    Listing 4-1.  The FORLOOP.C program.
  4627.  
  4628.    The start statement establishes the variable i as the loop's control
  4629.    variable. This is the variable whose value is tested to determine when the
  4630.    loop will stop running. (Many people use i, j, or k for loop control
  4631.    variables. This tradition owes its roots to FORTRAN. However, any legal
  4632.    name will do.)
  4633.  
  4634.    The next statement, i <= 10, is the loop's test, or condition. It
  4635.    specifies that the body of the loop execute repeatedly as long as the
  4636.    value of i is less than or equal to 10. The test condition is a relational
  4637.    statement that compares the loop control variable to an assigned value and
  4638.    returns a value of 1 (true) or 0 (false).
  4639.  
  4640.    The last statement in the for loop parentheses is i++. This update
  4641.    statement changes the value of the loop control variable each time the
  4642.    loop body executes. Here we use the ++ increment operator to increase i by
  4643.    one each time it executes, and, in fact, most for loops use update
  4644.    statements that either increment or decrement the control value by one.
  4645.    Using values other than one, however, is almost as easy: The statement
  4646.    value += 10, for example, adds 10 to value each time it executes. You can
  4647.    also use multiplication or division rather than addition or subtraction.
  4648.  
  4649.    Let's step through FORLOOP.C one statement at a time to see how it works:
  4650.  
  4651.    ■  Set i to 1.
  4652.  
  4653.    ■  Check i to see if it is less than or equal to 10.
  4654.  
  4655.    ■  Because the result of this test is true, execute the body of the loop.
  4656.       (The body consists of a printf() statement that prints the value of i.)
  4657.  
  4658.    ■  Execute the update statement, i++. (Set i to i + 1, or 2.)
  4659.  
  4660.    ■  Check the test statement again to see if i is still less than or equal
  4661.       to 10. If it is, execute the body of the loop again. Continue the cycle
  4662.       until the test condition is false (when the value of i increases to
  4663.       11).
  4664.  
  4665.    Figure 4-1 on the following page shows this program as a flowchart. You
  4666.    can follow the arrows to trace the flow of execution.
  4667.  
  4668.    ──────────────────────────────────────────────────────────────────────────
  4669.    Choosing a Control Variable
  4670.    If you are used to writing loops in BASIC, remember that with C, you must
  4671.    declare the loop control variable before you use it in the loop. Select a
  4672.    data type for the control variable that can accommodate the full range of
  4673.    values the variable will hold when the loop is run.
  4674.  
  4675.    For example, a loop that will run 50,000 times requires a control variable
  4676.    of type unsigned int because a signed int value cannot exceed 32,767.
  4677.    ──────────────────────────────────────────────────────────────────────────
  4678.  
  4679.       ┌────────────────┐
  4680.       │  Initialize    │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4681.       │     i = 1      │                          ┌─────────▒─────────────────
  4682.       └───────┼────────┘                          │° for (i = 1; i <= 10; i++°
  4683.               │                                   │°               ▒       ▒ °
  4684.                          ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒{▒▒▒▒▒▒▒▒▒▒       ▒ °
  4685.               /\          ▒                    │°     printf("%d\n", i);▒ °
  4686.             /    \ ▒▒▒▒▒▒▒                     │°     }        ▒        ▒ °
  4687.           /  TEST  \    No                      │°              ▒        ▒ °
  4688.    ┌───/  i <= 10   \ ──────       END        │°              ▒        ▒ °
  4689.    │    \           /                          │°              ▒        ▒ °
  4690.    │      \  ?   /                            │°              ▒        ▒ °
  4691.    │        \   /                             │°              ▒        ▒ °
  4692.    │          \/                                  │°              ▒        ▒ °
  4693.    │          │ Yes                               └───────────────▒────────▒──
  4694.    │  ┌───────────────┐                                          ▒        ▒
  4695.      │Do body of loop │                                          ▒        ▒
  4696.    │  │  print f...    │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒        ▒
  4697.    │  └───────┬────────┘                                                   ▒
  4698.    │          │                                                            ▒
  4699.    │  ┌───────────────┐                                                   ▒
  4700.    │  │  Add 1 to i    │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4701.    │  └───────┬────────┘
  4702.    │          │
  4703.    └─────────┘
  4704.  
  4705.    Figure 4-1. The for loop.
  4706.  
  4707.    Why does the loop stop running? Let's look at the situation when i = 10:
  4708.    The printf() statement in the body of the loop prints the number 10. The
  4709.    update statement then increments the loop by 1 and the test statement
  4710.    executes. Because the value of i is now 11, the test fails (returns a
  4711.    value of "false"). This causes the program to skip the loop body and
  4712.    execute the next statement, which prints the message All done!
  4713.  
  4714.  for Loop Style
  4715.  
  4716.    As with other C statements, the statements within the parentheses of a for
  4717.    loop can extend to more than one line if necessary. As noted in our
  4718.    discussion of conventions, we align the braces vertically for the loop
  4719.    body, as shown in FORLOOP.C. An older style aligns the braces as follows:
  4720.  
  4721.      for (i = 1; i <= 10; i++) {
  4722.          printf("%d\n",i);
  4723.      }
  4724.  
  4725.    With this style, the braces can get lost in a long listing, making it
  4726.    difficult to find where the body of the loop begins and ends. Aligning the
  4727.    braces vertically makes them easier to spot and highlights the body of the
  4728.    loop.
  4729.  
  4730.    Also note that we indent the body of a C loop to the right of the line
  4731.    that specifies it. To indent text in the QuickC editor, simply press the
  4732.    Tab key. The default indention in QuickC is eight characters, but you can
  4733.    change this value at the Options box of the View menu. We use a tab of
  4734.    four characters in our listings.
  4735.  
  4736.    Pitfalls to Avoid in for Loops
  4737.  
  4738.    An easy mistake to make when writing for loops is to put a semicolon after
  4739.    the closing parenthesis:
  4740.  
  4741.      for (i = 1; i <= 10; i++);───────────────────────────────Semicolon added
  4742.  
  4743.    This does not cause a compiler error: In C, a semicolon by itself is a
  4744.    "null statement." Such a statement does nothing, but it counts as a legal
  4745.    statement. Using a semicolon after the parenthesis makes the null
  4746.    statement the body of the loop. Adding the semicolon to FORLOOP.C causes
  4747.    the loop to do "nothing" 10 times; the program then prints the value of i
  4748.    (which is 11 after the loop exits) and All Done!
  4749.  
  4750.    Also, always remember to put braces before and after a loop body that
  4751.    consists of more than one statement. If you do not use braces, only the
  4752.    first statement following the parentheses executes as the body of the
  4753.    loop. The remaining statements will execute only once, after the loop
  4754.    terminates. (This is another reason for adopting the practice of always
  4755.    putting braces around the statements in a loop body, even when the body
  4756.    has only one statement.)
  4757.  
  4758.  Multistatement for Loops
  4759.  
  4760.    FORLOOP.C has only one statement in the body of the loop, but most
  4761.    programs are much more complex. Let's develop a program that will print a
  4762.    table of square roots, squares, and cubes for the integers from 1 through
  4763.    9. Because this program must calculate and print three values for each
  4764.    number, it needs several statements in the body of the for loop.
  4765.  
  4766.    Using QuickC Library Functions
  4767.  
  4768.    To write such a program, we need a means of producing the square root of a
  4769.    number. Although C does not have operators for calculating squares or
  4770.    cubes directly, we can get these values simply by multiplying a variable
  4771.    by itself two and three times respectively. To get the square root,
  4772.    however, we must call on QuickC's sqrt() function. This function returns
  4773.    the square root of any value you pass to it. For example, if i = 4, then
  4774.    sqrt(i) = 2.
  4775.  
  4776.    The square root function, sqrt(), is an example of a QuickC library
  4777.    function (sometimes called a "library routine"). We've already used
  4778.    several QuickC "core" functions, such as printf() and scanf(). Because
  4779.    these functions are part of the QuickC environment, you can use them
  4780.    without any special commands. (Appendix B lists all the built-in core
  4781.    functions.)
  4782.  
  4783.    ──────────────────────────────────────────────────────────────────────────
  4784.    Quick Tip
  4785.    Sometimes it is convenient to break out of a loop during its execution.
  4786.    Perhaps you recognize a problem with its output, or perhaps you find
  4787.    yourself in a runaway loop──one whose test will not or cannot fail. To
  4788.    break out of a loop, press Ctrl-Break.
  4789.    ──────────────────────────────────────────────────────────────────────────
  4790.  
  4791.    However, sqrt() is not on this list. It is one of many library routines
  4792.    that are defined in the header files (often called "include files") of the
  4793.    \INCLUDE directory. One of the early tasks in learning QuickC is becoming
  4794.    familiar with its external library functions. Fortunately, QuickC makes it
  4795.    easy to explore the function library.
  4796.  
  4797.    QuickC's extensive on-line help screens let you call up a summary of any
  4798.    function to find out whether it is a core function or an external library
  4799.    function. To find out about sqrt(), select Topic from the Help menu. Next,
  4800.    select the appropriate topic, math; this produces a list of library
  4801.    functions that include the sqrt() function. When you select this function,
  4802.    a small help window appears at the top of the QuickC screen. (See Figure
  4803.    4-2.) The first entry in this window informs you that sqrt() resides in
  4804.    both the float.h and math.h include files.
  4805.  
  4806.    QuickC also lets you browse through include files while you are working on
  4807.    a program. Simply select Include from the View menu, select the \INCLUDE
  4808.    directory from the window (if necessary), and then select the include file
  4809.    you want to view. When you finish, select Open Last File from the File
  4810.    menu, and QuickC returns you to the program you were working on.
  4811.  
  4812.    Of course, the preferred reference for all QuickC library functions is the
  4813.    Microsoft QuickC Run-Time Library Reference, one of the manuals that come
  4814.    with QuickC. It introduces the library functions by category.
  4815.  
  4816.    ┌────────────────────────────────────────────────────────────────────────┐
  4817.    │ Figure 4-2 can be found on p.98 of the printed version of the book.    │
  4818.    └────────────────────────────────────────────────────────────────────────┘
  4819.  
  4820.    Figure 4-2. Library function help window.
  4821.  
  4822.    Using an Include File in a Program
  4823.  
  4824.    To use functions or other definitions from an include file in your
  4825.    program, you must specify the name of the file you want to call before the
  4826.    start of main(). For example:
  4827.  
  4828.      #include <graph.h>
  4829.  
  4830.    includes the file that contains graphics functions and definitions in your
  4831.    program. (The angle brackets that enclose the filename tell QuickC to look
  4832.    for the file in the default \INCLUDE directory, whose pathname the setup
  4833.    procedure stored in the environmental variable INCLUDE.) This statement is
  4834.    actually a "directive" to the QuickC preprocessor, a program that examines
  4835.    your C program code and looks for special commands that tell it to make
  4836.    changes in the program text before compilation begins. In this case, the
  4837.    #include preprocessor directive reads the contents of the specified
  4838.    include file into the program and compiles it as though you had typed it
  4839.    in. Only after it reads and compiles all the include files does QuickC
  4840.    compile your program statements. Note that preprocessor statements such as
  4841.    #include are not actually C language statements and do not end with a
  4842.    semicolon.
  4843.  
  4844.    Creating a Program List
  4845.  
  4846.    We have seen that we need to use a #include statement if we want to refer
  4847.    to the sqrt() function in the program we want to run, TABLE.C (Listing
  4848.    4-2). In addition, before we compile the program, we need to tell QuickC
  4849.    where to find the compiled library code that corresponds to the definition
  4850.    of sqrt() in the include file math.h. We can do this by creating what is
  4851.    called a "program list." To do this, first select Set Program List from
  4852.    the File menu. In the dialog window (Figure 4-3 on the following page),
  4853.    type in the name of your program followed by the extension .mak. (Thus,
  4854.    for TABLE.C you type table.mak.) Next, select Edit Program List from the
  4855.    File menu.
  4856.  
  4857.    ──────────────────────────────────────────────────────────────────────────
  4858.    /* table.c -- prints square root, square, and cube */
  4859.    /*            for the numbers 1 thru 9             */
  4860.  
  4861.    #include <math.h> /* include math functions so we  */
  4862.                          /*  can do square root       */
  4863.  
  4864.    main()
  4865.    {
  4866.         int i;
  4867.         printf("i\t sqrt(i)\tsquare(i)\tcube(i)\n\n");
  4868.         for (i = 1; i < 10; i++)
  4869.              /* beginning of body of loop */
  4870.              {
  4871.              printf("%d\t", i);
  4872.              printf("%f\t", sqrt(i));
  4873.              printf("%d\t\t", i * i);
  4874.              printf("%d\n", i * i * i);
  4875.              }
  4876.              /* end of body of loop */
  4877.    }
  4878.    ──────────────────────────────────────────────────────────────────────────
  4879.  
  4880.    Listing 4-2.  The TABLE.C program.
  4881.  
  4882.    The dialog window, shown in Figure 4-4, lists all the C programs in the
  4883.    current directory. Select TABLE.C from the window with the mouse or
  4884.    keyboard, and then select the Add/Remove button. Finally, select the Save
  4885.    button to save the edited program list. You are now ready to run TABLE.C.
  4886.  
  4887.    ┌────────────────────────────────────────────────────────────────────────┐
  4888.    │ Figure 4-3 can be found on p.100 of the printed version of the book.   │
  4889.    └────────────────────────────────────────────────────────────────────────┘
  4890.  
  4891.    Figure 4-3. Set Program List dialog window.
  4892.  
  4893.    ┌────────────────────────────────────────────────────────────────────────┐
  4894.    │ Figure 4-4 can be found on p.100 of the printed version of the book.   │
  4895.    └────────────────────────────────────────────────────────────────────────┘
  4896.  
  4897.    Figure 4-4. Edit Program List dialog window.
  4898.  
  4899.    We use the #include <math.h> statement before the definition of the main()
  4900.    function to tell QuickC to use the math.h include file in the program. A
  4901.    printf() statement then prints the table header. Because we only want to
  4902.    print the header once, we don't place this statement inside the loop!
  4903.  
  4904.    Next comes the for loop. The loop specifications establish the test
  4905.    condition as i < 10 and the update as increments of 1.
  4906.  
  4907.    The body of the loop consists of four printf() statements: The first
  4908.    prints the value of i; the next three print, in order, the square root,
  4909.    the square, and the cube for each value. The program results in the
  4910.    following neatly formatted table:
  4911.  
  4912.      i        sqrt(i)        square(i)        cube(i)
  4913.      1        1.000000       1                1
  4914.      2        1.414214       4                8
  4915.      3        1.732051       9                27
  4916.      4        2.000000       16               64
  4917.      5        2.236068       25               125
  4918.      6        2.449490       36               216
  4919.      7        2.645751       49               343
  4920.      8        2.828427       64               512
  4921.      9        3.000000       81               729
  4922.  
  4923.  Multiple Initializations and Calculations in for Loops
  4924.  
  4925.    An almost universal rule in C states that anywhere you can put a single C
  4926.    statement, you can put multiple statements. For example, in a for loop,
  4927.    you can initialize two variables in the first part of the loop
  4928.    specification, as follows:
  4929.  
  4930.      for (count = 1, total = 0; count < values; count++)
  4931.          {
  4932.          total += count;
  4933.          }
  4934.  
  4935.    Here we initialize the for loop by setting the loop control variable count
  4936.    to 1. At the same time, we set the variable total to zero. This loop adds
  4937.    all the integers between 1 and the number specified in values. Note that a
  4938.    comma separates the two statements in the initialization: Semicolons
  4939.    separate the three parts of the loop specification (start or
  4940.    initialization, test, and update); however, commas separate multiple
  4941.    statements within each part.
  4942.  
  4943.    ──────────────────────────────────────────────────────────────────────────
  4944.    Quick Tip
  4945.    If you want QuickC to search for a file in the current directory instead
  4946.    of the default include directory, enclose the filename in quotes: #include
  4947.    "graph.h". If you want QuickC to search another directory, specify the
  4948.    full pathname: #include "c:\qc\mydefs\defs.h".
  4949.    ──────────────────────────────────────────────────────────────────────────
  4950.  
  4951.    You can also use multiple calculations in the update portion of the loop
  4952.    specification. For example, we can rewrite the above loop as follows:
  4953.  
  4954.      for (count = 1, total = 0; count < values;
  4955.          total += count, count++)
  4956.          {;}
  4957.  
  4958.    Here we moved the statement that added each new value of count to total
  4959.    out of the loop body and put it in the update part of the loop
  4960.    specification. However, a loop must have a body to be legal, so we added a
  4961.    single semicolon (a null statement) as the loop body. (The null statement
  4962.    is somewhat dangerous because you might accidentally delete the stray
  4963.    semicolon. We try to avoid this by indenting the semicolon to the loop
  4964.    body position. We also enclose the semicolon in braces. The braces are
  4965.    unnecessary, but they help to emphasize the importance of the semicolon in
  4966.    the loop structure.)
  4967.  
  4968.    The use of multiple statements and null bodies in loops is a matter of
  4969.    programming style. Many C programmers try to be as concise as possible, so
  4970.    you will often encounter these usages in C code. We present these variants
  4971.    to acquaint you with common C programming practices; you gain no
  4972.    performance advantage by doing all initializations and calculations within
  4973.    the loop specification.
  4974.  
  4975.    The INFLATE.C program (Listing 4-3) is another example that uses multiple
  4976.    initializations and calculations. At first glance, you might think that
  4977.    the braces in the for loop have been forgotten or misplaced.
  4978.  
  4979.    ──────────────────────────────────────────────────────────────────────────
  4980.    /* inflate.c -- shows multiple initialization */
  4981.    /*              and calculations in for loop  */
  4982.  
  4983.    main()
  4984.    {
  4985.         int year;
  4986.         float value, rate;
  4987.         printf("What do you think the inflation rate will be?");
  4988.         scanf("%f", &rate);
  4989.         printf("If the dollar is worth 100 cents in 1987\n");
  4990.         printf("and the inflation rate is %2.2f, then:\n", rate);
  4991.  
  4992.         for (year = 1988, value = 1.0; year <= 1999;
  4993.             value *= (1.0 - rate),
  4994.             printf("in %d the dollar will be worth", year),
  4995.             printf(" %2.0f cents\n", value * 100), ++ year)
  4996.             {;}
  4997.    }
  4998.    ──────────────────────────────────────────────────────────────────────────
  4999.  
  5000.    Listing 4-3.  The INFLATE.C program.
  5001.  
  5002.    The program asks you to estimate the average inflation rate for the next
  5003.    decade or so. (We're sure your guess is as good as ours!) If you enter
  5004.    .06, the program generates the following:
  5005.  
  5006.      What do you think the inflation rate will be? .06
  5007.      If the dollar is worth 100 cents in 1987
  5008.      and the inflation rate is 0.06, then:
  5009.      in 1988 the dollar will be worth 94 cents
  5010.      in 1989 the dollar will be worth 88 cents
  5011.      in 1990 the dollar will be worth 83 cents
  5012.      in 1991 the dollar will be worth 78 cents
  5013.      in 1992 the dollar will be worth 73 cents
  5014.      in 1993 the dollar will be worth 69 cents
  5015.      in 1994 the dollar will be worth 65 cents
  5016.      in 1995 the dollar will be worth 61 cents
  5017.      in 1996 the dollar will be worth 57 cents
  5018.      in 1997 the dollar will be worth 54 cents
  5019.      in 1998 the dollar will be worth 51 cents
  5020.      in 1999 the dollar will be worth 48 cents
  5021.  
  5022.    The program uses scanf() to obtain the estimated inflation rate. Then it
  5023.    prints the introduction to the table and enters a for loop. Because the
  5024.    table prints yearly values, we call the loop control variable year. (Note,
  5025.    by the way, that control variables need not start at 0 or 1.) The
  5026.    initialization part of the loop also sets value to 1.0. (In other words,
  5027.    the dollar starts at its full value.) The test part of the loop causes the
  5028.    printing of values for the years 1988 through 1999.
  5029.  
  5030.    The update part of the loop specification does the work of this loop──the
  5031.    loop has a null body. Each year the current value is multiplied by 1.0 -
  5032.    rate to show the effects of inflation. The arithmetic assignment operator,
  5033.    *=, causes this new amount to become the new value. The printf()
  5034.    statements print the amount in cents by first multiplying value by 100;
  5035.    the format specifier %2.0f rounds it off to whole cents. Finally, ++year
  5036.    increments year, and the loop is ready for another pass.
  5037.  
  5038.    ──────────────────────────────────────────────────────────────────────────
  5039.    A for Loop Using Characters
  5040.    Because the PC's ASCII character set is merely a set of integer values
  5041.    from 0 to 255, a for loop can process characters as easily as it does
  5042.    ordinary integers. For example, the int control variable can be
  5043.    initialized by setting it to the character value `a'. There is no problem
  5044.    with this, because `a' is simply the integer value 97. Then, by specifying
  5045.    a loop test condition such as i <= `m', you determine that the body of the
  5046.    loop will be repeated 13 times, once for each letter in the first half of
  5047.    the alphabet.
  5048.    ──────────────────────────────────────────────────────────────────────────
  5049.  
  5050.  Nesting for Loops
  5051.  
  5052.    Sometimes it is useful to have one of the statements in the body of a loop
  5053.    be another loop. This is called nesting loops. For example, you might
  5054.    design a program to read a disk data file that is arranged so that each
  5055.    line contains four data fields. An "outer" loop could process each line,
  5056.    and an "inner" loop could process each field. The outline for this program
  5057.    might be:
  5058.  
  5059.      open_file(name);
  5060.      for (line = 1; line <= last_line; line++)
  5061.          {
  5062.          for (field = 1; field <= 4; field++)
  5063.              {
  5064.              process_field;
  5065.              }
  5066.          }
  5067.      save_file(name);
  5068.  
  5069.    The first, or outer, loop uses the control variable line and the test line
  5070.    <= last_line to read each line of the file in turn. (In this example, we
  5071.    assume that the number of lines in the file has been previously
  5072.    determined.) The inner for loop uses the control variable field to step
  5073.    through the four fields of each line. The body of this nested loop calls
  5074.    the function process_field to do the actual reading of data. When the last
  5075.    field in the line is processed, the inner loop exits. Because we are still
  5076.    in the body of the outer loop, the outer loop continues by moving to the
  5077.    next line; then the inner loop runs again. Only when the inner loop runs
  5078.    for the last line do the nested loop structure and the save_file()
  5079.    statement execute.
  5080.  
  5081.    Our next sample program, GRAPHBOX.C (Listing 4-4 on page 106), uses
  5082.    several for loops, including a pair of nested ones, to draw a box on the
  5083.    screen using PC graphics characters.
  5084.  
  5085.    As we mentioned earlier, the IBM PC uses the ASCII values from 128 to 255
  5086.    to represent the "extended character set," which includes many shapes that
  5087.    you can use to create effective graphics. To find the appropriate
  5088.    characters for drawing a box, select the help screens for ASCII characters
  5089.    from the Help menu (or press the F1 key). The second of the two screens
  5090.    contains the extended characters. For example, with character number 201
  5091.    you can draw the upper-left corner of the box.
  5092.  
  5093.    To display these characters, you must use the QuickC core library function
  5094.    called putch(). Call the function by specifying the ASCII code of the
  5095.    desired character in parentheses. For example, to draw the corner
  5096.    character mentioned above, specify:
  5097.  
  5098.      putch(201);
  5099.  
  5100.    Using #define
  5101.  
  5102.    Our box-drawing program uses many different characters to represent the
  5103.    corners and sides of the box, plus the newline, return, and blank
  5104.    characters. Remembering the ASCII codes for all these characters is a
  5105.    difficult task, and relying on memory could lead to coding mistakes. But C
  5106.    has a feature that helps eliminate this problem.
  5107.  
  5108.    C provides a mechanism for assigning symbolic names to frequently used
  5109.    values in a program. The preprocessor directive #define lets you specify a
  5110.    name and assign a value to it, as in the following example:
  5111.  
  5112.      #define UPLEFT 201
  5113.  
  5114.    Before QuickC compiles your program, the preprocessor finds each
  5115.    occurrence of the name UPLEFT and replaces it with the number 201. You
  5116.    remember the name; QuickC remembers the number. You can also use #define
  5117.    with characters. If you use the definition #define color "green" and you
  5118.    use the statement printf(color); in your program, the preprocessor
  5119.    translates the statement into printf("green"); before QuickC compiles it.
  5120.  
  5121.    Always place #define statements before the definition of main(), and do
  5122.    not end them with a semicolon. (If you use a semicolon, the preprocessor
  5123.    will treat it as part of the value to be substituted. This often leads to
  5124.    a bug that causes a compiler error.)
  5125.  
  5126.    You can use #define to make your code more readable by substituting
  5127.    easy-to-remember names for numbers. For example, you could use NL for the
  5128.    newline character instead of 10, the newline ASCII value. Also, #define
  5129.    makes it easy to change many values in a program without having to change
  5130.    many individual statements.
  5131.  
  5132.    ──────────────────────────────────────────────────────────────────────────
  5133.    #define vs Variables
  5134.    You might ask why you should use #define when you could do the same thing
  5135.    more easily with ordinary variables. After all, you could declare int nl =
  5136.    10; and then use putch(nl); (to simplify punctuation) and thereby avoid
  5137.    the preprocessor step. But there are two reasons why this isn't a good
  5138.    idea.
  5139.  
  5140.    First, using #define produces more efficient code than does using a
  5141.    variable. When your program uses variables, QuickC must compile extra
  5142.    machine instructions to store, change, or fetch the needed values. With
  5143.    #define, on the other hand, the preprocessor compiles the values directly
  5144.    into the compiled code: The program doesn't need any extra instructions.
  5145.    As a result, your compiled code is faster and more compact.
  5146.  
  5147.    Second, a variable should represent a quantity that is subject to change
  5148.    by the program. The ASCII value 10 for a newline character, however, is a
  5149.    constant. Using #define guarantees that the value you define cannot
  5150.    accidentally be changed while the program is running.
  5151.  
  5152.    Incidentally, the new ANSI C standard creates the keyword const to let you
  5153.    avoid #define directives. Using the new keyword, you might declare const
  5154.    int nl = 10; to define the constant nl.
  5155.    ──────────────────────────────────────────────────────────────────────────
  5156.  
  5157.    ──────────────────────────────────────────────────────────────────────────
  5158.    /* graphbox.c -- defined to use PC-specific graphics characters */
  5159.  
  5160.    #define NL 10
  5161.    #define CR 13
  5162.    #define BLANK 32
  5163.    #define UPLEFT 201
  5164.    #define UPRIGHT 187
  5165.    #define LOWLEFT 200
  5166.    #define LOWRIGHT 188
  5167.    #define LINE 205
  5168.    #define SIDE 186
  5169.  
  5170.    main()
  5171.    {
  5172.         int i, j, height, width;
  5173.  
  5174.         /* get height and width from user */
  5175.         printf("How high a box do you want? ");
  5176.         scanf("%d", &height);
  5177.         printf("How wide do you want it to be? ");
  5178.         scanf("%d", &width);
  5179.  
  5180.         /* draw top of box */
  5181.         putch(UPLEFT);
  5182.         for (i = 0; i < (width - 2); i++)
  5183.              putch(LINE);
  5184.         putch(UPRIGHT);
  5185.         putch(NL);
  5186.         putch(CR); /* go to next line */
  5187.  
  5188.         /* draw sides of box */
  5189.         for (i = 0; i < (height - 2); i++)  /* outer loop */
  5190.              {
  5191.              putch(SIDE); /* left side */
  5192.              for (j = 0; j < (width - 2); j++) /* inner loop */
  5193.                   {
  5194.                   putch(BLANK);
  5195.                   }
  5196.              putch(SIDE); /* right side */
  5197.              putch(NL);
  5198.              putch(CR); /* move to next line */
  5199.              }
  5200.  
  5201.         /* draw bottom of box */
  5202.         putch(LOWLEFT);
  5203.         for (i = 0; i < (width - 2); i++)
  5204.              putch(LINE);
  5205.         putch(LOWRIGHT);
  5206.         putch(NL);
  5207.         putch(CR); /* box is done, move cursor to new line */
  5208.    }
  5209.    ──────────────────────────────────────────────────────────────────────────
  5210.  
  5211.    Listing 4-4.  The GRAPHBOX.C program.
  5212.  
  5213.    To continue with the previous example, if you convert your program to run
  5214.    on a mainframe that uses a non-ASCII character set, you need only to
  5215.    change the value of NL in the #define statement to reflect the new
  5216.    character value throughout the program.
  5217.  
  5218.    When you run the GRAPHBOX.C program, it asks:
  5219.  
  5220.      How high a box do you want? 8──────────────────────Enter height in lines
  5221.      How wide do you want it to be? 20──────────────Enter width in characters
  5222.  
  5223.    Figure 4-5 shows the graphics box that this program generates on your
  5224.    screen.
  5225.  
  5226.    ╔═══════════════════╗
  5227.    ║                   ║
  5228.    ║                   ║
  5229.    ║                   ║
  5230.    ║                   ║
  5231.    ║                   ║
  5232.    ║                   ║
  5233.    ║                   ║
  5234.    ╚═══════════════════╝
  5235.  
  5236.    Figure 4-5. Character graphics box produced by GRAPHBOX.C.
  5237.  
  5238.    The program begins with nine #define statements that name the needed
  5239.    characters and their values. The first section of main() prompts the user
  5240.    for a height and width. Then a putch() displays the character for the
  5241.    upper-left corner of the box. Next, a for loop prints a graphics
  5242.    double-line character width - 2 times. (We print two less than width
  5243.    characters to leave room for the upper-left and upper-right corner
  5244.    characters.)
  5245.  
  5246.    The third section of main() draws the sides of the box. After subtracting
  5247.    the top and bottom lines, we want to print height - 2 lines: This is
  5248.    provided for by the test statement in the next for loop. For each line,
  5249.    the program prints the SIDE character (the double bar) and then uses a
  5250.    nested for loop to print width - 2 blank characters to position the cursor
  5251.    at the right side of the box. Another SIDE character completes the line;
  5252.    then an NL and a CR move the cursor to the next line.
  5253.  
  5254.    The statements that print the bottom line are the same as those that
  5255.    printed the top line, except that they use the special characters for the
  5256.    lower-left and lower-right corners of the box.
  5257.  
  5258.  
  5259.  The while Loop
  5260.  
  5261.    C contains another loop structure, called the while loop, which takes the
  5262.    following general form:
  5263.  
  5264.      while (test)
  5265.          {
  5266.          statements;
  5267.          }
  5268.  
  5269.    Structurally, the while loop is a for loop with only the test part of the
  5270.    specification, its condition, in parentheses. You initialize loop
  5271.    variables in a statement before the while, and you update or increment the
  5272.    loop with a statement in the loop body. Thus, although the for loop
  5273.    features compactness and holds the entire loop specification in the
  5274.    parentheses, the while loop is easier to read because the parentheses
  5275.    contain only the test expression. The WHILE.C program (Listing 4-5 at the
  5276.    bottom of the page) shows a simple example.
  5277.  
  5278.    The program produces the following output:
  5279.  
  5280.      1
  5281.      2
  5282.      3
  5283.      4
  5284.      5
  5285.      6
  5286.      7
  5287.      8
  5288.      9
  5289.      10
  5290.      Done!
  5291.  
  5292.    The statement int count = 1; declares and initializes the loop control
  5293.    variable. At the while statement, the condition count < 11 is tested.
  5294.    Because it is true, the body of the loop executes. The body consists of a
  5295.    printf() statement that prints the current value of count, and the
  5296.    statement count++; which increments count. The test condition is then
  5297.    checked again, and the loop continues printing numbers until count reaches
  5298.    11. At this point the test fails, the loop terminates, and the statement
  5299.    printf("Done!\n"); executes. Figure 4-6 shows a flowchart of this while
  5300.    loop.
  5301.  
  5302.    ──────────────────────────────────────────────────────────────────────────
  5303.    /* while.c -- a simple while loop */
  5304.  
  5305.    main()
  5306.    {
  5307.         int count = 1;
  5308.  
  5309.         while (count < 11)  /* loop condition */
  5310.              /* body of loop */
  5311.              {
  5312.              printf("%d\n", count);
  5313.              count++;
  5314.              }
  5315.         printf("Done!\n");
  5316.    }
  5317.    ──────────────────────────────────────────────────────────────────────────
  5318.  
  5319.    Listing 4-5.  The WHILE.C program.
  5320.  
  5321.    At this point you might ask why you need while statements if they are
  5322.    merely variant forms of for loops. The answer is simple. A for loop is
  5323.    designed to work with a specific series of values (such as numbers from 1
  5324.    to 10 or 1 to total_lines), and it usually counts up or down. A while
  5325.    loop, however, is designed to run indefinitely as long as some condition
  5326.    remains true. It also can test many kinds of conditions.
  5327.  
  5328.    For example, suppose you want to write a program that draws endlessly
  5329.    changing graphic patterns until the user presses a key to stop it. A while
  5330.    loop is ideal for this purpose when used with the QuickC library function
  5331.    kbhit(), which returns a 1 (true) if a key is pressed and a 0 (false) if
  5332.    no key is pressed. (A loop that waits for some external event to take
  5333.    place is called a "polling loop.") The main loop of your graphics program
  5334.    might appear as follows:
  5335.  
  5336.      while (!kbhit())
  5337.          {
  5338.          draw statements;
  5339.          }
  5340.  
  5341.    The draw statements create the graphics while the test part of the while
  5342.    loop specification polls the keyboard. As long as the user does not press
  5343.    a key, the kbhit() function returns a 0, or false. Notice that we use an
  5344.    !, which is the "logical not" operator, in front of kbhit(). "Not false"
  5345.    is the same as "true," so the test for the while loop is satisfied and the
  5346.    body of the loop executes as long as the user doesn't press a key. If you
  5347.    find this reverse logic difficult to understand, try translating the loop
  5348.    specification into words:
  5349.  
  5350.      while───────────────────────────────────────────────────────"As long as"
  5351.      !───────────────────────────────────────────────────────────────────"no"
  5352.      kbhit()─────────────────────────────────────────────────"key is pressed"
  5353.  
  5354.       ┌────────────────┐                           ┌─────────────────────────┐
  5355.       │  Initialize    │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒int count = 1         °│
  5356.       │   count = 1    │                           │°                       °│
  5357.       └────────────────┘  ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒while (count < 11)    °│
  5358.                          ▒                        │° {                     °│
  5359.               /\          ▒                    ▒▒▒▒printf("%d\n", count);°│
  5360.             /    \ ▒▒▒▒▒▒▒                     ▒│°                       °│
  5361.           /  TEST  \    No                      ▒▒▒▒count++;              °│
  5362.    ┌───/count < 11  \ ──────       END        ▒│° }                     °│
  5363.    │    \           /                          ▒│°                       °│
  5364.    │      \  ?   /                            ▒│°                       °│
  5365.    │        \   /                             ▒└─────────────────────────┘
  5366.    │          \/                                  ▒
  5367.    │          │ Yes                               ▒
  5368.    │  ┌───────────────┐                          ▒
  5369.      │Do body of loop │                          ▒
  5370.    │  │  print f...    │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  5371.    │  │  count++;      │
  5372.    │  └───────┬────────┘
  5373.    │          │
  5374.    └─────────┘
  5375.  
  5376.    Figure 4-6. The while loop.
  5377.  
  5378.    When the user presses a key, kbhit() returns "true," but the logical not
  5379.    operator reverses the result into "not true," or 0, and the loop exits.
  5380.  
  5381.    Note that a polling while loop needs no counter variable or incrementing.
  5382.    The while loop needs only to test a condition that will eventually change.
  5383.    (If the condition never changes, the program never stops.)
  5384.  
  5385.  Using while to Animate a Character
  5386.  
  5387.    We can nest while loops much as we nested for loops. The ANIMATE.C program
  5388.    (Listing 4-6) uses a set of nested while loops to produce simple
  5389.    animation──making a character appear to move back and forth across the
  5390.    screen.
  5391.  
  5392.    When you run ANIMATE.C, a "double arrow" graphics character (» or «) and
  5393.    the flashing cursor move back and forth across the screen until you press
  5394.    a key.
  5395.  
  5396.    ANIMATE.C starts with #define statements that specify the right arrow and
  5397.    left arrow PC graphics characters as well as the backspace and blank
  5398.    characters, which we use for moving the cursor back and for erasing the
  5399.    previously drawn arrow.
  5400.  
  5401.    The outer loop uses while (!kbhit()), which keeps the program running
  5402.    until you press a key. The inner while() loop moves the arrow to the right
  5403.    by repeatedly
  5404.  
  5405.    1.  displaying the right arrow character,
  5406.  
  5407.    2.  backing up the cursor,
  5408.  
  5409.    3.  erasing the previously displayed arrow by overprinting it with a blank
  5410.        space character, and
  5411.  
  5412.    4.  incrementing pos to display an arrow in the next space.
  5413.  
  5414.    (Remember, the blank moves the cursor to the space with the displayed
  5415.    arrow.) A while loop then tests pos to stop the arrow when it reaches the
  5416.    right side of the screen (position 79).
  5417.  
  5418.    Notice the two nested while loops that we use to slow the display so the
  5419.    eye can follow it. This loop simply counts to 1000. We often use delay
  5420.    loops such as this to slow a program to accommodate human perception or
  5421.    peripheral devices that cannot keep up with the CPU. (Sophisticated delay
  5422.    loops read and use the system clock.)
  5423.  
  5424.    Another set of while loops moves the arrow from the right side of the
  5425.    screen to the left side. You should have little trouble figuring out how
  5426.    it works. Note that the arrow must move backward, so we decrement (rather
  5427.    than increment) pos and test for pos > 1 to see when the arrow reaches the
  5428.    left side of the screen.
  5429.  
  5430.    What happens when the arrow reaches the left side of the screen? The body
  5431.    of the outer loop finishes, and control returns to the test statement in
  5432.    the outer loop. Assuming no key has been pressed, the body of the loop
  5433.    then executes again.
  5434.  
  5435.    ──────────────────────────────────────────────────────────────────────────
  5436.    /* animate.c -- animates a graphics character */
  5437.    /*              until a key is pressed        */
  5438.  
  5439.    /* Special characters */
  5440.    #define RTARROW 175
  5441.    #define LFTARROW 174
  5442.    #define BLANK 32
  5443.    #define BACKSPACE 8
  5444.  
  5445.    main()
  5446.    {
  5447.        int pos, i, j = 1;
  5448.        while (!kbhit())
  5449.            {
  5450.            pos = 1;
  5451.            while (pos < 79)
  5452.                {
  5453.                putch(RTARROW);
  5454.                i = 1;
  5455.                while (i < 1000)
  5456.                    {
  5457.                    j = i + 10;
  5458.                    i++;
  5459.                    }
  5460.                putch(BACKSPACE);
  5461.                putch(BLANK);
  5462.                pos++;
  5463.                }
  5464.            while (pos > 1)
  5465.                {
  5466.                putch(LFTARROW);
  5467.                i = 1;
  5468.                while (i < 1000)
  5469.                    {
  5470.                    j = i + 10;
  5471.                    i++;
  5472.                    }
  5473.                putch(BACKSPACE);
  5474.                putch(BLANK);
  5475.                putch(BACKSPACE);
  5476.                putch(BACKSPACE);
  5477.                pos--;
  5478.                }
  5479.            }
  5480.    }
  5481.    ──────────────────────────────────────────────────────────────────────────
  5482.  
  5483.    Listing 4-6.  The ANIMATE.C program.
  5484.  
  5485.  Combining while and for Loops
  5486.  
  5487.    The following program, MIXLOOPS.C (Listing 4-7), accepts a character from
  5488.    the user and counts through the alphabet until it reaches the character,
  5489.    beeping once for each count. The loop continues to accept characters until
  5490.    the user enters a blank. (Note: As written, the program works only with
  5491.    lowercase alphabetic characters; you can extend it to accept others by
  5492.    changing the starting value of the variable i.)
  5493.  
  5494.    A session with MIXLOOPS.C might run as follows:
  5495.  
  5496.      c──────────────────────────────────────────────────User enters character
  5497.      In FOR loop!─────────────────────────────Beeps each time line is printed
  5498.      In FOR loop!
  5499.      In FOR loop!
  5500.       ───────────────────────────────────────User enters blank to end program
  5501.  
  5502.    The outer loop, a while loop, contains the test:
  5503.  
  5504.      while ((ch = getche()) != ' ')
  5505.  
  5506.    This introduces another noncore QuickC library function called getche(),
  5507.    which stands for "get character with echo." This function accepts a
  5508.    character from the user and echoes (displays) it on the screen. Because
  5509.    this function is located in the conio.h include file, you must add the
  5510.    appropriate #include line before the definition of main().
  5511.  
  5512.    An important feature of this loop is its use of a function call whose
  5513.    value is both assigned to a variable and tested in the loop condition.
  5514.    We'll learn more about function calls in the next chapter.
  5515.  
  5516.    ──────────────────────────────────────────────────────────────────────────
  5517.    /* mixloops.c -- reads characters,       */
  5518.    /*               beeps for ASCII count,  */
  5519.    /*               uses a while and a for  */
  5520.    #include <conio.h>
  5521.  
  5522.    main()
  5523.    {
  5524.         char ch;
  5525.         int  i;
  5526.  
  5527.         while ((ch = getche()) != ' ') /* get a char. */
  5528.              {
  5529.              for (i = 'a'; i <= ch; ++i) /* count up to alphabet pos.*/
  5530.                   {
  5531.                   printf("In FOR loop!\n");
  5532.                   printf("\a");  /* sound beep each time */
  5533.                   }
  5534.              }
  5535.    }
  5536.    ──────────────────────────────────────────────────────────────────────────
  5537.  
  5538.    Listing 4-7.  The MIXLOOPS.C program.
  5539.  
  5540.    When the user enters a character, the assignment ch = getche() assigns the
  5541.    ASCII value of the character to the variable ch. The not equals operator
  5542.    != then compares the character value to the ASCII value for the blank
  5543.    character, specified as '  '. This results in a true or false value that
  5544.    the while loop tests.
  5545.  
  5546.    If the user does not enter a space, the for loop, which makes up the body
  5547.    of the while loop, executes. The for loop tests for i <= ch. Thus, if the
  5548.    user enters the character f, the loop counts from the ASCII value of `a'
  5549.    to that of `f': The body of the for loop executes one time each for the
  5550.    values `a' through `f', and you hear six beeps.
  5551.  
  5552.    MIXLOOPS.C is a good example of the appropriate use of while and for
  5553.    loops. The outer, while loop waits indefinitely for a condition to change
  5554.    (the user enters a space); the inner loop, the for loop, counts to a
  5555.    definite value (the ASCII value of the character entered in the while
  5556.    loop).
  5557.  
  5558.  
  5559.  The do Loop
  5560.  
  5561.    The third (and final) C looping structure is the do loop, which takes the
  5562.    following general form:
  5563.  
  5564.      do
  5565.          {
  5566.          statements;
  5567.          }
  5568.      while (test);
  5569.  
  5570.    The do loop is very similar to the while loop, with one major exception──
  5571.    the while loop performs the test and then executes the body of the loop;
  5572.    the do loop executes the body of the loop and then performs the test.
  5573.    Thus, the body of a do loop always executes at least once, even if the
  5574.    result of the first test is false.
  5575.  
  5576.    The DO.C program (Listing 4-8) demonstrates a simple do loop that
  5577.    performs the now-familiar task of counting from 1 to 10.
  5578.  
  5579.    ──────────────────────────────────────────────────────────────────────────
  5580.    /* do.c -- a simple do-while loop */
  5581.  
  5582.    main()
  5583.    {
  5584.         int i = 1;
  5585.         do
  5586.              {
  5587.              printf("%d\n", i);
  5588.              i++;
  5589.              }
  5590.         while (i < 11);
  5591.         printf("Done!\n");
  5592.    }
  5593.    ──────────────────────────────────────────────────────────────────────────
  5594.  
  5595.    Listing 4-8.  The DO.C program.
  5596.  
  5597.    Of the three C looping structures, the do loop is by far the least used.
  5598.    Usually when you test for a change in condition, a while loop is more
  5599.    appropriate because you want the program to react immediately to user
  5600.    input, especially a "quit" command.
  5601.  
  5602.    Use the do loop to repeat an action until some condition changes only when
  5603.    the test need not be made immediately. A good example is the TIMER.C
  5604.    program (Listing 4-9).
  5605.  
  5606.    ──────────────────────────────────────────────────────────────────────────
  5607.    /* timer.c -- uses do loop to    */
  5608.    /*            check elapsed time */
  5609.    #include <time.h>
  5610.  
  5611.    main()
  5612.    {
  5613.         long start, end, /* starting and ending times */
  5614.                          /* measured in seconds since */
  5615.                          /* Jan. 1, 1970 */
  5616.              ltime;      /* used to get val from time function */
  5617.         int seconds;     /* elapsed time to be set */
  5618.  
  5619.         printf("QuickC Egg Timer\n");
  5620.         printf("Enter time to set in seconds: ");
  5621.         scanf("%d", &seconds);
  5622.         start = time(<ime);  /* get system elapsed seconds */
  5623.                                /* since 1-1-70 */
  5624.         end = start + seconds; /* calculate alarm time */
  5625.  
  5626.         do
  5627.            {;}                       /* null statement for loop body */
  5628.         while (time(<ime) < end);   /* wait for alarm time  */
  5629.  
  5630.         printf("Time's Up!\a\a\a\n");
  5631.    }
  5632.    ──────────────────────────────────────────────────────────────────────────
  5633.  
  5634.    Listing 4-9.  The TIMER.C program.
  5635.  
  5636.    ──────────────────────────────────────────────────────────────────────────
  5637.    Quick Tip
  5638.    Pascal programmers should note the similarity of C's do and Pascal's
  5639.    repeat until loops. The difference is that the C do loop repeats the body
  5640.    until the specified condition is false, whereas the Pascal loop repeats
  5641.    the body until the condition is true.
  5642.    ──────────────────────────────────────────────────────────────────────────
  5643.  
  5644.    This program lets you specify a time in seconds, after which the program
  5645.    beeps three times and prints Time's Up! The program uses the noncore
  5646.    library function time(), which, when given the address of a long type
  5647.    variable, stores in that variable the number of seconds that have elapsed
  5648.    since Jan. 1, 1970, as measured by your PC's clock. As you would expect,
  5649.    the function also returns this value for use in the calling statement.
  5650.  
  5651.    After the initial messages are printed and the user enters a number, the
  5652.    program calls the time() function. Because this function, like scanf(),
  5653.    requires an address as its parameter, you must call the function as
  5654.    time(<ime), using the address operator & to specify the address of the
  5655.    long variable ltime. The returned value, the elapsed seconds from Jan. 1,
  5656.    1970 to the second the user enters a number, is assigned to the variable
  5657.    start. We add the number of seconds specified by the user to this variable
  5658.    and store the result in the variable end. This variable thus contains the
  5659.    number of elapsed seconds at which the program will terminate.
  5660.  
  5661.    The do loop then begins. Because this is a timer program and the user
  5662.    wants to wait some period of time, the test does not need to be performed
  5663.    before the body of the loop executes, so the do loop is appropriate. The
  5664.    body of the loop is a null statement──all we want to do is wait. The test
  5665.    while (time(<ime) < end) repeatedly calls the time() function and checks
  5666.    the returned value until the elapsed time exceeds the value in end.
  5667.  
  5668.  
  5669.  Debugging and Loops
  5670.  
  5671.    It's rare for a program to work correctly the first time you run it.
  5672.    Debugging is the art of knowing what to look for in a program that has
  5673.    errors and of correctly interpreting what you see. Some common errors in C
  5674.    programs that involve elements we have already discussed include:
  5675.  
  5676.    ■  Syntax errors
  5677.  
  5678.    ■  Uninitialized variables
  5679.  
  5680.    ■  Wrong or incompatible data types
  5681.  
  5682.    ■  Incorrectly specified loops
  5683.  
  5684.    Throughout this book we point out common programming errors. Syntax errors
  5685.    are the easiest to fix: The compiler enforces the rules of C syntax and
  5686.    informs you when and where you have erred. (Sometimes, though, you must
  5687.    sort out the real problems from the syntax errors that occur as a result
  5688.    of an earlier error!)
  5689.  
  5690.    True bugs are much harder to detect and fix because they cannot be
  5691.    detected by QuickC. We'll define a "logic bug" as an error that does not
  5692.    violate the rules of C but generates program results that are either
  5693.    completely or partially incorrect. For example, C contains no rule that a
  5694.    variable must be initialized. There is no rule preventing you from
  5695.    assigning the result of a double calculation to an int variable. And
  5696.    loops, with their sometimes complex conditions and specifications, offer
  5697.    plenty of opportunity for bugs, such as the problem that arises when you
  5698.    use a semicolon after a for loop specification.
  5699.  
  5700.    Until recently, debugging a C program was a tedious process that involved
  5701.    putting printf() statements in strategic parts of a program to reveal the
  5702.    values of key variables or the order in which program statements executed
  5703.    (or both). Then came programs called "debuggers" that could run and report
  5704.    on a C program. (If you bought QuickC with Microsoft C 5.0, you also
  5705.    received CodeView, a sophisticated debugger.) QuickC represents the next
  5706.    step in the evolution of debugging: The debugging features are built into
  5707.    the QuickC environment itself. (QuickC's debugger only works in the medium
  5708.    model.)
  5709.  
  5710.    The BUGS.C program (Listing 4-10) is a bug-ridden program that we will
  5711.    fix using the QuickC Debug menu and facilities. It features a while loop
  5712.    and is supposed to let the user enter as many as five numbers and get
  5713.    their total and average.
  5714.  
  5715.    Type this program exactly as shown and run it. (If you spot some bugs
  5716.    along the way, give yourself a star. But please type the program as shown
  5717.    so you can step through the debugging exercise properly.) When you run the
  5718.    program, this is what happens:
  5719.  
  5720.      Continue (y/n)? y───────────────────────────────────────────────Type `y'
  5721.      Enter a number:
  5722.      Enter a number:
  5723.      Enter a number:
  5724.      Enter a number:
  5725.      Enter a number:
  5726.  
  5727.    ──────────────────────────────────────────────────────────────────────────
  5728.    /* bugs.c -- for practice with debugger */
  5729.  
  5730.    main()
  5731.    {
  5732.         char response;
  5733.         int number, max_numbers = 5, count = 0, total = 0;
  5734.         float average;
  5735.  
  5736.         printf("Continue (y/n)? ");
  5737.         response = getche();
  5738.         while ((response != 'n') && (count < max_numbers))
  5739.              printf("\nEnter a number: ");
  5740.              scanf("%d", &number);
  5741.              total += number;
  5742.              printf("Continue (y/n)? ");
  5743.              response = getche();
  5744.         average = total / count;
  5745.         printf("\nTotal is %d\n", total);
  5746.         printf("Average is %f\n", average);
  5747.    }
  5748.    ──────────────────────────────────────────────────────────────────────────
  5749.  
  5750.    Listing 4-10.  The BUGS.C program.
  5751.  
  5752.    The program is running out of control. To break out of it and return to
  5753.    the QuickC environment, press Ctrl-Break. Now the screen displays the
  5754.    following messages:
  5755.  
  5756.      Enter a number:
  5757.      Enter a number:
  5758.      E^C
  5759.  
  5760.      run-time error R6014 : (1 of 1)
  5761.      - control-BREAK encountered
  5762.  
  5763.      Program returned (255).  Press any key
  5764.  
  5765.    Press a key to return to QuickC. (You can ignore this error message.)
  5766.  
  5767.    Now you need to figure out which bug or bugs caused the program to fail.
  5768.    Because the program uses a while loop, it seems likely that something is
  5769.    causing one statement of the loop to be repeated endlessly. To debug the
  5770.    program, you must first select the Compile menu and then select the Debug
  5771.    option. (The Debug menu is shown in Figure 4-7.) This tells QuickC to
  5772.    gather debugging information as it compiles the program. Now select Build
  5773.    Program from the bottom of the Compile menu to recompile the program with
  5774.    debug information. Then go to the Debug menu and select Trace On. (This is
  5775.    a toggle setting──select it to turn it on, denoted by a check mark to the
  5776.    left of Trace On; select it again to turn it off.) Trace On highlights the
  5777.    statement currently being executed (in color if you have a color display).
  5778.    This lets you easily follow the flow of the program as it executes.
  5779.  
  5780.    ┌────────────────────────────────────────────────────────────────────────┐
  5781.    │ Figure 4-7 can be found on p.117 of the printed version of the book.   │
  5782.    └────────────────────────────────────────────────────────────────────────┘
  5783.  
  5784.    Figure 4-7. The Debug menu.
  5785.  
  5786.    Another option in this menu is Screen Swapping. When you turn on Screen
  5787.    Swapping, QuickC alternates between the output screen and the QuickC
  5788.    environment screen as every statement executes. This causes a flickering
  5789.    effect that can be annoying. Even with Screen Swapping off, QuickC shows
  5790.    the output screen whenever any statement produces output or requests
  5791.    input. We suggest you leave Screen Swapping off. Finally, select Start
  5792.    from the Run menu to run the program.
  5793.  
  5794.    As the program runs, notice that the statement currently being executed is
  5795.    highlighted. (If you have a color monitor, you can change colors by
  5796.    selecting Options from the View menu.) The first printf() statement
  5797.    executes and is followed by the scanf() statement that solicits a
  5798.    response. Type y to continue.
  5799.  
  5800.    After that, the program runs away. Notice that the loop specification line
  5801.    and the next printf() line execute continually. Do you see why? We didn't
  5802.    use braces to mark the beginning and end of the loop body. Therefore, the
  5803.    printf() line is executed as the body of the loop. Because this statement
  5804.    doesn't get or change values for either of the loop's two control
  5805.    variables, response and count, the loop test never becomes false, and the
  5806.    loop never terminates. Now you can stop the program (with Ctrl-Break) and
  5807.    insert the braces before and after the indented lines.
  5808.  
  5809.    This example illustrates how easy it is to use the QuickC debugger. You
  5810.    simply turn on the debugging features, observe the problem, and go back to
  5811.    the program to fix it. Because everything is done in the same QuickC
  5812.    environment, you don't have to save or reload any files.
  5813.  
  5814.    ──────────────────────────────────────────────────────────────────────────
  5815.    Controlling the Debugger from the Keyboard
  5816.    It is often easier to use keyboard commands rather than menu selections to
  5817.    debug a running program. You can use the following QuickC keyboard
  5818.    commands while debugging a program:
  5819.  
  5820.      Function Key      Result
  5821.      ──────────────────────────────────────────────────────────────────────
  5822.      F8                Execute next statement, trace through function
  5823.      F10               Execute next statement, trace around function
  5824.      F7                Execute until current cursor position is reached
  5825.      F4                Display the output screen
  5826.      ──────────────────────────────────────────────────────────────────────
  5827.  
  5828.    (When a statement calls a function you have defined elsewhere, F8 traces
  5829.    through the definition of the function. F10, on the other hand, does not
  5830.    detour to trace a called function.)
  5831.    ──────────────────────────────────────────────────────────────────────────
  5832.  
  5833.    Now run the program again. As the highlight moves on the screen, notice
  5834.    that the whole body of the loop executes. That's an improvement. You now
  5835.    can run BUGS.C and enter a series of numbers to be totaled and averaged.
  5836.    Let's say you enter three numbers──8, 12, and 10. This is what happens:
  5837.  
  5838.      Continue (y/n)? y
  5839.      Enter a number: 8
  5840.      Continue (y/n)? y
  5841.      Enter a number: 12
  5842.      Continue (y/n)? y
  5843.      Enter a number: 10
  5844.      Continue (y/n)? n
  5845.      run-time error R6003
  5846.      - integer divide by 0
  5847.  
  5848.      Program returned (255).  Press any key
  5849.  
  5850.    Clearly the program still doesn't work right. A look at the listing shows
  5851.    that the program is supposed to add each new number to total and, after
  5852.    the last number is entered, divide total by count to get average.
  5853.    Apparently count is still zero when the loop exits, thus triggering the
  5854.    divide by zero error. Why? To find out, let's use another feature of the
  5855.    QuickC debugger, "watch variables."
  5856.  
  5857.    Move the cursor in the text area to the variable name count. Select the
  5858.    Debug menu again, and then select Add Watch. The window shown in Figure
  5859.    4-8 appears. The Watch window is a device that lets you designate program
  5860.    variables for QuickC to monitor. When the value of one of these variables
  5861.    changes, QuickC displays its new value in a window at the top of the
  5862.    screen. This eliminates the need to put extra printf() statements in your
  5863.    program to monitor variables.
  5864.  
  5865.    ┌────────────────────────────────────────────────────────────────────────┐
  5866.    │ Figure 4-8 can be found on p.119 of the printed version of the book.   │
  5867.    └────────────────────────────────────────────────────────────────────────┘
  5868.  
  5869.    Figure 4-8. Adding a watch variable.
  5870.  
  5871.    Because you already selected it with the cursor, the word count appears in
  5872.    the window. Simply select OK to add count to the list of watch variables.
  5873.    (To remove watch variables later, select Delete Last Watch or Delete All
  5874.    Watch from the Debug menu.)
  5875.  
  5876.    You can also specify another display format for the value of the watch
  5877.    variable by adding a comma and a format specifier to the variable──for
  5878.    example, count,d──which specifies an integer format display for count. The
  5879.    format specifiers are similar to those you used with printf() and scanf().
  5880.  
  5881.    Next, select Add Watch twice and add the variables number and total to the
  5882.    watch list. (Either position the cursor on the names or type them in the
  5883.    dialog box.)
  5884.  
  5885.    Finally, let's set a breakpoint. This is a place in the program at which
  5886.    execution will stop. This lets you examine the status of the watch
  5887.    variables. Move the cursor to the last line in the body of the while
  5888.    loop──response = getche();──and choose Toggle Breakpoint (or press F9)
  5889.    from the Debug Menu. (Select the toggle again with the cursor on the same
  5890.    line to remove the breakpoint, or choose Clear All Breakpoints. You can
  5891.    set any number of breakpoints.)
  5892.  
  5893.    Now you're ready to run the program again, so choose Start from the Run
  5894.    menu. Again, the program prompts you for numbers, and you can watch the
  5895.    statements in the while loop as they execute. The program stops at the
  5896.    breakpoint at the end of the body of the loop. At the top of the screen, a
  5897.    small window lists the watch variables and their current values. After you
  5898.    inspect them, select Continue from the Run menu (or press F5) to resume
  5899.    program execution. (Figure 4-9 shows the screen display with the current
  5900.    statement and breakpoint highlighted; the watch variable information
  5901.    window is at the top.)
  5902.  
  5903.    ┌────────────────────────────────────────────────────────────────────────┐
  5904.    │ Figure 4-9 can be found on p.120 of the printed version of the book.   │
  5905.    └────────────────────────────────────────────────────────────────────────┘
  5906.  
  5907.    Figure 4-9. Debugging in progress.
  5908.  
  5909.    As the loop cycles, notice that number accepts the value of the number you
  5910.    entered, and total grows as you add new numbers. But count always remains
  5911.    zero. Have you figured out why? We forgot to put a statement in the body
  5912.    of the loop that increments count. Adding count++; after total += number;
  5913.    completes our debugging of the program.
  5914.  
  5915.    You can do more complex things with the debugger, so be sure to read
  5916.    Chapter 8 of the Microsoft QuickC Programmer's Guide for more information.
  5917.    For example, when you learn about arrays and structures, you can use watch
  5918.    variables to display them, too. Meanwhile, you also can use the debugger
  5919.    as a learning tool for tracing the flow of programs in this book, the
  5920.    sample programs provided by Microsoft, or other C programs.
  5921.  
  5922.  
  5923.  
  5924.  ────────────────────────────────────────────────────────────────────────────
  5925.  Chapter 5  Decisions and Branching
  5926.  
  5927.    All programming languages must be able to perform controlled "branching."
  5928.    Branching uses the result of a test or condition to determine which
  5929.    statement (or group of statements) will execute next. In this chapter we
  5930.    discuss the variations of branching in C and learn how to use them with
  5931.    looping statements.
  5932.  
  5933.  
  5934.  The if Statement
  5935.  
  5936.    In C, as in most languages, the if keyword introduces a branching
  5937.    statement. The following structure is the simplest form of branching:
  5938.  
  5939.      if (condition)
  5940.          statement(s);
  5941.  
  5942.    An if statement, like a while loop, evaluates a condition first. The
  5943.    condition can be any combination of values and relational or logical
  5944.    operators that yields a true (nonzero) or false (zero) value──answer ==
  5945.    `y', for example. If the condition is true, the following statement (or
  5946.    group of statements in braces) executes. (As with loops, the statement or
  5947.    statements controlled by the condition are called the "body" of the
  5948.    statement.) If the condition is false, the following statement or group of
  5949.    statements does not execute, and execution continues with the next
  5950.    statement or group of statements. A simple example follows:
  5951.  
  5952.      if (balance < 0)
  5953.         printf("Your account is overdrawn!\n");
  5954.      printf("Your current balance is %8.2f\n", balance);
  5955.  
  5956.    If the customer's balance is less than zero, the first printf() statement
  5957.    executes, telling the customer the account is overdrawn; then the second
  5958.    printf() statement, which prints the current balance, executes. If the
  5959.    customer's balance is zero or more, the condition is false, and the first
  5960.    printf() statement does not execute──the program skips it. Only the second
  5961.    printf() statement executes.
  5962.  
  5963.    In the above example, we indent the first printf() statement to show that
  5964.    the if controls it──it is the body of the if statement. (In C, we indent
  5965.    statements for our benefit only: The compiler doesn't require indention.)
  5966.    Always enclose the condition in parentheses, and do not use a semicolon
  5967.    directly after the parentheses because the complete if statement includes
  5968.    the if, the condition, and the statement body.
  5969.  
  5970.    The IF.C program (Listing 5-1) features the if statement.
  5971.  
  5972.    ──────────────────────────────────────────────────────────────────────────
  5973.    /* if.c -- simple IF statement */
  5974.  
  5975.    char ch;
  5976.    main()
  5977.    {
  5978.        printf("Do you want to continue y/n? "); /* prompt */
  5979.        if (ch = getche() == 'y')
  5980.            printf("\nLet's continue ...\n");    /* if true */
  5981.        printf("\nAll done.\n");                 /* always executed */
  5982.    }
  5983.    ──────────────────────────────────────────────────────────────────────────
  5984.  
  5985.    Listing 5-1.  The IF.C program.
  5986.  
  5987.    ──────────────────────────────────────────────────────────────────────────
  5988.    Quick Tip
  5989.    If you know BASIC or Pascal, note that C does not use the then keyword
  5990.    before the body of the if statement. Most other languages use the
  5991.    following form for the if statement:
  5992.  
  5993.      if (condition)
  5994.          then statement(s)
  5995.  
  5996.    If you mistakenly use then with if, the QuickC compiler will catch the
  5997.    error, of course, and you will soon stop making it.
  5998.    ──────────────────────────────────────────────────────────────────────────
  5999.  
  6000.    IF.C asks the user if he or she wants to continue. The test expression ch
  6001.    = getche() == `y' gets the response character, assigns it to ch, and tests
  6002.    it. The program generates one of two responses:
  6003.  
  6004.      Do you want to continue y/n? y──────────────────────────────User types y
  6005.      Let's continue ...
  6006.      All done.
  6007.  
  6008.      Do you want to continue y/n? n─────User types any character other than y
  6009.      All done.
  6010.  
  6011.    Note that the program prints Let's continue ... only if the user types y;
  6012.    however, it always prints All done.
  6013.  
  6014.    The if statement represents a fork in the road: One of two possible
  6015.    courses is followed, depending on the result of the test. The flowchart in
  6016.    Figure 5-1 depicts such a branch, with the test shown in a diamond-shaped
  6017.    box.
  6018.  
  6019.                               ┌────────────────────────────────┐
  6020.                            No │                                 │
  6021.        ┌───────────┐         /\          ┌───────────┐    ┌──────────┐
  6022.        │ printf    │       /    \        │ printf    │    │ printf    │
  6023.        │ ("Do you  │     /   if   \      │ ("\nLet's │    │ ("\nAll   │
  6024.        │ want to   ├──/ch=getche() \───│ continue  ├───│ done.\n");│
  6025.        │ continue  │   \   =='y')   /    │ ...\n");  │    │           │
  6026.        │ y/n");    │     \        /      │           │    │           │
  6027.        │           │       \    /        │           │    │           │
  6028.        └───────────┘         \/          └───────────┘    └───────────┘
  6029.  
  6030.    Figure 5-1. Flowchart for the if statement.
  6031.  
  6032.  Comparing if and while
  6033.  
  6034.    Notice the structural similarity of the following two statements:
  6035.  
  6036.      if (score > 90)
  6037.          printf("Excellent!");
  6038.  
  6039.    and
  6040.  
  6041.      while (question <= total_questions)
  6042.          ask_question();
  6043.  
  6044.    Both statements test a condition and (if the condition is true) execute
  6045.    the following statement. The important difference between the two
  6046.    constructions is that the if statement executes the body of the statement
  6047.    only once; but the while statement executes the body repeatedly (as long
  6048.    as the test continues to be true).
  6049.  
  6050.    If you think about the two statements, you can see why each is appropriate
  6051.    for its assigned task. A statement that prints the final score of a quiz
  6052.    needs to be executed only once. On the other hand, a statement that calls
  6053.    a function that asks the next question in the quiz must be executed
  6054.    repeatedly.
  6055.  
  6056.  Using a Group of Statements with an if
  6057.  
  6058.    The body of an if statement can contain any number of statements. Consider
  6059.    the following example:
  6060.  
  6061.      if (choice == 'd')
  6062.          {
  6063.          printf("How much do you want to deposit? ");
  6064.          scanf("%f", &deposit);
  6065.          balance += deposit;
  6066.          printf("Thank you. Your new balance is ");
  6067.          printf("%8.2f", balance);
  6068.          }
  6069.  
  6070.    When choice is `d', the program executes all five statements between the
  6071.    braces. Notice that we use the same indention for the braces and the
  6072.    statements.
  6073.  
  6074.  Nested if Statements
  6075.  
  6076.    Just as the body of a loop can contain another loop, the body of an if
  6077.    statement can contain another if statement. For example, a simple text
  6078.    formatter might use the following code fragment:
  6079.  
  6080.      if (pos == line_length)
  6081.          if (++line_count > lines_page)
  6082.              {
  6083.              print_footer;
  6084.              putch(FF);
  6085.              ++page_number;
  6086.              print_header;
  6087.              }
  6088.  
  6089.    If the first if statement is true (the character position equals the line
  6090.    length), the program executes the body of the statement, which is itself
  6091.    an if statement. This statement increments line_count by one, and if the
  6092.    result is greater than lines_page, the body of the inner if statement
  6093.    executes. These statements print a footer, output a "form feed" character,
  6094.    add one to the page number, and print a header for the next page. (Because
  6095.    we must repeatedly test for the end of line and the end of page, we would
  6096.    actually place these if statements inside a while loop. As you might
  6097.    expect, you will often use if statements inside loops, and we will show
  6098.    you examples of these later in this chapter.)
  6099.  
  6100.  Providing Alternatives with else
  6101.  
  6102.    The if statement has an adjunct──else──that is useful for executing a
  6103.    statement or group of statements only if the given condition is false. The
  6104.    general form of the if-else statement is simply an extension of the simple
  6105.    if statement:
  6106.  
  6107.      if (condition)
  6108.          statement(s);
  6109.      else
  6110.          statement(s);
  6111.  
  6112.    Consider the following example:
  6113.  
  6114.      if (age >= 18)
  6115.          {
  6116.          printf("To vote, enter number of candidate: ");
  6117.          scanf("%d", &candidate);
  6118.          }
  6119.      else
  6120.          printf("Sorry, you must be at least 18 to vote.\n");
  6121.  
  6122.    The first group of statements executes only if age is greater than or
  6123.    equal to 18. The statement following else executes only if that condition
  6124.    is false. If-else statements let you provide appropriate responses for
  6125.    both true and false results.
  6126.  
  6127.    Note that we align the else with its corresponding if because together
  6128.    they form one if statement of two parts. Correspondingly, we also indent
  6129.    the statement(s) controlled by the else to match the statements under the
  6130.    if.
  6131.  
  6132.    The IFELSE.C program (Listing 5-2) uses an if statement with an else to
  6133.    simulate the logon sequence for a bulletin board system.
  6134.  
  6135.    ──────────────────────────────────────────────────────────────────────────
  6136.    /* ifelse.c -- IF with ELSE */
  6137.  
  6138.    char ch;
  6139.    int num;
  6140.    main()
  6141.    {
  6142.        printf("Are you a new user? y/n? ");
  6143.        if (ch = getche() == 'y')
  6144.            {
  6145.            /* executed if IF is true */
  6146.            printf("\n\nYou must register to use this\n");
  6147.            printf("bulletin board. Please read\n");
  6148.            printf("Bulletin #1 first. Thank You.\n");
  6149.            }
  6150.        else
  6151.            /* executed if IF is false */
  6152.            {
  6153.            printf("\n\nEnter your secret number: ");
  6154.            scanf("d", &num);
  6155.            }
  6156.    }
  6157.    ──────────────────────────────────────────────────────────────────────────
  6158.  
  6159.    Listing 5-2.  The IFELSE.C program.
  6160.  
  6161.    If the user replies y to the question Are you a new user?, the statements
  6162.    following the if execute. If the user types n (or anything else), the
  6163.    statements following the else execute instead.
  6164.  
  6165.    Here is a sample dialogue:
  6166.  
  6167.      Are you a new user? y/n? y
  6168.  
  6169.      You must register to use this
  6170.      bulletin board. Please read
  6171.      Bulletin #1 first. Thank You.
  6172.  
  6173.      Are you a new user? y/n? n
  6174.  
  6175.      Enter your secret number: 31415
  6176.  
  6177.  Matching an else to an if
  6178.  
  6179.    As you write more advanced programs, you will need to use more complex if
  6180.    statements, such as:
  6181.  
  6182.      if (temp < 900)
  6183.          if (temp > 750)
  6184.              printf("Warning! Boiler overheating!\n");
  6185.      else
  6186.          printf("Start emergency shutdown!\n");
  6187.  
  6188.    This program is meant to check the temperature and print a warning if the
  6189.    temperature is between 750 degrees and 900 degrees, or print an emergency
  6190.    warning if the temperature is greater than 900 degrees. It might look
  6191.    correct, but it's not.
  6192.  
  6193.    When this if statement actually executes, it prints nothing if the
  6194.    temperature exceeds 900, and it prints the emergency warning if the
  6195.    temperature is less than 750! We actually want the else to go with the
  6196.    outer if to print the emergency warning only if the temperature exceeds
  6197.    900. However, although we physically aligned the else so that it appears
  6198.    to go with the outer if, the compiler reads the statement differently. It
  6199.    considers the else to belong to the inner (nested) if.
  6200.  
  6201.    Always remember that QuickC matches a given else with the preceding
  6202.    unenclosed if that doesn't already have an else. Now that we understand
  6203.    this rule, we can fix the program by enclosing the inner if in braces so
  6204.    that the else is not attached to it:
  6205.  
  6206.      if (temp < 900)
  6207.          {
  6208.          if (temp > 750)
  6209.              printf("Warning! Boiler overheating!\n");
  6210.          }
  6211.      else
  6212.          printf("Start emergency shutdown!\n");
  6213.  
  6214.  
  6215.  The Conditional Assignment Statement ?
  6216.  
  6217.    Compared to BASIC or even Pascal, C might seem to be a sparse language
  6218.    that provides the essential tools for programming but few frills. However,
  6219.    we've already seen several elements (such as the special increment and
  6220.    decrement operators) by which C provides "shorthand" expressions to
  6221.    simplify commonly encountered programming chores. Another such common
  6222.    programming task is assigning one of two values to a variable, depending
  6223.    on the result of a test. For example, suppose we want to set the variable
  6224.    max to the larger of the values of the variables n1 and n2. Of course, we
  6225.    can use an if and else, as follows:
  6226.  
  6227.      if (n1 > n2)
  6228.          max = n1;
  6229.      else
  6230.          max = n2;
  6231.  
  6232.    But we can also use C's conditional assignment statement to do the job──
  6233.    and in one line of code. The general form for the conditional assignment
  6234.    statement is:
  6235.  
  6236.      variable = (expression) ? value1 : value2;
  6237.  
  6238.    QuickC evaluates the expression in parentheses first. In this form of
  6239.    assignment statement, if the expression is true (nonzero), value1 is
  6240.    assigned to variable; if the expression is false (zero), value2 is
  6241.    assigned to variable. Note that a question mark follows (expression) and a
  6242.    colon (:) separates the two values.
  6243.  
  6244.    We can now rewrite our earlier statement for assigning a value to max as
  6245.    follows:
  6246.  
  6247.      max = (n1 > n2) ? nl : n2;
  6248.       │        │        │    └─────────────────────────────── Assign if false
  6249.       │        │        └───────────────────────────────────── Assign if true
  6250.       │        └────────────────────────────────────────── Expression to test
  6251.       └──────────────────────────────────────────── Variable to receive value
  6252.  
  6253.    This translates as "If n1 > n2, then assign the value of n1 to max;
  6254.    otherwise, assign the value of n2 to max." Although this statement might
  6255.    look odd, it's easy to use and quite handy.
  6256.  
  6257.  Assigning Truth Values
  6258.  
  6259.    If the two possible values for a variable are actually "true" and "false,"
  6260.    you don't need to use the conditional assignment statement. Simply assign
  6261.    the result of the expression to the variable. For example,
  6262.  
  6263.      frozen = (temp <= 32)
  6264.  
  6265.    sets the value of frozen to true (nonzero) if the temperature is less than
  6266.    or equal to 32 and sets it to false otherwise.
  6267.  
  6268.    The SHORTIF.C program (Listing 5-3 on the following page) illustrates
  6269.    some shorthand and conditional assignments.
  6270.  
  6271.    ──────────────────────────────────────────────────────────────────────────
  6272.    /* shortif.c -- shows 'shorthand' IF / ELSE   */
  6273.    /*           -- gets absolute value of number */
  6274.  
  6275.    main()
  6276.    {
  6277.        int num, pos, abs;
  6278.        printf("Enter a whole number: ");
  6279.        scanf("%d", &num);
  6280.  
  6281.        pos = (num >= 0); /* is number positive? */
  6282.  
  6283.        abs = (pos) ? num : -num;  /* assigns negative of */
  6284.                          /* number if number is negative */
  6285.        if (pos)
  6286.            printf ("The number is positive.\n");
  6287.        else
  6288.            printf("The number is negative.\n");
  6289.        printf("Absolute value of number is: %d\n", abs);
  6290.    }
  6291.    ──────────────────────────────────────────────────────────────────────────
  6292.  
  6293.    Listing 5-3.  The SHORTIF.C program.
  6294.  
  6295.    First, the program gets a number from the user. Then it tests the number
  6296.    to see if it is positive. Notice we do this by assigning the result of the
  6297.    expression (num >= 0) to the variable pos. This value now contains "true"
  6298.    if the number is positive, or "false" if it is not. (Remember that these
  6299.    are actually numeric values, 1 and 0, that have the logical effects of
  6300.    "true" and "false" when used in tests.)
  6301.  
  6302.    Next, the program uses a conditional assignment statement to calculate the
  6303.    absolute value of the number. (The absolute value of a number is its value
  6304.    disregarding its sign. Thus, both 5 and -5 have an absolute value of 5.)
  6305.    Recall that a conditional assignment statement assigns one of two values
  6306.    to a variable based on the truth result of an expression. However, you can
  6307.    also use a single variable that has a truth value instead of an
  6308.    expression. Because the variable pos was assigned a truth value earlier,
  6309.    we can use it here as the test for the conditional assignment.
  6310.  
  6311.    Now let's look at the assignment statement and the if-else branches. If
  6312.    the entered number (num) is positive, pos contains "true," and the
  6313.    statement assigns num to the absolute value abs. In other words, the
  6314.    absolute value of a positive number is simply the number itself.
  6315.  
  6316.    If num is negative, however, then pos contains "false," and the statement
  6317.    assigns the second value, -num, to abs. The negative of a negative number
  6318.    is a positive number and, therefore, the absolute value. The examples on
  6319.    the following page demonstrate the output when the program is run twice──
  6320.    first with a positive number and then with a negative number.
  6321.  
  6322.      Enter a whole number: 23
  6323.      The number is positive.
  6324.      Absolute value of number is: 23
  6325.      Enter a whole number: -58
  6326.      The number is negative.
  6327.      Absolute value of number is: 58
  6328.  
  6329.  
  6330.  Multipath Branching
  6331.  
  6332.    Thus far, we've discussed simple branches (the single if) and two-way
  6333.    branches (the if and else). Simple branches are most useful for testing a
  6334.    condition that can have only one of two values──typically "true" and
  6335.    "false." But what about those situations in which you must test for one of
  6336.    several values? This commonly occurs in a menu from which a user must
  6337.    choose one of several items.
  6338.  
  6339.    Consider, for example, a program that offers the user a choice of readings
  6340.    from a home weather station. Let's say the user can choose among
  6341.    temperature, humidity, pressure, and wind velocity. Here's one way we
  6342.    could set up the menu:
  6343.  
  6344.      printf("Enter reading wanted: t = temp  h = humidity\n");
  6345.      printf("p = pressure  w = wind velocity ");
  6346.      ch = getche();
  6347.      if (ch == 't')
  6348.          printf("Current temperature is %5.2\n", temp)
  6349.      else
  6350.          if (ch == 'h')
  6351.              printf("Humidity is %4.2f\n", humidity);
  6352.          else
  6353.              if (ch == 'p')
  6354.                  printf("Air pressure is %5.2f\n", pressure);
  6355.              else
  6356.                  if (ch == 'w')
  6357.                      printf("Wind velocity is %d\n", wind);
  6358.                  else
  6359.                      {/* default */
  6360.                      printf("Invalid choice. Choose ");
  6361.                      printf(" t, h, p, or w.\n");
  6362.                      }
  6363.  
  6364.    This chain of if statements, each hooked to the preceding statement's
  6365.    else, will work, but it has many disadvantages. Its many levels of nesting
  6366.    are difficult to read. Also, the many indentions run the code off the edge
  6367.    of the screen, requiring awkward line breaks.
  6368.  
  6369.    This type of code also creates a conceptual problem. The structure of
  6370.    these statements suggests that each if statement is dependent on all of
  6371.    the preceding if statements. This suggests that we are checking for some
  6372.    kind of special case that is true only if all the ifs in the series are
  6373.    true. But nothing is further from the truth──we merely want to compare ch
  6374.    to four possible values and provide a branch for each value. (We also need
  6375.    a default branch to handle invalid user-entry values.)
  6376.  
  6377.    We can improve the visual organization of our branches in the following
  6378.    manner:
  6379.  
  6380.      if (ch == 't')
  6381.          printf("Current temperature is %5.2\n", temp)
  6382.      else if (ch == 'h')
  6383.          printf("Humidity is %4.2f\n", humidity);
  6384.      else if (ch == 'p')
  6385.          printf("Air pressure is %5.2f\n", pressure);
  6386.      else if (ch == 'w')
  6387.          printf("Wind velocity is %d\n", wind);
  6388.      else { /* default */
  6389.           printf("Invalid choice. Choose ");
  6390.           printf("t, h, p, or w.\n");
  6391.           }
  6392.  
  6393.    This arrangement is clearer and more compact. All of the branches now have
  6394.    the same level of indention, showing that they are co-equal and not
  6395.    dependent on each other. However, it is important to note that else if is
  6396.    not a distinct command: Changing indention doesn't change the way the
  6397.    compiler handles this code.
  6398.  
  6399.  
  6400.  The switch Statement
  6401.  
  6402.    C offers a special switch statement that makes writing multiple branches
  6403.    much easier. The general form of switch follows:
  6404.  
  6405.      switch (variable)
  6406.          {
  6407.          case 'constant1':
  6408.              statement(s);
  6409.              break;
  6410.          case 'constant2':
  6411.              statement(s);
  6412.              break;
  6413.          case 'constant_n':
  6414.              statement(s);
  6415.              break;
  6416.          default:
  6417.              statement(s);
  6418.          }
  6419.  
  6420.    Specify the name of the variable to be tested in parentheses after the
  6421.    word switch. As with the other loops and branches, don't use a semicolon
  6422.    at the end of the first line: The entire structure comprises one
  6423.    statement.
  6424.  
  6425.    The body of the switch statement (enclosed in braces) is a list of
  6426.    possible branches. Each branch consists of the word case followed by a
  6427.    constant value (a number or character) in parentheses. During execution,
  6428.    this constant is compared with the switch variable: If they are equal, the
  6429.    statements for that case execute. Note that single quotes enclose each
  6430.    constant, and the line ends in a colon.
  6431.  
  6432.    One or more statements follow each case line. (Do not enclose a group of
  6433.    statements in braces──the compiler handles all statements under a given
  6434.    case as a single unit.) The last statement in each branch is the keyword
  6435.    break. The break statement immediately ends execution of the switch
  6436.    statement; program execution resumes at the statement that follows the
  6437.    body of the switch statement. Usually you will conclude each case in a
  6438.    switch statement with the keyword break. If a switch statement behaves
  6439.    erratically, look for missing break statements in the individual cases.
  6440.    Also, include a default: to handle invalid values.
  6441.  
  6442.    Sometimes, however, you will want to execute a set of statements if the
  6443.    switch variable has any one of several values. You can do this by placing
  6444.    the set of statements after a series of switch values, as in the
  6445.    following:
  6446.  
  6447.      switch (ch)
  6448.          {
  6449.          case 'q':
  6450.          case 'Q':
  6451.              show_score();
  6452.              end_game();
  6453.              break;
  6454.          case ...
  6455.          }
  6456.  
  6457.    No statement is associated with 'q', so execution falls through to the
  6458.    code for 'Q', the show_score() and end_game() functions execute, and break
  6459.    is encountered.
  6460.  
  6461.    A switch statement can contain any number of branches, which is why the
  6462.    last branch in our format description uses the notation constant_n. A
  6463.    special case, default:, is an optional branch that is usually placed after
  6464.    the last explicit case in the switch statement. It specifies the branch
  6465.    that executes if none of the conditions for the other cases match the
  6466.    value of variable. Although default: is optional, programmers frequently
  6467.    use it to respond to erroneous values, such as an invalid choice.
  6468.  
  6469.    Let's use the switch statement to rewrite our weather station menu:
  6470.  
  6471.      switch (ch)
  6472.          {
  6473.          case 't':
  6474.              printf("Current temperature is %5.2\n", temp)
  6475.              break;
  6476.          case 'h':
  6477.              printf("Humidity is %4.2f\n", humidity);
  6478.              break;
  6479.          case 'p':
  6480.              printf("Air pressure is %5.2f\n", pressure);
  6481.              break;
  6482.          case 'w':
  6483.              printf("Wind velocity is %d\n", wind);
  6484.              break;
  6485.          default:
  6486.              printf("Invalid choice. Choose ");
  6487.              printf("t, h, p, or w.\n");
  6488.          }
  6489.  
  6490.    Figure 5-2 on the following page illustrates this switch statement. The
  6491.    multiple branches suggest tracks in a railroad switching yard, the
  6492.    probable origin of the name.
  6493.  
  6494.                                               ┌───────┐    ┌──────────┐
  6495.                                  ┌───────────│  't'  │───│printf... │
  6496.                                  │            │       │    │break;    │
  6497.                                  │            └───────┘    └──────────┘
  6498.                                  │            ┌───────┐    ┌──────────┐
  6499.                                  │    ┌──────│  'h'  │───│printf... │
  6500.                                  │    │       │       │    │break;    │
  6501.            Value of      ──────┘    │       └───────┘    └──────────┘
  6502.           ┌────────┐        ────────┘       ┌───────┐    ┌──────────┐
  6503.           │        │    │      ─────────────│  'p'  │───│printf... │
  6504.    switch │ ( ch ) │    *                    │       │    │break;    │
  6505.           │        │                         └───────┘    └──────────┘
  6506.           └────────┘         ────────┐       ┌───────┐    ┌──────────┐
  6507.                          ──────┐    └──────│  'w'  │───│printf... │
  6508.                                  │            │       │    │break;    │
  6509.                                  │            └───────┘    └──────────┘
  6510.                                  │            ┌───────┐    ┌──────────┐
  6511.                                  └───────────│default│───│printf... │
  6512.                                               │       │    │break;    │
  6513.                                               └───────┘    └──────────┘
  6514.  
  6515.    Figure 5-2. The switch statement.
  6516.  
  6517.  
  6518.  The break Statement
  6519.  
  6520.    The break statement has other uses than as the last statement in each case
  6521.    of a switch statement. A break statement can also be used with the three
  6522.    looping statements: (for, while, and do). In all cases, however, break has
  6523.    the same effect──it immediately "breaks out of" the enclosing structure
  6524.    and causes execution to resume after the end of the switch or loop
  6525.    structure. The BREAK.C program (Listing 5-4) uses break to exit from a
  6526.    while loop:
  6527.  
  6528.    This program uses the rand() library function to generate a series of
  6529.    random numbers. On each pass through the while loop, the program generates
  6530.    and displays one random number in the range 0 through 32,767. The
  6531.    statement
  6532.  
  6533.      if (number < 32000)
  6534.          break;
  6535.  
  6536.    terminates the while loop if the program generates a random number greater
  6537.    than 32,000. The output might look something like the following:
  6538.  
  6539.      41
  6540.      18467
  6541.      28145
  6542.      16827
  6543.      491
  6544.      2995
  6545.      11942
  6546.      5436
  6547.      32391
  6548.      Broken out of WHILE loop.
  6549.  
  6550.    ──────────────────────────────────────────────────────────────────────────
  6551.    /* break.c -- shows how to get out of loop with BREAK */
  6552.  
  6553.    #include <stdio.h>
  6554.    #define TRUE 1
  6555.  
  6556.    main()
  6557.    {
  6558.        int number;
  6559.        while (TRUE) /* endless loop */
  6560.            {
  6561.            /* get a random number between 0 and 32767 */
  6562.            number = rand();
  6563.            printf("%d\n", number);
  6564.  
  6565.            /* break out of loop if random number */
  6566.            /* is greater than 32000              */
  6567.            if (number > 32000)
  6568.                break; /* exit WHILE loop */
  6569.            }
  6570.        printf("Broken out of WHILE loop.\n");
  6571.    }
  6572.    ──────────────────────────────────────────────────────────────────────────
  6573.  
  6574.    Listing 5-4.  The BREAK.C program.
  6575.  
  6576.    The last value, 32391, triggered the break statement. The while loop
  6577.    terminates, and the printf() statement following the body of the while
  6578.    loop executes.
  6579.  
  6580.    The SWITCH.C program (Listing 5-5 on the following page) shows you how to
  6581.    create a simple menu using a while loop containing a switch statement. The
  6582.    program asks the user to select one of four math routines (octal
  6583.    representation, hex representation, square, or square root), prompts for a
  6584.    number to be converted, and prints the result. The user types q to exit
  6585.    the program.
  6586.  
  6587.    Following is a sample dialogue with SWITCH.C:
  6588.  
  6589.      Select a math routine:
  6590.      o = octal  h = hex   s = square
  6591.      r = square root  q = quit: o
  6592.      Enter a whole number: 30
  6593.      Result: 36
  6594.  
  6595.      Select a math routine:
  6596.      o = octal  h = hex   s = square
  6597.      r = square root  q = quit: r
  6598.      Enter a whole number: 10
  6599.      Result: 3.162278
  6600.  
  6601.      Select a math routine:
  6602.      o = octal  h = hex   s = square
  6603.      r = square root  q = quit: q
  6604.  
  6605.      Program returned (113).  Press any key
  6606.  
  6607.    ──────────────────────────────────────────────────────────────────────────
  6608.    /* switch.c -- demonstrates switch statement */
  6609.    /*             prints values according       */
  6610.    /*             to user's choice              */
  6611.    #include <math.h> /* for sqrt() */
  6612.    #define TRUE 1
  6613.    main()
  6614.    {
  6615.        char choice;   /* routine wanted by user   */
  6616.        int number;    /* number entered by user   */
  6617.  
  6618.        while (TRUE)   /* endless loop */
  6619.        {
  6620.            printf("\nSelect a math routine:\n");
  6621.            printf("o = octal  h = hex   s = square\n");
  6622.            printf("r = square root  q = quit: ");
  6623.            choice = getche(); printf("\n");
  6624.  
  6625.            if (choice == 'q')
  6626.                break; /* exits WHILE loop; ends program */
  6627.  
  6628.            /* rest of program executed if choice <> 'q' */
  6629.                printf("Enter a whole number: ");
  6630.                scanf("%d", &number);
  6631.  
  6632.            switch (choice) /* print according to */
  6633.                            /* choice requested   */
  6634.                {
  6635.                case 'o':   /* print octal */
  6636.                    printf("Result: %o\n", number);
  6637.                    break;  /* break here in each case    */
  6638.                            /* exits the switch statement */
  6639.  
  6640.                case 'h':   /* print hex */
  6641.                    printf("Result: %x\n", number);
  6642.                    break;
  6643.  
  6644.                case 's':   /* square */
  6645.                    printf("Result: %d\n", number * number);
  6646.                    break;
  6647.  
  6648.                case 'r':   /* square root */
  6649.                    printf("Result: %f\n", sqrt(number));
  6650.                    break;
  6651.  
  6652.                default:
  6653.                    printf("Choice must be o, h, s, r, or q\n");
  6654.                }
  6655.         }
  6656.    }
  6657.    ──────────────────────────────────────────────────────────────────────────
  6658.  
  6659.    Listing 5-5.  The SWITCH.C program.
  6660.  
  6661.    We enclose the menu in an endless while loop because the user will be
  6662.    making choices indefinitely. Notice that we use while (TRUE) instead of
  6663.    while (1). Both have the same effect, but the code is clearer when we use
  6664.    a #define statement to make TRUE equal to 1 and use the descriptive name
  6665.    in the program.
  6666.  
  6667.    After the program displays the menu and getche() gets the user's choice,
  6668.    an if with a break statement tests for the possibility that the user wants
  6669.    to quit. If the user quits, the while loop terminates and the program
  6670.    ends.
  6671.  
  6672.    If the user did not enter q, the program obtains the number to be
  6673.    processed. A switch statement then processes the number. The constants in
  6674.    the various cases correspond to the menu options so the switch statement
  6675.    can match the user's choice with the appropriate case. If the choice is
  6676.    `o' or `h', a format specifier returns the appropriate value; if the
  6677.    choice is `s' or `r', the value is calculated.
  6678.  
  6679.    The default: case handles any value not specified in the menu by printing
  6680.    a list of valid values. Note that the default: case needs no break because
  6681.    there are no further statements in the switch statement that can be
  6682.    executed.
  6683.  
  6684.  switch vs if-else
  6685.  
  6686.    Using switch gives you a structure that is at least as clear as the series
  6687.    of else ifs shown earlier, because each case is clearly distinct. The
  6688.    switch has the additional advantage that the variable to be compared is
  6689.    stated clearly once, at the beginning of the structure, rather than being
  6690.    buried inside the individual tests.
  6691.  
  6692.    Whether you decide to use switch or the if-else form is a matter of style.
  6693.    A good rule of thumb is to use switch whenever four or more possible
  6694.    values (including a default) are involved. Some programmers argue that
  6695.    switch is clearer for even three possible branches.
  6696.  
  6697.    There is, however, one situation in which you cannot use switch──even when
  6698.    many branches must be used. A switch statement can be used only to test
  6699.    simple constant values. You cannot, for example, do the following:
  6700.  
  6701.      switch (expenditure)
  6702.          {
  6703.          case < 10.00:───────────────────────Expression is illegal for switch
  6704.              printf("petty cash");
  6705.              break;
  6706.          case < 100.00:
  6707.              printf("see office manager");
  6708.              break;
  6709.          case < 500.00:
  6710.              printf("see district manager");
  6711.              break;
  6712.          default:
  6713.              printf("see head office");
  6714.          }
  6715.  
  6716.    Unlike many versions of the Pascal case statement and similar structures
  6717.    in other languages, the C switch statement cannot compare a value against
  6718.    ranges of values. It also cannot be used with relational expressions. For
  6719.    these programming tasks, you must use multiple if-else structures.
  6720.  
  6721.  
  6722.  The continue Statement
  6723.  
  6724.    Under some conditions we might need to skip some of the statements in the
  6725.    body of a loop and return to the loop's test condition. For example, if a
  6726.    program offers a menu operation that has potentially irrevocable
  6727.    consequences (such as overwriting the contents of a file), you might want
  6728.    to ask Do you really want to overwrite this file? If the user answers no,
  6729.    the program must skip the remaining statements and return to the menu. The
  6730.    continue statement lets you do this.
  6731.  
  6732.    A continue statement takes the following general form. We illustrate it
  6733.    here with a while loop, although you can use it in any kind of loop (but
  6734.    not a switch).
  6735.  
  6736.      while (condition)
  6737.          {
  6738.          some statements;
  6739.          if (condition)
  6740.              continue;
  6741.          rest of statements;
  6742.          }
  6743.  
  6744.    The if statement tests a condition as usual: If its condition is true, the
  6745.    continue executes. This restarts the loop before the rest of the
  6746.    statements in the body of the loop execute, and the while loop condition
  6747.    is tested again.
  6748.  
  6749.    The CONTINUE.C program (Listing 5-6) uses a simple example of a continue
  6750.    statement. The program also illustrates a "toggle switch" variable, sw. A
  6751.    toggle switch changes to the opposite of its current value each time you
  6752.    use it. If it's "on," the next time you use it you turn it off.
  6753.  
  6754.    The body of the endless while loop first prints out the current status of
  6755.    the sw switch. Next, the program uses a break statement to give the user
  6756.    an opportunity to quit. The program then asks the user whether the switch
  6757.    should be toggled. If the answer is not `y,' a continue statement skips
  6758.    the last statement in the loop body and the switch is not toggled. If the
  6759.    answer is `y,' the continue doesn't execute, and the last statement sw =
  6760.    !sw toggles the switch. (Recall that the ! operator reverses the truth
  6761.    value of the associated variable.)
  6762.  
  6763.    The next program, M.C (Listing 5-7), demonstrates various combinations of
  6764.    for loops and if statements and includes a continue statement. The program
  6765.    draws a letter M within the dimensions specified in the #define statements
  6766.    at the beginning of the program.
  6767.  
  6768.    ──────────────────────────────────────────────────────────────────────────
  6769.    /* continue.c -- shows CONTINUE in a loop */
  6770.    main()
  6771.    {
  6772.        int sw = 0;
  6773.        char ch;
  6774.        while (1) /* endless loop */
  6775.        {
  6776.            /* print current status */
  6777.            if (sw)
  6778.                printf("\nSwitch is ON\n");
  6779.            else
  6780.                printf("\nSwitch is OFF\n");
  6781.  
  6782.            printf("Do you want to quit? ");
  6783.            if (ch = getche() == 'y')
  6784.                break;    /* exit loop on yes */
  6785.  
  6786.            printf("\nDo you want to toggle the switch? ");
  6787.            if (ch = getche() != 'y')
  6788.                continue; /* restart loop on no */
  6789.  
  6790.            sw = !sw;     /* toggle switch */
  6791.            }
  6792.    }
  6793.    ──────────────────────────────────────────────────────────────────────────
  6794.  
  6795.    Listing 5-6.  The CONTINUE.C program.
  6796.  
  6797.    ──────────────────────────────────────────────────────────────────────────
  6798.    /* m.c -- draws a letter M        */
  6799.    /*        using IF and CONTINUE  */
  6800.  
  6801.    /* define characters */
  6802.    #define CH 'M'    /* character to "draw" with */
  6803.    #define BLANK ' '
  6804.    #define NL 10
  6805.    #define CR 13
  6806.    #define LEFT 20   /* left side of M   */
  6807.    #define RIGHT 46  /* right side of M  */
  6808.    #define BOTTOM 22 /* last line to use */
  6809.    main()
  6810.    {
  6811.        int pos, line;
  6812.        /* space to left side */
  6813.        for (line = 1; line <= BOTTOM; line++)
  6814.            {
  6815.            for (pos = 1; pos < LEFT; pos++)
  6816.                {
  6817.                putch(BLANK);
  6818.                }
  6819.            putch(CH); /* draw left side */
  6820.            /* are we past midpoint? */
  6821.            if (line > ((RIGHT - LEFT) / 2))
  6822.                {
  6823.                /* yes, so just draw right side */
  6824.                for (pos = LEFT; pos < RIGHT; pos++)
  6825.                    {
  6826.                    putch(BLANK);
  6827.                    }
  6828.                putch(CH);
  6829.                putch(NL);
  6830.                putch(CR);
  6831.                continue; /* start loop over, do next line */
  6832.                }
  6833.                /* not past midpoint, check for interior */
  6834.            for (pos = LEFT; pos < RIGHT; pos++)
  6835.                {
  6836.                if ((pos == (LEFT + line)) ||
  6837.                     (pos == (RIGHT - line)))
  6838.                    putch(CH);
  6839.                else
  6840.                    putch(BLANK);
  6841.                }
  6842.           putch(CH);
  6843.           putch(NL);
  6844.           putch(CR); /* could also use printf("\n"); */
  6845.           }
  6846.    }
  6847.    ──────────────────────────────────────────────────────────────────────────
  6848.  
  6849.    Listing 5-7.  The M.C program.
  6850.  
  6851.    The M.C program generates the following output:
  6852.  
  6853.      M M                       MM
  6854.      M  M                     M M
  6855.      M   M                   M  M
  6856.      M    M                 M   M
  6857.      M     M               M    M
  6858.      M      M             M     M
  6859.      M       M           M      M
  6860.      M        M         M       M
  6861.      M         M       M        M
  6862.      M          M     M         M
  6863.      M           M   M          M
  6864.      M            M M           M
  6865.      M             M            M
  6866.      M                          M
  6867.      M                          M
  6868.      M                          M
  6869.      M                          M
  6870.      M                          M
  6871.      M                          M
  6872.      M                          M
  6873.      M                          M
  6874.      M                          M
  6875.  
  6876.    Drawing the letter M involves drawing two distinct sections──the V-shaped
  6877.    inner part and the straight-sided outer part. The overall control for
  6878.    drawing all the individual lines resides in the outermost for loop. Each
  6879.    line is started by a small for loop that moves to the left side of the M
  6880.    and draws the character "M" there.
  6881.  
  6882.    What happens next depends on whether the current line number is in the top
  6883.    or bottom part of the M. We determine this by testing to see if the
  6884.    distance down the screen in lines is greater than half the distance across
  6885.    the M in characters. (This test is arbitrary. Feel free to try other
  6886.    formulas and to vary the size of the M by changing the #define
  6887.    directives.)
  6888.  
  6889.    If we are not below the bottom of the V part of the M, the for statement
  6890.    in the body of the if moves to the right side, which is then drawn. The
  6891.    continue (which doesn't require an if here) then skips the rest of the
  6892.    statements, which aren't needed.
  6893.  
  6894.    If the if statement is false, we are still in the upper portion of the M:
  6895.    The body of the if is skipped, and the rest of the statements in the body
  6896.    of the outer loop execute. The if statement works on the principle that
  6897.    the inner lines of the M are drawn one space further to the right and to
  6898.    the left from the sides of the M for each line further down the screen.
  6899.    Thus, the appropriate positioning for the inner lines is found by adding
  6900.    and subtracting the current line number.
  6901.  
  6902.  
  6903.  The goto Statement
  6904.  
  6905.    C's goto statement transfers control to the line containing the specified
  6906.    label. For example, you might use goto with an if statement, as follows:
  6907.  
  6908.      printf("Do you want to continue? \n");
  6909.      if (ch = getche() == 'y')
  6910.          goto yes;
  6911.      printf("Goodbye\n")
  6912.          goto end;
  6913.      yes: printf("Let's continue ...\n");
  6914.      end:
  6915.  
  6916.    Here, if the user enters y, the goto immediately causes execution to skip
  6917.    to the printf() statement that follows the label yes: (which must end with
  6918.    a colon). If the user does not enter y, the second goto skips the "yes"
  6919.    branch.
  6920.  
  6921.    ──────────────────────────────────────────────────────────────────────────
  6922.    The Appropriate Use of continue
  6923.    The continue statement is rarely used in C programs. Often (in Microsoft
  6924.    C, for example), continue's function is handled by an else branch for the
  6925.    relevant if statement or by a new if statement. However, if you have a
  6926.    complicated, multiple-nested set of if-else statements, using a continue
  6927.    statement might simplify things.
  6928.    ──────────────────────────────────────────────────────────────────────────
  6929.  
  6930.    If this looks confusing, that's because it is. You can do the operation
  6931.    much more clearly with an if and an else:
  6932.  
  6933.      printf("Do you want to continue? \n");
  6934.      if (ch = getche() == 'y')
  6935.          printf("Let's continue ...\n");
  6936.      else
  6937.          printf("Goodbye\n");
  6938.  
  6939.    Nearly all contemporary computer scientists discourage the use of goto
  6940.    because it obscures program logic and makes code difficult to decipher, as
  6941.    anyone who has ever tried to debug an old-style BASIC program knows. If
  6942.    your programming background is in the older versions of BASIC or FORTRAN,
  6943.    resist the impulse to use goto statements. Examine the logic of your
  6944.    program: You probably will see, as in the above example, that an if-else
  6945.    with appropriate conditions (or a switch, break, or continue) lets you
  6946.    express the operation more clearly. That's why you can go for months
  6947.    without encountering a goto in C programs. (An occasional exception is the
  6948.    goto that breaks out of a multiple-nested loop. You can't use break in
  6949.    this situation because it only breaks out of the current loop. But even in
  6950.    this case, you can avoid a goto by redesigning the program structure to
  6951.    use "flag" variables. We will discuss flag variables later.)
  6952.  
  6953.  
  6954.  More Complex Conditions for Branching
  6955.  
  6956.    Because we have been concentrating on the mechanics of branching, we have
  6957.    used only simple test conditions in our branching statements. In the last
  6958.    chapter, we showed you how to use logical operators (&& and ||) to create
  6959.    multiple conditions for controlling loops. You can also use these compound
  6960.    conditions to control the execution of if statements.
  6961.  
  6962.    The next program, PIXELS.C (Listing 5-8), introduces the QuickC Graphics
  6963.    Library. It generates random positions for pixels (points of light on the
  6964.    screen) and uses a compound condition to display only selected pixels.
  6965.  
  6966.  Running the Program
  6967.  
  6968.    We've already included header files in several of our programs. The
  6969.    machine code represented by these header files was in the standard library
  6970.    (such as MLIBCE.LIB, the medium memory model with floating-point
  6971.    emulation), so all you needed to specify was #include and the appropriate
  6972.    header file. QuickC knew where to find the default library.
  6973.  
  6974.    To use graphics, however, you must specify the graph.h header file. The
  6975.    definitions it contains reside in a separate Graphics Library,
  6976.    GRAPHICS.LIB. You might need to tell QuickC where to find this library. As
  6977.    with the TABLE.C program in the last chapter, you need a program list.
  6978.    Create a program list called PIXELS.MAK and add PIXELS.C to it. (If you
  6979.    are unsure how to proceed, reread "Creating a Program List" in Chapter
  6980.    4.)
  6981.  
  6982.    ──────────────────────────────────────────────────────────────────────────
  6983.    /* pixels.c -- creates shapes       */
  6984.    /*             from random pixels   */
  6985.    #include <graph.h> /* for graphics  */
  6986.  
  6987.    main()
  6988.    {
  6989.        int pixels, xpos, ypos;
  6990.        /* window coordinates */
  6991.        int xmin = 100, xmax = 540;
  6992.        int ymin = 50,  ymax = 150;
  6993.  
  6994.        srand(0);               /* init random nums */
  6995.        _setvideomode(_HRESBW); /* CGA 640 x 200    */
  6996.        _setcolor(1);           /* white foreground */
  6997.  
  6998.        /* generate random pixel locations      */
  6999.        for (pixels = 1; pixels < 10000; pixels++)
  7000.            {
  7001.            xpos = rand() % 639;
  7002.            ypos = rand() % 199;
  7003.  
  7004.            /* set pixel if within window */
  7005.            if ((xpos > xmin && xpos < xmax) &&
  7006.                 (ypos > ymin && ypos < ymax))
  7007.               _setpixel(xpos, ypos);
  7008.            }
  7009.        getch(); /* freeze screen until key pressed */
  7010.                 /* restore original video mode */
  7011.        _setvideomode(_DEFAULTMODE);
  7012.    }
  7013.    ──────────────────────────────────────────────────────────────────────────
  7014.  
  7015.    Listing 5-8.  The PIXELS.C program.
  7016.  
  7017.    You will need to add the Graphics Library (GRAPHICS.LIB) to the program
  7018.    list as well unless you specified that the Graphics Library was to be
  7019.    included in your standard library when you ran the SETUP program. (See
  7020.    Chapter 2.)
  7021.  
  7022.    For future programs in this book, we will not remind you to create a
  7023.    program list. In general, if the program uses any standard functions that
  7024.    are not part of the core library (listed in Appendix :ARB), you must
  7025.    create a program list with the name of the program in it before you can
  7026.    compile the program to memory. If you wish, you can simply try to compile
  7027.    the program and create the program list if you get the error unresolved
  7028.    external.
  7029.  
  7030.    PIXELS.C starts by including the graph.h header file, which contains
  7031.    definitions for graphics at every resolution and color supported by the
  7032.    IBM graphics adapters (CGA, EGA, VGA, and so on, each with several modes).
  7033.    We discuss graphics modes and graphics routines in Chapter 15. Here,
  7034.    simply note that the _setvideomode() statement in PIXELS.C sets the video
  7035.    mode to the constant _HRESBW, which represents the two-color
  7036.    high-resolution CGA mode having a resolution of 640 pixels by 200 pixels.
  7037.    The _setcolor statement sets the foreground color (the color of the
  7038.    displayed pixels) to white.
  7039.  
  7040.    The values xmin, xmax, ymin, and ymax contain the coordinate positions of
  7041.    the screen "window" in which the program plots pixels. Figure 5-3 shows
  7042.    the screen and the coordinates of the selected window, as well as some
  7043.    sample output for the program.
  7044.  
  7045.    The heart of the program is the for loop that plots 10,000 random pixel
  7046.    positions. Notice that we use the % (modulus) operator to select values in
  7047.    the range 0 through 639 for X, and 0 to 199 for Y. (This corresponds to
  7048.    the 640-by-200 resolution for the specified CGA high-resolution mode.)
  7049.  
  7050.    The if statement checks for an X and a Y position within the window
  7051.    specified by xmin, xmax, ymin, and ymax. Notice that the && logical AND
  7052.    operator ensures that each value is greater than or equal to the minimum
  7053.    and less than or equal to the maximum. The && between the two expressions
  7054.    in parentheses tests the random value to see if it fits in both the X and
  7055.    Y ranges.
  7056.  
  7057.    ┌────────────────────────────────────────────────────────────────────────┐
  7058.    │ Figure 5-3 can be found on p.144 of the printed version of the book.   │
  7059.    └────────────────────────────────────────────────────────────────────────┘
  7060.  
  7061.    Figure 5-3. Screen coordinates and output for PIXELS.C.
  7062.  
  7063.  Variations of PIXELS.C
  7064.  
  7065.    You can create many interesting shapes by substituting different
  7066.    conditions in the if statement. The GALAX.C program (Listing 5-9)
  7067.    establishes a center point (center_x, center_y) and a radius. The if
  7068.    statement in the for loop uses a formula that determines if a point is
  7069.    within the circle──if it is, the program plots the pixel.
  7070.  
  7071.    The result of running GALAX.C (Figure 5-4 on the following page) looks
  7072.    more like an ellipse than a circle because in the 640-by-200 mode, pixels
  7073.    are spaced together more closely horizontally than they are vertically.
  7074.    Because the program must calculate many square roots, it runs a little
  7075.    slowly. We use an if (kbhit()) to let you stop the program whenever you
  7076.    press a key.
  7077.  
  7078.    ──────────────────────────────────────────────────────────────────────────
  7079.    /* galax.c -- creates an ellipse by selecting */
  7080.    /*              from random pixels            */
  7081.    #include <graph.h> /* for graphics */
  7082.    #include <math.h>  /* for sqrt() */
  7083.    #include <conio.h> /* for kbhit() */
  7084.    main()
  7085.    {
  7086.        int pixels, radius = 50;
  7087.        double center_x = 320, center_y = 100,
  7088.            xpos, ypos;
  7089.        srand(0);
  7090.        _setvideomode(_HRESBW);
  7091.        _setcolor(1);
  7092.        for (pixels = 1; pixels < 25000; pixels++)
  7093.            {
  7094.            /* draws filled ellipse, due */
  7095.            /* to dimensions of hi-res screen */
  7096.            /* generate random location */
  7097.            xpos = rand() % 639;
  7098.            ypos = rand() % 199;
  7099.            if (sqrt /* is distance within radius? */
  7100.                  ((xpos - center_x) * (xpos - center_x)
  7101.                  + (ypos - center_y) * (ypos - center_y))
  7102.                  < radius)
  7103.               _setpixel(xpos, ypos);
  7104.            if (kbhit())
  7105.                 break; /* exit if key pressed */
  7106.            }
  7107.        getch(); /* freeze screen until key pressed */
  7108.        _setvideomode(_DEFAULTMODE);
  7109.    }
  7110.    ──────────────────────────────────────────────────────────────────────────
  7111.  
  7112.    Listing 5-9.  The GALAX.C program.
  7113.  
  7114.    ┌────────────────────────────────────────────────────────────────────────┐
  7115.    │ Figure 5-4 can be found on p.146 of the printed version of the book.   │
  7116.    └────────────────────────────────────────────────────────────────────────┘
  7117.  
  7118.    Figure 5-4. Output of GALAX.C.
  7119.  
  7120.  
  7121.  
  7122.  ────────────────────────────────────────────────────────────────────────────
  7123.  Chapter 6  Functions and Function Calls
  7124.  
  7125.    One of the great advantages that C offers a programmer is its huge variety
  7126.    of library functions, which cover everything from manipulating text to
  7127.    controlling memory allocation. The seasoned C programmer soon learns that
  7128.    the C library contains most of the tools needed to perform a given task.
  7129.    However, the real power of C derives from the ease with which you can
  7130.    design customized C functions that perform the specific and unique
  7131.    operations your program requires. In this chapter, we will show you how to
  7132.    create and use these functions.
  7133.  
  7134.  
  7135.  Functions and Program Design
  7136.  
  7137.    Every C program must have at least one user-defined function, namely
  7138.    main(). Most real-world C programs, however, consist of many user-written
  7139.    functions, because the procedure for processing data usually involves many
  7140.    different steps. A program that calculates statistics, for example, might
  7141.    have to ask the user for data, check the data for validity, store the data
  7142.    in memory or on disk, process the data (often according to several
  7143.    criteria), and report the results, possibly in a variety of formats. If
  7144.    all of this program code were in the main() function, the resulting jumble
  7145.    would hamper a programmer trying to visualize where one step ends and the
  7146.    next one begins. Debugging the program would be nearly impossible because
  7147.    you would have difficulty figuring out which of the intertwined parts
  7148.    worked correctly and which ones did not. And if you decided to revise the
  7149.    program to add new capabilities, you could not easily find the appropriate
  7150.    place to add new code.
  7151.  
  7152.    Most experienced programmers design programs using a "top-down" approach.
  7153.    This method resembles writing an outline for a report. First, list the
  7154.    principal ideas or steps. Then divide those ideas or steps into subtopics,
  7155.    and continue subdividing until you feel ready to write the actual
  7156.    sentences. Using a similar approach, the main() function for our
  7157.    statistics program might read:
  7158.  
  7159.      main()
  7160.      {
  7161.      data_menu();
  7162.      while (more_data)
  7163.          {
  7164.          get_data();
  7165.          check_data();
  7166.          store_data();
  7167.          }
  7168.      process_data();
  7169.      report_menu();
  7170.      do_report();
  7171.      }
  7172.  
  7173.    Each of the names followed by parentheses in the definition of main() is a
  7174.    call to a user-defined function. Notice how this "outline" clearly shows
  7175.    the overall flow of the program. First, the program offers the user
  7176.    choices in a data-entry menu; then it enters a loop that receives,
  7177.    validates, and stores data as long as more data is entered. The data is
  7178.    then processed. Another menu lets the user generate a specific type of
  7179.    report, and finally the program prints that report.
  7180.  
  7181.    Note that using separate functions does more than merely keep the parts of
  7182.    a program conceptually separate; it also provides an orderly way of
  7183.    communicating information between different sections of the program. Each
  7184.    function receives information, such as the values of certain variables,
  7185.    and after it finishes executing, returns the transformed information to
  7186.    another section of the program.
  7187.  
  7188.    In a C program, any function can call any other function. This means that
  7189.    your user-defined functions can call other user-defined functions as well
  7190.    as C library functions. For example, the definition of do_report(), shown
  7191.    on the opposite page, might call other user-defined functions, each of
  7192.    which prints a different kind of report, corresponding to the choices
  7193.    offered in the report_menu() part of the program.
  7194.  
  7195.      do_report()
  7196.          {
  7197.          switch (choice)
  7198.              {
  7199.              case 'b' :
  7200.                  bar();
  7201.                  break;
  7202.              case 'p' :
  7203.                  pie();
  7204.                  break;
  7205.              case 'l' :
  7206.                  line();
  7207.                  break;
  7208.              case 't' :
  7209.                  table();
  7210.                  break
  7211.              }
  7212.          }
  7213.  
  7214.    Normally, you declare each user-defined function in main() before the
  7215.    program calls it. The definitions of these user-defined functions usually
  7216.    follow the end of the definition of main(). (You also can define groups of
  7217.    functions in separate files: We will discuss this in Chapter 12.) Figure
  7218.    6-1 proposes a general outline for a program that declares and uses three
  7219.    user-defined functions.
  7220.  
  7221.    Dividing a program into logically organized user-defined functions also
  7222.    lets you develop the program one piece at a time. You can start by putting
  7223.    "stub" definitions in the functions, such as:
  7224.  
  7225.      pie()
  7226.          {
  7227.          printf("executing pie()\n");
  7228.          }
  7229.  
  7230.       Function
  7231.       declarations
  7232.    ┌────────────────┐                Function definitions
  7233.    │ main ( )       │    ┌──────────────────────────────────────────┐
  7234.    │ {              │  ┌─┼─────────────────────────┐                │
  7235.    │   func1 ( );   │ ─┼─┼───────┐                 │                │
  7236.    │   func2 ( );   │ ─┘ │┌────────────┐   ┌────────────┐  ┌────────────┐
  7237.    │   func3 ( );   │ ───┘│  func1 ( )  │   │  func2 ( )  │  │  func3 ( )  │
  7238.    │   ─────────    │     │  {          │   │  {          │  │  {          │
  7239.    │   ─────────    │     │  ───────    │   │  ───────    │  │  ───────    │
  7240.    │   ─────────    │     │  ───────    │   │  ───────    │  │  ───────    │
  7241.    │   ─────────    │     │  ───────    │   │  ───────    │  │  ───────    │
  7242.    │ }              │     │  }          │   │  }          │  │  }          │
  7243.    └────────────────┘     └─────────────┘   └─────────────┘  └─────────────┘
  7244.  
  7245.    Figure 6-1. Outline for a C program with functions.
  7246.  
  7247.    These let you test the overall control structures of the program (the
  7248.    loops, branches, and switches) before you write the actual routines that
  7249.    perform the various tasks. Then you can replace functions one at a time
  7250.    with their real definitions. After you are certain that a function works
  7251.    properly, you can move to the next function. The basic philosophy of this
  7252.    type of programming is "divide and conquer."
  7253.  
  7254.  
  7255.  Declaring and Defining a Function
  7256.  
  7257.    Now that we've discussed the advantages of user-written functions in
  7258.    program development, let's look at the mechanics of declaring, defining,
  7259.    and using your own functions. Always remember that you must declare your
  7260.    functions before you use them. In earlier chapters, when you used the
  7261.    #include directive to allow calling C library functions in your program,
  7262.    QuickC inserted function declarations and definitions into the program.
  7263.    For functions you create yourself, however, you must provide the
  7264.    declaration and a definition.
  7265.  
  7266.  Declaring a Function
  7267.  
  7268.    Let's declare and define a function that prints an error message. The
  7269.    general format of a simple function declaration is as follows:
  7270.  
  7271.      return_type name();
  7272.  
  7273.    In the declaration, return_type refers to the data type (int, float, etc.)
  7274.    of the value that the function returns. Because our first example is a
  7275.    function that does not return a value, we must use the special word void
  7276.    as the return type. (The word void, in this instance, doesn't mean
  7277.    "invalid," but rather "empty.")
  7278.  
  7279.    The function name──error, in our example──must be followed by parentheses,
  7280.    which hold the parameters the function is designed to use. In the case of
  7281.    an error message function, parameters might include a string to print and
  7282.    values that would indicate that the message be printed in high-intensity
  7283.    text, accompanied by a beep, and so on. You must always include
  7284.    parentheses──even if, as in the case of our error() example, you use no
  7285.    parameters. (The compiler uses the parentheses to distinguish a function
  7286.    from a variable.) Note also that you must use a semicolon at the end of
  7287.    the line. Thus, we declare our error message─printing function as follows:
  7288.  
  7289.      void error();
  7290.  
  7291.    As with variable declarations, you can declare several functions of the
  7292.    same type on one line, as in the following declaration:
  7293.  
  7294.      void error(), greeting(), warning();
  7295.  
  7296.    Usually, programmers place the declarations for user-defined functions in
  7297.    the definition of main(), before any other statements (except possibly
  7298.    comments).
  7299.  
  7300.      main()
  7301.      {
  7302.          void error(); /* function declaration */
  7303.          other function declarations;
  7304.          ...
  7305.          other statements;
  7306.          ...
  7307.      }
  7308.  
  7309.    However, if a program has many user-defined functions, you might want to
  7310.    put the declarations before main(). This enables you to see the
  7311.    declarations more easily and separates them from the code of main()
  7312.    proper.
  7313.  
  7314.  Defining a Function
  7315.  
  7316.    After you declare a function, you must define it with statements that will
  7317.    execute when the program calls the function. The first line of the
  7318.    function definition essentially repeats the original function declaration:
  7319.  
  7320.      void error()
  7321.  
  7322.    However, remember that, with a definition, you use no semicolon at the end
  7323.    of the line. The next line should contain an opening brace ({ ); then come
  7324.    the statements that define the function; and finally, the definition ends
  7325.    with a closing brace (} ). Thus, we write our error() function definition
  7326.    as follows:
  7327.  
  7328.      void error()
  7329.          {
  7330.          printf("Error!\a\n");
  7331.          }
  7332.  
  7333.    When a statement calls this function, it prints the word Error! and sounds
  7334.    a beep. (Notice the \a [alert] escape sequence, which is listed in Figure
  7335.    3-5 on p. 68.)
  7336.  
  7337.    ──────────────────────────────────────────────────────────────────────────
  7338.    ANSI and Function Declarations
  7339.    QuickC and other current versions of C do not require you to declare
  7340.    functions that return no value or an int value. The new ANSI standard and
  7341.    modern programming practice encourage you to declare all functions,
  7342.    however. This is to help the reader see how the functions work and to
  7343.    allow the compiler to check for inconsistencies between the definition of
  7344.    a function and the way it is called. For these reasons, which we explain
  7345.    in greater detail later, we declare all functions in our example programs.
  7346.    ──────────────────────────────────────────────────────────────────────────
  7347.  
  7348.  Calling the User-defined Function
  7349.  
  7350.    We call our user-defined error() function the same way we call a library
  7351.    function like printf()──by naming it in a statement in main() or in the
  7352.    body of another function. Consider the following example:
  7353.  
  7354.      main()
  7355.      {
  7356.      ...
  7357.          if ((number < 1) || (number > 9))
  7358.              error();  /* function call */
  7359.      }
  7360.  
  7361.    The if statement calls the error() function only if number is either less
  7362.    than 1 or greater than 9. Again, note that the function call must include
  7363.    the parentheses with the function name.
  7364.  
  7365.    The DBLBAR.C program (Listing 6-1) calls the user-defined function line()
  7366.    to print a double bar before and after a program title. Note that we
  7367.    declare line() before the statements in main(), that we call line() twice
  7368.    from within main(), and that we define line() following the end of main().
  7369.    Figure 6-2 shows the flow of control in this program.
  7370.  
  7371.    ──────────────────────────────────────────────────────────────────────────
  7372.    /* dblbar.c -- prints header using */
  7373.    /*             line() function     */
  7374.  
  7375.    #define DOUBLE_BAR 205
  7376.  
  7377.    main()
  7378.    {
  7379.        void line();       /* declare line() function */
  7380.  
  7381.        line();            /* call line() function    */
  7382.        printf("dblbar.c -- prints header using\n");
  7383.        printf("line() function\n");
  7384.        line();            /* call line() again        */
  7385.    }
  7386.  
  7387.    void line()            /* function definition      */
  7388.    {
  7389.        int pos;
  7390.        for (pos = 1; pos <= 40; pos++)
  7391.            putch(DOUBLE_BAR);
  7392.        printf("\n");
  7393.    }
  7394.    ──────────────────────────────────────────────────────────────────────────
  7395.  
  7396.    Listing 6-1.  The DBLBAR.C program.
  7397.  
  7398.                               ┌──First call
  7399.         ┌───────────────────┐ │  and return
  7400.         │ main ( )          │ │           ┌ - - - - - - - - - - - - -
  7401.         │ {                 │ │           |                           |
  7402.         │ void line ( );    │ │           |   ┌───────────────────┐   |
  7403.       ┌─┼line ( ); ────────┼─────────────|───┼void line ( )- - - -
  7404.       │ │ printf ("...);    │             |   │ {                 │
  7405.       │ │ printf ("...);    │             |   │ int pos;          │
  7406.      - -│line ( );- - - - -│- - - - - - -    │ for (     )       │
  7407.    |  │ │ }                 │ │               │ printf ("...);    │
  7408.    |  │ └───────────────────┘ │           ┌───┼─}- - -            │
  7409.    |  │                       │           │   │       |           │
  7410.    |  │           Second call─┘           │   │       |           │
  7411.    |  │           and return              │   └───────|───────────┘
  7412.    |  └───────────────────────────────────┘           |
  7413.    |                                                  |
  7414.    └ - - - - - - - - - - - - - - - - - - - - - - - -  ┘
  7415.  
  7416.    Figure 6-2. Flow of control in DBLBAR.C.
  7417.  
  7418.    You can also follow the flow of this program by using QuickC's debugger.
  7419.    Select the Debug option in the Compile dialog box, and then select Trace
  7420.    On from the Debug window. When you recompile the program, you see the
  7421.    highlighted statement move through main() until it reaches the first call
  7422.    to line(). The debugger then highlights the statements in line().
  7423.    Highlighting returns to main() with the statement following the call to
  7424.    line(). Control shifts in the same manner when the program encounters the
  7425.    second call to line().
  7426.  
  7427.  A Disadvantage in Using Functions
  7428.  
  7429.    The double-bar program demonstrates the advantage of using functions──they
  7430.    reduce the size of the program. Any time we need to draw a line, we simply
  7431.    call line() rather than repeat the whole for loop. However, using
  7432.    functions has a potential disadvantage. At the machine-code level, each
  7433.    time the program calls a function, the current status of the calling
  7434.    program (including the contents of CPU registers) has to be saved,
  7435.    information must be passed to the function via a memory area called the
  7436.    "stack," and various other housekeeping operations must be performed to
  7437.    return control to the calling statement. Therefore, calling a function
  7438.    involves a lot more "overhead" than merely using a copy of the desired
  7439.    code wherever you need it in your program. (The performance difference is
  7440.    not noticeable with only a few function calls, but you might notice it
  7441.    when you execute a function call thousands of times within a loop.) The
  7442.    loss of efficiency is not critical in most cases and usually is far
  7443.    outweighed by the benefits of using functions. But keep in mind that the
  7444.    more function calls you use, the more important the overhead factor
  7445.    becomes.
  7446.  
  7447.  
  7448.  Local and Automatic Variables
  7449.  
  7450.    A defined function, such as line(), can contain its own variable
  7451.    declarations within its definition. Variables declared within a function
  7452.    definition are called local variables, and they are accessible only within
  7453.    the function in which they are declared. Outside the function braces, the
  7454.    variables don't exist. To be accessible to all the functions in your
  7455.    program, a variable must be declared globally──outside of any function.
  7456.    The extent of a variable's accessibility, or "visibility," is called the
  7457.    "scope" of a variable.
  7458.  
  7459.    In Figure 6-3, note that variables defined in func1() cannot be accessed
  7460.    from main(). They are "invisible" to main(), func2(), or anywhere else
  7461.    outside of the definition of func1(). For example, the definition of
  7462.    line() in DBLBAR.C declares an int variable pos, which is used in the for
  7463.    loop. (See Listing 6-1 on p. 152.) Suppose the main() function in
  7464.    DBLBAR.C contained the following line:
  7465.  
  7466.      printf("The variable pos in line() has a value of %d\n", pos);
  7467.  
  7468.    This line would produce a compiler error, because main() doesn't "know"
  7469.    that a variable called pos exists──pos is the private property of the
  7470.    line() function.
  7471.  
  7472.    ┌─────────────┐                        ADDRESS
  7473.    │  main  ( )  │
  7474.    │  {          │
  7475.    │   int n;- - - - - -Visible only     8706
  7476.    │   func1 ( );│       in main ()       (remains
  7477.    │   func2 ( );│                        until end
  7478.    │  }          │                        of program)
  7479.    └─────────────┘
  7480.    ┌─────────────┐
  7481.    │  func1 ( )  │
  7482.    │  {          │
  7483.    │   int n;- - - - - -Visible only     8694
  7484.    │   ───────   │       in func1 ()      (reused)
  7485.    │   ───────   │
  7486.    │  }          │
  7487.    └─────────────┘
  7488.    ┌─────────────┐
  7489.    │  func2 ( )  │
  7490.    │  {          │
  7491.    │   int n;- - - - - -Visible only     8694
  7492.    │   ───────   │       in func2 ()      (reused)
  7493.    │   ───────   │
  7494.    │  }          │
  7495.    └─────────────┘
  7496.  
  7497.    Figure 6-3. Local variables.
  7498.  
  7499.    Similarly, if you declare a variable called pos within main(), it is
  7500.    private to main() and not accessible from within a function called by
  7501.    main().
  7502.  
  7503.    Because variables defined inside functions are local in C, you can use
  7504.    variables with the same name in different functions. Thus, many of your
  7505.    program functions can use a variable named count, yet QuickC maintains and
  7506.    refers to each one separately.
  7507.  
  7508.  Variables Used in Functions Are Automatic
  7509.  
  7510.    Another important characteristic of a local variable is that it is
  7511.    "automatic": The variable is created (meaning that internal storage is
  7512.    allocated and the address recorded) each time its function is called.
  7513.    Conversely, the variable is destroyed and its internal storage released
  7514.    when the function ends and control returns to the calling statement. Only
  7515.    a local variable can be automatic (and temporary) because the compiler
  7516.    knows that it is valid only while the function executes. (A global
  7517.    variable must be stored permanently, because the compiler must always
  7518.    assume that the program will need its value again.) Automatic variables
  7519.    permit more efficient storage allocation because the same block of memory
  7520.    can store many temporary variables as the program executes. C programs
  7521.    that use local, automatic variables also are smaller than comparable
  7522.    programs that make the same variables global.
  7523.  
  7524.    The LOCAL.C program (Listing 6-2 on the following page) illustrates the
  7525.    way local variables work. (Again, refer to Figure 6-3.) The main()
  7526.    function declares an int variable, n, and prints its value and internal
  7527.    address. The program then calls the func1() and func2() functions. Each of
  7528.    these functions also defines a variable called n and prints its value and
  7529.    address.
  7530.  
  7531.    ──────────────────────────────────────────────────────────────────────────
  7532.    The Scope of Variables
  7533.    In Pascal, you can "nest" function or procedure definitions within each
  7534.    other. A variable defined in a function or procedure is not only
  7535.    accessible to that function or procedure, but also to any definitions
  7536.    nested within the outer definition. This can make questions of the scope
  7537.    of certain variables rather complex. In C you cannot nest function
  7538.    definitions; therefore, a variable defined within a function is accessible
  7539.    only within that function.
  7540.  
  7541.    If you've programmed in older versions of BASIC, you probably expect all
  7542.    variables to be global, that is, accessible throughout the program. You
  7543.    also might remember times that this "feature" created nasty bugs. For
  7544.    example, you might have used count as the control variable of a loop in
  7545.    one subroutine and then days later used another variable called count in a
  7546.    different subroutine. Depending on the order in which BASIC called the
  7547.    subroutines, hard-to-trace bugs probably resulted because BASIC remembered
  7548.    the last value in count when it started the new count. If you are a BASIC
  7549.    programmer coming to C, rest assured that QuickC will never confuse the
  7550.    count of one function with the count of another.
  7551.    ──────────────────────────────────────────────────────────────────────────
  7552.  
  7553.    ──────────────────────────────────────────────────────────────────────────
  7554.    /* local.c -- local variables defined */
  7555.    /*            within functions        */
  7556.  
  7557.    main()
  7558.        {
  7559.        int n = 12;
  7560.        int func1(), func2();
  7561.        printf("n in main(): val %d ", n);
  7562.        printf("address %d\n", &n);
  7563.  
  7564.        printf("Calling func1()\n");
  7565.        func1();
  7566.        printf("Calling func2()\n");
  7567.        func2();
  7568.        }
  7569.  
  7570.    int func1()
  7571.        {
  7572.        int n = 8; /* local variable */
  7573.        printf("n in func1(): val %d ", n);
  7574.        printf("address %d\n", &n);
  7575.        }
  7576.  
  7577.    int func2()
  7578.        {
  7579.        int n = 20; /* local variable */
  7580.        printf("n in func2(): val %d ", n);
  7581.        printf("address %d\n", &n);
  7582.        }
  7583.    ──────────────────────────────────────────────────────────────────────────
  7584.  
  7585.    Listing 6-2.  The LOCAL.C program.
  7586.  
  7587.    The program's output (which may vary from setup to setup) demonstrates
  7588.    that QuickC recognizes each variable's correct value and address without
  7589.    any confusion:
  7590.  
  7591.      n in main(): val 12 address 8706
  7592.      Calling func1()
  7593.      n in func1(): val 8 address 8694
  7594.      Calling func2()
  7595.      n in func2(): val 20 address 8694
  7596.  
  7597.    Also notice that n in func1() and n in func2() use the same address. This
  7598.    occurs because when func1() ends, it discards its reference to the now
  7599.    useless local variable n. When the program calls func2(), QuickC reuses
  7600.    the same address for the new func2() local automatic variable n.
  7601.  
  7602.    Note that the address of the n in main() wasn't reused when the n in
  7603.    func1() or func2() was created. Variables declared in main() have no
  7604.    special status──the n in main() is as automatic and local as the variable
  7605.    in the other functions. Remember, however, that QuickC discards an
  7606.    automatic variable only when the function in which it is defined
  7607.    terminates. Because main() doesn't end execution until the program itself
  7608.    ends, its variables (including n) are not destroyed and reused.
  7609.  
  7610.  The auto Storage Class
  7611.  
  7612.    All variables declared within function definitions are, by default,
  7613.    automatic. Consider the following example:
  7614.  
  7615.      void plot_object()
  7616.          {
  7617.          auto int length, width;
  7618.          ...
  7619.          }
  7620.  
  7621.    The variables length and width are automatic because they are declared
  7622.    within a function. The auto designation merely reminds us of this. Note
  7623.    that auto is not a data type. Rather, it (and the keywords register,
  7624.    static, and extern) is what is called a "storage class." It refers to how
  7625.    QuickC manages the variable as the program runs. Specify the storage class
  7626.    before and in addition to the variable's data type (int in the previous
  7627.    example).
  7628.  
  7629.  
  7630.  Static Variables
  7631.  
  7632.    Occasionally you will need a variable to retain its value after its
  7633.    function terminates. To do this, you must declare the variable used in the
  7634.    function with the static storage type, as follows:
  7635.  
  7636.      static int total;
  7637.  
  7638.    Now the value of total calculated during a previous call is still there
  7639.    when you call the function again. You use this storage class to keep
  7640.    running totals, for example. Note that a static variable is still local
  7641.    and accessible only within the function in which it is defined.
  7642.  
  7643.    The STATIC.C program (Listing 6-3 on the following page) uses the
  7644.    function countline() to count the words and characters in a line of text.
  7645.    (It simply counts a word whenever it encounters a space.) The static
  7646.    variables chars and words accumulate the counts. Because the variables are
  7647.    static, they retain the previous total each time the function is called.
  7648.  
  7649.    A sample of the program's output follows:
  7650.  
  7651.      Type some lines of text.
  7652.      Start a line with a . to quit.
  7653.  
  7654.      By now you should be able to
  7655.      Words so far 7. Chars. so far 28
  7656.      function very well in C!
  7657.      Words so far 12. Chars. so far 52
  7658.      .
  7659.  
  7660.    ──────────────────────────────────────────────────────────────────────────
  7661.    /* static.c -- demonstrates a static variable */
  7662.    /*             that holds count of lines,     */
  7663.    /*             words, and characters          */
  7664.  
  7665.    main()
  7666.        {
  7667.        void countline();
  7668.        printf("Type some lines of text.\n");
  7669.        printf("Start a line with a . to quit.\n\n");
  7670.  
  7671.        while (getche() != '.')
  7672.            countline();  /* accumulate word and */
  7673.                          /* line counts         */
  7674.        }
  7675.  
  7676.    void countline()
  7677.        {
  7678.        static int words = 0; /* static variables */
  7679.        static int chars = 0;
  7680.        char ch;
  7681.        ++chars; /* count char typed when */
  7682.                 /*function was called   */
  7683.  
  7684.        while ((ch = getche()) != '\r')
  7685.            {
  7686.            ++chars;
  7687.            if (ch == ' ')
  7688.                ++words;
  7689.            }
  7690.            ++words; /* count last word */
  7691.  
  7692.        printf("\nWords so far %d. Chars. so far %d\n", words, chars);
  7693.        }
  7694.    ──────────────────────────────────────────────────────────────────────────
  7695.  
  7696.    Listing 6-3.  The STATIC.C program.
  7697.  
  7698.  
  7699.  External Variables
  7700.  
  7701.    You can declare global variables in C when you want two or more functions
  7702.    to share relevant values or to communicate with each other by periodically
  7703.    changing the value of a common variable. A global variable in C is
  7704.    referred to as external because it is defined outside the function
  7705.    definitions in the program.
  7706.  
  7707.    To declare an external variable, simply put its declaration outside of any
  7708.    function definition. External variables are usually placed after any
  7709.    #includes and #defines, but before the definition of main(). In the
  7710.    following example, we declare scale and palette outside of the function,
  7711.    making them external (global) and accessible throughout the program. The
  7712.    variables length and width, on the other hand, are local and accessible
  7713.    only within main().
  7714.  
  7715.      #include <stdio.h>
  7716.      #define VERSION 1.0
  7717.  
  7718.      int scale = 1.5,        /* global variables */
  7719.          palette = 1;        /* go here          */
  7720.  
  7721.      main()
  7722.          {
  7723.          int length, width;  /* local variables */
  7724.          ...                /* go here         */
  7725.  
  7726.    The EXTERNAL.C program (Listing 6-4) shows how you might use an external
  7727.    variable. We declare the variable length before main() to make it an
  7728.    external variable. After the user supplies a value for length, main()
  7729.    calls three functions: square(), triangle(), and circle(). Each of these
  7730.    functions accesses and uses the value of length to calculate the
  7731.    appropriate area.
  7732.  
  7733.    ──────────────────────────────────────────────────────────────────────────
  7734.    /* external.c -- shows an external variable */
  7735.  
  7736.    #define PI 3.14159
  7737.    int length; /* external (global) variable */
  7738.                /* declared before main()    */
  7739.  
  7740.    main()
  7741.        {
  7742.        void square(), triangle(), circle();
  7743.  
  7744.        printf("What length do you want to use? ");
  7745.        scanf("%d", &length);
  7746.  
  7747.        square();   /* calculate areas */
  7748.        triangle();
  7749.        circle();
  7750.        }
  7751.  
  7752.    void square()
  7753.        {
  7754.        float area;
  7755.        area = length * length;
  7756.        printf("A square with sides of %d has an area of %f\n",
  7757.            length, area);
  7758.        }
  7759.  
  7760.    void triangle()
  7761.        {
  7762.        float area;
  7763.        area = (length * length) / 2;
  7764.        printf("A right triangle with sides of %d has an area %f\n",
  7765.            length, area);
  7766.        }
  7767.    void circle()
  7768.        {
  7769.        float area;
  7770.        area = (length * length * PI);
  7771.        printf("A circle with radius of %d has area of %f\n",
  7772.            length, area);
  7773.        }
  7774.    ──────────────────────────────────────────────────────────────────────────
  7775.  
  7776.    Listing 6-4.  The EXTERNAL.C program.
  7777.  
  7778.    Try to resist the temptation to make all your variables external; this
  7779.    invites the problems we discussed earlier. Variables used in only one
  7780.    function should remain local. Variables used by only two or three
  7781.    functions might be better handled as parameters passed from one function
  7782.    to another. (We will discuss function parameters shortly.)
  7783.  
  7784.  
  7785.  Register Variables
  7786.  
  7787.    Let's look at one more storage type for variables, the register type.
  7788.    Microprocessors such as the 8088 and 80286 have several built-in storage
  7789.    locations called registers. A program can store and retrieve data from a
  7790.    register more quickly than from a location in regular memory, where C
  7791.    usually stores variables. As a result, you gain a performance advantage by
  7792.    assigning a register to a frequently used variable in a time-sensitive
  7793.    application.
  7794.  
  7795.    The only problem with using registers is that usually there aren't enough
  7796.    registers to store all the data of a given operation. As shown in Figure
  7797.    6-4, the IBM family of Intel microprocessors (8088, 8086, and 80286) have
  7798.    four general-purpose, 16-bit registers that hold data being manipulated at
  7799.    the machine level.
  7800.  
  7801.               16 bits
  7802.              (2 bytes)
  7803.                  │
  7804.     ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  7805.    ┌─────────────┬─────────────┐
  7806.    │     AH      │     AL      │ AX
  7807.    ├─────────────┼─────────────┤
  7808.    │     BH      │     BL      │ BX
  7809.    ├─────────────┼─────────────┤
  7810.    │     CH      │     CL      │ CX
  7811.    ├─────────────┼─────────────┤
  7812.    │     DH      │     DL      │ DX
  7813.    └─────────────┴─────────────┘
  7814.        8 bits        8 bits
  7815.       (1 byte)      (1 byte)
  7816.  
  7817.    Figure 6-4. General-purpose registers for the Intel 8086 family.
  7818.  
  7819.    In other languages, the compiler software determines which variables, if
  7820.    any, will be assigned registers. In C, however, you can tell the compiler
  7821.    to assign a register to a specific variable when you declare that
  7822.    variable, as follows:
  7823.  
  7824.      register int count;
  7825.  
  7826.    This declaration tells QuickC to store the count variable in a CPU
  7827.    register. (You can't specify which physical register to use, however.)
  7828.    Because registers in the 8088, 8086, and 80286 cannot store variables with
  7829.    values larger than two bytes, only char and int variables can be
  7830.    accommodated. Additionally, you cannot declare external or static
  7831.    variables as register variables, because registers cannot serve as
  7832.    permanent storage locations. Finally, QuickC assigns only two variables
  7833.    per function as register variables: You can make more declarations, but
  7834.    only the first two are honored. In fact, depending on the CPU workload,
  7835.    there is no guarantee that both, or even one, of the registers will be
  7836.    available. If speed is important to your program, try the declarations to
  7837.    see if they help.
  7838.  
  7839.    Which variables should you declare to be register variables? Obvious
  7840.    candidates include loop control variables or variables that are part of
  7841.    statements performed in a loop. But even though most loops execute many
  7842.    times, you shouldn't specify these variables as register storage type.
  7843.    QuickC uses optimization techniques to try to produce the fastest machine
  7844.    code possible from your program, and one of its basic speedup techniques
  7845.    is the assigning of registers to variables in loops. Thus, you gain little
  7846.    by specifying these as register variables──in fact, you might even confuse
  7847.    the compiler and end up with less efficient code. The best variables to
  7848.    specify as register type are variables that are not involved with loops
  7849.    yet are used three or more times each time the function is called.
  7850.  
  7851.  
  7852.  Passing Information to a Function
  7853.  
  7854.    Thus far, our user-defined functions have not required that any
  7855.    information be passed when we called them. Most functions, however,
  7856.    require one or more items of information, called arguments, or parameters.
  7857.    This is often true of the QuickC core library functions: printf() needs to
  7858.    know what to print and how to print it; scanf() needs to know what
  7859.    information to get from the user and where to store it; and so on. Indeed,
  7860.    because it uses no parameters, the line() function in Listing 6-1 on p.
  7861.    152 is extremely limited. As it stands, it always prints a line of 40
  7862.    characters. However, suppose we want 20 or 60 characters. Let's define
  7863.    this function so that when you call it, a parameter tells it how long the
  7864.    line should be:
  7865.  
  7866.      void line (length)   /* length is parameter      */
  7867.          int length;      /* declaration of parameter */
  7868.          {
  7869.          int pos;
  7870.          for (pos = 1; pos <= length; pos++)
  7871.              putch(DOUBLE_BAR);
  7872.          }
  7873.  
  7874.    When you call this function, the length parameter (placed in parentheses
  7875.    in the function definition) receives the current value of the variable
  7876.    length. The items named in the definition of a function are called "formal
  7877.    parameters." The definition of the line() function includes one formal
  7878.    parameter, length. When you call a function, you must include an actual
  7879.    value, such as a constant or a variable, for each formal parameter the
  7880.    function requires. Thus, if we use the statement line(10); to call the
  7881.    line() function, the value 10 is the "actual parameter" corresponding to
  7882.    the formal parameter, length. Inside the line() function, length becomes a
  7883.    variable of type int with the value 10.
  7884.  
  7885.    Notice that we declare the parameter length as an int in the function
  7886.    definition for line(). This declaration serves the same purpose as the
  7887.    declaration of an ordinary variable: It tells the compiler what type of
  7888.    data the parameter represents. Notice also, however, that unlike the
  7889.    declaration of an ordinary variable, which follows the opening brace of
  7890.    the function definition body, the declaration of a function parameter
  7891.    precedes the opening brace. An alternative syntax, favored by many
  7892.    programmers, places the parameter type before the name within the
  7893.    parentheses, as in the following:
  7894.  
  7895.      void line (int length)
  7896.  
  7897.    Note that when a function uses parameters, the parameter should also be
  7898.    put in the declaration of the function in or before main(). Thus, in a
  7899.    program that uses line(), the declaration would be:
  7900.  
  7901.      main()
  7902.      {
  7903.      void line (length);
  7904.      ...
  7905.      }
  7906.  
  7907.    or:
  7908.  
  7909.      void line (int length);
  7910.  
  7911.    It's easiest to use the same form for the function declaration and for the
  7912.    first line of the function definition──but remember that the declaration
  7913.    ends with a semicolon, whereas the definition does not.
  7914.  
  7915.    Once you declare the parameter length, the line() function refers to it as
  7916.    though it had been declared and initialized as an ordinary variable. In
  7917.    our example, length sets the limit for the loop condition, thus
  7918.    controlling the length of the line.
  7919.  
  7920.    Parameters make functions versatile. The program now can call line() and
  7921.    set the length of the line with any appropriate value: a number, a
  7922.    variable name, a #define constant, or an expression.
  7923.  
  7924.    By the way, you can call the line() function using a variable with the
  7925.    same name as the parameter (length). The variable in the function that
  7926.    calls line() belongs to the calling function, and the parameter "belongs"
  7927.    to the called function. They are, in effect, separate local variables──the
  7928.    only connection between them is the value.
  7929.  
  7930.    Let's look at the ALERT.C program (Listing 6-5), which uses a function
  7931.    with a parameter. The beep() function uses a parameter named times to
  7932.    control the number of times a beep is sounded. When the function executes,
  7933.    the if statement checks to see if times has a value in the range of 1 to
  7934.    4. If it doesn't, the program prints an error message. Notice that the
  7935.    error message prints the name of the function and the value that length
  7936.    passed to it. Including this type of information helps you debug your
  7937.    programs.
  7938.  
  7939.    If the value of times is in the correct range, a for loop with the limit
  7940.    of times generates the correct number of beeps. Try changing the calling
  7941.    statement in main() to beep(0) or beep(100).
  7942.  
  7943.    ──────────────────────────────────────────────────────────────────────────
  7944.    /* alert.c -- sounds alarm by calling a        */
  7945.    /*            beep() function with a parameter */
  7946.  
  7947.    main()
  7948.    {
  7949.        void beep(times);  /* function declaration */
  7950.        printf("*** Alert! Alert! ***\n");
  7951.        beep(3);     /* call beep() with parameter */
  7952.    }
  7953.  
  7954.    void beep(times)
  7955.        int times;   /* declare function parameter */
  7956.    {
  7957.        int count;
  7958.  
  7959.        /* check that parameter is between 1 and 4 */
  7960.        if ((times < 1) || (times > 4))
  7961.            {
  7962.            printf("Error in beep(): %d beeps specified.\n",
  7963.                times);
  7964.            printf("Specify one to four beeps");
  7965.            }
  7966.        else /* sound the beeps */
  7967.            for (count = 1; count <= times; count++)
  7968.                printf("\a");  /* "alert" escape sequence */
  7969.    }
  7970.    ──────────────────────────────────────────────────────────────────────────
  7971.  
  7972.    Listing 6-5.  The ALERT.C program.
  7973.  
  7974.  How Parameters Work
  7975.  
  7976.    Now that you know how to use parameters, let's take a detailed look at how
  7977.    they work. Figure 6-5 on the following page shows what happens when a
  7978.    program calls a function that has a parameter. When it executes the
  7979.    function call line(short), QuickC places the value of the variable short
  7980.    in an internal memory area called the "stack" and passes control to the
  7981.    line() function. The line() function "knows" from its definition that it
  7982.    should expect one parameter, called length. It also knows that it is an
  7983.    int value. Thus, the function reads two bytes (an int) from the stack and
  7984.    creates a temporary storage location for them. This value can now be
  7985.    accessed by length within the line() function. It is basically a local,
  7986.    automatic variable that behaves as if it had been declared and initialized
  7987.    within the function definition.
  7988.  
  7989.             Caller
  7990.    ┌──────────────────────┐
  7991.    │  main ( )            │     ┌─────────Discarded when
  7992.    │  int short=10;       │     │          function terminates
  7993.    │  {         ││        │     │
  7994.    │┌───────────┘└───────┐│     │
  7995.    ││   line (short);    ├┼───10 ───┐
  7996.    │└────────────────────┘│   ────   │       Called function
  7997.    │    ───────────────── │   ────   │   ┌──────────────────────┐
  7998.    │    ───────────────── │   ────   │   │ void line (length)   │
  7999.    │  }                   │   ────   └──│ int length; (=10)    │
  8000.    └──────────────────────┘  Stack       │ {                    │
  8001.                                          │  ──────────          │
  8002.                                          │  ──────────          │
  8003.                                          │  ──────────          │
  8004.                                          │ }                    │
  8005.                                          └──────────────────────┘
  8006.  
  8007.    Figure 6-5. Function parameters and the stack.
  8008.  
  8009.    Note that the parameter in a function call is not normally affected by the
  8010.    operation of the function. The function operates with a local variable it
  8011.    creates, not with the variable in the calling statement.
  8012.  
  8013.  Multiple User-written Functions
  8014.  
  8015.    The TIMER2.C program (Listing 6-6) uses a callable custom function,
  8016.    delay(), to improve the timer program we used in Chapter 4. The main()
  8017.    function asks the user for the number of seconds to be timed and the
  8018.    interval by which the program should count off the time, beeping once at
  8019.    each interval. The while loop repeatedly calls delay(interval) to wait for
  8020.    interval seconds; then it sounds the beep (by calling the beep() function)
  8021.    and prints the elapsed seconds. Be sure you understand the positions and
  8022.    components of the function declarations, the function definitions, and the
  8023.    parameter declarations for the delay() and beep() functions.
  8024.  
  8025.    ──────────────────────────────────────────────────────────────────────────
  8026.    Passing Parameters in Pascal and C
  8027.    In Pascal, you can pass either the value of a variable or its address in a
  8028.    parameter. (The first is a "call by value," the second is a "call by
  8029.    reference.") In C, function parameters are always passed by value: The
  8030.    variable itself is never passed. The value can, however, represent the
  8031.    address of a variable. In this case the variable itself, and not merely
  8032.    the value, can be accessed and changed by the called function. (This is
  8033.    called a "pointer," which we discuss in Chapter 8.)
  8034.    ──────────────────────────────────────────────────────────────────────────
  8035.  
  8036.    ──────────────────────────────────────────────────────────────────────────
  8037.    /* timer2.c -- interval timer                */
  8038.    /*             calls delay(), uses beep      */
  8039.  
  8040.    main()
  8041.    {
  8042.        /* function declarations */
  8043.        void beep (times);
  8044.        void delay (seconds);
  8045.  
  8046.        /* variable declarations */
  8047.        int seconds, interval, tick;
  8048.  
  8049.        printf("Set for how many seconds? ");
  8050.        scanf("%d", &seconds);
  8051.        printf("Interval to show in seconds? ");
  8052.        scanf("%d", &interval);
  8053.        printf("Press a key to start timing\n");
  8054.        getch();
  8055.  
  8056.        tick = 0;                /* run "clock" for */
  8057.        while (tick < seconds)   /* time specified  */
  8058.            {
  8059.            delay(interval); /* wait interval seconds */
  8060.            tick += interval;
  8061.            printf("%d\n", tick);
  8062.            beep(1);
  8063.            }
  8064.        beep(3);
  8065.    }
  8066.  
  8067.    void delay(seconds)
  8068.                   /* wait for number of seconds specified */
  8069.                   /* See TIMER.C in chapter 4 for details */
  8070.                   /* on the library function time().      */
  8071.  
  8072.    int seconds;   /* parameter declaration */
  8073.    {
  8074.        /* variable declarations */
  8075.        long start, end, /* starting and ending times */
  8076.                         /* measured in seconds since */
  8077.                         /* Jan. 1, 1970 */
  8078.             ltime;      /* used to get value from time function */
  8079.  
  8080.        start = time(<ime);  /* get system-elapsed seconds */
  8081.                               /* since 1-1-70 */
  8082.        end = start + seconds; /* calculate alarm time */
  8083.  
  8084.        do
  8085.            {;}                       /* null statement for loop body */
  8086.        while (time(<ime) < end);   /* wait for end of time  */
  8087.    }
  8088.  
  8089.    void beep(times)
  8090.        /* parameter declaration */
  8091.    int times;
  8092.    {
  8093.        /* variable declaration  */
  8094.        int count;
  8095.  
  8096.  
  8097.        /* check that parameter is between 1 and 4 */
  8098.        if ((times < 1) || (times > 4))
  8099.            {
  8100.            printf("Error in beep(): %d beeps specified.\n",
  8101.                times);
  8102.            printf("Specify one to four beeps\n");
  8103.            }
  8104.        else /* sound the beeps */
  8105.            for (count = 1; count <= times; count++)
  8106.                printf("\a");  /* "alert" escape sequence */
  8107.    }
  8108.    ──────────────────────────────────────────────────────────────────────────
  8109.  
  8110.    Listing 6-6.  The TIMER2.C program.
  8111.  
  8112.    The delay() function has the same code as the TIMER.C program in Chapter
  8113.    4, except that it adds the parameter seconds to the current time to
  8114.    determine what time should be compared with the system time in the do
  8115.    loop. A sample run follows:
  8116.  
  8117.      Set for how many seconds? 30
  8118.      Interval to show in seconds? 5
  8119.      Press a key to start timing
  8120.      5────────────────────────────────────────────────Beeps after each number
  8121.      10
  8122.      15
  8123.      20
  8124.      25
  8125.      30
  8126.  
  8127.    Putting User Functions in an Include File
  8128.  
  8129.    Notice in TIMER2.C that the definition of the beep() function follows that
  8130.    of delay(). We've used the beep() function before, and we will use it
  8131.    again in several other programs. You would save program space if you put
  8132.    the definitions of beep() and related functions (perhaps line(), another
  8133.    function that prints characters in reverse video, a function that draws a
  8134.    box around a string, and so on) in a header file. Then you could include
  8135.    these functions in any program without typing or pasting them in by hand.
  8136.    Simply save the definitions in a file that uses the traditional .h
  8137.    extension (hilite.h, for example). Then insert the line #include
  8138.    "hilite.h" at the beginning of your program. (You can use the existing
  8139.    INCLUDE subdirectory, but your file system would be better organized if
  8140.    you created a subdirectory called INCLUDE\USER to hold these user-written
  8141.    include files.)
  8142.  
  8143.  
  8144.  Functions with Many Parameters
  8145.  
  8146.    Functions can use any number of parameters. The actual parameters
  8147.    specified in the function call parentheses are assigned, in order, to the
  8148.    corresponding formal parameters in the function definition.
  8149.  
  8150.    As a general rule, however, functions that use more than five parameters
  8151.    become cumbersome to use. If you must use more than this number,
  8152.    reconsider the operations your function performs and try to do the
  8153.    operations in two or more simpler functions. After all, one of the chief
  8154.    benefits of using functions is that they keep each piece of a program at a
  8155.    manageable size. The LINES.C program (Listing 6-7) uses five parameters
  8156.    in its line() function, which draws a colored line on the screen. (To run
  8157.    this program, you need a CGA, EGA, or Hercules board.)
  8158.  
  8159.    ──────────────────────────────────────────────────────────────────────────
  8160.    /* lines.c -- calls line() with */
  8161.    /*            five parameters   */
  8162.  
  8163.    #include <graph.h>
  8164.  
  8165.    main()
  8166.    {
  8167.        void line (x1, y1, x2, y2, color);
  8168.  
  8169.        int x1, x2, y1, y2, i, color;
  8170.  
  8171.        _setvideomode(_MRES16COLOR); /* 320-by-200  16 col. */
  8172.        srand(2);                    /* new random seed    */
  8173.        for (i = 0; i < 100; i++)
  8174.            {
  8175.            x1 = rand() % 319;       /* random coordinates */
  8176.            x2 = rand() % 319;
  8177.            y1 = rand() % 199;
  8178.            y2 = rand() % 199;
  8179.            color = (rand() % 14) + 1; /* random color 1-15 */
  8180.            line(x1, y1, x2, y2, color); /* draw a line   */
  8181.            }
  8182.        while(!kbhit()); /* wait for key to be hit */
  8183.  
  8184.        _setvideomode(_DEFAULTMODE); /* restore video mode */
  8185.    }
  8186.  
  8187.    void line (x1, y1, x2, y2, color)
  8188.    int x1, y1, x2, y2, color;
  8189.    {
  8190.        _moveto(x1, y1); /* position at first endpoint   */
  8191.        _setcolor(color);
  8192.        _lineto(x2, y2); /* draw line to second endpoint */
  8193.    }
  8194.    ──────────────────────────────────────────────────────────────────────────
  8195.  
  8196.    Listing 6-7.  The LINES.C program.
  8197.  
  8198.    The line() function draws a line between the points (x1,y1) and (x2,y2)
  8199.    using a specified color. As you learned from PIXELS.C in Chapter 5, you
  8200.    must use a system of coordinates to specify pixel locations on the
  8201.    graphics screen. This program uses the 320-by-200, 16-color mode, with
  8202.    coordinates starting at (0,0) in the upper-left corner of the screen and
  8203.    ending with (319,199) in the lower-right corner.
  8204.  
  8205.    After the program sets the video mode and initializes the random number
  8206.    generator with the QuickC library function srand(2), a for loop executes.
  8207.    The body of the loop generates random sets of endpoints for lines. (The
  8208.    QuickC random number function rand() generates random integers between 0
  8209.    and 32,767. To produce a random number between 0 and a number n, we use
  8210.    the expression rand() % n. Because the modulus operator gets the remainder
  8211.    by dividing the first number by the second, the result is a number greater
  8212.    than or equal to 0 [no remainder] and less than the second number.) A
  8213.    similar expression generates a random color between 1 and 15. (We can't
  8214.    use color 0 because that is the background color──a line drawn in that
  8215.    color would be invisible.)
  8216.  
  8217.    Finally, the program calls line() and passes five parameters: the two
  8218.    pairs of endpoint coordinates and the color number. Notice that commas
  8219.    must separate the parameters. The line() function draws the line by first
  8220.    calling the QuickC graphics function _moveto() to position the cursor at
  8221.    the randomly specified point (x1,y1). Another graphics function,
  8222.    _setcolor(), sets the current drawing color to the value of color.
  8223.    Finally, the QuickC _lineto() function draws the line to the second
  8224.    endpoint (x2,y2). The for loop in main() then repeats the process to draw
  8225.    100 random lines in random colors.
  8226.  
  8227.  
  8228.  Functions That Return Information
  8229.  
  8230.    Sending values to a function is only one way that information flows
  8231.    between a calling program and a function in C. A function can also send
  8232.    information to the program. For example, in the expression
  8233.  
  8234.      ch = getche()
  8235.  
  8236.    getche() returns a value (the character) to the calling statement, which
  8237.    in turn assigns the value to the variable ch. To have a function return a
  8238.    value to its caller, add a statement to the function definition that
  8239.    consists of the keyword return with the value to be returned enclosed in
  8240.    parentheses, as follows:
  8241.  
  8242.      return (value);
  8243.  
  8244.    Replace value with any information you want the function to return──the
  8245.    value of a variable, the result of a calculation, a character the function
  8246.    has read, or anything else that can be expressed using one of C's data
  8247.    types. When the flow of execution reaches a return statement, the function
  8248.    immediately terminates, returning the specified value to the calling
  8249.    statement. (A function can have several return statements to return
  8250.    different values under different conditions, such as in the branches of an
  8251.    if or switch statement. However, the function always terminates at the
  8252.    first return statement it encounters.) In the calling statement, the
  8253.    returned value replaces the function call, and execution of the statement
  8254.    continues.
  8255.  
  8256.    Let's look at a very simple example, a function that accepts a quantity in
  8257.    yards, converts it to feet, and returns the result:
  8258.  
  8259.      int ytof(yards)
  8260.          int yards;
  8261.          {
  8262.          return(yards * 3);
  8263.          }
  8264.  
  8265.    This function takes the number of yards passed to it through its formal
  8266.    parameter yards. The return statement calculates the number of feet with
  8267.    the expression yards * 3 and returns the value to the caller. Suppose the
  8268.    calling program uses the following statement:
  8269.  
  8270.      distance = ytof(course_length);
  8271.  
  8272.    and assume that the user supplies a course_length of 750 yards. When the
  8273.    statement calls ytof(), it passes the value of course_length to the ytof()
  8274.    function. The function returns 2250 (750 * 3), which replaces the function
  8275.    call in the statement. The statement now reads:
  8276.  
  8277.      distance = 2250;
  8278.  
  8279.    and the assignment operator assigns this value to distance.
  8280.  
  8281.    Also note that the definition of the ytof() function begins not with the
  8282.    type void but rather with the type int. The return type void signifies
  8283.    that the function does not return a value. (We also must declare the
  8284.    parameter yards to be an int in the definition of ytof().)
  8285.  
  8286.    Now let's look at a more useful example. Some languages have a built-in
  8287.    exponentiation operator; C does not. However, the math.h include file
  8288.    contains a function called pow() that you can call as pow(x,y). It raises
  8289.    the first parameter (x) to the power specified in the second parameter
  8290.    (y). Because this function uses double values, it can handle both integer
  8291.    and floating-point values with great precision. The EXPO.C program
  8292.    (Listing 6-8 on the following page) creates an integer version of this
  8293.    function that can respond to various types of input.
  8294.  
  8295.    The expo() function takes two parameters (the number to be raised to a
  8296.    power and the power to raise it to) and returns a value to the calling
  8297.    statement. However, part of designing functions that return values is
  8298.    deciding how to handle special cases. This program must be able to handle
  8299.    three special cases: an exponent less than 0 (negative), an exponent equal
  8300.    to 0, and an exponent equal to 1. Thus, we designed EXPO.C to respond to
  8301.    valid inputs, special inputs, and error conditions with appropriate
  8302.    messages and return values.
  8303.  
  8304.    ──────────────────────────────────────────────────────────────────────────
  8305.    /* expo.c -- uses exp() function to  */
  8306.    /*            calculate powers       */
  8307.  
  8308.    main()
  8309.    {
  8310.        int expo(number, power);
  8311.        int number, power;
  8312.  
  8313.        printf("Enter a number: ");
  8314.        scanf("%d", &number);
  8315.        printf("Raise to what power? ");
  8316.        scanf("%d", &power);
  8317.  
  8318.        printf("Result: %d", expo(number, power));
  8319.    }
  8320.  
  8321.    int expo(number, power)
  8322.    {
  8323.        int count, value;
  8324.        int total = 1;      /* store value of calculation */
  8325.        if (power < 0)      /* reject negative exponents  */
  8326.            {
  8327.            printf("Error in expo(): negative exponent\n");
  8328.            return(0);
  8329.            }
  8330.  
  8331.        if (power == 0) /* any number to 0 power is 1 */
  8332.            return(1);
  8333.  
  8334.        if (power == 1) /* any number to 1 power is itself */
  8335.            return(number);
  8336.  
  8337.        /* calculate for power > 1 */
  8338.        for (count = 1; count <= power; count++)
  8339.            total *= number;
  8340.        return(total);
  8341.    }
  8342.    ──────────────────────────────────────────────────────────────────────────
  8343.  
  8344.    Listing 6-8.  The EXPO.C program.
  8345.  
  8346.    A negative exponent results in a fraction that is less than 1. For
  8347.    example, 2 to the -3 power is the same as:
  8348.  
  8349.       1                     1
  8350.      ─── which is equal to ─── or 0.125
  8351.      2^3                    8
  8352.  
  8353.    This function handles only positive powers because it uses int type
  8354.    variables that can't handle fractions. The first if statement tests the
  8355.    power parameter and prints an error message if it is less than zero. The
  8356.    return statement returns a value of zero to the calling program, and the
  8357.    function terminates.
  8358.  
  8359.    Now let's look at the remaining two cases in expo(). If the power
  8360.    specified in calling expo() is 0, a return statement returns 1 (any number
  8361.    to the zero power is one). If the power specified is 1, expo() returns the
  8362.    number itself.
  8363.  
  8364.    Finally, a for loop calculates all other cases (positive powers greater
  8365.    than 1). Because we initialized total to 1 at the beginning of the
  8366.    function, the expression total *= number in the for loop multiplies number
  8367.    by itself power times.
  8368.  
  8369.    The main() function simply lets you test the expo() function by assigning
  8370.    it a number and a power.
  8371.  
  8372.  
  8373.  Recursion
  8374.  
  8375.    Thus far, calling functions and returning values from them has been a
  8376.    simple and straightforward matter. However, you can use function calls in
  8377.    a way that disturbs these rules slightly──with amazing results. Recursion
  8378.    is an idea that some find difficult to grasp at first, yet a little
  8379.    perseverance will lead you to a programming tool of great beauty,
  8380.    elegance, and power. Here's how it works: In C, any function can call any
  8381.    other function. In fact, a function can call itself──and that is the
  8382.    essence of recursion.
  8383.  
  8384.    A classic example of recursion is the calculating of the factorial of a
  8385.    number. Recall that the factorial of a number is the product of all the
  8386.    integers between 1 and that number, inclusive. For example, the factorial
  8387.    of 4 (written by mathematicians as 4!) is 1 * 2 * 3 * 4, or 24.
  8388.  
  8389.    A program could calculate a factorial by the "brute force" method, using a
  8390.    for loop and multiplying the loop control variable by the previous total.
  8391.    But there is another way to calculate factorials. Consider that 4! = 4 * 3
  8392.    * 2 * 1, and 3! = 3 * 2 * 1. From this we can deduce that 4! = 4 * 3!, or
  8393.    in general terms, that the factorial of a number n is equal to n * (n -
  8394.    1)!, which in turn is equivalent to n * (n - 1) * (n - 2)!, and so on.
  8395.    Eventually we get to 0!, which, by definition, is equal to 1.
  8396.  
  8397.    ──────────────────────────────────────────────────────────────────────────
  8398.    Special Return Values and Error Numbers
  8399.    Why return a value if an error occurs? Because the value returned can warn
  8400.    the caller that an error has occurred. The warning value selected is a
  8401.    value that the function will not return by normal operation. If normal
  8402.    operation of the function returns a positive number, a number such as 0 or
  8403.    -1 sometimes indicates an error. For functions that don't normally return
  8404.    a number, the return value usually indicates something relevant about the
  8405.    function's operation: For example, the return value of scanf() is the
  8406.    number of data fields read, and a 0 indicates an error. Other functions
  8407.    return 0 if their operation was successful; a nonzero return value not
  8408.    only indicates an error but also represents an error number that specifies
  8409.    the precise problem. As you continue to work with QuickC, you will become
  8410.    familiar with how library functions handle errors and what the return
  8411.    values mean.
  8412.    ──────────────────────────────────────────────────────────────────────────
  8413.  
  8414.    Figure 6-6a depicts the calculation of 4! and then generalizes the
  8415.    calculation of a factorial in Figure 6-6b. Note that you keep breaking
  8416.    down the expression by subtracting 1 from the current value of n, taking
  8417.    its factorial, and multiplying it by the preceding value. Eventually the
  8418.    expression becomes equal to n - n, or 0. But 0! = 1, so we no longer need
  8419.    to break down n any further. Multiplying all the values together gives the
  8420.    factorial of the original number n.
  8421.  
  8422.    The RECURSE.C program (Listing 6-9) demonstrates how to use this
  8423.    recursive method to calculate factorials.
  8424.  
  8425.                   4!
  8426.                  / \
  8427.                 4 * 3!
  8428.                    / \
  8429.                   3 * 2!
  8430.                      / \
  8431.                     2 * 1!
  8432.                        / \
  8433.                       1 * 0!
  8434.                         │
  8435.                         │
  8436.                         1
  8437.                      4! = 24
  8438.  
  8439.    (A)           BREAKING DOWN 4!
  8440.  
  8441.  
  8442.                   n!
  8443.                  /  \
  8444.               n * (n-1)!                     ┌───────────────────┐
  8445.                  /      \           ▒▒▒▒▒▒▒▒│ (n-(n-1) * (n-n)! │
  8446.                (n-1) * (n-2)!       ▒        │   = 1 * 0!        │
  8447.                       /      \      ▒        │   = 1 * 1 = 1     │
  8448.                     (n-2) * (n-3)!  ▒        └───────────────────┘
  8449.                               .     ▒
  8450.                               .     ▒
  8451.                               .     ▒
  8452.                             (n-(n-1) * (n-n)!
  8453.  
  8454.    (B)                       BREAKING DOWN n!
  8455.  
  8456.    Figure 6-6. Breaking down factorial expressions.
  8457.  
  8458.    ──────────────────────────────────────────────────────────────────────────
  8459.    /* recurse.c -- demonstrates recursion */
  8460.  
  8461.    int level = 1; /* recursion level */
  8462.    main()
  8463.    {
  8464.        int num, result;
  8465.  
  8466.        printf("Factorial of what number? ");
  8467.        scanf("%d", &num);
  8468.        result = factorial(num);
  8469.        printf("Result is: %d\n", result);
  8470.    }
  8471.  
  8472.    factorial(int number)
  8473.    {
  8474.        int result;
  8475.        printf("entering: ");
  8476.        printf("level %d. number = %d. &number = %d\n",
  8477.                level++, number, &number);
  8478.  
  8479.        if (number == 0)
  8480.            result = 1;
  8481.        else
  8482.            result = number * factorial(number - 1);
  8483.  
  8484.        printf("exiting : ");
  8485.        printf("level %d. number = %d. &number = %d. ",
  8486.                --level, number, &number);
  8487.        printf("result = %d\n", result);
  8488.  
  8489.        return(result);
  8490.    }
  8491.    ──────────────────────────────────────────────────────────────────────────
  8492.  
  8493.    Listing 6-9.  The RECURSE.C program.
  8494.  
  8495.  A Recursive Function at Work
  8496.  
  8497.    Let's examine how the factorial(number) function in RECURSE.C works. An if
  8498.    statement terminates the function and returns 1 if number is 0 (because 0!
  8499.    is 1). For any other value of number, the else branch executes
  8500.  
  8501.      result = number * factorial(number - 1);
  8502.  
  8503.    This is a recursive call because factorial() is actually calling itself.
  8504.  
  8505.    Now let's follow execution from start to finish. The main() function makes
  8506.    the first call to factorial() with the value of number. Because number
  8507.    initially is not 0, factorial() executes the else branch and calls itself
  8508.    with number - 1. In this new call, execution again encounters the else
  8509.    branch, and another call to factorial() results. Although this call also
  8510.    uses number - 1, the number here is actually the value factorial()
  8511.    received from its previous call, or number - 2.
  8512.  
  8513.    As a result of the repeated calls of factorial() to itself, the decreasing
  8514.    values passed with each call accumulate on the stack (because the values
  8515.    passed to a function call are not removed from the stack until the call
  8516.    terminates). Also, remember that each call to factorial() creates a new
  8517.    set of the automatic variables number and result. These variables
  8518.    accumulate (one set for each call) until the function terminates. It is as
  8519.    though QuickC places a "bookmark" in each function call when the next call
  8520.    executes so that the compiler can keep track of what remains to be done in
  8521.    each.
  8522.  
  8523.    The printf() statements in the program record the above process, as
  8524.    follows:
  8525.  
  8526.      Factorial of what number? 4
  8527.      entering: level 1. number = 4. &number = 8720
  8528.      entering: level 2. number = 3. &number = 8706
  8529.      entering: level 3. number = 2. &number = 8692
  8530.      entering: level 4. number = 1. &number = 8678
  8531.      entering: level 5. number = 0. &number = 8664
  8532.      exiting : level 5. number = 0. &number = 8664. result = 1
  8533.      exiting : level 4. number = 1. &number = 8678. result = 1
  8534.      exiting : level 3. number = 2. &number = 8692. result = 2
  8535.      exiting : level 2. number = 3. &number = 8706. result = 6
  8536.      exiting : level 1. number = 4. &number = 8720. result = 24
  8537.      Result is: 24
  8538.  
  8539.    Notice the new address for each call's version of the number variable:
  8540.    This proves that separate automatic variables are being created. (The
  8541.    actual addresses the program returns may vary from setup to setup.)
  8542.  
  8543.    The "turning point" in the recursive process occurs when number decreases
  8544.    to 0, the call factorial(0) is made, and the if branch finally executes.
  8545.    Finally the function returns to the caller (the preceding version of
  8546.    factorial()), after assigning the value 1 to result. Now the preceding
  8547.    call can "pick up its bookmark" and replace factorial(number - 1) with 1,
  8548.    multiply it by the value of number that was saved in its automatic
  8549.    variable, and then return this value to its preceding caller. You can see
  8550.    this happening in the second half of the output listing: The calls move
  8551.    back through the recursion levels, back through the addresses of the
  8552.    accumulated automatic variables, with each result being multiplied by the
  8553.    preceding one, until the function returns to main() with the correct
  8554.    result, 24.
  8555.  
  8556.  Recursion and Stack Size
  8557.  
  8558.    Some problems are naturally recursive──searching through directories and
  8559.    their subdirectories, parsing commands into subcommands, or working with
  8560.    tree structures. One thing to keep in mind, however, is that recursion
  8561.    uses a lot of memory for storing automatic variables and the stack. (The
  8562.    stack holds not only the parameters passed for each call but also the
  8563.    register values and return addresses.) Try running RECURSE.C with larger
  8564.    input numbers. You can only use numbers to 7 before type int, which stores
  8565.    the result, overflows. If you rewrite the program to use long, you can use
  8566.    numbers to 16. With type double, you can generate some truly impressive
  8567.    factorials, but trying to generate 62! causes a stack overflow error. The
  8568.    stack, which by default can store 2048 bytes, simply cannot hold any more
  8569.    recursions. (You can specify a larger stack size by selecting Set Runtime
  8570.    Options from the Run menu. Still, there is a limit in our medium memory
  8571.    model because the stack and the program data share one 64 KB segment. In
  8572.    Chapter 11, we also will show you how to use a compiler command-line
  8573.    switch to use memory models in which the stack has an entire 64 KB segment
  8574.    to itself.)
  8575.  
  8576.  
  8577.  Noninteger Functions
  8578.  
  8579.    The value returned by a function does not have to be an integer type.
  8580.    Functions can return a float, a char, or any other standard C data type.
  8581.    So far, we have declared and defined functions using a return data type,
  8582.    such as:
  8583.  
  8584.      int expo(number, power)
  8585.  
  8586.    An older style of C programming omits the return type when the function
  8587.    returns an int, because the compiler defaults to int if no type is
  8588.    specified. We base our style on the new ANSI standard, which encourages
  8589.    declaring return types for all functions and using void for functions that
  8590.    do not return values. For example, we might define a function that
  8591.    calculates the cube root of a number as:
  8592.  
  8593.      float cube_root(number)
  8594.  
  8595.    This specifies that the cube_root() function returns a value of type
  8596.    float. Remember that we also must declare this function in or before
  8597.    main():
  8598.  
  8599.      main()
  8600.          {
  8601.          char response;
  8602.          int x, y;
  8603.          float result;
  8604.          float cube_root(number);   /* function declaration */
  8605.  
  8606.    The GETYN.C program (Listing 6-10 on the following page) demonstrates the
  8607.    declaration and use of a noninteger function. It defines a function,
  8608.    getyn(), that prompts for a "yes or no" answer, checks to make sure the
  8609.    character entered by the user is either a y or an n, and returns the
  8610.    entered character. We declare the function at the start of main() and
  8611.    define it as follows:
  8612.  
  8613.      char getyn()
  8614.  
  8615.    because it returns a value of type char. Notice that this function does
  8616.    not use a parameter. Although many functions that return values, such as
  8617.    the expo() function, require parameters, some functions receive their
  8618.    information not from the calling statement but from some other source. In
  8619.    the case of getyn(), and indeed with the standard functions that read
  8620.    characters (getch(), getche(), and so on), the user supplies the value.
  8621.  
  8622.    ──────────────────────────────────────────────────────────────────────────
  8623.    /* getyn.c -- calls char function getyn()    */
  8624.    /*               with error checking         */
  8625.  
  8626.    #define TRUE 1
  8627.  
  8628.    main()
  8629.    {
  8630.        char ch;
  8631.        char getyn();
  8632.  
  8633.        printf("Do you want to continue? ");
  8634.        if ((ch = getyn()) == 'y')
  8635.            printf("Answer was y\n");
  8636.        else
  8637.            printf("Answer was n\n");
  8638.        printf("Value of ch was %c\n", ch);
  8639.    }
  8640.  
  8641.    char getyn()
  8642.    {
  8643.        char ch;
  8644.        while (TRUE)
  8645.            {
  8646.            printf(" (y or n) ");
  8647.            ch = getche();
  8648.            printf("\n");
  8649.            if ((ch == 'y') || (ch == 'n'))
  8650.            /* valid response, break out of loop */
  8651.                break;
  8652.            /* give error message and loop again */
  8653.            printf("please enter ");
  8654.            }
  8655.        return(ch);
  8656.    }
  8657.    ──────────────────────────────────────────────────────────────────────────
  8658.  
  8659.    Listing 6-10.  The GETYN.C program.
  8660.  
  8661.    In the getyn() function, a while loop prompts the user to enter a y or n,
  8662.    a getche() gets a character, and an if statement checks to see if the
  8663.    character is a y or an n. If it is, a break statement exits the loop, and
  8664.    the return statement returns the character. If the character is something
  8665.    other than y or n, a prompt asks the user to reenter a value, and then the
  8666.    loop repeats. Putting an input-type statement in a loop provides a
  8667.    framework for error checking.
  8668.  
  8669.    The getyn() function is a handy tool that you can use in place of getch()
  8670.    or getche() whenever you want the user to enter a valid response to a
  8671.    yes/no question.
  8672.  
  8673.  
  8674.  Function Prototypes
  8675.  
  8676.    We've seen that you can declare the return type for a function at the
  8677.    beginning of your program, such as:
  8678.  
  8679.      float distance(x1, y1, x2, y2);
  8680.  
  8681.    This declaration tells QuickC that your function returns a float value.
  8682.    That takes care of the value coming out of the function. But what about
  8683.    the values going into the function──the function parameters?
  8684.  
  8685.    As it stands, this definition does not specify a data type for the
  8686.    parameters. Consequently, we might design the function to work with
  8687.    integer values and then accidentally give it some double values as real
  8688.    parameters. If you don't specify the data type of the function parameter,
  8689.    QuickC isn't even aware of the potential problem.
  8690.  
  8691.    The MIXTYPES.C program (Listing 6-11) shows what can happen when the type
  8692.    of data passed to the function does not match the expected type.
  8693.  
  8694.    We wrote this program in the older C style: It has no function declaration
  8695.    and only the minimum function definition. After all, the examine()
  8696.    function merely prints its parameter. (It expects a parameter of the
  8697.    default int type, hence the "%d" format specifier in the printf() control
  8698.    string.)
  8699.  
  8700.    In main() we incorrectly declare the variable n as float and call
  8701.    examine() with it.
  8702.  
  8703.    ──────────────────────────────────────────────────────────────────────────
  8704.    /* mixtypes.c -- shows problem with calling           */
  8705.    /*               a function with wrong type parameter */
  8706.  
  8707.    main()
  8708.    {
  8709.        /* didn't bother to declare int function */
  8710.        float n = 5.0;
  8711.        int i;
  8712.  
  8713.        printf("n in main() is %f\n", n);
  8714.        i = examine(n);    /* pass float to function */
  8715.        printf("examine() returned n as %d\n", i);
  8716.    }
  8717.  
  8718.    examine(num)  /* function didn't declare return type */
  8719.    {
  8720.        printf("examine() says n is %d\n", num);
  8721.        return(num);
  8722.    }
  8723.    ──────────────────────────────────────────────────────────────────────────
  8724.  
  8725.    Listing 6-11.  The MIXTYPES.C program.
  8726.  
  8727.    What happens when you run MIXTYPES.C?
  8728.  
  8729.      n in main() is 5.000000
  8730.      examine() says n is 0
  8731.      examine() returned n as 0
  8732.  
  8733.    The printf() statement in main() verified a float type. But when we try to
  8734.    print the value of this parameter inside examine(), we see that its value
  8735.    is now 0. Because we didn't specify a type for the num parameter in
  8736.    examine(), the float passed to the function without comment. However,
  8737.    because the function expects num to be an int (the default), the float is
  8738.    fetched from the stack as if it were an int. (Treating the 4-byte value
  8739.    5.0 as a 2-byte int returns two zero bytes, or 0.) Finally, examine()
  8740.    returns this incorrect value to main().
  8741.  
  8742.    How can we avoid this problem? In Chapter 3, we discussed strategies for
  8743.    ensuring sensible type conversions, such as using type casts. Here we need
  8744.    to tell QuickC the data type of the function's parameters. You do this by
  8745.    providing a complete declaration called a function prototype.
  8746.  
  8747.    A function prototype declares the name of the function, its return type,
  8748.    the data type of each parameter, and, optionally, the parameter's name.
  8749.    Below are some sample declarations:
  8750.  
  8751.      int factorial(int number);
  8752.      int expo(int number, int power);
  8753.      void line(int x1, int y1, int x2, int y2, int color);
  8754.      char getyn(void);
  8755.  
  8756.    These are all functions we used earlier in this chapter. Although you have
  8757.    already used return type declarations, the full ANSI prototypes add an
  8758.    additional specification──the data type for each formal parameter. The
  8759.    prototype for factorial() indicates that it returns a value of type int
  8760.    and accepts one parameter of type int. The prototype for expo() specifies
  8761.    that it returns an int and accepts two int parameters.
  8762.  
  8763.    ──────────────────────────────────────────────────────────────────────────
  8764.    Type Checking in Pascal and C
  8765.    In the type-mixing situation described above, a Pascal compiler would show
  8766.    an error. Pascal checks actual parameter types against the expected
  8767.    parameter types and is very strict about making you define types for
  8768.    everything. The traditional C philosophy, on the other hand, expects the
  8769.    programmer to anticipate problems carefully, so the compiler permits the
  8770.    mixing of function parameter types. Thus, because C does not force you to
  8771.    declare types for function parameters, it often cannot tell you that
  8772.    anything is wrong when the types of the actual and expected parameters
  8773.    don't match. If you follow modern C programming practice and define
  8774.    function return and parameter types, the compiler will alert you to many
  8775.    potential problems.
  8776.    ──────────────────────────────────────────────────────────────────────────
  8777.  
  8778.    The line() function uses a return type of void because it does not return
  8779.    a value; it does, however, take five int parameters. Finally, getyn()
  8780.    returns a char but has a parameter of void, which signifies that the
  8781.    function takes no parameters. In addition, the prototypes specify the
  8782.    names of the parameters. (Although the names are optional──you could say,
  8783.    for example, int factorial(int)──we recommend using the parameter names in
  8784.    the declaration so that all the information is in one place.)
  8785.  
  8786.    The beginning of the function definition should also contain the function
  8787.    return type, function name, and the list of formal parameters (the
  8788.    parameter names), as in the following:
  8789.  
  8790.      int factorial(int number)
  8791.      int expo(int number, int power)
  8792.      void line(int x1, int y1, int x2, int y2, int color)
  8793.      char getyn(void)
  8794.  
  8795.    You also could declare the parameter types separately on the following
  8796.    lines. (Again, the void in parentheses after getyn signifies that the
  8797.    function takes no parameters. Also, notice that the function definitions
  8798.    do not end with semicolons.)
  8799.  
  8800.  Advantages of Using Prototypes
  8801.  
  8802.    Using prototypes might involve a little more thought and a little more
  8803.    typing, but it offers many advantages, which is why the ANSI C standard
  8804.    and QuickC support it. First, the complete prototype contains all of the
  8805.    information you need to use the function: what you can put in and what you
  8806.    can expect to get out. Indeed, if you look up a library function using the
  8807.    on-line help, you will find the complete prototype prominently displayed.
  8808.  
  8809.    It is important to note that if you use prototypes, QuickC will check both
  8810.    the type and number of the parameters in your function calls against the
  8811.    type and number of the parameters you specify in the prototype. In cases
  8812.    where types are mixed, QuickC will try to promote smaller to larger types.
  8813.    (See the examples in Chapter 3.) If you use the wrong number of
  8814.    parameters, QuickC will display an error message.
  8815.  
  8816.    The PROTO.C program (Listing 6-12 on the following page) is a revision of
  8817.    the problem program MIXTYPES.C, rewritten to use function prototypes. This
  8818.    program produces more reasonable output than that produced by MIXTYPES.C:
  8819.  
  8820.      n in main() is 5.000000
  8821.      examine() says n is 5
  8822.      examine() returned n as 5
  8823.  
  8824.    With the prototype, QuickC knew that examine() needed an int. When the
  8825.    program tried to pass it a float, QuickC converted the value to an int
  8826.    before passing it to the function. (Some conversions can cause variables
  8827.    to lose precision, but the resulting value will be much more likely to be
  8828.    acceptable.)
  8829.  
  8830.    ──────────────────────────────────────────────────────────────────────────
  8831.    /* proto.c -- demonstrates function prototyping */
  8832.    /*            and parameter checking           */
  8833.  
  8834.    main()
  8835.    {
  8836.        float n = 9995.997;
  8837.        int i;
  8838.        int examine(int num);  /* declare function */
  8839.                               /* with prototype   */
  8840.  
  8841.        printf("n in main() is %f\n", n);
  8842.        i = examine(n);    /* pass float to function */
  8843.        printf("examine() returned n as %d\n", i);
  8844.    }
  8845.  
  8846.    int examine(num)
  8847.    {
  8848.        printf("examine() says n is %d\n", num);
  8849.        return(num);
  8850.    }
  8851.    ──────────────────────────────────────────────────────────────────────────
  8852.  
  8853.    Listing 6-12.  The PROTO.C program.
  8854.  
  8855.  
  8856.  Putting It All Together: A Larger Program
  8857.  
  8858.    To sum up our work with functions and function calls, we present the
  8859.    number game GETCLOSE.C (Listing 6-13), which uses 10 functions (counting
  8860.    main()). Although this program is much longer than previous programs,
  8861.    notice how the use of functions breaks this large, more complex program
  8862.    into manageable pieces. Look at the following listing; then we'll see how
  8863.    easy to understand this program actually is.
  8864.  
  8865.    ──────────────────────────────────────────────────────────────────────────
  8866.    /* getclose.c -- a number game using */
  8867.    /*               random numbers      */
  8868.  
  8869.    #define TRUE 1
  8870.    #define FALSE 0
  8871.  
  8872.        /* external variables */
  8873.        int number,     /* total number in current game   */
  8874.            moves,      /* number of moves in current game*/
  8875.            target,     /* target number to reach         */
  8876.            done,       /* true if game is over           */
  8877.            score,      /* score of current game          */
  8878.            wins = 0,   /* number of games won            */
  8879.            losses = 0, /* number of games lost           */
  8880.            total = 0;  /* total score                    */
  8881.  
  8882.        char move;
  8883.        /* function prototype declarations */
  8884.        void intro(void);       /* tell player about game   */
  8885.        char getyn(void);       /* get yes/no response      */
  8886.        int  random(int num);   /* random between 1 and num */
  8887.        void new_target(void);  /* target number for game   */
  8888.        char get_move(void);    /* get player's move        */
  8889.        void do_move(void);     /* generate num from move   */
  8890.        void check_move(void);  /* won, lost, or continue?  */
  8891.        void show_score(void);  /* show score for game      */
  8892.        void show_total(void);  /* show total score         */
  8893.    main()
  8894.    {
  8895.        intro();         /* print instructions */
  8896.  
  8897.        while (TRUE)     /* new games until user quits */
  8898.            {
  8899.            printf("\nDo you want to continue? ");
  8900.            if (getyn() != 'y')
  8901.                break;   /* exit program */
  8902.  
  8903.            done = FALSE;
  8904.            number = moves = score = 0;
  8905.            new_target();  /* target number for this game */
  8906.            while (!done)  /* play one game */
  8907.                {
  8908.                get_move();/* user selects random number  */
  8909.                do_move(); /* generate random number      */
  8910.                           /* and add                     */
  8911.                check_move();  /* win, lose, or continue? */
  8912.                }
  8913.            show_score();  /* score for this game */
  8914.            show_total();  /* total score         */
  8915.            }
  8916.    }
  8917.  
  8918.    void intro(void)
  8919.    {
  8920.        printf("Welcome to Getclose\n\n");
  8921.        printf("The object of this game is to\n");
  8922.        printf("try to get as close to the target\n");
  8923.        printf("number as possible in as few\n");
  8924.        printf("moves as possible by choosing from\n");
  8925.        printf("various ranges of random numbers.\n");
  8926.        printf("You score if you get within 4 of the\n");
  8927.        printf("target. You get a 100-point bonus for\n");
  8928.        printf("hitting the target, but you get no score\n");
  8929.        printf("if you go over.\n\n");
  8930.        }
  8931.    char getyn(void)
  8932.                        /* get yes or no answer      */
  8933.                        /* repeats until valid entry */
  8934.    {
  8935.        char ch;  /* character to read and return */
  8936.        while (TRUE)
  8937.            {
  8938.            printf(" (y or n) ");
  8939.            ch = getche();
  8940.            printf("\n");
  8941.            if ((ch == 'y') || (ch == 'n'))
  8942.            /* valid response, break out of loop */
  8943.                break;
  8944.            /* give error message and loop again */
  8945.            printf("please enter ");
  8946.            }
  8947.        return(ch);
  8948.    }
  8949.  
  8950.    int random(int num)
  8951.        /* generate random number between 1 and num     */
  8952.        /* doesn't use library function srand() because */
  8953.        /* we don't want the same seed each time        */
  8954.    {
  8955.        long seconds, result;
  8956.        time(&seconds);   /* randomize with system time */
  8957.        return(abs ((int)seconds * rand() % num) + 1);
  8958.    }
  8959.  
  8960.    void new_target(void)
  8961.                 /* generate a new target number */
  8962.                 /* between 50 and 99            */
  8963.    {
  8964.        target = 50 + random(49);
  8965.        printf("\nYour target for this game is %d\n",
  8966.            target);
  8967.    }
  8968.  
  8969.    char get_move(void)
  8970.    {
  8971.        while (TRUE)
  8972.            {
  8973.            printf("\nPick a random number from 1 to\n");
  8974.            printf("a) 5  b) 10  c) 25  d) 50  e) 100 ");
  8975.            move = getche();
  8976.            if ((move >= 'a') && (move <= 'e'))
  8977.                {
  8978.                ++moves; /* count the move */
  8979.                break;   /* valid response */
  8980.                }
  8981.            /* invalid response, try again */
  8982.            printf("\nPlease type a, b, c, d, or e\n");
  8983.            }
  8984.    }
  8985.  
  8986.    void do_move(void)
  8987.    {
  8988.        int num = 0;  /* random value to obtain */
  8989.        switch (move)
  8990.            {
  8991.            case 'a' :
  8992.                num = random(5);
  8993.                break;
  8994.            case 'b' :
  8995.                num = random(10);
  8996.                break;
  8997.            case 'c' :
  8998.                num = random(25);
  8999.                break;
  9000.            case 'd' :
  9001.                num = random(50);
  9002.                break;
  9003.            case 'e' :
  9004.                num = random(100);
  9005.                break;
  9006.            }
  9007.        number += num;  /* add new number to total */
  9008.        printf("\n\nYou got a %d. Number is now: %d ", num, number);
  9009.        printf("(Target is %d)\n", target);
  9010.    }
  9011.  
  9012.    void check_move(void)
  9013.    {
  9014.        int temp;
  9015.        if (number > target)
  9016.            {
  9017.            printf("\nYou went over! ");
  9018.            printf("No score this game.\n");
  9019.            losses++;
  9020.            done = TRUE; /* to break out of loop */
  9021.            }
  9022.        if (number == target)
  9023.            {
  9024.            printf("\nYou hit the target ");
  9025.            printf("for 100 bonus points!\n");
  9026.            score = (100 / moves) + 100;
  9027.            total += score;
  9028.            wins++;
  9029.            done = TRUE;
  9030.            }
  9031.        if ((number >= (target - 4)) && (number < target))
  9032.            {
  9033.            temp = 100 / moves;
  9034.            /* does player want to go for broke? */
  9035.            printf("\nTake %d points (y) or continue (n)? ",
  9036.                temp);
  9037.            if (getyn() == 'y')
  9038.                {
  9039.                score = temp;
  9040.                total += score;
  9041.                wins++;
  9042.                done = TRUE;
  9043.                }
  9044.           }
  9045.    }
  9046.  
  9047.    void show_score(void)
  9048.    {
  9049.        printf("\nYou scored %d points in %d moves.\n",
  9050.            score, moves);
  9051.    }
  9052.  
  9053.    void show_total(void)
  9054.    {
  9055.        printf("You have won %d game(s) ", wins);
  9056.        printf("and lost %d.\n", losses);
  9057.        printf("Your total score is %d\n", total);
  9058.    }
  9059.    ──────────────────────────────────────────────────────────────────────────
  9060.  
  9061.    Listing 6-13.  The GETCLOSE.C program.
  9062.  
  9063.  Overview of the Game
  9064.  
  9065.    GETCLOSE.C is a number game in which you try to reach a randomly generated
  9066.    target number between 50 and 99 in as few moves as possible. Each "move"
  9067.    consists of choosing one of five possible ranges of random numbers: 1─5,
  9068.    1─10, 1─25, 1─50, and 1─100. You start at zero, and each number you choose
  9069.    is added to your total. Thus, each move brings your total closer to the
  9070.    target number. If you get within 4 of the target, you can settle for a
  9071.    score that depends on the number of moves you've made, or you can continue
  9072.    to try to hit the target exactly. If you actually hit the target number,
  9073.    you get a 100-point bonus. If you go over, however, you lose and score
  9074.    nothing. The program lets you play new games, and it keeps track of your
  9075.    total score and the number of games you have won and lost.
  9076.  
  9077.    The strategy of the game involves deciding how large a range from which to
  9078.    pick the next random number. If you pick from the larger ranges, you can
  9079.    reach the target number in only a few moves, gaining you a high score. But
  9080.    the big ranges also present you with a greater chance of overshooting the
  9081.    target, giving you no points at all. (Playing the game is a little like
  9082.    playing blackjack, except that you have five different decks from which to
  9083.    choose cards.)
  9084.  
  9085.  Playing the Game
  9086.  
  9087.    Type in the program, run it, and play a few games to get an idea of the
  9088.    different operations the program performs. Then read the next section to
  9089.    explore the program's inner workings. The following is a sample game:
  9090.  
  9091.      Welcome to Getclose
  9092.  
  9093.      The object of this game is to
  9094.      try to get as close to the target
  9095.      number as possible in as few
  9096.      moves as possible by choosing from
  9097.      various ranges of random numbers.
  9098.      You score if you get within 4 of the
  9099.      target. You get a 100-point bonus for
  9100.      hitting the target, but you get no score
  9101.      if you go over.
  9102.  
  9103.  
  9104.      Do you want to continue?  (y or n) y
  9105.  
  9106.      Your target for this game is 93
  9107.  
  9108.      Pick a random number from 1 to
  9109.      a) 5  b) 10  c) 25  d) 50  e) 100 e
  9110.  
  9111.      You got a 31. Number is now: 31 (Target is 93)
  9112.  
  9113.      Pick a random number from 1 to
  9114.      a) 5  b) 10  c) 25  d) 50  e) 100 d
  9115.  
  9116.      You got a 13. Number is now: 44 (Target is 93)
  9117.  
  9118.      Pick a random number from 1 to
  9119.      a) 5  b) 10  c) 25  d) 50  e) 100 d
  9120.  
  9121.      You got a 19. Number is now: 63 (Target is 93)
  9122.  
  9123.      Pick a random number from 1 to
  9124.      a) 5  b) 10  c) 25  d) 50  e) 100 d
  9125.  
  9126.      You got a 13. Number is now: 76 (Target is 93)
  9127.  
  9128.      Pick a random number from 1 to
  9129.      a) 5  b) 10  c) 25  d) 50  e) 100 c
  9130.  
  9131.      You got a 16. Number is now: 92 (Target is 93)
  9132.  
  9133.      Take 20 points (y) or continue (n)?  (y or n) y
  9134.  
  9135.      You scored 20 points in 5 moves.
  9136.      You have won 1 game(s) and lost 0.
  9137.      Your total score is 20
  9138.  
  9139.  The main() Function
  9140.  
  9141.    As you have seen, the main() function of a C program controls the overall
  9142.    flow of the program, while calls to various functions do the actual work.
  9143.    To explore GETCLOSE.C, look at the structure of main(). Even without
  9144.    knowing how the functions work, you can see the general structure of the
  9145.    program. First, it calls the intro() function to explain the game briefly.
  9146.    (Notice that we commented each of the function prototype declarations in a
  9147.    block before main(). This quickly lets you understand the purpose of every
  9148.    function.)
  9149.  
  9150.    The outer while loop permits unlimited games until the user decides to
  9151.    quit. At the start of each game, new_target() generates a new target
  9152.    number, and then the inner while loop processes the player's moves until
  9153.    the game ends. In this loop, getmove() prints a menu and lets the user
  9154.    select a range of random numbers for the next move. The do_move() function
  9155.    gets the random number and adds it to the player's current total;
  9156.    check_move() then compares the current total and the target number and
  9157.    decides if the player has won, lost, or can continue playing.
  9158.  
  9159.    Finally, when the inner loop (which represents one game) ends,
  9160.    show_score() displays the score of the last game, and show_total()
  9161.    displays the total score and the games won and lost thus far.
  9162.  
  9163.    You can also use the QuickC Calls menu to help you understand how the
  9164.    function calls work. First, compile GETCLOSE.C with Debug selected, and
  9165.    then move the cursor to the body of a function you want to examine. Use
  9166.    the Debug menu to set a breakpoint there, then run the program. When the
  9167.    program stops at the breakpoint, pull down the Calls menu to see a list of
  9168.    all called functions. Then display the text of any listed function by
  9169.    selecting it. The Calls menu is especially useful for examining programs
  9170.    that nest function calls.
  9171.  
  9172.  Modifying GETCLOSE.C
  9173.  
  9174.    One of the best ways to improve your knowledge of C is to take a program
  9175.    such as GETCLOSE.C and try to add features to it. You might already have
  9176.    some ideas in mind from playing and studying the game. Here are some
  9177.    possibilities:
  9178.  
  9179.    1.  Give points for how close the player gets to the target number.
  9180.  
  9181.    2.  Generate a "poison number" between 1 and the target number minus 10.
  9182.        If the player gets within 4 of this number without going over, he or
  9183.        she loses.
  9184.  
  9185.    3.  Similarly, you could specify a "free number" that, when reached, is
  9186.        not counted as a turn, thus potentially increasing the player's score.
  9187.  
  9188.  
  9189.  
  9190.  ────────────────────────────────────────────────────────────────────────────
  9191.  PART 3  ADVANCED C TOPICS
  9192.  ────────────────────────────────────────────────────────────────────────────
  9193.  
  9194.  
  9195.  
  9196.  ────────────────────────────────────────────────────────────────────────────
  9197.  Chapter 7  Arrays
  9198.  
  9199.    In programming, it is often advantageous to collect variables into sets or
  9200.    lists, so that many values can be stored and manipulated as a single
  9201.    conceptual unit. Such a collection of variables, when all those variables
  9202.    are the same type, is called an array. Arrays are used to organize values
  9203.    in applications that range from the "top ten" scores in a video game to
  9204.    the payroll records for thousands of employees.
  9205.  
  9206.    To visualize the advantage of arrays over simple variables, imagine that
  9207.    you run a business and that you want to store each employee's working
  9208.    hours in your computer. If you have even two employees, a year's worth of
  9209.    variables might look like this:
  9210.  
  9211.      int emp1_jan_1, emp2_jan_1;
  9212.      int emp1_jan_2, emp2_jan_2;
  9213.      ...──────────────────────────────────And so on for 362 intervening lines
  9214.      int emp1_dec_31, emp2_dec_31;
  9215.  
  9216.  
  9217.    Clearly, even the typing is a monumental undertaking. You can express the
  9218.    same number of variables as an array in C in a single line of code:
  9219.  
  9220.      int employees[2][365];
  9221.  
  9222.    Without a doubt, arrays let you organize data more concisely than do
  9223.    simple variables. This is convincingly illustrated in Figure 7-1.
  9224.  
  9225.    Although the details of declaration, storage, and retrieval differ from
  9226.    language to language, the basic nature of an array does not. In its
  9227.    simplest form, an array consists of one or more variables of the same
  9228.    storage type (size and number of bytes), arranged one after the other,
  9229.    continuously upward in memory. All variables in an array are referenced by
  9230.    a single name, called an identifier.
  9231.  
  9232.    ┌────────────────────────────────────────────────────────────────────────┐
  9233.    │ Figure 7-1 can be found on p.190 of the printed version of the book.   │
  9234.    └────────────────────────────────────────────────────────────────────────┘
  9235.  
  9236.    Figure 7-1. Arrays provide superior organization over simple variables for
  9237.    many common C programs.
  9238.  
  9239.  
  9240.  How Arrays Are Stored in Memory
  9241.  
  9242.    The elements in an array are stored consecutively in memory. An array
  9243.    consisting of only four int values, for example, is stored in memory as
  9244.    shown in Figure 7-2. Four int values (of two bytes each on the IBM PC)
  9245.    are arranged together in ascending order in memory. That is, the array
  9246.    begins with the leftmost int──the one lowest in memory──and continues
  9247.    upward in memory with one or more adjoining int values.
  9248.  
  9249.                  ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
  9250.    Array of ──── │     int     │     int     │     int     │     int     │
  9251.    4 ints        └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
  9252.  
  9253.    Memory ───────── 46     47     48     49     50     51     52     53
  9254.    location
  9255.  
  9256.    Figure 7-2. An array of four int values as stored in memory.
  9257.  
  9258.  
  9259.  How to Declare Arrays
  9260.  
  9261.    When you declare an array, you must tell the compiler how many items of
  9262.    which data type to set aside in memory for storage and the name to use
  9263.    when referencing that storage.
  9264.  
  9265.    The rules for declaring an array in C are relatively straightforward:
  9266.  
  9267.    ■  First, declare the type (char, float, int, etc.).
  9268.  
  9269.    ■  Second, declare the name. Array names use the same naming conventions
  9270.       as variable names.
  9271.  
  9272.    ■  Third, declare the number of items in the array by placing an integer
  9273.       constant expression inside square brackets; for example, [15].
  9274.  
  9275.    You recall, of course, that an "integer constant expression" is any
  9276.    integer constant value or any combination of integer constant values and
  9277.    arithmetic operators. Thus, 15 is an integer constant value, and so are 3,
  9278.    0x0F, and `a'. The last is a character constant that C views as an integer
  9279.    constant. But 3.0 is a floating-point constant and thus illegal for
  9280.    specifying the array size. The expression 15 * 2 is an integer constant
  9281.    expression because it is one integer constant value multiplied by another.
  9282.  
  9283.    Remember, you cannot specify the number of elements in an array with a
  9284.    variable. The following array declaration, for example, is illegal:
  9285.  
  9286.      int line_num = 15;
  9287.      int widths[line_num];
  9288.  
  9289.    ──────────────────────────────────────────────────────────────────────────
  9290.    BASIC and Pascal Array Declarations
  9291.    Declaring an array in C is similar to declaring an array in BASIC and
  9292.    Pascal. In BASIC, an array is declared as widths%(15); in Pascal, the same
  9293.    array is declared as widths : ARRAY [1...15] OF INTEGER. In C, we declare
  9294.    this array as:
  9295.  
  9296.      int widths[15];
  9297.  
  9298.    All three of these declarations identify an array named widths composed of
  9299.    15 integer variables. Each sets aside room in memory for 15 int values (30
  9300.    bytes on the IBM PC because each int occupies two bytes). As you can see,
  9301.    declaring an array in C retains the simplicity of BASIC but is clearer
  9302.    than BASIC.
  9303.  
  9304.    The 1...15 expression in the Pascal declaration tells the compiler that
  9305.    the elements in the array are represented by the numbers 1 through 15. In
  9306.    C, array elements are always numbered beginning with 0 and ascending to
  9307.    the specified number.
  9308.    ──────────────────────────────────────────────────────────────────────────
  9309.  
  9310.    You cannot use the expression line_num to declare the number of elements
  9311.    in the array widths. The C compiler looks at only one small piece of a
  9312.    program at a time. It first sees int line_num = 15 and generates code to
  9313.    store the value 15 into the variable line_num. When it reaches the array
  9314.    declaration, all it knows of line_num is that it currently contains the
  9315.    value 15; QuickC has no idea how that value will change as the program
  9316.    executes.
  9317.  
  9318.    In C, a constant variable, that is, one declared with the ANSI keyword
  9319.    const, is not considered a constant value. Therefore, the following
  9320.    example is illegal:
  9321.  
  9322.      const int line_num = 15;
  9323.      int widths[line_num];
  9324.  
  9325.    Using the const keyword declares to the compiler that you do not intend to
  9326.    change the value of line_num. It does not prevent a bug in your program
  9327.    from accidentally changing that value.
  9328.  
  9329.    If you attempt to declare the size of an array with a variable, even a
  9330.    const variable, QuickC will print the following error message:
  9331.  
  9332.      Error C2057:
  9333.      expected constant expression
  9334.  
  9335.    Examine the ARRAY1.C program (Listing 7-1). This "do-nothing" program
  9336.    demonstrates the correct way to declare arrays.
  9337.  
  9338.    In this program, SIZEOARRAY is specified using #define as 26. The number
  9339.    of items in ages is therefore declared with 26 * 2, which is legal.
  9340.  
  9341.    ──────────────────────────────────────────────────────────────────────────
  9342.    /* array1.c -- how to declare arrays legally        */
  9343.  
  9344.    #define SIZEOARRAY 26
  9345.  
  9346.    main()
  9347.    {
  9348.        char  initials[26];
  9349.        int   num_men[26], num_women[SIZEOARRAY];
  9350.        float ages[SIZEOARRAY * 2];
  9351.    }
  9352.    ──────────────────────────────────────────────────────────────────────────
  9353.  
  9354.    Listing 7-1.  The ARRAY1.C program.
  9355.  
  9356.  
  9357.  Referencing and Using Array Items
  9358.  
  9359.    The way you reference the items in an array (whether to store values in
  9360.    them or to fetch values from them) looks very much like the declaration.
  9361.    You merely state the identifier for the array and place the offset of the
  9362.    item within square brackets. The offset is always measured from the
  9363.    beginning of the array, with the first item having an offset of 0.
  9364.  
  9365.    For example, the expression
  9366.  
  9367.      widths[1] = 3;
  9368.  
  9369.    stores the value 3 in the second item of the array named widths; that is,
  9370.    the item whose offset from the beginning of the array is 1.
  9371.  
  9372.    Conversely, the expression
  9373.  
  9374.      this_width = widths[1];
  9375.  
  9376.    retrieves the value of the second item of the array widths and assigns
  9377.    that value to the variable this_width.
  9378.  
  9379.    In C, the offset into an array can be the result of any expression that
  9380.    returns a value. It can be the value of a variable, the result of a
  9381.    computation or logical test, or even the returned value of a function
  9382.    call. The only restriction is that the array offset must be specified with
  9383.    an integer value. The following are legal specifications:
  9384.  
  9385.      widths[1]───────────────────────────────────────────Offset is a constant
  9386.      widths[i]──────────────────────────────────────Offset is an int variable
  9387.      widths[i++]──────────────────────────────────────Offset is a computation
  9388.      widths[getnum()]───────────────────────────Return value of function call
  9389.      widths['a']────────────────────────────────────Offset is a char constant
  9390.  
  9391.    However, the following float type offset causes a compiler error:
  9392.  
  9393.      widths[fltval]──────────────────────────────────────float offset (error)
  9394.  
  9395.    Because there are no fractional memory locations, specifying an array's
  9396.    offset with a float causes the following QuickC error:
  9397.  
  9398.      error C2108:
  9399.      non-integral index
  9400.  
  9401.    With a legal offset specification, an array element is no different from
  9402.    an ordinary variable of that type. You can perform the same operations
  9403.    with an array item as you can with any ordinary variable. Consider, for
  9404.    example:
  9405.  
  9406.      widths[1] = 3;
  9407.      total  = widths[0] + widths[1] + widths[2];
  9408.  
  9409.    In the first operation, the value 3 is stored in the second element of the
  9410.    array named widths. In the second, values stored in three array elements
  9411.    are added together. Notice that we use the same notation to access each──
  9412.    an offset in brackets.
  9413.  
  9414.  An Example
  9415.  
  9416.    Now that you have the basic rules for declaring arrays and accessing items
  9417.    in those arrays, examine the XMAS.C program (Listing 7-2).
  9418.  
  9419.    In XMAS.C, we declare the array widths to contain 20 items of the type
  9420.    int. That array is then filled with values by the for loop; this is one
  9421.    way to store values in an array. Finally, each item in the array widths is
  9422.    passed to the function Center_out(); this is one way to access the values
  9423.    in an array.
  9424.  
  9425.    ──────────────────────────────────────────────────────────────────────────
  9426.    /* xmas.c -- fills an array with values, then passes */
  9427.    /*           each of those values to a function      */
  9428.  
  9429.    main()
  9430.    {
  9431.        int i, j, widths[20];
  9432.        void Center_out();
  9433.  
  9434.        for (i = 0, j = 1; i < 18; ++i, j += 2)
  9435.            {
  9436.            widths[i] = j;
  9437.            }
  9438.        widths[i++] = 3;
  9439.        widths[i] = 3;
  9440.  
  9441.        for (i = 0; i < 20; i++)
  9442.            {
  9443.            Center_out('X', widths[i]);
  9444.            }
  9445.  
  9446.    }
  9447.  
  9448.    void Center_out(char character, int width)
  9449.        {
  9450.        int i;
  9451.  
  9452.        for (i = 0; i < ((80 - width) / 2); ++i)
  9453.            {
  9454.            putch(' ');
  9455.            }
  9456.        for (i = 0; i < width; ++i)
  9457.            {
  9458.            putch(character);
  9459.            }
  9460.        putch('\r');
  9461.        putch('\n');
  9462.    }
  9463.    ──────────────────────────────────────────────────────────────────────────
  9464.  
  9465.    Listing 7-2.  The XMAS.C program.
  9466.  
  9467.    Whenever you reference an array element, the value of that element becomes
  9468.    available for use──you can assign the value to other variables or pass it
  9469.    to a function. Note, however, that passing an array element by giving its
  9470.    name and an offset merely passes a copy of that element, not the element
  9471.    itself. This is the method for passing ordinary variables.
  9472.  
  9473.  
  9474.  Bounds Checking Arrays in Your Code
  9475.  
  9476.    In XMAS.C, the for loop prevents your specifying an offset beyond the end
  9477.    of the array widths:
  9478.  
  9479.      for (i = 0; i < 20; ++i)
  9480.  
  9481.    In many programs, however, the ability to exceed an array's bounds is not
  9482.    prevented by your code but is controlled by the user. For example, the
  9483.    SADD.C program (Listing 7-3) is a simple adding machine that lets the
  9484.    user enter as many as three numbers, one per line, and terminate entry
  9485.    with any non-numeric character such as an x.
  9486.  
  9487.    Now run SADD.C and enter (on separate lines) the numbers 1, 2, and 3,
  9488.    followed by an x character. The program displays the correct sum,
  9489.    which is 6:
  9490.  
  9491.      1
  9492.      2
  9493.      3
  9494.      x
  9495.      ----------
  9496.      6
  9497.  
  9498.    ──────────────────────────────────────────────────────────────────────────
  9499.    /* sadd.c -- a small adding machine that illustrates  */
  9500.    /*            the need for array bounds checking      */
  9501.  
  9502.    main()
  9503.    {
  9504.        int offset = 0, i, result = 0;
  9505.        int stack[3];
  9506.  
  9507.        while (scanf("%d", &stack[offset]) == 1)
  9508.            {
  9509.            ++offset;
  9510.            }
  9511.        for (i = 0; i < offset; ++i)
  9512.            {
  9513.            result += stack[i];
  9514.            }
  9515.        printf("----------\n");
  9516.        printf("%d\n", result);
  9517.  
  9518.    }
  9519.    ──────────────────────────────────────────────────────────────────────────
  9520.  
  9521.    Listing 7-3.  The SADD.C program.
  9522.  
  9523.    Now run the program again, but this time enter four numbers:
  9524.  
  9525.      1
  9526.      2
  9527.      3
  9528.      4
  9529.      x
  9530.      ----------
  9531.      20
  9532.  
  9533.    The result shown is 20, which is wrong. But QuickC doesn't recognize that
  9534.    an error occurred and prints no error message. The C language itself,
  9535.    unlike Pascal and BASIC, contains no provisions to prevent offsets beyond
  9536.    the end of an array.
  9537.  
  9538.    To understand why SADD.C referenced stack[3], even though no fourth item
  9539.    exists (remember that arrays begin with item 0), let's look again at the
  9540.    way arrays are arranged in memory. As a bonus, we'll find out where the
  9541.    value 20 came from. Figure 7-3a shows how the compiler translates into
  9542.    memory the declarations from SADD.C (shown on the next page).
  9543.  
  9544.    ┌──────────────────────────────────────────────────────────────┐
  9545.    │°                                        Initialized         °│
  9546.    │°       int offset=0, i, result=0;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒  °│
  9547.    │°       int stack[3];                                     ▒  °│
  9548.    │°  ▒▒▒▒▒while (scanf("%d", &stack [offset]) == 1)         ▒  °│
  9549.    │°  ▒          ++offset;                 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒  °│
  9550.    │°  ▒                                    ▒                 ▒  °│
  9551.    │°  ▒    ┌────────┬────────┬────────┬───────┬────────┬───────┤
  9552.    │°  ▒    │    ?   │    ?   │    ?   │    0   │    ?   │    0   │
  9553.    │°  ▒    └────────┴────────┴────────┴────────┴────────┴────────┤
  9554.    │°  ▒     stack[0] stack[1] stack[2]  result      i     offset├─────┐
  9555.    │°  ▒                                                     °│     │
  9556.    └─────────────▒────────▒────────▒────────▒─────────────────────┘     │
  9557.        ▒▒▒▒▒▒▒▒▒▒1▒▒▒▒▒▒▒▒2▒▒▒▒▒▒▒▒3▒▒▒▒▒▒▒▒4                           │
  9558.                 │                            │                          │
  9559.                 └──────────────┬─────────────┘                          │
  9560.                                │                                        │
  9561.                      Stores these input values                          │
  9562.                      while incrementing offset──────────────────────────┘
  9563.  
  9564.    (A)
  9565.  
  9566.  
  9567.    ┌────────┬────────┬────────┬────────┬────────┬────────┐
  9568.    │    1   │    2   │    3   │    4   │    ?   │    4   │
  9569.    └────────┴────────┴────────────────┴────────┴────────┘
  9570.     stack[0] stack[1] stack[2]│ result      i     offset
  9571.                               │    
  9572.             Array ends here───┘    │
  9573.                                    │
  9574.                            Position of stack[3]
  9575.  
  9576.    (B)
  9577.  
  9578.    Figure 7-3. Consequence of referencing beyond the end of an array.
  9579.  
  9580.      int offset = 0, i, result = 0;
  9581.      int stack[3];
  9582.  
  9583.    First, the variables offset and result are set to 0. Then the while loop
  9584.    fills out the items in the 3-element array stack. The last value entered
  9585.    was 4, which was the fourth value placed into stack. But stack contains no
  9586.    fourth item (that is, no stack[3] ), so the fourth value is placed into
  9587.    result because result occupies the place in memory that follows the stack
  9588.    array.
  9589.  
  9590.    The arrangement depicted in Figure 7-3a occurs because QuickC places auto
  9591.    variables into memory from the top down, but it places static and global
  9592.    variables into memory from the bottom up.
  9593.  
  9594.    Now look closely at Figure 7-3b. Because result begins with a value of 4
  9595.    instead of 0, the for loop adds 1, 2, and 3 to it, resulting in a sum of
  9596.    10. The for loop continues (because offset is 4) by adding stack[3] to
  9597.    result (both reference the same address and the same value, 10), thus
  9598.    yielding the erroneous value of 20.
  9599.  
  9600.    To make programs less sensitive to improper user input, always provide
  9601.    code that detects array out-of-bounds conditions. You can do this by
  9602.    simply terminating the program when an error is detected, but writing your
  9603.    program so that it can recover from errors is better. The SADD2.C program
  9604.    (Listing 7-4) shows a common approach to array bounds checking that
  9605.    corrects the previous program's weakness.
  9606.  
  9607.    ──────────────────────────────────────────────────────────────────────────
  9608.    /* sadd2.c -- a small adding machine that includes */
  9609.    /*            array bounds checking                */
  9610.  
  9611.    #define MAXSTAK 3
  9612.  
  9613.    main()
  9614.    {
  9615.        int offset = 0, i, result = 0;
  9616.        int stack[MAXSTAK];
  9617.  
  9618.        while (scanf("%d", &stack[offset]) == 1)
  9619.            {
  9620.            if (++offset >= MAXSTAK)
  9621.                {
  9622.                printf("Stack Full\n");
  9623.                break;
  9624.                }
  9625.            }
  9626.        for (i = 0; i < offset; ++i)
  9627.            {
  9628.            result += stack[i];
  9629.            }
  9630.        printf("----------\n");
  9631.        printf("%d\n", result);
  9632.  
  9633.    }
  9634.    ──────────────────────────────────────────────────────────────────────────
  9635.  
  9636.    Listing 7-4.  The SADD2.C program.
  9637.  
  9638.    In this revision of SADD.C, we use the preprocessor #define directive to
  9639.    create an alias for the size of the array stack. Thus, you can later
  9640.    easily change the number of items in stack by changing a single #define
  9641.    and then recompiling.
  9642.  
  9643.    Next, we insert an if statement that checks a preincremented offset to be
  9644.    sure it does not exceed the number of items in stack, that is, MAXSTAK. If
  9645.    offset becomes too large, the if statement first causes a warning message
  9646.    to be printed and then breaks out of the while loop. The user gets an
  9647.    accurate sum for the numbers entered, despite the error, and any
  9648.    out-of-range numbers are simply ignored.
  9649.  
  9650.  
  9651.  How to Initialize Arrays
  9652.  
  9653.    When you declare an auto array (an array declared inside a function and
  9654.    without the keyword static), it is initially filled with garbage values,
  9655.    regardless of its type and size. (This also occurs when you create auto
  9656.    variables.) On the other hand, static arrays and arrays declared outside
  9657.    of functions always have their initial values set to zero──again just like
  9658.    ordinary variables. For example:
  9659.  
  9660.      char Letters[26];───────────────────────────────────Initialized to zeros
  9661.  
  9662.      main()
  9663.      {
  9664.          char vowels[5];──────────────────────────────────Starts with garbage
  9665.          static char consonants[21];─────────────────────Initialized to zeros
  9666.  
  9667.    When zero is not an appropriate initial value, you can give static and
  9668.    global variables starting values of your choice. To initialize an array:
  9669.  
  9670.    ■  Follow the right square bracket (]) in the array identifier with an
  9671.       assignment operator (=) and a left brace ({).
  9672.  
  9673.    ■  Then state each initializing value, followed by a comma.
  9674.  
  9675.    ■  Finally, terminate your comma-separated list of initializers with a
  9676.       right brace (}) and the usual semicolon.
  9677.  
  9678.    For example, to initialize the array Letters with the letters of the
  9679.    alphabet, you need simply declare it as:
  9680.  
  9681.      char Letters[26] = { 'a', 'b', 'c', 'd', 'e',
  9682.                           'f', 'g', 'h', 'i', 'j',
  9683.                           'k', 'l', 'm', 'n', 'o',
  9684.                           'p', 'q', 'r', 's', 't',
  9685.                           'u', 'v', 'w', 'x', 'y',
  9686.                           'z', };
  9687.  
  9688.    Or, for an array of numbers you could declare:
  9689.  
  9690.      int Values[5] = { 12, 2, 44, 19, 7 };
  9691.  
  9692.    In both of the above examples, the type of the initializing values matches
  9693.    the type of the array and is a constant value. This is mandatory. Values
  9694.    in array initializing
  9695.  
  9696.    lists must be constant values or constant expressions, and those values
  9697.    must fit in the number of bytes declared for each array item. The array
  9698.    Letters is initialized with the type char, and `a' is a char constant. The
  9699.    array Values is initialized with type int, and 12 is an integer constant.
  9700.    A float array would have to be initialized with the type float, such as
  9701.    76.98, which is a floating-point constant.
  9702.  
  9703.    The ASIMOV.C program (Listing 7-5) contains in the initialized array
  9704.    Letters the name of a famous Isaac Asimov character. By entering the
  9705.    correct series of numbers, you can reveal that name.
  9706.  
  9707.    ──────────────────────────────────────────────────────────────────────────
  9708.    /* asimov.c -- illustrates how to initialize an      */
  9709.    /*             array with starting values            */
  9710.  
  9711.    #define MAXL 16
  9712.    char Letters[MAXL] = {
  9713.        'e', 'I', 'a', 'N', 'o', 'R', 'O', 'o',
  9714.        'u', 't', 'o', 'R', 'l', 'o', 'B', 'b', };
  9715.  
  9716.    main()
  9717.    {
  9718.        int num, i;
  9719.  
  9720.        printf("Guess my identity with numbers.\n");
  9721.        printf("(any non-number quits)\n\n");
  9722.  
  9723.        while (scanf("%d", &num) == 1)
  9724.            {
  9725.            if (num <= 0)
  9726.                {
  9727.                printf("Guesses must be above zero\n");
  9728.                continue;
  9729.                }
  9730.            for (i = 1; i <= num; ++i)
  9731.                {
  9732.                printf("%c", Letters[(i * num) % MAXL]);
  9733.                }
  9734.            printf("\n");
  9735.            }
  9736.    }
  9737.    ──────────────────────────────────────────────────────────────────────────
  9738.  
  9739.    Listing 7-5.  The ASIMOV.C program.
  9740.  
  9741.    ──────────────────────────────────────────────────────────────────────────
  9742.    Quick Tip
  9743.    The list of initializers for Letters ends with a trailing comma. That is
  9744.    not an error. Trailing commas in initializer value lists are optional but
  9745.    enable long lists to be rearranged easily with your text editor.
  9746.    ──────────────────────────────────────────────────────────────────────────
  9747.  
  9748.  Letting the Compiler Supply the Size
  9749.  
  9750.    When you declare the values for an initialized array, it is not always
  9751.    possible, or necessary, to state explicitly the number of items in the
  9752.    array. C provides an alternative. For example, the following declaration
  9753.    omits the size of the array:
  9754.  
  9755.      int  Primes[ ] = {1, 2, 3, 5, 7, 11,};
  9756.                  └─────────────────────────────────── Number of items omitted
  9757.  
  9758.    Whenever you omit the size, the C compiler counts the number of
  9759.    initializers and dimensions the array to the correct size for that count.
  9760.    Because the preceding example contains six initializers, that declaration
  9761.    is equivalent to declaring:
  9762.  
  9763.      int  Primes[6] = {1, 2, 3, 5, 7, 11,};
  9764.  
  9765.    When the size of an array is omitted, you might expect bounds checking in
  9766.    your code to be difficult. Fortunately, you can use the sizeof operator to
  9767.    find the number of bytes in an array and thus specify, using #define, a
  9768.    bounds-checking value. When used with the preceding declaration, the
  9769.    expression
  9770.  
  9771.      #define MAXL (sizeof(Primes)/sizeof(int))
  9772.  
  9773.    gives MAXL a value of 6.
  9774.  
  9775.    The sizeof keyword, when given the name of an array, yields the number of
  9776.    bytes in that array. The #define, then, is the number of bytes in the
  9777.    array Primes (12 bytes) divided by the number of bytes in an int (2
  9778.    bytes).
  9779.  
  9780.  Overinitializing and Underinitializing
  9781.  
  9782.    One good reason to omit the size of an array is that C permits a mismatch
  9783.    between the number of initializing values and the size you declare. When
  9784.    there are fewer initializers, the compiler silently fills the remainder
  9785.    with zero values. When there are too many initializers, the compiler
  9786.    complains and stops. Some compilers (especially under UNIX) will issue a
  9787.    warning and truncate the array.
  9788.  
  9789.    The UNDOVER.C program (Listing 7-6) demonstrates this behavior. As the
  9790.    program stands, it prints the following message:
  9791.  
  9792.      The first 6 primes are: 1 2 3 5 7 11
  9793.  
  9794.    Now change Primes[6] to Primes[8] in the declaration and run the program
  9795.    again. This time it prints:
  9796.  
  9797.      The first 8 primes are: 1 2 3 5 7 11 0 0
  9798.  
  9799.    The new result shows that underinitializing causes the compiler to fill
  9800.    the leftover items with zero values. Now change the declaration again,
  9801.    this time from Primes[8] to Primes[3]. This time the QuickC compiler stops
  9802.    and issues the message:
  9803.  
  9804.      error C2078:
  9805.      too many initializers
  9806.  
  9807.    ──────────────────────────────────────────────────────────────────────────
  9808.    /* undover.c -- illustrates the effect of underinitializing and */
  9809.    /*              overinitializing arrays                         */
  9810.  
  9811.    int Primes[6] = { 1, 2, 3, 5, 7, 11 };
  9812.    #define NUMP (sizeof(Primes) / sizeof(int))
  9813.  
  9814.    main()
  9815.    {
  9816.        int i;
  9817.  
  9818.        printf("The first %d primes are: ", NUMP);
  9819.        for (i = 0; i < NUMP; ++i)
  9820.            {
  9821.            printf("%d ", Primes[i]);
  9822.            }
  9823.        printf("\n");
  9824.    }
  9825.    ──────────────────────────────────────────────────────────────────────────
  9826.  
  9827.    Listing 7-6.  The UNDOVER.C program.
  9828.  
  9829.  
  9830.  Arrays and Functions
  9831.  
  9832.    As you saw earlier in XMAS.C, passing one of an array's elements to a
  9833.    function is like passing an ordinary variable to a function. That is, a
  9834.    copy of the value of that element is passed, not the element itself.
  9835.  
  9836.    However, when you pass whole arrays to functions, the situation changes.
  9837.    Although you are still passing by value, what you are actually passing is
  9838.    the address of the array (its location in memory). The effect of this is
  9839.    that you appear to be passing the array itself and that the array itself
  9840.    will be changed. (See the next chapter for further details.) For now,
  9841.    we'll simply show you how to pass arrays to functions and how to use those
  9842.    arrays when they get there.
  9843.  
  9844.  Passing Arrays to Functions
  9845.  
  9846.    To pass an array to a function, merely state the array's name (minus the
  9847.    offset) in the function call. For example, if you have declared an array
  9848.    as follows:
  9849.  
  9850.      static int list[7] = { 5, 1, 3, 7, 2, 4, 6 };
  9851.  
  9852.    you would pass that array to a function, called Bub_sort() for example, by
  9853.    stating its name, as follows:
  9854.  
  9855.      Bub_sort(list);
  9856.  
  9857.    This tells the compiler to send the entire array named list to Bub_sort().
  9858.  
  9859.    At the receiving end, in Bub_sort(), you need to declare the type of the
  9860.    received array. To do so, declare an array in the normal C manner and
  9861.    leave the square brackets empty:
  9862.  
  9863.      Bub_sort(vals)
  9864.      int vals[];
  9865.      {
  9866.  
  9867.    This declares that a function named Bub_sort() will receive one argument,
  9868.    the int array vals. Because Bub_sort() is receiving an array──via the
  9869.    array's address──it receives the array itself and not a copy of that
  9870.    array. This allows Bub_sort() to change the original array.
  9871.  
  9872.    The BUBSORT.C program (Listing 7-7) demonstrates the differences between
  9873.    passing array elements to functions and passing entire arrays.
  9874.  
  9875.    ──────────────────────────────────────────────────────────────────────────
  9876.    /* bubsort.c  --  passing an array to a function  */
  9877.    /*                affects the original array      */
  9878.  
  9879.    #define NUMINTS 6
  9880.  
  9881.    extern void Bub_sort();
  9882.    extern void Triple();
  9883.    main()
  9884.    {
  9885.        int num = 2, i;
  9886.        static int list[NUMINTS] = { 6, 5, 4, 3, 2, 1 };
  9887.  
  9888.        printf("num before Triple = %d\n", num);
  9889.        Triple(num);
  9890.        printf("num after Triple = %d\n", num);
  9891.        printf("list[0] before Triple = %d\n", list[0]);
  9892.        Triple(list[0]);
  9893.        printf("list[0] after Triple = %d\n", list[0]);
  9894.        printf("Before sorting -> ");
  9895.        for (i = 0; i < NUMINTS; ++i)
  9896.            {
  9897.            printf("%d ", list[i]);
  9898.            }
  9899.        printf("\n");
  9900.  
  9901.        Bub_sort(list);
  9902.        printf("After sorting ->  ");
  9903.        for (i = 0; i < NUMINTS; ++i)
  9904.            {
  9905.            printf("%d ", list[i]);
  9906.            }
  9907.        printf("\n");
  9908.  
  9909.    }
  9910.    void Triple(int x)  /* function doesn't affect original */
  9911.    {
  9912.        x *= 3;
  9913.    }
  9914.  
  9915.    void Bub_sort(int vals[NUMINTS]) /* function changes original */
  9916.    {
  9917.        int i, j, temp;
  9918.  
  9919.        for (i = (NUMINTS - 1); i > 0; --i)
  9920.            {
  9921.            for (j = 0; j < i; ++j)
  9922.                {
  9923.                if (vals[j] > vals[j+1])
  9924.                    {
  9925.                    temp      = vals[j];
  9926.                    vals[j]   = vals[j+1];
  9927.                    vals[j+1] = temp;
  9928.                    }
  9929.                }
  9930.            }
  9931.    }
  9932.    ──────────────────────────────────────────────────────────────────────────
  9933.  
  9934.    Listing 7-7.  The BUBSORT.C program.
  9935.  
  9936.    This program first calls the Triple() function, passing it both an
  9937.    ordinary variable and one of the elements in the array list. The value of
  9938.    the original isn't changed in either case; only the value (a copy) of what
  9939.    is sent is changed.
  9940.  
  9941.    Next, we pass the array list to the function Bub_sort() (a simple bubble
  9942.    sorting function). The program prints the array before and after the
  9943.    function call to demonstrate that the Bub_sort() function changes the
  9944.    values in the original array; it does not sort a copy.
  9945.  
  9946.  Variations
  9947.  
  9948.    When a function receives an array, the number of elements in the
  9949.    declaration of that array is usually omitted because the size
  9950.    specification is optional:
  9951.  
  9952.      Bub_sort(vals)
  9953.      int vals[ ];
  9954.               └──────────────────────────────────────── Size of array omitted
  9955.  
  9956.    Restating that size in the function declaration, however, is often a good
  9957.    idea. As we have seen, C does no array bounds checking on your behalf, so
  9958.    restating the size of the received array helps to clarify and document
  9959.    your program:
  9960.  
  9961.      Bub_sort(vals)
  9962.      int vals[NUMINTS];
  9963.                  └────────────────────────────────────── Restated for clarity
  9964.  
  9965.    The type of the received array should also match that of the original. If
  9966.    the types do not match, your program might not work properly. The reason
  9967.    we say "might not" is that you might want to mismatch types intentionally.
  9968.    The HEXOUT.C program (Listing 7-8) demonstrates such a planned mismatch.
  9969.    This program asks you to enter a floating-point number and then prints out
  9970.    that number, one byte at a time, in hexadecimal notation.
  9971.  
  9972.    HEXOUT.C first reads a floating-point value into the array fary──a float
  9973.    type array consisting of only one element. That array is then passed to
  9974.    Hexout(). In Hexout(), we declare the type of the received array as
  9975.    unsigned char. This "deception" causes Hexout() to handle the array fary
  9976.    as if it were an array of single unsigned bytes, whereas the original was
  9977.    actually a 4-byte float type. We will explain this shortly. This deception
  9978.    illustrates one of C's primary strengths, the freedom of the programmer to
  9979.    change types in midstream.
  9980.  
  9981.    ──────────────────────────────────────────────────────────────────────────
  9982.    /* hexout.c --  prints a floating-point variable in */
  9983.    /*              hexadecimal format                  */
  9984.  
  9985.    extern void Hexout();
  9986.    main()
  9987.    {
  9988.        float fary[1];
  9989.  
  9990.        printf("Enter a floating-point number\n");
  9991.        printf("(Any non-numeric entry quits)\n\n");
  9992.        while (scanf("%f", &fary[0]) == 1)
  9993.            {
  9994.            Hexout(fary);
  9995.            }
  9996.    }
  9997.  
  9998.    void Hexout(unsigned char chary[])
  9999.    {
  10000.        int i;
  10001.  
  10002.        for (i = 0; i < sizeof(float); ++i)
  10003.            {
  10004.            printf("%02X ", chary[i]);
  10005.            }
  10006.        printf("\n\n");
  10007.    }
  10008.    ──────────────────────────────────────────────────────────────────────────
  10009.  
  10010.    Listing 7-8.  The HEXOUT.C program.
  10011.  
  10012.  
  10013.  How Array Offsets Advance
  10014.  
  10015.    When you reference an array element with an array name and an offset,
  10016.    QuickC invisibly converts the element offset to a bytes-in-memory offset.
  10017.    To illustrate this, let's look at how two different type arrays are
  10018.    organized in memory. Figure 7-4 shows that an array of char type occupies
  10019.    one byte of memory for each element and that an array of float type
  10020.    occupies four bytes of memory for each element.
  10021.  
  10022.    For the char array, chary[4], each element occupies one byte, so each
  10023.    element offset specification corresponds to the bytes-in-memory offset.
  10024.    For the float array fary[2], however, each element occupies four bytes, so
  10025.    each element offset specification corresponds to a bytes-in-memory offset
  10026.    of 4 bytes. In the latter case, when you specify
  10027.  
  10028.      fary[1]
  10029.  
  10030.    you are really telling the compiler to reference a value that is four
  10031.    bytes into the array fary[]. Because a float value occupies four bytes of
  10032.    memory, your element offset of 1 becomes a bytes-in-memory offset of 4
  10033.    bytes.
  10034.  
  10035.    This explains how, in the preceding program, HEXOUT.C, it is possible to
  10036.    print out a float one byte at a time. Inside the function Hexout(), the
  10037.    compiler thinks it is handling an array of unsigned char type, in which
  10038.    each element occupies a single byte. Thus, i increments in unmultiplied
  10039.    steps of single bytes.
  10040.  
  10041.                   char chary[4] = {'t', 'e', 's', 't'};
  10042.  
  10043.                       │ 1 byte │
  10044.                       │        │
  10045.                       ├────────┼────────┬────────┬────────┐
  10046.                       │   't'  │   'e'  │   's'  │    't' │
  10047.                       └────────┴────────┴────────┴────────┘
  10048.  
  10049.    (A)                        ARRAY OF char VALUES
  10050.  
  10051.  
  10052.    float fary [2] = {1.2, 4.3};
  10053.  
  10054.    │ 1 byte │
  10055.    │        │
  10056.    ├────────┴────────┬────────┬────────┬────────┬────────┬────────┬────────┐
  10057.    │                1.2                │                4.3                │
  10058.    └────────┴────────┴────────┴────────┴────────┴────────┴────────┴────────┘
  10059.                    fary[0]                             fary[0]
  10060.  
  10061.    (B)                        ARRAY OF float VALUES
  10062.  
  10063.    Figure 7-4. How offsets differ by number of bytes based on the type of the
  10064.    array.
  10065.  
  10066.  
  10067.  Multidimensional Arrays
  10068.  
  10069.    In C you can easily create and use arrays of two, three, or many
  10070.    dimensions. Two-dimensional arrays correspond to such useful items as
  10071.    calendars, spreadsheets, and maps. We begin with the rules for
  10072.    two-dimensional arrays and then apply them to arrays of three and more
  10073.    dimensions. Three-dimensional arrays find application in items such as 3-D
  10074.    graphics, layered indexes, and solid topology. Many-dimensioned arrays
  10075.    delve into the arcane worlds of higher math and complex games.
  10076.  
  10077.  Two-dimensional Arrays
  10078.  
  10079.    Two-dimensional arrays represent rectangular grids of data. As illustrated
  10080.    in Figure 7-5, they are organized in rows first and then columns. Because
  10081.    computer memory is linear, those rows and columns are stored in memory one
  10082.    row after the other.
  10083.  
  10084.    The rules for declaring a two-dimensional array are similar to those for
  10085.    declaring a one-dimensional array. They take the following form:
  10086.  
  10087.      type name[rows][columns];
  10088.  
  10089.    As with one-dimensional arrays, you must specify the number of rows and
  10090.    the number of columns as integer constant expressions. Thus, the
  10091.    expression
  10092.  
  10093.      int week[7][8];
  10094.  
  10095.    declares a two-dimensional array of type int, named week, with 7 rows (for
  10096.    7 days) and 8 columns (for 8 working hours per day). You can fill it with
  10097.    any number of useful items, for example, the number of lines of code
  10098.    written per hour per day.
  10099.  
  10100.                                      Columns
  10101.                                         │
  10102.                             ┌───────────┴───────────┐
  10103.                             │                       │
  10104.                             ┌───────┬───────┬───────┐ ───┐
  10105.                             │   1   │   2   │   3   │    │
  10106.                             ├───────┼───────┼───────┤    │
  10107.                             │   4   │   5   │   6   │    ├── Rows
  10108.                             ├───────┼───────┼───────┤    │
  10109.                             │   7   │   8   │   9   │    │
  10110.                             └───────┴───────┴───────┘ ───┘
  10111.                                         │
  10112.                                         │  Arranged in memory as
  10113.                                         
  10114.     ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
  10115.     │   1   │   2   │   3   │   4   │   5   │   6   │   7   │   8   │   9   │
  10116.     └───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘
  10117.     │                       │                       │                       │
  10118.     └───────────┬───────────┴───────────┬───────────┴───────────┬───────────┘
  10119.                 │                       │                       │
  10120.            Zeroth row               First row              Second row
  10121.  
  10122.    Figure 7-5. Two-dimensional arrays are arranged in memory row by row.
  10123.  
  10124.    Referencing two-dimensional array elements is as simple as referencing
  10125.    elements of one-dimensional arrays. Specify the row and column with
  10126.    integer expressions:
  10127.  
  10128.      int day  = 6, /* Saturday */
  10129.          hour = 2; /* 10:00 A.M. */
  10130.  
  10131.      printf("Wrote %d lines of code.\n", week[day][hour]);
  10132.  
  10133.    Initializing Two-dimensional Arrays
  10134.  
  10135.    Before we go into the somewhat more complex rules for initializing
  10136.    two-dimensional arrays, enter the MAGIC.C program (Listing 7-9). This
  10137.    program initializes an array of type int with scrambled numbers and then
  10138.    asks the user to rearrange those numbers into the correct order by
  10139.    continually swapping squares adjacent to the 0 with the 0. The object is
  10140.    to rearrange the numbers into ascending order, with 0 at the top left,
  10141.    counting up row by row.
  10142.  
  10143.    ──────────────────────────────────────────────────────────────────────────
  10144.    /* magic.c  --  demonstrates use of a two-dimensional  */
  10145.    /*              array of type int                      */
  10146.  
  10147.    main()
  10148.    {
  10149.        static int square[3][3] = { 5, 8, 3, 4, 2, 0, 7, 1, 6 };
  10150.        int zrow = 1, zcol = 2;  /* location of the zero */
  10151.        int num, row, col, i, j, rowdist, coldist;
  10152.  
  10153.        while (1)
  10154.            {
  10155.            printf("Swap what with zero?\n");
  10156.            printf("(Q to quit)\n");
  10157.  
  10158.            /* Print the square. */
  10159.            for (i = 0; i < 3; ++i)
  10160.                {
  10161.                for (j = 0; j < 3; ++j)
  10162.                    {
  10163.                    printf(" %d ", square[i][j]);
  10164.                    }
  10165.                printf("\n");
  10166.                }
  10167.  
  10168.            /* Enter the user number. */
  10169.            if ((num = getch()) == 'Q')
  10170.                exit(0);
  10171.            num -= '0';
  10172.            if (num < 1 || num > 9)
  10173.                {
  10174.                printf("Not a legal number.\n\n");
  10175.                continue;
  10176.                }
  10177.            /* Find that square. */
  10178.            for (row = 0; row < 3; ++row)
  10179.                {
  10180.                for (col = 0; col < 3; ++col)
  10181.                    {
  10182.                    if (num == square[row][col])
  10183.                        {
  10184.                        goto GOTIT;
  10185.                        }
  10186.                    }
  10187.                }
  10188.    GOTIT:
  10189.            /* Check for a legal move. */
  10190.            if (row > 2 || col > 2)
  10191.                {
  10192.                printf("Bad Box Specification\n\n");
  10193.                continue;
  10194.                }
  10195.            rowdist = zrow - row;
  10196.            if (rowdist < 0)
  10197.                rowdist *= -1;
  10198.            coldist = zcol - col;
  10199.            if (coldist < 0)
  10200.                coldist *= -1;
  10201.            if (rowdist > 1 || coldist > 1)
  10202.                {
  10203.                printf("Not a Neighbor\n\n");
  10204.                continue;
  10205.                }
  10206.  
  10207.            /* Make the move. */
  10208.            square[zrow][zcol] = square[row][col];
  10209.            square[row][col] = 0;
  10210.            zrow = row;
  10211.            zcol = col;
  10212.  
  10213.            /* See if done, and solved. */
  10214.            for (i = 0; i < 3; ++i)
  10215.                {
  10216.                for (j = 0; j < 3; ++j)
  10217.                    {
  10218.                    if (square[i][j] != ((i * 3) + j))
  10219.                        {
  10220.                        break;
  10221.                        }
  10222.                    }
  10223.                }
  10224.            if ((i * j) == 9)
  10225.                break;
  10226.            }
  10227.        printf("\n\aYOU GOT IT !!!\n");
  10228.    }
  10229.    ──────────────────────────────────────────────────────────────────────────
  10230.  
  10231.    Listing 7-9.  The MAGIC.C program.
  10232.  
  10233.    We initialize the two-dimensional array in MAGIC.C by filling it row by
  10234.    row. When, for clarity, you want to specify where one row ends and the
  10235.    next begins, you can enclose each row's initializers in another set of
  10236.    braces:
  10237.  
  10238.      static int square[3][3] = {
  10239.          {5, 8, 3},─────────────────────────────────────────────────────Row 0
  10240.          {2, 4, 0},─────────────────────────────────────────────────────Row 1
  10241.          {7, 1, 6}──────────────────────────────────────────────────────Row 2
  10242.      };
  10243.  
  10244.    This amounts to specifying each row as its own subset of initializers,
  10245.    clearly a more readable arrangement.
  10246.  
  10247.    To underinitialize a 3-by-3 array, we could use the following:
  10248.  
  10249.      static int square[3][3] = {
  10250.          5, 8, 3, 2, 4, 7, 1, 6 };
  10251.                                └─────────────────────── One initializer short
  10252.  
  10253.    Here the last column of the last row is omitted and thus is 0 by default.
  10254.    We also could underinitialize by a selected row, as follows:
  10255.  
  10256.      static int square[3][3] = {
  10257.          {5, 8, 3},
  10258.          {2, 4},──────────────────────────────────────────────────Row 1 short
  10259.          {7, 1, 6}
  10260.      };
  10261.  
  10262.    Here we omit the third column of the second row, thus setting the value to
  10263.    0.
  10264.  
  10265.    Two-dimensional Arrays and Functions
  10266.  
  10267.    As with one-dimensional arrays, you pass a two-dimensional array to a
  10268.    function by merely stating its name:
  10269.  
  10270.      Make_move(board);
  10271.  
  10272.    Again, this passes the two-dimensional array itself, not a copy.
  10273.  
  10274.    For the receiving function, Make_move(), you must always declare the size
  10275.    of the columns. The number of rows──as with one-dimensional arrays that
  10276.    have only one row──is optional, as shown in the following legal example:
  10277.  
  10278.      Make_move(field)
  10279.      int field[][3];
  10280.  
  10281.    The TTT.C program (Listing 7-10 on the next page) is a somewhat
  10282.    unsophisticated tic-tac-toe game that will help you understand how to use
  10283.    two-dimensional arrays. It's an easy game to win. Forcing a tie, however,
  10284.    is difficult. For clarity, the declaration for field in Make_move()
  10285.    includes the number of rows.
  10286.  
  10287.    ──────────────────────────────────────────────────────────────────────────
  10288.    /* ttt.c    --  a tic-tac-toe game demonstrates  */
  10289.    /*              passing two-dimensional arrays   */
  10290.    /*              to functions                     */
  10291.  
  10292.    main()
  10293.    {
  10294.        static char board[3][3] = {
  10295.            { '-', '-', '-' },
  10296.            { '-', '-', '-' },
  10297.            { '-', '-', '-' },
  10298.        };
  10299.        int row, col, ch;
  10300.        extern char Check_winner();
  10301.        extern void Make_move(), Draw_field();
  10302.  
  10303.        printf("You are X and make the first move.\n");
  10304.        while (1)
  10305.            {
  10306.            printf("Specify coordinate for your X.\n");
  10307.            printf("(For example, a2, or Q to quit)\n");
  10308.  
  10309.            /* Print the square. */
  10310.            Draw_field(board);
  10311.  
  10312.            /* Enter the user's coordinates. */
  10313.            if ((row = getch()) == 'Q')
  10314.                exit(0);
  10315.            row -= 'a';
  10316.            col = getch() - '1';
  10317.  
  10318.            /* Check for a legal move. */
  10319.            if (row < 0 || row > 2 || col < 0 || col > 2)
  10320.                {
  10321.                printf("Bad Square Specification\n\n");
  10322.                continue;
  10323.                }
  10324.            if (board[row][col] != '-')
  10325.                {
  10326.                printf("Sorry, Square Occupied\n\n");
  10327.                continue;
  10328.                }
  10329.  
  10330.            /* Make the move. */
  10331.            board[row][col] = 'X';
  10332.            if ((ch = Check_winner(board)) != '-' || ch == 't')
  10333.                break;
  10334.            Make_move(board);
  10335.            if ((ch = Check_winner(board)) != '-' || ch == 't')
  10336.                break;
  10337.            }
  10338.        Draw_field(board);
  10339.        if (ch == 't')
  10340.            printf("It's a tie!\n");
  10341.        else if (ch == 'X')
  10342.            printf("You win!\n");
  10343.        else
  10344.            printf("I win!\n");
  10345.        }
  10346.  
  10347.    char Check_winner(char field[][3])
  10348.        {
  10349.        int row, col;
  10350.  
  10351.        for (row = col = 0; row < 3; ++row, ++col)
  10352.            {
  10353.            if (field[row][0] != '-'             /* horizontal */
  10354.                    && field[row][0] == field[row][1]
  10355.                    && field[row][1] == field[row][2])
  10356.                {
  10357.                return(field[row][0]);
  10358.                }
  10359.            if (field[0][col] != '-'             /* vertical */
  10360.                    && field[0][col] == field[1][col]
  10361.                    && field[1][col] == field[2][col])
  10362.                {
  10363.                return(field[0][col]);
  10364.                }
  10365.            }
  10366.        if (field[0][0] != '-'         /* right diagonal */
  10367.                && field[0][0] == field[1][1]
  10368.                && field[1][1] == field[2][2])
  10369.            {
  10370.            return(field[0][0]);
  10371.            }
  10372.        if (field[0][2] != '-'         /* left diagonal */
  10373.                && field[0][2] == field[1][1]
  10374.                && field[1][1] == field[2][0])
  10375.            {
  10376.            return(field[0][2]);
  10377.            }
  10378.  
  10379.        for (row = 0; row < 3; ++row)        /* any moves left */
  10380.            {
  10381.            for (col = 0; col < 3; ++col)
  10382.                {
  10383.                if (field[row][col] == '-')
  10384.                    {
  10385.                    return('-');
  10386.                    }
  10387.                }
  10388.            }
  10389.        return ('t');
  10390.    }
  10391.  
  10392.    void Make_move(char field[3][3])
  10393.    {
  10394.        int row, col;
  10395.  
  10396.        for (row = 2; row >= 0; --row)
  10397.            {
  10398.            for (col = 2; col >= 0; --col)
  10399.                {
  10400.                if (field[row][col] == '-')
  10401.                    {
  10402.                    field[row][col] = 'O';
  10403.                    return;
  10404.                    }
  10405.                }
  10406.            }
  10407.    }
  10408.  
  10409.    void Draw_field(char field[][3])
  10410.    {
  10411.        int row, col;
  10412.  
  10413.        printf("\n   1  2  3\n\n");
  10414.        for (row = 0; row < 3; ++row)
  10415.            {
  10416.            printf("%c ", 'a' + row);
  10417.            for (col = 0; col < 3; ++col)
  10418.                {
  10419.                printf(" %c ", field[row][col]);
  10420.                }
  10421.            printf("\n");
  10422.            }
  10423.        printf("\n");
  10424.    }
  10425.    ──────────────────────────────────────────────────────────────────────────
  10426.  
  10427.    Listing 7-10.  The TTT.C program.
  10428.  
  10429.  Arrays of Three and More Dimensions
  10430.  
  10431.    In C you can give an array an unlimited number of dimensions, but remember
  10432.    that the more dimensions an array has, the more unmanageable it becomes.
  10433.    You have already seen how two-dimensional arrays are declared,
  10434.    initialized, and passed to functions. The rules for using more dimensions
  10435.    are a simple extension of those same concepts.
  10436.  
  10437.    Declaring Multidimensional Arrays
  10438.  
  10439.    The general rule for declaring multidimensional arrays is as follows:
  10440.  
  10441.      type name[exp][exp][exp][exp] ...
  10442.                 │    │    │    │    └─────────────────────────────────── Etc.
  10443.                 │    │    │    └──────────────────────────── Fourth dimension
  10444.                 │    │    └────────────────────────────────── Third dimension
  10445.                 │    └────────────────────────────────────── Second dimension
  10446.                 └──────────────────────────────────────────── First dimension
  10447.  
  10448.    First, specify the type that will be stored in each array item, and then
  10449.    name the entire array. Each exp is an integer constant expression that
  10450.    specifies the number of elements in that dimension. Each succeeding
  10451.    square-bracketed [exp] defines another dimension.
  10452.  
  10453.    Think of a three-dimensional array as a cube. Figure 7-6 shows a
  10454.    conceptualization of a cube that corresponds to the following declaration:
  10455.  
  10456.      #define DEPTH  3
  10457.      #define ROWS   3
  10458.      #define COLS   3
  10459.  
  10460.      int cube[DEPTH][ROWS][COLS];
  10461.                 │   └─────┬────┘
  10462.                 │         └─────────────── Size of each two-dimensional array
  10463.                 └─────────────────── Number of two-dimensional arrays (depth)
  10464.  
  10465.    You can also think of this three-dimensional array as an array of three
  10466.    two-dimensional arrays.
  10467.  
  10468.    ┌────────────────────────────────────────────────────────────────────────┐
  10469.    │ Figure 7-6 can be found on p.213 of the printed version of the book.   │
  10470.    └────────────────────────────────────────────────────────────────────────┘
  10471.  
  10472.    Figure 7-6. Three-dimensional arrays can be thought of as a cube.
  10473.  
  10474.    Initializing Multidimensional Arrays
  10475.  
  10476.    When you use a list of values to initialize a multidimensional static or
  10477.    global array, the compiler reads that list from left to right, filling the
  10478.    array row by row for each plane of the depth. The following declaration
  10479.    places the initializing values into cube, beginning with the value 1, as
  10480.    shown in Figure 7-7.
  10481.  
  10482.      int cube[3][3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9,
  10483.       10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
  10484.       22, 23, 24, 25, 26, 27};
  10485.  
  10486.    To specify the order for initializing, you can enclose any group with
  10487.    braces. Those braces correspond to the depth first, then to the rows and
  10488.    columns. You can therefore rewrite the above declaration more clearly as
  10489.    follows:
  10490.  
  10491.      int cube[3][3][3] =
  10492.      {
  10493.       { {1,  2,  3},  {4,  5,  6},  {7,  8,  9} },
  10494.       { {10, 11, 12}, {13, 14, 15}, {16, 17, 18} },
  10495.       { {19, 20, 21}, {22, 23, 24}, {25, 26, 27} }
  10496.      };
  10497.  
  10498.    Here each inner set of braces encloses a given row's list of initializers.
  10499.    Use this technique when you need to underinitialize a given row, column,
  10500.    or depth. Clearly, as you progress beyond three dimensions, initializing
  10501.    can become very confusing. Just remember the general rules, or, in
  10502.    despair, simplify your algorithm.
  10503.  
  10504.             ┌───────────────────────\
  10505.             │\┌───────┬───────┬───────\
  10506.             │ │  19   │  20   │  21   │ \
  10507.             │\├───────┼───────┼───────┤   \
  10508.             │ │  22   │  23   │  24   │     \
  10509.             │\├───────┼───────┼───────┤       \
  10510.           ┌─\ │  25   │  26   │  27   │         \
  10511.           │  \└───────┴───────┴───────┘           \
  10512.           │     \           ┌───────────────────────\
  10513.           │       \         │\┌───────┬───────┬───────\
  10514.           │         \       │ │  10   │  11   │  12   │ \
  10515.           │           \     │\├───────┼───────┼───────┤   \
  10516.           │             \   │ │  13   │  14   │  15   │     \
  10517.           │               \ │\├───────┼───────┼───────┤       \
  10518.           │                 │ │  16   │  17   │  18   │         \
  10519.    Depth──┤                  \└───────┴───────┴───────┘           \
  10520.           │                     \          ┌────────────────────────\
  10521.           │                       \        │\┌───────┬───────┬───────┐──┐
  10522.           │                         \      │ │   1   │   2   │   3   │  │
  10523.           │                           \    │\├───────┼───────┼───────┤  │
  10524.           │                             \  │ │   4   │   5   │   6   │  ├──Row
  10525.           │                               \│\├───────┼───────┼───────┤  │
  10526.           │                                \ │   7   │   8   │   9   │  │
  10527.           └─────────────────────────────────\└───────┴───────┴───────┘──┘
  10528.                                              │                       │
  10529.                                              └───────────┬───────────┘
  10530.                                                       Columns
  10531.  
  10532.    Figure 7-7. Initializing a three-dimensional array.
  10533.  
  10534.    Using Multidimensional Arrays in Functions
  10535.  
  10536.    To pass a multidimensional array to a function, you need specify only the
  10537.    name of that array as an argument:
  10538.  
  10539.      Draw_planes(cube);
  10540.  
  10541.    On the receiving end──in the function Draw_planes()──you must specify the
  10542.    sizes of all but the leftmost dimension. That size is optional, as in the
  10543.    following:
  10544.  
  10545.      int
  10546.      Draw_planes(box);
  10547.      int box[][3][3];
  10548.      {
  10549.  
  10550.    The BOX.C program (Listing 7-11) shows the initialization of a
  10551.    three-dimensional array and then prints out the result.
  10552.  
  10553.    ──────────────────────────────────────────────────────────────────────────
  10554.    /* box.c  --  demonstrates the result of initializing  */
  10555.    /*            a three-dimensional array                */
  10556.  
  10557.    main()
  10558.    {
  10559.        static int cube[3][3][3] = {
  10560.            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
  10561.            13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
  10562.            23, 24, 25, 26, 27 };
  10563.        int plane;
  10564.        extern void Draw_plane();
  10565.  
  10566.        for (plane = 0; plane < 3; ++plane)
  10567.            {
  10568.            Draw_plane(cube, plane);
  10569.            }
  10570.    }
  10571.  
  10572.    void Draw_plane(int box[3][3][3], int slice)
  10573.    {
  10574.        int row, col;
  10575.  
  10576.        printf("Plane[%d] =\n", slice);
  10577.        for (row = 0; row < 3; ++row)
  10578.            {
  10579.            for (col = 0; col < 3; ++col)
  10580.                {
  10581.                printf( "%2d ", box[slice][row][col]);
  10582.                }
  10583.            printf("\n");
  10584.            }
  10585.        printf("\n");
  10586.    }
  10587.    ──────────────────────────────────────────────────────────────────────────
  10588.  
  10589.    Listing 7-11.  The BOX.C program.
  10590.  
  10591.  
  10592.  Advanced Topics and Tricks
  10593.  
  10594.    In this section we discuss three advanced techniques that can be very
  10595.    handy:
  10596.  
  10597.    ■  Negative subscripting
  10598.  
  10599.    ■  Large and huge arrays
  10600.  
  10601.    ■  Passing pieces of arrays
  10602.  
  10603.  Negative Subscripting
  10604.  
  10605.    Recall that unless you include code to perform bounds checking, C lets you
  10606.    reference items both beyond the end and before the beginning of an array.
  10607.    You have already seen the consequences of referencing beyond an array's
  10608.    end. Referencing before its beginning is something new, as Figure 7-8
  10609.    demonstrates.
  10610.  
  10611.    If you declare three consecutive arrays such as the following:
  10612.  
  10613.      int first[3], second[3], third[3];
  10614.  
  10615.    and then reference with a negative subscript:
  10616.  
  10617.      second[-1]
  10618.  
  10619.    you actually reference either third[2] or first[2], depending on whether
  10620.    the arrays are auto or static, as shown in Figure 7-8. QuickC places auto
  10621.    arrays into memory from right to left (top down) and static arrays from
  10622.    left to right (bottom up).
  10623.  
  10624.                   second [-1]
  10625.                        │
  10626.                        │
  10627.    ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
  10628.    │   7   │   8   │   9   │   4   │   5   │   6   │   1   │   2   │   3   │
  10629.    └───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘
  10630.    │                       │                       │                       │
  10631.    └───────────┬───────────┴───────────┬───────────┴───────────┬───────────┘
  10632.                │                       │                       │
  10633.             third [3]              second [3]              first [3]
  10634.  
  10635.    (A)                         ARRAY DECLARED auto
  10636.  
  10637.  
  10638.                   second [-1]
  10639.                        │
  10640.                        │
  10641.    ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
  10642.    │   1   │   2   │   3   │   4   │   5   │   6   │   7   │   8   │   9   │
  10643.    └───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘
  10644.    │                       │                       │                       │
  10645.    └───────────┬───────────┴───────────┬───────────┴───────────┬───────────┘
  10646.                │                       │                       │
  10647.            first [3]               second [3]             third [3]
  10648.  
  10649.    (B)                          ARRAY DECLARED static
  10650.  
  10651.    Figure 7-8. Effect of negative subscripting on auto and static arrays.
  10652.  
  10653.    The L2WORDS.C program (Listing 9-11 on pp. 282─83) illustrates this
  10654.    technique.
  10655.  
  10656.  Large and Huge Arrays
  10657.  
  10658.    On the IBM PC an integer is 2 bytes long, so you have to be careful when
  10659.    declaring arrays larger than 32,767 elements. That is because 32,767 is
  10660.    the highest positive value a 2-byte integer can hold. If you successively
  10661.    reference the elements in an array with the following loop:
  10662.  
  10663.      int i;
  10664.      for (i = 0; i < 40000; i++)
  10665.          printf("%dn", array[i]);
  10666.  
  10667.    the 0th through 32,767th elements print out correctly, but the 32,768th
  10668.    element prints out as array[-32768].
  10669.  
  10670.    Integers are signed variables, so they wrap to negative numbers when they
  10671.    exceed their highest positive value. Therefore, to reference elements in
  10672.    large arrays, use either unsigned int or long offsets.
  10673.  
  10674.    Another problem occurs when arrays grow to more than 65,536 bytes total on
  10675.    the IBM PC. In this case, use the huge keyword in the array declaration,
  10676.    as follows:
  10677.  
  10678.      int huge bigbox[100][100][100];
  10679.  
  10680.    Here the keyword huge is required because the total size of the array
  10681.    bigbox is 100 x 100 x 100 times 2 (two bytes per int), or 2,000,000 bytes
  10682.    total. This tells the compiler to set aside more space for this array than
  10683.    the space reserved for ordinary variables. Whenever you use large arrays
  10684.    that require the huge keyword, compile with the large memory model. That
  10685.    model will be discussed in greater detail in Chapter 12. (Of course, you
  10686.    will need lots of memory in your computer, too.)
  10687.  
  10688.  Passing Pieces of Arrays
  10689.  
  10690.    When you reference array elements with fewer dimensional offsets than were
  10691.    present in that array's declaration, you are actually referencing the
  10692.    address of a subarray. If, for example, you declare:
  10693.  
  10694.      int square[3][3];
  10695.  
  10696.    and then later reference that array without specifying the second
  10697.    dimension:
  10698.  
  10699.      Print_row(cube[1]);
  10700.  
  10701.    you would pass the address of cube's second row (a one-dimensional
  10702.    subarray) to Print_row(). Then declare Print_row() to receive a
  10703.    one-dimensional array:
  10704.  
  10705.      Print_row(row)
  10706.      int row[];
  10707.      {
  10708.  
  10709.  
  10710.  The Bitwise Operators, Tiny Arrays
  10711.  
  10712.    Just as arrays can get larger and larger and more and more complex, it is
  10713.    also possible to go the other direction and store data in the individual
  10714.    bits of a single byte. You can manipulate individual bits of a byte using
  10715.    the bitwise operators. Those operators are:
  10716.  
  10717.    Operator           Description
  10718.    ──────────────────────────────────────────────────────────────────────────
  10719.    &                  The bitwise AND operator
  10720.    |                  The bitwise OR operator
  10721.    ^                  The bitwise exclusive-OR operator
  10722.    ~                  The unary inversion operator (ones-complement)
  10723.    >>                 The unary right-shift operator
  10724.    <<                 The unary left-shift operator
  10725.    ──────────────────────────────────────────────────────────────────────────
  10726.  
  10727.    Each of these affects the individual bits in the bytes of a value, which
  10728.    can be either a constant or a variable. Remember, a char uses 8 bits, an
  10729.    int 16 bits, and a long 32 bits. First, we demonstrate the application of
  10730.    the bitwise operators, and then discuss the logic of each.
  10731.  
  10732.    The BITWISE.C program (Listing 7-12) lets you enter values interactively
  10733.    and then apply the bitwise operators to them. By running this program, you
  10734.    will better understand the discussion that follows. (Note that a set bit
  10735.    is represented with a 1 and a clear bit is represented with a 0.)
  10736.  
  10737.    ──────────────────────────────────────────────────────────────────────────
  10738.    /* bitwise.c -- demonstrates the bitwise operators */
  10739.  
  10740.    #include <stdio.h>
  10741.  
  10742.    main()
  10743.    {
  10744.        unsigned int val1, val2, result;
  10745.        int ch;
  10746.        extern void show();
  10747.  
  10748.        while(1)
  10749.            {
  10750.            printf("\nval1: ");
  10751.            if (scanf("%d", &val1) != 1)
  10752.                break;
  10753.  
  10754.            printf("val2: ");
  10755.            if (scanf("%d", &val2) != 1)
  10756.                break;
  10757.            printf("\tval1   = ");
  10758.            show(val1);
  10759.            printf("\tval2   = ");
  10760.            show(val2);
  10761.  
  10762.            printf("Bitwise Operator: ");
  10763.            while ((ch = getchar()) == '\n')
  10764.                {
  10765.                continue;
  10766.                }
  10767.            if (ch == EOF)
  10768.                break;
  10769.            switch (ch)
  10770.                {
  10771.                case '&':
  10772.                    result = val1 & val2;
  10773.                    printf("Executing: result = val1 & val2;\n");
  10774.                    break;
  10775.                case '|':
  10776.                    result = val1 |= val2;
  10777.                    printf("Executing: result = val1 | val2;\n");
  10778.                    break;
  10779.                case '^':
  10780.                    result = val1 ^= val2;
  10781.                    printf("Executing: result = val1 ^ val2;\n");
  10782.                    break;
  10783.                case '~':
  10784.                    result = ~val1;
  10785.                    printf("Executing: result = ~val1;\n");
  10786.                    printf("\tresult = ");
  10787.                    show(result);
  10788.                    result = ~val2;
  10789.                    printf("Executing: result = ~val2;\n");
  10790.                    break;
  10791.                case '<':
  10792.                    result = val1 <<= val2;
  10793.                    printf("Executing: result = val1 <<val2;\n");
  10794.                    break;
  10795.                case '>':
  10796.                    result = val1 >>= val2;
  10797.                    printf("Executing: result = val1 >>val2;\n");
  10798.                    break;
  10799.                case 'q':
  10800.                case 'Q':
  10801.                    return(0);
  10802.                default:
  10803.                    continue;
  10804.                }
  10805.            printf("\tresult = ");
  10806.            show(result);
  10807.            }
  10808.    }
  10809.    void bitout(unsigned char num[])
  10810.    {
  10811.        int bytes = 2, i, j;
  10812.  
  10813.        /* IBM PC stores ints low/hi. */
  10814.        for (i = bytes-1; i >= 0; --i)
  10815.            {
  10816.            for (j = 7; j >= 0; --j)
  10817.                {
  10818.                putchar((num[i]&(1<<j))?'1':'0');
  10819.                }
  10820.            }
  10821.    }
  10822.  
  10823.    void show(unsigned int val)
  10824.    {
  10825.        extern void bitout();
  10826.  
  10827.        printf("(%05u decimal)", val);
  10828.        bitout(&val);
  10829.        printf(" binary\n");
  10830.    }
  10831.    ──────────────────────────────────────────────────────────────────────────
  10832.  
  10833.    Listing 7-12.  The BITWISE.C program.
  10834.  
  10835.  The Binary Bitwise Operators
  10836.  
  10837.    The bitwise AND, the bitwise OR, and the bitwise exclusive-OR are binary
  10838.    operators. That is, like the addition operator, they operate on two
  10839.    values──not one. You can invoke them as follows:
  10840.  
  10841.      result = val1 & val2;     /* bitwise AND          */
  10842.      result = val1 | val2;     /* bitwise OR           */
  10843.      result = val1 ^ val2;     /* bitwise exclusive-OR */
  10844.  
  10845.    Or you can invoke them with the op= form:
  10846.  
  10847.      result &= val1;    /* bitwise AND          */
  10848.      result |= val1;    /* bitwise OR           */
  10849.      result ^= val1;    /* bitwise exclusive-OR */
  10850.  
  10851.    The Bitwise AND Operator
  10852.  
  10853.    The bitwise AND operator, &, compares the bits in two values and produces
  10854.    a value based on the comparison of the same bits in each:
  10855.  
  10856.    var1           &              var2          yields         result
  10857.    ──────────────────────────────────────────────────────────────────────────
  10858.    1                             1                            1
  10859.    0                             1                            0
  10860.    1                             0                            0
  10861.    0                             0                            0
  10862.    ──────────────────────────────────────────────────────────────────────────
  10863.  
  10864.    For the bitwise AND, the result bit is set only if the same bit in both
  10865.    values is set. Otherwise, the result bit is cleared.
  10866.  
  10867.    The bitwise AND operator is useful for turning off (clearing) a selected
  10868.    bit in a variable. A typical application for the & operator is to turn off
  10869.    a blinking cursor when you are accessing screen memory directly:
  10870.  
  10871.      var1 =  3;
  10872.      var1 &= 0xFFFE;─────────────────────────────────────────Turn off low bit
  10873.  
  10874.    This results in the following calculation:
  10875.  
  10876.                   0000000000000011 ───────────────────────────────────── var1
  10877.                 & 1111111111111110 ─────────────────────────────────── OxFFFE
  10878.                 ──────────────────
  10879.      Yields ───── 0000000000000010
  10880.                                  
  10881.                                  │
  10882.                                  └─────────────────────────── Low bit cleared
  10883.  
  10884.    The Bitwise OR Operator
  10885.  
  10886.    The bitwise OR operator, |, compares the bits in two values and sets the
  10887.    result bit for any bit that is set in either of the values:
  10888.  
  10889.    var1           |              var2          yields         result
  10890.    ──────────────────────────────────────────────────────────────────────────
  10891.    1                             1                            1
  10892.    0                             1                            1
  10893.    1                             0                            1
  10894.    0                             0                            0
  10895.    ──────────────────────────────────────────────────────────────────────────
  10896.  
  10897.    For the bitwise OR, the result bit is set if either or both corresponding
  10898.    bits in both values are set. Otherwise, the result bit is cleared.
  10899.  
  10900.    The bitwise OR operator is useful for turning on (setting) a selected bit
  10901.    in a variable. A typical application for the | operator is to turn on the
  10902.    high bit of a character variable before sending that character to the
  10903.    printer:
  10904.  
  10905.      var1 =  0;
  10906.      var1 |= 1;───────────────────────────────────────────────Turn on low bit
  10907.  
  10908.    This results in the following calculation:
  10909.  
  10910.                   0000000000000000 ───────────────────────────────────── var1
  10911.                 | 0000000000000001 ────────────────── Equivalent to 1 decimal
  10912.                 ──────────────────
  10913.      Yields ───── 0000000000000001
  10914.                                  
  10915.                                  │
  10916.                                  └─────────────────────────────── Low bit set
  10917.  
  10918.    The Bitwise exclusive-OR Operator
  10919.  
  10920.    The bitwise exclusive-OR operator, ^, compares the bits in two values and
  10921.    produces a set bit only if one bit or the other is set, but not both:
  10922.  
  10923.    var1           ^              var2          yields         result
  10924.    ──────────────────────────────────────────────────────────────────────────
  10925.    1                             1                            0
  10926.    0                             1                            1
  10927.    1                             0                            1
  10928.    0                             0                            0
  10929.    ──────────────────────────────────────────────────────────────────────────
  10930.  
  10931.    For the bitwise exclusive-OR, ^, the result bit is set if one or the other
  10932.    of the corresponding bits in the values is set, but not both.
  10933.  
  10934.    The bitwise exclusive-OR operator is useful for toggling (setting,
  10935.    clearing, setting, etc.) a selected bit in a variable. A typical
  10936.    application for the ^ operator is to toggle a flag in a game, thereby
  10937.    determining which of two players is to make the next move:
  10938.  
  10939.      var1 =  0;
  10940.      var1 ^= 1;
  10941.      var1 ^= 1;
  10942.  
  10943.    This results in the following calculations:
  10944.  
  10945.                   0000000000000000 ───────────────────────────────────── var1
  10946.                 ^ 0000000000000001 ────────────────── Equivalent to 1 decimal
  10947.                 ──────────────────
  10948.      Yields ───── 0000000000000001
  10949.                                  
  10950.                           ▓      │
  10951.                           ▓      └──────────────────── Low bit set (Player 2)
  10952.                           ▓
  10953.                           ▓
  10954.                           
  10955.  
  10956.                   0000000000000001 ──────────────────────── New value of var1
  10957.                 ^ 0000000000000001 ────────────────── Equivalent to 1 decimal
  10958.                 ──────────────────
  10959.      Yields ───── 0000000000000000
  10960.                                  
  10961.                                  │
  10962.                                  └─────── Low bit toggled to clear (Player 1)
  10963.  
  10964.  The Unary Bitwise Operators
  10965.  
  10966.    The unary bitwise operators affect the bits of a single value. These
  10967.    operators are:
  10968.  
  10969.    Operator       Description
  10970.    ──────────────────────────────────────────────────────────────────────────
  10971.    ~              The unary ones-complement operator
  10972.    >>             The unary right-shift operator
  10973.    <<             The unary left-shift operator
  10974.    ──────────────────────────────────────────────────────────────────────────
  10975.  
  10976.    The Unary Ones-Complement Operator
  10977.  
  10978.    The ones- complement of a variable is derived by inverting all the bits in
  10979.    that value. If a bit is set, that bit changes to clear, and vice versa. In
  10980.    C, the ~ causes the bits in a value to be inverted, as follows:
  10981.  
  10982.      var1    0000000000000111
  10983.  
  10984.      ~var1   1111111111111000──────────────────────────────────────────Result
  10985.  
  10986.    Two applications are common for the ones-complement operator. One is to
  10987.    set selected bits in a variable regardless of the number of bytes occupied
  10988.    by that variable. Suppose you have an int and you want all but the zeroth
  10989.    bit set. One way to do this is by:
  10990.  
  10991.      number = 0xFFFE;
  10992.  
  10993.    This does the job, but pays the price of assuming an int always occupies
  10994.    two bytes of storage. Although that is true on the IBM PC, it is not the
  10995.    case on most 32-bit machines. The correct way to set all but the zeroth
  10996.    bit──and the portable way──is to use the ones-complement operator:
  10997.  
  10998.      number = ~1;
  10999.  
  11000.    The second common application for the ones-complement operator is turning
  11001.    off selected bits. One way to turn off the zeroth bit, while leaving all
  11002.    the other bits in a variable unchanged, is:
  11003.  
  11004.      masks &= 0xFFFE;
  11005.  
  11006.    But again, the ones-complement operator should be used for portability:
  11007.  
  11008.      masks &= ~1;
  11009.  
  11010.    The Unary Shift Operators
  11011.  
  11012.    The shift operators move all the bits in a variable right or left by the
  11013.    number of bit positions specified. The shift operators are used as
  11014.    follows:
  11015.  
  11016.      result = value <<bits;
  11017.      result = value >>bits;
  11018.  
  11019.    Here the first line shifts the value in value left──from the low toward
  11020.    the high bit──by the number of bit positions specified by bits. The second
  11021.    line shifts value in the opposite direction──right, or from the high
  11022.    toward the low bit. For example:
  11023.  
  11024.      val1       0000000000111000
  11025.      val1 <<3   0000000111000000───────────────────────────────────Left shift
  11026.      val1 >>3   0000000000000111──────────────────────────────────Right shift
  11027.  
  11028.    When shifting left, the bits on the right are filled with clear bits. With
  11029.    QuickC, the fill bits for a right shift are always set. For portability,
  11030.    however, always use unsigned variables when right-shifting.
  11031.  
  11032.    The shift operators are useful for aligning a bit prior to ORing it into a
  11033.    variable. Shifting also provides a quick way to multiply or divide by 2.
  11034.    Each bit you shift to the left multiplies a number by 2; each bit you
  11035.    shift to the right divides it by 2.
  11036.  
  11037.      int val = 1;
  11038.  
  11039.      val <<= 1;──────────────────────────────────────────────val now equals 2
  11040.      val <<= 1;──────────────────────────────────────────────val now equals 4
  11041.      val <<= 1;──────────────────────────────────────────────val now equals 8
  11042.  
  11043.  Summary of Bitwise Operators
  11044.  
  11045.    If you haven't already done so, enter, compile, and run the BITWISE.C
  11046.    program (Listing 7-12 on p. 218). Watching the actions of bits as the
  11047.    program applies each bitwise operator will give you a feel for bits and
  11048.    will lead you to develop sophisticated applications of your own. You will
  11049.    find the bitwise operators used a great deal in the hardware-specific
  11050.    chapters at the end of this book.
  11051.  
  11052.  
  11053.  
  11054.  ────────────────────────────────────────────────────────────────────────────
  11055.  Chapter 8  Addresses and Pointers
  11056.  
  11057.    One of the chief strengths of C is its ability to manipulate individual
  11058.    areas of memory with almost the same precision that assembly language
  11059.    provides. This chapter discusses this ability in detail by showing you a
  11060.    new kind of variable called a "pointer"──a variable whose contents
  11061.    identify a memory address. Using pointers can greatly increase the speed
  11062.    at which your programs execute, lets you access your computer's hardware
  11063.    directly, and allows you to write subroutines that manipulate variables
  11064.    directly (via the address).
  11065.  
  11066.  
  11067.  Addresses Reviewed
  11068.  
  11069.    The concept of memory addresses is vital to C programming. Recall, for
  11070.    example, that all arguments passed to scanf() must be preceded by an
  11071.    ampersand (&). In the following expression:
  11072.  
  11073.      scanf("%d", &num);
  11074.  
  11075.    the & tells scanf() to read an integer from the keyboard and to place that
  11076.    input value into the variable num, whose address is passed with the
  11077.    expression &num.
  11078.  
  11079.    You also used addresses with arrays. In the previous chapter we mentioned
  11080.    that when an entire array is passed to a function, it is passed as
  11081.    addresses. For example, the code fragment
  11082.  
  11083.      char choices[4] = {'Q', 'E', 'S', 'L'};
  11084.  
  11085.      Get_move(choices);
  11086.  
  11087.    passes the address of the choices array to the function Get_move(), rather
  11088.    than the individual elements of that array. When you use an array name
  11089.    without specifying an element in square brackets, the compiler uses the
  11090.    internal starting memory address of that array as its value.
  11091.  
  11092.    One of C's strengths is the ease with which it lets you manipulate the
  11093.    values of variables by way of their addresses. This type of address
  11094.    manipulation, known as indirection, is accomplished with pointers.
  11095.  
  11096.  
  11097.  What Is a Pointer?
  11098.  
  11099.    A pointer, in its simplest form, is a variable whose value (contents) is
  11100.    an address, or a number corresponding to a specific location in memory.
  11101.    That is, if address_var is a pointer-type variable, and num is an integer
  11102.    variable, the expression
  11103.  
  11104.      address_var = #
  11105.  
  11106.    causes the address of the variable num to be placed into the pointer
  11107.    variable named address_var. This assignment ignores the actual value of
  11108.    num.
  11109.  
  11110.    You can use pointers in your programs to:
  11111.  
  11112.    ■  Save information from functions that return addresses
  11113.  
  11114.    ■  Indirectly return more than one value from a function
  11115.  
  11116.    ■  Speed up execution by manipulating pointers rather than large blocks of
  11117.       data
  11118.  
  11119.    ■  Access and modify text screen memory
  11120.  
  11121.    ■  Call functions using their addresses, thus creating more flexible code
  11122.  
  11123.    ■  Access and manipulate strings
  11124.  
  11125.    Before you can use a pointer, also called a "pointer to," you must declare
  11126.    it. Declaring a pointer is much like declaring an ordinary variable, the
  11127.    only difference being that you must always precede the pointer's name with
  11128.    the * character.
  11129.  
  11130.    The following example declares two variables: an integer called num and a
  11131.    pointer called address_var.
  11132.  
  11133.      int num, *address_var;
  11134.  
  11135.    The * before address_var tells the compiler that address_var is a pointer
  11136.    whose contents will be an address. Because address_var is declared as type
  11137.    int, the compiler knows that address_var will contain the address of an
  11138.    integer variable. Figure 8-1 illustrates this process.
  11139.  
  11140.    In this example, we declare two variables and two pointers (Figure 8-1a).
  11141.    The variables are num (an int) and fval (a float). We also declare two
  11142.    pointers, address_var and faddress_var.
  11143.  
  11144.    The pointer address_var contains the address of an int type of variable;
  11145.    pointer faddress_var contains the address of a float type of variable. The
  11146.    two assignment statements in Figure 8-1b store the addresses in the
  11147.    appropriate pointers. The result of the assignment is that address_var now
  11148.    holds num's address (and thus points to num), and faddress_var holds
  11149.    fval's address (and thus points to fval).
  11150.  
  11151.         int num/ *address_var;   ───┐
  11152.                                     │▒▒▒▒▒▒▒▒▒▒ These declarations
  11153.         float fval, *faddress-var;──┘         ▒ create...
  11154.                                               
  11155.  
  11156.    Memory──  4096   4097  4098  4099  4050  4051  4052  4053  4054  4055
  11157.    locations ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
  11158.    in bytes  │           │           │           │           │           │
  11159.              └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
  11160.                    │           │     │                       │     │
  11161.                    │           │     └───────────┬───────────┘     │
  11162.                    │           │                 │                 │
  11163.                   num     address-var          fval          faddress-vars
  11164.  
  11165.    (A)
  11166.  
  11167.  
  11168.           address_var = # ───┐
  11169.                                  │▒▒▒▒▒▒▒▒▒▒ These assignments
  11170.           faddress-var = &fval; ─┘         ▒ yield...
  11171.                                            
  11172.  
  11173.                ┌────&num──────┐        ┌──────────&fval──────────┐
  11174.                │               │        │                          │
  11175.    Memory──  4096   4097  4098 │4099  4050  4051  4052  4053  4054 │4055
  11176.    locations ┌─────┬─────┬──────────┬─────┬─────┬─────┬─────┬──────────┐
  11177.    in bytes  │           │   4096    │           │           │   4050    │
  11178.              └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
  11179.                    │           │     │                       │     │
  11180.                    │           │     └───────────┬───────────┘     │
  11181.                    │           │                 │                 │
  11182.                   num     address-var          fval          faddress-var
  11183.                               ▒                                  ▒
  11184.                    ▒           ▒                 ▒                 ▒
  11185.                    ▒▒▒▒▒▒▒▒▒▒▒▒▒                 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  11186.                      Points to                         Points to
  11187.  
  11188.    (B)
  11189.  
  11190.    Figure 8-1. Result of assigning an address to a pointer.
  11191.  
  11192.  
  11193.  Accessing Variables with Pointers
  11194.  
  11195.    The * operator (pronounced "star"), when used to signify a pointer, is
  11196.    called the indirection operator because it lets you access variables
  11197.    indirectly. When you use the * operator in front of a pointer (other than
  11198.    in its declaration) you tell the compiler to fetch or store the value that
  11199.    the pointer points to. For example, in the fragment
  11200.  
  11201.      int num, *address_var;
  11202.  
  11203.      address_var = #
  11204.      *address_var = 3;
  11205.  
  11206.    you first declare an int variable (num) and a pointer to an int
  11207.    (address_var). Next, the value you store in address_var is the address of
  11208.    the variable num. Finally, the * in front of address_var tells the
  11209.    compiler to store the value 3 in the variable whose address is stored in
  11210.    address_var. Because address_var contains the address of num, that value
  11211.    is stored in num. (See Figure 8-2 on p. 234.)
  11212.  
  11213.    The POINTER.C program (Listing 8-1) illustrates the procedure for
  11214.    declaring, assigning a value to, and using pointers.
  11215.  
  11216.    ──────────────────────────────────────────────────────────────────────────
  11217.    /* pointer.c  --  demonstrates pointer declaration,   */
  11218.    /*                assignment, and use                 */
  11219.  
  11220.    #define WAIT printf("(press any key)"); getch(); \
  11221.                 printf("\n\n")
  11222.  
  11223.    main()
  11224.    {
  11225.        int num, *address_var;
  11226.  
  11227.        num = 0;
  11228.        address_var = #
  11229.  
  11230.        printf("The address of the variable ");
  11231.        printf("\"num\" is:  0x%04X\n", &num);
  11232.        printf("The value in the pointer ");
  11233.        printf("\"address_var\" is:  0x%04X\n", address_var);
  11234.        printf("The value in the variable ");
  11235.        printf("\"num\" is: %d\n", num);
  11236.        WAIT;
  11237.        printf("Since \"address_var\" points to \"num\"\n");
  11238.        printf("the value in ");
  11239.        printf("\"*address_var\" is: %d\n", *address_var);
  11240.        WAIT;
  11241.        printf("To verify this, let's store 3 in\n");
  11242.        printf("\"*address_var\", then print out ");
  11243.        printf("\"num\" and \"*address_var\"\n");
  11244.        printf("again.\n");
  11245.        WAIT;
  11246.        printf("Doing: *address_var = 3;\n\n");
  11247.        *address_var = 3;
  11248.  
  11249.        printf("The address of the variable ");
  11250.        printf("\"num\" is:  0x%04X\n", &num);
  11251.        printf("The value in the pointer ");
  11252.        printf("\"address_var\" is:  0x%04X\n", address_var);
  11253.        printf("The value in the variable ");
  11254.        printf("\"num\" is: %d\n", num);
  11255.        WAIT;
  11256.        printf("Since \"address_var\" points to \"num\"\n");
  11257.        printf("the value in ");
  11258.        printf("\"*address_var\" is: %d\n", *address_var);
  11259.        WAIT;
  11260.  
  11261.        printf("Now we will add 15 to \"num\" and print\n");
  11262.        printf("\"num\" and \"*address_var\" again.\n");
  11263.        WAIT;
  11264.  
  11265.        printf("Doing: num += 15;\n\n");
  11266.        num += 15;
  11267.  
  11268.        printf("The address of the variable ");
  11269.        printf("\"num\" is:  0x%04X\n", &num);
  11270.        printf("The value in the pointer ");
  11271.        printf("\"address_var\" is:  0x%04X\n", address_var);
  11272.        printf("The value in the variable ");
  11273.        printf("\"num\" is: %d\n", num);
  11274.        WAIT;
  11275.        printf("Since \"address_var\" points to \"num\"\n");
  11276.        printf("the value in ");
  11277.        printf("\"*address_var\" is: %d\n", *address_var);
  11278.        WAIT;
  11279.  
  11280.        printf("Doing: return (*address_var);\n\n");
  11281.        return (*address_var);
  11282.    }
  11283.    ──────────────────────────────────────────────────────────────────────────
  11284.  
  11285.    Listing 8-1.  The POINTER.C program.
  11286.  
  11287.    The output of this program follows. Compare it to the listing.
  11288.  
  11289.      The address of the variable "num" is:  0x1388
  11290.      The value in the pointer "address_var" is:  0x1388
  11291.      The value in the variable "num" is: 0
  11292.      (press any key)
  11293.  
  11294.      Since "address_var" points to "num"
  11295.      the value in "*address_var" is: 0
  11296.      (press any key)
  11297.      To verify this, let's store 3 in
  11298.      "*address_var", then print out "num" and "*address_var"
  11299.      again.
  11300.      (press any key)
  11301.  
  11302.      Doing: *address_var = 3;
  11303.  
  11304.      The address of the variable "num" is: 0x1388
  11305.      The value in the pointer "address_var" is: 0x1388
  11306.      The value in the variable "num" is: 3
  11307.      (press any key)
  11308.  
  11309.      Since "address_var" points to "num"
  11310.      the value in "*address_var" is: 3
  11311.      (press any key)
  11312.  
  11313.      Now we will add 15 to "num" and print
  11314.      "num" and "*address_var" again.
  11315.      (press any key)
  11316.  
  11317.      Doing: num += 15;
  11318.  
  11319.      The address of the variable "num" is:  0x1388
  11320.      The value in the pointer "address_var" is: 0x1388
  11321.      The value in the variable "num" is: 18
  11322.      (press any key)
  11323.  
  11324.      Since "address_var" points to "num"
  11325.      the value in "*address_var" is: 18
  11326.      (press any key)
  11327.  
  11328.      Doing: return (*address_var);
  11329.  
  11330.    In the POINTER.C program, the pointer address_var contains the address of
  11331.    num (as a result of the assignment address_var = &num) and therefore
  11332.    yields the value stored in num. That is, we indirectly access num via its
  11333.    address (*address_var = 3). Because address_var contains num's address,
  11334.    you can use *address_var anywhere you would use num. For example, we could
  11335.    have ended the program with return (num) to produce the same result.
  11336.  
  11337.  
  11338.  Passing Pointers to Functions
  11339.  
  11340.    Until now, with the exception of arrays, we have passed arguments to
  11341.    functions by value. Thus, you might think we could write a function that
  11342.    squares the argument passed to it as follows:
  11343.  
  11344.      square(int num)
  11345.          {
  11346.          num *= num;
  11347.          }
  11348.  
  11349.    This doesn't work, however, because the variable num is a local variable
  11350.    to the function square(), and the result is not accessible by other
  11351.    functions. Thus, calling square() with
  11352.  
  11353.      main()
  11354.      {
  11355.          int val = 5;
  11356.  
  11357.          square(val);
  11358.      }
  11359.  
  11360.    does not result in main()'s variable val being squared, because main()
  11361.    doesn't "see" the variable num.
  11362.  
  11363.    You can get around this by having square() return a value, as follows:
  11364.  
  11365.      main()
  11366.      {
  11367.          int val = 5;
  11368.  
  11369.          val = square(val);────────────────────────Value returned by square()
  11370.      }
  11371.  
  11372.      square(int num)
  11373.      {
  11374.          num *= num;
  11375.          return (num);─────────────────────────────────square() returns value
  11376.      }
  11377.  
  11378.    Another approach is to use pointers. When you pass a pointer to a
  11379.    function, you still pass a copy of its value, but the value you pass is an
  11380.    address. Therefore, in square(), you must declare num as a pointer because
  11381.    it will receive an address:
  11382.  
  11383.      square(int *address_var) ─────────────────── Pointer receives an address
  11384.      {
  11385.  
  11386.          *address_var *= *address_var;
  11387.      }                └────────────────────────────── Multiplication operator
  11388.  
  11389.    This form of square() receives an address as its argument. The pointer to
  11390.    hold that address, address_var, is declared as int *address_var because it
  11391.    receives the address of an int variable.
  11392.  
  11393.    To use this new square() function, we must pass it an address. We can do
  11394.    this in either of two ways. We can use the & operator, as follows:
  11395.  
  11396.      main()
  11397.      {
  11398.          int val = 5;
  11399.  
  11400.          square(&val);────────────────────────────────────────Pass an address
  11401.      }
  11402.  
  11403.    Or we can pass a pointer:
  11404.  
  11405.      main()
  11406.      {
  11407.          int val = 5, *here;
  11408.  
  11409.          here = &val;
  11410.          square(here);─────────────────────The value of here is val's address
  11411.      }
  11412.  
  11413.    After making our declarations, we place the address of val into the
  11414.    pointer here. When we pass here to square(), its value──the address of
  11415.    val──is what is actually passed. This results in val being squared.
  11416.  
  11417.    The SQUARE.C program (Listing 8-2) summarizes this passing of pointers
  11418.    and addresses in an interactive quiz. In it, we've expanded on our
  11419.    original square() subroutine. In the new Square(), we return two values
  11420.    from a single function! The first, returned by return, is an error
  11421.    status──zero for a successful square and -1 for any attempt to square a
  11422.    number larger than 181 or less than -181 (the square root of 32,767, the
  11423.    largest signed int on the IBM PC). We return the second value with the
  11424.    pointer *where.
  11425.  
  11426.    ──────────────────────────────────────────────────────────────────────────
  11427.    /* square.c  --  a quiz to demonstrate passing        */
  11428.    /*               pointers and addresses in functions  */
  11429.  
  11430.    main()
  11431.    {
  11432.        int val, count, guess;
  11433.  
  11434.        for (count = 1; count < 255; ++count)
  11435.            {
  11436.            val = count;
  11437.            printf("What is the square of %d?\n", val);
  11438.            if (scanf("%d", &guess) != 1)
  11439.                return(0);        /* non-number exits   */
  11440.  
  11441.            if(Square(&val) != 0)    /* pass val's address */
  11442.                {
  11443.                printf("Range Error\n");
  11444.                exit(1);
  11445.                }
  11446.            if (val != guess)
  11447.                printf("Wrong. It is %d.\n", val);
  11448.            else
  11449.                printf("Right!\n");
  11450.            printf("Continue? ");
  11451.            if (getche() != 'y')
  11452.                break;
  11453.            }
  11454.    }
  11455.    int Square(int *where)
  11456.    {
  11457.        if (*where > 181 || *where < -181)
  11458.            return (-1);
  11459.        *where = (*where) * (*where);
  11460.        return (0);
  11461.    }
  11462.    ──────────────────────────────────────────────────────────────────────────
  11463.  
  11464.    Listing 8-2.  The SQUARE.C program.
  11465.  
  11466.    In this program, we use a separate variable, count, in the for loop
  11467.    because the value of val is indirectly changed by the call to Square(). If
  11468.    we had used val as follows:
  11469.  
  11470.      for (val = 1; val < 255; ++val)
  11471.  
  11472.    you would be prompted only for the numbers 1, 2, 5, and 26, and then you
  11473.    would receive a Range Error.
  11474.  
  11475.  
  11476.  Pointers and Arrays
  11477.  
  11478.    Pointers let you manipulate strings and arrays more succinctly and
  11479.    efficiently. We'll learn about strings in the next chapter. Here we will
  11480.    discuss the relationship between arrays and pointers, detailing potential
  11481.    pitfalls along the way.
  11482.  
  11483.    Recall from the previous chapter that referencing an array by name,
  11484.    without an offset, yields that array's address. What we didn't tell you
  11485.    was that the address of an array is the same as the address of the array's
  11486.    first element. For example, in the following array declaration:
  11487.  
  11488.      int coins[4] = {25, 10, 5, 1};
  11489.  
  11490.    the reference
  11491.  
  11492.      Find_change(coins, amount);
  11493.  
  11494.    actually causes the address of the array coins[4] to be passed to the
  11495.    function Find_change(). Because the address of an array is the location in
  11496.    memory of its beginning, we can also reference that array with the
  11497.    expression
  11498.  
  11499.      &coins[0]
  11500.  
  11501.    Here the address operator & yields the address of the first item in the
  11502.    array coins and, therefore, the address of the array itself.
  11503.  
  11504.    You can assign the address of another variable to a pointer with the &
  11505.    operator (address_var = &num[1]). Because each item in an array is a
  11506.    variable, the assignment
  11507.  
  11508.      address_var = &coins[0];
  11509.  
  11510.    results in address_var containing the address of the first integer in the
  11511.    array coins.
  11512.  
  11513.    Because &coins[0] and coins are equivalent, the following expression is
  11514.    the same as the one above:
  11515.  
  11516.      address_var = coins;
  11517.  
  11518.    Now here comes the exciting part. When a value, say 1, is added to a
  11519.    pointer, it increments the address in that pointer by the number of bytes
  11520.    in the type to which it points. For example, in Figure 8-2 the variable
  11521.    address_var begins with a value that is the address of coins. Notice what
  11522.    happens when we add 1 to address_var. Because address_var is a pointer to
  11523.    the type int, and because an int occupies two bytes (on the IBM PC), the
  11524.    value in address_var is increased by 2. The new value in address_var is
  11525.    thus the address of coins[1] (the next element in the array).
  11526.  
  11527.                                Points to
  11528.                                ▒▒▒▒▒▒▒▒▒▒
  11529.                                ▒        ▒
  11530.                         ┌─────────────┐ ▒
  11531.                         │             │ 
  11532.    Memory locations──  4392   4393  4394  4395  4396  4397  4398  4399
  11533.    in bytes           ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
  11534.                       │   4394    │           │           │           │
  11535.                       └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
  11536.                             │           │           │           │
  11537.                             │           │           │           │
  11538.                             │           │           │           │
  11539.                        address-var   coins[0]    coins[1]    coins[2]
  11540.                                                               
  11541.                                                    ▒           ▒
  11542.                                                    ▒           ▒
  11543.                        4392   4393                  ▒           ▒
  11544.                       ┌─────┬─────┐                 ▒           ▒
  11545.                       │   4394    │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒           ▒
  11546.                       └─────┴─────┘   Next points to            ▒
  11547.                             │                                   ▒
  11548.                             │                                   ▒
  11549.                             │                                   ▒
  11550.    Increment value───address_var += 1;                          ▒
  11551.    of pointer                                                  ▒
  11552.                                                                ▒
  11553.                                                                ▒
  11554.                        4392   4393                              ▒
  11555.                       ┌─────┬─────┐                             ▒
  11556.                       │   4398    │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  11557.                       └─────┴─────┘    Then points to
  11558.                             │
  11559.                             │
  11560.                             │
  11561.    Increment pointer───address_var += 1;
  11562.    again
  11563.  
  11564.    Figure 8-2. The value of a pointer increases by multiples of the number of
  11565.    bytes in the data type to which it points.
  11566.  
  11567.    The CHANGE.C program (Listing 8-3) demonstrates how the pointer coin_ptr
  11568.    advances through the array coins, each step determined by the number of
  11569.    bytes for the type int. Compile the program with the Debug option set
  11570.    because we want to trace its execution.
  11571.  
  11572.    ──────────────────────────────────────────────────────────────────────────
  11573.    /* change.c  -- a change-making program demonstrates   */
  11574.    /*              how pointers advance the correct       */
  11575.    /*              number of bytes based on type          */
  11576.  
  11577.    #define NCOINS (4)
  11578.    #define CENT (0x9b)  /* IBM PC cent character */
  11579.    #define WAIT printf("(Press any key to continue)"); \
  11580.                 getch(); printf("\n\n")
  11581.  
  11582.    main()
  11583.    {
  11584.        static int coins[NCOINS] = {25, 10, 5, 1};
  11585.        int *coin_ptr, i = 0;
  11586.        int pennies1, pennies2, count;
  11587.        float amount;
  11588.  
  11589.        printf("Enter an amount and I will ");
  11590.        printf("give you change.\nAmount: ");
  11591.        if (scanf("%f", &amount) != 1)
  11592.            {
  11593.            printf("I don't know how to change that!\n");
  11594.            exit(1);
  11595.            }
  11596.        pennies2 = pennies1 = (int)(amount * 100.0);
  11597.  
  11598.        coin_ptr = coins;
  11599.        for (i = 0; i < NCOINS; ++i)
  11600.            {
  11601.            WAIT;
  11602.            count = 0;
  11603.            while ((pennies1 -= coins[i]) >= -1)
  11604.                ++count;
  11605.            if (count > 0)
  11606.                {
  11607.                printf("%4d %2d%c", count, coins[i], CENT);
  11608.                printf(" coins by array offset.\n");
  11609.                }
  11610.            if (pennies1 == 0)
  11611.                break;
  11612.            pennies1 += coins[i];
  11613.  
  11614.            count = 0;
  11615.            while ((pennies2 -= *coin_ptr) >= 0)
  11616.                ++count;
  11617.            if (count > -1)
  11618.                {
  11619.                printf("%4d %2d%c", count, *coin_ptr, CENT);
  11620.                printf(" coins by pointer indirection.\n");
  11621.                }
  11622.            if (pennies2 == 0)
  11623.                break;
  11624.            pennies2 += *coin_ptr;
  11625.            ++coin_ptr;
  11626.            }
  11627.    }
  11628.    ──────────────────────────────────────────────────────────────────────────
  11629.  
  11630.    Listing 8-3.  The CHANGE.C program.
  11631.  
  11632.    After you compile CHANGE.C, turn off screen swapping and specify the
  11633.    following four watch variables:
  11634.  
  11635.      coin_ptr
  11636.      *coin_ptr
  11637.      i
  11638.      coins[i]
  11639.  
  11640.    (See pp. 119-20 if you forgot how to specify watch variables. You don't
  11641.    need to specify the types with a comma; the defaults are correct.) Now
  11642.    step through the program with the F8 function key. Observe that as ++i
  11643.    followed by coins[i] steps through the array, so does ++coin_ptr followed
  11644.    by *coin_ptr. Figure 8-3 shows the screen as the program is being traced.
  11645.  
  11646.    ┌────────────────────────────────────────────────────────────────────────┐
  11647.    │ Figure 8-3 can be found on p.236 of the printed version of the book.   │
  11648.    └────────────────────────────────────────────────────────────────────────┘
  11649.  
  11650.    Figure 8-3. Incrementing a pointer moves it through an array in steps
  11651.    that correspond to the number of bytes in the data type.
  11652.  
  11653.    This equivalence between arrays and incrementing pointers is one of C's
  11654.    chief strengths. It can also be confusing and can lead to some unexpected
  11655.    bugs. In the CHANGE.C program, we perform bounds checking with the for
  11656.    loop. If we rewrite that loop without i, we need to do one of two things.
  11657.    One option is to put some stop value into our array, such as the last
  11658.    element (0) in the following:
  11659.  
  11660.      int coins[5] = {25, 10, 5, 1, 0};
  11661.  
  11662.    This approach is often used with string variables.
  11663.  
  11664.    The other option requires that we add some means of detecting when the
  11665.    address in coin_ptr becomes too large, as follows:
  11666.  
  11667.      for (coin_ptr = coins; coin_ptr < &coins[4]; ++coin_ptr)
  11668.  
  11669.    This approach is more common for situations where a stop value is not
  11670.    practical. In a database, for example, you might have 32 bytes available
  11671.    and want to use all 32 for a mailing address, with none reserved for a
  11672.    terminating value.
  11673.  
  11674.  
  11675.  Pointer Arithmetic
  11676.  
  11677.    QuickC permits fewer arithmetic operations on pointers than on other kinds
  11678.    of variables. Because pointers contain addresses as their values, whenever
  11679.    you change one, you reference a new location inside your computer's
  11680.    memory. Obviously, you don't want to reference random locations──not only
  11681.    would they be meaningless, but they might overwrite crucial memory
  11682.    locations and crash your PC.
  11683.  
  11684.    To help avoid such meaningless addresses, C permits only a handful of
  11685.    mathematical operations to be performed on pointers. They are:
  11686.  
  11687.    Addition  You can add values to addresses (like incrementing with ++).
  11688.    This is most useful with arrays.
  11689.  
  11690.    Subtraction  You can subtract values from addresses (decrementing with --
  11691.    and subtracting with -).
  11692.  
  11693.    Comparison  You can compare one address to another to see if it is greater
  11694.    than, less than, equal to, or not equal to the other.
  11695.  
  11696.    ──────────────────────────────────────────────────────────────────────────
  11697.    Quick Tip
  11698.    C does not provide many safeguards against referencing incorrect
  11699.    addresses. QuickC, however, lets you compile with Pointer Check turned on.
  11700.    Although this provides a measure of safety (by verifying that pointer
  11701.    values address program data), it results in slower-executing programs.
  11702.    ──────────────────────────────────────────────────────────────────────────
  11703.  
  11704.    The operations allowed on pointers are a small set when compared to the
  11705.    operations allowed on numeric variables and array items. Let's examine why
  11706.    you cannot use the other arithmetic operations:
  11707.  
  11708.    Multiplication  Doubling an address or even multiplying it by, let's say,
  11709.    523 would yield a new address value that, at best, would be somewhere in
  11710.    your data and at worst would be beyond the end of your program, possibly
  11711.    in the code of another memory resident program (like QuickC or
  11712.    COMMAND.COM).
  11713.  
  11714.    Division  Halving an address or even dividing it by, let's say, 10 would
  11715.    yield a new address value that, at best, would be somewhere inside your
  11716.    own code and at worst would be inside the MS-DOS interrupt vectors.
  11717.  
  11718.    Bitwise operators  You cannot manipulate the bits in an address. This
  11719.    would result in a totally random address.
  11720.  
  11721.    Unary negation  You can't reverse the sign of an address because addresses
  11722.    are always unsigned.
  11723.  
  11724.    Now let's look at the CHANGE2.C program (Listing 8-4). This rewrite of
  11725.    CHANGE.C illustrates the incrementing of pointers and the comparison of
  11726.    two pointers.
  11727.  
  11728.    ──────────────────────────────────────────────────────────────────────────
  11729.    /* change2.c -- modified to demonstrate passing       */
  11730.    /*              an address to a function              */
  11731.  
  11732.    #define NCOINS (4)
  11733.    #define CENT (0x9B)  /* IBM PC cent character */
  11734.  
  11735.    main()
  11736.    {
  11737.        static int coins[NCOINS] = {25, 10, 5, 1};
  11738.        int pennies;
  11739.        float amount;
  11740.  
  11741.        printf("Enter an amount and I will ");
  11742.        printf(" give you change.\nAmount: ");
  11743.        if (scanf("%f", &amount) != 1)
  11744.            {
  11745.            printf("I don't know how to change that!\n");
  11746.            exit(1);
  11747.            }
  11748.        pennies = (int)(amount * 100.0);
  11749.  
  11750.        Show_change(coins, &coins[NCOINS], pennies);
  11751.  
  11752.        }
  11753.    Show_change(int amts[], int *end, int due)
  11754.    {
  11755.        int count;
  11756.  
  11757.        while (amts < end)    /* compare pointers */
  11758.            {
  11759.            count = 0;
  11760.            while ((due -= *amts) >= -1)
  11761.                {
  11762.                ++count;
  11763.                }
  11764.            if (count > 0)
  11765.                printf("%4d %2d%c\n", count, *amts, CENT);
  11766.            if (due == 0)
  11767.                break;
  11768.            due += *amts;
  11769.  
  11770.            ++amts;                /* increment a pointer */
  11771.            }
  11772.    }
  11773.    ──────────────────────────────────────────────────────────────────────────
  11774.  
  11775.    Listing 8-4.  The CHANGE2.C program.
  11776.  
  11777.    The function Show_change() receives addresses of the array coins and the
  11778.    fourth element in that array (one past its end). This introduces some new
  11779.    concepts: the interchangeability of the declaration coins[] with the
  11780.    declaration *coins and the importance of left versus right values.
  11781.  
  11782.  
  11783.  The Interchangeability of *amts and amts[]
  11784.  
  11785.    In the following declaration:
  11786.  
  11787.      Show_change(int amts[]);
  11788.      {
  11789.  
  11790.    the expression int amts[] tells the compiler to pass this array to the
  11791.    function Show_change(). However, you can also use an array declaration of
  11792.    the form *amts interchangeably with amts[]. The two are equivalent. In
  11793.    fact, if you declare an array as amts[], you can use that array's name as
  11794.    though it were a pointer:
  11795.  
  11796.      Show_change(int amts[])
  11797.          {             └──────────────────────────── Declared as an array
  11798.          ...
  11799.          due = *amts;
  11800.                └──┴──────────────────────────────── but used as a pointer
  11801.  
  11802.    and vice versa:
  11803.  
  11804.      Show_change(int *amts[])
  11805.          {              └────────────────────────── Declared as a pointer
  11806.          ...
  11807.          due = amts[i];
  11808.                  └──┴─────────────────────────────── but used as an array
  11809.  
  11810.    Note, however, that this interchangeability works only when the array is
  11811.    declared as one of a function's received arguments. An attempt to use that
  11812.    singular equivalence elsewhere results in either a Syntax or an lvalue
  11813.    error.
  11814.  
  11815.  
  11816.  lvalue vs rvalue
  11817.  
  11818.    An lvalue is any variable whose value can change (have a new value
  11819.    assigned to it). An rvalue is a variable whose value cannot change. The
  11820.    easiest way to differentiate between the two is to remember that rvalues
  11821.    go to the right of the assignment operator and lvalues go to the left. Why
  11822.    is this important?
  11823.  
  11824.    Arrays are usually rvalues because of the way C generates its intermediate
  11825.    code. C treats an array as a label (like the target of a goto is a label).
  11826.    As an address of a location, an array is a constant value much like the
  11827.    number 3 is a constant.
  11828.  
  11829.    Confusing lvalues and rvalues with array names is a common source of
  11830.    errors for the beginning C programmer. Always remember that array names
  11831.    cannot be assigned to, incremented, or decremented, except when they are
  11832.    declared as one of the received arguments of a function, as follows:
  11833.  
  11834.      char *Amount;───────────────────────────────────Global pointer or lvalue
  11835.      int   Bills[4] = {20,10,5,1};────────────────────────────Array or rvalue
  11836.  
  11837.      some_function(char amts[];)──────────────────────Equivalent to a pointer
  11838.          {
  11839.          char *address_var,───────────────────────────Local pointer or lvalue
  11840.                old_coins[];──────────────────────────────────────Syntax error
  11841.  
  11842.          ++Amounts;─────────────────────────────────────────────────────Legal
  11843.          ++Bills;─────────────────────────────────Illegal operation on rvalue
  11844.          ++amts;────────────────────────────────────────────────────────Legal
  11845.          ++address_var;─────────────────────────────────────────────────Legal
  11846.          ++old_coins;───────────────────────────────────────────────────Legal
  11847.          }
  11848.  
  11849.    In this sample program, *Amount and *address_var are pointers, values that
  11850.    can be incremented. Although amts[] is declared as an array, the
  11851.    interchangeability we discussed earlier permits us to increment it as
  11852.    though it were a pointer. On the other hand, because Bills is not a
  11853.    function's argument (it is a global array), it is an rvalue that cannot be
  11854.    incremented. Finally, old_coins[] generates a syntax error because only
  11855.    arrays in function argument declarations can be used without specifying
  11856.    the size of their leftmost dimension.
  11857.  
  11858.  
  11859.  Type Casting Pointers and Addresses
  11860.  
  11861.    Occasionally you will need to perform an arithmetic operation on a pointer
  11862.    other than addition, subtraction, or comparison. Fortunately, C is very
  11863.    flexible, and it permits you to perform those other operations on pointers
  11864.    by using type casts (also called "casts"). In Chapter 3 you used a type
  11865.    cast to convert one type to another: You can also use that technique with
  11866.    pointers. For example, suppose you need to divide a pointer's value by 2.
  11867.    You could use the method:
  11868.  
  11869.      unsigned long temp;
  11870.      int *point = some_address;
  11871.  
  11872.      temp = (unsigned long)point;
  11873.      temp /= 2;
  11874.      point = (int *)temp;
  11875.  
  11876.    First, we assign the address some_address to the pointer int *point. Next,
  11877.    we type cast the value in point (the address of some_address) to force a
  11878.    change to unsigned long, and then we store the resulting value in temp.
  11879.    Because it is legal to divide an unsigned long, we divide temp by 2. Then
  11880.    we cast that result, still an unsigned long, to the type int * (meaning
  11881.    pointer to an int). Finally, we place the correctly typed new value in
  11882.    point.
  11883.  
  11884.    The PEEK.C program (Listing 8-5) illustrates this use of type casting.
  11885.    PEEK.C asks the user for a number, then treats that number as an address
  11886.    and shows you the value stored at that address.
  11887.  
  11888.    ──────────────────────────────────────────────────────────────────────────
  11889.    /* peek.c    -- demonstrates how to cast an int to a  */
  11890.    /*              pointer                               */
  11891.  
  11892.    main()
  11893.    {
  11894.        char *mem_ptr;
  11895.        unsigned int address;
  11896.  
  11897.        while (1)
  11898.            {
  11899.            printf("Examine what memory location?\n");
  11900.            printf("Enter location in decimal: ");
  11901.            if (scanf("%u", &address) != 1)
  11902.                break;
  11903.  
  11904.            mem_ptr = (char *)address;   /* cast  */
  11905.  
  11906.            printf("The value in %u is 0x%02X\n",
  11907.                    address, (unsigned char)*mem_ptr);
  11908.            }
  11909.    }
  11910.    ──────────────────────────────────────────────────────────────────────────
  11911.  
  11912.    Listing 8-5.  The PEEK.C program.
  11913.  
  11914.  
  11915.  far Pointers
  11916.  
  11917.    So far, we've assumed that all pointers occupy two bytes of memory. Two
  11918.    bytes can represent only addresses in the range 0 through 65535, however──
  11919.    not nearly enough to reference every location in the latest PCs.
  11920.    Fortunately, QuickC provides a 4-byte pointer, called a far pointer, that
  11921.    can address more than four billion bytes of memory.
  11922.  
  11923.    In particular, far pointers are useful for directly accessing the text
  11924.    screen's memory and for producing sophisticated graphics programs. In this
  11925.    section we'll show you how to manipulate the text screen of a graphics
  11926.    adapter.
  11927.  
  11928.    To declare a far pointer, merely add the keyword far to the pointer
  11929.    declaration, as follows:
  11930.  
  11931.      int far *screenp;
  11932.  
  11933.    We must use a far pointer to access screen memory because that memory is
  11934.    located at 0xB000000 (for machines with CGA) or 0xB800000 (for machines
  11935.    with EGA or VGA), locations that clearly will not fit into a 2-byte
  11936.    pointer (two bytes can hold only four hex digits, not eight). To place
  11937.    this hexadecimal constant into a far pointer, use the following type cast:
  11938.  
  11939.      screenp = (int far *)0xB000000;──────────────────────────────────────CGA
  11940.      screenp = (int far *)0xB800000;───────────────────────────────EGA or VGA
  11941.  
  11942.    This tells the compiler to handle the constant 0xB000000 (or 0xB800000) as
  11943.    a far address and to assign that address to the far pointer variable
  11944.    screenp.
  11945.  
  11946.    The SCRINV.C program (Listing 8-6) demonstrates a simple technique for
  11947.    manipulating text screen memory. Every time you press a key, the screen
  11948.    flips over. (Type Q to quit.) In the listing, adjust the constant assigned
  11949.    to screenp to suit your hardware: For EGA or VGA, replace 0xB000000 with
  11950.    0xB800000.
  11951.  
  11952.    This program uses a pointer as if it were an array. Although we declare
  11953.    screenp as a far pointer:
  11954.  
  11955.      int far *screenp;
  11956.  
  11957.    we reference its elements using an offset in square brackets, as follows:
  11958.  
  11959.      temp = screenp[i];
  11960.  
  11961.    ──────────────────────────────────────────────────────────────────────────
  11962.    Quick Tip
  11963.    Be careful when casting pointers to integers. You should always type cast
  11964.    to an unsigned long because that type will be large enough to hold all
  11965.    addresses. Specifying unsigned will prevent addresses from being (wrongly)
  11966.    considered negative, which could lead to incorrect results.
  11967.    ──────────────────────────────────────────────────────────────────────────
  11968.  
  11969.    ──────────────────────────────────────────────────────────────────────────
  11970.    /* scrinv.c  --  using a far pointer to access text   */
  11971.    /*               screen memory                        */
  11972.  
  11973.    #define ROWS 25
  11974.    #define COLS 80
  11975.  
  11976.    main()
  11977.    {
  11978.        int far *screenp;
  11979.        int temp, i;
  11980.  
  11981.        do
  11982.            {
  11983.            /* use 0xB800000 for EGA or VGA */
  11984.            screenp = (int far *)0xB000000;
  11985.  
  11986.            for (i = 0; i < ((ROWS*COLS)/2); ++i)
  11987.                {
  11988.                temp = screenp[i];
  11989.                screenp[i] = screenp[(ROWS*COLS)-i-1];
  11990.                screenp[(ROWS*COLS)-i-1] = temp;
  11991.                }
  11992.            } while (getch() != 'Q');
  11993.  
  11994.    }
  11995.    ──────────────────────────────────────────────────────────────────────────
  11996.  
  11997.    Listing 8-6.  The SCRINV.C program.
  11998.  
  11999.  
  12000.  Functions That Return Addresses
  12001.  
  12002.    In Chapter 6, we demonstrated that functions can return values and that
  12003.    those values are of type int unless you declare otherwise. You can also
  12004.    declare functions that return addresses. The C library contains many
  12005.    functions of this type, and your functions can also take advantage of the
  12006.    speed and compactness this procedure offers.
  12007.  
  12008.    You declare a function that returns an address the way you declare a
  12009.    pointer variable──with a type, a *, and a name. For example, the following
  12010.    function returns the address of a char type:
  12011.  
  12012.      char *function(int arg)
  12013.      {
  12014.  
  12015.    ──────────────────────────────────────────────────────────────────────────
  12016.    Quick Tip
  12017.    We declared screenp as a pointer to an int because each character on your
  12018.    PC text screen is represented by two bytes of information──one byte is the
  12019.    character and the other is that character's attribute (normal, blinking,
  12020.    inverse, etc.). (We will discuss this organization and the various
  12021.    attributes in Chapter 14.)
  12022.    ──────────────────────────────────────────────────────────────────────────
  12023.  
  12024.    This is like using a function as a pointer. Let's try another example.
  12025.    Examine the function Range() in the following fragment from an upcoming
  12026.    program.
  12027.  
  12028.      char *Range(int key)
  12029.      {
  12030.          static char  k2[]   = {'a', 'b', 'c'},
  12031.                       k3[]   = {'d', 'e', 'f'},
  12032.                       k4[]   = {'g', 'h', 'i'};
  12033.          char *kp;
  12034.  
  12035.          if (key == 2)
  12036.              {
  12037.              return (k2);───────────────────────────────────────Address of k2
  12038.              }
  12039.          else if (key == 3)
  12040.              {
  12041.              return (&k3[0]);───────────────────────────────────Address of k3
  12042.              }
  12043.          kp = k4;
  12044.          return (kp);───────────────────Return value of a pointer, an address
  12045.      }
  12046.  
  12047.    This example demonstrates that you can return an address in three ways: as
  12048.    an array name (k2), as the address of the first element in an array
  12049.    (&k3[0]), or as a pointer (kp).
  12050.  
  12051.    Now let's call the above function from another named main():
  12052.  
  12053.      main()
  12054.      {
  12055.          char *keys;
  12056.          extern char *Range();────────Range will return the address of a char
  12057.  
  12058.    Notice that you can only use the return value of Range() after you
  12059.    correctly declare it, both in its own declaration and in (or before) any
  12060.    functions that call it.
  12061.  
  12062.    You can use a pointer value returned by a function the same way you use a
  12063.    pointer──with one exception. The address returned by a function is an
  12064.    rvalue: Thus, you can neither place it to the left of the assignment
  12065.    operator nor change it by computation. The following examples illustrate
  12066.    three correct ways to use the value returned by Range():
  12067.  
  12068.      keys = Range(2);────────────────────Address assigned to keys (a pointer)
  12069.  
  12070.      printf("%cn", Range(2)[1]);─────────────────────Address used as an array
  12071.  
  12072.      printf("%cn", *(Range(2)+1));──────────────────Address used as a pointer
  12073.  
  12074.    The first example assigns the address value returned by Range() to a
  12075.    pointer variable (keys). The second example uses the address returned by
  12076.    Range() as if it were an array, printing the second element. The third
  12077.    example uses the address returned by Range() as if it were a pointer,
  12078.    printing the value stored in that address plus one.
  12079.  
  12080.    The PHWORD.C program (Listing 8-7) asks the user for a telephone number
  12081.    and then, using the letters of the telephone dial, prints out all the
  12082.    possible words that can be made from that number.
  12083.  
  12084.    ──────────────────────────────────────────────────────────────────────────
  12085.    /* phword.c   --  generates all the possible words     */
  12086.    /*                in a phone number; demonstrates      */
  12087.    /*                functions that return addresses      */
  12088.  
  12089.    #define MAXD (7)    /* 7 digits max */
  12090.  
  12091.    main()
  12092.    {
  12093.        int digits[MAXD], ndigits = 0, line = 0;
  12094.        char *letters;
  12095.        signed char digit;
  12096.        int a, b, c, d, e, f, g;
  12097.        extern char *Range();
  12098.  
  12099.        printf("Enter Phone Number (7 digits): ");
  12100.        do
  12101.            {
  12102.            digit = getch() - '0';
  12103.            if (digit == ('-' - '0'))
  12104.                continue;
  12105.            if (digit < 0 || digit > 9)
  12106.                {
  12107.                printf("\nAborted: Nondigit\n");
  12108.                return(1);
  12109.                }
  12110.            digits[ndigits++] = digit;
  12111.            printf("%d", digit);
  12112.            } while (ndigits < 7);
  12113.        printf("\n");
  12114.  
  12115.        for( a = 0; a < 3; ++a)
  12116.         for( b = 0; b < 3; ++b)
  12117.          for( c = 0; c < 3; ++c)
  12118.           for( d = 0; d < 3; ++d)
  12119.            for( e = 0; e < 3; ++e)
  12120.             for( f = 0; f < 3; ++f)
  12121.              for( g = 0; g < 3; ++g)
  12122.                  {
  12123.                  printf("%c", Range(digits[0])[a]);
  12124.                  printf("%c", Range(digits[1])[b]);
  12125.                  printf("%c", Range(digits[2])[c]);
  12126.                  printf("%c", Range(digits[3])[d]);
  12127.                  printf("%c", Range(digits[4])[e]);
  12128.                  printf("%c", Range(digits[5])[f]);
  12129.                  printf("%c", Range(digits[6])[g]);
  12130.                  printf("\n");
  12131.                  if (++line == 20)
  12132.                      {
  12133.                      printf("Press any key for more");
  12134.                      printf(" (or q to quit): ");
  12135.                      if (getch() == 'q')
  12136.                          return (0);
  12137.                      printf("\n");
  12138.                      line = 0;
  12139.                      }
  12140.                  }
  12141.    }
  12142.  
  12143.    char *Range(int key)
  12144.    {
  12145.        static char keys[10][3] = {
  12146.            {'0', '0', '0'},
  12147.            {'1', '1', '1'},
  12148.            {'a', 'b', 'c'},
  12149.            {'d', 'e', 'f'},
  12150.            {'g', 'h', 'i'},
  12151.            {'j', 'k', 'l'},
  12152.            {'m', 'n', 'o'},
  12153.            {'p', 'r', 's'},
  12154.            {'t', 'u', 'v'},
  12155.            {'w', 'x', 'y'}
  12156.        };
  12157.  
  12158.        return (keys[key]);
  12159.    }
  12160.    ──────────────────────────────────────────────────────────────────────────
  12161.  
  12162.    Listing 8-7.  The PHWORD.C program.
  12163.  
  12164.    The PHWORD.C program also illustrates another point about arrays. When you
  12165.    reference a multidimensional array with only a partial list of offsets,
  12166.    the value generated is the address of the portion you referenced. Thus,
  12167.    although keys in Range() is a two-dimensional array, referencing with only
  12168.    a single dimension, as follows:
  12169.  
  12170.      return (keys[key]);
  12171.  
  12172.    yields the address of only the row specified. In other words, it yields
  12173.    the address of a one-dimensional array that is a subset of the
  12174.    two-dimensional array.
  12175.  
  12176.    ──────────────────────────────────────────────────────────────────────────
  12177.    Quick Tip
  12178.    The extern keyword tells QuickC that the variable or function named will
  12179.    be found elsewhere, either later in the current file or in another file
  12180.    that you plan to compile separately. It can also be used to tell QuickC
  12181.    that you plan to use a variable found in a library routine.
  12182.    ──────────────────────────────────────────────────────────────────────────
  12183.  
  12184.    Notice in PHWORD.C that main() screens your telephone number for illegal
  12185.    characters. The function Range() would be more portable if we checked for
  12186.    illegal values inside of it and returned an error code. The trick is to
  12187.    return an error address that is always illegal. Defined in the standard
  12188.    header file stdio.h is the perfect value to convey address errors──NULL.
  12189.    This special zero address value is guaranteed to be illegal. By using NULL
  12190.    rather than 0, you ensure the portability of your programs.
  12191.  
  12192.    The following is a rewrite of Range() that uses NULL:
  12193.  
  12194.      #include <stdio.h>       /* for NULL */
  12195.  
  12196.      char *Range(int key)
  12197.      {
  12198.          static char keys[10][3] = ...
  12199.  
  12200.          if (key < 0 || key > 9)
  12201.              {
  12202.              return (NULL);
  12203.              }
  12204.  
  12205.    Now Range() does its own error checking. It can return NULL, even though
  12206.    it is declared char *, because NULL is a special address value that is
  12207.    illegal regardless of the expected return type.
  12208.  
  12209.  
  12210.  Dynamic Arrays
  12211.  
  12212.    In the previous chapter, we explained that arrays in C must be
  12213.    dimensioned with integer constant expressions, and therefore you cannot
  12214.    change the size of a declared array. But now that you have pointers at
  12215.    your disposal, the situation is somewhat different. By using standard C
  12216.    Library routines, you can allocate memory while the program is running
  12217.    (that is, "dynamically") and thus create arrays "on the fly." You can also
  12218.    use other C library routines to change the size of dynamically allocated
  12219.    arrays, again while the program is running.
  12220.  
  12221.    The ability to create, change the size of, and discard arrays from within
  12222.    your running program opens a host of new programming possibilities. It
  12223.    frees your program from having to know ahead of time how many lines of
  12224.    text a user will type, for example, or how many characters it will receive
  12225.    via a modem. When you design a database, it is clearly better to allow
  12226.    users to add fields at will, rather than restricting them to a
  12227.    predetermined record structure. Games are generally more interesting when
  12228.    players can add characters at any time. Text editors are more powerful
  12229.    when the user can interactively define keyboard macros.
  12230.  
  12231.    The standard library routines for the dynamic allocation and reallocation
  12232.    of memory are listed in Table 8-1 on the following page. The return types
  12233.    for these functions are declared in the header file <malloc.h>. If you
  12234.    look at those declarations (using the Include option on the View menu),
  12235.    you will see that they are all declared as pointer type void *. This new
  12236.    type, when applied to a function's return value, permits the returned
  12237.    address to be legally assigned to any type of pointer. This makes it very
  12238.    easy for us to create dynamic arrays of any type.
  12239.  
  12240.    Table 8-1 Memory Allocation Library Routines
  12241.    ──────────────────────────────────────────────────────────────────────────
  12242.    malloc()           Memory allocate
  12243.    calloc()           Computed memory allocate
  12244.    realloc()          Reallocate memory
  12245.    free()             Free allocated memory
  12246.    sbrk()             Request memory from system
  12247.    ──────────────────────────────────────────────────────────────────────────
  12248.  
  12249.  The malloc() Memory Allocation Function
  12250.  
  12251.    The malloc() function is the most frequently used library allocation
  12252.    function. It takes a single argument, the number of bytes of memory you
  12253.    wish to allocate (reserve), and returns the address of that memory. If
  12254.    malloc() cannot find as much free memory as you specify, it returns a NULL
  12255.    value. The correct form for using malloc() (including a check for failure)
  12256.    follows:
  12257.  
  12258.      #include <stdio.h>──────────────────────────────────────────────For NULL
  12259.      #include <malloc.h>─────────────────────────────For malloc() declaration
  12260.      ...
  12261.      int *iptr;────────────────────────────────────────────To receive address
  12262.      size_t bytes = 100;──────────────────────────────────────Number of bytes
  12263.  
  12264.      if ((iptr = malloc(bytes)) == NULL)
  12265.          {
  12266.          /* handle error here */
  12267.          }
  12268.      printf("Now let's fill the array iptr[]\n");
  12269.  
  12270.    The parentheses in the malloc() expression force the result of the
  12271.    assignment──the value of iptr──to be compared to NULL. If malloc succeeds
  12272.    in allocating memory, iptr contains the address of that dynamically
  12273.    allocated memory.
  12274.  
  12275.    Because the value of iptr evaluates as an address, you can use iptr as if
  12276.    it were an array. For example, the following expression is perfectly
  12277.    legal:
  12278.  
  12279.      iptr[5]
  12280.  
  12281.    ──────────────────────────────────────────────────────────────────────────
  12282.    Quick Tip
  12283.    Note in the above example that we declare bytes as type size_t. This type
  12284.    is defined in <malloc.h> as an unsigned int for QuickC. Because the type
  12285.    size_t is a part of the ANSI standard, you should use it rather than
  12286.    unsigned int to ensure the portability of your programs.
  12287.  
  12288.    However, to transport programs written with size_t to different machines,
  12289.    you might need to use #define to make size_t an unsigned int.
  12290.    ──────────────────────────────────────────────────────────────────────────
  12291.  
  12292.    The TOTAL.C program (Listing 8-8) asks you to type numbers, one per line,
  12293.    and dynamically builds an array of those numbers. When you enter a
  12294.    non-numeric character, the program displays your list of numbers from the
  12295.    array and totals them.
  12296.  
  12297.    This program introduces two new elements to our memory allocation
  12298.    routines: free() and realloc(). The free() function releases memory that
  12299.    you reserve with malloc() or realloc(). The realloc() function copies
  12300.    memory into a larger or smaller block of memory.
  12301.  
  12302.    ──────────────────────────────────────────────────────────────────────────
  12303.    /* total.c  -- how to build an array on the fly     */
  12304.  
  12305.    #include <stdio.h>         /* for NULL   */
  12306.    #include <malloc.h>        /* for size_t */
  12307.  
  12308.    main()
  12309.    {
  12310.        int *iptr, count = 0, i, total;
  12311.        size_t bytes = sizeof(int);
  12312.  
  12313.        /* Start the array with room for one value. */
  12314.        if ((iptr = malloc(bytes)) == NULL)
  12315.            {
  12316.            printf("Oops, malloc failed\n");
  12317.            exit(1);
  12318.            }
  12319.  
  12320.        printf("Enter as many integer values as you want.\n");
  12321.        printf("I will build an array on the fly with them.\n");
  12322.        printf("(Any non-number means you are done.)\n");
  12323.  
  12324.        while (scanf("%d", &iptr[count]) == 1)
  12325.            {
  12326.            ++count;
  12327.            /* Enlarge the array. */
  12328.            if ((iptr = realloc(iptr,bytes*(count+1))) == NULL)
  12329.                {
  12330.                printf("Oops, realloc failed\n");
  12331.                exit(1);
  12332.                }
  12333.            }
  12334.        total = 0;
  12335.        printf("You entered:\n");
  12336.        for (i = 0; i < count; i++)
  12337.            {
  12338.            printf("iptr[%d] = %d\n", i, iptr[i]);
  12339.            total += iptr[i];
  12340.            }
  12341.        printf("\nTotal: %d\n", total);
  12342.    }
  12343.    ──────────────────────────────────────────────────────────────────────────
  12344.  
  12345.    Listing 8-8.  The TOTAL.C program.
  12346.  
  12347.    The free() function takes a single argument, the address returned by
  12348.    malloc() or realloc(), and uses it to release that memory. Note that if
  12349.    you pass free() an address other than one returned by one of these
  12350.    functions, your program may crash.
  12351.  
  12352.    The realloc() function takes two arguments: first, the address returned by
  12353.    malloc() or one returned from a previous call to realloc(); and second, a
  12354.    new size in bytes. The function copies the contents of the old memory to
  12355.    the new memory (truncating if the new size is smaller) and returns the
  12356.    address of the new memory. Like malloc(), realloc() returns a NULL address
  12357.    if it fails.
  12358.  
  12359.  The calloc() Memory Allocation Routine
  12360.  
  12361.    QuickC supplies a companion routine to malloc() called calloc() (for
  12362.    "calculated allocate"). The calloc() function also allocates memory, but
  12363.    with a twist that makes it ideal for arrays. Instead of merely allocating
  12364.    a number of bytes, it takes a pair of arguments: the number of items and
  12365.    the number of bytes (sizeof) of each item. The form for using calloc() is
  12366.    as follows:
  12367.  
  12368.      address = calloc(items, sizeof(item));
  12369.  
  12370.    Like malloc(), calloc() returns the address of successfully allocated
  12371.    memory or NULL if not enough memory is available.
  12372.  
  12373.    The advantage offered by calloc() is that it initializes allocated memory
  12374.    to zero values, whereas malloc() can leave memory that is filled with
  12375.    garbage. The free() function also releases memory reserved by calloc().
  12376.  
  12377.  The sbrk() Memory Extension Function
  12378.  
  12379.    The malloc() family of routines keeps track of all the memory you
  12380.    allocate. These routines use extra bytes to keep a list of allocated
  12381.    memory and still more bytes to ensure that all addresses are even. If your
  12382.    program is short on space, those pieces of memory might be too valuable to
  12383.    waste on mere housekeeping. These functions also need to search through
  12384.    lists of available memory to find blocks of the requested size. If you
  12385.    have allocated many chunks of memory, that search slows the execution of
  12386.    your program.
  12387.  
  12388.    QuickC's sbrk() function offers a quick and efficient way to allocate
  12389.    memory when you don't need to keep track of how much has been allocated.
  12390.    When you load a program into memory, it is arranged as shown in Figure
  12391.    8-4. The address of the end of the data segment serves to record the
  12392.    highest memory location you can legally access. The sbrk() function
  12393.    requests that the highest location be extended by a specified number of
  12394.    bytes, as follows:
  12395.  
  12396.      address = sbrk(bytes);
  12397.  
  12398.    The value returned by sbrk() is the address of the old limit before it was
  12399.    extended (in other words, the address of the first byte of the newly
  12400.    acquired memory). The address of the first byte beyond the new memory
  12401.    allocation then replaces the previously stored value.
  12402.  
  12403.                ┌- - - - - - - - - - -─┐───New highest after sbrk()
  12404.                |                      |
  12405.                |                      |
  12406.                ├──────────────────────┤───Offset from DS
  12407.                ├─────────────────────┤
  12408.                │            └─────────┼────Highest memory location
  12409.                │                      │    your program can use
  12410.                │                      │
  12411.                │        DATA          │────Uninitialized data
  12412.                │                      │
  12413.                │                      │
  12414.                ├──────────────────────┤
  12415.                │                      │
  12416.                │        DATA          │────Initialized data
  12417.                │                      │
  12418.                ├──────────────────────┤
  12419.               │                      │
  12420.        │       │                      │
  12421.        │       │        CODE          │────Your program's code
  12422.        │       │                      │
  12423.        │       │                      │
  12424.    Increasing  │                      │
  12425.    memory      └──────────────────────┘───DS
  12426.  
  12427.    Figure 8-4. The sbrk() function lets you extend the limit of accessible
  12428.    memory.
  12429.  
  12430.    Because sbrk() returns an address of -1 on failure, the full call to
  12431.    sbrk(), including an error check, is as follows:
  12432.  
  12433.      #include <malloc.h> /* for size_t */
  12434.      ...
  12435.      int *iptr;
  12436.      size_t bytes = 100;
  12437.      ...
  12438.      if ((iptr = sbrk(bytes)) == (int *)-1)
  12439.          {
  12440.          /*handle error here */
  12441.          }
  12442.          /* you have 100 bytes at the address in iptr */
  12443.  
  12444.    Note that we must typecast the -1 to (int *) so that the comparison will
  12445.    be to the same type as iptr.
  12446.  
  12447.    The TOTAL2.C program (Listing 8-9 on the following page) uses sbrk() to
  12448.    transform the earlier TOTAL.C program into an adding machine of unlimited
  12449.    capacity. We can use sbrk() in TOTAL2.C because we only take memory and
  12450.    never release or exchange any. Because sbrk() extends memory continuously,
  12451.    our array always remains intact. With malloc(), on the other hand, memory
  12452.    may not be allocated continuously, so you must call realloc() to enlarge
  12453.    and possibly move your array.
  12454.  
  12455.    Unfortunately, giving back pieces of memory that you acquired with sbrk()
  12456.    requires advanced programming expertise. If you need to juggle memory
  12457.    (taking, then giving back part, and so on), malloc() and realloc() are
  12458.    much easier to use. Do not, however, mix sbrk() and the malloc() routines
  12459.    in the same program.
  12460.  
  12461.    ──────────────────────────────────────────────────────────────────────────
  12462.    /* total2.c -- how to build an array on the fly       */
  12463.    /*             using sbrk()                           */
  12464.  
  12465.    #include <stdio.h>        /* for NULL   */
  12466.    #include <malloc.h>       /* for size_t */
  12467.  
  12468.    main()
  12469.    {
  12470.        int *iptr, count = 0, i, total;
  12471.        size_t bytes = sizeof(int);
  12472.  
  12473.        /* Start the array with room for one value. */
  12474.        iptr = sbrk(0);
  12475.        if (sbrk(bytes) == (int *)-1)
  12476.            {
  12477.            printf("Oops, sbrk failed\n");
  12478.            exit(1);
  12479.            }
  12480.  
  12481.        printf("Enter as many integer values as you want.\n");
  12482.        printf("I will build an array on the fly with them.\n");
  12483.        printf("(Any non-number means you are done.)\n");
  12484.  
  12485.        while (scanf("%d", &iptr[count]) == 1)
  12486.            {
  12487.            ++count;
  12488.            /* Enlarge the array. */
  12489.            if (sbrk(bytes) == (int *)-1)
  12490.                {
  12491.                printf("Oops, sbrk failed\n");
  12492.                exit(1);
  12493.                }
  12494.            }
  12495.        total = 0;
  12496.        for (i = 0; i < count; i++)
  12497.            total += iptr[i];
  12498.        /* just print the total this time */
  12499.        printf("%d\n", total);
  12500.    }
  12501.    ──────────────────────────────────────────────────────────────────────────
  12502.  
  12503.    Listing 8-9.  The TOTAL2.C program.
  12504.  
  12505.  
  12506.  Advanced Pointer Techniques
  12507.  
  12508.    Perhaps you've heard horror stories about C pointers and incomprehensible
  12509.    code. Well, some of those stories are true. Reading and understanding
  12510.    poorly written code is like trying to untangle a plate of spaghetti. C
  12511.    gives you the freedom to design many types of strange but useful
  12512.    constructs. But C also gives you the freedom to design the
  12513.    incomprehensible. This section discusses some of C's magnificent but
  12514.    potentially arcane constructs──those dealing with the more elaborate and
  12515.    sophisticated uses of pointers.
  12516.  
  12517.  Arrays of Pointers
  12518.  
  12519.    C lets you create arrays of any type of elements. Thus, you can even
  12520.    create an array whose elements are pointers. For example, to create an
  12521.    array of 10 pointers, in which each item is a pointer to a float, simply
  12522.    declare the following:
  12523.  
  12524.      float *array_name[10];
  12525.  
  12526.    The * preceding the array name in this declaration tells the compiler that
  12527.    the array is an array of pointers; therefore, each element holds an
  12528.    address. The float signifies that all pointers will point to float
  12529.    variables.
  12530.  
  12531.    You can use this technique for speeding up sorting routines, for example.
  12532.    Because an address on a PC occupies only two bytes (except for far
  12533.    pointers), while the data it points to occupies four bytes (for a float),
  12534.    it's faster to exchange two 2-byte addresses than to exchange the data.
  12535.    The advantage offered by arrays of pointers becomes even more evident when
  12536.    we use them with strings in the next chapter.
  12537.  
  12538.    The REVERSE.C program (Listing 8-10 on the following page) reads in lines
  12539.    of characters. The addresses of those lines are stored in an array of
  12540.    pointers to char. (See Figure 8-5.) An empty input line causes the lines
  12541.    of text pointed to by the array of pointers to be printed in reverse
  12542.    order.
  12543.  
  12544.                              cptrs[]
  12545.                              ┌─────┐
  12546.     Pointer to first line────│     │─────────This is the text
  12547.                              ├─────┤
  12548.    Pointer to second line────│     │─────┐    that we typed in.
  12549.                              ├─────┤     │
  12550.                      etc.    │     │───┐ └─────It will be reve
  12551.                              ├─────┤   │
  12552.                              │     │──┐└─────rsed. Line 3 is
  12553.                              ├─────┤  └─────────────┘
  12554.                              │     │─────┐    here. Line 4 is
  12555.                              ├─────┤     └──────────┘
  12556.                              │     │─────┐    here. Line 5 is
  12557.                              ├─────┤     └──────────┘
  12558.                              │     │─────┐    Here. And so on...
  12559.                              ├─────┤     └──────────┘
  12560.                              │     │
  12561.                              ├─────┤           Continuous memory
  12562.                              │     │           allocated with srbk()
  12563.                              └─────┘
  12564.                             Array of
  12565.                             pointers
  12566.  
  12567.    Figure 8-5. An array of pointers, each element of which contains a line of
  12568.    text in allocated memory.
  12569.  
  12570.    ──────────────────────────────────────────────────────────────────────────
  12571.    /* reverse.c -- demonstrates an array of pointers     */
  12572.    /*              by reversing lines of text            */
  12573.  
  12574.    #include <stdio.h>        /* for NULL   */
  12575.    #include <malloc.h>       /* for size_t */
  12576.  
  12577.    #define MAXL 20
  12578.  
  12579.    main()
  12580.    {
  12581.        char *cptrs[MAXL];            /* array of pointers */
  12582.        char *cp;
  12583.        int count, i, j, ch;
  12584.        extern char *Getbyte();
  12585.  
  12586.        printf("Type in several lines of text, and I will\n");
  12587.        printf("print them back out in reverse order.\n");
  12588.        printf("(Any blank line ends input):\n");
  12589.  
  12590.        for (i = 0; i < MAXL; ++i)
  12591.            {
  12592.            cp = Getbyte();
  12593.            cptrs[i] = cp;        /* assign address to pointer */
  12594.            count = 0;
  12595.            while ((ch = getchar()) != '\n')  /* gather line */
  12596.                {
  12597.                *cp = ch;
  12598.                cp = Getbyte();
  12599.                ++count;
  12600.                }
  12601.            *cp = '\0';
  12602.            if (count == 0)        /* all done if blank line */
  12603.                break;
  12604.            }
  12605.        printf("---------<reversed>---------\n");
  12606.        for (j = i-1; j >= 0; --j)
  12607.            {
  12608.            printf("%s\n", cptrs[j]);
  12609.            }
  12610.    }
  12611.  
  12612.    char *Getbyte(void)
  12613.    {
  12614.        char *cp;
  12615.  
  12616.        if ((cp = sbrk(1)) == (char *)-1)
  12617.            {
  12618.            printf("Panic: sbrk failed\n");
  12619.            exit(1);
  12620.            }
  12621.        return (cp);
  12622.    }
  12623.    ──────────────────────────────────────────────────────────────────────────
  12624.  
  12625.    Listing 8-10.  The REVERSE.C program.
  12626.  
  12627.    The fact that we can print an array of characters with printf()
  12628.    illustrates the correspondence between arrays of char and strings. We will
  12629.    discuss that relationship in detail in the next chapter.
  12630.  
  12631.  Pointers to Pointers
  12632.  
  12633.    As you have seen, a pointer is a variable whose value is an address, and
  12634.    that address is usually the location in memory of another variable.
  12635.    However, in C, that other variable can also be a pointer. There is no
  12636.    limit to how far you can extend this "pointer-to-a-pointer" relationship──
  12637.    you can have pointers to pointers to pointers and so on, ad infinitum.
  12638.    Here, however, we'll minimize the danger of creating "spaghetti code" by
  12639.    restricting ourselves to pointers to pointers, sometimes referred to as
  12640.    "handles."
  12641.  
  12642.    Figure 8-6 illustrates the relationship of a pointer to a pointer. The
  12643.    variable pp contains as its value the address of p. The variable p in turn
  12644.    contains as its value the address of num, an ordinary integer. Because p
  12645.    points to an int, pp is a pointer to a pointer to an int.
  12646.  
  12647.    The following example shows how to declare a pointer to a pointer:
  12648.  
  12649.      int **pp, *p, num;
  12650.          │     └─────────────────────────────────────────── Pointer to an int
  12651.          └──────────────────────────────────── Pointer to a pointer to an int
  12652.  
  12653.    The two * characters tell the compiler that pp is a pointer to a pointer
  12654.    and holds as its value the address of another pointer.
  12655.  
  12656.    When accessing the values pointed to by pp, the number of *s determines
  12657.    which value is obtained. Consider the following initialization:
  12658.  
  12659.      p = #─────────────────────────────────────────────────Address of num
  12660.      pp = &p;────────────────────────────────────────────────────Address of p
  12661.  
  12662.                                  Points to a variable
  12663.                     ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  12664.                     ▒                                              ▒
  12665.              ┌───────────┐                                         ▒
  12666.              │           │                                         
  12667.    Memory──   621    622   623   624   625   626   627   628   629   630
  12668.    locations ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
  12669.    in bytes  │    629    │           │    621    │           │     3     │
  12670.              └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
  12671.                    │                       │                       │
  12672.                    │                       │                       │
  12673.                    p                       pp                     num
  12674.                                           ▒
  12675.                    ▒                       ▒
  12676.                    ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  12677.                       Points to a pointer
  12678.  
  12679.    Figure 8-6. Pointer to a pointer: a variable whose value is the address of
  12680.    another pointer.
  12681.  
  12682.    The following statement yields the value stored in the address that pp
  12683.    points to:
  12684.  
  12685.      *pp
  12686.  
  12687.    Because pp points to p, *pp yields the address stored in p, that of num.
  12688.    Placing another * in front of pp:
  12689.  
  12690.      **pp
  12691.  
  12692.    tells the compiler to fetch the value stored in the pointer pointed to by
  12693.    pp. Because pp points to p, and p in turn points to num, **pp fetches the
  12694.    value of num. Thus, all three of the following yield the value stored in
  12695.    the variable num:
  12696.  
  12697.      **pp
  12698.      *p
  12699.      num
  12700.  
  12701.    One useful application for a pointer to a pointer is in traversing arrays
  12702.    of pointers. The REVERSE2.C program (Listing 8-11) is a rewrite of the
  12703.    previous REVERSE.C. In this version, we replace the final for loop with a
  12704.    while loop that decrements pp, a pointer to a pointer.
  12705.  
  12706.    ──────────────────────────────────────────────────────────────────────────
  12707.    /* reverse2.c -- demonstrates a pointer to a pointer  */
  12708.  
  12709.    #include <stdio.h>        /* for NULL   */
  12710.    #include <malloc.h>       /* for size_t */
  12711.  
  12712.    #define MAXL 20
  12713.  
  12714.    main()
  12715.    {
  12716.        char *cptrs[MAXL];
  12717.        char **pp;                    /* pointer to pointer */
  12718.        char *cp;
  12719.        int count, i, ch;
  12720.        extern char *Getbyte();
  12721.  
  12722.        printf("Type in several lines of text, and I will\n");
  12723.        printf("print them back out in reverse order.\n");
  12724.        printf("(Any blank line ends input):\n");
  12725.  
  12726.        for (i = 0; i < MAXL; ++i)
  12727.            {
  12728.            cp = Getbyte();
  12729.            cptrs[i] = cp;        /* assign address to pointer */
  12730.            count = 0;
  12731.            while ((ch = getchar()) != '\n')  /* gather line */
  12732.                {
  12733.                *cp = ch;
  12734.                cp = Getbyte();
  12735.                ++count;
  12736.                }
  12737.            *cp = '\0';
  12738.            if (count == 0)        /* all done if blank line */
  12739.                break;
  12740.            }
  12741.        printf("---------<reversed>---------\n");
  12742.        pp = &cptrs[i];
  12743.        while (pp >= cptrs)
  12744.            {
  12745.            printf("%s\n", *(pp--));
  12746.            }
  12747.    }
  12748.  
  12749.    char *Getbyte(void)
  12750.    {
  12751.        char *cp;
  12752.  
  12753.        if ((cp = sbrk(1)) == (char *)-1)
  12754.            {
  12755.            printf("Panic: sbrk failed\n");
  12756.            exit(1);
  12757.            }
  12758.        return (cp);
  12759.    }
  12760.    ──────────────────────────────────────────────────────────────────────────
  12761.  
  12762.    Listing 8-11.  The REVERSE2.C program.
  12763.  
  12764.    This program shows that a pointer to a pointer is decremented (or
  12765.    incremented) by the number of bytes in a pointer:
  12766.  
  12767.      printf("%s\n", *(pp--))
  12768.                     └──┬──┘
  12769.                        └──┬───────────────────────────────────────── The same
  12770.                     ┌─────┴──┐
  12771.      printf("%s\n", cptrs[i--])
  12772.  
  12773.    Recall that the address in a pointer changes by a number of bytes that
  12774.    corresponds to the type to which it points. A char pointer changes by one
  12775.    byte, while a float pointer changes by four bytes. A pointer to a pointer
  12776.    changes by the number of bytes in an address because it points to a
  12777.    pointer, and thus to an address. Because cptrs[] is an array of pointers,
  12778.    and pp points to one of those addresses, decrementing pp causes it to
  12779.    point to the immediately preceding element in that array. Figure 8-7 on
  12780.    the following page illustrates this process.
  12781.  
  12782.    ──────────────────────────────────────────────────────────────────────────
  12783.    Pointer Pointer
  12784.    Pointers are so versatile that they can contain the address of almost
  12785.    anything. However, you cannot use pointers to obtain the address of the
  12786.    following C elements: constants (such as 5); variables declared with the
  12787.    keyword register; labels (the targets of goto); and keywords (such as if,
  12788.    while, and so on).
  12789.    ──────────────────────────────────────────────────────────────────────────
  12790.  
  12791.                           cptrs[]
  12792.                           ┌─────┐
  12793.                ┌───end────│     │─────────This is the text
  12794.                │          ├─────┤
  12795.                │  --pp────│     │─────┐    that we typed in.
  12796.                │          ├─────┤     │
  12797.       pp       │  --pp────│     │───┐ └─────It will be reve
  12798.    ┌───────┐   │          ├─────┤   │
  12799.    │       │ ──┤  --pp────│     │──┐└─────rsed. Line 3 is
  12800.    └───────┘   │          ├─────┤  └─────────────┘
  12801.    Points to   │  --pp────│     │─────┐    here. Line 4 is
  12802.     pointer    │          ├─────┤     └──────────┘
  12803.                │  --pp────│     │─────┐    here. Line 5 is
  12804.                │          ├─────┤     └──────────┘
  12805.                └─start────│     │─────┐    Here. And so on...
  12806.                           ├─────┤     └──────────┘
  12807.                           │     │
  12808.                           ├─────┤           Continuous memory
  12809.                           │     │           allocated with srbk()
  12810.                           └─────┘
  12811.                          Array of
  12812.                          pointers
  12813.  
  12814.    Figure 8-7. Decrementing a pointer to a pointer moves it down through an
  12815.    array of pointers.
  12816.  
  12817.  Pointers to Functions
  12818.  
  12819.    It is often useful to know the address of a function. You declare a
  12820.    pointer to a function as follows:
  12821.  
  12822.      int (*pointer_name)();
  12823.  
  12824.    This declares the variable pointer_name to be a pointer *pointer_name. The
  12825.    trailing parentheses tell the compiler that the pointer *pointer_name
  12826.    contains the address of a function. The int specifies that the function
  12827.    pointed to returns an int.
  12828.  
  12829.    To obtain the address of a function, merely state its name. However, be
  12830.    sure you declare the function before you take its address:
  12831.  
  12832.      int (*funptr)();─────────────────────────────────A pointer to a function
  12833.      extern int Quit();───────────────────────────────────A function declared
  12834.  
  12835.      funptr = Quit;──────────────────────Address of Quit() assigned to funptr
  12836.  
  12837.    In this example, funptr contains the address of Quit(), and we can call
  12838.    Quit() through funptr, as follows:
  12839.  
  12840.      *funptr();
  12841.  
  12842.    The preceding * tells the compiler to use the value pointed to by funptr
  12843.    (the address of Quit()). The trailing parentheses tell the compiler to
  12844.    call the function whose address we just fetched.
  12845.  
  12846.    The CHOOSE.C program (Listing 8-12) goes one step further by creating an
  12847.    array of pointers to functions. First, the program asks you to choose a
  12848.    menu item. Then it translates your choice into an array offset and calls
  12849.    the function whose address is stored at that offset.
  12850.  
  12851.    ──────────────────────────────────────────────────────────────────────────
  12852.    /* choose.c   --  an array of pointers to functions   */
  12853.    /*                used to create a menu               */
  12854.  
  12855.    void Choice1(), Choice2(), Choice3();
  12856.  
  12857.    void (*Dochoice[3])() = {Choice1, Choice2, Choice3};
  12858.  
  12859.    main()
  12860.    {
  12861.        int ch;
  12862.  
  12863.        printf("Select 1, 2 or 3: ");
  12864.        ch = getch(); putch(ch);
  12865.        ch -= '1';
  12866.        if (ch < 0 || ch > 2)
  12867.            printf("\nNo such choice.\n");
  12868.        else
  12869.            Dochoice[ch]();
  12870.  
  12871.    }
  12872.  
  12873.    void Choice1(void)
  12874.    {
  12875.            printf("\nThis is choice 1\n");
  12876.    }
  12877.  
  12878.    void Choice2(void)
  12879.    {
  12880.            printf("\nThis is choice 2\n");
  12881.    }
  12882.  
  12883.    void Choice3(void)
  12884.    {
  12885.            printf("\nThis is choice 3\n");
  12886.    }
  12887.    ──────────────────────────────────────────────────────────────────────────
  12888.  
  12889.    Listing 8-12.  The CHOOSE.C program.
  12890.  
  12891.    Arrays of pointers to functions are best applied in interactive programs.
  12892.    Believe it or not, you'll find it easier to design word processors and
  12893.    complex games once you master this technique.
  12894.  
  12895.    The following example illustrates the advantage of using an array of
  12896.    pointers to functions instead of a simpler switch statement. Examine the
  12897.    following fragment from a hypothetical text processor:
  12898.  
  12899.      int (*commands[128])() = {
  12900.                 ...
  12901.                 Go_left,     /* l */
  12902.                 Mark_line,   /* m */
  12903.                 Next_search, /* n */
  12904.                 ...
  12905.                 };
  12906.  
  12907.    This array has 128 pointers to functions, each of which corresponds to a
  12908.    key on the keyboard. Pressing l causes Go_left() to be called, moving the
  12909.    cursor left. If the user wishes to change the meaning of the keys,
  12910.    swapping the functions of l and n, for example, you need only use the
  12911.    following:
  12912.  
  12913.      int (*temp)();───────────────────────────────────────────Scratch pointer
  12914.      int from, to;
  12915.  
  12916.      from = 'l';
  12917.      to   = 'n';
  12918.      temp = commands[from];
  12919.      commands[from] = commands[to];
  12920.      commands[to] = temp;
  12921.  
  12922.    Here we first declare a scratch variable to be used in the swap. We
  12923.    declare it as a pointer to a function because we will be swapping pointers
  12924.    to functions. We then assign to temp the address stored in commands[from],
  12925.    where from is the offset that corresponds to the numeric value of the
  12926.    letter `n'. Because that array item is a pointer to the function
  12927.    Next_search(), we are saving the address of that function. We then copy
  12928.    the address in commands[to] into commands[from]. Finally, we assign the
  12929.    address saved in temp to commands[to]. The result of this exchange is that
  12930.    typing n now causes the Go_left() function to be called, and typing l
  12931.    causes the Next_search() function to be called, thereby reversing their
  12932.    roles.
  12933.  
  12934.    Contrast this flexible form of programming with an inflexible switch
  12935.    statement, such as the following:
  12936.  
  12937.      switch(key)
  12938.          {
  12939.          ...
  12940.          case 'l':
  12941.              Go_left();
  12942.              break;
  12943.  
  12944.          case 'm':
  12945.              Mark_line();
  12946.              break;
  12947.  
  12948.          case 'n':
  12949.              Next_search();
  12950.              break;
  12951.          ...
  12952.          }
  12953.  
  12954.    Clearly, a program that a user can customize is more difficult to write,
  12955.    yet a versatile program is always worth the extra effort.
  12956.  
  12957.  Unscrambling the Spaghetti
  12958.  
  12959.    In the previous sections of this chapter you've seen some complicated
  12960.    declarations. You will see more of them in the chapters to follow, so it
  12961.    behooves us to establish some rules that will help us understand complex
  12962.    declarations.
  12963.  
  12964.    Remember: Always start reading at the inside of a declaration with the
  12965.    name (identifier); then work your way outward. For example, to unscramble
  12966.    the following declaration:
  12967.  
  12968.      int (*name)();
  12969.  
  12970.    follow the definition from the inside out: name is a pointer to a function
  12971.    of type int. Thus, this declaration is a pointer to a function that
  12972.    returns an int.
  12973.  
  12974.    Let's try this same technique on a different declaration:
  12975.  
  12976.      float (*name)[3];
  12977.  
  12978.    In this example, name is a pointer to an array of three float variables.
  12979.    Thus, it is a pointer to an array of three floats. Contrast that
  12980.    declaration with the following:
  12981.  
  12982.      float *name[3];
  12983.  
  12984.    Here name is an array of three pointers to float variables. This example
  12985.    is an array of three pointers to floats. The difference lies in the
  12986.    parentheses. Be sure to obey the order of precedence for operators.
  12987.  
  12988.    As an example of using parentheses, try to decipher the following
  12989.    declaration from CHOOSE.C:
  12990.  
  12991.      int (*funs[4])();
  12992.  
  12993.    Here the * operator has a higher precedence than the [] operators, so *
  12994.    binds to funs first. Therefore, funs is a pointer, and four such pointers
  12995.    exist in an array; these pointers point to functions that return the type
  12996.    int. Thus, the declaration is an array of four pointers to functions that
  12997.    return int.
  12998.  
  12999.  
  13000.  
  13001.  ────────────────────────────────────────────────────────────────────────────
  13002.  Chapter 9  Strings
  13003.  
  13004.    A "string" is a sequence of ASCII characters──this sentence, for example,
  13005.    is a string. Strings give your programs life by enabling them to
  13006.    communicate with the user. Nearly all programs──from our simple printf()
  13007.    statements to the sophisticated dialogues of complex interactive
  13008.    programs──use strings of one type or another.
  13009.  
  13010.    Unlike BASIC and Pascal, the C language has no built-in string-type
  13011.    variable. Instead, C uses the convention that a string is an array of type
  13012.    char whose final, or terminating, value is the special character '\0'──a
  13013.    one-byte zero value. Figure 9-1 on the following page illustrates such an
  13014.    array.
  13015.  
  13016.    We refer to this arrangement as a convention because nothing in C prevents
  13017.    you from handling strings in another manner. For example, you might store
  13018.    strings as arrays of short variables, using one byte to hold the character
  13019.    and the other to hold the character's attributes (more on this in Chapter
  13020.    13). Or you might store strings as a value length followed by length
  13021.    number of characters. However, because you will most often handle strings
  13022.    in the conventional way, we will emphasize that method in our discussion
  13023.    of strings.
  13024.  
  13025.    Address of bytes──  9876   9877  9878  9879  9880  9881  9882  9883
  13026.    in memory          ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
  13027.                       │ 'H' │ 'e' │ 'l' │ 'l' │ 'o' │'\n' │'\O' │     │
  13028.                       └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
  13029.                       │                             │        
  13030.                       └──────────────┬──────────────┘        │
  13031.                                      │                       │
  13032.                               ASCII characters        Terminating zero
  13033.  
  13034.    Figure 9-1. In C, a string is an array of type char terminated by a zero
  13035.    value.
  13036.  
  13037.  
  13038.  Declaring and Initializing Strings
  13039.  
  13040.    A string is merely an array of type char, and you initialize it the same
  13041.    way you would any other array. The following example fills the char array
  13042.    named phrase with ASCII character constants that spell "Hello" followed by
  13043.    the newline character:
  13044.  
  13045.      char phrase[] = {'H', 'e', 'l', 'l', 'o', '\n', '\0'};
  13046.  
  13047.    We made this array a conventional C string by adding a terminating zero
  13048.    value (the character constant '\0'). As with all arrays, string arrays can
  13049.    be initialized only if you use the keyword static or declare them
  13050.    globally──outside of all functions.
  13051.  
  13052.    The HELLO.C program (Listing 9-1) illustrates the proper way to
  13053.    initialize string arrays. It also demonstrates the printf() format command
  13054.    %s, which tells printf() to print the next argument as a string.
  13055.  
  13056.    Because zero-terminated char arrays so commonly represent strings in C,
  13057.    the language provides a built-in shorthand. When C finds text enclosed in
  13058.    full quotation marks (called string constants), it immediately stores that
  13059.    text as an array of type char and adds the terminating '\0'. This
  13060.    characteristic of C provides you an alternate way to initialize arrays.
  13061.  
  13062.    ──────────────────────────────────────────────────────────────────────────
  13063.    /* hello.c  --  legal ways to initialize strings as */
  13064.    /*              arrays of char values               */
  13065.  
  13066.    char Gphrase[] = {
  13067.        'H','e','l','l','o','\n','\0' };    /* global initialization */
  13068.  
  13069.    main()
  13070.    {
  13071.        static char gphrase[] = {
  13072.            'h','e','l','l','o','\n','\0' };    /* local initialization */
  13073.  
  13074.        printf("Global: %s", Gphrase);
  13075.        printf("Local:  %s", gphrase);
  13076.  
  13077.    }
  13078.    ──────────────────────────────────────────────────────────────────────────
  13079.  
  13080.    Listing 9-1.   The HELLO.C program.
  13081.  
  13082.    For example, you can create the same arrays as those declared in HELLO.C
  13083.    by substituting the following lines of code:
  13084.  
  13085.      char Gphrase[] = "Hello\n";────────────────────────Global initialization
  13086.  
  13087.      static char lphrase[] = "Hello\n";──────────────────Local initialization
  13088.  
  13089.    As an aid in declaring long string constants, the compiler combines
  13090.    adjacent quoted strings into a single string constant. This feature lets
  13091.    you easily initialize long strings, as in the following example:
  13092.  
  13093.      static char long_phrase[]  = "This is one long "
  13094.                                   "sentence that the compiler "
  13095.                                   "combines into a single string.";
  13096.  
  13097.    C uses the rule that if nothing but white space (spaces, tabs, or
  13098.    newlines) separates two quoted strings, those strings are concatenated to
  13099.    form a single string. Thus, the above QuickC declaration is equivalent to
  13100.    the following:
  13101.  
  13102.      static char long_phrase[]  =
  13103.      "This is one long sentence that the compiler combines into a single
  13104.      string.";
  13105.  
  13106.    Under pre-ANSI C, long string initializers can be emulated with the
  13107.    #define preprocessor directive. Recall that you can extend #define lines
  13108.    by ending each with a backslash and a newline character (that is, type \
  13109.    and press Enter). Because this #define technique is portable to all
  13110.    compilers, we will use it throughout the rest of the book:
  13111.  
  13112.      #define PHRASE \
  13113.      "This is one long sentence that the compiler \
  13114.      combines into a single string."
  13115.  
  13116.      static char long_phrase = PHRASE;
  13117.  
  13118.    ──────────────────────────────────────────────────────────────────────────
  13119.    A Constant Reminder
  13120.    When you declare string constants, remember that it is illegal for a
  13121.    newline character to appear anywhere between full quotation marks. The
  13122.    following example is illegal:
  13123.  
  13124.      static char long_phrase = "This is one
  13125.      long sentence that the...";
  13126.  
  13127.    and results in the following QuickC error message:
  13128.  
  13129.      error C2001:
  13130.      newline in constant
  13131.  
  13132.    If you want to insert a newline character into a string constant, use the
  13133.    escape sequence for a newline character (\n) instead:
  13134.  
  13135.      static char long_phrase[] = "This is one \n long sentence that the ..."
  13136.  
  13137.    ──────────────────────────────────────────────────────────────────────────
  13138.  
  13139.  
  13140.  The String Pool and String Addresses
  13141.  
  13142.    QuickC copies all of a program's quoted strings into a common area of
  13143.    memory called the string pool. They are copied there, one after the other,
  13144.    in the order that they occur in the program. (Figure 9-2 illustrates this
  13145.    process.)
  13146.  
  13147.    The STRPOOL.C program (Listing 9-2) dumps the contents of the string pool
  13148.    to your terminal screen. Note in STRPOOL.C that any char array that ends
  13149.    with a zero value, such as Cent_string, is placed into the string pool.
  13150.  
  13151.    We place nonprinting characters into quoted strings as we did with
  13152.    printf()──that is, a newline character, with \n; a carriage return, with
  13153.    \r; and a tab, with \t. Other special characters that you can place in
  13154.    string constants are the full quotation mark, with \"; the formfeed
  13155.    character, with \f; the backspace character, with \b; and the bell (beep)
  13156.    character, with \a.
  13157.  
  13158.    You can include any character from the PC's extended character set in a
  13159.    string constant by using a \x followed by a two-digit hexadecimal number.
  13160.    For example, \x9B is used to represent the ¢ character. (QuickC's General
  13161.    help screens include a handy table that lists these escape sequences.)
  13162.  
  13163.    Note also in the program that we assigned the address of a string to a
  13164.    pointer (cp = Start). Nowhere are pointers used more heavily than with
  13165.    strings.
  13166.  
  13167.              Your program                              String pool
  13168.    ┌────────────────────────────────┐     ┌─────┬─────┬─────┬─────┬─────┬─────
  13169.    │°char phrase [ ] = "Hello\n";───┼─────┼'H' │ 'e' │ 'l' │ 'l' │ 'o' │'\n'
  13170.    │°main ( )                      °│     ├─────┼─────┼─────┼─────┼─────┼─────
  13171.    │°{                             °│  ┌──┼'\O'─┼'T' │ 'y' │ 'p' │ 'e' │ ' '
  13172.    │°  printf("Type in a line of");─┼──┘  ├─────┼─────┼─────┼─────┼─────┼─────
  13173.    │°  printf(" text and I will");──┼──┐  │ 'i' │ 'n' │ ' ' │ 'a' │ ' ' │ 'l'
  13174.    │°  .                           °│  │  ├─────┼─────┼─────┼─────┼─────┼─────
  13175.    │°  .                           °│  │  │ 'i' │ 'n' │ 'e' │ ' ' │ 'o' │ 'f'
  13176.    │°  .                           °│  │  ├─────┼─────┼─────┼─────┼─────┼─────
  13177.    │°                              °│  └──┼'\O'─┼' ' │ 't' │ 'e' │ 'x' │ 't'
  13178.    │°                              °│     ├─────┼─────┼─────┼─────┼─────┼─────
  13179.    └────────────────────────────────┘     │ ' ' │ 'a' │ 'n' │ 'd' │ ' ' │ 'I'
  13180.                                           ├─────┼─────┼─────┼─────┼─────┼─────
  13181.                                           │ ' ' │ 'w' │ 'i' │ 'l' │ 'l' │'\O'
  13182.                                           ├─────┼─────┼─────┼─────┼─────┼─────
  13183.                                           |     |     |     |     |     |
  13184.                                           |     |     |     |     |     |
  13185.  
  13186.    Figure 9-2. Quoted string constants are placed one after the other into
  13187.    the string pool.
  13188.  
  13189.    ──────────────────────────────────────────────────────────────────────────
  13190.    /* strpool.c  -- dumps the string pool to show how    */
  13191.    /*               quoted strings are stored            */
  13192.  
  13193.    #define PHRASE \
  13194.    "This is one long sentence that the compiler \
  13195.    combines into a single string."
  13196.  
  13197.    char Start[]        = "start";
  13198.    char Long_phrase[]  = PHRASE;
  13199.    char Short_phrase[] = "This is a short phrase";
  13200.    char Cent_string[]  = "\x9B";
  13201.  
  13202.    main()
  13203.    {
  13204.        static char local_phrase[] = "This is local";
  13205.        char *cp;
  13206.  
  13207.        printf("Dump of the string pool:\n");
  13208.        printf("-----------------------\n");
  13209.  
  13210.        printf("\"");                /* print leading quote */
  13211.  
  13212.        /*
  13213.         * Note that the address of a string can be
  13214.         * assigned to a pointer: cp = Start
  13215.         */
  13216.        for (cp = Start; *cp != '^'; ++cp)
  13217.            {
  13218.            if (*cp == '\0')        /* print '\0' as a quote */
  13219.                printf("\"\n\"");
  13220.            else if (*cp == '\n' )  /* print '\n' as '\' 'n' */
  13221.                printf("\\n");
  13222.            else
  13223.                printf("%c", *cp);
  13224.            }
  13225.        printf("^");                /* marks end */
  13226.    }
  13227.    ──────────────────────────────────────────────────────────────────────────
  13228.  
  13229.    Listing 9-2.  The STRPOOL.C program.
  13230.  
  13231.  
  13232.  Pointers and Initialized Strings
  13233.  
  13234.    In the last chapter we assigned the address of an array to a pointer. We
  13235.    can also initialize a pointer to char with the address of a quoted string
  13236.    constant, as follows:
  13237.  
  13238.      char *str = "This is a phrase";
  13239.  
  13240.    This example initializes the char pointer *str to contain the address of
  13241.    the quoted string constant. Because the compiler places all string
  13242.    constants into the "string pool," the address in *str is that of the
  13243.    letter "T" (the first character of the char array) in the string pool.
  13244.  
  13245.    Recall that an array declaration creates an rvalue and a pointer
  13246.    declaration creates an lvalue. Consider the following declarations:
  13247.  
  13248.      char ary[] = "This is a phrase";
  13249.      char *str = "This is another";
  13250.  
  13251.    The ary[] declaration creates an rvalue (an address reference, such as a
  13252.    label) that cannot be changed with calculations.
  13253.  
  13254.    The *str declaration, on the other hand, creates an lvalue (a pointer
  13255.    variable whose value is an address), which can be changed with
  13256.    calculations. You can, for example, increment the pointer as follows:
  13257.  
  13258.      ++str;
  13259.  
  13260.    The distinction between lvalue and rvalue can be a confusing one for
  13261.    beginning C programmers. Remember that an array name (such as ary[]) is a
  13262.    fixed location and cannot be changed; a pointer (such as *str) is a
  13263.    variable and can be changed.
  13264.  
  13265.    The BIFFRED.C program (Listing 9-3) demonstrates that you can use
  13266.    pointers to manipulate strings in the string pool. Examine the program
  13267.    before you run it. Can you predict what it will do?
  13268.  
  13269.    ──────────────────────────────────────────────────────────────────────────
  13270.    /* biffred.c  --  strings in the string pool can be */
  13271.    /*                manipulated via pointers          */
  13272.  
  13273.    char Start[] = "start";
  13274.  
  13275.    main()
  13276.    {
  13277.        char *cp;
  13278.        int pass;
  13279.  
  13280.        for (pass = 0; pass < 2; ++pass)
  13281.            {
  13282.            printf("My name is FRED\n");
  13283.  
  13284.            cp = Start;
  13285.  
  13286.            while (*cp != 'F')
  13287.                ++cp;
  13288.  
  13289.            *cp   = 'B';
  13290.            *++cp = 'I';
  13291.            *++cp = 'F';
  13292.            *++cp = 'F';
  13293.            }
  13294.    }
  13295.    ──────────────────────────────────────────────────────────────────────────
  13296.  
  13297.    Listing 9-3.  The BIFFRED.C program.
  13298.  
  13299.  
  13300.  Formatting Strings with printf()
  13301.  
  13302.    So far, we've used printf() to print and format numbers (int with %d and
  13303.    float with %f, for example), individual characters with %c, and quoted
  13304.    strings with %s. The ability of printf() to print strings, however, goes
  13305.    far beyond the mere echoing of quoted string constants. In the following
  13306.    example:
  13307.  
  13308.      printf("%s\n", ary);
  13309.  
  13310.    the expression ary can be the address of any char type array that ends
  13311.    with the character constant value '\0'. It can be a quoted string constant
  13312.    such as
  13313.  
  13314.      printf("%s\n", "This is a phrase");
  13315.  
  13316.    or the address of a string from either a char array or a value in a
  13317.    pointer, as in the following examples:
  13318.  
  13319.      char *str, ary[] = "This is a phrase";
  13320.  
  13321.      str = ary;
  13322.  
  13323.      printf("%s\n", ary);─────────────────────────────────Address of an array
  13324.      printf("%s\n", str);──────────────────────────────────Value in a pointer
  13325.  
  13326.    Because all quoted strings are placed into the string pool and replaced
  13327.    with their starting address in that string pool, it follows that the
  13328.    format specification in the control string of this example:
  13329.  
  13330.      printf("%s\n", str);
  13331.             └──┬─┘
  13332.                └────────────────────────────────────────────── Control string
  13333.  
  13334.    can also be expressed as either an array address or the value in a
  13335.    pointer, as follows:
  13336.  
  13337.      char *str, ary[] = "This is a phrase.";
  13338.      char *cp,  ctl[] = "%s\n";
  13339.  
  13340.      str = ary;
  13341.      cp  = ctl;
  13342.  
  13343.      printf(ctl, ary);────────────────────────────────────Addresses of arrays
  13344.      printf(cp, str);──────────────────────────────────────────Pointer values
  13345.      printf(ctl, str);─────────────────────────────────────Mixture of the two
  13346.  
  13347.    The CONTROL.C program (Listing 9-4 on the following page) demonstrates
  13348.    this equivalence. This program asks you to type either an l or an r, and
  13349.    then it prints out a string with the corresponding left or right
  13350.    justification.
  13351.  
  13352.    CONTROL.C lets you see how the printf() format specifier %s is used to
  13353.    format strings. The various options you can use with %s are summarized in
  13354.    Table 9-1 on the following page. You can also combine them as in the
  13355.    following statement, which prints the first four letters of computer
  13356.    right-justified in a 25-character field.
  13357.  
  13358.      printf("%25.4s\n", "computer");
  13359.  
  13360.    ──────────────────────────────────────────────────────────────────────────
  13361.    /* control.c  --  demonstrates string justification */
  13362.    /*                using printf()                   */
  13363.  
  13364.    char Some_text[] = "Some Text";
  13365.    char Left_control[] =    "<<%-15s>>";
  13366.    char Right_control[] =    "<<%15s>>";
  13367.  
  13368.    main()
  13369.    {
  13370.        char ch;
  13371.  
  13372.        while (1)
  13373.            {
  13374.            printf("Select l)eft r)ight or q)uit: ");
  13375.            ch = getch();
  13376.            putch(ch);
  13377.  
  13378.            printf("\n\n");
  13379.            switch((int) ch)
  13380.                {
  13381.                case 'l':
  13382.                case 'L':
  13383.                    printf(Left_control, Some_text);
  13384.                    break;
  13385.                case 'r':
  13386.                case 'R':
  13387.                    printf(Right_control, Some_text);
  13388.                    break;
  13389.                case 'q':
  13390.                case 'Q':
  13391.                    exit (0);
  13392.                default:
  13393.                    printf("Huh?");
  13394.                    break;
  13395.                }
  13396.            printf("\n\n");
  13397.            }
  13398.    }
  13399.    ──────────────────────────────────────────────────────────────────────────
  13400.  
  13401.    Listing 9-4.  The CONTROL.C program.
  13402.  
  13403.    Note: In these format specifiers, num must be a decimal integer. You can
  13404.    combine the last option, %.nums, with any of the others, producing, for
  13405.    example, %25.5s.
  13406.  
  13407.    Table 9-1 Variations of the printf() %s Specifier
  13408.    ──────────────────────────────────────────────────────────────────────────
  13409.    %s          Prints the string exactly as it is
  13410.    %nums       Prints the string right-justified in a field of width num
  13411.    %-nums      Prints the string left-justified in a field of width num
  13412.    %.nums      Prints num characters of string
  13413.    ──────────────────────────────────────────────────────────────────────────
  13414.  
  13415.  
  13416.  String Input and Output
  13417.  
  13418.    The standard C Library contains several functions specifically designed to
  13419.    facilitate input and output of strings. Here we discuss some that read
  13420.    from your keyboard or print to your screen. The next chapter ("Managing
  13421.    Files") deals with file-handling counterparts to these functions. In
  13422.    Chapter 13, we will present additional routines that directly access the
  13423.    keyboard and screen hardware.
  13424.  
  13425.  String Input with scanf()
  13426.  
  13427.    We've already used scanf() several times: Now let's discuss it in detail.
  13428.    The scanf() function uses the same % specifiers that printf() does, but it
  13429.    uses them to read values, not to print them. Unfortunately, scanf()
  13430.    handles strings a little differently than does printf(). Where printf()
  13431.    prints the entire string to a terminating '\0', scanf() reads only
  13432.    space-delimited words of text. That is, for each %s in its control string,
  13433.    scanf() reads all characters up to, but not including, space, tab, or
  13434.    newline. Therefore, scanf() is best used for reading words rather than
  13435.    lines of text.
  13436.  
  13437.    The scanf() routine, when used with %s to read words of text, takes the
  13438.    form
  13439.  
  13440.      scanf("%s", buf);
  13441.  
  13442.    where buf is the address of a char array (buffer) into which scanf()
  13443.    places the text it reads from the keyboard. The array buf can be either a
  13444.    char array or a pointer to memory created by malloc(). (Note that you do
  13445.    not need to use an ampersand with an array name.) The scanf() function
  13446.    appends a terminating '\0' to the text in buf.
  13447.  
  13448.    The short SCANLINE.C program (Listing 9-5 on the following page)
  13449.    illustrates a simple way to use scanf() for reading words of text from the
  13450.    keyboard. It asks you to type in a line of text and then uses scanf() to
  13451.    print the words of that text, one word per line.
  13452.  
  13453.    When you run SCANLINE.C, notice that it prints nothing until you press the
  13454.    Enter key. This is because scanf() is a "buffered I/O" routine. It reads
  13455.    from the standard input (the keyboard), but it "sees" nothing until you
  13456.    "flush the standard input buffer" by pressing the Enter key. (We discuss
  13457.    this concept of buffered versus unbuffered I/O in the next chapter.)
  13458.  
  13459.    The scanf() function provides two variations for the %s specifier. (See
  13460.    Table 9-2.) These let you read more than individual words.
  13461.  
  13462.    Table 9-2 Variations of the scanf() %s Specifier
  13463.    ──────────────────────────────────────────────────────────────────────────
  13464.    %nums       Reads num characters including space, tab, or newline
  13465.                characters (Specify num as a decimal integer.)
  13466.    %[range]    Reads a specified range of characters
  13467.    ──────────────────────────────────────────────────────────────────────────
  13468.  
  13469.    ──────────────────────────────────────────────────────────────────────────
  13470.    /* scanline.c  -- demonstrates how scanf() reads  */
  13471.    /*                the individual words of a line  */
  13472.  
  13473.    #define INTRO \
  13474.    "Type in lines of text. They will be printed out\n\
  13475.    one word per line, thus demonstrating scanf().\n\
  13476.    (Type Ctrl-Z to Quit)\n"
  13477.  
  13478.    main()
  13479.    {
  13480.        char buf[512];    /* should be big enough */
  13481.  
  13482.        printf(INTRO);
  13483.  
  13484.        /*
  13485.         * scanf() returns the number of items
  13486.         * its control string matched
  13487.         */
  13488.        while (scanf("%s", buf) == 1)
  13489.            {
  13490.            printf("%s\n", buf);
  13491.            }
  13492.  
  13493.    }
  13494.    ──────────────────────────────────────────────────────────────────────────
  13495.  
  13496.    Listing 9-5.  The SCANLINE.C program.
  13497.  
  13498.    The following example reads 127 characters from the keyboard and places
  13499.    them into the array buf:
  13500.  
  13501.      char buf[128];
  13502.  
  13503.      scanf("%127s", buf);──────────────────────────────────────────%nums form
  13504.      buf[127] = '\0';
  13505.  
  13506.    This form of scanf() has two disadvantages. First, because newline
  13507.    characters can be read into buf, you can't easily tell whether buf
  13508.    contains a complete line or a partial line or a number of lines. Second,
  13509.    because this form does not append a terminating '\0' to the text, you must
  13510.    add it yourself.
  13511.  
  13512.    For better control, use the more complex scanf() %[range] directive. Here
  13513.    range is any list of characters that you want to include in buf. The
  13514.    following example:
  13515.  
  13516.      scanf("%[0123456789]", buf);
  13517.  
  13518.    reads in only the digits 0 through 9. Anything else causes scanf() to stop
  13519.    reading and terminate buf with a '\0'.
  13520.  
  13521.    A more useful variation of the %[range] directive can be constructed using
  13522.    the ^ character. When you use a ^ as the first character in range, scanf()
  13523.    reads all characters up to, but not including, any characters in range and
  13524.    stops reading at the first excluded character. This version of scanf()
  13525.    also appends a terminating '\0' to the characters it reads. The following
  13526.    example shows how to use this variation:
  13527.  
  13528.      scanf("%[^\n]", buf);─────────────────────────────Read all but a newline
  13529.      scanf("%[\n]", dummy);───────────────────────────────Read only a newline
  13530.  
  13531.    The first line tells scanf() to read all characters up to, but not
  13532.    including, the newline character and to place those characters into buf.
  13533.    The second line tells scanf() to read only a newline character (the one
  13534.    that terminated the first scanf()) and to place it into dummy. The scanf()
  13535.    function can be tricky to use (witness the need for the second statement),
  13536.    but with practice, you will find it a valuable and powerful programming
  13537.    tool.
  13538.  
  13539.    The SCRANGE.C program (Listing 9-6) summarizes the scanf() function. It
  13540.    prompts for, and reads in, several lines of text, displaying exactly what
  13541.    scanf() reads as it executes.
  13542.  
  13543.    ──────────────────────────────────────────────────────────────────────────
  13544.    /* scrange.c  --  illustrates scanf()'s control */
  13545.    /*                directives                    */
  13546.  
  13547.    main()
  13548.    {
  13549.        char buf[512],    /* should be big enough */
  13550.             dummy[2];    /* for \n and \0        */
  13551.        int  num;
  13552.  
  13553.        do
  13554.            {
  13555.            printf("Running:\n");
  13556.            printf("\tscanf(\"%%d\", &num);\n");
  13557.            printf("\tscanf(\"%%[^\\n]\", buf);\n");
  13558.            printf("\tscanf(\"%%[\\n]\", dummy);\n");
  13559.  
  13560.            printf("\nType enough to satisfy this:\n");
  13561.            printf("(Set num equal to zero to quit)\n");
  13562.  
  13563.            scanf("%d", &num);
  13564.            scanf("%[^\n]", buf);
  13565.            scanf("%[\n]", dummy);
  13566.  
  13567.            printf("\n\tnum = %d\n", num);
  13568.            printf("\tbuf[] = \"%s\"\n", buf);
  13569.            printf("\n\n");
  13570.  
  13571.            } while (num != 0) ;
  13572.  
  13573.    }
  13574.    ──────────────────────────────────────────────────────────────────────────
  13575.  
  13576.    Listing 9-6.  The SCRANGE.C program.
  13577.  
  13578.  Lines of Text with gets() and puts()
  13579.  
  13580.    Although we can use variations of scanf() to read lines of text, the
  13581.    QuickC library contains a pair of routines specifically tailored for
  13582.    reading and writing strings as lines of text. A line of text, in this
  13583.    case, is any string that includes a terminating newline. This is the most
  13584.    natural form of text entry because it corresponds to a line of text on the
  13585.    screen.
  13586.  
  13587.    Although the newline, '\n', is used throughout C to represent the end of a
  13588.    line of text, it does not correspond to the characters produced or
  13589.    expected by your hardware. The Enter key, for example, actually produces
  13590.    the '\r' character. And printing a '\n' to your screen moves the cursor
  13591.    down but not to the left on the screen. Fortunately, scanf() and gets()
  13592.    convert an Enter keypress ('\r') to a newline ('\n'), and both printf()
  13593.    and puts() convert a newline ('\n') into a carriage return/linefeed
  13594.    combination ('\r' '\n') when writing to your screen.
  13595.  
  13596.    The gets() (pronounced "get s") function reads all typed characters up to
  13597.    and including a newline (generated when you press Enter) and places those
  13598.    characters into a char array. The newline is then replaced with a '\0' to
  13599.    form a C string. The puts() (pronounced "put s") function prints a string
  13600.    on the screen and adds a newline to the end.
  13601.  
  13602.    The DIALOG.C program (Listing 9-7) uses gets(), puts(), and printf() to
  13603.    carry on a simple conversation. Note that because the gets() function
  13604.    returns NULL if it fails, we must use the directive #include <stdio.h> to
  13605.    incorporate the definition of NULL.
  13606.  
  13607.    ──────────────────────────────────────────────────────────────────────────
  13608.    /* dialog.c  -- a conversation using gets() and puts()  */
  13609.  
  13610.    #include <stdio.h>        /* for NULL and BUFSIZ */
  13611.  
  13612.    #define THE_QUESTION \
  13613.    "And what is your view on the current price of corn\n\
  13614.    and the stability of our trade import balance?"
  13615.  
  13616.    main()
  13617.    {
  13618.        char name[BUFSIZ],
  13619.             buf[BUFSIZ];
  13620.        extern char *gets();
  13621.  
  13622.        name[0] = '\0';        /* clear the name */
  13623.  
  13624.        puts("\n\nHi there. And what is your name?");
  13625.  
  13626.        if (gets(name) != NULL && name[0] != '\')
  13627.            {
  13628.            printf("\nPleased to meet you, %s.\n", name);
  13629.            puts(THE_QUESTION);
  13630.            /*
  13631.             * force an extra <enter> before replying
  13632.             */
  13633.            do
  13634.                {
  13635.                if (gets(buf) == NULL)
  13636.                    break;
  13637.  
  13638.                } while (*buf != '\0');        /* wait for empty line */
  13639.  
  13640.            puts("Sorry. I needed to think about that.");
  13641.            printf("Nice talking to you, %s.\n", name);
  13642.            }
  13643.        else
  13644.            puts("How rude!");
  13645.  
  13646.        puts("Goodbye.");
  13647.    }
  13648.    ──────────────────────────────────────────────────────────────────────────
  13649.  
  13650.    Listing 9-7.  The DIALOG.C program.
  13651.  
  13652.  
  13653.  String Manipulation Routines
  13654.  
  13655.    As you can see, the string I/O routines in DIALOG.C are not very
  13656.    sophisticated. Fortunately, the QuickC library contains a host of
  13657.    functions that permit more complex string manipulations. We won't describe
  13658.    all of the functions here──each has its own page in the Microsoft QuickC
  13659.    Run-Time Library Reference──but we do list many of them in Table 9-3 on
  13660.    page 279. We will, however, use many of these functions in one large
  13661.    program and then discuss those selected string-handling routines.
  13662.  
  13663.    The ACME.C program (Listing 9-8) asks the user to fill out an employment
  13664.    application for a fictional company. It isn't particularly user friendly,
  13665.    and it terminates if you type something it can't understand.
  13666.  
  13667.    ──────────────────────────────────────────────────────────────────────────
  13668.    /* acme.c  --     illustrates an assortment of the    */
  13669.    /*                C library string-handling routines  */
  13670.  
  13671.    #include <stdio.h>        /* for NULL */
  13672.    #include <string.h>        /* for strchr(), et al */
  13673.  
  13674.    #define NAME_PATTERN \
  13675.    "first<space>last  or\n\
  13676.    first<space>middle<space>last"
  13677.  
  13678.    #define ADDRESS_PATTERN \
  13679.    "number<space>street<comma><space>city"
  13680.  
  13681.    char Buf[BUFSIZ];        /* global I/O buffer */
  13682.    main()
  13683.    {
  13684.        char *ocp, *cp, *first, *last, *street, *city;
  13685.        void Prompt(), Cant();
  13686.  
  13687.        printf("Acme Employment Questionnaire\n");
  13688.  
  13689.        /*
  13690.         * Expect first<space>last or
  13691.         *        first<space>middle<space>last
  13692.         */
  13693.        Prompt("Full Name");
  13694.  
  13695.         /* search forward for a space */
  13696.        if ((cp = strchr(Buf,' ')) == NULL)
  13697.            Cant("First Name", NAME_PATTERN);
  13698.        *cp = '\0';
  13699.        first = strdup(Buf);
  13700.        *cp = ' ';
  13701.  
  13702.         /* search back from end for a space */
  13703.        if ((cp = strchr(Buf,' ')) == NULL)
  13704.            Cant("Last Name", NAME_PATTERN);
  13705.        last = strdup(++cp);
  13706.  
  13707.        /*
  13708.         * Expect number<space>street<comma><space>city<comma>
  13709.         */
  13710.        Prompt("Full Address");
  13711.  
  13712.         /* search forward for a comma */
  13713.        if ((cp = strchr(Buf,',')) == NULL)
  13714.            Cant("Street", ADDRESS_PATTERN);
  13715.        *cp = '\0';
  13716.        street = strdup(Buf);
  13717.  
  13718.         /* Search forward from last comma for next comma */
  13719.        if ((ocp = strchr(++cp,',')) == NULL)
  13720.            Cant("City", ADDRESS_PATTERN);
  13721.        *ocp = '\0';
  13722.        city = strdup(++cp);
  13723.  
  13724.        printf("\n\nYou Entered:\n");
  13725.        printf("\tFirst Name: \"%s\"\n", first);
  13726.        printf("\tLast Name:  \"%s\"\n", last);
  13727.        printf("\tStreet:     \"%s\"\n", street);
  13728.        printf("\tCity:       \"%s\"\n", city);
  13729.  
  13730.    }
  13731.  
  13732.    void Cant(char *what, char *pattern)
  13733.    {
  13734.        printf("\n\n\bFormat Error!!!\n");
  13735.        printf("Can't parse your %s.\n", what);
  13736.        printf("Expected an entry of the form:\n\n");
  13737.        printf("%s\n\nAborted\n", pattern);
  13738.        exit(1);
  13739.    }
  13740.  
  13741.    void Prompt(char *str)
  13742.    {
  13743.        while (1)
  13744.            {
  13745.            printf("\n%s: ", str );
  13746.            if (gets(Buf) == NULL || *Buf == '\0')
  13747.                {
  13748.                printf("Do you wish to quit? ");
  13749.                if (gets(Buf) == NULL || *Buf == 'y')
  13750.                    exit (0);
  13751.                continue;
  13752.                }
  13753.            break;
  13754.            }
  13755.    }
  13756.    ──────────────────────────────────────────────────────────────────────────
  13757.  
  13758.    Listing 9-8.  The ACME.C program.
  13759.  
  13760.  The strchr() String Function
  13761.  
  13762.    The first new function in ACME.C is strchr() (for "string character").
  13763.    This routine requires two arguments──a string to search and a character to
  13764.    look for in that string:
  13765.  
  13766.      strchr(Buf, ' ')
  13767.              └────┴────────────────────── Search string for a space character
  13768.  
  13769.    If strchr() finds the character in the string, it returns the address of
  13770.    that character. If it doesn't find the character, it returns NULL. Thus,
  13771.    we can handle the error as follows if the character is not in the string:
  13772.  
  13773.                        ┌────┬─────────────── Search Buf for a space character
  13774.      if ((cp = strchr(Buf, ' ')) == NULL)
  13775.            └──────────────────────────┼───────────────────────── Save address
  13776.                                       └─────────────── Then test for an error
  13777.  
  13778.    In the example, cp is a pointer to char into which we assign the address
  13779.    returned by strchr(). If the result of that assignment (the value of cp)
  13780.    is NULL, the string Buf contains no space character.
  13781.  
  13782.    Because strchr() returns the address of a string, you must either declare
  13783.    it in your program as char *strchr(); or use the statement #include
  13784.    <string.h> (as we did in ACME.C), to supply the declaration for strchr().
  13785.  
  13786.  The strdup() String Function
  13787.  
  13788.    The second new function in ACME.C is strdup(). This is a Microsoft QuickC
  13789.    function that does not exist in other C libraries. When passed a string,
  13790.    strdup() makes a copy of that string and returns the address of the copy.
  13791.    Because this type of "string duplication" is not portable, we'll show you
  13792.    a version (Listing 9-9) that is. The implementation of this portable
  13793.    version of strdup() introduces two new string-handling functions, strlen()
  13794.    and strcpy().
  13795.  
  13796.    ──────────────────────────────────────────────────────────────────────────
  13797.    #include <stdio.h>  /* for NULL  */
  13798.    #include <malloc.h> /* malloc    */
  13799.  
  13800.    char *
  13801.    strdup(str)
  13802.    char *str;
  13803.    {
  13804.        char *newstr;
  13805.        int  bytes;
  13806.  
  13807.        bytes = strlen(str);
  13808.        if ((newstr = malloc(bytes + 1)) == NULL)
  13809.            return (NULL);
  13810.    88     (void)strcpy(newstr, str);
  13811.        return (newstr);
  13812.    }
  13813.    ──────────────────────────────────────────────────────────────────────────
  13814.  
  13815.    Listing 9-9.  The strdup() function.
  13816.  
  13817.  The strlen() String Function
  13818.  
  13819.    The strlen() function counts the number of characters in a string
  13820.    (excluding the terminating '\0') and returns that count. For example, the
  13821.    assignments
  13822.  
  13823.      static char word[] = "Biff";
  13824.  
  13825.      bytes = strlen(word);
  13826.  
  13827.    cause bytes to be assigned the value 4 because the string word contains
  13828.    four letters.
  13829.  
  13830.  The strcpy() String Function
  13831.  
  13832.    The strcpy() function copies its second argument (a string) into its
  13833.    first, a buffer large enough to hold that copy. The value returned by
  13834.    strcpy() is the address of its first argument. Because we wanted to ignore
  13835.    that return value in our version of strdup(), we typecast the call as type
  13836.    void:
  13837.  
  13838.      if ((newstr = malloc(bytes + 1)) == NULL)
  13839.           return (NULL);
  13840.      (void)strcpy(newstr, str);
  13841.  
  13842.    To create the space for the copy, we call malloc() with an argument of
  13843.    bytes + 1, which creates room for both the copy of the string and the
  13844.    appended terminating '\0'. (Remember strlen(), which gave us the value in
  13845.    bytes, does not count the terminating '\0'.)
  13846.  
  13847.    Table 9-3 QuickC Library String Manipulation Functions
  13848.    ──────────────────────────────────────────────────────────────────────────
  13849.    strlen(str)          Returns the length of a string str, not counting the
  13850.                         terminating '\0'
  13851.    strcat(s1, s2)       Concatenates the second string (s2) to the end of the
  13852.                         first (s2)
  13853.    strcmp(s1, s2)       Compares two strings (s1 and s2); returns 0 if they
  13854.                         are the same, otherwise returns the arithmetic
  13855.                         difference of the first two nonmatching characters
  13856.    stricmp(s1, s2)      Compares two strings without regard to case
  13857.    strncmp(s1, s2, n)   Compares n characters in the two strings (s1 and s2)
  13858.    strcpy(buf, str)     Copies a string (str) into a char buffer buf, which
  13859.                         must be large enough to hold both the string and its
  13860.                         terminating '\0'
  13861.    strncpy(buf, str, n) Copies n characters of the string str into the buffer
  13862.                         buf
  13863.    strchr(str, ch)      Finds a character (ch) in a string (str); returns the
  13864.                         address of ch if found, otherwise returns NULL
  13865.    strcspn(s1, s2)      Finds a substring in s1 that begins with anything
  13866.                         other than one of the characters in s2; returns the
  13867.                         address of that substring if found, otherwise returns
  13868.                         NULL
  13869.    strstr(s1, s2)       Finds the first occurrence of the substring s1 in the
  13870.                         larger string s2; returns the address of that
  13871.                         substring if found, otherwise returns NULL
  13872.    strrev(str)          Reverses the characters in the string str; returns
  13873.                         the address of that reversed string
  13874.    strupr(str)          Converts a string (str) to uppercase characters
  13875.    strset(str, ch)      Clears a string (str), converting all its characters
  13876.                         to the character ch
  13877.    strdup(str)          Duplicates a string (str), returning the address of
  13878.                         the new copy
  13879.    sprintf(str, cntl,   Formatted print into a string (str), converting args
  13880.    args,...)            based on the control string cntl
  13881.    sscanf(str, cntl,    Formatted convert, like scanf(), but converts from
  13882.    addrs,...)           the string rather than from the keyboard
  13883.    ──────────────────────────────────────────────────────────────────────────
  13884.  
  13885.    You should be aware that although stricmp(), strcspn(), and strupr() are
  13886.    supplied with the Microsoft QuickC library, they are not a part of ANSI C.
  13887.    Do not use them if you want your programs to be portable to other
  13888.    compilers and computers.
  13889.  
  13890.  C vs BASIC String Functions
  13891.  
  13892.    As you have seen, sophisticated C string handling can require complicated
  13893.    programming. Although the C library string-handling routines can emulate
  13894.    much of BASIC, the following example demonstrates that such emulation is
  13895.    usually less straightforward:
  13896.  
  13897.      A$ = B$────────────────────────────────────────────────────────────BASIC
  13898.      first = strdup(Buf);───────────────────────────────────────────────────C
  13899.  
  13900.    Some functions common to BASIC are missing from C. Among them are LEFT$,
  13901.    MID$, and RIGHT$. Listing 9-10 shows a C version of LEFT$. We leave it as
  13902.    an exercise for you to write C versions of the other two BASIC commands.
  13903.  
  13904.    C offers two principal advantages over BASIC──it permits the programmer to
  13905.    extend string-handling library routines with customized routines, and it
  13906.    allows easy access to strings from pointers.
  13907.  
  13908.    ──────────────────────────────────────────────────────────────────────────
  13909.    #include <stdio.h>   /* for NULL     */
  13910.    #include <string.h>  /* for strdup() */
  13911.  
  13912.    char *
  13913.    leftstr(str, cnt)
  13914.    char *str;
  13915.    int  cnt;
  13916.    {
  13917.        char *cp;
  13918.  
  13919.        if (strlen(str) < cnt || cnt <= 0)
  13920.            return (NULL);
  13921.        if (strlen(str) == cnt)
  13922.            return (strdup(str));
  13923.        cp = strdup(str);
  13924.        cp[cnt - 1] = '0';
  13925.        return (cp);
  13926.    }
  13927.    ──────────────────────────────────────────────────────────────────────────
  13928.  
  13929.    Listing 9-10.  The leftstr() function.
  13930.  
  13931.  
  13932.  Arrays and Strings
  13933.  
  13934.    Because a string is nothing more than an array of type char, you can use a
  13935.    two-dimensional array of type char as an array of strings. However, you
  13936.    must be sure to terminate each row (string) with a '\0' character, as
  13937.    follows:
  13938.  
  13939.      char names[3][6] = {
  13940.              { 'J','o','e','\0' },
  13941.              { 'D','u','k','e','\0' },
  13942.              { 'O','z','z','i','e','\0' }
  13943.      };
  13944.  
  13945.    You also can take the easier route of using string constants (quoted
  13946.    strings) as array initializers:
  13947.  
  13948.      char names[3][6] = { "Joe", "Duke", "Ozzie" };
  13949.  
  13950.    Both forms create identical arrays, as illustrated in Figure 9-3. Also
  13951.    notice that underinitializing rows sets the trailing characters in rows 0
  13952.    and 1 to '\0'.
  13953.  
  13954.         char names [3] [6] = {"Joe", "Duke", "Ozzie"};
  13955.  
  13956.                                    Columns
  13957.                                       │
  13958.               ┌───────────────────────┴───────────────────────┐
  13959.               │                                      ┌────────┼─┐
  13960.             ┌─┌───────┬───────┬───────┬───────┬──────┬───────┐ │
  13961.             │ │  'J'  │  'o'  │  'e'  │  '\O' │  '\O' │  '\O' ─┼─ Auto-initia
  13962.             │ ├───────┼───────┼───────┼──────┼───────┼───────┤ │  trailing ze
  13963.    Rows of ─┤ │  'D'  │  'u'  │  'k'  ││ 'e'  │  '\O' │  '\O' ─┘
  13964.    strings  │ ├───────┼───────┼───────┼┼──────┼──────┼───────┤
  13965.             │ │  'O'  │  'z'  │  'z'  ││ 'i'  ││ 'e'  │  '\O' │
  13966.             └─└───────┴───────┴───────┴┼──────┴┼──────┴──────┘
  13967.                                        │       │       │
  13968.                                        └───────┴───────┴────────── String-
  13969.                                                                    terminating
  13970.                                                                    zeros
  13971.  
  13972.    Figure 9-3. A two-dimensional array of char values as an array of strings.
  13973.  
  13974.    As we've already seen, strings can be easily manipulated by pointers.
  13975.    Because of this, arrays of pointers to strings are often used in place of
  13976.    the two-dimensional arrays of char. The previous sample arrays, declared
  13977.    and initialized as an array of pointers, appear as follows:
  13978.  
  13979.      char *names[3] = { "Joe", "Duke", "Ozzie" };
  13980.               └──────────────────────────────────────────── Array of pointers
  13981.  
  13982.    This pointer form also uses storage space more efficiently than the
  13983.    two-dimensional array. Compare the memory use of this form, depicted in
  13984.    Figure 9-4, with that of the preceding approach (shown in Figure 9-3).
  13985.  
  13986.       ┌──────────┐       ┌───────┬───────┬───────┬───────┐
  13987.       │          │──────│  'J'  │  'o'  │  'e'  │  '\O' │
  13988.       ├──────────┤       ├───────┼───────┼───────┼───────┼───────┐
  13989.       │          │──────│  'D'  │  'u'  │  'k'  │  'e'  │  '\O' │
  13990.       ├──────────┤       ├───────┼───────┼───────┼───────┼───────┼───────┐
  13991.       │          │──────│  'O'  │  'z'  │  'z'  │  'i'  │  'e'  │  '\O' │
  13992.       └──────────┘       └───────┴───────┴───────┴───────┴───────┴───────┘
  13993.       └─────┬────┘
  13994.             │
  13995.    Array of 3 pointers
  13996.             │
  13997.      ┌──────┴─────┐
  13998.      char *names[3] = {"Joe", "Duke", "Ozzie"};
  13999.  
  14000.    Figure 9-4. Arrays of pointers to strings use memory efficiently.
  14001.  
  14002.    The L2WORDS.C program (Listing 9-11) illustrates one application for an
  14003.    array of pointers to strings. It asks you to enter a line of text, then it
  14004.    breaks that line into individual words and returns an array of pointers to
  14005.    the substrings that form those words. Line2words() assumes that spaces
  14006.    separate words, but it can take multiple words as a single word if you
  14007.    surround them with full quotation marks. A routine like Line2words() is
  14008.    useful for writing your own command-line interpreter (COMMAND.COM).
  14009.  
  14010.    ──────────────────────────────────────────────────────────────────────────
  14011.    /* l2words.c  --  employs an array of pointers to  */
  14012.    /*                strings to break a line of text  */
  14013.    /*                into its component words         */
  14014.  
  14015.    #include <stdio.h>        /* for NULL and BUFSIZ */
  14016.  
  14017.    main()
  14018.    {
  14019.        char **Line2words();    /* declare function type */
  14020.        char **list;            /* pointer to pointer    */
  14021.        char buf[BUFSIZ];       /* buffer for input      */
  14022.        int  count, i, quote_flag;
  14023.  
  14024.        printf("Enter a line of text and I will break\n");
  14025.        printf("it up for you.\n");
  14026.  
  14027.        if (gets(buf) == NULL)
  14028.            exit(1);
  14029.  
  14030.        list = Line2words(buf, &count);
  14031.  
  14032.        for (i = 0; i < count; i++)
  14033.            {
  14034.            quote_flag = 0;
  14035.            printf("<");
  14036.            if (list[i] != buf)
  14037.                {
  14038.                if( list[i][-1] == '"')    /* negative subscript */
  14039.                    {
  14040.                    ++quote_flag;
  14041.                    printf("\"");
  14042.                    }
  14043.                }
  14044.            printf("%s", list[i]);
  14045.  
  14046.            if (quote_flag)
  14047.                printf("\"");
  14048.  
  14049.            printf(">\n");
  14050.            }
  14051.    }
  14052.    #define MAXW 64
  14053.  
  14054.    char **Line2words(char *line, int  *count)
  14055.    {
  14056.        static char *words[MAXW];
  14057.        int  index;
  14058.  
  14059.        index = 0;        /* zero internal index */
  14060.  
  14061.        while (*line != '\0')
  14062.            {
  14063.            /* turn spaces and tabs into zeros */
  14064.            if (*line == ' ' || *line == '\t')
  14065.                {
  14066.                *(line++) = '\0';
  14067.                continue;
  14068.                }
  14069.            words[index] = line++;    /* found a word */
  14070.  
  14071.            /* is it quoted? */
  14072.            if ( *(words[index]) == '"')
  14073.                {
  14074.                /* Yes, advance pointer to just past quote. */
  14075.                ++words[index];
  14076.  
  14077.                /* find next quote. */
  14078.                while (*line && *line != '"')
  14079.                    {
  14080.                    ++line;
  14081.                    }
  14082.  
  14083.                /* and turn it into a '\0'. */
  14084.                if (*line)
  14085.                    *(line++) = '\0';
  14086.                }
  14087.            else
  14088.                {
  14089.                /* otherwise skip to next space */
  14090.                while (*line && *line != ' ' && *line != '\t')
  14091.                    {
  14092.                    ++line;
  14093.                    }
  14094.                }
  14095.            if (++index == MAXW)
  14096.                break;
  14097.            }
  14098.        *count = index;        /* set count via pointer   */
  14099.        return (words);        /* return address of array */
  14100.    }
  14101.    ──────────────────────────────────────────────────────────────────────────
  14102.  
  14103.    Listing 9-11.  The L2WORDS.C program.
  14104.  
  14105.    L2WORDS.C does a few tricky things: First, notice that we declare the
  14106.    function Line2words() as char **. This means that it returns a pointer to
  14107.    a pointer. That pointer contains the address of the first element of our
  14108.    array of pointers. The first element in that array points to the first
  14109.    word.
  14110.  
  14111.    Second, notice that when the program prints words, it checks lines[i][-1]
  14112.    (negative subscripting) to see if the string has full quotation marks
  14113.    around it. If it does, the program replaces them when it prints the word.
  14114.  
  14115.  
  14116.  The Arguments to main()──argv and argc
  14117.  
  14118.    When you run a program from the command interpreter (COMMAND.COM under
  14119.    MS-DOS, or sh or csh under UNIX), you can specify arguments for the
  14120.    program on the command line. For example, when you run QuickC by typing
  14121.  
  14122.      C> qc file.c
  14123.  
  14124.    QuickC starts with the file named file.c already loaded. All C programs,
  14125.    including QuickC, retrieve arguments from the command line in the same
  14126.    way. That is, every C program begins execution with the function named
  14127.    main(), and that function, like any other, can receive arguments.
  14128.    Traditionally called argc and argv, these arguments are received by main()
  14129.    as follows:
  14130.  
  14131.      main(argc, argv)
  14132.      int argc;
  14133.      char *argv[];
  14134.  
  14135.    These arguments to main() contain all the information that you need to
  14136.    access the command-line arguments: argc is the number of command-line
  14137.    arguments, and argv is an array of pointers to those arguments.
  14138.  
  14139.    The SHOWARGS.C program (Listing 9-12) shows how to access and use the
  14140.    arguments passed to main(). To run this program from within QuickC, you
  14141.    must first set the command-line arguments with Set Runtime Options on the
  14142.    Run menu.
  14143.  
  14144.    When you run SHOWARGS.C with the following command-line preset in the Set
  14145.    Runtime Options dialog box:
  14146.  
  14147.      kit makes lovely paper
  14148.  
  14149.    the program prints the following:
  14150.  
  14151.      argc = 5───────────────────────────────────────────Five pointers in argv
  14152.  
  14153.      argv[0] -> "C"
  14154.      argv[1] -> "kit"
  14155.      argv[2] -> "makes"
  14156.      argv[3] -> "lovely"
  14157.      argv[4] -> "paper"
  14158.      argv[5] -> NULL
  14159.  
  14160.    ──────────────────────────────────────────────────────────────────────────
  14161.    /* showargs.c  --  shows how to access the arguments  */
  14162.    /*                 passed to main()                   */
  14163.  
  14164.    #include <stdio.h>        /* for NULL */
  14165.  
  14166.    main(argc, argv)
  14167.    int argc;
  14168.    char *argv[];
  14169.    {
  14170.        int i;
  14171.  
  14172.        printf("argc = %d\n", argc);
  14173.        printf("\n");
  14174.  
  14175.        for (i = 0; i < argc; ++i)
  14176.            {
  14177.            printf("argv[%d] -> \"%s\"\n", i, argv[i]);
  14178.            }
  14179.        printf("argv[%d] -> NULL\n", i);
  14180.        printf("\n");
  14181.    }
  14182.    ──────────────────────────────────────────────────────────────────────────
  14183.  
  14184.    Listing 9-12.  The SHOWARGS.C program.
  14185.  
  14186.    The first string that argv points to (an array of pointers to strings) is
  14187.    usually the name of your program. (Under QuickC, your program will always
  14188.    be named C when you run it from the Run menu, but argv[0] is correct when
  14189.    you run your program later as a .EXE file.)
  14190.  
  14191.    Because argv is an array of pointers to char, you often will see it
  14192.    alternatively declared as follows:
  14193.  
  14194.      main(argc, argv)
  14195.      int argc;
  14196.  
  14197.      main(argc, argv)
  14198.      int argc;
  14199.      char **argv;
  14200.      {    └─────────────────────────────────────────── A pointer to a pointer
  14201.  
  14202.    Recall that this pointer to a pointer and the declaration char *argv[] are
  14203.    interchangeable.
  14204.  
  14205.    The main() function is actually passed three arguments, but the third
  14206.    argument, called envp, is seldom used. Like argv, it is an array of
  14207.    pointers to strings and must be declared as follows:
  14208.  
  14209.      main(argc, argv, envp)
  14210.      int argc;
  14211.      char *argv[], *envp[];
  14212.      {
  14213.  
  14214.    The strings that envp points to are your system's environmental variables,
  14215.    such as PATH.
  14216.  
  14217.    Take a moment to modify SHOWARGS.C so that it matches the SHOW2.C program
  14218.    (Listing 9-13). After you run this program, choose DOS Shell from the
  14219.    File menu and type set. Compare the output produced by the MS-DOS SET
  14220.    command to that produced by this program.
  14221.  
  14222.    ──────────────────────────────────────────────────────────────────────────
  14223.    /* show2.c  --     shows how to use main()'s envp */
  14224.  
  14225.    #include <stdio.h>        /* for NULL */
  14226.  
  14227.    main(argc, argv, envp)
  14228.    int argc;
  14229.    char *argv[], *envp[];
  14230.    {
  14231.        int i;
  14232.  
  14233.        printf("argc = %d\n", argc);
  14234.        printf("\n");
  14235.  
  14236.        for (i = 0; i < argc; ++i)
  14237.            {
  14238.            printf("argv[%d] -> \"%s\"\n", i, argv[i]);
  14239.            }
  14240.        printf("argv[%d] -> NULL\n", i);
  14241.        printf("\n");
  14242.  
  14243.        for (i= 0; envp[i] != NULL; ++i)
  14244.            {
  14245.            printf("envp[%d] -> \"%s\"\n", i, envp[i]);
  14246.            }
  14247.        printf("envp[%d] -> NULL\n", i);
  14248.  
  14249.    }
  14250.    ──────────────────────────────────────────────────────────────────────────
  14251.  
  14252.    Listing 9-13.  The SHOW2.C program.
  14253.  
  14254.  
  14255.  Character Classification and Transformation
  14256.  
  14257.    You often need to be able to classify individual characters of a string
  14258.    (such as uppercase versus lowercase) and then transform them (such as
  14259.    converting uppercase to lowercase). QuickC includes a standard C header
  14260.    file called ctype.h, which defines many character classifications and
  14261.    transformation routines. (Use the View Include menu to examine it.) To
  14262.    access ctype.h, merely use #include to include it at the head of your
  14263.    program.
  14264.  
  14265.    The routines in ctype.h are not true functions: They are #define macros.
  14266.    We'll describe #define macros in detail in Chapter 12. In the meantime,
  14267.    you can use these routines because they work like function calls.
  14268.  
  14269.  The Character Classification Routines
  14270.  
  14271.    Each of the character classification routines in Table 9-4 takes a single
  14272.    argument──the character to classify──and returns a 1 for true or a 0 for
  14273.    false.
  14274.  
  14275.    The WHATCHAR.C program (Listing 9-14) prints all possible classifications
  14276.    for each character in a line of entered text. The program limits the line
  14277.    of text to 20 characters so that the display doesn't scroll off the
  14278.    screen.
  14279.  
  14280.    Table 9-4 The Character Classification Routines in ctype.h
  14281.    ──────────────────────────────────────────────────────────────────────────
  14282.    isalnum()   Tests for alphanumeric ('A' through 'Z,' 'a' through 'z,' and
  14283.                '0' through '9')
  14284.    isalpha()   Tests for a letter ('A' through 'Z' and 'a' through 'z')
  14285.    isascii()   Tests for an ASCII character (0x00 through 0x7F)
  14286.    iscntrl()   Tests for a control character (less than ' ' or equal to 0x7F)
  14287.    isdigit()   Tests for a digit ('0' through '9')
  14288.    isgraph()   Tests for printable character (inverse of iscntrl() but
  14289.                excludes space)
  14290.    islower()   Tests for lowercase letter ('a' through 'z')
  14291.    isprint()   Tests for printable character (inverse of iscntrl())
  14292.    ispunct()   Tests for punctuation character
  14293.    iswhite()   Tests for white space ('\t,' '\n,' '\f,' and ' ')
  14294.    isupper()   Tests for uppercase letter ('A' through 'Z')
  14295.    isxdigit()  Tests for a hexadecimal digit ('A' through 'F,' 'a' through
  14296.                'f,' '0' through '9')
  14297.    ──────────────────────────────────────────────────────────────────────────
  14298.  
  14299.    ──────────────────────────────────────────────────────────────────────────
  14300.    /* whatchar.c  --  demonstrates the character         */
  14301.    /*                 classification routines in ctype.h */
  14302.  
  14303.    #include <stdio.h>        /* for NULL and BUFSIZ */
  14304.    #include <ctype.h>        /* for iscntl(), et al */
  14305.    #define MAXL 20
  14306.  
  14307.    main()
  14308.    {
  14309.        char buf[BUFSIZ];
  14310.        int i;
  14311.  
  14312.        printf("Enter a line of text (20 chars max):\n");
  14313.        if (gets(buf) == NULL)
  14314.            exit(1);
  14315.  
  14316.        for (i = 0; i < MAXL; ++i)
  14317.            {
  14318.            if (buf[i] == '\0')
  14319.                break;
  14320.            printf("'%c' ->", buf[i]);
  14321.            if (isalpha(buf[i]))   printf(" isalpha");
  14322.            if (isascii(buf[i]))   printf(" isascii");
  14323.            if (iscntrl(buf[i]))   printf(" iscntrl");
  14324.            if (isgraph(buf[i]))   printf(" isgraph");
  14325.            if (isprint(buf[i]))   printf(" isprint");
  14326.            if (isdigit(buf[i]))   printf(" isdigit");
  14327.            if (isupper(buf[i]))   printf(" isupper");
  14328.            if (islower(buf[i]))   printf(" islower");
  14329.            if (ispunct(buf[i]))   printf(" ispunct");
  14330.            if (isspace(buf[i]))   printf(" isspace");
  14331.            if (isalnum(buf[i]))   printf(" isalnum");
  14332.            if (isxdigit(buf[i]))  printf(" isxdigit");
  14333.            printf("\n");
  14334.            }
  14335.    }
  14336.    ──────────────────────────────────────────────────────────────────────────
  14337.  
  14338.    Listing 9-14.  The WHATCHAR.C program.
  14339.  
  14340.    The include file ctype.h also defines routines to transform characters.
  14341.    Each of the routines in Table 9-5 takes a single argument, the character
  14342.    to transform, and returns the transformed character, as in the following
  14343.    example:
  14344.  
  14345.      ch = toupper('a');
  14346.  
  14347.    Here toupper() is given a lowercase 'a'. Because 'a' is lowercase,
  14348.    toupper() transforms it to an uppercase 'A' and assigns that value to the
  14349.    variable ch.
  14350.  
  14351.    The INVERT.C program (Listing 9-15) uses both the character
  14352.    classification and transformation routines to reverse a line of entered
  14353.    text. That is, it prints the line backward and inverts the case of each
  14354.    character.
  14355.  
  14356.    Table 9-5 The Character Transformation Routines in ctype.h
  14357.    ──────────────────────────────────────────────────────────────────────────
  14358.    toascii()   Converts a non-ASCII character to an ASCII character (clears
  14359.                all but the low-order seven bits)
  14360.    toupper()   Converts a lowercase character to an uppercase character
  14361.    tolower()   Converts an uppercase character to a lowercase character
  14362.    ──────────────────────────────────────────────────────────────────────────
  14363.  
  14364.    ──────────────────────────────────────────────────────────────────────────
  14365.    /* invert.c  --  combines character classification and */
  14366.    /*               transformation to invert text        */
  14367.  
  14368.    #include <stdio.h>         /* for NULL           */
  14369.    #include <ctype.h>        /* for toupper, et al. */
  14370.  
  14371.    main()
  14372.    {
  14373.        char buf[BUFSIZ];
  14374.        int i;
  14375.  
  14376.        printf("Type in a line of text and I will invert it.\n");
  14377.  
  14378.        if (gets(buf) == NULL)
  14379.            exit(1);
  14380.        /* Print the string backward. */
  14381.        for (i = (strlen(buf) - 1); i >= 0; --i)
  14382.            {
  14383.            if (isupper(buf[i]))            /* upper to lower */
  14384.                putchar(tolower(buf[i]));
  14385.            else if (islower(buf[i]))       /* lower to upper */
  14386.                putchar(toupper(buf[i]));
  14387.            else
  14388.                putchar(buf[i]);
  14389.            }
  14390.        putchar('\n');
  14391.  
  14392.    }
  14393.    ──────────────────────────────────────────────────────────────────────────
  14394.  
  14395.    Listing 9-15.   The INVERT.C program.
  14396.  
  14397.  
  14398.  
  14399.  ────────────────────────────────────────────────────────────────────────────
  14400.  Chapter 10  Managing Files
  14401.  
  14402.    C files are primarily disk files that contain text, executable images of
  14403.    programs, or data. These disk files represent stored programs and data
  14404.    that form a common "library" of information that is available to a wide
  14405.    range of programs.
  14406.  
  14407.    The QuickC library functions that handle file input and output are
  14408.    arranged in three categories, or levels, as illustrated in Figure 10-1 on
  14409.    the following page. At the top level are the buffered (stream I/O)
  14410.    routines; below those are the unbuffered (raw I/O) routines; and at the
  14411.    bottom are the direct BIOS interfaces. The low-level routines are not a
  14412.    part of portable C because they access PC-specific internal routines. The
  14413.    higher-level routines, however, are universal to all C compilers. We will
  14414.    not cover the low-level BIOS routines in this book.
  14415.  
  14416.    The top-level file I/O routines are called "buffered stream" routines
  14417.    because they interpose themselves between your program and files. They
  14418.    read and write large blocks of information (buffering), and then they pass
  14419.    a continuous series (stream) of bytes to your program, as needed.
  14420.  
  14421.                              ┌────────────────────┐
  14422.                              │                    │
  14423.                              │      Buffer        │────────────────┐
  14424.                              │                    │                 │
  14425.                              └───────────────────┘                 │
  14426.                                        │                            │
  14427.                                        │                            │
  14428.                              ┌───────────────────┐                 │
  14429.                   ┌─────────│Top-level           │                 │
  14430.                   │          │functions like      │         ┌───────────────┐
  14431.    ┌───────────────┐        │fopen() and fgetc() │         │                │
  14432.    │                │        └────────────────────┘         │    Your        │
  14433.    │      Disk      │        ┌────────────────────┐         │    program     │
  14434.    │                │        │Mid-level           │         │                │
  14435.    └──────────────┘        │functions like      │         └──────────────┘
  14436.             │     └─────────│open() and read()   │──────────┘     │
  14437.             │                └────────────────────┘                 │
  14438.             │                ┌────────────────────┐                 │
  14439.             │                │Low-level           │                 │
  14440.             └───────────────│functions like      │────────────────┘
  14441.                              │_bios_disk()        │
  14442.                              └────────────────────┘
  14443.  
  14444.    Figure 10-1. The three levels of file I/O.
  14445.  
  14446.    The middle file level is called unbuffered because it lets your program
  14447.    access files directly. Reads and writes do not pass through an
  14448.    intermediate buffer; they pass directly between the operating system and
  14449.    your program. These mid-level routines can execute faster than the
  14450.    top-level routines, but they are more complex to use.
  14451.  
  14452.    Both top-level and mid-level file routines have two modes──text and
  14453.    binary. Text mode is used with text files, or files that contain ASCII
  14454.    text (which is readable by persons). Binary mode is used with files that
  14455.    contain binary information, such as executable programs. In text mode,
  14456.    Ctrl-Z (a byte containing the value 0x1A) marks the end of a file. In
  14457.    binary mode, Ctrl-Z can legally be a part of the file; the operating
  14458.    system keeps track of file length.
  14459.  
  14460.  
  14461.  Top-Level I/O
  14462.  
  14463.    All buffered file I/O functions require that you begin your program with
  14464.    #include <stdio.h>. That header file contains the definition for FILE, the
  14465.    data type that you use to manipulate files. The type FILE is used as shown
  14466.    on the next page.
  14467.  
  14468.      #include <stdio.h>
  14469.      ...
  14470.      FILE *fp;
  14471.  
  14472.    Remember, always use #include <stdio.h> for the definition of the type
  14473.    FILE. Then declare a file pointer to point to the data type FILE.
  14474.  
  14475.  Opening Files with fopen()
  14476.  
  14477.    Before you can access a file for reading or writing or both, you must
  14478.    first open that file. For buffered I/O routines (those that use a file
  14479.    pointer), open the file with the fopen() function, as follows:
  14480.  
  14481.      fp = fopen(filename, activity);
  14482.                    │          └───────────────── Open to read, write, or both
  14483.                    └──────────────────────────────────── Name of file to open
  14484.  
  14485.    The fopen() function requires two arguments: the name of the file to open
  14486.    (a string or the address of a string) and an activity (also a string) as
  14487.    listed in Table 10-1. The activity determines whether the file is open
  14488.    for reading, writing, or appending. (In this case, read means to take
  14489.    information sequentially from a file, write means to put information
  14490.    sequentially into a file, and append means to add information to the end
  14491.    of a file.)
  14492.  
  14493.    The fopen() function returns a value of type FILE *. In our example we
  14494.    assigned this value to file pointer fp, which we will use to access and
  14495.    manipulate the file. If fopen() fails, it returns NULL. Therefore, the
  14496.    complete call to fopen(), including error handling, is as follows:
  14497.  
  14498.      fp = fopen("test.c", "r");
  14499.      if (fp == NULL)
  14500.      {
  14501.          /* handle error here */
  14502.      }
  14503.  
  14504.    This opens the TEST.C file for reading (activity "r"). After the file
  14505.    pointer returned by fopen() is assigned to fp, we test fp to see if it is
  14506.    NULL. We test for an error here because it is possible that the file
  14507.    TEST.C does not exist.
  14508.  
  14509.    Table 10-1 Possible Modes (Activities) for fopen()
  14510.    Mode       Description
  14511.    ──────────────────────────────────────────────────────────────────────────
  14512.    "r"        Open for reading only. The file must already exist.
  14513.    "w"        Open for writing only. Creates the file if it does not exist.
  14514.    "a"        Open for appending (write-only, starting at the end of a file).
  14515.               Creates the file if it does not exist.
  14516.    "r+"       Open for both reading and writing. The file must already exist.
  14517.    "w+"       Open for both reading and writing. Creates the file if it does
  14518.               not already exist.
  14519.    "a+"       Open for both reading and writing, starting at the end of the
  14520.               file. Creates the file if it does not exist.
  14521.    ──────────────────────────────────────────────────────────────────────────
  14522.  
  14523.    Each open file requires its own file pointer. The following two open
  14524.    files, for example, require two separate file pointers:
  14525.  
  14526.      #include <stdio.h>
  14527.      ...
  14528.      FILE *fp_in, *fp_out;
  14529.      ...
  14530.      fp_in = fopen("test.txt", "r");
  14531.      fp_out = fopen("test.bak", "w");
  14532.  
  14533.    In this example, fp_in is the file pointer for the file opened for reading
  14534.    (activity "r"), and fp_out is the file pointer for the file opened for
  14535.    writing (activity "w").
  14536.  
  14537.    ──────────────────────────────────────────────────────────────────────────
  14538.    File Access in BASIC and C
  14539.    If you're used to BASIC file handling, you'll find that QuickC offers
  14540.    fewer "built-in" conveniences but ultimately provides more power and
  14541.    flexibility. In BASIC, you might open a random access file with the
  14542.    following statement, which specifies the file identification number and
  14543.    record length:
  14544.  
  14545.      OPEN "C:\ACCT\TRANS" FOR RANDOM AS #1 LEN = 256
  14546.  
  14547.    Before you can use the file, you have to use FIELD statements to associate
  14548.    whatever numeric or string variables you are going to use with the
  14549.    corresponding data fields in the file record. Because most versions of
  14550.    BASIC don't have a data type similar to the C struct, you have to
  14551.    manipulate numerous separate variables to move data to and from the file.
  14552.    The built-in random access support does allow you to get a record by its
  14553.    record number directly using the GET statement, however.
  14554.  
  14555.    C has a different approach: A file can contain any valid C data type, such
  14556.    as a struct, which already has its fields defined, so you don't have to
  14557.    set up file data fields. On the other hand, file manipulation methods,
  14558.    such as random access, are not built-in in C. You can achieve random
  14559.    access, however, by converting a record number to an offset and then using
  14560.    the library function fseek() to position C's file pointer to the correct
  14561.    record. You can also use the fgetpos() and fsetpos() functions to
  14562.    manipulate the file pointer.
  14563.  
  14564.    Also, because C uses function calls rather than BASIC's procedural
  14565.    commands to manipulate files, you can quickly check for errors by putting
  14566.    the function call in an if statement.
  14567.    ──────────────────────────────────────────────────────────────────────────
  14568.  
  14569.  Reading Characters with fgetc()
  14570.  
  14571.    There's more to reading a file than merely opening the file to read. To
  14572.    see what we mean, examine the STRINGS.C program (Listing 10-1), which
  14573.    reads a file one character at a time and looks for strings of five or more
  14574.    printable characters. The program takes a command-line argument, so before
  14575.    you run it, you must create the argument using the Set Runtime Options
  14576.    screen from the Run menu. In the Command Line box, type c:\qc\qc.exe (or
  14577.    the name of any existing file). Figure 10-2 on the next page shows the
  14578.    screen after you type the command.
  14579.  
  14580.    ──────────────────────────────────────────────────────────────────────────
  14581.    /* strings.c  --  opens a file and searches it for */
  14582.    /*                possible strings                 */
  14583.  
  14584.    #include <stdio.h>        /* for FILE, BUFSIZ, & EOF */
  14585.    #include <ctype.h>        /* for isprint()           */
  14586.  
  14587.    main(argc, argv)
  14588.    int argc;
  14589.    char *argv[];
  14590.    {
  14591.        FILE *fp;
  14592.        char buf[BUFSIZ];
  14593.        int ch, count;
  14594.  
  14595.        if (argc != 2)
  14596.            {
  14597.            fprintf(stderr, "usage: strings file\n");
  14598.            exit(1);
  14599.            }
  14600.        if ((fp = fopen(argv[1], "rb")) == NULL)
  14601.            {
  14602.            fprintf(stderr, "Can't open %s\n", argv[1]);
  14603.            exit(1);
  14604.            }
  14605.  
  14606.        count = 0;
  14607.        while ((ch = fgetc(fp)) != EOF)
  14608.            {
  14609.            if (! isprint(ch) || count >= (BUFSIZ - 1))
  14610.                {
  14611.                if (count > 5)
  14612.                    {
  14613.                    buf[count] = 0;
  14614.                    puts(buf);
  14615.                    }
  14616.                count = 0;
  14617.                continue;
  14618.                }
  14619.            buf[count++] = ch;
  14620.            }
  14621.    }
  14622.    ──────────────────────────────────────────────────────────────────────────
  14623.  
  14624.    Listing 10-1.  The STRINGS.C program.
  14625.  
  14626.    ┌────────────────────────────────────────────────────────────────────────┐
  14627.    │ Figure 10-2 can be found on p.296 of the printed version of the book.  │
  14628.    └────────────────────────────────────────────────────────────────────────┘
  14629.  
  14630.    Figure 10-2. The Set Runtime Options dialog box lets you enter a command
  14631.    line.
  14632.  
  14633.    When we run STRINGS.C on a large file such as QC.EXE, the program prints
  14634.    many screens of possible strings. For convenience, you might add a
  14635.    "paging" feature to the program.
  14636.  
  14637.    STRINGS.C uses the fgetc() function, a file-oriented version of the
  14638.    getchar() routine we've used before. After it is passed a single argument
  14639.    (a file pointer), the function returns the next character read from the
  14640.    file pointed to. Assigning that character to a variable of type int lets
  14641.    us detect EOF (End Of File) easily.
  14642.  
  14643.      int ch;
  14644.  
  14645.      if ((ch = fgetc(fp)) == EOF)
  14646.      {
  14647.            /* handle end of file here */
  14648.      }
  14649.  
  14650.    Notice that STRINGS.C calls fopen() with the activity argument "rb". This
  14651.    is a PC-specific extension of the normal "open for reading" argument. The
  14652.    b tells fopen() to open the file in binary mode but to do no character
  14653.    translation for us──that is, to give fgetc() every byte from the file as
  14654.    is. If we did not specify the b, fopen() would have opened the file in
  14655.    text mode. Had we used text mode, however, our program would not have read
  14656.    all of QC.EXE because the Ctrl-Z character, which is a legal byte in
  14657.    binary files, would have marked the end of the file. Table 10-2 shows the
  14658.    difference between these two modes.
  14659.  
  14660.    Also notice that STRINGS.C ends without closing the file. C, unlike BASIC,
  14661.    closes all open files when you exit the program. This is true whether you
  14662.    exit main() with a return or from another function with an exit().
  14663.  
  14664.    Table 10-2 Text vs Binary Modes for fopen()
  14665.    ──────────────────────────────────────────────────────────────────────────
  14666.    t       text mode        Translates carriage return/linefeed combinations
  14667.                             into single linefeeds on input and makes the
  14668.                             reverse translation on output. Ctrl-Z marks the
  14669.                             end of the file.
  14670.    b       binary mode      Suppresses the above translations. The operating
  14671.                             system keeps track of the file's length.
  14672.    ──────────────────────────────────────────────────────────────────────────
  14673.  
  14674.  Closing Files with fclose()
  14675.  
  14676.    Although MS-DOS lets you have as many as 20 simultaneously open files, you
  14677.    might want to close each open file before you open another one. Closing a
  14678.    file writes everything to disk, updates the directory entry for that file,
  14679.    and frees a file pointer.
  14680.  
  14681.    When you open files with fopen(), you can close them with fclose(), as
  14682.    follows:
  14683.  
  14684.      if (fclose(fp) == EOF)
  14685.      {
  14686.            /* unable to close file */
  14687.      }
  14688.      /* fp may be reused here */
  14689.  
  14690.    If fclose() cannot close a file (because the floppy disk containing that
  14691.    file was removed, for example), it returns EOF.
  14692.  
  14693.  Line I/O with fgets() and fputs()
  14694.  
  14695.    The standard C Library contains a pair of file-oriented routines called
  14696.    fgets() ("file get string") and fputs() ("file put string"). They are
  14697.    similar to the gets() and puts() pair we discussed in the last chapter:
  14698.    fgets() reads lines of text from files and fputs() writes lines of text
  14699.    into files. Use them as follows:
  14700.  
  14701.      #include <stdio.h>
  14702.      #define SIZE 512
  14703.      ...
  14704.      FILE *fp_in, *fp_out;
  14705.      char buf[SIZE];
  14706.      ...
  14707.      /* open fp_in for reading and fp_out for writing */
  14708.      ...
  14709.      if (fgets(buf, SIZE, fp_in) == NULL)
  14710.      {
  14711.            /* error reading or EOF */
  14712.      }
  14713.      /* a line of text is now in buf */
  14714.      ...
  14715.  
  14716.      if (fputs(buf, fp_out) == EOF)
  14717.      {
  14718.           /* error writing */
  14719.      }
  14720.  
  14721.    The fgets() function takes three arguments: the address of a char buffer,
  14722.    the maximum number of characters to read into that buffer, and a file
  14723.    pointer to a file opened for reading. In the example, fgets() reads a
  14724.    maximum of SIZE characters (up to and including the first newline
  14725.    character) and appends a terminating '\0' to the characters to form a
  14726.    string. The fputs() function requires two arguments: the address of a
  14727.    zero-terminated string (in buf) and a file pointer to a file opened for
  14728.    writing. In the example, fputs() writes the string in buf to fp_out──
  14729.    including any newline in that string. Note as well that fputs() does not
  14730.    add any newlines.
  14731.  
  14732.    The fputs() and fgets() functions differ from their counterparts puts()
  14733.    and gets(). Each handles the newline character in a different way, as
  14734.    follows:
  14735.  
  14736.    ──────────────────────────────────────────────────────────────────────────
  14737.    gets(buf)      Reads characters from keyboard and places them into buf.
  14738.                   Replaces the trailing newline character ('\n') with a '\0'.
  14739.  
  14740.    fgets(buf,     Reads a maximum of len characters from a file opened for
  14741.    len, fp)       reading. Places len or fewer characters (up to and
  14742.                   including a newline) into buf. Retains the newline
  14743.                   character and adds a terminating '\0'.
  14744.  
  14745.    puts(buf)      Prints the string in buf to the screen and adds a newline
  14746.                   character to the output on the screen.
  14747.  
  14748.    fputs(buf, fp) Prints (writes) the string in buf into the file (opened for
  14749.                   writing) pointed to by the file pointer fp. Does not add a
  14750.                   newline character to the output.
  14751.    ──────────────────────────────────────────────────────────────────────────
  14752.  
  14753.    The CCOPY.C program (Listing 10-2) reads one file and writes to a second.
  14754.    The "C" preceding "COPY" (in the program name) signals that this COPY
  14755.    "crunches" its input──eliminating all empty lines, leading tabs, and
  14756.    spaces. You could use this program to prepare files before sending them
  14757.    over a slow modem.
  14758.  
  14759.    ──────────────────────────────────────────────────────────────────────────
  14760.    /* ccopy.c  --  copies a file, cutting blank lines and  */
  14761.    /*              leading space from lines of copy        */
  14762.  
  14763.    #include <stdio.h>        /* for FILE, BUFSIZ, NULL */
  14764.    #include <ctype.h>        /* for iswhite()          */
  14765.  
  14766.    main(argc, argv)
  14767.    int argc;
  14768.    char *argv[];
  14769.    {
  14770.        FILE *fp_in, *fp_out;
  14771.        char buf[BUFSIZ];
  14772.        char *cp;
  14773.  
  14774.        if (argc != 3)
  14775.            {
  14776.            printf("usage: ccopy infile outfile\n");
  14777.            exit(1);
  14778.            }
  14779.        if ((fp_in = fopen(argv[1], "r")) == NULL)
  14780.            {
  14781.            printf("Can't open %s for reading.\n", argv[1]);
  14782.            exit(1);
  14783.            }
  14784.        if ((fp_out = fopen(argv[2], "w")) == NULL)
  14785.            {
  14786.            printf("Can't open %s for writing.\n", argv[2]);
  14787.            exit(1);
  14788.            }
  14789.  
  14790.        printf("Copying and Crushing: %s->%s ...",
  14791.                    argv[1], argv[2]);
  14792.  
  14793.        while (fgets(buf, BUFSIZ, fp_in) != NULL)
  14794.            {
  14795.            cp = buf;
  14796.            if (*cp == '\n')    /* blank line */
  14797.                continue;
  14798.            while (isspace(*cp))
  14799.                {
  14800.                ++cp;
  14801.                }
  14802.            if (*cp == '\0')    /* empty line */
  14803.                continue;
  14804.            if (fputs(cp, fp_out) == EOF)
  14805.                {
  14806.                printf("\nError writing %s.\n", argv[2]);
  14807.                exit(1);
  14808.                }
  14809.            }
  14810.        printf("Done\n");
  14811.    }
  14812.    ──────────────────────────────────────────────────────────────────────────
  14813.  
  14814.    Listing 10-2.  The CCOPY.C program.
  14815.  
  14816.    To run this program you need to set its command line from the Set Runtime
  14817.    Options dialog box. The Command Line text box requires two filenames as
  14818.    arguments──first, the file to read, and second, the file to write to. For
  14819.    example, you might enter the filenames strings.c temp. The first name is
  14820.    the existing text file to be read (note that the fopen() in CCOPY.C uses
  14821.    "r" for text mode). The second name is the new file that will be created
  14822.    (activity "w").
  14823.  
  14824.    Within a loop, fgets() reads a line of text from the first file, the
  14825.    program crunches that line, and fputs() writes the condensed line into the
  14826.    second file. After you run CCOPY.C, choose DOS Shell from the File menu
  14827.    and look at the newly created file using the TYPE command and Ctrl-S.
  14828.  
  14829.  Error Detection with feof() and ferror()
  14830.  
  14831.    Using fgets() has a drawback──it returns NULL for both EOF (which you
  14832.    expect) and read errors (which you don't expect). However, you can
  14833.    differentiate between the two by using feof() and ferror().
  14834.  
  14835.    The feof() function tests a file opened for reading and associated with a
  14836.    file pointer to see if the end of that file has been reached. It returns
  14837.    true (nonzero) at the end of the file; otherwise it returns 0. The
  14838.    ferror() function returns true if there is any error with the file──
  14839.    including reaching the end of file. The following example shows how to use
  14840.    them together to differentiate between the two conditions:
  14841.  
  14842.      if (feof(fp_in))
  14843.      {
  14844.            /* reached end of file while reading */
  14845.      }
  14846.      else if (ferror(fp_in))
  14847.      {
  14848.            /* some read error has occurred */
  14849.      }
  14850.  
  14851.    EOF is meaningful only when reading; use ferror() alone when writing to a
  14852.    file:
  14853.  
  14854.      if (ferror(fp_out))
  14855.      {
  14856.            /* some write error has occurred */
  14857.      }
  14858.  
  14859.    Always include error-checking routines in your programs to protect
  14860.    yourself from careless users. Users sometimes remove floppy disks while
  14861.    the drive light is on or try writing to disks that are write-protected.
  14862.    Error detection lets you either take corrective action or notify users of
  14863.    their mistakes.
  14864.  
  14865.  Block I/O with fread() and fwrite()
  14866.  
  14867.    So far we've treated files as lines of text. However, you will often want
  14868.    to read and write files in specific blocks whose size is measured in
  14869.    bytes. (Executable program files and data files, for example, generally
  14870.    contain no meaningful lines of text.) To do this, the standard C Library
  14871.    provides a pair of routines called fread() and fwrite(). Their forms are
  14872.    nearly identical:
  14873.  
  14874.      fread(buffer, size, count, fp_in);
  14875.               │      │      │    └──────────────────────── A file pointer
  14876.               │      │      └────────────────────────── How many size items
  14877.               │      └──────────────────────────── How many bytes per item
  14878.               └───────────────────── Address of (size * count) bytes buffer
  14879.  
  14880.  
  14881.      fwrite(buffer, size, count, fp_out);
  14882.               │      │      │    └──────────────────────── A file pointer
  14883.               │      │      └────────────────────────── How many size items
  14884.               │      └──────────────────────────── How many bytes per item
  14885.               └───────────────────── Address of (size * count) bytes buffer
  14886.  
  14887.    Both routines require that you specify #include <stdio.h> to define FILE
  14888.    for the file pointer and to define the new type size_t for the variables
  14889.    size and count:
  14890.  
  14891.      size_t size;
  14892.      size_t count;
  14893.      FILE   *fp;
  14894.  
  14895.    QuickC defines the type size_t in the <stdio.h> header file as an unsigned
  14896.    long. Because it might be defined differently with other compilers, you
  14897.    should use size_t for portability.
  14898.  
  14899.    Both functions return the number of bytes actually read or written. When
  14900.    that number is less than size times count, an error has occurred. In the
  14901.    case of fread(), however, that error can also indicate that you've reached
  14902.    the end of the file. Therefore, you need to use feof() to distinguish end
  14903.    of file from other errors.
  14904.  
  14905.    The UPPITY.C program (Listing 10-3) shows one way to use fread() and
  14906.    fwrite(). It reads an entire file into memory (using malloc() to obtain
  14907.    that memory), converts it to uppercase, then writes the entire file to a
  14908.    new file having the .UP extension.
  14909.  
  14910.    ──────────────────────────────────────────────────────────────────────────
  14911.    /* uppity.c --  makes an uppercase copy of a file using */
  14912.    /*              fread() and fwrite()                    */
  14913.  
  14914.    #include <string.h>     /* for strrchr() */
  14915.    #include <stdio.h>      /* for NULL      */
  14916.    #include <malloc.h>     /* for malloc()  */
  14917.    #include <ctype.h>      /* for isupper() */
  14918.  
  14919.    #define HUNK 512
  14920.  
  14921.    main(argc, argv)
  14922.    int argc;
  14923.    char *argv[];
  14924.    {
  14925.        char *cp, newname[128], *np;
  14926.        FILE *fp;
  14927.        int  hunks = 0, bytes = 0, totbytes = 0;
  14928.        int  i;
  14929.        if (argc != 2)
  14930.            {
  14931.            printf("usage: uppity file\n");
  14932.            exit(1);
  14933.            }
  14934.  
  14935.        if ((fp = fopen(argv[1], "rb")) == NULL)
  14936.            {
  14937.            printf("\"%s\": Can't open.\n", argv[1]);
  14938.            exit(1);
  14939.            }
  14940.        if ((cp = malloc(HUNK)) == NULL)
  14941.            {
  14942.            printf("Malloc Failed.\n");
  14943.            exit(1);
  14944.            }
  14945.  
  14946.        while ((bytes = fread(cp + (HUNK * hunks), 1, HUNK, fp)) == HUNK)
  14947.            {
  14948.            totbytes += bytes;
  14949.            ++hunks;
  14950.            if ((cp = realloc(cp, HUNK + (HUNK * hunks))) == NULL)
  14951.                {
  14952.                printf("Realloc Failed.\n");
  14953.                exit(1);
  14954.                }
  14955.            }
  14956.        if (bytes < 0)
  14957.            {
  14958.            printf("\"%s\": Error Reading.\n", argv[1]);
  14959.            exit(1);
  14960.            }
  14961.        totbytes += bytes;
  14962.  
  14963.        for (i = 0; i < totbytes; ++i)
  14964.            if (islower(cp[i]))
  14965.                cp[i] = toupper(cp[i]);
  14966.  
  14967.        (void)fclose(fp);
  14968.  
  14969.        if ((np = strchr(argv[1], '.')) != NULL)
  14970.            *np = '\0';
  14971.        strcpy(newname, argv[1]);
  14972.        strcat(newname, ".up");
  14973.        if ((fp = fopen(newname, "wb")) == NULL)
  14974.            {
  14975.            printf("\"%s\": Can't open.\n", argv[1]);
  14976.            exit(1);
  14977.            }
  14978.  
  14979.        if (fwrite(cp, 1, totbytes, fp) != totbytes)
  14980.            {
  14981.            printf("\"%s\": Error writing.\n", argv[1]);
  14982.            exit(1);
  14983.            }
  14984.  
  14985.    }
  14986.    ──────────────────────────────────────────────────────────────────────────
  14987.  
  14988.    Listing 10-3.  The UPPITY.C program.
  14989.  
  14990.    UPPITY.C continually reallocates memory for each HUNK (512 bytes) of the
  14991.    file read in. A more direct approach would find the size of the file, then
  14992.    read in that many bytes with a single fread(). You can do this with the
  14993.    stat() function. Unfortunately, to use stat() you must understand
  14994.    "structures," and we won't be describing those until the next chapter.
  14995.    Keep in mind that you might want to modify UPPITY.C when you learn how to
  14996.    use structures.
  14997.  
  14998.  Predeclared File Pointers
  14999.  
  15000.    When you run any QuickC program, five file pointers are always provided
  15001.    for five preopened files. Those file pointers are stdin, stdout, stderr,
  15002.    stdaux, and stdprn. (See Table 10-3.) Because these preopened file
  15003.    pointers are defined in stdio.h, you must include that header file if you
  15004.    want to use them.
  15005.  
  15006.    To demonstrate the use of these file pointers, we revised CCOPY.C (the
  15007.    "crunch-and-copy program") to produce the CCOPY2.C program (Listing
  15008.    10-4). This revision checks for the presence of a second (output)
  15009.    filename. If it is missing, fputs() directs the output to stdout (your
  15010.    screen).
  15011.  
  15012.    Table 10-3 QuickC's Preopened File Pointers
  15013.    ──────────────────────────────────────────────────────────────────────────
  15014.    stdin      The standard input. Your keyboard viewed as a file. Also, input
  15015.               to your program provided by redirection using <file from the
  15016.               MS-DOS command line.
  15017.    stdout     The standard output. Your screen viewed as a file. Also, output
  15018.               to disk files provided by redirection using >file from the
  15019.               MS-DOS command line.
  15020.    stderr     The standard error output. Always your screen. This file
  15021.               pointer is unaffected by redirection from the MS-DOS command
  15022.               line.
  15023.    stdaux     The standard auxiliary. Usually your serial port or COM1. This
  15024.               file pointer provides easy access to your modem.
  15025.    stdprn     The standard printer output. Usually your parallel port or PRN.
  15026.               This file pointer provides an easy way to generate hard copy
  15027.               from within a QuickC program.
  15028.    ──────────────────────────────────────────────────────────────────────────
  15029.  
  15030.    ──────────────────────────────────────────────────────────────────────────
  15031.    /* ccopy2.c  -- copies a file, cutting blank lines and  */
  15032.    /*              leading space from lines of copy        */
  15033.  
  15034.    /*          Modified to demonstrate stdout and stderr   */
  15035.  
  15036.    #include <stdio.h>        /* for FILE, BUFSIZ, NULL */
  15037.    #include <ctype.h>        /* for iswhite()          */
  15038.  
  15039.    main(argc, argv)
  15040.    int argc;
  15041.    char *argv[];
  15042.    {
  15043.        FILE *fp_in, *fp_out;
  15044.        char buf[BUFSIZ];
  15045.        char *cp;
  15046.  
  15047.        if (argc < 2)
  15048.            {
  15049.            fprintf(stderr, "usage: ccopy2 infile {outfile}\n");
  15050.            exit(1);
  15051.            }
  15052.        if ((fp_in = fopen(argv[1], "r")) == NULL)
  15053.            {
  15054.            fprintf(stderr, "\"%s\": Can't open.\n", argv[1]);
  15055.            exit(1);
  15056.            }
  15057.        if (argc == 3)
  15058.            {
  15059.                if ((fp_out = fopen(argv[2], "w")) == NULL)
  15060.                    {
  15061.                    fprintf(stderr, "\"%s\": Can't open.\n", argv[2]);
  15062.                    exit(1);
  15063.                    }
  15064.            }
  15065.        else
  15066.            fp_out = stdout;
  15067.  
  15068.        while (fgets(buf, BUFSIZ, fp_in) != NULL)
  15069.            {
  15070.            cp = buf;
  15071.            if (*cp == '\n')    /* blank line */
  15072.                continue;
  15073.            while (isspace(*cp))
  15074.                {
  15075.                ++cp;
  15076.                }
  15077.            if (*cp == '\0')    /* empty line */
  15078.                continue;
  15079.            if (fputs(cp, fp_out) == EOF)
  15080.                {
  15081.                fprintf(stderr, "Error writing.\n");
  15082.                exit(1);
  15083.                }
  15084.            }
  15085.        if (! feof(fp_in))        /* error reading? */
  15086.            {
  15087.            fprintf(stderr, "\"%s\": Error reading.\n", argv[1]);
  15088.            exit(1);
  15089.            }
  15090.    }
  15091.    ──────────────────────────────────────────────────────────────────────────
  15092.  
  15093.    Listing 10-4.  The CCOPY2.C program.
  15094.  
  15095.  Formatted File I/O with fprintf() and fscanf()
  15096.  
  15097.    CCOPY2.C didn't print error messages with printf(); instead, it used the
  15098.    file-oriented version of printf(), called fprintf(), to send error
  15099.    messages to stderr, which is always your screen. This ensures that you
  15100.    will always see error messages, even when the program is printing its
  15101.    output to a file.
  15102.  
  15103.    C's file-oriented counterparts to printf() and scanf() are called
  15104.    fprintf() and fscanf(). They are identical to their nonfile brethren, with
  15105.    one exception: Each requires a file pointer as its first argument, as
  15106.    follows:
  15107.  
  15108.      fprintf(fp_out, control, args ...);
  15109.              └─┬──┘  └───────┬────────┘
  15110.                │             └─────────────────────────── Same as printf()
  15111.                └─────────────────────────────────────────── A file pointer
  15112.  
  15113.      fscanf(fp_in, control, addresses ...);
  15114.             └─┬─┘  └─────────┬───────────┘
  15115.               │              └──────────────────────────── Same as scanf()
  15116.               └──────────────────────────────────────────── A file pointer
  15117.  
  15118.  Random Access with fseek()
  15119.  
  15120.    Sophisticated applications, such as databases, must be able to move around
  15121.    in files (recall that files are continuous streams of bytes) reading and
  15122.    writing selected portions. The fseek() function lets a program access any
  15123.    file element by determining the position of the next read or write in a
  15124.    file, as follows:
  15125.  
  15126.      fseek(fp, offset, origin)
  15127.         │     │   │      └───────────────────────────────────── From where
  15128.         └──┬──┘   └───────────────────────────────── How far to reposition
  15129.            └───────────────────────────────────────────────── File pointer
  15130.  
  15131.    The offset, in bytes, tells fseek() how far to move in the file, and it
  15132.    must be type long. The origin determines where to measure offset from; it
  15133.    can be any one of three values──the beginning, current position, or end of
  15134.    the file. (See Table 10-4.)
  15135.  
  15136.    If fseek() cannot reposition in a file, it returns the value -1L (the L is
  15137.    needed because fseek() returns the type long). If fseek() is successful,
  15138.    it returns the new position in the file, measured in bytes from the
  15139.    beginning of the file.
  15140.  
  15141.    Table 10-4 origin Positions for fseek()
  15142.    ──────────────────────────────────────────────────────────────────────────
  15143.    SEEK_SET       From the beginning of the file; offset must always be
  15144.                   positive.
  15145.    SEEK_CUR       Relative to the current position. A negative offset moves
  15146.                   toward the beginning of the file; a positive offset moves
  15147.                   toward the end of the file. (You can move beyond the end of
  15148.                   the file, thus enlarging the file.)
  15149.    SEEK_END       From the end of the file; offset can be positive or
  15150.                   negative. Movement is the same as SEEK_CUR, but relative to
  15151.                   the end of the file.
  15152.    ──────────────────────────────────────────────────────────────────────────
  15153.  
  15154.    The PHONE.C program (Listing 10-5 on the following page) is a miniature
  15155.    telephone number database. When run without command-line arguments, it
  15156.    asks you for numbers to add to its database file. Run with a command-line
  15157.    argument, it searches for an entry that matches the argument and prints
  15158.    the data it finds.
  15159.  
  15160.    ──────────────────────────────────────────────────────────────────────────
  15161.    /* phone.c  -- a telephone number mini-database that  */
  15162.    /*             demonstrates fseek()                   */
  15163.  
  15164.    #include <stdio.h>        /* for FILE, BUFSIZ, NULL */
  15165.  
  15166.    #define MAXL (128)
  15167.    char Name[MAXL];
  15168.    char Number[MAXL];
  15169.    char File[] = "C:\\TMP\\PHONE.DB";
  15170.    int  Count;
  15171.    FILE *Fp;
  15172.    int  Distance = (MAXL * MAXL);
  15173.  
  15174.    main(argc, argv)
  15175.    int argc;
  15176.    char *argv[];
  15177.    {
  15178.        if (argc == 1)
  15179.            Ask();
  15180.        else
  15181.            Find(argv[1]);
  15182.  
  15183.    }
  15184.  
  15185.    Find(char *str)
  15186.    {
  15187.        int i;
  15188.  
  15189.        if ((Fp = fopen(File, "r")) == NULL)
  15190.            {
  15191.            fprintf(stderr, "\"%s\": Can't Read\n", File);
  15192.            exit (1);
  15193.            }
  15194.        if (fread(&Count, 1, sizeof(int), Fp) != sizeof(int))
  15195.            {
  15196.            fprintf(stderr, "\"%s\": Error Reading\n", File);
  15197.            exit (1);
  15198.            }
  15199.        for (i = 0; i < Count; i++)
  15200.            {
  15201.            fread(Name, 1, MAXL, Fp);
  15202.            fread(Number, 1, MAXL, Fp);
  15203.            if (ferror(Fp))
  15204.                {
  15205.                fprintf(stderr, "\"%s\": Error Reading.\n", File);
  15206.                exit (1);
  15207.                }
  15208.            if (strcmp(*str, *Name) == 0)
  15209.                {
  15210.                printf("Name: %s\n", Name);
  15211.                printf("Number: %s\n", Number);
  15212.                return;
  15213.                }
  15214.            }
  15215.        fprintf(stderr, "\"%s\": Not in database.\n", str);
  15216.        return;
  15217.    }
  15218.  
  15219.    Ask()
  15220.    {
  15221.        if ((Fp = fopen(File, "r+")) == NULL)
  15222.            Make();
  15223.        else if (fread(&Count, 1, sizeof(int), Fp) != sizeof(int))
  15224.            {
  15225.            fprintf(stderr, "\"%s\": Error Reading\n", File);
  15226.            exit (1);
  15227.            }
  15228.        printf("Name: ");
  15229.        if (gets(Name) == NULL || *Name == '\0')
  15230.            return;
  15231.        printf("Number: ");
  15232.        if (gets(Number) == NULL || *Number == '\0')
  15233.            return;
  15234.        if (fseek(Fp, (long)(Distance * Count), SEEK_CUR) != 0)
  15235.            {
  15236.            fprintf(stderr, "\"%s\": Error Seeking.\n", File);
  15237.            exit (1);
  15238.            }
  15239.        fwrite(Name, 1, MAXL, Fp);
  15240.        fwrite(Number, 1, MAXL, Fp);
  15241.        if (ferror(Fp))
  15242.            {
  15243.            fprintf(stderr, "\"%s\": Error Writing.\n", File);
  15244.            exit (1);
  15245.            }
  15246.        if (fseek(Fp, 0L, SEEK_SET) != 0)
  15247.            {
  15248.            fprintf(stderr, "\"%s\": Error Seeking.\n", File);
  15249.            exit (1);
  15250.            }
  15251.        ++Count;
  15252.        if (fwrite(&Count, 1, sizeof(int), Fp) != sizeof(int))
  15253.            {
  15254.            fprintf(stderr, "\"%s\": Error Writing\n", File);
  15255.            exit (1);
  15256.            }
  15257.        return;
  15258.    }
  15259.    Make()
  15260.    {
  15261.        if ((Fp = fopen(File, "w+")) == NULL)
  15262.            {
  15263.            fprintf(stderr, "\"%s\": Can't Create\n", File);
  15264.            exit (1);
  15265.            }
  15266.        Count = 0;
  15267.        if (fwrite(&Count, 1, sizeof(int), Fp) != sizeof(int))
  15268.            {
  15269.            fprintf(stderr, "\"%s\": Error Creating\n", File);
  15270.            exit (1);
  15271.            }
  15272.    }
  15273.    ──────────────────────────────────────────────────────────────────────────
  15274.  
  15275.    Listing 10-5.  The PHONE.C program.
  15276.  
  15277.    The PHONE.C program might seem more complex than it really is. We included
  15278.    many error-checking routines to prevent the user from making careless
  15279.    errors. Note how the program checks the first character of each input line
  15280.    for a zero character (*Name == '\0'). This shows that the user pressed
  15281.    Enter without typing any information.
  15282.  
  15283.  Moving with the rewind() Function
  15284.  
  15285.    Moving to the beginning of a file (rewinding) is so common in C programs
  15286.    that the standard C Library includes a special function to perform that
  15287.    task. Called rewind(), it takes a single argument──a file pointer for the
  15288.    opened file──and moves the position of the next read or write to the
  15289.    beginning of the file. Consider the following:
  15290.  
  15291.      rewind(fp);
  15292.  
  15293.    rewind() returns no value and therefore gives no indication of failure.
  15294.    Other than this difference, however, the above rewind() is identical to
  15295.    the following fseek():
  15296.  
  15297.      fseek( fp, OL, SEEK_SET)
  15298.                  │     └────────────────────── Move from beginning of file
  15299.                  └────────────────────────────────── Offset must be a long
  15300.  
  15301.  Determining Position in a File with ftell()
  15302.  
  15303.    Moving through a file with fseek() often requires that you first know your
  15304.    current position in the file. When you pass the ftell() function a file
  15305.    pointer, it returns your present position in that file. That position, a
  15306.    long value, is the measure in bytes from the beginning of the file.
  15307.    Consider the following:
  15308.  
  15309.      if ((pos = ftell(fp)) == -1L)
  15310.      {
  15311.            /* can't find position */
  15312.      }
  15313.      /* current position is pos bytes from beginning */
  15314.  
  15315.    Used in that way, ftell() is identical to the following fseek() call:
  15316.  
  15317.      if ((pos = fseek(fp, 0L, SEEK_CUR)) == -1L)
  15318.      {
  15319.           /* can't find position */
  15320.      }
  15321.      /* current position is pos bytes from beginning */
  15322.  
  15323.    As you progress in learning C, you will find need for functions that we
  15324.    have not covered in our discussions. For a complete summary of top-level
  15325.    (stream) I/O routines, refer to Section 4.8 of the Microsoft QuickC
  15326.    Run-Time Library Reference.
  15327.  
  15328.  
  15329.  Mid-level (Unbuffered) File I/O
  15330.  
  15331.    Most of the top-level (buffered) stream file input/output functions have
  15332.    mid-level, unbuffered counterparts that permit direct access to disk
  15333.    files. Because they do not buffer data, they are frequently faster and
  15334.    more efficient, often allowing disk files to be read directly into a
  15335.    program's memory. (The top-level fread() function, for example, actually
  15336.    calls the mid-level read() to do its work.)
  15337.  
  15338.    One disadvantage of the unbuffered routines is that they offer only the
  15339.    most basic of services. Although these routines offer a read() and a
  15340.    write(), there are no corresponding mid-level versions of fgets(),
  15341.    fputs(), fscanf(), fprintf(), or fgetc(). Another disadvantage is that you
  15342.    cannot use unbuffered functions in the same program that uses calls to
  15343.    top-level functions. If you mix them, as shown in Figure 10-3, you risk
  15344.    losing synchronization of data. That is, if you first call fgetc(), then
  15345.    call read(), the read() will not begin with the next byte following the
  15346.    fgetc(). The fgetc() reads and buffers 512 bytes from the file, then it
  15347.    returns the first one of those buffered bytes. The call to read(),
  15348.    however, reads a single byte directly from the disk.
  15349.  
  15350.                                    512-byte buffer
  15351.                               ┌─┌────────────────────┐
  15352.                               │ │    Now is the      │  'N'
  15353.                               │ │    time...         ├──────────┐
  15354.    fgetc() reads and buffers  │ └───────────────────┘          │
  15355.    512 bytes at a time ───────┤           │                     │
  15356.                               │ ┌─────────┴──────────┐          │
  15357.       ┌────────────────┐      │ │     Top-level      │        ┌──────────────
  15358.       │                ├──────┼│     fgetc()        │        │
  15359.       │ File: "Now is  │      └─└────────────────────┘        │    Your
  15360.       │  the time..."  │                                      │    program
  15361.       │                │        ┌────────────────────┐        │
  15362.       │                ├───────│     Mid-level      │        └──────────────
  15363.       └────────────────┘        │     read()         ├──────────┘
  15364.                                 └────────────────────┘  'N'
  15365.                                   │
  15366.                 read() reads ─────┘
  15367.                 only one byte
  15368.  
  15369.    Figure 10-3. Data synchronization is lost when you mix buffered with
  15370.    unbuffered file I/O routines.
  15371.  
  15372.  Opening a File with open()
  15373.  
  15374.    Unlike fopen(), open() returns its identifying value as a simple integer.
  15375.    This value, called a "file descriptor," is later passed to all other
  15376.    mid-level routines. To use the open() function, you must specify #include
  15377.    <fcntl.h> (not <stdio.h>, as you would with fopen()), as follows:
  15378.  
  15379.      #include <fcntl.h>
  15380.      ...
  15381.      int fd;──────────────────────────────────────────────The file descriptor
  15382.      ...
  15383.      if ((fd = open(filename, oflag)) < 0)
  15384.      {
  15385.             /* handle error here */
  15386.      }
  15387.  
  15388.    The file descriptor, fd, is type int. The first argument, filename, is a
  15389.    string or the address of a string, and the second, oflag, is an int that
  15390.    supplies open() with a file activity (read, write, append, create) and a
  15391.    file mode (text or binary). The values for oflag are defined in fcntl.h,
  15392.    and their meanings are listed in Table 10-5. Note that you can combine
  15393.    oflag values by using the bitwise OR operator (|). For example, the
  15394.    following declaration opens the file TEST.EXE for reading in binary mode:
  15395.  
  15396.      fd = open("TEST.EXE", O_BINARY | O_RDONLY)
  15397.                                │    │     └────────────── For reading only
  15398.                                │    └─── Combined with bitwise OR operator
  15399.                                └────────────────────── Open in binary mode
  15400.  
  15401.    If it fails, open() returns a negative integer value. Thus, all file
  15402.    descriptor values are greater than or equal to zero.
  15403.  
  15404.    Table 10-5 Values for oflag Declared in fcntl.h
  15405.    Value                                Description
  15406.    ──────────────────────────────────────────────────────────────────────────
  15407.    O_RDONLY                             Accesses as read-only.
  15408.    O_RDWR                               Accesses as read-write.
  15409.    O_WRONLY                             Accesses as write-only.
  15410.    O_BINARY                             Sets mode for a binary file.
  15411.    O_TEXT                               Sets mode for a text file.
  15412.    O_APPEND                             Opens for appending.
  15413.    O_CREAT                              Creates file if it doesn't exist.
  15414.    O_EXEL                               Returns error if file already exists.
  15415.    O_TRUNC                              Truncates existing file to zero
  15416.                                         length.
  15417.    ──────────────────────────────────────────────────────────────────────────
  15418.  
  15419.    Of the possible values for oflag, you must use one of the first three
  15420.    activities in Table 10-5, (O_RDONLY, O_RDRW, or O_WRONLY); all others in
  15421.    the table are optional and can be added using bitwise OR. Unless specified
  15422.    otherwise, the mode is set for a text file; reads and writes begin at the
  15423.    start of the file; the file is not created if it doesn't exist; and the
  15424.    file is not truncated.
  15425.  
  15426.    If you combine the O_CREAT value with O_RDWR or O_WRONLY to create a file,
  15427.    open() requires a third argument called pmode ("permissions" mode). Use
  15428.    the argument as follows:
  15429.  
  15430.      fd = open(filename, oflag, pmode);
  15431.                            │    └The permissions of the newly created file
  15432.                            └──────────────────(O_RDWR or O_WRONLY|O_CREAT)
  15433.  
  15434.    The possible values for pmode, listed in Table 10-6, determine whether
  15435.    the created file will be a read-only file, a write-only file, or a
  15436.    readable and writable file. (You must combine the two defined pmode values
  15437.    with a bitwise OR operator to create a readable and writable file.)
  15438.    Because pmode values are defined in sys\stat.h>, you must specify the
  15439.    following include files to create a file with open():
  15440.  
  15441.      #include <fcntl.h>──────────────────────────────────────For oflag values
  15442.      #include <sys\types.h>────────────────────────────────────────For stat.h
  15443.      #include <sys\stat.h>───────────────────────────────────For pmode values
  15444.  
  15445.    Note that #include <sys\types.h> must always precede #include <sys\stat.h>
  15446.    because the first contains the definitions needed by the second.
  15447.  
  15448.    With MS-DOS, you cannot create a file that is write-only. Because all
  15449.    files are always readable, you can omit the S_IREAD value for pmode. (If
  15450.    you do use the value, MS-DOS ignores it.)
  15451.  
  15452.    The following example is a complete call to open(), including all the
  15453.    #include directives:
  15454.  
  15455.      #include <fcntl.h>
  15456.      #include <sys\types.h>
  15457.      #include <sys\stat.h>
  15458.  
  15459.      int fd;
  15460.  
  15461.      fd = open("TEST.EXE", O_RDWR|O_BINARY|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE);
  15462.  
  15463.    This example opens a file named TEST.EXE in binary mode for reading and
  15464.    writing. It creates the file if it doesn't exist, and truncates it if it
  15465.    does.
  15466.  
  15467.    Table 10-6 Values for pmode from <sys\stat.h>
  15468.    ──────────────────────────────────────────────────────────────────────────
  15469.    S_IWRITE                             Creates a writable file.
  15470.    S_IREAD                              Creates a readable file.
  15471.    ──────────────────────────────────────────────────────────────────────────
  15472.  
  15473.  Closing a File with close()
  15474.  
  15475.    Just as fclose() closes a file based on a file pointer, the unbuffered
  15476.    close() library function closes a file based on a file descriptor, as
  15477.    follows:
  15478.  
  15479.      if (close(fd) != 0)
  15480.      {
  15481.            /* handle error closing here */
  15482.      }
  15483.  
  15484.    A successfully executed close() returns a zero value; any nonzero return
  15485.    value indicates an error.
  15486.  
  15487.    When your program exits, QuickC closes all files opened with the mid-level
  15488.    open(). Because you can have only 20 files open at one time, you should
  15489.    close files inside your program. Closing a file with close() frees that
  15490.    file's file descriptor for reuse.
  15491.  
  15492.  Writing to a File with write()
  15493.  
  15494.    The write() function is used to write to files. It is simpler to use than
  15495.    the top-level fwrite() function because it requires only three arguments,
  15496.    as in the following:
  15497.  
  15498.      write(fd_out, buf, bytes)
  15499.            └──┬─┘   │     └────────────────────── Number of bytes to write
  15500.               │     └───────────────────── Where to write those bytes from
  15501.               └───────────── File descriptor for a file opened for writing
  15502.  
  15503.    The expression buf is the address in memory of the first byte that you
  15504.    want to write to the file. That address can be any address expression, but
  15505.    it is usually the address of an array. The final argument, bytes,
  15506.    represents the number of characters you want to write to the file.
  15507.  
  15508.    The write() function normally returns the number of bytes written (the
  15509.    same value as bytes). If write() fails, however, it returns a smaller or
  15510.    negative number.
  15511.  
  15512.    The SCRSAVE.C program (Listing 10-6) demonstrates one way to use open()
  15513.    and write(). It copies the contents of the text screen into a local
  15514.    buffer, which is then written to a disk file. (The program will not
  15515.    overwrite an existing file.)
  15516.  
  15517.    ──────────────────────────────────────────────────────────────────────────
  15518.    /* scrsave.c  --  demonstrates write() by saving the */
  15519.    /*                text screen to a file              */
  15520.  
  15521.    #include <stdio.h>        /* for stderr              */
  15522.    #include <fcntl.h>        /* for O_CREAT | O_BINARY  */
  15523.    #include <sys\types.h>    /* for stat.h              */
  15524.    #include <sys\stat.h>     /* for S_IREAD | S_IWRITE  */
  15525.  
  15526.    #define SCRCHARS  (25 * 80)
  15527.    int Buf[SCRCHARS];
  15528.    main(argc, argv)
  15529.    int argc;
  15530.    char *argv[];
  15531.    {
  15532.        int *cp, *ep, fname[16];
  15533.        int far *sp;
  15534.        int fd_out, bytes;
  15535.  
  15536.        if (argc != 2)
  15537.            {
  15538.            fprintf(stderr, "usage: scrsave file\n");
  15539.            exit(0);
  15540.            }
  15541.        if (strlen(argv[1]) > 8)
  15542.            {
  15543.            fprintf(stderr, "\"%s\": Filename too long.\n", argv[1]);
  15544.            exit(1);
  15545.            }
  15546.        strcpy(fname, argv[1]);
  15547.        strcat(fname, ".SCR");
  15548.        if (access(fname, 0) == 0)
  15549.            {
  15550.            fprintf(stderr, "\"%s\": Won't overwrite.\n", fname);
  15551.            exit(1);
  15552.            }
  15553.        if ((fd_out = open(fname, O_WRONLY | O_CREAT | O_BINARY,
  15554.                           S_IREAD | S_IWRITE)) < 0)
  15555.            {
  15556.            fprintf(stderr, "\"%s\": Can't create.\n", fname);
  15557.            exit(1);
  15558.            }
  15559.        /* Copy the screen into a near buffer. */
  15560.        ep = &Buf[SCRCHARS - 1];
  15561.        cp = Buf;
  15562.        /* use 0xB8000000 for EGA or VGA */
  15563.        sp = (int far *)(0xB0000000);
  15564.        for (; cp < ep; ++cp, ++sp)
  15565.            *cp = *sp;
  15566.        /* Write it. */
  15567.        bytes = write(fd_out, Buf, SCRCHARS * 2);
  15568.        if (bytes != SCRCHARS * 2)
  15569.            {
  15570.            fprintf(stderr, "\"%s\": Error writing.\n", fname);
  15571.            exit(1);
  15572.            }
  15573.    }
  15574.    ──────────────────────────────────────────────────────────────────────────
  15575.  
  15576.    Listing 10-6.  The SCRSAVE.C program.
  15577.  
  15578.    Note that we copy the screen rather than write it directly because write()
  15579.    expects a normal pointer, whereas accessing the screen requires a far
  15580.    pointer.
  15581.  
  15582.  Reading a File with read()
  15583.  
  15584.    Use the read() function to read from files. It is a simpler function to
  15585.    use than fread() because it takes only three arguments, as follows:
  15586.  
  15587.      read(fd_in, buf, bytes)
  15588.             │     │     └───────────────────────── Number of bytes to read
  15589.             │     └──────────────────────────── Where to place those bytes
  15590.             └─────────────── File descriptor for a file opened for reading
  15591.  
  15592.    In this example, buf is either an array or the address of allocated
  15593.    memory. Be sure it is large enough to hold the number of bytes specified
  15594.    by the argument bytes, however, because the compiler does not check this
  15595.    for you.
  15596.  
  15597.    If the call to read() is successful, it returns the same value as bytes.
  15598.    If it returns a smaller value, then that value represents the number of
  15599.    bytes left in the file. A zero return value signifies the end of the file,
  15600.    and a -1 return value shows that a read error occurred.
  15601.  
  15602.    The SCRREST.C program (Listing 10-7) reads a file, copying as much as a
  15603.    screenful of what it reads to text-screen memory. It works with any file
  15604.    type, but reading files created with SCRSAVE.C (Listing 10-6) is its most
  15605.    useful application. Before you run the program, pull down the Debug menu
  15606.    and activate Screen Swapping On.
  15607.  
  15608.    ──────────────────────────────────────────────────────────────────────────
  15609.    /* scrrest.c  --  demonstrates read() by restoring */
  15610.    /*                text screen from any file        */
  15611.  
  15612.    #include <stdio.h>        /* for stderr              */
  15613.    #include <fcntl.h>        /* for O_RDONLY | O_BINARY */
  15614.  
  15615.    #define SCRCHARS  (25 * 80)
  15616.    int Buf[SCRCHARS];
  15617.  
  15618.    main(argc, argv)
  15619.    int argc;
  15620.    char *argv[];
  15621.    {
  15622.        int *cp, *ep;
  15623.        int far *sp;
  15624.        int fd_in, bytes;
  15625.  
  15626.        if (argc != 2)
  15627.            {
  15628.            fprintf(stderr, "usage: scrrest file.scr\n");
  15629.            exit(0);
  15630.            }
  15631.        if ((fd_in = open(argv[1], O_RDONLY | O_BINARY)) < 0)
  15632.            {
  15633.            fprintf(stderr, "\"%s\": Can't open to read.\n", argv[1]);
  15634.            exit(1);
  15635.            }
  15636.        /* Read it. */
  15637.        bytes = read(fd_in, Buf, SCRCHARS * 2);
  15638.        if (bytes < 0)
  15639.            {
  15640.            fprintf(stderr, "\"%s\": Error Reading.\n", argv[1]);
  15641.            exit(1);
  15642.            }
  15643.        if (bytes == 0)
  15644.            {
  15645.            fprintf(stderr, "\"%s\": Empty File.\n", argv[1]);
  15646.            exit(1);
  15647.            }
  15648.        /* Copy the buffer to screen memory. */
  15649.        ep = &Buf[bytes / 2];
  15650.        cp = Buf;
  15651.  
  15652.        /* use 0xB8000000 for EGA or VGA */
  15653.        sp = (int far *)(0xB0000000);
  15654.        for (; cp < ep; ++cp, ++sp)
  15655.            *sp = *cp;
  15656.    }
  15657.    ──────────────────────────────────────────────────────────────────────────
  15658.  
  15659.    Listing 10-7.  The SCRREST.C program.
  15660.  
  15661.  Positioning with lseek()
  15662.  
  15663.    The unbuffered lseek() function lets a program position its next read or
  15664.    write to begin anywhere in a file. Almost identical to the buffered
  15665.    fseek(), lseek() takes a file descriptor as its first argument, rather
  15666.    than a file pointer. Therefore, use the lseek() function as follows:
  15667.  
  15668.      #include <io.h>      /* defines lseek()    */
  15669.      #include <stdio.h>   /* for origin, etc.   */
  15670.  
  15671.      long newpos, offset = 100L;
  15672.      int  fd;
  15673.  
  15674.      newpos = lseek(fd, offset, origin);
  15675.        │            │      │      └─── From where (current, begin, or end)
  15676.        │            │      └───────────────── Move this many bytes forward
  15677.        │            └────────────────────── In this file (file descriptor)
  15678.        └───────────────────────────────────────────── New position in file
  15679.  
  15680.    In this example, fd is a file descriptor for a file previously opened with
  15681.    open(). The second argument, offset, is the number of bytes to move in the
  15682.    file and must be of the type long. If offset is negative, you move toward
  15683.    the beginning of the file. The last argument, origin, can be one of the
  15684.    three possible definitions that specify where the move begins. These
  15685.    definitions are the same as those used by fseek(), which were mentioned in
  15686.    Table 10-4 on p. 305. Also, as with fseek(), you must specify #include
  15687.    <stdio.h> to access those definitions.
  15688.  
  15689.    After a successful repositioning, lseek() returns the new position in the
  15690.    file. A return value of -1L indicates an error. (Note that lseek() returns
  15691.    the type long.)
  15692.  
  15693.    The VIEW.C program (Listing 10-8) is a simple file-viewing program that
  15694.    illustrates how to use lseek() to move through a file. Pressing + moves
  15695.    you forward in the file, pressing - moves you backward, and typing q or Q
  15696.    ends the program.
  15697.  
  15698.    ──────────────────────────────────────────────────────────────────────────
  15699.    /* view.c  --  demonstrates lseek() by displaying  */
  15700.    /*             a file and moving around in it      */
  15701.  
  15702.    #include <fcntl.h>        /* for open()         */
  15703.    #include <stdio.h>        /* for SEEK_CUR, etc. */
  15704.  
  15705.    #define HUNK 512
  15706.    #define MOVE 512L
  15707.  
  15708.    main(argc, argv)
  15709.    int argc;
  15710.    char *argv[];
  15711.    {
  15712.        char ch, buf[HUNK];
  15713.        long position = 0L;
  15714.        int  bytes, eofflag = 0, fd_in;
  15715.  
  15716.        if (argc != 2)
  15717.            {
  15718.            fprintf(stderr, "Usage: view file\n");
  15719.            exit(0);
  15720.            }
  15721.  
  15722.        if ((fd_in = open(argv[1], O_RDONLY)) < 0)
  15723.            {
  15724.            fprintf(stderr, "\"%s\": Can't open.\n", argv[1]);
  15725.            exit(1);
  15726.            }
  15727.  
  15728.        for (;;)
  15729.            {
  15730.            bytes = read(fd_in, buf, HUNK);
  15731.            if (bytes == 0)
  15732.                {
  15733.                if (! eofflag)
  15734.                    {
  15735.                    fprintf(stderr, "\n<<at end of file>>\n");
  15736.                    ++eofflag;
  15737.                    }
  15738.                else
  15739.                    exit(0);
  15740.                }
  15741.            else if (bytes < 0)
  15742.                {
  15743.                fprintf(stderr, "\"%s\": Error Reading.\n", argv[1]);
  15744.                exit(1);
  15745.                }
  15746.            else
  15747.                {
  15748.                eofflag = 0;
  15749.                position = lseek(fd_in, 0L, SEEK_CUR);
  15750.                if (position == -1L)
  15751.                    {
  15752.                    fprintf(stderr, "\"%s\": Error Seeking.\n", argv[1]);
  15753.                    exit(1);
  15754.                    }
  15755.                Print(buf, bytes);
  15756.                do
  15757.                    {
  15758.                    ch = getch();
  15759.                    if (ch == 'q' || ch == 'Q')
  15760.                        exit(0);
  15761.                    } while (ch != '+' && ch != '-');
  15762.  
  15763.                if (ch == '-')
  15764.                    {
  15765.                    position = lseek(fd_in, -2 * MOVE, SEEK_CUR);
  15766.                    if (position == -1L)
  15767.                        {
  15768.                        fprintf(stderr, "\"%s\": Error Seeking.\n", argv[1]);
  15769.                        exit(1);
  15770.                        }
  15771.                    }
  15772.                }
  15773.            }
  15774.    }
  15775.  
  15776.    Print(char *buf, int cnt)
  15777.    {
  15778.        int i;
  15779.  
  15780.        for (i = 0; i < cnt; ++i, ++buf)
  15781.            {
  15782.            if (*buf < ' ' && *buf != '\n' && *buf != '\t')
  15783.                printf("^%c", *buf + '@');
  15784.            else
  15785.                putchar(*buf);
  15786.            }
  15787.    }
  15788.    ──────────────────────────────────────────────────────────────────────────
  15789.  
  15790.    Listing 10-8.  The VIEW.C program.
  15791.  
  15792.  Finding Current Position with tell()
  15793.  
  15794.    Notice that VIEW.C finds the current position in the viewed file with the
  15795.    following:
  15796.  
  15797.      position = lseek(fd_in, 0L, SEEK_CUR);
  15798.  
  15799.    Because the need to know the current position is so common, the QuickC
  15800.    library provides the tell() function. Similar to the top-level ftell()
  15801.    routine, tell() takes a single argument, a file descriptor, and returns
  15802.    the current position in the file associated with that file descriptor.
  15803.    That position is a type long measure in bytes from the beginning of the
  15804.    file. If tell() fails for any reason, it returns a value of -1L.
  15805.  
  15806.  
  15807.  The File System
  15808.  
  15809.    Not only do programs read and write to files, they often need to manage
  15810.    the file system as a whole. By the file system, we mean the MS-DOS
  15811.    directory hierarchy, the organization of directories, and the naming of
  15812.    directories and files. For example, your program might need to create or
  15813.    remove a directory or file, or relocate in the directory hierarchy (change
  15814.    the working directory), or create unique temporary filenames. In this
  15815.    section we discuss the file system and the C Library routines that let you
  15816.    manipulate it. We also warn you of possible pitfalls and present a few
  15817.    routines that let you handle errors gracefully.
  15818.  
  15819.  Directories
  15820.  
  15821.    MS-DOS does not permit you to use fopen() or open() to open a directory.
  15822.    You can, however, create and remove directories or establish any directory
  15823.    as your current working directory. The routines for handling directories
  15824.    are listed in Table 10-7. All of the routines require that you first
  15825.    specify #include <direct.h>, which contains their declarations.
  15826.  
  15827.    The directory-handling functions chdir(), mkdir(), and rmdir() take a
  15828.    single argument──a string or the address of a string that specifies a full
  15829.    pathname (such as C:\TMP\JUNKDIR), or a directory name relative to the
  15830.    current working directory (such as JUNKDIR). All three return an integer 0
  15831.    if they are successful; otherwise, they return a -1. Consider, for
  15832.    example, the code fragment on the next page.
  15833.  
  15834.    Table 10-7 The Directory-Handling Library Functions
  15835.    ──────────────────────────────────────────────────────────────────────────
  15836.    chdir(path)    Changes the current working directory to path. Returns 0 if
  15837.                   successful.
  15838.    mkdir(path)    Creates a new directory named path. Returns 0 if
  15839.                   successful.
  15840.    rmdir(path)    Removes the directory whose name is path. Returns 0 if
  15841.                   successful.
  15842.    getcwd(buf, n) Places the full pathname of your current working directory
  15843.                   into the char buffer buf of length n. Returns NULL if an
  15844.                   error occurs.
  15845.    ──────────────────────────────────────────────────────────────────────────
  15846.  
  15847.      #include <direct.h>
  15848.  
  15849.      if (chdir("C:\\TMP") != 0)
  15850.      {
  15851.              /* chdir failed, so exit */
  15852.      }
  15853.      if (mkdir("JUNKDIR") != 0)
  15854.      {
  15855.              /* mkdir failed, so exit */
  15856.      }
  15857.      if (rmdir("JUNKDIR") != 0)
  15858.      {
  15859.              /* rmdir failed, so exit */
  15860.      }
  15861.  
  15862.    The #include <direct.h> directive provides definitions for the three
  15863.    routines that follow it. The chdir() function changes the current working
  15864.    directory to C:\TMP. (Note that in C you must use a double backslash to
  15865.    produce a single backslash.) Next, inside C:\TMP, the program uses mkdir()
  15866.    to create a new subdirectory called JUNKDIR. The final call to rmdir()
  15867.    removes that same subdirectory.
  15868.  
  15869.    The last routine in Table 10-7, getcwd() ("get current working
  15870.    directory"), takes two arguments and returns the address of a string. You
  15871.    can call this function using one of two forms. In the following form:
  15872.  
  15873.      #include <direct.h>
  15874.      #include <stdio.h>   /* for NULL */
  15875.  
  15876.      char buf[512];
  15877.      if (getcwd(buf, 512) == NULL)
  15878.      {
  15879.            /* couldn't get current working directory */
  15880.      }
  15881.  
  15882.    The getcwd() function is passed the address of a char buffer, buf, into
  15883.    which it places the name of the current working directory. The length 512
  15884.    is the number of bytes in the buffer. (Remember that the buffer must be
  15885.    large enough for both the name and a terminating '\0'.)
  15886.  
  15887.    The second form for calling getcwd() is as follows:
  15888.  
  15889.      #include <direct.h>
  15890.      #include <stdio.h>   /* for NULL */
  15891.  
  15892.      char *name;
  15893.      if ((name = getcwd(NULL, 0)) == NULL)
  15894.      {
  15895.            /* couldn't get current working directory */
  15896.      }
  15897.  
  15898.    This form passes getcwd(), the special zero address NULL, and a length of
  15899.    zero. This causes getcwd to use malloc() to allocate enough space for the
  15900.    name of the current working directory name (plus 1 for the terminating
  15901.    '\0'), to copy that name into the newly allocated space, and to return the
  15902.    address of that space. Both forms of getcwd() return NULL if the operation
  15903.    fails.
  15904.  
  15905.    The DIRX.C program (Listing 10-9) demonstrates all four of the
  15906.    directory-handling subroutines. It first creates a subdirectory in the
  15907.    current directory, then relocates to that subdirectory and creates a
  15908.    sub-subdirectory. Finally, it returns to the original directory and
  15909.    attempts to remove the first subdirectory it created. It fails at this
  15910.    point because it is illegal to remove a subdirectory that is not empty. If
  15911.    you run the program again, it will fail immediately──it cannot execute the
  15912.    first mkdir() because a directory with that name already exists.
  15913.  
  15914.    ──────────────────────────────────────────────────────────────────────────
  15915.    /* dirx.c  --  directory examples  */
  15916.  
  15917.    #include <direct.h>
  15918.    #include <stdio.h>
  15919.  
  15920.    #define SUBDIR "SUBDIR"
  15921.    #define SUBSUBDIR "SUBSUB"
  15922.  
  15923.    main()
  15924.    {
  15925.        char *current_dir;
  15926.        void Err();
  15927.  
  15928.        if ((current_dir = getcwd(NULL, 0)) == NULL)
  15929.            Err("getcwd()", "Can't get current directory.");
  15930.  
  15931.        if (mkdir(SUBDIR) != 0)
  15932.            Err(SUBSUBDIR, "Can't make directory.");
  15933.  
  15934.        if (chdir(SUBDIR) != 0)
  15935.            Err(SUBDIR, "Can't cd into directory.");
  15936.  
  15937.        if (mkdir(SUBSUBDIR) != 0)
  15938.            Err(SUBSUBDIR, "Can't make directory.");
  15939.  
  15940.        if (chdir(current_dir) != 0)
  15941.            Err(SUBDIR, "Can't cd back to.");
  15942.  
  15943.        if (rmdir(SUBDIR) != 0)
  15944.            Err(SUBDIR, "Can't remove directory.");
  15945.  
  15946.    }
  15947.  
  15948.    void Err(char *what, char *msg)
  15949.    {
  15950.        fprintf(stderr, "\"%s\": %s\n", what, msg);
  15951.        exit (1);
  15952.    }
  15953.    ──────────────────────────────────────────────────────────────────────────
  15954.  
  15955.    Listing 10-9.  The DIRX.C program.
  15956.  
  15957.  Manipulating Files by Name
  15958.  
  15959.    Several standard C Library routines make it easy for you to remove and
  15960.    rename files and also to create unique filenames from within a program.
  15961.    These routines (listed in Table 10-8) are useful in databases, compilers,
  15962.    games, and any other program that needs to manipulate files.
  15963.  
  15964.    The routines unlink() and remove() are identical. Each takes a single
  15965.    argument──the address of a string──and erases (removes from the disk) the
  15966.    file whose name is specified in that string. The filename that you specify
  15967.    can either be a full path such as C:\TMP\JUNK, which removes the file JUNK
  15968.    from the directory C:\TMP, or it can be a relative pathname such as JUNK,
  15969.    in which case the called routine removes the file JUNK from the current
  15970.    working directory.
  15971.  
  15972.    The rename() function can do more than merely rename files. It can rename
  15973.    directories and move files from one directory to another (but not from one
  15974.    disk to another). Consider the following example, in which JUNK is a file
  15975.    and DIR1 and DIR2 are directories:
  15976.  
  15977.      rename("JUNK", "OLDJUNK");─────────────────────────────────Rename a file
  15978.      rename("DIR1\\JUNK", "DIR2\\JUNK");──────────────────────────Move a file
  15979.      rename("DIR1", "OLDDIR1");────────────────────────────Rename a directory
  15980.  
  15981.    The first line renames the file JUNK in the current working directory as
  15982.    OLDJUNK; the second line moves the file JUNK in the subdirectory DIR1 into
  15983.    the subdirectory DIR2. Note that you could have renamed JUNK during the
  15984.    move. Also remember that, in C, you must use two backslashes to produce a
  15985.    single backslash.
  15986.  
  15987.    The third line of the above example renames the directory DIR1 as OLDDIR1.
  15988.    It is important to note that directories, unlike files, cannot be moved.
  15989.  
  15990.    Table 10-8 Routines That Manipulate Files by Name
  15991.    ──────────────────────────────────────────────────────────────────────────
  15992.    unlink(path)   Removes (erases) the file whose name is specified by path.
  15993.                   Returns 0 if the call is successful.
  15994.    remove(path)   Same as unlink().
  15995.    rename(old,    Renames the file old, giving it the new name new. Also
  15996.    new)           allows the renaming of directories. Files can be moved with
  15997.                   this routine. Returns 0 if successful.
  15998.    mktemp(tmplt)  Fills out the template tmplt with a filename that does not
  15999.                   already exist.
  16000.    ──────────────────────────────────────────────────────────────────────────
  16001.  
  16002.    The mktemp() function generates a unique filename that is guaranteed not
  16003.    to exist on your disk. Use it as follows:
  16004.  
  16005.      #include <io.h>     /* defines mktemp() */
  16006.      #include <stdio.h>  /* for NULL */
  16007.  
  16008.      static char template[] = "C:\\TMP\\XXXXXX";
  16009.  
  16010.      if (mktemp(template) == NULL)
  16011.      {
  16012.           /* No unique name possible */
  16013.      }
  16014.  
  16015.    First we specify #include <io.h> for the definition of mktemp(). In that
  16016.    header file, mktemp() is defined as returning the address of a string
  16017.    (that is, char *). We also must use #include <stdio.h> to define NULL,
  16018.    which mktemp() returns if it fails.
  16019.  
  16020.    The template passed to mktemp() must take the form baseXXXXXX; that is, it
  16021.    may be any prefix, path, or part of a filename, ending with six X
  16022.    characters. The mktemp() function replaces the X characters with one
  16023.    alphanumeric character followed by five digits, thus forming a unique name
  16024.    (one that does not already exist on the disk), such as A00000.
  16025.  
  16026.    The FMENU.C program (Listing 10-10) uses all of these routines within a
  16027.    small file-handling menu program. It enables you to rename/move a file or
  16028.    directory, remove a file, or create a unique file. You can use FMENU.C as
  16029.    the core of your own programs that let the user control files without
  16030.    exiting to MS-DOS. Before you compile and run FMENU.C, follow the steps
  16031.    outlined in the box on page 325, "Making New Library Routines Available
  16032.    to QuickC."
  16033.  
  16034.    ──────────────────────────────────────────────────────────────────────────
  16035.    /* fmenu.c  --  demonstrates file renaming, etc. */
  16036.  
  16037.    #include <direct.h>
  16038.    #include <stdio.h>
  16039.    #include <string.h>
  16040.  
  16041.    #define MAXPATH (80)
  16042.    char From_name[MAXPATH],
  16043.         To_name[MAXPATH];
  16044.  
  16045.    int Input(char *prompt, char buf[])
  16046.    {
  16047.        printf("%s: ", prompt);
  16048.        if (gets(buf) == NULL || *buf == '\0')
  16049.            return (0);
  16050.        return (1);
  16051.    }
  16052.    void Rename(void)
  16053.        {
  16054.        printf("->Rename/move\n");
  16055.        if (!Input("From", From_name)) return;
  16056.        if (!Input("To", To_name)) return;
  16057.        if (rename(From_name, To_name) != 0)
  16058.            perror("RENAME");
  16059.        else
  16060.            printf("Renamed: \"%s\" -> \"%s\"\n",
  16061.                    From_name, To_name);
  16062.    }
  16063.    void Remove(void)
  16064.    {
  16065.        printf("->Remove\n");
  16066.        if (!Input("Remove", From_name)) return;
  16067.        if (!Input("Are You Sure", To_name)) return;
  16068.        if (*To_name != 'y' && *To_name != 'Y')
  16069.            return;
  16070.        if (remove(From_name) != 0)
  16071.            perror(From_name);
  16072.        else
  16073.            printf("Removed: \"%s\"\n", From_name);
  16074.    }
  16075.    void Maketemp(void)
  16076.    {
  16077.        printf("->Maketemp\n");
  16078.        if (!Input("In What Directory", From_name))
  16079.            return;
  16080.        (void)strcat(From_name, "\\XXXXXX");
  16081.        if (mktemp(From_name) == NULL)
  16082.            printf("Can't create a unique name.\n");
  16083.        else
  16084.            printf("Created: \"%s\"\n", From_name);
  16085.    }
  16086.    void Quit(void)
  16087.    {
  16088.        printf("->Quit\n");
  16089.        if (!Input("Are You Sure", From_name))
  16090.            return;
  16091.        if (*From_name != 'y' && *From_name != 'Y')
  16092.            return;
  16093.        exit(0);
  16094.    }
  16095.  
  16096.    main()
  16097.    {
  16098.        static void (*doit[])() = {Rename, Remove, Maketemp, Quit};
  16099.        int ch;
  16100.        while (1)
  16101.            {
  16102.            printf("--------------------------------------------\n");
  16103.            printf("1) Rename/move a file or rename a directory.\n");
  16104.            printf("2) Remove a file.\n");
  16105.            printf("3) Make a unique temporary file.\n");
  16106.            printf("4) Quit.\n");
  16107.            printf("--------------------------------------------\n");
  16108.            printf("Select: ");
  16109.  
  16110.            do
  16111.                {
  16112.                ch = getchar();
  16113.                } while (ch < '1' || ch > '4');
  16114.            getchar();    /* gobble trailing newline */
  16115.            printf("%c\n\n", ch);
  16116.            ch -= '1';
  16117.            doit[ch]();
  16118.            }
  16119.    }
  16120.    ──────────────────────────────────────────────────────────────────────────
  16121.  
  16122.    Listing 10-10.  The FMENU.C program.
  16123.  
  16124.    FMENU.C uses a technique we discussed in Chapter 8──an array of pointers
  16125.    to functions. Each menu choice corresponds to a function in that array,
  16126.    and each of those functions utilizes a different routine for file
  16127.    manipulation. Note that FMENU.C contains an error-printing routine you
  16128.    haven't seen before──perror().
  16129.  
  16130.  Printing Clear and Meaningful Diagnostics with perror()
  16131.  
  16132.    All C programs use a system-defined global variable called errno, which is
  16133.    set and cleared with each system or I/O call. A standard C Library routine
  16134.    called perror() prints an appropriate error message based on the current
  16135.    value in errno. For example, suppose an fopen() for reading a file named
  16136.    JUNK fails because the file didn't exist. In that case QuickC sets errno
  16137.    to 2, and perror(), when called as
  16138.  
  16139.      perror("JUNK");
  16140.  
  16141.    prints the following to the standard error output:
  16142.  
  16143.      JUNK: No such file or directory
  16144.  
  16145.    Using perror() helps your program generate clearer and more meaningful
  16146.    diagnostic messages. However, remember to call perror() immediately after
  16147.    a library routine returns an error. If you call another library routine
  16148.    before perror(), it might change errno and cause perror() to print an
  16149.    incorrect message. For example,
  16150.  
  16151.      if((fp = fopen(fname, "rb")) == NULL)
  16152.      {
  16153.          fprintf(stderr, "Program Aborted because\n");
  16154.          perror(fname);
  16155.          exit(1);
  16156.      }
  16157.  
  16158.    does not work because the fprintf() preceding perror() succeeds and thus
  16159.    sets errno to zero, causing perror() to print the incorrect message
  16160.    Undefined error.
  16161.  
  16162.  
  16163.  Advanced Error Handling
  16164.  
  16165.    A program that can recover from any error is called "robust." Robust
  16166.    programs are not merely carefully written programs──they are programs that
  16167.    include library routines for handling all abnormal conditions and that
  16168.    issue clear diagnostic messages to the user. Table 10-9 lists the most
  16169.    useful routines for handling abnormal conditions.
  16170.  
  16171.    Table 10-9 Abnormal-Condition Handlers and Diagnostic Routines
  16172.    ──────────────────────────────────────────────────────────────────────────
  16173.    signal()       Traps errors that can terminate a program, such as Ctrl-C
  16174.                   and floating-point exceptions.
  16175.    setjmp()       Prepares for a jump between functions.
  16176.    longjmp()      Executes a jump between functions.
  16177.    ──────────────────────────────────────────────────────────────────────────
  16178.  
  16179.    ──────────────────────────────────────────────────────────────────────────
  16180.    Making New Library Routines Available to QuickC
  16181.    To compile and run the FMENU.C program successfully, perform the following
  16182.    steps to add a few routines to QuickC that are not normally available.
  16183.  
  16184.    1.  Create the following program and save it using F.C as its filename.
  16185.  
  16186.        #include <direct.h>
  16187.        main()
  16188.        {
  16189.            rename();
  16190.            mktemp();
  16191.            perror();
  16192.        }
  16193.  
  16194.    2.  Exit QuickC and run the following MS-DOS command line (ignore any
  16195.        warnings about actual arguments):
  16196.  
  16197.        qcl /c /am f.c
  16198.  
  16199.    3.  Run the following command line to create an add-on Quick Library:
  16200.  
  16201.        link c:\lib\quicklib.obj+f.obj,f.qlb,,/q;
  16202.  
  16203.        where c:\lib is the location for your QuickC libraries as determined
  16204.        when you ran SETUP.
  16205.  
  16206.    4.  Rerun QuickC with the following:
  16207.  
  16208.        qc /lf
  16209.  
  16210.        For a more detailed explanation of Quick Libraries, see Chapter 12 of
  16211.        this book and Section 10.1 of your Microsoft QuickC Programmer's
  16212.        Guide.
  16213.  
  16214.  Signals
  16215.  
  16216.    Signals are conditions that cause a program to terminate prematurely. The
  16217.    signals for MS-DOS are listed in signal.h: They include Ctrl-C,
  16218.    Ctrl-Break, and floating-point errors such as division by zero. A text
  16219.    editor is an example of a program that should not terminate if one of
  16220.    these conditions occurs. The user might, for example, be editing a
  16221.    temporary copy of a file──you would want to write a user's changes to disk
  16222.    before exiting, no matter what.
  16223.  
  16224.    To handle errors such as these, use the signal() function as follows:
  16225.  
  16226.      #include <signal.h>
  16227.  
  16228.      status = signal(sig, funct);
  16229.         │             │     └────── Function address or SIG_IGN or SIG_DFL
  16230.         │             └──────────── One of the signals defined in signal.h
  16231.         └──────────────────────────────────────────────── SIG_ERR on error
  16232.  
  16233.    ──────────────────────────────────────────────────────────────────────────
  16234.    Error-handling Philosophies: BASIC vs C
  16235.    Most versions of BASIC build an error-handling mechanism into the language
  16236.    in the form of the ON ERROR ... GOTO label construct. When an error is
  16237.    encountered, control switches to the appropriate label or line number.
  16238.    Although you can turn this facility on and off, you don't have fine
  16239.    control of it.
  16240.  
  16241.    To review the situation in C, each function is responsible for reporting
  16242.    errors back to its caller. This procedure is more flexible than that used
  16243.    by BASIC, but it admits some inconsistencies. Functions that return
  16244.    pointers (such as fopen(), which returns a pointer to the file opened)
  16245.    often return a null pointer, which can be tested against the predefined
  16246.    value NULL. Other functions return the value -1 to indicate an error and
  16247.    store the specific error number in the global variable errno, using
  16248.    error-number values defined in the include file errno.h. Still other
  16249.    functions cannot return error values because no values are reserved for
  16250.    that purpose: All values might conceivably be returned by normal
  16251.    operation. You can, however, use the function ferror() to find out if any
  16252.    error occurred during input or output to a particular file. If you are not
  16253.    sure how a particular function handles error conditions, a quick way to
  16254.    find out is to use QuickC's on-line help facility discussed earlier in
  16255.    this book.
  16256.  
  16257.    In return for the greater flexibility C provides, you must explicitly test
  16258.    for an error (usually by putting the function call in an if or while
  16259.    statement or by calling ferror()) and then call any error-handling
  16260.    functions.
  16261.  
  16262.    The signal mechanism (discussed in this section) provides an additional,
  16263.    UNIX-compatible way to handle error conditions reported by the operating
  16264.    system. This mechanism is similar to the BASIC mechanism in that it
  16265.    establishes a global connection between a particular error condition and
  16266.    an error-handling function.
  16267.    ──────────────────────────────────────────────────────────────────────────
  16268.  
  16269.    We specify #include <signal.h> for definitions of signal(), its return
  16270.    value, and all of the possible values for sig. The signal() function takes
  16271.    two arguments. The first specifies the type of error, the values of which
  16272.    are listed in <signal.h> and summarized for MS-DOS in Table 10-10 on the
  16273.    following page. The second argument is the name (or address) of a function
  16274.    to be called if sig occurs, or one of the two predefined values: SIG_IGN
  16275.    (ignore this signal) or SIG_DFL (resume the default action, that is,
  16276.    terminate the program). Figure 10-4 illustrates the use of signal().
  16277.  
  16278.         #include <signal.h>
  16279.         int Sigflag = 0;    /*  global  */
  16280.         main ()
  16281.         {
  16282.              extern int Funct ();
  16283.           1  if  (signal (SIGINT, Funct) == SIG_ERR)
  16284.                  {
  16285.                  printf ("Signal () failed. \n");
  16286.                  exit  (0);
  16287.                  }
  16288.              for (;;)      /* forever      */
  16289.                  {
  16290.    ┌─────────── printf ("Waiting For Ctrl-C\n");
  16291.    │      5                                   ───2 3
  16292.    │             if (Sigflag != 0)                  │
  16293.    │             break 6                            │
  16294.    │             }                                  │
  16295.    │    } 7                                         │
  16296.    │                                                │
  16297.    │    Funct ()───────────────────────────────────┘
  16298.    │    {
  16299.    │        ++Sigflag;
  16300.    │    } 4
  16301.    └─────┘
  16302.  
  16303.     1  Calling siganl() sets up the program to handle the Ctrl-C interrupt.
  16304.  
  16305.     2  User presses Ctrl-C (or Ctrl-Break) during the perpetual for loop which
  16306.        is printing Waiting for Ctrl-C at the time.
  16307.  
  16308.     3  Funct() is immediately called and increments Sigflag.
  16309.  
  16310.     4  Funct() returns and...
  16311.  
  16312.     5  the printf() statement previously interrupted is then executed (again).
  16313.  
  16314.     6  We check Sigflag and because it was set to a nonzero value when Funct()
  16315.        was called, we exit the perpetual for loop by breaking out of it.
  16316.  
  16317.     7  Program ends.
  16318.  
  16319.    Figure 10-4. Analysis of signal().
  16320.  
  16321.    As a rule, the signal-handling function, Funct(), should not perform any
  16322.    I/O operation. Rather than handling the error itself, it should set a
  16323.    global flag variable, then return to let the main body of the code handle
  16324.    the error. The main program stops, and the signal-handling function,
  16325.    Funct(), is called with the signal number sig as its argument. When
  16326.    Funct() finishes and returns, the main program continues from the exact
  16327.    point at which it stopped.
  16328.  
  16329.    Handling signals under MS-DOS is fairly simple because only six signals
  16330.    are defined, and only three of those actually do anything. However, if you
  16331.    move your code to XENIX or UNIX, you should be prepared to handle thirty
  16332.    or more signals, all of which can affect your program.
  16333.  
  16334.    Table 10-10 Signals Defined for MS-DOS
  16335.    ──────────────────────────────────────────────────────────────────────────
  16336.    SIGABRT        Abnormal program termination. Terminates the program and
  16337.                   exits with a return value of 3.
  16338.    SIGFPE         Floating-point exception (such as division by zero or an
  16339.                   invalid operation). Terminates the program.
  16340.    SIGINT         Interrupt for keyboard. Sent when the user types the key
  16341.                   sequence Ctrl-C. Terminates the program.
  16342.    ──────────────────────────────────────────────────────────────────────────
  16343.  
  16344.  Jumping Between Functions with setjmp() and longjmp()
  16345.  
  16346.    Sometimes when a signal occurs, your program might not be able to continue
  16347.    its main body of code. A signal caused by division by zero, for example,
  16348.    would result in a completely wrong answer should it continue. For
  16349.    situations such as these, when you need to jump to an earlier stage of the
  16350.    program, the standard C Library offers two functions: setjmp() and
  16351.    longjmp().
  16352.  
  16353.    setjmp() prepares the program for an eventual jump to an earlier state, as
  16354.    follows:
  16355.  
  16356.      #include <setjmp.h>
  16357.  
  16358.      jmp_buf env;
  16359.  
  16360.      if (setjmp(env) != 0)
  16361.      {
  16362.          /* We got here because of a longjmp()
  16363.             from someplace else */
  16364.      }
  16365.      /* all prepared for a longjmp() */
  16366.  
  16367.    We specify #include <setjmp.h> for the definition of jmp_buf. The variable
  16368.    env is declared as the type jump_buf and is the buffer that will hold all
  16369.    the information QuickC needs to perform a jump between functions. Next,
  16370.    the call to setjmp() prepares for an eventual call to longjmp(). The
  16371.    result of this preparation is always 0. When setjmp() returns a 0, you
  16372.    know that the program is set up for a later call to longjmp() but that the
  16373.    call has not occurred. A later call to longjmp() causes the program to
  16374.    call setjmp() again, but this time the call returns a nonzero value.
  16375.  
  16376.    Use the longjmp() routine as follows:
  16377.  
  16378.      longjmp(env, ret);
  16379.  
  16380.    The program calls longjmp() with the same env with which it called
  16381.    setjmp() earlier. The ret argument must be a nonzero number because it is
  16382.    the value returned by setjmp(). (Figure 10-5 illustrates this
  16383.    relationship.)
  16384.  
  16385.         #include <set jmp.h>
  16386.         jmp_buf Env;        /*  global  */
  16387.         main ()
  16388.         {
  16389.    ┌───── 1 if setjmp (Env)  != 0) ─────────────────────┐
  16390.    │             {                                        │
  16391.    │             printf ("Exiting at A\n");               │
  16392.    │             exit (0); A                              │
  16393.    │             }                                        │
  16394.    │                                                      │
  16395.    └─────────── printf ("Calling Foo ()\n");             │
  16396.    ┌────────── 2 Foo();                                   │
  16397.    │                                                      │
  16398.    │             printf ("Exiting at B\n");               │
  16399.    │             Exit (0); B                              │
  16400.    │    }                                                 │
  16401.    │                                                      │
  16402.    └── Foo()                                             │
  16403.         {                                                 │
  16404.                  printf ("In Foo ()\n");                  │
  16405.                                                           │
  16406.                  longjmp (Env, 1); 3 ─────────────────────┘
  16407.         }
  16408.  
  16409.     1  The first call to setjmp() returns 0, so flow continues with the first
  16410.        line after the if.
  16411.  
  16412.     2  Foo() is called.
  16413.  
  16414.     3  In Foo(), longjmp() returns us to 1. This time, however, setjmp() retur
  16415.        1, so we exit at A. Note that B is never reached.
  16416.  
  16417.    Figure 10-5. Analysis of setjmp() and longjmp().
  16418.  
  16419.  
  16420.  
  16421.  ────────────────────────────────────────────────────────────────────────────
  16422.  Chapter 11  Advanced Data Types
  16423.  
  16424.    Many programs, such as databases, spreadsheets, catalogs, and indexes,
  16425.    group information in such a way that each item needs to be a different C
  16426.    data type. (See Figure 11-1 on the following page.) To facilitate writing
  16427.    these programs, C offers a "structure" type──a special array-like form in
  16428.    which each element can be a different type.
  16429.  
  16430.    These kinds of programs also need to be able to store different types of
  16431.    data, at one time or another, at the same place in memory. The street
  16432.    number in Figure 11-1, for example, could be numeric, such as 212,
  16433.    requiring an integer variable, or it could be alphanumeric, such as 212B,
  16434.    requiring a string variable. The C union data type solves this problem by
  16435.    letting you store different types at the same place in memory.
  16436.  
  16437.    This chapter shows you how to program with structures and unions. It also
  16438.    discusses the less frequently used data types enum and bit fields.
  16439.    Finally, we'll detail typedef, an alternative to the #define preprocessor
  16440.    directive that lets you create new types from old.
  16441.  
  16442.    ┌──────────────────────────────────────────────────────────┐
  16443.    │            char             char             char        │
  16444.    │ NAME  _______________  _______________  _______________  │
  16445.    │           first             last            middle       │
  16446.    │                                                          │
  16447.    │             long                   char                  │
  16448.    │ ADDRESS  ___________  _________________________________  │
  16449.    │          street_num               street                 │
  16450.    │                                                          │
  16451.    │                char            char           long       │
  16452.    │          ________________  _____________  _____________  │
  16453.    │                city            state           zip       │
  16454.    │                                                          │
  16455.    │          int           long                              │
  16456.    │ PHONE  (______)  ___________________                     │
  16457.    │       area_code        phone                             │
  16458.    │                                                          │
  16459.    └──────────────────────────────────────────────────────────┘
  16460.  
  16461.    Figure 11-1. To enter the information on an address/phone index card into
  16462.    a computer, you need to use different data types organized as a single
  16463.    conceptual unit.
  16464.  
  16465.  
  16466.  Structure──An Array of Different Types
  16467.  
  16468.    An obvious limitation of arrays is that the variables in a single array
  16469.    must all be of the same type (all char, all int, and so on). However, you
  16470.    will frequently need to group variables of different types together so
  16471.    that you can manipulate them as a single conceptual unit. The information
  16472.    on the index card in Figure 11-1 is a good example. Because all of the
  16473.    different "types" of information actually relate to a single person, it is
  16474.    more convenient and conceptually sound to place all of that information in
  16475.    a single array. Unfortunately, arrays cannot handle different data types.
  16476.    To group strings and integers, for example, you must use a structure,
  16477.    which can hold any mixture of types, including arrays, pointers, and
  16478.    integers.
  16479.  
  16480.    Think of a structure as a special kind of array. However, whereas the
  16481.    variables in an array are called elements and are referenced by an offset,
  16482.    the variables in a structure are called "members" and are referenced by
  16483.    name.
  16484.  
  16485.    You declare a structure with the C keyword struct. The first step in
  16486.    setting up a structure is to declare a pattern, or template, for the
  16487.    variables it will contain and to give that pattern a name. A pattern for
  16488.    the structure that contains the address-book information in Figure 11-1,
  16489.    for example, appears at the top of the next page.
  16490.  
  16491.    To declare a structure pattern, follow the keyword struct with the name of
  16492.    the pattern (cardstruct). Next, list the variables, or members, of the
  16493.    structure between a set of braces. Note that although this list resembles
  16494.    a list of variable declarations, you are not allocating memory for storage
  16495.    of the structure's members──you are merely creating a template that
  16496.    reserves those names for future use.
  16497.  
  16498.         ┌───────────────────────────────────────────────────────── Keyword
  16499.         │        ┌─────────────────────────────────────────── Name of pattern
  16500.         │        │     ┌──────────────────────────── Variables between braces
  16501.      struct cardstruct {
  16502.          char *first, *last, *middle;────────────────────── Member list start
  16503.          long street_num;
  16504.          char *street, *city, *state;
  16505.          long zip;
  16506.          int area_code;
  16507.          long phone;───────────────────────────────────────── Member list end
  16508.      };
  16509.      │└──────────────────────────────────────────────────── Closing semicolon
  16510.      └────────────────────────────────────────────── Variables between braces
  16511.  
  16512.  Structure Variables
  16513.  
  16514.    To reserve memory for a structure's members, you must declare structure
  16515.    variables that follow the pattern you defined. The following declaration
  16516.    sets aside memory for two structure variables (card1 and card2) using the
  16517.    above cardstruct pattern:
  16518.  
  16519.      struct cardstruct card1, card2;
  16520.  
  16521.    This declaration starts with the keyword struct, as did the pattern, but
  16522.    this time struct is followed by the name of a previously declared pattern
  16523.    and then by the names of the structure variables. Remember, you manipulate
  16524.    card1 and card2 in the program──the pattern cardstruct merely declares new
  16525.    structures. This statement reserves memory (allocates enough storage) for
  16526.    the predefined members of those two structure variables, as shown in
  16527.    Figure 11-2.
  16528.  
  16529.    struct cardstruct card 1, card 2;
  16530.                      └────┘  └────┘
  16531.                        │        │
  16532.                   ┌────┘        └─────────────────┐
  16533.         ┌───────┬──────┐                   ┌──────┬───────┐
  16534.         │  *first       │                   │  *first       │
  16535.         ├───────┼───────┤                   ├───────┼───────┤
  16536.         │  *last        │                   │  *last        │
  16537.         ├───────┼───────┤                   ├───────┼───────┤
  16538.         │  *middle      │                   │  *middle      │
  16539.         ├───────┼───────┼───────┬───────┐   ├───────┼───────┼───────┬───────┐
  16540.         │          street_num           │   │          street_num           │
  16541.         ├───────┼───────┼───────┴───────┘   ├───────┼───────┼───────┴───────┘
  16542.         │  *street      │                   │  *street      │
  16543.         ├───────┼───────┤                   ├───────┼───────┤
  16544.         │  *city        │                   │  *city        │
  16545.         ├───────┼───────┤                   ├───────┼───────┤
  16546.         │  *state       │                   │  *state       │
  16547.         ├───────┼───────┼───────┬───────┐   ├───────┼───────┼───────┬───────┐
  16548.         │              zip              │   │              zip              │
  16549.         ├───────┼───────┼───────┴───────┘   ├───────┼───────┼───────┴───────┘
  16550.         │    area_code  │                   │    area_code  │
  16551.         ├───────┼───────┼───────┬───────┐   ├───────┼───────┼───────┬───────┐
  16552.         │            phone              │   │            phone              │
  16553.         └───────┴───────┴───────┴───────┘   └───────┴───────┴───────┴───────┘
  16554.         │1 byte │
  16555.         │       │
  16556.  
  16557.    Figure 11-2. Declaring structure variables sets aside enough memory for
  16558.    the variables defined by cardstruct.
  16559.  
  16560.  Accessing Structure Members
  16561.  
  16562.    To access a member of a structure in C, specify the name of the structure
  16563.    variable that contains the member, then the . (pronounced "dot") operator,
  16564.    then the name of the member you need to access, as in the following
  16565.    example:
  16566.  
  16567.      printf("%d\n", card1.area_code);
  16568.                      │   │  └──────────────────── Name of member of structure
  16569.                      │   └─────────────────────────────────────────── A "dot"
  16570.                      └───────────────────────────────────── Name of structure
  16571.  
  16572.    This expression prints the value of the integer area_code, one of the
  16573.    member variables in the structure variable named card1.
  16574.  
  16575.    You can manipulate members of structures as you would any C variables: You
  16576.    can assign values to them, use them in computations, and so on. The only
  16577.    difference is that you must reference each member variable with the name
  16578.    of its structure (card1 or card2, for example), a dot, and then its own
  16579.    name.
  16580.  
  16581.    The CARD.C program (Listing 11-1) demonstrates structures by prompting
  16582.    you to fill out information for a fictional address-book card; then it
  16583.    prints out the information you entered.
  16584.  
  16585.    ──────────────────────────────────────────────────────────────────────────
  16586.    /* card.c  --  demonstrates how to declare structures  */
  16587.    /*             and how to use structure members        */
  16588.  
  16589.    #include <stdio.h>      /* for NULL and stdin */
  16590.    #include <string.h>     /* for strdup()       */
  16591.  
  16592.    #define MAXN 79
  16593.  
  16594.    struct cardstruct {                 /* global pattern */
  16595.        char *first, *last, *middle;
  16596.        long street_num;
  16597.        char *street, *city, *state;
  16598.        long zip;
  16599.        int  area_code;
  16600.        long phone;
  16601.    };
  16602.  
  16603.    main()
  16604.    {
  16605.        char *Str_Input();
  16606.        long Lint_Input();
  16607.        struct cardstruct card1;
  16608.  
  16609.        card1.first         = Str_Input("First Name");
  16610.        card1.last          = Str_Input("Last Name");
  16611.        card1.middle        = Str_Input("Middle Name");
  16612.        card1.street_num    = Lint_Input("Street Number");
  16613.        card1.street        = Str_Input("Street Name");
  16614.        card1.city          = Str_Input("City");
  16615.        card1.state         = Str_Input("State");
  16616.        card1.zip           = Lint_Input("Zip Code");
  16617.        card1.area_code     = (int)Lint_Input("Area Code");
  16618.        card1.phone         = Lint_Input("Phone Number");
  16619.  
  16620.        printf("\n\n");
  16621.        printf("%s %s %s\n", card1.first, card1.middle,
  16622.                card1.last);
  16623.        printf("%ld %s, %s, %s %ld\n", card1.street_num,
  16624.                card1.street, card1.city, card1.state,
  16625.                card1.zip);
  16626.        printf("(%d) %ld\n", card1.area_code, card1.phone);
  16627.    }
  16628.  
  16629.    char *Str_Input(char *prompt)
  16630.    {
  16631.        char buf[MAXN+1], *ptr;
  16632.  
  16633.        printf("%s: ", prompt);
  16634.        if (fgets(buf, MAXN, stdin) == NULL)
  16635.            exit(0);
  16636.        buf[strlen(buf) - 1] = '\0'; /* strip '\n' */
  16637.        if (strlen(buf) == 0)
  16638.            exit(0);
  16639.        if ((ptr = strdup(buf)) == NULL)
  16640.            exit(0);
  16641.        return (ptr);
  16642.    }
  16643.  
  16644.    long Lint_Input(char *prompt)
  16645.    {
  16646.        char buf[MAXN + 1];
  16647.        long num;
  16648.  
  16649.        printf("%s: ", prompt);
  16650.        if (fgets(buf, MAXN, stdin) == NULL)
  16651.            exit(0);
  16652.        if (sscanf(buf, "%ld", &num) != 1)
  16653.            exit(0);
  16654.        return (num);
  16655.    }
  16656.    ──────────────────────────────────────────────────────────────────────────
  16657.  
  16658.    Listing 11-1.  The CARD.C program.
  16659.  
  16660.    CARD.C uses the members of the structure card1 exactly as it would
  16661.    ordinary variables. It assigns values to them with the = operator and
  16662.    passes those values to printf() to be printed.
  16663.  
  16664.  Shorthand Structure Declarations
  16665.  
  16666.    As a bit of shorthand, you can declare structure patterns and allocate
  16667.    storage for structure variables in a single statement, as follows:
  16668.  
  16669.    When you allocate storage for structure variables as a part of the
  16670.    declaration, the name of the pattern becomes optional and you can omit it:
  16671.  
  16672.            ┌───────────────────────────────────────── Name of pattern omitted
  16673.      struct {
  16674.          /* list of members here */
  16675.      } card1, card2;
  16676.          └──────┴─────────────────────────────── Structures allocated storage
  16677.  
  16678.    You must use the pattern name, however, if you intend to declare
  16679.    additional structure variables using that pattern name later in the
  16680.    program:
  16681.  
  16682.      struct cardstruct card3, card4;
  16683.  
  16684.  Structure Assignment
  16685.  
  16686.    When you declare structure variables with the same pattern, you can assign
  16687.    one to another, as follows:
  16688.  
  16689.      card2 = card1;
  16690.  
  16691.    This assignment copies the values of all card1 members into the
  16692.    corresponding members of card2.
  16693.  
  16694.    If you try to assign one structure variable to another when those
  16695.    structures are declared with different pattern names (even if the members
  16696.    of both are identical), QuickC returns the following error message:
  16697.  
  16698.      error C2115:
  16699.      '=' : incompatible types
  16700.  
  16701.    ──────────────────────────────────────────────────────────────────────────
  16702.    Quick Tip
  16703.    One way to make a program such as CARD.C more robust, or user friendly, is
  16704.    to enable the program to handle telephone numbers that contain a hyphen
  16705.    (-) character. Consider the necessary revisions to CARD.C. Why is this
  16706.    enhancement difficult in a program that uses scanf() to parse user input?
  16707.    ──────────────────────────────────────────────────────────────────────────
  16708.  
  16709.    If you need to assign values from one structure to another of a different
  16710.    pattern, you must assign the members individually. For example, if card1
  16711.    uses the pattern cardstruct and memo uses another pattern, memostruct, you
  16712.    could assign the members of one to the other in the following way:
  16713.  
  16714.      card1.first  = memo.first_name;
  16715.      card1.last   = memo.last_name;
  16716.      card1.middle = memo.mid_name;
  16717.  
  16718.  Passing Structures to Functions
  16719.  
  16720.    Passing a structure to a function passes a copy of its members. This
  16721.    prevents the called function from changing the original structure. To pass
  16722.    a structure to a function, simply state the structure's name, as follows:
  16723.  
  16724.      Showcard(card1);
  16725.  
  16726.    In this example, a copy of the structure variable card1──including copies
  16727.    of all its members──is passed to the function Showcard(). Remember,
  16728.    structures differ from arrays in this regard: When you pass a structure to
  16729.    a function, you pass only a copy of that structure; when you pass an
  16730.    array, you pass the address of that array, thus allowing the original
  16731.    array to be changed by the calling function.
  16732.  
  16733.    In the receiving function (such as Showcard() below), you must declare the
  16734.    type of the received argument with struct and the pattern name
  16735.    (cardstruct). This tells the compiler that Showcard() is receiving a
  16736.    structure as its argument, and that the pattern for that structure is
  16737.    named cardstruct:
  16738.  
  16739.                                   ┌────────────────────────── Receive copy of
  16740.      Showcard(struct cardstruct card)
  16741.      {                    └────────────────── structure based on this pattern
  16742.          /* body of function */
  16743.      }
  16744.  
  16745.    The CARD2.C program (Listing 11-2 beginning on the following page) is a
  16746.    revised CARD.C program. In it, we fill out two cards and then print those
  16747.    cards using the Showcard() function.
  16748.  
  16749.    ──────────────────────────────────────────────────────────────────────────
  16750.    Quick Tip
  16751.    There are two drawbacks to passing structures to functions. First, not all
  16752.    compilers support the passing of structures, so if portability is
  16753.    important, you might want to avoid this technique. Second, as structures
  16754.    get larger, QuickC takes longer to copy them for each function call. This
  16755.    can become very time-consuming if it occurs in the middle of a loop. Thus,
  16756.    to speed the processing of your programs and enable the original to be
  16757.    changed, we advise you to use pointers to structures.
  16758.    ──────────────────────────────────────────────────────────────────────────
  16759.  
  16760.    ──────────────────────────────────────────────────────────────────────────
  16761.    /* card2.c --  demonstrates structure assignment and   */
  16762.    /*             how to pass a structure to a function   */
  16763.  
  16764.    #include <stdio.h>      /* for NULL  and stdin */
  16765.    #include <string.h>     /* for strdup()        */
  16766.  
  16767.    #define MAXN 79
  16768.  
  16769.    struct cardstruct {                 /* global pattern */
  16770.        char *first, *last, *middle;
  16771.        long street_num;
  16772.        char *street, *city, *state;
  16773.        long zip;
  16774.        int  area_code;
  16775.        long phone;
  16776.    };
  16777.  
  16778.    main()
  16779.    {
  16780.        int  i;
  16781.        char *Str_Input();
  16782.        long Lint_Input();
  16783.        struct cardstruct card1, card2;
  16784.  
  16785.        for (i = 0; i < 2; i++) /* do twice */
  16786.            {
  16787.            printf("\nCard %d:\n\n", i + 1);
  16788.  
  16789.            card1.first         = Str_Input("First Name");
  16790.            card1.last          = Str_Input("Last Name");
  16791.            card1.middle        = Str_Input("Middle Name");
  16792.            card1.street_num    = Lint_Input("Street Number");
  16793.            card1.street        = Str_Input("Street Name");
  16794.            card1.city          = Str_Input("City");
  16795.            card1.state         = Str_Input("State");
  16796.            card1.zip           = Lint_Input("Zip Code");
  16797.            card1.area_code     = (int)Lint_Input("Area Code");
  16798.            card1.phone         = Lint_Input("Phone Number");
  16799.  
  16800.            if (i == 0)
  16801.                card2 = card1;      /* structure assignment */
  16802.            }
  16803.        Showcard(card2);
  16804.        Showcard(card1);
  16805.  
  16806.    }
  16807.    Showcard(struct cardstruct card)
  16808.    {
  16809.        printf("\n\n");
  16810.  
  16811.        printf("%s %s %s\n", card.first, card.middle, card.last);
  16812.        printf("%ld %s, %s, %s %ld\n", card.street_num,
  16813.                card.street, card.city, card.state, card.zip);
  16814.        printf("(%d) %ld\n", card.area_code, card.phone);
  16815.    }
  16816.  
  16817.    char *Str_Input(char *prompt)
  16818.    {
  16819.        char buf[MAXN + 1], *ptr;
  16820.  
  16821.        printf("%s: ", prompt);
  16822.        if (fgets(buf, MAXN, stdin) == NULL)
  16823.            exit(0);
  16824.        buf[strlen(buf) - 1 ] = '\0'; /* strip '\n' */
  16825.        if (strlen(buf) == 0)
  16826.            exit(0);
  16827.        if ((ptr = strdup(buf)) == NULL)
  16828.            exit(0);
  16829.        return (ptr);
  16830.    }
  16831.  
  16832.    long Lint_Input(char *prompt)
  16833.    {
  16834.        char buf[MAXN + 1];
  16835.        long num;
  16836.  
  16837.        printf("%s: ", prompt);
  16838.        if (fgets(buf, MAXN, stdin) == NULL)
  16839.            exit(0);
  16840.        if (sscanf(buf, "%ld", &num) != 1)
  16841.            exit(0);
  16842.        return (num);
  16843.    }
  16844.    ──────────────────────────────────────────────────────────────────────────
  16845.  
  16846.    Listing 11-2.  The CARD2.C program.
  16847.  
  16848.    In CARD2.C, Showcard() receives a copy of card1 from main(). Note that the
  16849.    members of the Showcard() structure, card, are accessed with the same
  16850.    "dot" notation as the originals in main().
  16851.  
  16852.  Pointers to Structures
  16853.  
  16854.    Passing a pointer to a structure, rather than a copy of a structure, to a
  16855.    function has two advantages. It permits the function to modify the members
  16856.    of the original structure. Also, far fewer bytes must be copied when a
  16857.    pointer is passed than are copied when a structure is passed──the result
  16858.    is faster executing code.
  16859.  
  16860.    You declare a pointer to a structure the same way that you declare a
  16861.    pointer to any other type──by preceding its name with a *, as follows:
  16862.  
  16863.      struct cardstruct *cardptr;
  16864.                  │     └────── A pointer to a structure of pattern cardstruct
  16865.                  └─────────────────────────────────────────── Name of pattern
  16866.  
  16867.    This example declares a pointer variable, cardptr, whose contents will be
  16868.    an address. The struct cardstruct in the declaration tells the compiler
  16869.    that cardptr will point to a structure variable based on the pattern
  16870.    cardstruct. (See Figure 11-3.)
  16871.  
  16872.    Before you can use the pointer cardptr, it must be given a value. Because
  16873.    it is a pointer to a structure, we will assign it the address of the
  16874.    structure variable card1 from CARD.C:
  16875.  
  16876.      cardptr = &card1;
  16877.  
  16878.    The & operator fetches the address of a structure. (Note that this differs
  16879.    from arrays, where the array name itself yields the address.) To assign
  16880.    the address of a structure variable to a pointer to a structure, declare
  16881.    both the pointer and the structure with the same pattern name. If you
  16882.    declare them with different pattern names, QuickC returns the following
  16883.    warning message:
  16884.  
  16885.      warning C4049:
  16886.      '=' : indirection to different types
  16887.  
  16888.    The & operator can also pass the address of a structure directly to a
  16889.    function:
  16890.  
  16891.      Enter(&card1);
  16892.            └───────────────────────────── Pass address of card1 to a function
  16893.  
  16894.    struct cardstruct *cardptr;
  16895.                      └───────┘
  16896.                          │
  16897.              ┌───────┬──────┐ Points to   ┌───────┬───────┐
  16898.              │   address     │────────────│  *first       │
  16899.              └───────┴───────┘             ├───────┼───────┤
  16900.                                            │  *last        │
  16901.                                            ├───────┼───────┤
  16902.                                            │  *middle      │
  16903.                                            ├───────┼───────┼───────┬───────┐
  16904.                                            │          street_num           │
  16905.                                            ├───────┼───────┼───────┴───────┘
  16906.                                            │  *street      │
  16907.                                            ├───────┼───────┤
  16908.                                            │  *city        │
  16909.                                            ├───────┼───────┤
  16910.                                            │  *state       │
  16911.                                            ├───────┼───────┼───────┬───────┐
  16912.                                            │              zip              │
  16913.                                            ├───────┼───────┼───────┴───────┘
  16914.                                            │    area_code  │
  16915.                                            ├───────┼───────┼───────┬───────┐
  16916.                                            │            phone              │
  16917.                                            └───────┴───────┴───────┴───────┘
  16918.                                             Structure of pattern cardstruct
  16919.  
  16920.    Figure 11-3. A pointer to a structure contains the address of a structure
  16921.    variable.
  16922.  
  16923.    We also must declare the received argument for the Enter() function as a
  16924.    pointer to a structure, as follows:
  16925.  
  16926.      Enter(struct cardstruct *item)
  16927.           {                  └───────────────── Pointer to receive an address
  16928.  
  16929.    Again, be sure that you declare the same pattern name for both the passed
  16930.    and the received structures.
  16931.  
  16932.  Accessing Structure Members with a Pointer
  16933.  
  16934.    To access the members of a structure with a pointer, you need to use a new
  16935.    symbol, ->. Called "to", -> is actually two characters──a "minus"
  16936.    character followed by a "greater than" character. The following code
  16937.    illustrates the use of the -> operator. In it, the pointer cardptr
  16938.    accesses the phone member of the structure card1:
  16939.  
  16940.      struct cardstruct {──────────────────────────────────── Define a pattern
  16941.          char *first, *last, *middle;
  16942.          int age;
  16943.      };
  16944.  
  16945.      struct cardstruct card1, *cardptr;
  16946.                  │        │       └──────────────────── Declare a pointer and
  16947.                  │        └───────────────────────────── a structure variable
  16948.                  └────────────────────────────────────── both of that pattern
  16949.      cardptr = &card1;───────────────────── Assign card1's address to cardptr
  16950.      cardptr->phone = 5551212;──────────── Access member of card1 via cardptr
  16951.             └────────────────────────────── Points "to" member phone of card1
  16952.  
  16953.    The CARD3.C program (Listing 11-3) is another revision of CARD.C. This
  16954.    modification has Showcard() receiving the address of a structure. Rather
  16955.    than printing a copy, it prints the original via a pointer to the
  16956.    structure.
  16957.  
  16958.    ──────────────────────────────────────────────────────────────────────────
  16959.    /* card3.c --  demonstrates pointers to structures     */
  16960.  
  16961.    #include <stdio.h>      /* for NULL  and stdin */
  16962.    #include <string.h>     /* for strdup()        */
  16963.  
  16964.    #define MAXN 79
  16965.  
  16966.    struct cardstruct {                 /* global pattern */
  16967.        char *first, *last, *middle;
  16968.        long street_num;
  16969.        char *street, *city, *state;
  16970.        long zip;
  16971.        int  area_code;
  16972.        long phone;
  16973.    };
  16974.    main()
  16975.    {
  16976.        int  i;
  16977.        char *Str_Input();
  16978.        long Lint_Input();
  16979.        struct cardstruct card1, card2;
  16980.  
  16981.        for (i = 0; i < 2; i++) /* do twice */
  16982.            {
  16983.            printf("\nCard %d:\n\n", i + 1);
  16984.  
  16985.            card1.first         = Str_Input("First Name");
  16986.            card1.last          = Str_Input("Last Name");
  16987.            card1.middle        = Str_Input("Middle Name");
  16988.            card1.street_num    = Lint_Input("Street Number");
  16989.            card1.street        = Str_Input("Street Name");
  16990.            card1.city          = Str_Input("City");
  16991.            card1.state         = Str_Input("State");
  16992.            card1.zip           = Lint_Input("Zip Code");
  16993.            card1.area_code     = (int)Lint_Input("Area Code");
  16994.            card1.phone         = Lint_Input("Phone Number");
  16995.  
  16996.            if (i == 0)
  16997.                card2 = card1;
  16998.            }
  16999.        Showcard(&card2);     /* pass addresses of structures */
  17000.        Showcard(&card1);
  17001.  
  17002.        return (0);
  17003.    }
  17004.  
  17005.    Showcard(cardptr)
  17006.    struct cardstruct *cardptr; /* pointer receives an address */
  17007.    {
  17008.        printf("\n\n");
  17009.  
  17010.        printf("%s %s %s\n", cardptr->first, cardptr->middle,
  17011.                cardptr->last);
  17012.        printf("%ld %s, %s, %s %ld\n", cardptr->street_num,
  17013.                cardptr->street, cardptr->city, cardptr->state,
  17014.                cardptr->zip );
  17015.        printf("(%d) %ld\n", cardptr->area_code, cardptr->phone);
  17016.    }
  17017.  
  17018.    char *Str_Input(char *prompt)
  17019.    {
  17020.        char buf[MAXN + 1], *ptr;
  17021.  
  17022.        printf("%s: ", prompt);
  17023.        if (fgets(buf, MAXN, stdin) == NULL)        exit(0);
  17024.        buf[strlen(buf) - 1 ] = '\0'; /* strip '\n' */
  17025.        if (strlen(buf) == 0)
  17026.            exit(0);
  17027.        if ((ptr = strdup(buf)) == NULL)
  17028.            exit(0);
  17029.        return (ptr);
  17030.    }
  17031.  
  17032.    long Lint_Input(char *prompt)
  17033.    {
  17034.        char buf[MAXN + 1];
  17035.        long num;
  17036.  
  17037.        printf("%s: ", prompt);
  17038.        if (fgets(buf, MAXN, stdin) == NULL)
  17039.            exit(0);
  17040.        if (sscanf(buf, "%ld", &num) != 1)
  17041.            exit(0);
  17042.        return (num);
  17043.    }
  17044.    ──────────────────────────────────────────────────────────────────────────
  17045.  
  17046.    Listing 11-3.  The CARD3.C program.
  17047.  
  17048.  Arrays of Structures
  17049.  
  17050.    Structures can be organized in arrays like any other type of variable. You
  17051.    declare an array of structures as follows:
  17052.  
  17053.      struct cardstruct {
  17054.         /* members declared here */
  17055.      } cards[3];
  17056.              └───────────────────────────── An array of three structures
  17057.  
  17058.    This example declares an array of three structures (cards[3]) and defines
  17059.    the pattern cardstruct at the same time. If you had already defined the
  17060.    pattern, you could declare the same array as follows:
  17061.  
  17062.      struct cardstruct cards[3];
  17063.  
  17064.    Use an array of structures the same way you use any other array. For
  17065.    example, the following statement prints the first member of the second
  17066.    card:
  17067.  
  17068.      printf("%s", cards[1].first);
  17069.  
  17070.    The expression cards[1] accesses the second structure of the array, and
  17071.    the .first yields the member named first from that structure.
  17072.  
  17073.    To pass the address of one of the structures in the array cards, use the &
  17074.    operator followed by the structure's offset in square brackets.
  17075.  
  17076.      ┌──────────────────────────────────────────────────────────── Address of
  17077.      &cards[i]
  17078.             └─────────────────── the <FI>i<FS>th structure in the array of str
  17079.  
  17080.    The ROLO.C program (Listing 11-4) is a complete address book built from
  17081.    the earlier CARD.C program. It asks you to fill out the three cards in our
  17082.    array of structures. Then it prints out the information in those cards. By
  17083.    combining this use of structures with the file-handling routines of
  17084.    PHONE.C (from the previous chapter), you have the basis for a truly
  17085.    useful phone-index program.
  17086.  
  17087.    ──────────────────────────────────────────────────────────────────────────
  17088.    /* rolo.c  --  demonstrates pointers to structures    */
  17089.  
  17090.    #include <stdio.h>      /* for NULL  and stdin */
  17091.    #include <string.h>     /* for strdup()        */
  17092.  
  17093.    #define MAXN 79
  17094.    #define MAXCARDS 3
  17095.  
  17096.    struct cardstruct {                 /* global pattern */
  17097.        char first[MAXN],
  17098.             last[MAXN],
  17099.             middle[MAXN];
  17100.        unsigned long street_no;
  17101.        char street[MAXN],
  17102.             city[MAXN],
  17103.             state[MAXN];
  17104.        unsigned long zip;
  17105.        unsigned int area;
  17106.        unsigned long phone;
  17107.    };
  17108.    struct cardstruct cards[MAXCARDS];
  17109.  
  17110.    main()
  17111.    {
  17112.        int  i;
  17113.  
  17114.        for (i = 0; i < MAXCARDS; ++i)
  17115.            {
  17116.            printf("\n<card %d of %d>\n", i + 1, MAXCARDS);
  17117.            Input(&cards[i]);
  17118.            }
  17119.        for (i = 0; i < MAXCARDS; ++i)
  17120.            {
  17121.            printf("\n<%d> ", i + 1);
  17122.            Showcard(&cards[i]);
  17123.            }
  17124.    }
  17125.    Input(struct cardstruct *cardp)
  17126.    {
  17127.        char *Str_Input();
  17128.        long Lint_Input();
  17129.  
  17130.        strcpy(cardp->first,Str_Input("First Name"));
  17131.        strcpy(cardp->last,Str_Input("Last Name"));
  17132.        strcpy(cardp->middle,Str_Input("Middle Name"));
  17133.        cardp->street_no = Lint_Input("Street Number");
  17134.        strcpy(cardp->street,Str_Input("Street"));
  17135.        strcpy(cardp->city,Str_Input("City"));
  17136.        strcpy(cardp->state,Str_Input("State"));
  17137.        cardp->zip = Lint_Input("Zip Code");
  17138.        cardp->area = (int)Lint_Input("Area Code");
  17139.        cardp->phone = Lint_Input("Phone Number");
  17140.    }
  17141.  
  17142.    char *Str_Input(char *prompt)
  17143.    {
  17144.        char buf[MAXN + 1], *ptr;
  17145.  
  17146.        printf("%s: ", prompt);
  17147.        if (fgets(buf, MAXN, stdin) == NULL)
  17148.            exit(0);
  17149.        buf[strlen(buf) - 1 ] = '\0'; /* strip '\n' */
  17150.        if (strlen(buf) == 0)
  17151.            exit(0);
  17152.        if ((ptr = strdup(buf)) == NULL)
  17153.            exit(0);
  17154.        return (ptr);
  17155.    }
  17156.  
  17157.    long Lint_Input(char *prompt)
  17158.    {
  17159.        char buf[MAXN + 1];
  17160.        long  num;
  17161.  
  17162.        printf("%s: ", prompt);
  17163.        if (fgets(buf, MAXN, stdin) == NULL)
  17164.            exit(0);
  17165.        if (sscanf(buf, "%ld", &num) != 1)
  17166.            exit(0);
  17167.        return (num);
  17168.    }
  17169.  
  17170.    Showcard(struct cardstruct *cardptr)
  17171.    {
  17172.        printf("\n\n");
  17173.        printf("%s %s %s\n", cardptr->first, cardptr->middle,
  17174.                cardptr->last);
  17175.        printf("%ld %s, %s, %s %ld\n", cardptr->street_no,
  17176.                cardptr->street, cardptr->city, cardptr->state,
  17177.                cardptr->zip);
  17178.        printf("(%d) %ld\n", cardptr->area, cardptr->phone);
  17179.    }
  17180.    ──────────────────────────────────────────────────────────────────────────
  17181.  
  17182.    Listing 11-4.  The ROLO.C program.
  17183.  
  17184.    ROLO.C uses an array of three structures. Notice that the cards[] array
  17185.    consists of structures that themselves contain arrays.
  17186.  
  17187.  Arrays of Pointers to Structures
  17188.  
  17189.    Not only can you create arrays of structures, you can also create arrays
  17190.    of pointers to structures. These arrays of pointers offer the advantage of
  17191.    increased efficiency. For example, when sorting, it is faster to swap two
  17192.    pointers than it is to exchange the vastly greater number of bytes of the
  17193.    structures themselves.
  17194.  
  17195.    You declare an array of pointers to structures as follows:
  17196.  
  17197.      struct cardstruct *cardps[3]
  17198.  
  17199.    This example declares an array of three pointers in which each pointer
  17200.    points to a structure of the pattern cardstruct. Figure 11-4 illustrates
  17201.    such an arrangement.
  17202.  
  17203.    You can initialize cardps[] (an array of pointers to structures) to
  17204.    contain the address of the corresponding elements in the array of
  17205.    structures cards[] as follows:
  17206.  
  17207.      cardps[0] = &cards[0];
  17208.      cardps[1] = &cards[1];
  17209.      cardps[2] = &cards[2];
  17210.  
  17211.    This lets you use the -> operator to indirectly reference the members of
  17212.    each structure in cards[] with the pointers in cardps[]. For example, the
  17213.    street member of the second structure of the array of structures cards[]
  17214.    can be indirectly referenced through the array of pointers to structures
  17215.    in cardps[], as follows:
  17216.  
  17217.      strcpy(cardps[1]->street, "Any St.");
  17218.                      └───────────── Points "to" the member street of cards[1]
  17219.  
  17220.  Structure Recursion and Linked Lists
  17221.  
  17222.    Structures are so versatile that they can hold every possible type in C,
  17223.    including themselves. This remarkable ability to be self-inclusive opens
  17224.    whole new sets of programming possibilities. The most common of these is
  17225.    the technique shown in Figure 11-5 (on p. 348) that uses "linked lists."
  17226.  
  17227.                     ┌─────────────────────┐
  17228.                  ┌─│   first []          │
  17229.                  │  ├─────────────────────┤
  17230.                  │  │   last []           │
  17231.                  │  ├─────────────────────┤
  17232.                  │  │   middle []         │
  17233.                  │  ├───────────┬─────────┘
  17234.                  │  │street_num │
  17235.                  │  ├───────────┴─────────┐
  17236.                  │  │   street []         │
  17237.                  │  ├─────────────────────┤
  17238.                  │  │   city []           │
  17239.                  │  ├─────────────────────┤
  17240.                  │  │   state []          │
  17241.                  │  ├───────────┬─────────┘
  17242.                  │  │   zip     │
  17243.                  │  ├──────┬────┘
  17244.                  │  │area  │
  17245.    ┌────┬────┐   │  ├──────┴────┐
  17246.    │ address │───┘  │   phone   │
  17247.    ├────┼────┤      ├───────────┴─────────┐
  17248.    │ address │─────│   first []          │
  17249.    ├────┼────┤      ├─────────────────────┤
  17250.    │ address │───┐  │   last []           │
  17251.    └────┴────┘   │  ├─────────────────────┤
  17252.       cardps [3] │  │   middle []         │
  17253.                  │  ├───────────┬─────────┘
  17254.                  │  │street_num │
  17255.                  │  ├───────────┴─────────┐
  17256.                  │  │   street []         │
  17257.                  │  ├─────────────────────┤
  17258.                  │  │   city []           │
  17259.                  │  ├─────────────────────┤
  17260.                  │  │   state []          │
  17261.                  │  ├───────────┬─────────┘
  17262.                  │  │   zip     │
  17263.                  │  ├──────┬────┘
  17264.                  │  │area  │
  17265.                  │  ├──────┴────┐
  17266.                  │  │   phone   │
  17267.                  │  ├───────────┴─────────┐
  17268.                  └─│   first []          │
  17269.                     ├─────────────────────┤
  17270.                     │   last []           │
  17271.                     ├─────────────────────┤
  17272.                     │   middle []         │
  17273.                     ├───────────┬─────────┘
  17274.                     │street_num │
  17275.                     ├───────────┴─────────┐
  17276.                     │   street []         │
  17277.                     ├─────────────────────┤
  17278.                     │   city []           │
  17279.                     ├─────────────────────┤
  17280.                     │   state []          │
  17281.                     ├───────────┬─────────┘
  17282.                     │   zip     │
  17283.                     ├──────┬────┘
  17284.                     │area  │
  17285.                     ├──────┴────┐
  17286.                     │   phone   │
  17287.                     └───────────┘
  17288.                           cards [3]
  17289.  
  17290.    Figure 11-4. An array of pointers to structures. Each element points to a
  17291.    structure in an array of structures.
  17292.  
  17293.    ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
  17294.    │                 │  ┌─│                 │  ┌─│                 │
  17295.    ├─────────────────┤  │  ├─────────────────┤  │  ├─────────────────┤
  17296.    ├─────────────────┤  │  ├─────────────────┤  │  ├─────────────────┤
  17297.    ├─────────┬───────┘  │  ├─────────┬───────┘  │  ├─────────┬───────┘
  17298.    ├─────────┴───────┐  │  ├─────────┴───────┐  │  ├─────────┴───────┐
  17299.    ├─────────────────┤  │  ├─────────────────┤  │  ├─────────────────┤
  17300.    ├─────────────────┤  │  ├─────────────────┤  │  ├─────────────────┤
  17301.    ├─────────┬───────┘  │  ├─────────┬───────┘  │  ├─────────┬───────┘
  17302.    ├────┬────┘          │  ├────┬────┘          │  ├────┬────┘
  17303.    ├────┴────────────┐  │  ├────┴────────────┐  │  ├────┴────────────┐
  17304.    ├─────────────────┤  │  ├─────────────────┤  │  ├─────────────────┤
  17305.    │    nextcard     ├──┘  │    nextcard     ├──┘  │    nextcard     │
  17306.    └─────────────────┘     └─────────────────┘     └─────────────────┘
  17307.  
  17308.    Figure 11-5. In a linked list, each structure contains a pointer to
  17309.    another structure of the same type.
  17310.  
  17311.    A linked list is an arrangement of structures in which each structure
  17312.    contains a pointer to (the address of) its neighbor. For example, to
  17313.    declare such a linked list in ROLO.C, we must modify the structure pattern
  17314.    as follows:
  17315.  
  17316.      struct cardstruct {
  17317.          char first[MAXN],
  17318.               last[MAXN],
  17319.               middle[MAXN];
  17320.          unsigned long street_no;
  17321.          char street[MAXN],
  17322.               city[MAXN],
  17323.               state[MAXN];
  17324.          unsigned long zip;
  17325.          unsigned int area;
  17326.          unsigned long phone;
  17327.          struct cardstruct *nextcard;────────────────────────────────── Added
  17328.                            └ Pointer to another structure of this same pattern
  17329.  
  17330.    The new member *nextcard is a pointer to a structure, but it points to a
  17331.    structure of its own pattern. By declaring several structures of this
  17332.    pattern with
  17333.  
  17334.      struct cardstruct card1, card2, card3, card4;
  17335.  
  17336.    and then initializing the nextcard member of each to contain the address
  17337.    of its neighbor, you create a linked list:
  17338.  
  17339.      card1.nextcard = &card2;
  17340.      card2.nextcard = &card3;
  17341.      card3.nextcard = &card4;
  17342.  
  17343.    The ROLO2.C program (Listing 11-5) uses malloc() to build a linked list
  17344.    of structures while the program is running. Using this approach, we can
  17345.    add as many cards to our address book as we want (subject to the limit of
  17346.    the computer's memory).
  17347.  
  17348.    ──────────────────────────────────────────────────────────────────────────
  17349.    /* rolo2.c --  demonstrates a linked list */
  17350.  
  17351.    #include <stdio.h>      /* for NULL  and stdin */
  17352.    #include <string.h>     /* for strdup()        */
  17353.    #include <malloc.h>     /* for malloc()        */
  17354.  
  17355.    #define MAXN 79
  17356.  
  17357.    struct cardstruct {                 /* global pattern */
  17358.        char first[MAXN],
  17359.             last[MAXN],
  17360.             middle[MAXN];
  17361.        unsigned long street_no;
  17362.        char street[MAXN],
  17363.             city[MAXN],
  17364.             state[MAXN];
  17365.        unsigned long zip;
  17366.        unsigned int area;
  17367.        unsigned long phone;
  17368.        struct cardstruct *nextcard;
  17369.    };
  17370.  
  17371.    main()
  17372.    {
  17373.        int i;
  17374.        struct cardstruct card, *first, *current;
  17375.  
  17376.        first = (struct cardstruct *)malloc(sizeof(struct cardstruct));
  17377.        if (first == NULL)
  17378.            exit(1);
  17379.        if (Input(&card) != 0)
  17380.            exit(1);
  17381.        *first = card;
  17382.        current = first;
  17383.  
  17384.        while (Input(&card) == 0)
  17385.            {
  17386.            current->nextcard =
  17387.                (struct cardstruct *)malloc(sizeof(struct cardstruct));
  17388.            if (current->nextcard == NULL)
  17389.                exit(1);
  17390.            current = current->nextcard;
  17391.            *current = card;
  17392.            }
  17393.        current->nextcard = NULL;
  17394.  
  17395.        Dumplist(first);
  17396.    }
  17397.    Dumplist(struct cardstruct *head)
  17398.    {
  17399.        do
  17400.            {
  17401.            Showcard(head);
  17402.            } while ((head = head->nextcard) != NULL);
  17403.    }
  17404.  
  17405.    Showcard(struct cardstruct *cardptr)
  17406.    {
  17407.        printf("\n\n");
  17408.  
  17409.        printf("%s %s %s\n", cardptr->first, cardptr->middle,
  17410.                cardptr->last);
  17411.        printf("%ld %s, %s, %s %ld\n", cardptr->street_no,
  17412.                cardptr->street, cardptr->city, cardptr->state,
  17413.                cardptr->zip );
  17414.        printf("(%d) %ld\n", cardptr->area, cardptr->phone);
  17415.    }
  17416.  
  17417.    Input(struct cardstruct *cardp)
  17418.    {
  17419.        char *Str_Input();
  17420.        long Lint_Input();
  17421.  
  17422.        printf("\n<new card> (Empty first name Quits)\n");
  17423.        strcpy(cardp->first,Str_Input("First Name"));
  17424.        if (*(cardp->first) == '\0')
  17425.            return (1);
  17426.        strcpy(cardp->last,Str_Input("Last Name"));
  17427.        strcpy(cardp->middle,Str_Input("Middle Name"));
  17428.        cardp->street_no = Lint_Input("Street Number");
  17429.        strcpy(cardp->street,Str_Input("Street"));
  17430.        strcpy(cardp->city,Str_Input("City"));
  17431.        strcpy(cardp->state,Str_Input("State"));
  17432.        cardp->zip = Lint_Input("Zip Code");
  17433.        cardp->area = (int)Lint_Input("Area Code");
  17434.        cardp->phone = Lint_Input("Phone Number");
  17435.        return (0);
  17436.    }
  17437.  
  17438.    char *Str_Input(char *prompt)
  17439.    {
  17440.        char buf[MAXN + 1], *ptr;
  17441.  
  17442.        printf("%s: ", prompt);
  17443.        if (fgets(buf, MAXN, stdin) == NULL)
  17444.            exit(0);
  17445.        buf[strlen(buf) - 1 ] = '\0'; /* strip '\n' */
  17446.        if ((ptr = strdup(buf)) == NULL)
  17447.            exit(0);    return (ptr);
  17448.    }
  17449.  
  17450.    long Lint_Input(char *prompt)
  17451.    {
  17452.        char buf[MAXN + 1];
  17453.        long  num;
  17454.  
  17455.        printf("%s: ", prompt);
  17456.        if (fgets(buf, MAXN, stdin) == NULL)
  17457.            exit(0);
  17458.        if (sscanf(buf, "%ld", &num) != 1)
  17459.            num = 0;
  17460.        return (num);
  17461.    }
  17462.    ──────────────────────────────────────────────────────────────────────────
  17463.  
  17464.    Listing 11-5.  The ROLO2.C program.
  17465.  
  17466.    Notice that the last structure in the list always has its nextcard member
  17467.    set to NULL. That's how the program marks the end of the linked list.
  17468.  
  17469.    This program also illustrates two other interesting properties of
  17470.    structures. First, when you apply the sizeof operator to a structure or to
  17471.    a structure's pattern, it yields the total number of bytes for all the
  17472.    members of the structure:
  17473.  
  17474.      malloc(sizeof(struct cardstruct));
  17475.  
  17476.    Second, we had to type cast the value returned by malloc() to a type
  17477.    appropriate for the pointer to which the value is assigned:
  17478.  
  17479.      first = (struct cardstruct *)malloc(sizeof(struct cardstruct));
  17480.               └────────┬────────┘
  17481.                        └─────────────── Type cast to a pointer to a structure
  17482.  
  17483.    Note that you must use the structure pattern name in the type cast, not
  17484.    the structure variable name. Had we omitted the type cast, QuickC would
  17485.    complain with:
  17486.  
  17487.      Warning C4049:
  17488.      '=' indirection to different types
  17489.  
  17490.  Initializing Structures with Starting Values
  17491.  
  17492.    As in arrays, you can initialize structures that are static or global when
  17493.    you declare them. The type of the initializing value must, of course,
  17494.    match the type of the corresponding member. An attempt to initialize with
  17495.    the wrong type will yield the following QuickC warning:
  17496.  
  17497.      Warning C4047:
  17498.      "initializing": different levels of indirection
  17499.  
  17500.    The following structure is declared correctly:
  17501.  
  17502.      static struct cardstruct card = {
  17503.               "Bob",─────────────────────────────────────────────Member first
  17504.               "Roberts",──────────────────────────────────────────Member last
  17505.               "Mason",──────────────────────────────────────────Member middle
  17506.               42─────────────────────────────────────────────Member street_no
  17507.               "Willow Way",─────────────────────────────────────Member street
  17508.               "Tonopah",──────────────────────────────────────────Member city
  17509.               "Nevada",──────────────────────────────────────────Member state
  17510.               84521L,──────────────────────────────────────────────Member zip
  17511.               916,────────────────────────────────────────────────Member area
  17512.               5551212L───────────────────────────────────────────Member phone
  17513.      };
  17514.  
  17515.    As with arrays, if you specify fewer initializers than members, QuickC
  17516.    gives the trailing uninitialized members the default value of zero.
  17517.  
  17518.  
  17519.  Union──Multiple Types in the Same Space
  17520.  
  17521.    You can think of a "union" as the opposite of a structure. While struct is
  17522.    a collection of many types, each with its own location in memory, a union
  17523.    is a collection of many types that all share the same location in memory.
  17524.    Thus, a union can contain different types at various times, but it can
  17525.    contain only a single value of a single type at any given time.
  17526.  
  17527.    Although its uses are limited, a union is a blessing when you do encounter
  17528.    a need for one. For example, consider writing a function that needs to
  17529.    print either an int or a float, yet doesn't know ahead of time what type
  17530.    it will receive as its argument. Before we can show you how to write such
  17531.    a function, however, we need to cover the basics of declaring and using
  17532.    unions.
  17533.  
  17534.    You declare a union as you would a structure, except you use the keyword
  17535.    union instead of struct:
  17536.  
  17537.               ┌────────────────────────────────────────────── Name of pattern
  17538.      union twotype {
  17539.          float ftype;──────────────────────────────────────────────── Members
  17540.          int   itype;
  17541.      } one_of_many ;
  17542.         └──────────────────────── Name of a union variable of pattern twotype
  17543.  
  17544.    This example tells the compiler to reserve memory for the variable
  17545.    one_of_many, which will hold either a float or an int. Because the float
  17546.    is larger, union reserves four bytes──enough space to hold either type.
  17547.  
  17548.    As a general rule, you should place the largest member first in a union
  17549.    declaration. Some compilers allocate memory based only on the first
  17550.    member, rather than searching all members for the largest. QuickC is well
  17551.    behaved in this regard, however. It allocates the correct number of bytes
  17552.    for a union, regardless of the order of the member declarations.
  17553.  
  17554.    As with structure members, you access the members of a union with the
  17555.    "dot" operator. However, the compiler interprets the type of the union as
  17556.    the type specified by the member name, as follows:
  17557.  
  17558.      one_of_many.ftype = 1.0;────────────────────────────Interpret as a float
  17559.      one_of_many.itype = 1;───────────────────────────────Interpret as an int
  17560.  
  17561.    The UDEMO.C program (Listing 11-6) is a simple demonstration of how a
  17562.    union works. After asking the user to enter a type, it uses scanf() to
  17563.    read that type and printf() to echo it to the screen.
  17564.  
  17565.    ──────────────────────────────────────────────────────────────────────────
  17566.    /* udemo.c  --  demonstrates a union at work */
  17567.  
  17568.    #include <stdio.h>
  17569.  
  17570.    char *Strings[6] = {
  17571.            "Quit",
  17572.            "line of text",
  17573.            "floating-point double value",
  17574.            "long integer value",
  17575.            "floating-point value",
  17576.            "integer value"
  17577.    };
  17578.  
  17579.    struct Unitstruct {
  17580.        union {
  17581.            char   wtype[BUFSIZ];
  17582.            double dtype;
  17583.            long   ltype;
  17584.            float  ftype;
  17585.            int    itype;
  17586.        } manyu;
  17587.        int type_in_union;
  17588.    };
  17589.  
  17590.    main()
  17591.    {
  17592.        struct Unitstruct one_of_many;
  17593.  
  17594.        while ((one_of_many.type_in_union = Menu()) != 0 )
  17595.            {
  17596.            Inputval(&one_of_many);
  17597.            Printval(&one_of_many);
  17598.            }
  17599.    }
  17600.  
  17601.    Inputval(struct Unitstruct *one_of_many)
  17602.    {
  17603.        printf("\nEnter a %s: ", Strings[one_of_many->type_in_union]);
  17604.        switch(one_of_many->type_in_union)
  17605.            {
  17606.            case 1:
  17607.                fgets(one_of_many->manyu.wtype, BUFSIZ, stdin);
  17608.                break;
  17609.            case 2:
  17610.                scanf("%lf", &(one_of_many->manyu.dtype));
  17611.                while (getchar()!= '\n');
  17612.                break;
  17613.            case 3:
  17614.                scanf("%ld", &(one_of_many->manyu.ltype));
  17615.                while (getchar()!= '\n');
  17616.                break;
  17617.            case 4:
  17618.                scanf("%f", &(one_of_many->manyu.ftype));
  17619.                while (getchar()!= '\n');
  17620.                break;
  17621.            case 5:
  17622.                scanf("%i", &(one_of_many->manyu.itype));
  17623.                while (getchar()!= '\n');
  17624.                break;
  17625.            }
  17626.    }
  17627.  
  17628.    Printval(struct Unitstruct *one_of_many)
  17629.    {
  17630.        printf("The %s you entered\nwas: ", Strings[one_of_many->type_in_union]
  17631.        switch (one_of_many->type_in_union)
  17632.            {
  17633.            case 1:
  17634.                fputs(one_of_many->manyu.wtype, stdout);
  17635.                break;
  17636.            case 2:
  17637.                printf("%lf", one_of_many->manyu.dtype);
  17638.                break;
  17639.            case 3:
  17640.                printf("%ld", one_of_many->manyu.ltype);
  17641.                break;
  17642.            case 4:
  17643.                printf("%f", one_of_many->manyu.ftype);
  17644.                break;
  17645.            case 5:
  17646.                printf("%i", one_of_many->manyu.itype);
  17647.                break;
  17648.            }
  17649.        printf("\n\n");
  17650.    }
  17651.  
  17652.    Menu()
  17653.    {
  17654.        int i;
  17655.        char ch;
  17656.        for (i = 0; i < 6; ++i)
  17657.            {
  17658.            printf("%d) %s\n", i, Strings[i]);
  17659.            }
  17660.        printf("Which: ");
  17661.        do
  17662.            {
  17663.            ch = getch();
  17664.            } while (ch < '0' || ch > '5');
  17665.        printf("%c\n", ch);
  17666.        return (ch - '0');
  17667.    }
  17668.    ──────────────────────────────────────────────────────────────────────────
  17669.  
  17670.    Listing 11-6.  The UDEMO.C program.
  17671.  
  17672.  Unions and Functions
  17673.  
  17674.    Unlike a structure, you cannot pass a union to a function. Instead, you
  17675.    must pass the value of the type currently stored in that union. For
  17676.    example, the statement
  17677.  
  17678.      printf("%f", one_of_many.ftype);
  17679.               │               └───────── Sends the float value in one_of_many
  17680.               └────────────────────────────────────────────── Expects a float
  17681.  
  17682.    sends printf() the float value in one_of_many, which matches the printf()
  17683.    %f format specifier. Note that it is meaningless in C to use a union
  17684.    variable (such as one_of_many) without a corresponding "dot" and member
  17685.    name.
  17686.  
  17687.    ──────────────────────────────────────────────────────────────────────────
  17688.    Quick Tip
  17689.    The UDEMO.C program illustrates a common technique for managing unions.
  17690.    Because a union contains no inherent indication of the type it contains,
  17691.    unions are often made members of structures, with another member used to
  17692.    store that indication:
  17693.  
  17694.      struct Unitstruct{
  17695.          union {
  17696.              char   wtype[BUFSIZE];
  17697.              double dtype;
  17698.              long   ltype;
  17699.              float  ftype;
  17700.              int    itype;
  17701.          } manyu;
  17702.          int type_in_union;
  17703.          };
  17704.  
  17705.    By packaging a union and an int together in a structure like this, we are
  17706.    better able to keep track of the type stored in the union at any given
  17707.    time.
  17708.    ──────────────────────────────────────────────────────────────────────────
  17709.  
  17710.  Unions Received by Functions
  17711.  
  17712.    C permits you to use a union as the type of an argument received by a
  17713.    function, but the procedure can be risky. The following statement
  17714.    illustrates one way to declare a received variable in a subroutine as a
  17715.    union:
  17716.  
  17717.      #define FLT 0  /* floating-point type */
  17718.      #define INT 1  /* integer type        */
  17719.  
  17720.      Printval(val, type)
  17721.      union twotype val;
  17722.      int type;
  17723.      {
  17724.           switch (type)
  17725.               {
  17726.               case FLT: printf("%f", val.ftype); break;
  17727.               case INT: printf("%d", val.itype); break;
  17728.               }
  17729.      }
  17730.  
  17731.    This function receives two arguments: a union of two possible types and an
  17732.    int that specifies which of the two possible types is in that union.
  17733.  
  17734.    But beware. Depending on how the compiler passes arguments to functions,
  17735.    this approach can fail. In QuickC, a float is four bytes and an int is two
  17736.    bytes; therefore, the stack (received arguments) resembles Figure 11-6a
  17737.    when passing a float and Figure 11-6b when passing an int. However,
  17738.    because the pattern for twotype reserves four bytes, passing an int to
  17739.    Printval() causes the type argument to appear in the wrong place.
  17740.  
  17741.    You can resolve this dilemma by constraining union members to types that
  17742.    use the same number of bytes. That is, if you declare twotype as follows:
  17743.  
  17744.      union twotype {
  17745.          float fval;
  17746.          long ival;
  17747.      };
  17748.  
  17749.    it would contain either of two types, but each type requires four bytes. A
  17750.    better solution is to package a union and an int together inside a
  17751.    structure, as you saw earlier. That approach avoids the potential pitfalls
  17752.    of declaring a function that receives a bare-bones union.
  17753.  
  17754.  Pointers to Unions
  17755.  
  17756.    Pointers to unions behave like pointers to structures. You retrieve the
  17757.    address of a union with the & operator and the union variable name, as
  17758.    follows:
  17759.  
  17760.      &one_of_many
  17761.  
  17762.    Printval (float, int)
  17763.                │     │        High address
  17764.                │     │     ┌────────────────┐
  17765.                │     └────├──    int     ──┤2-byte int
  17766.                │           ├────────────────┤
  17767.                │           ├──            ──┤
  17768.                └──────────├──   float    ──┤4-byte float
  17769.                            ├──            ──┤
  17770.    Start of arguments ────└────────────────┘
  17771.                               Low address
  17772.  
  17773.    (A)
  17774.  
  17775.  
  17776.    Printval (int, int)
  17777.               │    │          High address
  17778.               │    │       ┌────────────────┐
  17779.               │    │       ├──            ──┤Second argument missing
  17780.               │    │       ├────────────────┤
  17781.               │    └──────├──    int     ──┤2-byte int
  17782.               │            ├────────────────┤
  17783.               └───────────├──    int     ──┤2-byte int
  17784.    Start of arguments ────└────────────────┘
  17785.                               Low address
  17786.  
  17787.    (B)
  17788.  
  17789.    Figure 11-6. Passing different-size data types to the same function can
  17790.    cause confusion.
  17791.  
  17792.    To fetch the address of a union member, specify the & operator, the union
  17793.    variable name, the "dot" operator, and the member name, as follows:
  17794.  
  17795.      &one_of_many.ftype
  17796.  
  17797.    Declaring pointers to unions and manipulating values via the addresses in
  17798.    those pointers is also identical to the form used by structure pointers.
  17799.    Declare a pointer to a union as follows:
  17800.  
  17801.      union manytype *up;
  17802.                     └───────────── Pointer to a union of the pattern manytype
  17803.  
  17804.    Place a value (an address) into that pointer in the following form:
  17805.  
  17806.      up = &one_of_many;
  17807.  
  17808.    To access the type of the value stored in the union whose address is in
  17809.    up, use the -> operator as follows:
  17810.  
  17811.      up->ftype = 1.0;
  17812.  
  17813.    Structures and unions are closely related. The main difference is that a
  17814.    structure holds many values simultaneously; a union holds only a single
  17815.    type of value at any one time. As you have seen, structures can include
  17816.    unions as members. It is also legal for unions to contain structures as
  17817.    members. We'll use this latter technique at the end of this chapter, when
  17818.    we discuss bit fields.
  17819.  
  17820.  
  17821.  Enumerated Data with enum
  17822.  
  17823.    Many kinds of information are best represented by a finite list of
  17824.    discrete integer values──for example, the days of the week, the months of
  17825.    the year, or even the phases of the moon. Such kinds of information, in
  17826.    which every possibility is known in advance, lend themselves to
  17827.    enumeration──a listing of all possible values for a given topic or
  17828.    concept.
  17829.  
  17830.    If you need to represent the days of the week in a program as discrete
  17831.    integers, you could make the following declarations and assignments:
  17832.  
  17833.      int monday  = 0, tuesday = 1, wednesday = 2, thursday = 3,
  17834.          friday = 4, saturday = 5, sunday = 6;
  17835.  
  17836.    and later use those values as follows:
  17837.  
  17838.      pay_day = friday;
  17839.  
  17840.    The previous approach, although reasonable, has a potential pitfall.
  17841.    Because the days of the week are int variables, the program might change
  17842.    their values, and so render them meaningless. To avoid this problem we can
  17843.    use the following directives:
  17844.  
  17845.      #define MONDAY 0
  17846.      #define TUESDAY 1
  17847.      [etc.]
  17848.  
  17849.    The program can't change these values because they are integer constant
  17850.    aliases. But this is still not an ideal solution because you cannot group
  17851.    #define definitions under a single conceptual name.
  17852.  
  17853.    The best solution uses the C enumerated data type, enum, whose members are
  17854.    constants grouped under a single name. To represent the days of the week
  17855.    using enum, first declare a pattern similar to a structure or union
  17856.    pattern:
  17857.  
  17858.               ┌────────────────────────────────────────────── Name of pattern
  17859.      enum week_days {
  17860.          monday,───────────────────────────────────────────────────── Members
  17861.          tuesday,
  17862.          wednesday,
  17863.          thursday,
  17864.          friday,
  17865.          saturday,
  17866.          sunday
  17867.      } pay_day;
  17868.           └────────────────────────────────────────────── Enumerated variable
  17869.  
  17870.    This example declares a pattern called week_days, an enumerated data type,
  17871.    and the enumerated variable pay_day. Note that the members don't need to
  17872.    be preceded by a type keyword because the members of enum are always of
  17873.    type int. Also notice that you don't need to assign the members any
  17874.    values: The declaration itself gives the members constant integer values,
  17875.    starting with 0 for monday and counting through 6 for sunday.
  17876.  
  17877.    Another difference between enum and struct or union is that you access
  17878.    members of enum simply by stating the member's name without the "dot" or
  17879.    "->" notation:
  17880.  
  17881.      payday = monday;
  17882.  
  17883.    Any attempt to change the value of an enumerated member (monday = 5, for
  17884.    example) results in the following QuickC error message:
  17885.  
  17886.      error C2106:
  17887.      '=' : left operand must be lvalue
  17888.  
  17889.    This reminds you that the members of an enumerated data type, like all
  17890.    other constants, are rvalues and can appear only to the right of an
  17891.    assignment operator.
  17892.  
  17893.    Also note that you cannot use a pointer to indirectly change the value of
  17894.    an enumerated variable member. For example, the following assignment:
  17895.  
  17896.      int *p;
  17897.  
  17898.      p = &monday;────────────────────────────Can't take address of a constant
  17899.      *p = 5;
  17900.  
  17901.    fails because you can't retrieve the address of a constant. This attempt
  17902.    generates the following QuickC error message:
  17903.  
  17904.      error C2101:
  17905.      '&' on constant
  17906.  
  17907.    The TODAY.C program (Listing 11-7 on the following page) demonstrates one
  17908.    advantage to using enum──improved readability. The program asks you to
  17909.    specify the day on which you want to be paid. It then checks to make
  17910.    certain that you specified a legal day.
  17911.  
  17912.    The pattern week_day in TODAY.C shows that you can initialize an enum
  17913.    member to any integer value. Any uninitialized member, however, is
  17914.    assigned a value one higher than the member before it. For example, the
  17915.    declaration
  17916.  
  17917.      enum folks {
  17918.          mo = -1,
  17919.          roseann,
  17920.          betsy = 0,
  17921.          kit,
  17922.          joey = 1
  17923.      };
  17924.  
  17925.    sets mo to a -1, roseann and betsy to 0, and kit and joey to 1. This also
  17926.    shows that enum members can have duplicate values.
  17927.  
  17928.    ──────────────────────────────────────────────────────────────────────────
  17929.    /* today.c  -- demonstrates using enum  */
  17930.  
  17931.    main()
  17932.    {
  17933.        enum week_days {
  17934.            monday = 1,     /* start with 1 */
  17935.            tuesday,
  17936.            wednesday,
  17937.            thursday,
  17938.            friday,
  17939.            saturday,
  17940.            sunday
  17941.        } pay_day;
  17942.  
  17943.        static char *day_names[] = {
  17944.            "",
  17945.            "monday",
  17946.            "tuesday",
  17947.            "wednesday",
  17948.            "thursday",
  17949.            "friday",
  17950.            "saturday",
  17951.            "sunday"
  17952.        };
  17953.  
  17954.        printf("What day do you want to be paid on?\n");
  17955.  
  17956.        for (pay_day = monday; pay_day <= sunday; ++pay_day)
  17957.            {
  17958.            printf("%d. %s\n", pay_day, day_names[pay_day]);
  17959.            }
  17960.  
  17961.        printf("Which (%d-%d): ", monday, sunday);
  17962.  
  17963.        do
  17964.            {
  17965.            pay_day = getch();
  17966.            pay_day -= '0';
  17967.            } while (pay_day < monday || pay_day > sunday);
  17968.  
  17969.        printf("%d\n\n", pay_day);
  17970.  
  17971.        printf("You selected %s\n", day_names[pay_day]);
  17972.  
  17973.    }
  17974.    ──────────────────────────────────────────────────────────────────────────
  17975.  
  17976.    Listing 11-7.  The TODAY.C program.
  17977.  
  17978.  
  17979.  Bit Fields
  17980.  
  17981.    In Chapter 7, we discussed how to use bitwise operators to store data in
  17982.    the individual bits of bytes. Another, and simpler, way to store and
  17983.    access information in bits is with "bit fields."
  17984.  
  17985.    Bit fields offer two advantages over the bitwise operators. First, you can
  17986.    access bit fields by name (such as blink) rather than by an obscure mask
  17987.    (such as (1 << 7)). Second, the compiler generates code for bit fields
  17988.    that you normally would have to write yourself. Examine, for example, the
  17989.    following bit-field assignment:
  17990.  
  17991.      blink = 1;
  17992.  
  17993.    where blink is the name of the sixteenth bit of a 2-byte int. This
  17994.    statement is comparable to the following assignment using bitwise
  17995.    operators:
  17996.  
  17997.      ch |= (1 << 15);
  17998.  
  17999.    C's bit fields are especially handy when you need to manipulate items with
  18000.    built-in bit information. The characters in your screen memory are
  18001.    examples of such items. Recall that each screen character is represented
  18002.    by a 2-byte int. One byte is the character itself; the other is the
  18003.    attribute byte. (See Figure 11-7.)
  18004.  
  18005.                                 ┌────────Most significant bit
  18006.                             ┌──────┐─┐
  18007.       Blinking (1 bit) ─────│   7   │ │
  18008.                           ┌─├─     ─┤ │
  18009.                           │ │   6   │ │
  18010.                           │ ├─     ─┤ │
  18011.    Background (3 bits) ───┤ │   5   │ │
  18012.                           │ ├─     ─┤ │
  18013.                           │ │   4   │ │
  18014.                           └─├─     ─┤ ├───Attributes (1 byte)─┐
  18015.      Intensity (1 bit) ─────│   3   │ │                       │
  18016.                           ┌─├─     ─┤ │                       │
  18017.                           │ │   2   │ │                       │
  18018.                           │ ├─     ─┤ │                       │
  18019.    Foreground (3 bits) ───┤ │   1   │ │                       │
  18020.                           │ ├─     ─┤ │                       │
  18021.                           │ │   0   │ │                       │
  18022.                           └─├───────┤─┤                       ├──1 int
  18023.                             │   7   │ │                       │
  18024.                             ├─     ─┤ │                       │
  18025.                             │   6   │ │                       │
  18026.                             ├─     ─┤ │                       │
  18027.                             │   5   │ │                       │
  18028.                             ├─     ─┤ │                       │
  18029.                             │   4   │ │                       │
  18030.                             ├─     ─┤ ├───Character (1 byte)──┘
  18031.                             │   3   │ │
  18032.                             ├─     ─┤ │
  18033.                             │   2   │ │
  18034.                             ├─     ─┤ │
  18035.                             │   1   │ │
  18036.                             ├─     ─┤ │
  18037.                             │   0   │ │
  18038.                             └──────┘─┘
  18039.                                 └────────Least significant bit
  18040.  
  18041.    Figure 11-7. One character in screen memory is represented by two
  18042.    consecutive bytes.
  18043.  
  18044.    The following is an example of one such screen int declared using bit
  18045.    fields:
  18046.  
  18047.                ┌──────────────┬────────────── One integer...divided like this
  18048.      unsigned int character  :8,
  18049.                   foreground :3,
  18050.                   intensity  :1,
  18051.                   background :3,
  18052.                   blink      :1;
  18053.                     └─────────┴──────────────────── Name for...this many bits
  18054.  
  18055.    In this declaration, we tell QuickC to use the bits in one unsigned
  18056.    integer. Next, we specify the names for each group of bits in that
  18057.    integer, beginning with 8 bits, to which we give the name character, and
  18058.    continuing through all 16 bits until we end with blink as the name of the
  18059.    final bit.
  18060.  
  18061.    You may name as many bits as there are in the type declared (8 for a char,
  18062.    32 for a long, and so on). Only integer types can be used as bit fields,
  18063.    and only integer constants can be used to declare the number of bits.
  18064.    Always declare the bits from the bottom up (from the least significant to
  18065.    the most significant bits). A colon separates the name for each group of
  18066.    bits from the number of bits assigned to it; a comma separates each name
  18067.    :bits from the next; and, of course, a semicolon must end the entire
  18068.    declaration.
  18069.  
  18070.    If you declare fewer bits than there are in a type, the unused bits are
  18071.    simply ignored. If you declare more, an additional variable of the same
  18072.    type is allocated:
  18073.  
  18074.           ┌───────────────────────────────────────────────────── 8 bits
  18075.      unsigned char character :8,
  18076.                   foreground :3,
  18077.                   intensity  :1,
  18078.                   background :3,
  18079.                   blink      :1;
  18080.                               └─── 16 bits total allocates two char variables
  18081.  
  18082.    The name :bits combination is what defines a bit field as opposed to an
  18083.    ordinary variable. For example, the above declaration produces the same
  18084.    allocation as the following series of declarations:
  18085.  
  18086.      unsigned char character  :8;
  18087.      unsigned char foreground :3;
  18088.      unsigned char intensity  :1;
  18089.      unsigned char background :3;
  18090.      unsigned char blink      :1;
  18091.  
  18092.    In this example, the compiler gathers the bits from the declared bit
  18093.    fields into the most compact unit, regardless of how many bit fields you
  18094.    declare.
  18095.  
  18096.    Because you are not permitted to retrieve the address of a bit field, you
  18097.    usually will declare bit fields inside structures, as follows:
  18098.  
  18099.      struct screen_char_struct {
  18100.          unsigned int character  :8,
  18101.                       foreground :3,
  18102.                       intensity  :1,
  18103.                       background :3,
  18104.                       blink      :1;
  18105.      } screen_ch ;
  18106.        └───┬───┘
  18107.            └───────────────── Structure variable whose members are bit fields
  18108.  
  18109.    This approach has two advantages. First, you can access the individual bit
  18110.    fields with the usual structure/member notation. This improves
  18111.    readability:
  18112.  
  18113.      screen_ch.blink = 1;─────────────────Retrieve the address of a structure
  18114.  
  18115.    Second, you can access the address of a structure, but you cannot retrieve
  18116.    the address of a bit field. This lets you manipulate bit fields with
  18117.    pointers, which can increase the speed of your program:
  18118.  
  18119.      &screen_ch
  18120.  
  18121.    The SCRMENU.C program (Listing 11-8) demonstrates how to use bit fields
  18122.    to modify text-screen display. It lets you select an attribute; then it
  18123.    toggles the setting for that attribute for every character on the screen.
  18124.  
  18125.    ──────────────────────────────────────────────────────────────────────────
  18126.    /* scrmenu.c  -- uses bit fields to modify your text   */
  18127.    /*               screen's attributes                   */
  18128.  
  18129.    char *Choice_Words[] = {
  18130.        "Quit",
  18131.        "Foreground",
  18132.        "Intensity",
  18133.        "Background",
  18134.        "Blinking"
  18135.    };
  18136.    enum Choices {
  18137.        Quit,
  18138.        Foreground,
  18139.        Intensity,
  18140.        Background,
  18141.        Blinking
  18142.    };
  18143.  
  18144.    /* use 0xB800000 for EGA or VGA */
  18145.    #define SCR_START (0xB0000000)
  18146.    #define SCR_SIZE (25 * 80)
  18147.    main()
  18148.    {
  18149.        enum Choices choice;
  18150.  
  18151.        printf("Select from the following by number:\n");
  18152.  
  18153.        for (choice = Quit; choice <= Blinking; ++choice )
  18154.            {
  18155.            printf("%d. %s\n", choice, Choice_Words[choice]);
  18156.            }
  18157.  
  18158.        printf("\nWhich: ");
  18159.        do
  18160.            {
  18161.            choice = getch();
  18162.            choice -= '0';
  18163.            if (choice < Foreground || choice > Blinking)
  18164.                continue;
  18165.            Redraw( choice );
  18166.            } while (choice != Quit);
  18167.  
  18168.    }
  18169.  
  18170.    Redraw(enum Choices field)
  18171.    {
  18172.        struct screen_char {
  18173.            unsigned int character  :8,
  18174.                         foreground :3,
  18175.                         intensity  :1,
  18176.                         background :3,
  18177.                         blink      :1;
  18178.        } scrchar, far *sp, far *ep;
  18179.  
  18180.        sp = (struct screen_char far *)SCR_START;
  18181.        ep = sp + SCR_SIZE;
  18182.  
  18183.        while (sp < ep)
  18184.            {
  18185.            scrchar = *sp;
  18186.            switch (field)
  18187.                {
  18188.                case Foreground:
  18189.                    scrchar.foreground = (scrchar.foreground)? 0 : 7;
  18190.                    break;
  18191.                case Intensity:
  18192.                    scrchar.intensity = (scrchar.intensity)? 0 : 1;
  18193.                    break;
  18194.                case Background:
  18195.                    scrchar.background = (scrchar.background)? 0 : 7;
  18196.                    break;
  18197.                case Blinking:
  18198.                    scrchar.blink = (scrchar.blink)? 0 : 1;
  18199.                    break;
  18200.                }
  18201.            *(sp++) = scrchar;
  18202.            }
  18203.    }
  18204.    ──────────────────────────────────────────────────────────────────────────
  18205.  
  18206.    Listing 11-8.  The SCRMENU.C program.
  18207.  
  18208.    SCRMENU.C combines bit fields with enum and the #define preprocessor
  18209.    directive to virtually rid the body of the program of obscure constructs.
  18210.    Also, notice that we use a pointer to a structure to access the screen.
  18211.  
  18212.  
  18213.  Advanced typedef
  18214.  
  18215.    So far, we've used the #define preprocessor directive to create aliases,
  18216.    both for increased program clarity and as a shorthand method of entering
  18217.    repetitive code. We have also seen, in Chapter 3, that new types can be
  18218.    defined by using typedef. Superficially, #define and typedef appear to be
  18219.    interchangeable. To create simple aliases, you can use either one.
  18220.    Situations arise, however, in which typedef is suitable, but #define is
  18221.    not.
  18222.  
  18223.    For example, suppose you need to create a new type called string, an array
  18224.    of type char. Now suppose you attempt to create this new type with
  18225.    #define, as follows:
  18226.  
  18227.      #define string char s[128]
  18228.  
  18229.    You later would not be permitted to make the declaration
  18230.  
  18231.      string str1, str2;
  18232.  
  18233.    because the preprocessor would expand it to be
  18234.  
  18235.      char s[128] str1, str2;
  18236.  
  18237.    which is illegal. (Note the missing comma, among other things.) In
  18238.    situations such as this one, typedef is ideal. Rather than beginning with
  18239.    a #define directive, suppose you use the following:
  18240.  
  18241.      typedef char string[128];
  18242.  
  18243.    This creates a new type called string, which you can use later to declare
  18244.    variables of that new type:
  18245.  
  18246.      string str1, str2;
  18247.  
  18248.    Because we used typedef to define string, the compiler correctly
  18249.    translates this into
  18250.  
  18251.      char str1[128], str2[128];
  18252.  
  18253.    which is what we intended in the first place.
  18254.  
  18255.    The secret to using typedef is to follow three simple steps. First,
  18256.    declare an ordinary variable of the type you want:
  18257.  
  18258.      char s[128];
  18259.  
  18260.    Second, place the word typedef at the front:
  18261.  
  18262.      typedef char s[128];
  18263.  
  18264.    Third, replace the variable's name with the new type name:
  18265.  
  18266.      typedef char string[128];
  18267.  
  18268.    You can now use the newly defined type string exactly as you would one of
  18269.    C's built-in types, such as int.
  18270.  
  18271.    In addition to doing what #define cannot, typedef also lends clarity to
  18272.    otherwise obscure constructs. For example, consider the following two
  18273.    pointers to functions:
  18274.  
  18275.      int (*quit_fun)(), (*restart_fun)();
  18276.  
  18277.    This could be confusing if it were to appear throughout your program.
  18278.    Using typedef, however, you can create a new type called funptr:
  18279.  
  18280.      typedef (*funptr)();
  18281.  
  18282.    Now you can use funptr throughout your program to declare variables of
  18283.    that new type, as follows:
  18284.  
  18285.      funptr quit_fun, restart_fun;
  18286.  
  18287.    Use typedef judiciously──it is the most easily abused concept in C. The
  18288.    indiscriminate use of typedef, rather than making your program more
  18289.    readable, can make it more obscure and (sometimes) indecipherable.
  18290.  
  18291.  
  18292.  
  18293.  ────────────────────────────────────────────────────────────────────────────
  18294.  Chapter 12  Large Projects
  18295.  
  18296.    As your programs become larger and more complex, revising and maintaining
  18297.    them become less straightforward. Consequently, as your programming skills
  18298.    increase, you inevitably will find yourself looking for more efficient
  18299.    ways of handling programs. For example, you might want to:
  18300.  
  18301.    ■  Use one function in several programs without having to retype it every
  18302.       time.
  18303.  
  18304.    ■  Compile a program one way for testing and another for actual use──
  18305.       without having to rewrite it.
  18306.  
  18307.    ■  Combine several .C files into a single program, while recompiling only
  18308.       those files that need to be changed.
  18309.  
  18310.    ■  Transport one of your programs to another machine or compiler and
  18311.       compile it without needing to rewrite it.
  18312.  
  18313.    This chapter offers solutions for these and other common programming
  18314.    needs. We'll discuss how to use the C preprocessor for conditional
  18315.    compilation and for creating macros. Next, we'll show you how to create
  18316.    and manage QuickC's "program lists." Finally, we'll show you how to
  18317.    develop custom C libraries and how to access them from within QuickC.
  18318.  
  18319.  
  18320.  Advanced C Preprocessor
  18321.  
  18322.    Although compiling under QuickC appears to be a single swift process, it
  18323.    is actually three processes combined into one. First, your C program is
  18324.    "preprocessed." In this phase, conditional compilation occurs, and other
  18325.    preprocessing directives are executed: For example, #define MAX 3 converts
  18326.    all instances of MAX to 3. Second, the QuickC compiler translates your
  18327.    preprocessed code into machine language, or code that the computer can
  18328.    understand. Finally, your compiled machine code is combined (linked) with
  18329.    the precompiled code in the standard C Library of functions (such as
  18330.    printf()) to form the finished, executable program.
  18331.  
  18332.    Conditional compilation occurs in the preprocessing stage. Using lines
  18333.    that begin with a # character (pronounced "pound" or "number"), you can
  18334.    write code that compiles one way for testing and another for actual use.
  18335.    You can also write code that compiles differently on different machines or
  18336.    different compilers.
  18337.  
  18338.    The C preprocessor recognizes only lines of text that begin with the #
  18339.    character, such as #define and #include. Table 12-1 lists the complete
  18340.    set of these "preprocessor directives."
  18341.  
  18342.    Table 12-1 The Preprocessor Directives
  18343. ╓┌─┌───────────────┌─────────────────────────────────────────────────────────╖
  18344.    Directive       Description
  18345.    ──────────────────────────────────────────────────────────────────────────
  18346.    #define x y     Uses x as an alias for y throughout the program.
  18347.    #include <file> Reads file from the INCLUDE subdirectory and inserts it
  18348.                    into your program at this point.
  18349.    #include "file" Reads file from the current working directory and inserts
  18350.                    it into your program at this point.
  18351.    #ifdef x        If x is defined, compiles all program code between this
  18352.                    and the next matching #endif, #elif, or #else.
  18353.    #if (x)         If the integer constant expression x is true (nonzero),
  18354.                    compiles all program code between this directive and the
  18355.                    next matching #endif, #elif, or #else.
  18356.    Directive       Description
  18357.    ──────────────────────────────────────────────────────────────────────────
  18358.                   next matching #endif, #elif, or #else.
  18359.    #ifndef x       If x is not defined, compiles all program code between
  18360.                    this and the next matching #endif, #elif, or #else.
  18361.    #else           The inverse of the above three if directives. If the if is
  18362.                    true, the code before the #else is compiled. If the if is
  18363.                    false, the code following the #else is compiled.
  18364.    #elif (x)       The else if extension for #if in a chain of conditions.
  18365.    #endif          Terminates the current matching #if, #ifdef, or #ifndef.
  18366.    #line lineno    Sets the current line number to lineno and the current
  18367.    "file"          file to file.
  18368.    #pragma         Sets "compiler-specific" options.
  18369.    #define x(y) z  Defines preprocessor macros.
  18370.    ──────────────────────────────────────────────────────────────────────────
  18371.  
  18372.  
  18373.  Conditional Compilation
  18374.  
  18375.    Occasionally, you will need to compile only part of your code──for
  18376.    example, during debugging, or when you compile different versions for
  18377.    different users, or while compiling your program on a different computer
  18378.    or compiler. The C preprocessor offers an assortment of directives to
  18379.    facilitate this selective compiling process, called "conditional
  18380.    compilation."
  18381.  
  18382.    The #if and #endif Directives
  18383.  
  18384.    The most frequently used conditional directives are #if and #endif. The
  18385.    #if directive tests what is known as a restricted constant expression in
  18386.    your code to see if that expression is zero. If it is a nonzero (true)
  18387.    value, QuickC compiles all the code between that #if and its matching
  18388.    #endif. Use the directive as follows:
  18389.  
  18390.      #define BYTES 4
  18391.  
  18392.      #if (BYTES == 4)
  18393.      /* compile this code */
  18394.      #endif
  18395.  
  18396.    In this example, the expression (BYTES == 4) is a "constant expression"
  18397.    because it becomes (4 == 4) (the logical comparison of two integer
  18398.    constants). It is also a "restricted" constant expression, which is a
  18399.    constant expression that cannot contain:
  18400.  
  18401.    ■  sizeof operations
  18402.  
  18403.    ■  enumerated constants
  18404.  
  18405.    ■  typecasts
  18406.  
  18407.    ■  floating-point constants
  18408.  
  18409.    Therefore, the following directives are legal:
  18410.  
  18411.      #if (BYTES < 8)
  18412.      #if ((6 * 9 / 3) != (2 % 1))
  18413.  
  18414.    and the following are not:
  18415.  
  18416.      #if (sizeof(int) == 4)────────────────────────────────────sizeof illegal
  18417.  
  18418.      enum {true, false} yorn;
  18419.      #if (true == 0)──────────────────────────────Enumerated constant illegal
  18420.  
  18421.      #if (NULL == (char *)0)─────────────────────────────────Typecast illegal
  18422.  
  18423.      #if (MIN < 4.2)───────────────────────────────────float constant illegal
  18424.  
  18425.    One common use for the #define directive is in debugging. The program in
  18426.    Listing 12-1 on the following page, BUG.C, illustrates one possible way
  18427.    to use #define to change the behavior of your program. By using #define to
  18428.    define DEBUG_LEVEL to one of the values 0, 1, or 2, then recompiling and
  18429.    running, you will cause the program to print one of three messages to your
  18430.    screen. For a #define value of 0, nothing is printed; for 1, the calls to
  18431.    the subroutine sub() are documented; and for 2, entry into and exit from
  18432.    main() are printed.
  18433.  
  18434.    ──────────────────────────────────────────────────────────────────────────
  18435.    /* bug.c  --  shows how different levels of debugging  */
  18436.    /*            output can be produced using #if         */
  18437.  
  18438.    #define DEBUG_LEVEL 2     /* 0 = none, 1-2 for debug   */
  18439.    #include <stdio.h>
  18440.  
  18441.    main()
  18442.    {
  18443.        int ret;
  18444.  
  18445.    #if (DEBUG_LEVEL == 2)
  18446.        fprintf(stderr, "Entering main()\n");
  18447.    #endif
  18448.  
  18449.    #if (DEBUG_LEVEL == 1)
  18450.        fprintf(stderr, "Calling sub()\n");
  18451.    #endif
  18452.  
  18453.        ret = sub();
  18454.  
  18455.    #if (DEBUG_LEVEL == 1)
  18456.        fprintf(stderr, "sub() returned %d\n", ret);
  18457.    #endif
  18458.  
  18459.    #if (DEBUG_LEVEL == 2)
  18460.        fprintf(stderr, "Leaving main()\n");
  18461.    #endif
  18462.  
  18463.    }
  18464.  
  18465.    sub()
  18466.    {
  18467.        return (5);
  18468.    }
  18469.    ──────────────────────────────────────────────────────────────────────────
  18470.  
  18471.    Listing 12-1.  The BUG.C program.
  18472.  
  18473.    defined and #ifdef
  18474.  
  18475.    You can use the defined keyword with the #if directive to detect whether
  18476.    or not a name has been specified by #define:
  18477.  
  18478.      #if defined(name)
  18479.  
  18480.    If defined(name) determines that name was used in a #define directive, it
  18481.    evaluates to true. The keyword defined is used by the preprocessor only in
  18482.    this context; therefore, you can use it anywhere in your program without
  18483.    causing a conflict.
  18484.  
  18485.    The defined variation of #if replaces the pre-ANSI directive #ifdef. That
  18486.    is, although the following are equivalent:
  18487.  
  18488.      #if defined(name)
  18489.      #ifdef name
  18490.  
  18491.    the first form is preferable.
  18492.  
  18493.    You can use the same technique to see if a name has not been specified
  18494.    with #define, as follows:
  18495.  
  18496.      #if !defined(name)
  18497.      #ifndef name
  18498.  
  18499.    Again, the first form is preferable to the second.
  18500.  
  18501.    The defined variation of #if is especially useful for writing programs
  18502.    that will be compiled on another type of computer or a different compiler.
  18503.    The BITOUT.C program (Listing 12-2) is an adaptation of the Bitout()
  18504.    function used in the BITWISE.C program (Listing 7-12 on p. 218). After
  18505.    the user enters an integer, the program prints that integer in binary
  18506.    form. Note that it uses #if defined to print the bits one way on an
  18507.    80286-based computer and another way on a 68000-based machine.
  18508.  
  18509.    ──────────────────────────────────────────────────────────────────────────
  18510.    /* bitout.c  -- compiles one way on an IBM PC and      */
  18511.    /*              another on a 68000 chip─based machine  */
  18512.  
  18513.    #define CHIP_80286    /* don't define on a 68000 machine */
  18514.    #include <stdio.h>
  18515.  
  18516.    main()
  18517.    {
  18518.        int num;
  18519.  
  18520.        printf("Enter an integer number and I will print"
  18521.               " it out in binary\nNumber: ");
  18522.  
  18523.        if (scanf("%d", &num) != 1)
  18524.            {
  18525.            fprintf(stderr, "Not an integer\n");
  18526.            exit(1);
  18527.            }
  18528.        Bitout(num);
  18529.    }
  18530.  
  18531.    Bitout(unsigned int num)
  18532.    {
  18533.        int i, j;
  18534.        unsigned char *cp;
  18535.  
  18536.        cp = (char *)#
  18537.    #if defined(CHIP_80286)    /* IBM PC */
  18538.        for (i = 1; i >= 0; --i)
  18539.    #endif
  18540.    #if !defined(CHIP_80286)   /* otherwise 68000 machine */
  18541.        for (i = 0; i < 4; ++i)
  18542.    #endif
  18543.            {
  18544.            for (j = 7; j >= 0; --j)
  18545.                putchar((cp[i] & (1 << j)) ? '1' : '0');
  18546.            }
  18547.        putchar('\n');
  18548.    }
  18549.    ──────────────────────────────────────────────────────────────────────────
  18550.  
  18551.    Listing 12-2.  The BITOUT.C program.
  18552.  
  18553.    #else and elif
  18554.  
  18555.    We can simplify the two #if directives in BITOUT.C by using the #else
  18556.    directive:
  18557.  
  18558.      #if defined(CHIP_80286)
  18559.          for (i = 1; i >= 0; --i)
  18560.      #else
  18561.          for (i = 0; i < 4; ++i)
  18562.      #endif
  18563.  
  18564.    In this example, the preprocessor compiles the first for statement if
  18565.    CHIP_80286 has been defined using #define; otherwise, it compiles the
  18566.    second for statement.
  18567.  
  18568.    By using the #elif (else if) directive, you can create a whole chain of
  18569.    conditions. The following series of directives, for example,
  18570.  
  18571.      #if defined(CHIP_8086)
  18572.          for (i = 1; i >= 0; --i)
  18573.      #elif defined(CHIP_80286)
  18574.          for (i = 1; i >= 0; --i)
  18575.      #elif defined(CHIP_68000)
  18576.          for (i = 0; i < 4; ++i)
  18577.      #else
  18578.          fprintf(stderr, "Unknown chip\n");
  18579.          return;
  18580.      #endif
  18581.  
  18582.    tells the preprocessor to compile the first for statement if CHIP_8086 is
  18583.    defined, to compile the second for statement if CHIP_80286 is defined, or
  18584.    to compile the third for statement if CHIP_68000 is defined. If none of
  18585.    these is defined, the preprocessor compiles code to print an error and
  18586.    return.
  18587.  
  18588.    Logical Operators and #if
  18589.  
  18590.    Many of the preceding #if tests use similar code. You can take a coding
  18591.    shortcut by combining #if expressions using the C logical operators && and
  18592.    ||. For example, you can shorten the previous #elif sequence by using the
  18593.    logical OR operator as follows:
  18594.  
  18595.                             ┌──────────────────────────────────── Logical OR
  18596.      #if defined(CHIP_8086) || defined(CHIP_80286)
  18597.          for (i = 1; i >= 0; --i)
  18598.      #elif defined(CHIP_68000)
  18599.          for (i = 0; i < 4; ++i)
  18600.      #else
  18601.          fprint(stderr, "Unknown chip\n");
  18602.          return;
  18603.      #endif
  18604.  
  18605.    The #if directives and their corresponding #endif and #elif directives can
  18606.    be nested. However, when you nest them, we recommend that you use indents
  18607.    to show the levels of nesting, as follows:
  18608.  
  18609.      #if defined(IBMPC)
  18610.          #if defined(CGA) || defined(EGA)
  18611.              sp = (int far *)0xB8000000;
  18612.          #else
  18613.              sp = (int far *)0xB0000000;
  18614.          #endif
  18615.      #else
  18616.          fprintf(stderr, "No Screen Memory\n");
  18617.          return;
  18618.      #endif
  18619.  
  18620.    In this example, if IBMPC is not defined, the last #else executes. If
  18621.    IBMPC is defined, the program checks to see if either CGA or EGA (for the
  18622.    corresponding graphic adapter cards) is defined. If either is, we assign
  18623.    the address value 0xB8000000 (the location of screen memory for those
  18624.    cards) to the pointer sp. Otherwise, we use the address 0xB0000000 (the
  18625.    location of screen memory for the regular monochrome adapter).
  18626.  
  18627.    You can avoid problems when using # preprocessor directives by remembering
  18628.    two general rules. First, the # must always begin a line. Second, each
  18629.    directive can occupy only one line unless you extend it by typing a
  18630.    backslash and pressing Enter:
  18631.  
  18632.      #if defined(EGA) \─────────────────────────────────────────Line extended
  18633.          ||    \────────────────────────────────────────────────Line extended
  18634.          defined(CGA)
  18635.  
  18636.    Predefined Names
  18637.  
  18638.    QuickC always predefines two names: __FILE__ and __LINE__. (Note that both
  18639.    have two leading and two trailing underscore characters.) The name
  18640.    __FILE__ is always the name of the current C source file being compiled.
  18641.    It is a quoted string constant, so you can safely use it anywhere that
  18642.    strings are legal. The predefined name __LINE__ is an integer constant
  18643.    number that is always the current line number in the current file. You can
  18644.    use it anywhere as a legal integer constant.
  18645.  
  18646.    These two predefined names are generally used to print meaningful
  18647.    diagnostics during debugging. The ERR.C program (Listing 12-3)
  18648.    demonstrates their use for tracing the flow of a small program. By placing
  18649.    a #define ERR inside a #if directive, you can turn on and off custom
  18650.    tracing with a single change in code:
  18651.  
  18652.      #define TRACE 0      /* change to 1 to turn on */
  18653.  
  18654.      #if (TRACE > 0)
  18655.      #define ERR printf("Tracing: \"%s\" line %d\n",\
  18656.                          __FILE__, __LINE__ );
  18657.      #else
  18658.      #define ERR
  18659.      #endif
  18660.  
  18661.    If TRACE is defined as a value greater than zero, QuickC traces the
  18662.    program. If, on the other hand, TRACE is 0, then tracing is disabled.
  18663.  
  18664.    ──────────────────────────────────────────────────────────────────────────
  18665.    /* err.c  --  illustrates __FILE__ and __LINE__ in */
  18666.    /*            tracing a small program              */
  18667.  
  18668.    #define ERR printf("Tracing: \"%s\" line %d\n",\
  18669.                        __FILE__, __LINE__);
  18670.    main()
  18671.    {
  18672.        ERR
  18673.        err1();
  18674.        ERR
  18675.        err2();
  18676.        ERR
  18677.    }
  18678.  
  18679.    err1()
  18680.    {
  18681.        ERR
  18682.        err2();
  18683.    }
  18684.  
  18685.    err2()
  18686.    {
  18687.        ERR
  18688.    }
  18689.    ──────────────────────────────────────────────────────────────────────────
  18690.  
  18691.    Listing 12-3.  The ERR.C program.
  18692.  
  18693.  #pragma Instructions to the Compiler
  18694.  
  18695.    You can use the #pragma preprocessor directive to give compiler-specific
  18696.    instructions to the compiler (that is, instructions that usually must be
  18697.    given as part of the MS-DOS command line or by presetting QuickC's compile
  18698.    time options). Use it in the following way:
  18699.  
  18700.      #pragma instruction
  18701.  
  18702.    #pragma pack(1|2|4)
  18703.  
  18704.    The pack pragma tells the compiler to place structure members into memory
  18705.    on 1-byte, 2-byte, or 4-byte boundaries. Ordinarily, QuickC places
  18706.    structure members into memory so that int and long types always begin in
  18707.    an even address, which is equivalent to pack(2). (See Figure 12-1a.) By
  18708.    using the #pragma pack() preprocessor directive, you can tell the compiler
  18709.    to store structures in a smaller space (see Figure 12-1b) or to spread
  18710.    them out into a larger space with pack(4). (See Figure 12-1c.)
  18711.  
  18712.                            ┌──
  18713.                            │ struct {
  18714.                            │   char a;
  18715.                            │   int b;
  18716.      For the declaration ──┤   char c;
  18717.                            │   long d;
  18718.                            │ };
  18719.                            └──
  18720.  
  18721.                                                            ┌───────┐─┐
  18722.                                                        400 │       │ ├─a
  18723.                                                            ├───────┤─┤
  18724.                                                        401 │       │ │
  18725.         ┌───────┐─┐                ┌───────┐─┐             ├─     ─┤ │
  18726.     402 │       │ ├─a          402 │       │ ├─a       402 │       │ ├─unused
  18727.         ├───────┤─┤                ├───────┤─┤             ├─     ─┤ │
  18728.     403 │       │ ├─unused     403 │       │ │         403 │       │ │
  18729.         ├───────┤─┤                ├─     ─┤ ├─b           ├───────┤─┤
  18730.     404 │       │ │            404 │       │ │         404 │       │ │
  18731.         ├─     ─┤ ├─b              ├───────┤─┤             ├─     ─┤ ├─b
  18732.     405 │       │ │            405 │       │ ├─c       405 │       │ │
  18733.         ├───────┤─┤                ├───────┤─┤             ├───────┤─┤
  18734.     406 │       │ ├─c          406 │       │ │         406 │       │ ├─c
  18735.         ├───────┤─┤                ├─     ─┤ │             ├───────┤─┤
  18736.     407 │       │ ├─unused     407 │       │ │         407 │       │ ├─unused
  18737.         ├───────┤─┤                ├─     ─┤ ├─d           ├───────┤─┤
  18738.     408 │       │ │            408 │       │ │         408 │       │ │
  18739.         ├─     ─┤ │                ├─     ─┤ │             ├─     ─┤ │
  18740.     409 │       │ │            409 │       │ │         409 │       │ │
  18741.         ├─     ─┤ ├─ d             └───────┘─┘             ├─     ─┤ ├─d
  18742.     410 │       │ │                                    410 │       │ │
  18743.         ├─     ─┤ │                                        ├─     ─┤ │
  18744.     411 │       │ │                                    411 │       │ │
  18745.         └───────┘─┘                                        └───────┘─┘
  18746.  
  18747.    (A) RESULT OF USING         (B) RESULT OF US
  18748.    ING     (C) RESULT OF USING
  18749.       #pragma pack (2)            #pragma pack (1)        #pragma pack (4)
  18750.        (QuickC default)
  18751.  
  18752.    Figure 12-1. The pack() pragma determines how structures are placed
  18753.    into memory.
  18754.  
  18755.    The PACK.C program (Listing 12-4) illustrates this structure packing.
  18756.    When you run the program, note the addresses it prints. Then change the 1
  18757.    in #pragma pack(1) to a 2 and recompile and run PACK.C again. Finally,
  18758.    change that 2 to a 4 and repeat the process.
  18759.  
  18760.    An extension to the #pragma pack() directive lets you turn packing on and
  18761.    off:
  18762.  
  18763.      #pragma pack(1)─────────────────────────────────────Set one-byte packing
  18764.      ...
  18765.      #pragma pack() no───────────────────────────────────────Turn packing off
  18766.      ...
  18767.      #pragma pack() yes──────────────────────────────────Turn packing back on
  18768.  
  18769.    The example first tells the compiler to pack all structure members to the
  18770.    nearest 1-byte boundary. Next, the no tells the compiler to stop packing
  18771.    and revert to its default even-byte boundary arrangement. Finally, the yes
  18772.    tells the compiler to resume packing on 1-byte boundaries.
  18773.  
  18774.    ──────────────────────────────────────────────────────────────────────────
  18775.    /* pack.c  --  demonstrates structure packing with */
  18776.    /*             the #pragma pack() directive        */
  18777.  
  18778.    #pragma pack(4)        /* 1, 2 or 4 */
  18779.  
  18780.    main()
  18781.    {
  18782.        struct {
  18783.            char ch1;
  18784.            int  int1;
  18785.            char ch2;
  18786.            long int2;
  18787.        } s;
  18788.  
  18789.        printf("ch1  -> %lu\n", (unsigned long)(&s.ch1));
  18790.        printf("int1 -> %lu\n", (unsigned long)(&s.int1));
  18791.        printf("ch2  -> %lu\n", (unsigned long)(&s.ch2));
  18792.        printf("int2 -> %lu\n", (unsigned long)(&s.int2));
  18793.    }
  18794.    ──────────────────────────────────────────────────────────────────────────
  18795.  
  18796.    Listing 12-4.  The PACK.C program.
  18797.  
  18798.    ──────────────────────────────────────────────────────────────────────────
  18799.    Quick Tip
  18800.    The Intel 80386 chip executes at its fastest if int and long types begin
  18801.    on modulo 4-byte address boundaries. The Intel 80286 and earlier chips
  18802.    execute fastest when those types begin on even addresses. If size is more
  18803.    important to you than speed, use the #pragma pack(1) directive.
  18804.    ──────────────────────────────────────────────────────────────────────────
  18805.  
  18806.  Preprocessor Macros
  18807.  
  18808.    The #define preprocessor directive has a second form that is called a
  18809.    #define macro, or a preprocessor macro. The #define macro is an extremely
  18810.    powerful tool, used by programmers to place "in-line" code into a program
  18811.    in a manner that resembles a subroutine call. Take a moment to use
  18812.    QuickC's View Include feature to look at the <stdio.h> header file. Notice
  18813.    in line 105 of that file that the getc() function you have been using all
  18814.    along is not really a function at all. It is a #define macro. Because it
  18815.    is a macro, the preprocessor expands each occurrence of getc(stdin) in
  18816.    your program to the following:
  18817.  
  18818.      (────(stdin)->cnt >= 0 ? 0xFF & *(stdin)->_ptr++ : _filbuf(stdin))
  18819.  
  18820.    Certainly, it is easier to type getc(stdin) than to type this complex code
  18821.    sequence.
  18822.  
  18823.    The form for a #define macro is as follows:
  18824.  
  18825.      #define TRIPLE(x) (x*3)
  18826.  
  18827.    In this example, the defined name is TRIPLE and the (x) is its formal
  18828.    argument. The expression TRIPLE(x) is defined as an alias for the
  18829.    expression (x*3). This means that anywhere in the program that you use the
  18830.    following expression:
  18831.  
  18832.      TRIPLE(2)
  18833.  
  18834.    the actual argument (here 2) replaces every occurrence of the formal
  18835.    argument, x, in the original definition. This produces the following
  18836.    expansion:
  18837.  
  18838.      TRIPLE(2)
  18839.         │
  18840.         ├───────────────────────────────────────────────────────── Expands to
  18841.         │
  18842.         
  18843.      (2*3)
  18844.  
  18845.    To illustrate further, examine the following macro definition for MAX, a
  18846.    macro that compares two values and yields a new value that is the higher
  18847.    of the two:
  18848.  
  18849.                  ┌─┬──────────────────────────────────── Two formal arguments
  18850.      #define MAX(x,y) (((x) > (y)) ? (x) : (y))          separated by a comma
  18851.              └──┬───┘ └──────────┬───────────┘
  18852.                 │                └────────────────────────── Macro definition
  18853.                 └────────────────────────────────────────────────────── Macro
  18854.  
  18855.    This example shows that macros can take more than one formal argument──but
  18856.    arguments must be separated from one another by commas. The x in the macro
  18857.    replaces each x in the macro definition with its corresponding actual
  18858.    argument, and each y replaces its corresponding y. If you use the above
  18859.    macro definition in your code and then use the following expression:
  18860.  
  18861.      oldest = MAX(age1, age2);
  18862.  
  18863.    with int variables age1 and age2, the preprocessor expands the macro as
  18864.    follows:
  18865.  
  18866.      oldest = (((age1) > (age2)) ? (age1) : (age2));
  18867.  
  18868.    Potential Problems with Macros
  18869.  
  18870.    Use preprocessor macros with care──actual arguments to macros can cause
  18871.    unexpected changes, such as reading an extra character. You should avoid
  18872.    using the following types of arguments because they can produce unwanted
  18873.    side effects:
  18874.  
  18875.    ■  function calls
  18876.  
  18877.    ■  other macros
  18878.  
  18879.    ■  the increment (++) and decrement (--) operators
  18880.  
  18881.    ■  the assignment operator (=)
  18882.  
  18883.    For example, consider the following ISQ macro:
  18884.  
  18885.      #define ISQ(letter) ((letter) == 'q' || (letter) == 'Q')
  18886.  
  18887.    This macro detects whether a letter is an uppercase or lowercase 'Q' and
  18888.    is useful for testing if a user is quitting a program. You correctly use
  18889.    this macro as follows:
  18890.  
  18891.      ch = getchar();
  18892.  
  18893.      if (ISQ(ch))
  18894.          exit(0);
  18895.  
  18896.    In the preceding code, ch is a char variable; therefore, the if statement
  18897.    expands to
  18898.  
  18899.      if (((ch) == 'q' || (ch) == 'Q'))
  18900.  
  18901.    which is what you expect. However, if you use this macro incorrectly──for
  18902.    example, with a function call such as getchar(),
  18903.  
  18904.      if (ISQ(getchar()))
  18905.  
  18906.    it expands to an expression that doesn't do what you expect:
  18907.  
  18908.      if (((getchar()) == 'q' || (getchar()) == 'Q'))
  18909.  
  18910.    This example illustrates a common problem. The first call to getchar()
  18911.    reads a character and compares the value to 'q'. If that character is not
  18912.    a 'q', getchar() is called again to read a new character and to compare
  18913.    the new character to 'Q'. This is not what you intended, however. You want
  18914.    MAX to read only the first character and then to compare that character to
  18915.    both 'q' and 'Q'.
  18916.  
  18917.    Macros and Semicolons
  18918.  
  18919.    Never end a macro definition with a semicolon. For example, the following
  18920.    macro converts a printable character into a control character value:
  18921.  
  18922.      #define CTRL(x) ('x' - '@');
  18923.  
  18924.    The expression CTRL(A) expands to the expression ('A' - '@'); and yields
  18925.    the desired ASCII value 1 (Ctrl-A). However, the trailing semicolon causes
  18926.    a syntax error when you use the macro in an expression such as:
  18927.  
  18928.      printf("And 'A' prints as %c\n", CTRL(A));
  18929.  
  18930.    Note the syntax error that results when this expands to
  18931.  
  18932.       printf("And 'A' prints as %c\n", ('A'-'@'););
  18933.                                                 └────────────────────── Wrong
  18934.  
  18935.    Macros and Quotes
  18936.  
  18937.    As in normal #define directives, preprocessor macros do not substitute
  18938.    actual arguments inside full quotation marks. For example, the following
  18939.    macro would be a useful tool for debugging:
  18940.  
  18941.      #define PERR(x) printf("The value of x is %d\n", x)
  18942.  
  18943.    Unfortunately it won't work. Because the first x is inside full quotation
  18944.    marks, it isn't expanded. However, the final x is expanded:
  18945.  
  18946.      int val = 5;
  18947.      PERR(val);
  18948.      └────┬───┘
  18949.           └───────────┬─────────────────────────────────────────── Expands to
  18950.                       │
  18951.      ┌──────────────────────────────────┐
  18952.      printf("The value of x is %d\n", val);
  18953.  
  18954.    We can rectify this by using the preprocessor's "stringizing" operator #.
  18955.    When placed before a formal argument in a macro definition, the # causes
  18956.    that argument to be expanded and quoted. Thus, the correct way to define
  18957.    PERR is as follows:
  18958.  
  18959.      #define PERR(x) printf("The value of " #x " is %d\n", x)
  18960.                                             └─────────── Stringizing operator
  18961.  
  18962.    This correctly expands as:
  18963.  
  18964.      int val = 5;
  18965.      PERR(val);
  18966.      └───┬───┘
  18967.          └───────────┬──────────────────────────────────────────── Expands to
  18968.                      │
  18969.      ┌──────────────────────────────────────────┐
  18970.      printf("The value of " "val" " is %d\n", val);
  18971.  
  18972.    The example works because the compiler joins adjacent quoted string
  18973.    constants into a single string. The result is that printf() correctly
  18974.    prints the following:
  18975.  
  18976.      The value of val is 5
  18977.  
  18978.  
  18979.  Using QuickC for Large Projects
  18980.  
  18981.    Imagine you are writing a text editor program such as the one shown in
  18982.    Figure 12-2 on p. 381. With sufficient memory, QuickC can easily load and
  18983.    compile programs of this size. However, the larger a program is, the
  18984.    longer it takes to compile, load, and save. Therefore, you can manage
  18985.    large programs more easily when you break them into several smaller files
  18986.    by logically grouping the subroutines according to use. This approach has
  18987.    several advantages.
  18988.  
  18989.    ■  When a program consists of several files, you need to recompile only
  18990.       those files that change.
  18991.  
  18992.    ■  Grouping subroutines by usage lets you easily trace the logic of the
  18993.       program during debugging.
  18994.  
  18995.    ■  Perfected subroutines that no longer need to be recompiled can be
  18996.       shared by many programs.
  18997.  
  18998.  QuickC Program Lists
  18999.  
  19000.    The QuickC "program list" feature compiles several small files or library
  19001.    modules and combines them into a single executable program. This lets you
  19002.    create complex, large programs from many small, easily maintained files.
  19003.    Before we examine this feature, enter and save the following three files:
  19004.    TEXED.C (Listing 12-5), KEYS.C (Listing 12-6), and FILE.C (Listing
  19005.    12-7 on the following page). These are three small pieces of our
  19006.    imaginary text editor in Figure 12-2. Although these modules don't do
  19007.    much, they demonstrate the basics of using QuickC program lists.
  19008.  
  19009.    ──────────────────────────────────────────────────────────────────────────
  19010.    /* texed.c  --  main entry point to the editor; the   */
  19011.    /*              menu and signal handlers are here     */
  19012.  
  19013.    main(argc, argv)
  19014.    int argc;
  19015.    char *argv[];
  19016.    {
  19017.        char ch;
  19018.  
  19019.        while (1)
  19020.            {
  19021.            printf("\nTexEd Main Menu\n");
  19022.            printf("Select from:\n");
  19023.            printf("0) Quit\n\n");
  19024.            printf("1) Load File\n");
  19025.            printf("2) Save File\n");
  19026.            printf("3) Edit File\n");
  19027.            printf("Which: ");
  19028.            do
  19029.                {
  19030.                ch = getch();
  19031.                ch -= '0';
  19032.                } while (ch < 0 || ch > 3);
  19033.            printf("%d\n\n", (int)ch);
  19034.            switch(ch)
  19035.                {
  19036.                case 0: exit(0);
  19037.                case 1: Load_file(); break;
  19038.                case 2: Save_file(); break;
  19039.                case 3: Edit_file(); break;
  19040.                }
  19041.            }
  19042.    }
  19043.    ──────────────────────────────────────────────────────────────────────────
  19044.  
  19045.    Listing 12-5.  The TEXED.C file.
  19046.  
  19047.    2000-line text editor                Broken into separate files
  19048.    ┌───────────────────┐               ┌─┌───────────────────┐
  19049.    │                   │               │ │ Main()            │
  19050.    │                   │               │ │ Signal handlers   │────texted.c
  19051.    │                   │               │ │ menu()            │
  19052.    │                   │               │ ├───────────────────┤
  19053.    │                   │               │ │                   │
  19054.    │                   │               │ │ Read and process  │────keys.c
  19055.    │                   │               │ │ typed keys        │
  19056.    │                   │               │ ├───────────────────┤
  19057.    │                   │               │ │                   │
  19058.    │                   │───texted.c───│ │ Update the        │────screen.c
  19059.    │                   │               │ │ screen            │
  19060.    │                   │               │ ├───────────────────┤
  19061.    │                   │               │ │                   │
  19062.    │                   │               │ │ Special commands  │────cmds.c
  19063.    │                   │               │ │ like 'delete line'│
  19064.    │                   │               │ ├───────────────────┤
  19065.    │                   │               │ │                   │
  19066.    │                   │               │ │ File read and     │────file.c
  19067.    │                   │               │ │ write routines    │
  19068.    └───────────────────┘               └─└───────────────────┘
  19069.  
  19070.    Figure 12-2. A large program is often best split into several smaller and
  19071.    more manageable files.
  19072.  
  19073.    ──────────────────────────────────────────────────────────────────────────
  19074.    /* keys.c  --   The keyboard input-handling routines  */
  19075.    /*              for the texed editor                  */
  19076.  
  19077.    Edit_file()
  19078.    {
  19079.        char ch;
  19080.  
  19081.        printf("\nYou are now in the editor.\n");
  19082.        printf("Press 'Q' to exit back to main menu.\n");
  19083.  
  19084.        do
  19085.            {
  19086.            ch = getch();
  19087.            putch(ch);
  19088.            } while (ch != 'Q');
  19089.  
  19090.        printf("\n\n");
  19091.    }
  19092.    ──────────────────────────────────────────────────────────────────────────
  19093.  
  19094.    Listing 12-6.  The KEYS.C file.
  19095.  
  19096.    ──────────────────────────────────────────────────────────────────────────
  19097.    /* file.c  --  the file I/O routines for texed */
  19098.  
  19099.    Load_file()
  19100.    {
  19101.        printf("\nLoading ..... done.\n");
  19102.    }
  19103.  
  19104.    Save_file()
  19105.    {
  19106.        printf("\nSaving ...... done.\n");
  19107.    }
  19108.    ──────────────────────────────────────────────────────────────────────────
  19109.  
  19110.    Listing 12-7.  The FILE.C file.
  19111.  
  19112.    Next select Set Program List from the File menu and enter texed.mak in the
  19113.    File Name text box. This program list name is composed of two parts. The
  19114.    first, texed, is the name of your finished program. The second, the
  19115.    extension .mak, signifies that this program list file is a "make" file.
  19116.    (We'll explain make files in the next section.)
  19117.  
  19118.    After you enter the name texed.mak, QuickC prompts "`texed.mak' does not
  19119.    exist Create?". A Yes response displays the Edit Program List dialog box.
  19120.    This is where you specify the files in your program list. Enter the
  19121.    filenames TEXED.C, KEYS.C, and FILE.C. As you enter each, its name appears
  19122.    in the bottom window labeled Program List. After you enter all three
  19123.    files, your screen appears as in Figure 12-3. Now choose the Save List
  19124.    option to save your program list on disk and return to the main QuickC
  19125.    screen.
  19126.  
  19127.    ┌────────────────────────────────────────────────────────────────────────┐
  19128.    │ Figure 12-3 can be found on p.382 of the printed version of the book.  │
  19129.    └────────────────────────────────────────────────────────────────────────┘
  19130.  
  19131.    Figure 12-3. The Edit Program List dialog box.
  19132.  
  19133.    At the bottom left of the QuickC screen you now see Program List: Texed.
  19134.    This message signals that you will build your program from several files,
  19135.    not only from the one currently loaded, and that those files are in the
  19136.    program list named Texed. TEXED.MAK has three files in it, and TEXED.C is
  19137.    one of them. Now, every time you open TEXED.C, QuickC reminds you that a
  19138.    .MAK file and various other files are connected to it.
  19139.  
  19140.    To compile a program from a program list, display the Compile dialog box,
  19141.    but this time, instead of selecting Compile File, select Build Program.
  19142.    Notice that each of your files is loaded in turn and compiled. After all
  19143.    three have been compiled, the Microsoft Overlay Loader executes. This link
  19144.    program combines your compiled files, along with any precompiled routines
  19145.    that you use from the standard C Library (such as printf()). This process
  19146.    creates a single, executable program that you can run from within QuickC.
  19147.  
  19148.  Program List Files
  19149.  
  19150.    Program list files contain rules and instructions that tell QuickC how to
  19151.    build your program. They are composed of four elements: comment lines
  19152.    (lines that begin with a # character), production rules, dependencies, and
  19153.    link commands. Look inside the TEXED.MAK file that follows. This is a make
  19154.    file, a subset of the kind used by the MAKE program.
  19155.  
  19156.      #
  19157.      # Program; Texed
  19158.      #
  19159.  
  19160.      .c.obj:───────────────────────────Production rule--turn a .C into a .OBJ
  19161.          qcl  -c  -W1  -Ze  -AM $*.c─────────How to accomplish the above rule
  19162.  
  19163.      texed.obj : texed.c────────────┬────────────────────────────Dependencies
  19164.                                     │
  19165.      keys.obj : keys.c──────────────┤
  19166.                                     │
  19167.      file.obj : file.c──────────────┘
  19168.  
  19169.      Texed.exe : texed.obj keys.obj file.ob─More dependencies used to go from
  19170.           del Texed.lnk                     .OBJs to. EXEs
  19171.           echo texed.obj+ >>Texed.lnk
  19172.           echo keys.obj+ >>Texed.lnk
  19173.           echo file.obj >>Texed.lnk
  19174.           echo Texed.exe >>Texed.lnk
  19175.           echo Texed.map >>Texed.lnk
  19176.           link @Texed.lnk /NOI $(LDFLAGS);
  19177.  
  19178.    Production Rules in Program List Files
  19179.  
  19180.    A production rule is a description of how one file type is changed into
  19181.    another. For example, the production rule in our program list
  19182.  
  19183.      .c.obj:
  19184.       └──┴────────────────────────────────────Turn a .C file into a .OBJ file
  19185.  
  19186.    tells QuickC to change .C files (such as KEYS.C) into precompiled object
  19187.    files called .OBJ files (such as KEYS.OBJ). Microsoft's Overlay Loader
  19188.    later links these .OBJ files with functions from the standard C Library to
  19189.    produce the executable program.
  19190.  
  19191.    The line following the production rule is the command line:
  19192.  
  19193.      qcl -c -W1 -Ze -AM $*.c
  19194.  
  19195.    This tells QuickC how to make the transformation specified in the first
  19196.    line. It is the same command line you would enter at the MS-DOS prompt,
  19197.    except for the $*.c. The $*.c tells QuickC to use the name of a real .C
  19198.    file, such as KEYS.C, at this position in the command line. The other
  19199.    elements represent the following:
  19200.  
  19201.    Element  Description
  19202.    ──────────────────────────────────────────────────────────────────────────
  19203.    qcl      The command-line version of QuickC.
  19204.    -c       Compile to a .OBJ file and stop. That is, do not continue by
  19205.             calling LINK.
  19206.    -W1      Set the compile time warning level to level 1.
  19207.    -Ze      Handle language extensions, such as far, as reserved keywords.
  19208.    -AM      Use the medium-memory model.
  19209.    ──────────────────────────────────────────────────────────────────────────
  19210.  
  19211.    Production rules are one of the features of QuickC program lists that make
  19212.    building programs easy. For example, when you select the Compile menu to
  19213.    compile KEYS.C, you don't have to enter the command line. Instead, QuickC
  19214.    runs the following MS-DOS command:
  19215.  
  19216.      qcl -c -W1 -Ze -AM keys.c
  19217.  
  19218.    and compiles KEYS.C into KEYS.OBJ.
  19219.  
  19220.    Dependency Lines in the Program List File
  19221.  
  19222.    Dependency lines tell QuickC how to create one file from two or more
  19223.    files. A dependency has the following form:
  19224.  
  19225.      target : infile1 infile2 ...
  19226.  
  19227.    This tells QuickC to create a new "target" file (usually a .OBJ or .EXE)
  19228.    if any infiles have changed and to make that target by running the
  19229.    specified MS-DOS command line. Examine the following dependency lines in
  19230.    TEXED.MAK:
  19231.  
  19232.      texed.obj : texed.c
  19233.  
  19234.      keys.obj : keys.c
  19235.  
  19236.      file.obj : file.c
  19237.  
  19238.      Texed.exe : texed.obj keys.obj file.obj
  19239.            del Texed.lnk
  19240.            ...
  19241.  
  19242.    Note that each of the first three lines is followed by a blank line (no
  19243.    MS-DOS command line). We'll discuss these first three dependencies first,
  19244.    then we'll cover the last in detail.
  19245.  
  19246.    When a dependency does not specify an MS-DOS command line, QuickC uses the
  19247.    previously defined production rule (.c.obj:) in place of the missing
  19248.    command line. For the first three lines, then, the command line derived
  19249.    from the production rule becomes the following:
  19250.  
  19251.      texed.obj : texed.c
  19252.          qcl -c -W1 -Ze -AM texed.c
  19253.  
  19254.      keys.obj : keys.c
  19255.          qcl -c -W1 -Ze -AM keys.c
  19256.  
  19257.      file.obj : file.c
  19258.          qcl -c -W1 -Ze -AM texed.c
  19259.  
  19260.    Running the Linker
  19261.  
  19262.    The dependency for TEXED.EXE, the executable file of your finished
  19263.    program, is as follows:
  19264.  
  19265.      Texed.exe : texed.obj keys.obj file.obj───────────────────────Dependency
  19266.  
  19267.    The dependency tells QuickC to create TEXED.EXE from TEXED.OBJ, KEYS.OBJ,
  19268.    and FILE.OBJ.
  19269.  
  19270.    The LINK program combines your .OBJ files with subroutines from the
  19271.    standard C Library and creates an executable (.EXE) program as the result.
  19272.    When you run the LINK program, it asks you the following series of
  19273.    questions:
  19274.  
  19275.      Object Modules [.OBJ]:
  19276.      Run File [.EXE]:
  19277.      List File [NUL.MAP]:
  19278.  
  19279.    First, LINK asks for the names of the .OBJ files you want to combine to
  19280.    form your program. Add a + to each file that you specify to tell LINK that
  19281.    you will add more .OBJ files. The LINK program continues to prompt for
  19282.    object modules until you list one without a trailing +:
  19283.  
  19284.      Object Modules [.OBJ]:texed.obj+
  19285.      Object Modules [.OBJ]:keys.obj+
  19286.      Object Modules [.OBJ]:file.obj
  19287.  
  19288.    Next, LINK prompts for the name of your executable program (Run File). In
  19289.    our example, we enter the name texed.exe.
  19290.  
  19291.    Finally, LINK asks for the name of a "map" file. A map file merely
  19292.    contains a cross-referenced listing of your executable program. Therefore,
  19293.    you respond as follows:
  19294.  
  19295.      List File [NUL.MAP]:texed.map
  19296.  
  19297.    Using LINK from a Text File
  19298.  
  19299.    When you run LINK, you have the option to use a text file that contains
  19300.    the prewritten answers to its questions. To do this, when you run LINK,
  19301.    specify the file by preceding its name with an "at" character, @, as
  19302.    follows:
  19303.  
  19304.      link @Texed.lnk
  19305.               └──────── File questions containing answers to LINK's questions
  19306.  
  19307.    To understand how this works, let's examine the MS-DOS commands that
  19308.    follow the dependency for TEXED.EXE in your TEXED.MAK program list file:
  19309.  
  19310.      Texed.exe : texed.obj keys.obj file.─────────────── Dependency
  19311.              del Texed.lnk──────────────────────┐
  19312.              echo texed.obj+ >>Texed.lnk        │
  19313.              echo keys.obj+ >>Texed.lnk         │
  19314.              echo file.obj >>Texed.lnk          ├─────── MS-DOS command lines
  19315.              echo Texed.exe >>Texed.lnk         │
  19316.              echo Texed.map >>Texed.lnk         │
  19317.              link @Texed.lnk /NOI $(LDFLAGS);───┘
  19318.  
  19319.    First, the file TEXED.LNK is deleted in case it already exists. Next, five
  19320.    "redirect and append" commands (>>) tell echo to place the text into the
  19321.    file TEXED.LNK. TEXED.LNK now contains the following lines:
  19322.  
  19323.      texed.obj+
  19324.      keys.obj+
  19325.      file.obj
  19326.      Texed.exe
  19327.      Texed.map
  19328.  
  19329.    Finally, LINK executes using the file @TEXED.LNK as the file that contains
  19330.    the answers to its questions. This is equivalent to running LINK yourself
  19331.    and answering those questions as follows:
  19332.  
  19333.      Object Modules [.OBJ]:texed.obj+
  19334.      Object Modules [.OBJ]:keys.obj+
  19335.      Object Modules [.OBJ]:file.obj
  19336.      Run File [.EXE]:Texed.exe
  19337.      List File [NUL.MAP]:Texed.map
  19338.  
  19339.    Other Arguments to LINK
  19340.  
  19341.    The LINK command in our TEXED.MAK program list file has two arguments in
  19342.    addition to the @TEXED.LNK argument:
  19343.  
  19344.       link @Texed.lnk /NOI $(LDFLAGS);
  19345.                         │       └──────────────────────────────── Other flags
  19346.                         └────────────────────────────────── Don't ignore case
  19347.  
  19348.    The first, /NOI, tells LINK not to ignore case. That is, it tells LINK to
  19349.    treat uppercase letters as different from lowercase letters in variable
  19350.    and function names.
  19351.  
  19352.    The second, $(LDFLAGS), is a make macro definition that QuickC defines as
  19353.    nothing. To modify your .MAK program list file and add arguments to LINK,
  19354.    you must define LDFLAGS. See Chapter 11 in your Microsoft QuickC
  19355.    Programmer's Guide for information about this procedure. But beware, the
  19356.    LDFLAGS macro is the only macro that QuickC recognizes and preserves.
  19357.  
  19358.  Keeping Track of Changes
  19359.  
  19360.    QuickC keeps track of which files have changed in a program list. To see
  19361.    how this works, select Build Program from the Run menu. Now load the
  19362.    KEYS.C file and change it by inserting a blank line anywhere. Save that
  19363.    file and select Build Program again. This time, QuickC recompiles the
  19364.    KEYS.C file, but it does not compile the other two .C files because they
  19365.    haven't changed.
  19366.  
  19367.    Before QuickC runs a command line to create the target file from the
  19368.    infiles (based on a dependency in its program list), it first checks the
  19369.    modification dates for the target file and for each of the infiles. If
  19370.    this target was created after the infiles, QuickC doesn't need to
  19371.    recompile because the infiles have not changed. Specifically, in the
  19372.    dependency
  19373.  
  19374.      texed.obj : texed.c
  19375.  
  19376.    if TEXED.OBJ is newer than TEXED.C (its modification date and time is more
  19377.    recent), then QuickC does not recompile because TEXED.C has not changed
  19378.    since the last time it was compiled. But if TEXED.C is newer or if
  19379.    TEXED.OBJ doesn't yet exist, QuickC creates a new TEXED.OBJ by applying
  19380.    the .c.obj production rule and thus running the MS-DOS command line:
  19381.  
  19382.      qcl -c -W1 -Ze -AM texed.c
  19383.  
  19384.    This ability to know which files need to be recompiled makes QuickC a
  19385.    powerful tool for developing large and complex programs that are composed
  19386.    of many individual .C files.
  19387.  
  19388.  Header Files
  19389.  
  19390.    Programs formed from separate .C files often share identical declarations.
  19391.    For example, examine the two files in Listings 12-8a and 12-8b on the
  19392.    following page. These parts of a larger text editor program both use
  19393.    structures of the same pattern, and both use the #define directive to
  19394.    define the values OK and ERROR. (These listings are not intended to be
  19395.    compiled and run independently.) If you need to change the structures (by
  19396.    adding a member, for example), or to change the definition of ERROR (from
  19397.    1 to -1, for example), you must make changes in both files (and possibly
  19398.    many other files if the text editor program uses those values throughout).
  19399.  
  19400.    ──────────────────────────────────────────────────────────────────────────
  19401.    #define OK 1
  19402.    #define ERROR 0
  19403.    menu()
  19404.    {
  19405.        struct key_struct {
  19406.             char key;
  19407.             unsigned char move;
  19408.        } *kp, *Read_kbd();
  19409.        int cur_key, cur_move;
  19410.  
  19411.        kp = Read_kbd();
  19412.        cur_key = kp->key;
  19413.        cur_move = kp->move;
  19414.        if (cur_key == ERROR)
  19415.            return (cur_move);
  19416.        return (cur_key);
  19417.    }
  19418.    ──────────────────────────────────────────────────────────────────────────
  19419.  
  19420.    Listing 12-8a.  The TEXED.C file.
  19421.  
  19422.    ──────────────────────────────────────────────────────────────────────────
  19423.    #define OK 1
  19424.    #define ERROR 0
  19425.    struct key_struct {
  19426.        char key;
  19427.        unsigned char move;
  19428.    };
  19429.  
  19430.    struct key_struct *Read_key()
  19431.    {
  19432.        struct key_struct k;
  19433.  
  19434.        k.key = getch();
  19435.        if (k.key == ERROR)
  19436.            k.move = getch();
  19437.        return (&k);
  19438.    }
  19439.    ──────────────────────────────────────────────────────────────────────────
  19440.  
  19441.    Listing 12-8b.  The KEYS.C file.
  19442.  
  19443.    Therefore, your program is easier to maintain if you gather such common
  19444.    definitions into a single, separate file called a "header file," or a .h
  19445.    file. Listing 12-9 shows one such header file for our text editor
  19446.    program. Now you can easily make changes that affect all files. Simply
  19447.    modify TEXED.C and KEYS.C to use the #include preprocessor directive, as
  19448.    shown in Listings 12-10a and 12-10b. Because we use full quotation marks
  19449.    with that directive (rather than angle brackets as with #include
  19450.    <stdio.h>), the compiler looks for the header file in our current working
  19451.    directory.
  19452.  
  19453.    ──────────────────────────────────────────────────────────────────────────
  19454.    #define OK 1
  19455.    #define ERROR 0
  19456.  
  19457.    struct key_struct {
  19458.        char key;
  19459.        unsigned char move;
  19460.    };
  19461.    ──────────────────────────────────────────────────────────────────────────
  19462.  
  19463.    Listing 12-9.  The texed.h header file.
  19464.  
  19465.    ──────────────────────────────────────────────────────────────────────────
  19466.    #include "texed.h"
  19467.    menu()
  19468.    {
  19469.        struct key_struct *kp, *Read_kbd();
  19470.        int cur_key, cur_move;
  19471.  
  19472.        kp = Read_kbd();
  19473.        cur_key = kp->key;
  19474.        cur_move = kp->move;
  19475.        if (cur_key == ERROR)
  19476.            return (cur_move);
  19477.        return (cur_key);
  19478.    }
  19479.    ──────────────────────────────────────────────────────────────────────────
  19480.  
  19481.    Listing 12-10a.  The TEXED.C file (modified).
  19482.  
  19483.    ──────────────────────────────────────────────────────────────────────────
  19484.    #include "texed.h"
  19485.    struct key_struct *Read_key()
  19486.    {
  19487.        struct key_struct k;
  19488.  
  19489.        k.key = getch();
  19490.        if (k.key == ERROR)
  19491.            k.move = getch();
  19492.        return (&k);
  19493.    }
  19494.    ──────────────────────────────────────────────────────────────────────────
  19495.  
  19496.    Listing 12-10b.  The KEYS.C File (modified).
  19497.  
  19498.    Variables in Header Files
  19499.  
  19500.    You can also place declarations in header files that make variables global
  19501.    to all files. However, you cannot initialize variables in header files
  19502.    that are shared by more than one .C file. That is, in the header file
  19503.    texed.h,
  19504.  
  19505.      char Last_key;─────────────────────────────────────────────────────Legal
  19506.      int  Upper_flag = 1;─────────────────────────────────────────────Illegal
  19507.  
  19508.    the declaration for Last_key is always legal, but the declaration for
  19509.    Upper_flag is illegal because this .h file is specified by #include in
  19510.    several .C files.
  19511.  
  19512.    You can declare and initialize a global variable only once in a program.
  19513.    If you want to declare and initialize a global variable in one file and
  19514.    access that variable from another file, you must make this an explicit
  19515.    operation by placing the extern keyword in the second file, as follows:
  19516.  
  19517.      /* First file */  /* Second file */  /* Third file */
  19518.      ...               ...                ...
  19519.      int Key = 1;      extern int Key;    extern int Key;
  19520.                └────────────────────────────────────── Initialized once among
  19521.                                                         several files
  19522.  
  19523.    The extern keyword tells QuickC that the integer Key is located in another
  19524.    file.
  19525.  
  19526.    If a global variable is not initialized as part of its declaration, you
  19527.    can declare it in all files without the extern keyword, as follows:
  19528.  
  19529.      /* First file */  /* Second file */  /* Third file */
  19530.      ...               ...                 ...
  19531.      int Key = 1;      extern int Key;    extern int Key;
  19532.  
  19533.    The extern keyword tells QuickC that the integer Key is located in another
  19534.    file.
  19535.  
  19536.    If a global variable is not initialized as part of its declaration, you
  19537.    can declare it in all files without the extern keyword, as follows:
  19538.  
  19539.      /* First file */  /* Second file */  /* Third file */
  19540.      ...               ...                ...
  19541.      int Key;          int Key;           int Key;
  19542.  
  19543.    This is the same as declaring it once in a header file and then specifying
  19544.    that header with #include, as follows:
  19545.  
  19546.      /* Header file "head.h" */
  19547.      ...
  19548.      int Key;
  19549.  
  19550.      /* First file */  /* Second file */  /* Third file */
  19551.      ...               ...                ...
  19552.      #include "head.h" #include "head.h"  #include "head.h"
  19553.  
  19554.    ──────────────────────────────────────────────────────────────────────────
  19555.    Dependencies in Header Files
  19556.    Because a change in a header file results in a change in a .C file, you
  19557.    might wonder if you can place header files into your QuickC program list
  19558.    as a dependency, as follows:
  19559.  
  19560.      texed.obj :  texed.c texed.h
  19561.  
  19562.      keys.obj : keys.c texed.h
  19563.  
  19564.    As this dependency is written, it tells QuickC (in our program list) to
  19565.    recompile TEXED.OBJ if either TEXED.C or texed.h changes and to recompile
  19566.    KEYS.OBJ if either KEYS.C or texed.h changes.
  19567.  
  19568.    QuickC does allow you to place header file dependencies into your program
  19569.    lists: It recognizes and maintains them, but it does not treat .h files as
  19570.    real dependencies. That means, for example, that TEXED.OBJ is not
  19571.    recompiled if only texed.h changes. This is intentional and not a bug.
  19572.    ──────────────────────────────────────────────────────────────────────────
  19573.  
  19574.  Libraries
  19575.  
  19576.    In addition to listing .C files in a QuickC program list file, you can
  19577.    also list library (.LIB) files. Libraries are files that contain
  19578.    precompiled .OBJ files that you can use as part of a program.
  19579.  
  19580.    During the course of your programming, you will develop many general
  19581.    subroutines that can be used in many programs. By placing those
  19582.    subroutines into a special library, you can access them through a QuickC
  19583.    program list without having to recompile them. For example, consider the
  19584.    following three subroutines: leftstr.c (Listing 12-11), midstr.c (Listing
  19585.    12-12), and rightstr.c (Listing 12-13). (These subroutines, shown on
  19586.    pages 392-93, are C analogs to the BASIC functions LEFT$, MID$, and
  19587.    RIGHT$.)
  19588.  
  19589.    To create a library for these three subroutines, enter them using the
  19590.    QuickC editor, and then save each as an individual .C file. Now exit
  19591.    QuickC and compile each with qcl and the following MS-DOS commands:
  19592.  
  19593.      qcl /c /AM leftstr.c
  19594.      qcl /c /AM midstr.c
  19595.      qcl /c /AM rightstr.c
  19596.  
  19597.    qcl is the command-line version of QuickC. The /c tells QuickC to create a
  19598.    .OBJ file from the .C file, and /AM tells QuickC to use the medium-memory
  19599.    model.
  19600.  
  19601.    After you generate the three .OBJ files, you create a library for them by
  19602.    running the LIB program and answering its questions, as follows:
  19603.  
  19604.      Library name:basic.lib
  19605.      Library does not exist. Create?y
  19606.      Operations:+leftstr.obj&
  19607.      Operations:+midstr.obj&
  19608.      Operations:+rightstr.obj
  19609.      List file:
  19610.  
  19611.    The first and second lines tell LIB to create a library named BASIC.LIB.
  19612.    In the three Operations: lines, the + tells LIB that we are adding a .OBJ
  19613.    file to the library. The & following two of the lines is a signal that
  19614.    more files will be added. At the List file prompt we simply press Enter
  19615.    because our library is small, and we don't need a list of its contents.
  19616.    After a short wait, QuickC produces a library file named BASIC.LIB that we
  19617.    can place into any program list. To return to the QuickC menu, enter exit
  19618.    at the MS-DOS prompt.
  19619.  
  19620.    Now we'll create a program to test our library and demonstrate how to use
  19621.    a library from a program list. Enter the TEST.C program (Listing 12-14 on
  19622.    p. 393) and save it on disk. Next, choose Set Program List from the File
  19623.    menu and enter TEST.MAK as the name of the program list.
  19624.  
  19625.    After you press Enter and answer Yes to Test.mak doesn't exist. Create?,
  19626.    the Edit Program List dialog box appears. Select test.c as the first item
  19627.    in the list. Notice that the name of our library is not displayed. That's
  19628.    okay; simply type basic.lib. Finally, save this program list.
  19629.  
  19630.    ──────────────────────────────────────────────────────────────────────────
  19631.    /* leftstr.c -- a C version of BASIC's LEFT$ */
  19632.  
  19633.    #include <stdio.h>
  19634.  
  19635.    char *Leftstr(char *str, int cnt)
  19636.    {
  19637.        static char *cp = NULL;
  19638.        char *malloc();
  19639.  
  19640.        if (cnt > strlen(str))
  19641.            cnt = strlen(str);
  19642.        if (cp != NULL)
  19643.            free(cp);
  19644.        if ((cp = malloc(cnt + 1)) == NULL)
  19645.            return (NULL);
  19646.        strncpy(cp, str, cnt);
  19647.        return (cp);
  19648.    }
  19649.    ──────────────────────────────────────────────────────────────────────────
  19650.  
  19651.    Listing 12-11.  The leftstr.c subroutine.
  19652.  
  19653.    ──────────────────────────────────────────────────────────────────────────
  19654.    /* midstr.c -- a C version of BASIC's MID$  */
  19655.  
  19656.    #include <stdio.h>
  19657.  
  19658.    char *Midstr(char *str, int where, int cnt)
  19659.    {
  19660.        static char *cp = NULL;
  19661.        char *malloc();
  19662.  
  19663.        if (cnt > strlen(str + where))
  19664.            cnt = strlen(str + where);
  19665.        if (cp != NULL)
  19666.            free(cp);
  19667.        if ((cp = malloc(cnt + 1)) == NULL)
  19668.            return (NULL);
  19669.        strncpy(cp, str+where, cnt);
  19670.        return (cp);
  19671.    }
  19672.    ──────────────────────────────────────────────────────────────────────────
  19673.  
  19674.    Listing 12-12.  The midstr.c subroutine.
  19675.  
  19676.    ──────────────────────────────────────────────────────────────────────────
  19677.    /* rightstr.c -- a C version of BASIC's RIGHT$ */
  19678.  
  19679.    #include <stdio.h>
  19680.  
  19681.    char *Rightstr(char *str, int cnt)
  19682.    {
  19683.        static char *cp = NULL;
  19684.        char *malloc();
  19685.  
  19686.        if (cnt > strlen(str))
  19687.            cnt = strlen(str);
  19688.        if (cp != NULL)
  19689.            free(cp);
  19690.        if ((cp = malloc(cnt + 1)) == NULL)
  19691.            return (NULL);
  19692.        strcpy(cp, str + strlen(str) - cnt);
  19693.        return (cp);
  19694.    }
  19695.    ──────────────────────────────────────────────────────────────────────────
  19696.  
  19697.    Listing 12-13.  The rightstr.c subroutine.
  19698.  
  19699.    ──────────────────────────────────────────────────────────────────────────
  19700.    /* test.c -- tests the routines in basic.lib */
  19701.    /* Program list: test.c and basic.lib        */
  19702.  
  19703.    #include <stdio.h>
  19704.  
  19705.    main()
  19706.    {
  19707.        static char string[] = "This is a test.";
  19708.        char *cp, *Leftstr(), *Midstr(), *Rightstr();
  19709.  
  19710.        printf("Testing: \"%s\"\n", string);
  19711.  
  19712.        if ((cp = Leftstr(string, 4)) == NULL)
  19713.            {
  19714.            printf("Error in Leftstr()\n");
  19715.            exit(1);
  19716.            }
  19717.        printf("Leftstr() returned: \"%s\"\n", cp);
  19718.  
  19719.        if ((cp = Midstr(string, 4, 5)) == NULL)
  19720.            {
  19721.            printf("Error in Midstr()\n");
  19722.            exit(1);
  19723.            }
  19724.        printf("Midstr() returned: \"%s\"\n", cp);
  19725.  
  19726.        if ((cp = Rightstr(string, 5)) == NULL)
  19727.            {
  19728.            printf("Error in Rightstr()\n");
  19729.            exit(1);
  19730.            }
  19731.        printf("Rightstr() returned: \"%s\"\n", cp);
  19732.    }
  19733.    ──────────────────────────────────────────────────────────────────────────
  19734.  
  19735.    Listing 12-14.  The TEST.C program.
  19736.  
  19737.    At the QuickC editor, choose Compile from the Run menu. Because we are
  19738.    compiling from a program list, use Build Program to compile TEST.C and
  19739.    then combine it with the subroutines in BASIC.LIB.
  19740.  
  19741.    One additional advantage offered by .LIB files is that you can place them
  19742.    in your environmental LIB directory. From there, QuickC can find them no
  19743.    matter where you are in the directory hierarchy. The result of all this is
  19744.    that you need only one copy of common subroutines in a single library, and
  19745.    you can access those subroutines through a program list from any
  19746.    directory.
  19747.  
  19748.  Quick Libraries
  19749.  
  19750.    QuickC offers another kind of library, called a Quick Library. This
  19751.    alternative library can be loaded into memory when you first run QuickC.
  19752.    The advantage it offers is that you don't need to use a program list to
  19753.    access the subroutines in it.
  19754.  
  19755.    Let's build a Quick Library using the same subroutines that we used to
  19756.    build BASIC.LIB: leftstr.c (Listing 12-11), midstr.c (Listing 12-12),
  19757.    and rightstr.c (Listing 12-13). Begin by running qcl to create the .OBJ
  19758.    files:
  19759.  
  19760.      qcl /c /AM leftstr.c
  19761.      qcl /c /AM midstr.c
  19762.      qcl /c /AM rightstr.c
  19763.  
  19764.    Now run LINK to create the Quick Library:
  19765.  
  19766.      link
  19767.      Object Modules [.OBJ]:c:\lib\quicklib.obj +
  19768.      Object Modules [.OBJ]:leftstr.obj +
  19769.      Object Modules [.OBJ]:midstr.obj +
  19770.      Object Modules [.OBJ]:rightstr.obj /Q
  19771.      Run File [C:QUICKLIB.QLB]:basic.qlb /NOI
  19772.      List File [NUL.MAP]:
  19773.      Libraries [.LIB]:
  19774.  
  19775.    In this example, c:\lib\quicklib.obj is the full pathname of a special
  19776.    object file that you must use as the first listing in your Quick Library.
  19777.    (We've stored the file in the C:\LIB directory, but you can use any
  19778.    directory. We suggest that you specify your environmental LIB directory.)
  19779.    The + characters tell LINK that we will list more object files. The /Q
  19780.    after the last .OBJ tells LINK that this is a Quick Library. Then we
  19781.    specify basic.qlb as the name of our Quick Library and follow that name
  19782.    with /NOI, which tells LINK not to ignore case. Finally, we press Enter to
  19783.    skip the final prompts, List File and Libraries.
  19784.  
  19785.    Now you can have QuickC load the BASIC.QLB Quick Library every time you
  19786.    run QuickC. To do this, use the QuickC /l command-line argument, as
  19787.    follows:
  19788.  
  19789.      qc /lbasic.qlb test.c
  19790.  
  19791.    This tells QuickC first to load the BASIC.QLB Quick Library and then to
  19792.    load TEST.C in the editor. (Before you do this on your system, erase the
  19793.    TEST.MAK program list; otherwise, QuickC will try to use the .OBJ files
  19794.    from the disk rather than from your new Quick Library.)
  19795.  
  19796.    Now, when you compile TEST.C, QuickC always finds the functions Leftstr(),
  19797.    Midstr(), and Rightstr() in memory. Notice how much faster TEST.C compiles
  19798.    when you use this approach.
  19799.  
  19800.  
  19801.  
  19802.  ────────────────────────────────────────────────────────────────────────────
  19803.  PART 4  C AND THE HARDWARE
  19804.  ────────────────────────────────────────────────────────────────────────────
  19805.  
  19806.  
  19807.  
  19808.  ────────────────────────────────────────────────────────────────────────────
  19809.  Chapter 13  Keyboard and Cursor Control
  19810.  
  19811.    Almost every PC program needs to get information from the keyboard and to
  19812.    display information on a monochrome or color screen. So far, our programs
  19813.    have used the standard C Library functions such as getchar(), scanf(),
  19814.    putchar(), and printf(), and occasionally we've used command-line
  19815.    arguments. Using these approaches produces portable code. However, it also
  19816.    produces a bland interface that fails to take advantage of many PC
  19817.    capabilities. If you want your programs to do more than display mere text
  19818.    on the screen, study this and the next two chapters, which explore PC I/O.
  19819.    You will learn how to use function keys and cursor control keys, how to
  19820.    control the location and appearance of text on the screen, how to use
  19821.    color in text and in graphics, and how to construct graphic figures.
  19822.  
  19823.    In this chapter, we examine the keyboard and cursor control. We look at
  19824.    QuickC's numerous I/O functions and provide a more detailed discussion of
  19825.    the generic getchar() and the PC-specific getche() and getch(). We
  19826.    describe scan codes, show how to use ANSI.SYS to redefine keys and to
  19827.    provide cursor control, and discuss BIOS routines. Finally, we use the
  19828.    int86() function to create a library of BIOS-based screen-control and
  19829.    cursor-control functions.
  19830.  
  19831.  
  19832.  Keyboard Input Functions
  19833.  
  19834.    You use the standard C I/O functions to read and to display a variety of
  19835.    input: characters, strings, integers, and floating-point numbers. But the
  19836.    standard input functions don't detect non-ASCII keys, such as the function
  19837.    keys. And they don't provide many of the input control features typically
  19838.    required by programs such as word processors, spreadsheets, and games. To
  19839.    get that control, we need to process input at a "lower" level than that of
  19840.    standard I/O functions.
  19841.  
  19842.    Three QuickC functions read keyboard input character by character:
  19843.    getchar(), getche(), and getch(). Each reads one character at a time and
  19844.    reports its value to the calling program. (Actually, getchar() is not a
  19845.    true function; instead, it is defined as a macro in stdio.h.)
  19846.  
  19847.  Input Examples
  19848.  
  19849.    The programs on the opposite page illustrate how the three input functions
  19850.    respond to the same input──in this case, the input is the word hat
  19851.    followed by Enter.
  19852.  
  19853.    The GETCHAR.C program (Listing 13-1) produces the following output:
  19854.  
  19855.      Please enter a word.
  19856.      hat<Enter>
  19857.      1.. 2.. 3..───────────────────────Counting delayed until you press Enter
  19858.      3 characters altogether
  19859.  
  19860.    Counting doesn't start until you type the word and press Enter.
  19861.  
  19862.    Next, look at GETCHE.C (Listing 13-2), which generates the following
  19863.    output:
  19864.  
  19865.      Please enter a word.
  19866.      h1.. a2.. t3.. <Enter>───────────────────────────────────Immediate count
  19867.      3 characters altogether
  19868.  
  19869.    This time each letter is counted as it is typed.
  19870.  
  19871.    Finally, examine GETCH.C (Listing 13-3), which produces the following
  19872.    output:
  19873.  
  19874.      Please enter a word.
  19875.      1.. 2.. 3..──────────────────Input not displayed 3 characters altogether
  19876.  
  19877.    This time the input is invisible; only the output is displayed.
  19878.  
  19879.    The functions behave differently, and you use them for different purposes.
  19880.    The getchar() function buffers and echoes input; getche() does not buffer
  19881.    input but echoes it; getch() neither buffers nor echoes input. Buffered
  19882.    input goes into a temporary storage area before being transferred to the
  19883.    calling program. (Pressing Enter "empties" the buffer.) Echoed input is
  19884.    displayed on the screen.
  19885.  
  19886.    The getchar() function handles arrow keys or function keys inconsistently
  19887.    from one system to another. Try using GETCHAR.C with these keys as input
  19888.    and see how your system responds. The getche() and getch() functions do
  19889.    read these keys in a consistent manner, however. Try GETCHE.C, for
  19890.    example, with an arrow key or function key as input. Each of these keys,
  19891.    as you'll see, is counted as two keystrokes, and characters other than
  19892.    those you typed are echoed on the screen. This is perfectly proper and
  19893.    reasonable behavior, as you'll see when we discuss scan codes.
  19894.  
  19895.    ──────────────────────────────────────────────────────────────────────────
  19896.    /*      getchar.c -- using getchar()         */
  19897.  
  19898.    #include <stdio.h>
  19899.    main()
  19900.    {
  19901.        int count = 1;
  19902.  
  19903.        printf("Please enter a word.\n");
  19904.        while (getchar() != '\n')       /* here it is */
  19905.            printf("%d.. ", count++);
  19906.        printf("\n%d characters altogether\n", count - 1);
  19907.    }
  19908.    ──────────────────────────────────────────────────────────────────────────
  19909.  
  19910.    Listing 13-1.  The GETCHAR.C program.
  19911.  
  19912.    ──────────────────────────────────────────────────────────────────────────
  19913.    /*     getche.c -- using getche()             */
  19914.    #include <conio.h>     /* note different file included */
  19915.    main()
  19916.    {
  19917.        int count = 1;
  19918.  
  19919.        printf("Please enter a word.\n");
  19920.        while (getche() != '\r')    /* changed comparison */
  19921.            printf("%d.. ", count++);
  19922.        printf("\n%d characters altogether\n", count - 1);
  19923.    }
  19924.    ──────────────────────────────────────────────────────────────────────────
  19925.  
  19926.    Listing 13-2.  The GETCHE.C program.
  19927.  
  19928.    ──────────────────────────────────────────────────────────────────────────
  19929.    /*     getch.c -- using getch()             */
  19930.    #include <conio.h>
  19931.    main()
  19932.    {
  19933.        int count = 1;
  19934.  
  19935.        printf("Please enter a word.\n");
  19936.        while (getch() != '\r')
  19937.            printf("%d.. ", count++);
  19938.        printf("\n%d characters altogether\n", count - 1);
  19939.    }
  19940.    ──────────────────────────────────────────────────────────────────────────
  19941.  
  19942.    Listing 13-3.  The GETCH.C program.
  19943.  
  19944.  The getchar() Buffer
  19945.  
  19946.    The program using getchar() doesn't receive the generated code until this
  19947.    buffer is flushed. This occurs when you press Enter or when the buffer is
  19948.    filled. Because the getchar() buffer is 512 bytes, normal keyboard input
  19949.    does not fill it. QuickC sets up this input buffer when any input function
  19950.    from the stdio.h family is called, and all the input functions of that
  19951.    family, such as scanf() and gets(), share it. Thus, when your program uses
  19952.    both scanf() and getchar(), they share the same input buffer.
  19953.  
  19954.  Differences in Usage
  19955.  
  19956.    First, getchar() requires the stdio.h include file, while getch() and
  19957.    getche() use conio.h, the include file for console I/O functions. Second,
  19958.    getch() and getche use \r instead of \n to represent the action of Enter,
  19959.    and they do not interpret Ctrl-Z as an end-of-file indicator.
  19960.  
  19961.    The reason for these last two differences is that getchar(), by default,
  19962.    reads input in the text mode, and getch() and getche() read input in the
  19963.    binary mode. In the text mode, as you may recall, the carriage
  19964.    return/linefeed combination is converted to a linefeed on input, and the
  19965.    linefeed is converted to a carriage return/linefeed on output. The binary
  19966.    mode makes no conversions. As a result, getchar() uses \n to detect the
  19967.    Enter key, but getch() and getche() must use \r.
  19968.  
  19969.    The second difference is that getchar(), when used in the text mode,
  19970.    recognizes the Ctrl-Z character as marking the end of a file. This lets
  19971.    you simulate the end-of-file condition from the keyboard by entering
  19972.    Ctrl-Z. The binary mode used by getche() and getch() does not recognize
  19973.    Ctrl-Z (or any other character) to mark the end of a file. As a result,
  19974.    constructions such as
  19975.  
  19976.      while((ch = getche()) != EOF)     /* NO */
  19977.  
  19978.    do not work for keyboard input. When using getch() or getche() in such a
  19979.    loop, you must specify a keyboard character to indicate the end of input.
  19980.    We've used \r, and in many later examples we'll use the Esc key.
  19981.  
  19982.    Although the getchar() function uses text mode by default, you can call
  19983.    QuickC's setmode() function to place getchar() in binary mode. (See
  19984.    setmode() in the Microsoft QuickC Run-Time Library Reference for details.)
  19985.    However, you cannot switch getche() and getch() to text mode.
  19986.  
  19987.    ──────────────────────────────────────────────────────────────────────────
  19988.    Reminder
  19989.    Don't mix buffered functions such as getchar() and gets() with unbuffered
  19990.    functions such as getche() and getch(). The buffered functions transmit
  19991.    characters from the input buffer when it is flushed; the unbuffered
  19992.    functions read keys as they are pressed. Thus, a program mixing buffered
  19993.    and unbuffered input functions might not process the characters in the
  19994.    order they were typed.
  19995.    ──────────────────────────────────────────────────────────────────────────
  19996.  
  19997.    Table 13-1 summarizes the different behavior of the character input
  19998.    functions.
  19999.  
  20000.    Table 13-1 Character Input Functions
  20001.                                         getchar()   getche()     getch()
  20002.    ──────────────────────────────────────────────────────────────────────────
  20003.    Buffered                             o
  20004.    Echoes                               o           o
  20005.    Uses \n                              o
  20006.    Uses \r                                          o            o
  20007.    Uses stdio.h                         o
  20008.    Uses conio.h                                     o            o
  20009.    Text mode (default)                  o
  20010.    Binary mode                                      o            o
  20011.    Backspace editing                    o
  20012.    Reads ASCII keys                     o           o            o
  20013.    Reads non-ASCII keys                             o            o
  20014.    ──────────────────────────────────────────────────────────────────────────
  20015.  
  20016.  Typical Uses for Character Input Functions
  20017.  
  20018.    The primary advantage of using the buffered getchar() is that it lets
  20019.    users edit input with the Backspace key before they send it to the
  20020.    program. The nonbuffered form, on the other hand, requires users to type
  20021.    less because they needn't press Enter. For example, suppose your program
  20022.    uses the following prompt:
  20023.  
  20024.      Continue? <y/n>
  20025.  
  20026.    With getchar(), the user must type y and press Enter, while getche()
  20027.    requires only a y. Likewise, the getche() function is useful in programs
  20028.    that use a typed character to select a menu item. Consider the following
  20029.    fragment:
  20030.  
  20031.      while ((ch = getchar()) != 'q') /* oops example */
  20032.          switch (ch)
  20033.          {
  20034.              case 'a': ...
  20035.              case 'b': ...
  20036.              case 'c': ...
  20037.              default:  printf("Not a valid choice\n");
  20038.          }
  20039.  
  20040.    To choose case a, the user types a and presses Enter. The loop processes
  20041.    the a, recycles and processes the \n generated by the Enter key, and
  20042.    prints the default message. Replacing getchar() with getche() eliminates
  20043.    the need to press the Enter key and hence the need to add programming to
  20044.    process the extraneous \n.
  20045.  
  20046.    The non-echoed, nonbuffered getch() is useful, of course, when you don't
  20047.    want to display input on the screen. For example, you might use the k key
  20048.    to move an image on the screen. Also, a program that requires a user to
  20049.    type a secret password shouldn't display it on the screen.
  20050.  
  20051.    Let's use getch() to construct a simple password program. In a real
  20052.    application, we would ensure password security by also using encryption
  20053.    and periodic updating. In the PASSWORD.C program (Listing 13-4 on the
  20054.    following page), we'll build the password into the program and concentrate
  20055.    on processing the user's input.
  20056.  
  20057.    ──────────────────────────────────────────────────────────────────────────
  20058.    /*  password.c -- requires a password to complete the   */
  20059.    /*                program; illustrates a use of getch() */
  20060.  
  20061.    #include <stdio.h>
  20062.    #include <conio.h>
  20063.    #include <string.h>
  20064.    #define GUESS_LIMIT 4
  20065.    #define WORD_LIMIT 10  /* maximum length of password */
  20066.    #define TRUE 1
  20067.    #define FALSE 0
  20068.    char *Password = "I'mOk";
  20069.    main()
  20070.    {
  20071.         int g_count = 0;           /* guesses taken    */
  20072.         int w_count;               /* letters accepted */
  20073.         int in_count;              /* letters entered  */
  20074.         char entry[WORD_LIMIT + 1];
  20075.         char ch;
  20076.         int correct, go_on;
  20077.  
  20078.         do
  20079.              {
  20080.              puts("Enter the secret password.");
  20081.              in_count = w_count = 0;
  20082.              /* the following loop accepts no more chars */
  20083.              /* than entry[] will hold, but keeps track  */
  20084.              /* of total number typed                    */
  20085.              while ((ch = getch()) != '\r')
  20086.                   {
  20087.                   if (w_count < WORD_LIMIT)
  20088.                        entry[w_count++] = ch;
  20089.                   in_count++;
  20090.                   }
  20091.              entry[w_count] = '\0';
  20092.              if (in_count != w_count)
  20093.                   correct = FALSE;    /* too many chars */
  20094.              else
  20095.                   correct = (strcmp(entry, Password) == 0);
  20096.              g_count++;
  20097.              go_on = !correct && g_count < GUESS_LIMIT;
  20098.              if (go_on)
  20099.                   puts("\nNo good; try again.");
  20100.              } while (go_on);
  20101.         if (!correct)
  20102.              {
  20103.              puts("Sorry, no more guesses.  Bye.");
  20104.              return(1);
  20105.              }
  20106.         puts("Welcome to Swiss bank account 2929100.");
  20107.         puts("Your current balance is $10,232,862.61.");
  20108.    }
  20109.    ──────────────────────────────────────────────────────────────────────────
  20110.  
  20111.    Listing 13-4.  The PASSWORD.C program.
  20112.  
  20113.    Note the following loop:
  20114.  
  20115.      while ((ch = getch()) != '\r')
  20116.           {
  20117.                if (w_count < WORD_LIMIT)
  20118.                     entry[w_count++] = ch;
  20119.                in_count++;
  20120.           }
  20121.  
  20122.    It uses an if statement to prevent overflowing the array, yet it continues
  20123.    to read additional characters if the limit is exceeded. We could have made
  20124.    this loop stop at the character limit, but that would tell the illicit
  20125.    user the number of characters in the actual password.
  20126.  
  20127.    The structure of the do while loop reflects the two conditions that
  20128.    terminate the loop: a correct password or too many attempts. If the loop
  20129.    ends and correct is still false, the program knows that the reason for
  20130.    termination was too many attempts.
  20131.  
  20132.    ──────────────────────────────────────────────────────────────────────────
  20133.    Character and String Input in BASIC and C
  20134.    If you are used to BASIC, you know that you can read a character from the
  20135.    keyboard (with no echo) using the INKEY$ function. This function is
  20136.    similar to C's getch(). C conveniently provides the alternative getche()
  20137.    function for character input with echo, while in BASIC you would need a
  20138.    separate PRINT statement to echo the input character. Note that neither
  20139.    the BASIC function nor the C functions mentioned recognize Ctrl-Z as a
  20140.    signal for the end of file.
  20141.  
  20142.    Both BASIC and C provide generalized input functions that can handle a
  20143.    series of numeric or string variables. In BASIC, the INPUT statement
  20144.    allows you to supply a prompt string and accept input into one or more
  20145.    variables. For example:
  20146.  
  20147.      INPUT "ENTER NAME AND AGE: ",NAME$,AGE
  20148.  
  20149.    The scanf() function in C is similar in that it allows you to receive
  20150.    input for a series of variables of different types. The scanf() function,
  20151.    however, allows you a much greater degree of control over the format of
  20152.    each input value, the interpretation of white space, and the characters
  20153.    used to separate input values. Unlike the INPUT function, scanf() makes no
  20154.    provision for a prompt string, so it is normally preceded by a separate
  20155.    printf() statement with the desired string.
  20156.  
  20157.    In a typical trade-off for these two languages, BASIC's INPUT statement
  20158.    provides very rudimentary error checking and editing of the input line.
  20159.    While scanf() will reject any input that does not match the
  20160.    specifications, it does not terminate or restart when bad input is
  20161.    encountered. The C programmer is responsible for error checking to
  20162.    determine whether the values entered are actually reasonable and complete.
  20163.    ──────────────────────────────────────────────────────────────────────────
  20164.  
  20165.  
  20166.  Reading Non-ASCII Keys
  20167.  
  20168.    Some keys, such as the function keys, the cursor control keys, and Alt-key
  20169.    combinations, have no ASCII code. How can a QuickC program read them?
  20170.    Before answering this question, we need to discuss how the keyboard
  20171.    actually works.
  20172.  
  20173.  The Keyboard Processor and Scan Codes
  20174.  
  20175.    Information does not flow directly from the keyboard to a C program.
  20176.    Instead, pressing (or closing) a given key generates a "closure" code that
  20177.    indicates the physical location of the key. A microprocessor within the
  20178.    keyboard reads this code and then generates a new code, called a "system
  20179.    code." It also reports if the user is holding down the Shift, Ctrl, or Alt
  20180.    key. Finally, it generates a third code (two bytes called the "extended
  20181.    scan code") for the keystroke (or keystroke combination) and places it in
  20182.    a storage area called the "keyboard buffer." If the key is still "closed"
  20183.    after a predetermined period of time elapses, another keystroke is placed
  20184.    in the buffer. Thus, you can generate a string of characters by holding
  20185.    down a key. Releasing the key generates an "opening" code that tells the
  20186.    keyboard microprocessor that you are finished with that key. By default,
  20187.    the keyboard buffer holds a maximum of 16 extended scan codes.
  20188.  
  20189.    The purpose of the keyboard buffer is to hold characters that are typed
  20190.    faster than an application can process them. It is distinct from the
  20191.    buffer created for the stdio.h input functions.
  20192.  
  20193.    The getch() and getche() functions do not read the keyboard directly.
  20194.    Instead, they read the extended scan codes in the keyboard buffer. Because
  20195.    this code is more extensive than the standard ASCII code, programs can use
  20196.    it to identify function keys, cursor keys, and other keys lacking an ASCII
  20197.    code. (The only difference between getch() and getche() is that getche()
  20198.    echoes input; therefore, our next discussions about getch() actually apply
  20199.    to both functions.)
  20200.  
  20201.  Using Scan Codes
  20202.  
  20203.    Each extended scan code is two bytes. The first byte, which we call the
  20204.    "ASCII byte," contains the ASCII code, if any, for the keystroke. The
  20205.    second byte, which we call the "scan byte," contains a scan code for the
  20206.    key. This code is based on the physical position of the key on the
  20207.    keyboard, and, in some cases, on whether the Shift, Ctrl, or Alt key is
  20208.    pressed.
  20209.  
  20210.    The contents of an extended scan code reveal whether or not it represents
  20211.    an ASCII character. If it does, the ASCII byte is nonzero. If it does not,
  20212.    the ASCII byte is set to zero, and the numeric value of the scan byte
  20213.    encodes the keystroke or keystroke combination. For example, in Figure
  20214.    13-1, the uppercase Q character is represented by an ASCII byte of 81
  20215.    because that is its ASCII code. The scan code of 16 means the Q key is the
  20216.    sixteenth key in the keyboard numbering scheme. The F1 key has no ASCII
  20217.    representation, so the ASCII byte is 0. However, because it is the 59th
  20218.    key on the keyboard, the scan byte is 59.
  20219.  
  20220.            ┌────────┬────────┐               ┌────────┬────────┐
  20221.    Press Q │   81   │   16   │      Press F1 │   00   │   59   │
  20222.            └────────┴────────┘               └────────┴────────┘
  20223.              ASCII     Scan                  └────────┬────────┘
  20224.              byte      byte                   Extended scancode
  20225.  
  20226.    Figure 13-1. Scan codes.
  20227.  
  20228.    How does getch() use these extended codes? First, it looks at the ASCII
  20229.    byte. If the byte is nonzero, getch() knows it has found an ASCII
  20230.    character. It returns that value and then skips the scan byte and moves to
  20231.    the next ASCII byte. For example, it returns 0x41 for Shift-A, 0x61 for a,
  20232.    and 0x01 for Ctrl-A.
  20233.  
  20234.    When the ASCII byte is 0, getch() lets the program know it has found a
  20235.    non-ASCII keystroke by returning a value of 0. Because getch() needs to
  20236.    know which non-ASCII character was pressed, it does not skip to the next
  20237.    ASCII byte; instead, it goes to the scan byte. Thus, the next call to
  20238.    getch() results in it reading the scan code that goes with the 0 ASCII
  20239.    byte. In other words, only one call of getch() is needed to read an ASCII
  20240.    keystroke, but two calls are needed to read a non-ASCII keystroke. Also,
  20241.    the scan codes are returned only for the non-ASCII keystrokes.
  20242.  
  20243.    Suppose, for example, that you type the Shift-Q combination and then press
  20244.    the F1 key. The codes 81 16 00 59 are placed in the keyboard buffer. The
  20245.    first call to getch() returns the 81. The next call to the function skips
  20246.    to the 00 and returns that value, and the third call returns the 59. Thus,
  20247.    a program that plans to use the F1 key must look for return values of 0.
  20248.    When it encounters one, the program should check to see if the next call
  20249.    returns 59. If so, F1 was pressed. The return value of 0 is a flag that
  20250.    says, "Special processing required here."
  20251.  
  20252.    Now, how does getchar() process non-ASCII characters? It copies ASCII
  20253.    values into the program buffer created by the standard I/O buffer. When it
  20254.    finds a 0 ASCII byte in the buffer, it skips to the next input character.
  20255.    The 0 ASCII bytes and the scan codes never make it to the I/O buffer, let
  20256.    alone to the program.
  20257.  
  20258.  A Scan Code Example
  20259.  
  20260.    The SCANCODE.C program (Listing 13-5 on the following page) demonstrates
  20261.    these functions by reading input. If the input is ASCII, the program
  20262.    prints the ASCII code. If the input is non-ASCII, the program prints the
  20263.    scan codes.
  20264.  
  20265.    Following is some sample output:
  20266.  
  20267.      Press keys and see the codes!
  20268.      Press the Esc key to quit.
  20269.  
  20270.      Q has ASCII code 81──────────────────────────────────────────────Shift-Q
  20271.      Scan code is 59───────────────────────────────────────────────────────F1
  20272.      t has ASCII code 116────────────────────────────────t has ASCII code 116
  20273.      ^T has ASCII code 20──────────────────────────────────────────────Ctrl-T
  20274.  
  20275.    ──────────────────────────────────────────────────────────────────────────
  20276.    /*   scancode.c -- displays ASCII or scan code         */
  20277.    /*   This program illustrates using getch() to detect  */
  20278.    /*   special keys such as function keys.               */
  20279.  
  20280.    #include <conio.h>
  20281.    #define ESC '\033'     /* ESC key */
  20282.    main()
  20283.    {
  20284.         int ch;
  20285.  
  20286.         printf("Press keys and see the codes!\n");
  20287.         printf("Press the Esc key to quit.\n");
  20288.  
  20289.         while ((ch = getch()) != ESC)
  20290.              {
  20291.              if (ch != 0)
  20292.                   {
  20293.                   if (ch <= 32)    /* control characters */
  20294.                        printf("^%c has ASCII code %d\n",
  20295.                                ch + 64, ch);
  20296.                   else
  20297.                        printf("%c has ASCII code %d\n", ch, ch);
  20298.                   }
  20299.              else              /* ch IS 0 */
  20300.                   {
  20301.                   ch = getch();  /* get scan code */
  20302.                   printf("Scan code is %d\n", ch);
  20303.                   }
  20304.              }
  20305.    }
  20306.    ──────────────────────────────────────────────────────────────────────────
  20307.  
  20308.    Listing 13-5.  The SCANCODE.C program.
  20309.  
  20310.    What happens if you use getch() and getche() without checking for the zero
  20311.    value? They would interpret the ASCII byte and scan byte as two ASCII
  20312.    bytes, thus interpreting 00 59 as code for Ctrl-@ and for the semicolon
  20313.    character, instead of F1.
  20314.  
  20315.  Scan Code Values
  20316.  
  20317.    In this book we will use only those codes listed below in an include file
  20318.    called keys.h. When we need to use these keys, you can include that file,
  20319.    which is shown in Listing 13-6.
  20320.  
  20321.    Not all keystrokes produce scan codes. For example, Shift, Ctrl, and Alt
  20322.    modify the scan codes produced when other keys are pressed. The SCANCODE.C
  20323.    program demonstrates this. For example, press Alt. Nothing happens until
  20324.    you simultaneously press a second key.
  20325.  
  20326.    The operating system normally intercepts the Ctrl-Break combination as the
  20327.    code for terminating a program. Thus, getch(), getche(), and getchar()
  20328.    never read Ctrl-Break. (We will discuss how to handle Ctrl-Break later in
  20329.    this chapter.)
  20330.  
  20331.    ──────────────────────────────────────────────────────────────────────────
  20332.    /*  keys.h -- scan codes for several keys */
  20333.  
  20334.    #define F1 59   /* function key F1 */
  20335.    #define F2 60   /* function key F2 */
  20336.    #define F3 61   /* and so on       */
  20337.    #define F4 62
  20338.    #define F5 63
  20339.    #define F6 64
  20340.    #define F7 65
  20341.    #define F8 66
  20342.    #define F9 67
  20343.    #define F10 68
  20344.    #define HM 71   /* Home key    */
  20345.    #define UP 72   /* Up Arrow    */
  20346.    #define PU 73   /* Page Up     */
  20347.    #define LT 75   /* Left Arrow  */
  20348.    #define RT 77   /* Right Arrow */
  20349.    #define END 79  /* End key     */
  20350.    #define DN 80   /* Down Arrow  */
  20351.    #define PD 81   /* Page Down   */
  20352.    ──────────────────────────────────────────────────────────────────────────
  20353.  
  20354.    Listing 13-6.  The keys.h include file.
  20355.  
  20356.  
  20357.  Console I/O Functions
  20358.  
  20359.    The getch() and getche() functions belong to the console I/O family of
  20360.    functions. These functions communicate with the console (the keyboard and
  20361.    screen) more directly than do the I/O functions of the stdio.h family.
  20362.    However, unlike the stdio.h family, console I/O functions are not in the
  20363.    standard C Library and are therefore not necessarily portable. They are
  20364.    important because they provide special services not offered by the
  20365.    standard I/O package. The console I/O functions declared in the conio.h
  20366.    header file are:
  20367.  
  20368.      cgets()
  20369.      cprintf()
  20370.      cputs()
  20371.      cscanf()
  20372.      getch()
  20373.      getche()
  20374.      putch()
  20375.      ungetch()
  20376.  
  20377.      kbhit()
  20378.      inp()
  20379.      outp()
  20380.  
  20381.    The first eight functions in this list closely resemble the stdio.h
  20382.    functions with corresponding names. For example, cgets() resembles gets(),
  20383.    cprintf() is similar to printf(), and so on. We've already seen the
  20384.    kbhit() function. We'll discuss the inp() and outp() functions in Chapter
  20385.    14.
  20386.  
  20387.  Character Output Functions
  20388.  
  20389.    Now that we've used the character input functions, let's look at the
  20390.    console character output functions. The putch() function works much like
  20391.    putchar(). One difference is that putchar() is buffered and putch() is
  20392.    not. This means that putch() output goes to the screen directly; putchar()
  20393.    output goes to an intermediate storage area first. The second difference
  20394.    is that putchar() works in text mode by default, while putch() works in
  20395.    binary mode. The main practical consequence of this is in how newlines are
  20396.    handled. The C newline character (\n) represents going to the beginning of
  20397.    the next line. This actually consists of two operations: a linefeed (LF)
  20398.    and a carriage return (CR). In QuickC, the newline character is
  20399.    represented by the LF character, ^J. The text mode produces the desired
  20400.    effect by mapping an LF to a CR-LF combination on the screen. In the
  20401.    binary mode, no such mapping takes place, so you must explicitly generate
  20402.    both an LF and a CR character (\n and \r).
  20403.  
  20404.    A third difference is that the text mode used by putchar() interprets a
  20405.    tab character (\t) as a tabbing instruction; the binary mode used by
  20406.    putch() interprets it as an ASCII value to be displayed. With the IBM
  20407.    character set, using putch() to generate a tab character results in a
  20408.    small circle on the screen.
  20409.  
  20410.    The REKEY.C program (Listing 13-7) demonstrates how to use the console
  20411.    I/O functions getch() and putch() to map the characters you type to a
  20412.    different set of characters on the screen.
  20413.  
  20414.    Note that we initialize the Newchars[] array to 26 letters. The
  20415.    construction Newchars[ch - 'a'] causes the array index to be zero when ch
  20416.    is a, corresponding to the array value q. Similarly, if ch is b, the index
  20417.    is 1; and the array value is the next letter in the initialization string,
  20418.    w. The initialization continues in this fashion, as shown in Figure 13-2.
  20419.  
  20420.    The toupper() and tolower() QuickC macros (defined in ctype.h) convert
  20421.    cases; thus, we don't need to use another 26-element array for uppercase
  20422.    letters. Note the way in which the program explicitly translates Enter
  20423.    (read by getch() as \r) to an output of \r and \n.
  20424.  
  20425.              ┌────────┬────────┬────────┬────────┬────────┬────────┐
  20426.              │    q   │    w   │    e   │    r   │    t   │        │
  20427.              └────────┴────────┴────────┴────────┴────────┴────────┘
  20428.               'a'-'a'   'b'-'a'  'c'-'a'  'd'-'a'  'e'-'a'
  20429.  
  20430.    Newchars      [0]      [1]      [2]      [3]      [4]
  20431.  
  20432.    Figure 13-2. The Newchars[ch - a] array.
  20433.  
  20434.    ──────────────────────────────────────────────────────────────────────────
  20435.    /* rekey.c -- transliterates typed input             */
  20436.    /*    This program illustrates getch() and putch().  */
  20437.  
  20438.    #include <stdio.h>
  20439.    #include <conio.h>
  20440.    #include <ctype.h>
  20441.    #define ESC '\033'   /* the escape key */
  20442.    char Newchars[] = "qwertyuiopasdfghjklzxcvbnm";
  20443.     /* values to be assigned to the a,b,c keys, etc. */
  20444.    main()
  20445.    {
  20446.        char ch;
  20447.  
  20448.        printf("Type characters and see them transformed;\n");
  20449.        printf("Press the Esc key to terminate.\n");
  20450.        while ((ch = getch()) != ESC)
  20451.            if (islower(ch))
  20452.                putch(Newchars[ch - 'a']);
  20453.            else if (isupper(ch))
  20454.                {
  20455.                ch = tolower(ch);
  20456.                putch(toupper(Newchars[ch - 'a']));
  20457.                }
  20458.            else if (ch == '\r')
  20459.                {
  20460.                putch('\n');
  20461.                putch('\r');
  20462.                }
  20463.            else
  20464.                putch(ch);
  20465.    }
  20466.    ──────────────────────────────────────────────────────────────────────────
  20467.  
  20468.    Listing 13-7.  The REKEY.C program.
  20469.  
  20470.  Console String I/O
  20471.  
  20472.    Often we want a program to read a string──for example, the name of a file.
  20473.    Or we want to generate a string. These activities can be done character by
  20474.    character, but it is more convenient to use functions designed to handle
  20475.    strings. The console functions cgets() and cputs() perform these tasks. In
  20476.    action, these functions are similar to gets() and puts(), but there are
  20477.    some differences.
  20478.  
  20479.    Like gets(), cgets() reads an input string into an array. However, the
  20480.    first element of the array holds the maximum allowable size of the input
  20481.    string, including a terminating null character. You must initialize this
  20482.    element correctly. The second element holds the actual number of bytes
  20483.    used, and it is set by cgets() after it reads the input. The string itself
  20484.    starts at the third element. Thus, the array must be two bytes longer than
  20485.    the maximum string size, including a null character, as shown in Figure
  20486.    13-3 on the following page.
  20487.  
  20488.                ┌─────────Available space───────────┐
  20489.       0     1  │  2     3     4     5     6     7  │
  20490.    ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
  20491.    │  6  │  4  │  L  │  A  │  R  │  A  │ \O  │     │
  20492.    └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
  20493.       │     │     └──cgets() puts string here
  20494.       │     └──cgets() puts string size here
  20495.       └──You put available space here
  20496.  
  20497.    Figure 13-3. Storage of an array read by cputs().
  20498.  
  20499.    The cgets() function reads input until the maximum length of the string
  20500.    (not counting the null character) is reached or until the user presses
  20501.    Enter. The console beeps if you try to read beyond the limit, and you
  20502.    can't enter additional characters. The function will, however, let you use
  20503.    the Backspace key to correct input. This function returns a pointer to the
  20504.    beginning of the stored string; that is, if the array name is str, cgets()
  20505.    returns a pointer to str[2].
  20506.  
  20507.    The cputs() function takes a pointer to a string as its argument and
  20508.    displays that string on the console. Unlike puts(), cputs() does not
  20509.    append a newline character; therefore, you must explicitly include the
  20510.    \r\n combination to generate a new line. The return value is the last
  20511.    character written. The function returns 0 if the string is a null string
  20512.    and -1 if there is an error.
  20513.  
  20514.    The short STRIO.C program (Listing 13-8) illustrates how the two
  20515.    functions work. Notice how we use store + 2 as an argument for cputs(). We
  20516.    do this because the string starts at the location pointed to by store + 2.
  20517.    We kept the character limit small to make it easy to see what happens when
  20518.    you try to exceed it.
  20519.  
  20520.    ──────────────────────────────────────────────────────────────────────────
  20521.    /* strio.c -- uses cgets() and cputs()                   */
  20522.    /* program list -- strio.c (cgets() not in core library) */
  20523.    #include <conio.h>
  20524.    #define MAXSIZE 6
  20525.    main()
  20526.    {
  20527.         char store[MAXSIZE + 2];
  20528.  
  20529.         store[0] = MAXSIZE; /* puts limit in first element */
  20530.         cputs("What's your name?\n\r");
  20531.         cgets(store);
  20532.         cputs("\n\rI'll remember you, ");
  20533.         cputs(store + 2);
  20534.         cputs("!\n\r");
  20535.    }
  20536.    ──────────────────────────────────────────────────────────────────────────
  20537.  
  20538.    Listing 13-8.  The STRIO.C program.
  20539.  
  20540.    The following is a sample run of the program:
  20541.  
  20542.      What's your name?
  20543.      Steph
  20544.      I'll remember you, Steph!
  20545.  
  20546.    Note the \n\r at the beginning of the second cputs() statement. This
  20547.    prevents the message from being printed over the input line.
  20548.  
  20549.    Instead of using cputs(store + 2), we could have used cputs(&store[2]).
  20550.    Or, because the return value of cgets() points to the start of the
  20551.    string──not to the start of store[]──we could have declared a pointer and
  20552.    used it as follows:
  20553.  
  20554.      char *start;
  20555.       ...
  20556.      start = cgets(store);
  20557.       ...
  20558.      cputs(start);
  20559.  
  20560.  Formatted I/O
  20561.  
  20562.    Finally, the cscanf() and cprintf() functions provide console analogues to
  20563.    the standard I/O functions scanf() and printf(). The main differences are
  20564.    that cscanf() and cprintf() work directly with the console, that cprintf()
  20565.    requires you to use the \r\n combination instead of \n, and, of course,
  20566.    that they are less portable.
  20567.  
  20568.  
  20569.  Keyboard Control with ANSI.SYS
  20570.  
  20571.    Using getch() or getche() and the scan codes, a QuickC program can detect
  20572.    a function key or a cursor control key. But how can you turn that
  20573.    information into action? How, for example, can pressing the Left Arrow key
  20574.    be made to move the cursor one space to the left? There are three common
  20575.    techniques: One uses the ANSI.SYS driver provided with MS-DOS and PC-DOS;
  20576.    the second uses BIOS calls; and the third directly accesses video memory.
  20577.    Table 13-2 compares the three methods.
  20578.  
  20579.    The first method is the simplest, so we begin with it. Many terminals have
  20580.    internal hardware that lets you control cursor position and other screen
  20581.    attributes by sending "escape sequences" from your program to the
  20582.    terminal. These all begin with the ESC character, followed by different
  20583.    sequences corresponding to different actions. For example, the sequence
  20584.    ESC[2B moves the cursor down two lines in the same column. By using
  20585.    printf() to generate such a string, you can move the cursor around. The
  20586.    original IBM PC hardware design omitted this convenient feature.
  20587.  
  20588.    Table 13-2 Cursor and Screen Control Methods
  20589.    Method             ANSI.SYS         BIOS            Direct Memory Access
  20590.    ──────────────────────────────────────────────────────────────────────────
  20591.    Speed ranking      3                2               1
  20592.    Ease-of-use        1                2               3
  20593.    ranking
  20594.    Portability        ANSI-compatible  BIOS-compatible Display-specific
  20595.    ──────────────────────────────────────────────────────────────────────────
  20596.  
  20597.    MS-DOS version 2.0 came to the rescue, however, by providing the ANSI.SYS
  20598.    "driver" as a software fix. (A driver is software designed to handle
  20599.    specific hardware I/O devices.) The ANSI.SYS software intercepts output,
  20600.    examining it for escape sequences. When it finds a valid sequence, it
  20601.    performs the requested action. To use this method, you need ANSI.SYS up
  20602.    and running, and you need to know the proper escape sequences.
  20603.  
  20604.  Starting ANSI.SYS
  20605.  
  20606.    Running ANSI.SYS is not like running an ordinary program. You don't, for
  20607.    example, type ansi. Instead, you place this line in your CONFIG.SYS file:
  20608.  
  20609.      DEVICE=ANSI.SYS
  20610.  
  20611.    If the ANSI.SYS file is in a different directory from the CONFIG.SYS file,
  20612.    give the full pathname, as in the following example:
  20613.  
  20614.      DEVICE=C:\DOS\ANSI.SYS
  20615.  
  20616.    Now, when you boot your computer, ANSI.SYS is installed as part of MS-DOS.
  20617.  
  20618.  Using ANSI.SYS Escape Sequences
  20619.  
  20620.    One handy escape sequence lets you assign a string to a particular key.
  20621.    That is, it makes typing a single key have the same effect as typing the
  20622.    string. First, let's examine the format of the escape sequence required by
  20623.    ANSI.SYS:
  20624.  
  20625.      ESC[ASCIIcode;"string";ASCIIcodep
  20626.  
  20627.    Here ESC represents the escape character (ASCII 033). The first ASCIIcode
  20628.    represents the ASCII number of the key to which you assign the string. For
  20629.    non-ASCII keys, such as F1, use 0ancode, where the number following the 0;
  20630.    is the scan code for the key. Next, string represents, in string form, the
  20631.    characters you want to assign to the key. For example, the string could be
  20632.    dir/w. The final ASCIIcode lets you represent an assigned character in
  20633.    ASCII form instead of as a string. For example, you can use 13 instead of
  20634.    a carriage return. Finally, the character p terminates the escape
  20635.    sequence. You can use as many strings and ASCII codes as you like as long
  20636.    as you separate them with semicolons. For example, you can represent CD by
  20637.    "CD", by "C";68, or by 67;68, where 67 and 68 are ASCII codes for C and D.
  20638.    The ASGNKEY.C program (Listing 13-9), for example, assigns meanings to
  20639.    the F5 through F10 keys. These meanings remain in effect until you reboot.
  20640.  
  20641.    Because all the key assignments follow the same form, we use a macro to
  20642.    represent the general form. In the macro, printf() displays the escape
  20643.    sequence. First comes \033, the octal code for ESC. Then the left bracket
  20644.    and the 0; indicate a scan code. (The scan code itself is the variable K
  20645.    of the macro.) Next comes another semicolon and an open quote. (You must
  20646.    escape these with a \ when you use them within a string.) Next, the string
  20647.    itself is represented by the variable S. Then come the closing quote,
  20648.    another semicolon, a 13 (to represent a carriage return), and the
  20649.    closing p.
  20650.  
  20651.    ──────────────────────────────────────────────────────────────────────────
  20652.    /*   asgnkey.c -- uses ansi.sys to assign meanings   */
  20653.    /*                to several function keys           */
  20654.    /*  Note: This requires ANSI.SYS to be installed.    */
  20655.  
  20656.    #define KASSIGN(K, S) printf("\033[0;%d;\"%s\";13p", K, S)
  20657.    /* This macro assigns string S to key K */
  20658.    #define F5 63
  20659.    #define F6 64
  20660.    #define F7 65
  20661.    #define F8 66
  20662.    #define F9 67
  20663.    #define F10 68
  20664.    main()
  20665.    {
  20666.         KASSIGN(F5, "DIR *.C");
  20667.         KASSIGN(F6, "DIR *.H");
  20668.         KASSIGN(F7, "DIR *.OBJ");
  20669.         KASSIGN(F8, "DIR *.EXE");
  20670.         KASSIGN(F9, "DIR /W");
  20671.         KASSIGN(F10,"CD \\");
  20672.    }
  20673.    ──────────────────────────────────────────────────────────────────────────
  20674.  
  20675.    Listing 13-9.  The ASGNKEY.C program.
  20676.  
  20677.    Running this program changes the function key assignments, but you have to
  20678.    go to MS-DOS before you can see the effects. Once you exit to MS-DOS,
  20679.    pressing F5 through F8 causes MS-DOS to list the specified types of files
  20680.    (*.c, *.h, and so on). The F9 function key lists your directories in the
  20681.    compact form (the /W option). Also, F10 switches to the root directory.
  20682.    The defining string uses \\ for root because that is how you express a
  20683.    single \ in a C string. Because the code itself includes 13 for Return,
  20684.    you don't press Enter when using these function keys.
  20685.  
  20686.    You can easily modify this program to read in the desired function key
  20687.    number and the string interactively. But bear in mind that these
  20688.    assignments supersede existing ones and that they hold until you reboot.
  20689.    If, for example, you assign a function to F1, you override the editing
  20690.    function given to it by MS-DOS.
  20691.  
  20692.    Note that QuickC uses its own routines to read the keyboard, and it
  20693.    bypasses these function key definitions. So, while in QuickC, you still
  20694.    can use F5 to run a program. But if you call up an MS-DOS shell from
  20695.    QuickC, the new assignments apply.
  20696.  
  20697.  Cursor and Screen Control
  20698.  
  20699.    Now let's apply the ANSI.SYS method to a simple menu model. The goal is to
  20700.    write a program that clears the screen and displays a simple menu with one
  20701.    choice highlighted. The Up Arrow and Down Arrow keys move the cursor and
  20702.    highlighting to a different choice, and pressing Enter selects the
  20703.    highlighted choice. To do this, we need more escape codes. Table 13-3 on
  20704.    the following page lists some representative examples from which we'll
  20705.    select the ones we need. Our program will use the various cursor control
  20706.    sequences to move the cursor. The highlighting of a choice is handled
  20707.    using the SGR (Set Graphics Rendition) escape sequence, which lets you
  20708.    specify certain "attributes." Each character to be displayed can be
  20709.    assigned an attribute that controls its presentation: color, reverse
  20710.    video, blinking, and so on. In Table 13-3, ESC[ represents the Escape
  20711.    character, and num is a numeric parameter for which you substitute a
  20712.    specific number. Numbering of rows and columns starts with 1. For all but
  20713.    the last code sequence, any omitted num is assumed to be 1.
  20714.  
  20715.    Table 13-3 ANSI.SYS Escape Sequences
  20716. ╓┌─┌──────────────┌──────────────┌─────────────┌─────────────────────────────╖
  20717.    Name           Mnemonic       Escape Code   Description
  20718.    ──────────────────────────────────────────────────────────────────────────
  20719.    Cursor         CUP            ESC[num;numH  Moves the cursor to the
  20720.    Position                                    position specified by the
  20721.                                                numeric parameters. The first
  20722.                                                num is the line number; the
  20723.                                                second is the column number.
  20724.    Cursor Up      CUU            ESC[numA      Moves the cursor up num lines
  20725.                                                in the same column.
  20726.    Cursor Down    CUD            ESC[num       Moves the cursor down num
  20727.                                                lines in the same column.
  20728.    Cursor Forward CUF            ESC[numC      Moves the cursor right num
  20729.    Name           Mnemonic       Escape Code   Description
  20730.    ──────────────────────────────────────────────────────────────────────────
  20731.   Cursor Forward CUF            ESC[numC      Moves the cursor right num
  20732.                                                columns.
  20733.    Cursor Back    CUB            ESC[numD      Moves the cursor left num
  20734.                                                columns.
  20735.    Erase Display  ED             ESC[u         Erases the entire display and
  20736.                                                homes the cursor.
  20737.    Set Graphics   SGR            ESC[numm      Sets character attributes as
  20738.    Rendition                                   indicated by num. Possible
  20739.                                                values include 0 for normal, 1
  20740.                                                for high intensity, 5 for
  20741.                                                blink, and 7 for reverse
  20742.                                                video.
  20743.    ──────────────────────────────────────────────────────────────────────────
  20744.  
  20745.  
  20746.    To highlight a line of text, we must first print the escape code for
  20747.    highlighting on that line and then print the text. To confine highlighting
  20748.    to the menu line, we turn off highlighting at the end of the menu output.
  20749.  
  20750.    To move the cursor and highlighting, we use getch() and the scan codes to
  20751.    detect when the arrow keys are pressed. If the Down Arrow key is pressed,
  20752.    for example, the program moves the cursor and reprints the menu, changing
  20753.    which line is highlighted. Listing 13-10 shows the completed MENU.C
  20754.    program, and Figure 13-4 on p. 419 shows the menu at work.
  20755.  
  20756.    ──────────────────────────────────────────────────────────────────────────
  20757.    /*  menu.c -- uses ANSI.SYS for cursor control and   */
  20758.    /*            for video reverse in a sample menu     */
  20759.    /*  Note: Requires that ANSI.SYS be installed.       */
  20760.  
  20761.    #include <conio.h>
  20762.    #define ITEMS 5           /* number of menu items     */
  20763.    #define UP 72             /* scan code for up arrow   */
  20764.    #define DOWN 80           /* scan code for down arrow */
  20765.    #define VIDREV "\033[7m"  /* reverse video attribute  */
  20766.    #define ATTOFF "\033[0m"  /* turn attributes off      */
  20767.    #define ED()   printf("\033[2J")  /* erase display     */
  20768.    #define HOME() printf("\033[H")   /* home the cursor   */
  20769.    #define CUU(Y) printf("\033[%dA", Y);   /* cursor up   */
  20770.    #define CUD(Y) printf("\033[%dB", Y);   /* cursor down */
  20771.  
  20772.    char *Menu[ITEMS] = {"Add a number to the list",
  20773.                         "Delete a number from the list",
  20774.                         "Clear the list",
  20775.                         "Sum the list",
  20776.                         "Quit"};
  20777.    char *Heading =
  20778.    "Use arrow keys to highlight choice. "
  20779.    "Use Enter key to select choice.";
  20780.  
  20781.    void showmenu(int);
  20782.    int getmesg(int);
  20783.    main()
  20784.    {
  20785.        int messno = 0; /* message to be highlighted */
  20786.        ED();
  20787.        showmenu(messno);
  20788.        while (messno != ITEMS - 1)
  20789.            {
  20790.            messno = getmesg(messno);
  20791.            ED();
  20792.            switch (messno)
  20793.               {
  20794.               case 0 :
  20795.               case 1 :
  20796.               case 2 :
  20797.               case 3 : printf("...pretending to work...");
  20798.                        printf("Hit any key to continue\n");
  20799.                        getch();
  20800.                        ED();
  20801.                        showmenu(messno);
  20802.                        break;
  20803.               case 4 : printf("Quitting!\n");
  20804.                        break;
  20805.               default: printf("Programming error!\n");
  20806.                        break;
  20807.               }
  20808.            }
  20809.    }
  20810.  
  20811.    /* showmenu() displays the menu  */
  20812.    void showmenu(highlite)
  20813.    int highlite;   /* message number to be highlighted */
  20814.    {
  20815.        int n;
  20816.        char *start;
  20817.        HOME();
  20818.        printf("%s", Heading);
  20819.        for (n = 0; n < ITEMS; n++)
  20820.            {
  20821.            if (n == highlite)
  20822.                start = VIDREV; /* turn on reverse video */
  20823.            else
  20824.                start = ATTOFF;
  20825.            printf("\n\n%s%s%s", start, Menu[n], ATTOFF);
  20826.            }
  20827.        HOME();
  20828.        CUD(2 + 2 * highlite);
  20829.    }
  20830.  
  20831.    /*  getmesg() selects a menu item */
  20832.    int getmesg(mnum)
  20833.    int mnum; /* current message number */
  20834.    {
  20835.        char ch;
  20836.        while ((ch = getch()) != '\r')
  20837.            if (ch == 0)
  20838.                {
  20839.                ch = getch();
  20840.                switch (ch)
  20841.                    {
  20842.                    case UP   : if (mnum > 0)
  20843.                                    {
  20844.                                    CUU(2);
  20845.                                    showmenu (--mnum);
  20846.                                    }
  20847.                                else
  20848.                                    {
  20849.                                    CUD(2 * ITEMS - 2);
  20850.                                    showmenu(mnum = ITEMS - 1);
  20851.                                    }
  20852.                                break;
  20853.                    case DOWN : if (mnum < ITEMS - 1)
  20854.                                    {
  20855.                                    CUD(2);
  20856.                                    showmenu(++mnum);
  20857.                                    }
  20858.                                else
  20859.                                    {
  20860.                                    CUU(2 * ITEMS - 2);
  20861.                                    showmenu(mnum = 0);
  20862.                                    }
  20863.                                break;
  20864.                    }
  20865.                }
  20866.                return mnum;
  20867.    }
  20868.    ──────────────────────────────────────────────────────────────────────────
  20869.  
  20870.    Listing 13-10.  The MENU.C program.
  20871.  
  20872.    ┌────────────────────────────────────────────────────────────────────────┐
  20873.    │ Figure 13-4 can be found on p.419 of the printed version of the book.  │
  20874.    └────────────────────────────────────────────────────────────────────────┘
  20875.  
  20876.    Figure 13-4. The MENU.C program at work.
  20877.  
  20878.    ──────────────────────────────────────────────────────────────────────────
  20879.    Watching the Keyboard in BASIC and C
  20880.    The ANSI.SYS techniques discussed here allow you to achieve the
  20881.    functionality of the KEY statement in BASIC. The BASIC KEY n, string
  20882.    statement allows you to assign a string to the PC function key Fn──that
  20883.    is, to create a simple "keyboard macro." The ANSI method is more general
  20884.    (it can be used with any key, not just a function key) and is also not
  20885.    limited to assigning short strings.
  20886.  
  20887.    BASIC statements such as ON KEY provide a very useful facility called
  20888.    "event-driven programming." After you use the KEY statement to assign a
  20889.    key number to one of the keyboard keys, a press of that key while the
  20890.    program is running will be "trapped." The ON KEY(n) subroutine statement
  20891.    causes subroutine to be executed whenever the key that's assigned number n
  20892.    is pressed. This allows programs to respond to input immediately.
  20893.  
  20894.    C has no such built-in facilities. You can, however, put the program in an
  20895.    outer loop that calls the kbhit() function to see if a key has been
  20896.    pressed. If a key has been pressed, you can use getch() to read the key.
  20897.    After assigning the key to a variable of type char, you can use it in a
  20898.    switch statement that calls the appropriate function to handle the command
  20899.    received. This isn't true event-driven programming, because the response
  20900.    to a key comes only when the program is at the top of the loop, but QuickC
  20901.    programs run fast enough that the effect is often the same. The use of a
  20902.    special device driver or an environment such as Microsoft Windows can
  20903.    allow for true event-driven programming.
  20904.    ──────────────────────────────────────────────────────────────────────────
  20905.  
  20906.    The MENU.C program first defines several macros using printf() and the
  20907.    escape codes to represent some of the ANSI.SYS sequences from Table 13-3
  20908.    on p. 416. If you plan to use such macros often, you should create an
  20909.    include file for the macro definitions.
  20910.  
  20911.    Because we are illustrating ANSI.SYS and not numeric analysis, the program
  20912.    does no actual calculation. However, the switch statement in main()
  20913.    provides the skeleton for controlling program flow. The getmesg() function
  20914.    returns the array index of the selected message, and the switch selects a
  20915.    response based on that value. The switch is in a loop, so you can
  20916.    repeatedly make choices until you select Quit.
  20917.  
  20918.    In main(), the HOME() macro uses the CUP escape code to home the cursor.
  20919.    Because we omitted the two numeric parameters, the default values of 1 are
  20920.    used, which effectively home the cursor.
  20921.  
  20922.    The showmenu() function displays the menu. It receives the array index of
  20923.    the element to be highlighted. That message then starts with highlighting
  20924.    turned on; the other messages have it turned off.
  20925.  
  20926.    The getmesg() function, as we mentioned, returns the array index of the
  20927.    selected item. It also handles the cursor movement. In this function,
  20928.    getch() checks for the Up Arrow and the Down Arrow keys. If, for example,
  20929.    the Down Arrow key is pressed, CUD moves the cursor down two lines to the
  20930.    next message. The array index is also incremented to tell showmenu() which
  20931.    message to highlight. To keep the cursor inside the menu, we compare its
  20932.    position to the menu limits. If the cursor is on the bottom line of the
  20933.    menu, then pressing the Down Arrow key moves it to the top line.
  20934.  
  20935.    This program works as designed, but it runs slowly, and the redrawing of
  20936.    the screen is not very smooth. The ANSI.SYS approach to cursor and screen
  20937.    control is relatively simple, but using BIOS calls or direct memory access
  20938.    gives better performance.
  20939.  
  20940.  
  20941.  Using QuickC to Access the BIOS
  20942.  
  20943.    One way to create programs that take advantage of the special capabilities
  20944.    of an IBM PC/XT, PC/AT, or compatible without getting too involved in the
  20945.    hardware is to use BIOS calls.
  20946.  
  20947.  Background for the IBM BIOS
  20948.  
  20949.    BIOS is an acronym for Basic Input/Output System. It consists of a set of
  20950.    assembly-language routines permanently stored in what is called Read-Only
  20951.    Memory, or ROM, of the IBM PC. The computer can read and utilize
  20952.    information in ROM, but it cannot alter ROM. That preserves the integrity
  20953.    of the routines. The BIOS includes routines to read the keyboard, to
  20954.    control the video display, and to read from and write to disk drives. Most
  20955.    higher-level programming ultimately makes use of these routines. For
  20956.    instance, QuickC's getch() uses one of the keyboard routines, and many
  20957.    MS-DOS commands ultimately use the BIOS routines to do low-level work.
  20958.  
  20959.    In short, you can think of the BIOS as a built-in library of functions.
  20960.    All you need to do is find out what services are offered and how to use
  20961.    them.
  20962.  
  20963.    The ultimate source of information about the BIOS is the IBM Personal
  20964.    Computer Technical Reference Manual. This manual includes
  20965.    assembly-language listings of all the routines. We'll describe those
  20966.    routines as we use them.
  20967.  
  20968.  Using the BIOS
  20969.  
  20970.    Two problems face the QuickC programmer who wants to use the BIOS. One is
  20971.    that the routines, which are written in assembly language, don't work the
  20972.    same as C functions, so you have to learn a little about assembly language
  20973.    and about the hardware to understand them. The second is that these BIOS
  20974.    routines are accessed not by function calls but by "interrupt signals."
  20975.    For this reason, these routines are commonly called "interrupt routines,"
  20976.    or simply "interrupts." Let's clarify this topic first.
  20977.  
  20978.    Interrupt Routines
  20979.  
  20980.    The heart of a PC is its central processing unit, or CPU, but a PC
  20981.    contains other processors, too. For example, the keyboard processor
  20982.    handles keyboard input, and another processor handles data flow between
  20983.    the CPU and memory. To enable the CPU to keep in touch with its
  20984.    environment, an interrupt system was developed. Certain devices and
  20985.    assembly-language instructions can generate signals that take control of
  20986.    the microprocessor. The Intel 8086 family of microprocessors permits as
  20987.    many as 256 distinct interrupt signals, but fewer are actually used. When
  20988.    the CPU detects an interrupt signal, it "interrupts" its current activity
  20989.    and executes the set of assembly-language instructions identified with
  20990.    that particular signal.
  20991.  
  20992.    ──────────────────────────────────────────────────────────────────────────
  20993.    How Interrupts Work
  20994.    When you boot a PC, it sets up a table of addresses known as the
  20995.    "interrupt vectors." At the first address is the routine to be executed if
  20996.    interrupt signal 0 is detected. At the second address is the routine to be
  20997.    executed if interrupt signal 1 is detected, and so on. When an interrupt
  20998.    is detected, the corresponding address is found in the table, and the
  20999.    instructions beginning at that address are executed. At the end of those
  21000.    instructions, a "return from interrupt" instruction tells the
  21001.    microprocessor to resume its interrupted activity.
  21002.  
  21003.    The operating system also uses the interrupt table. When MS-DOS or PC-DOS
  21004.    is first loaded, it adds its own batch of interrupt routines. Memory
  21005.    resident programs also work by storing their addresses in the interrupt
  21006.    vector table. Incidentally, MS-DOS can substitute its own version of a
  21007.    ROM-based BIOS routine by overwriting the appropriate interrupt vector
  21008.    with a new address. The ROM itself is unchanged, but the computer is
  21009.    directed to the new address instead when the interrupt is issued. This
  21010.    method is sometimes used as a software "fix" for faulty BIOS routines.
  21011.    (The only way to update the actual BIOS is to get a newer version of the
  21012.    ROM chip.)
  21013.    ──────────────────────────────────────────────────────────────────────────
  21014.  
  21015.    Software Interrupts
  21016.  
  21017.    In assembly language, generating interrupts is simple. For example, to
  21018.    generate interrupt signal 0x10 (the video I/O interrupt), you use the
  21019.    following instruction:
  21020.  
  21021.      int 10h
  21022.  
  21023.    What if one interrupt arrives while another interrupt routine is
  21024.    executing? This situation is handled by a priority ranking. A
  21025.    higher-priority interrupt can interrupt a lower-priority routine, but not
  21026.    vice versa.
  21027.  
  21028.    C, as a general, portable language, doesn't have a built-in interrupt
  21029.    instruction. But the QuickC library offers several non-ANSI C functions
  21030.    designed to serve the same purpose. Seven functions make specific BIOS
  21031.    calls; they all have names beginning with _bios_ and are declared in the
  21032.    bios.h file. The dos.h file declares another 40 functions, most of which
  21033.    call specific MS-DOS functions. (Interrupt number 0x21 can be used to
  21034.    access many functions loaded into the system by MS-DOS; these are the
  21035.    MS-DOS system calls.) Five of the dos.h functions, however, are more
  21036.    general and can invoke a choice of interrupts. (See Table 13-4 for a
  21037.    summary of these functions.)
  21038.  
  21039.    We will use the int86() function because it is generally applicable. As
  21040.    its name suggests, it generates a specified interrupt for the 8086 family
  21041.    of microprocessors. However, before we can use this function, we have to
  21042.    see how interrupt routines use registers to transfer data.
  21043.  
  21044.    Table 13-4 Interrupt-accessing Functions in Order of Decreasing Generality
  21045.    Name               Use
  21046.    ──────────────────────────────────────────────────────────────────────────
  21047.    intx86()           Invokes interrupts requiring the use of segment
  21048.                       registers.
  21049.    int86()            Invokes interrupts not requiring use of the segment
  21050.                       registers.
  21051.    intxdos()          Invokes MS-DOS system calls requiring the use of
  21052.                       segment registers.
  21053.    intdos()           Invokes MS-DOS system calls not requiring use of the
  21054.                       segment registers.
  21055.    bdos()             Invokes MS-DOS system calls that use only the DX and AL
  21056.                       registers.
  21057.    _bios_...() family Invokes specific BIOS interrupts.
  21058.    _dos_...() family  Invokes specific MS-DOS calls.
  21059.    ──────────────────────────────────────────────────────────────────────────
  21060.  
  21061.    Interrupts, Assembly Language, and Registers
  21062.  
  21063.    Like C functions, interrupts pass information back and forth between the
  21064.    routine and the calling program. Instead of using arguments, however,
  21065.    interrupts use the microprocessor registers. The int86() function gets
  21066.    around this difference by using unions to pass the register information to
  21067.    and from the calling C program.
  21068.  
  21069.    Registers are small work and storage areas built into the CPU. For
  21070.    example, the 8088 chip, the most commonly used member of the 8086 family,
  21071.    has 13 registers, each capable of holding 16 bits. Four of the registers
  21072.    are general-purpose registers used for arithmetic and logical operations;
  21073.    they are called AX, BX, CX, and DX. Four "segment" registers store the
  21074.    addresses of various memory segments; these registers are called CS, DS,
  21075.    SS, and ES. Four more "pointer/index" registers keep track of addresses
  21076.    used in a program; they are called SP, BP, SI, and DI. Finally, the
  21077.    instruction pointer (IP) keeps track of the address of the next
  21078.    instruction to be executed. Also, the processor has nine "flags" that can
  21079.    be turned on or off. The flags can be considered to be individual bits in
  21080.    a flag register. These, then, are the resources open to an interrupt
  21081.    routine.
  21082.  
  21083.    There is one further complication. Each of the general-purpose registers
  21084.    can be considered to be two 8-bit registers. The AX register, for example,
  21085.    can be divided into the AH (H for high byte) and the AL (L for low byte)
  21086.    registers. Assigning a value to the AX register affects the whole
  21087.    register, but assigning a value to AL or AH affects only half of the
  21088.    register. Similarly, the BX register is divided into the BH and BL
  21089.    registers, and so on.
  21090.  
  21091.    Now that we have some background about registers, let's see how int86()
  21092.    works.
  21093.  
  21094.  The int86() Function
  21095.  
  21096.    The int86() function will be our tool for initiating interrupt routines,
  21097.    initializing registers, and reading registers. Its library description
  21098.    begins with the following:
  21099.  
  21100.      #include <dos.h>
  21101.      int int86(intno, inregs, outregs);
  21102.      int intno;           /* Interrupt number */
  21103.      union REGS *inregs;  /* Register values on call */
  21104.      union REGS *outregs; /* Register values on return */
  21105.  
  21106.    This syntax summary says to include the dos.h header file when using this
  21107.    function. Also, int86() takes three arguments. The first is the number of
  21108.    the desired interrupt. The second is the address of a union containing the
  21109.    register values passed to the interrupt. The third is the address of the
  21110.    union into which the post-interrupt register values are copied.
  21111.  
  21112.    To use int86(), you need to know how the type union REGS is defined. That
  21113.    information resides in the dos.h file, as follows:
  21114.  
  21115.      /* word registers */
  21116.  
  21117.      struct WORDREGS {
  21118.           unsigned int ax;
  21119.           unsigned int bx;
  21120.           unsigned int cx;
  21121.           unsigned int dx;
  21122.           unsigned int si;
  21123.           unsigned int di;
  21124.           unsigned int cflag;
  21125.           };
  21126.  
  21127.      /* byte registers */
  21128.  
  21129.      struct BYTEREGS {
  21130.           unsigned char al, ah;
  21131.           unsigned char bl, bh;
  21132.           unsigned char cl, ch;
  21133.           unsigned char dl, dh;
  21134.           };
  21135.  
  21136.      /* general-purpose registers union -- overlays the
  21137.      corresponding word and byte registers. */
  21138.  
  21139.      union REGS {
  21140.           struct WORDREGS x;
  21141.           struct BYTEREGS h;
  21142.           };
  21143.  
  21144.    Together, these definitions give two views of the registers.
  21145.  
  21146.    The WORDREGS structure provides the 16-bit view. This structure has seven
  21147.    members representing the four general-purpose registers, two of the
  21148.    pointer registers, and the "carry" flag (which we won't use). These are
  21149.    the registers most commonly used by the interrupts. (The int86x() function
  21150.    uses an additional structure to give access to more registers.) In this
  21151.    structure, for example, the ax member represents the AX register.
  21152.  
  21153.    The BYTEREGS structure gives the 8-bit view. This structure represents the
  21154.    four general-purpose registers, with each register split into two 1-byte
  21155.    registers. Thus, the ch member of this structure represents the CH
  21156.    register, the high byte of CX.
  21157.  
  21158.    The unusual part of this function is the definition of the union REGS. It
  21159.    superimposes the word view and the byte view. For example, suppose you use
  21160.    the following declaration:
  21161.  
  21162.      union REGS myreg;
  21163.  
  21164.    To assign a value to the AX register, use a statement such as the
  21165.    following:
  21166.  
  21167.      myreg.x.ax = 1026;
  21168.  
  21169.    The .x notation specifies the WORDREGS member of myreg; therefore,
  21170.    myreg.x.ax is the AX member of that structure.
  21171.  
  21172.    To assign a value to the BL register (the low byte of the BX register),
  21173.    use the following .h notation:
  21174.  
  21175.      myreg.h.bl = 22;
  21176.  
  21177.    This specifies the BYTEREGS member of the union.
  21178.  
  21179.    Recall that a union uses the same storage area for all its members. This
  21180.    means that myreg.h.al and myreg.h.ah overlie myreg.x.ax. To get the high
  21181.    byte of the 1026 that was assigned to myreg.x.ax, refer to myreg.h.ah (see
  21182.    Figure 13-5).
  21183.  
  21184.    union REGS myreg;
  21185.                                       word
  21186.                     ┌───────────────────┬───────────────────┐
  21187.                   / │                   │                   │ \  AX register
  21188.                 /   │              myreg.x.ax               │   \
  21189.               /     └───────────────────┴───────────────────┘     \
  21190.             /     / ┌─────────── /───/──┬──\───\────────────┐ \     \
  21191.           ┌───────────────────┐/   /    │    \   \┌───────────────────┐
  21192.           │     one byte      │  /      │      \  │     one byte      │
  21193.           │    myreg.h.ah     │/────────┴────────\│    myreg.h.al     │
  21194.     AH    └───────────────────┘─────────┬─────────└───────────────────┘  AL
  21195.    register         │                   │                   │        register
  21196.                     │                   │                   │
  21197.                     └───────────────────┴───────────────────┘
  21198.                     ┌───────────────────┬───────────────────┐
  21199.                     │                   │                   │ DX
  21200.                     │                   │                   │
  21201.                     └───────────────────┴───────────────────┘
  21202.  
  21203.    For a REGS union: .x means the 16-bit version
  21204.                      .h means the 8-bit version
  21205.  
  21206.    Figure 13-5. The REGS union.
  21207.  
  21208.    You now know enough theory to use int86(). However, you still need to know
  21209.    what values to pass as arguments to the BIOS routines. Let's look at a
  21210.    simple example.
  21211.  
  21212.  Interrupt 0x16──The Keyboard I/O Interrupt
  21213.  
  21214.    Because we have been discussing the keyboard, let's look at interrupt
  21215.    routine 0x16, which reads the keyboard. The QuickC library provides the
  21216.    _bios_kbrd() function to access this specific routine. However, we will
  21217.    use int86() in order to demonstrate a more general approach to using
  21218.    interrupts.
  21219.  
  21220.    Like many interrupts, 0x16 includes more than one subroutine. It has three
  21221.    subroutines; each is termed a "function" or "service." To select a
  21222.    particular function, you must place the "function code" number in the AH
  21223.    register before calling the interrupt. Let's take a look at what each
  21224.    function does.
  21225.  
  21226.    Interrupt 0x16, Function Code 0──Get Character
  21227.  
  21228.    This function reads the keyboard buffer if a character is present;
  21229.    otherwise, it waits until a keystroke is placed in the buffer. When it
  21230.    reads a key, it places the ASCII byte in the AL register and the scan byte
  21231.    in the AH register. (Note that the return values are written over the
  21232.    values we originally placed in AH and AL.) The code is removed from the
  21233.    keyboard buffer once it is read. The getch() function is based on this
  21234.    function.
  21235.  
  21236.    Interrupt 0x16, Function Code 1──Check Keyboard Buffer
  21237.  
  21238.    This function checks to see if the keyboard buffer is empty or not. If it
  21239.    is empty, the "zero flag" (ZF) is set to 1; otherwise, the flag is cleared
  21240.    (set to zero). If a character is present, the ASCII byte is placed in AL
  21241.    and the scan byte in AH, but the code in the buffer is left there. The
  21242.    kbhit() function is based on this function.
  21243.  
  21244.    Interrupt 0x16, Function Code 2──Get Keyboard Status
  21245.  
  21246.    This function reports on the status of the Shift and Ctrl keys. Each of
  21247.    eight keys is assigned a particular bit in the AL register. If one of the
  21248.    eight keys is closed, the corresponding bit is set to 1. Table 13-5 shows
  21249.    the corresponding bits and keys.
  21250.  
  21251.    Table 13-5 Keyboard Status Bits
  21252.    Bit         Set to 1 If
  21253.    ──────────────────────────────────────────────────────────────────────────
  21254.    0           Right Shift is closed
  21255.    1           Left Shift is closed
  21256.    2           Ctrl is closed
  21257.    3           Alt is closed
  21258.    4           Scroll Lock is active
  21259.    5           Num Lock is active
  21260.    6           Caps Lock is active
  21261.    7           Insert mode is active
  21262.    ──────────────────────────────────────────────────────────────────────────
  21263.  
  21264.  Reading ASCII and Scan Codes
  21265.  
  21266.    Let's use function code 0 to construct a more general version of getch()
  21267.    that we'll call Readkey(). It will return both the ASCII and the scan
  21268.    bytes. Using it will give you a better picture of how the keyboard codes
  21269.    work and show you that using interrupts from QuickC is not all that
  21270.    difficult. The readkey.c program (Listing 13-11) contains the Readkey()
  21271.    function.
  21272.  
  21273.    The dos.h file defines the union REGS type and declares the int86()
  21274.    function. We define symbolic constants to represent the interrupt number
  21275.    and the function code number. Finally, we define a two-member structure
  21276.    called SCANCODE for holding the two keyboard codes. Readkey() uses the reg
  21277.    structure to set the AH register to the proper function code and then it
  21278.    calls int86(). Because preserving the original register values is
  21279.    unnecessary, the same structure stores both the input values and the
  21280.    returned values of the registers. Finally, the program copies the two
  21281.    relevant register values into the structure that the function returns.
  21282.  
  21283.    The int86() syntax calls for two pointers to union REGS as arguments. In
  21284.    practice this usually calls for using the address operator applied to the
  21285.    appropriate union, as we have done here.
  21286.  
  21287.    Having developed the Readkey() function, let's use it in the next program,
  21288.    SHOWCODE.C, (Listing 13-12). To run this program within the QuickC
  21289.    environment, be sure that Screen Swapping On is active (on the Debug
  21290.    menu).
  21291.  
  21292.    This program reads a key, prints it (if it is printable), and displays
  21293.    both the ASCII and scan codes. Using it can be instructive. Following, for
  21294.    example, is the output for m, Shift-M, Ctrl-M, Alt-M, Enter, and Esc:
  21295.  
  21296.       m: ascii = 109, scan =  50────────────────────────────────────────────m
  21297.       M: ascii =  77, scan =  50──────────────────────────────────────Shift-M
  21298.      ^M: ascii =  13, scan =  50───────────────────────────────────────Ctrl-M
  21299.        : ascii =   0, scan =  50────────────────────────────────────────Alt-M
  21300.      ^M: ascii =  13, scan =  28────────────────────────────────────────Enter
  21301.      ^[: ascii =  27, scan =   1──────────────────────────────────────────Esc
  21302.  
  21303.    ──────────────────────────────────────────────────────────────────────────
  21304.    /* readkey.c -- contains the Readkey() function     */
  21305.    #include <dos.h>
  21306.    #define KEYINTR 0x16  /* keyboard read interrupt */
  21307.    #define GETCHAR 0     /* read scancode function  */
  21308.    struct SCANCODE {
  21309.                    unsigned char ascii;  /* ascii code */
  21310.                    unsigned char scan;   /* scan code  */
  21311.                    };
  21312.  
  21313.    struct SCANCODE Readkey()
  21314.    {
  21315.        union REGS reg;
  21316.        struct SCANCODE scancode;
  21317.  
  21318.        reg.h.ah = GETCHAR;         /* specify function   */
  21319.        int86(KEYINTR, ®, ®); /* note use of & oper.*/
  21320.        scancode.ascii = reg.h.al;
  21321.        scancode.scan = reg.h.ah;
  21322.        return (scancode);
  21323.    }
  21324.    ──────────────────────────────────────────────────────────────────────────
  21325.  
  21326.    Listing 13-11.  The readkey.c function.
  21327.  
  21328.    ──────────────────────────────────────────────────────────────────────────
  21329.    /*  showcode.c -- shows ASCII and scan codes for    */
  21330.    /*                keystrokes                        */
  21331.    /* Note: Set Screen Swapping On in the Debug menu.  */
  21332.    #include <stdio.h>
  21333.    #include <dos.h>
  21334.    #define KEYINTR 0x16  /* keyboard read interrupt */
  21335.    #define GETCHAR 0     /* read scancode function  */
  21336.    #define ESC '\033'    /* escape key              */
  21337.    struct SCANCODE {
  21338.                    unsigned char ascii;  /* ascii code */
  21339.                    unsigned char scan;   /* scan code  */
  21340.                    };
  21341.    struct SCANCODE Readkey();
  21342.  
  21343.    main()
  21344.    {
  21345.        struct SCANCODE keys;
  21346.  
  21347.        printf("Press keys to see their scancodes. ");
  21348.        printf("Press the Esc key to quit.\n");
  21349.        do  {
  21350.            keys = Readkey();
  21351.            if (keys.ascii > 0 && keys.ascii < 040)
  21352.                printf("^%c: ascii = %3d, scan = %3d\n",
  21353.                        keys.ascii + 0100, keys.ascii,
  21354.                        keys.scan);
  21355.            else if (keys.ascii >= 40)
  21356.                printf(" %c: ascii = %3d, scan = %3d\n",
  21357.                        keys.ascii, keys.ascii, keys.scan);
  21358.            else
  21359.                printf("  : ascii = %3d, scan = %3d\n",
  21360.                        keys.ascii, keys.scan);
  21361.            } while (keys.ascii != ESC);
  21362.    }
  21363.  
  21364.    struct SCANCODE Readkey()
  21365.    {
  21366.        union REGS reg;
  21367.        struct SCANCODE scancode;
  21368.  
  21369.        reg.h.ah = GETCHAR;
  21370.        int86(KEYINTR, ®, ®);
  21371.        scancode.ascii = reg.h.al;
  21372.        scancode.scan = reg.h.ah;
  21373.        return (scancode);
  21374.    }
  21375.    ──────────────────────────────────────────────────────────────────────────
  21376.  
  21377.    Listing 13-12.  The SHOWCODE.C program.
  21378.  
  21379.    The scan code for the first four characters is the same (50) because the
  21380.    same primary key (the M key) was used in each case. The modifying key, if
  21381.    any, then caused the ASCII part of the code to be changed. Note how the
  21382.    ASCII part for Alt-M is 0. Also note how the Enter key has the same ASCII
  21383.    code as Ctrl-M but a different scan code. The scan code is different
  21384.    because a different physical key was pressed. Incidentally, if you need to
  21385.    write a program that discriminates between input of Ctrl-M and the Enter
  21386.    key, you can use Readkey() to check the scan code. (The getch() function
  21387.    cannot distinguish between the two keystrokes.)
  21388.  
  21389.    The following represents another sample run; this time the input is F1,
  21390.    Ctrl-F1, Shift-F1, Alt-F1, and Esc:
  21391.  
  21392.        : ascii =   0, scan =  59───────────────────────────────────────────F1
  21393.        : ascii =   0, scan =  94──────────────────────────────────────Ctrl-F1
  21394.        : ascii =   0, scan =  84─────────────────────────────────────Shift-F1
  21395.        : ascii =   0, scan = 104───────────────────────────────────────Alt-F1
  21396.      ^[: ascii =  27, scan =   1──────────────────────────────────────────Esc
  21397.  
  21398.    In this example, the scan code changes even though the same primary key
  21399.    was pressed each time. With ASCII characters, the ASCII code discriminates
  21400.    among diferent combinations, but with the control keys, the ASCII byte is
  21401.    always 0, so the scan code itself must change. Also, notice that these
  21402.    keystrokes are nonprinting; therefore, the program displays only the
  21403.    codes.
  21404.  
  21405.    Finally, this example uses the following input: 1, the End key, Shift-End,
  21406.    and Esc:
  21407.  
  21408.      1: ascii =  49, scan =   2─────────────────────────────────────────────|
  21409.       : ascii =   0, scan =  79───────────────────────────────────────────End
  21410.      1: ascii =  49, scan =  79─────────────────────────────────────Shift-End
  21411.  
  21412.    Note how Shift-End and 1 produce the same ASCII code (49) but different
  21413.    scan codes (2 and 79). We mention this because the QuickC editor uses the
  21414.    Shift-End combination to highlight a line. If the programming for QuickC
  21415.    relied on getch(), that would be impossible to do. Apparently QuickC, like
  21416.    our program, checks the scan code too. This lets it assign a different
  21417.    function to Shift-End.
  21418.  
  21419.  
  21420.  Cursor and Screen Control with BIOS Calls
  21421.  
  21422.    Now that you know how to use interrupts, we can extend that technique to
  21423.    cursor and screen control. To illustrate these applications, we will
  21424.    construct a rudimentary first step toward a word processor. With this
  21425.    program, you can do the following:
  21426.  
  21427.    ■  Start with a clear screen.
  21428.  
  21429.    ■  Enter text from the keyboard and see it on the screen.
  21430.  
  21431.    ■  Use the arrow keys to move the cursor.
  21432.  
  21433.    ■  Use the function keys to turn highlighting on and off.
  21434.  
  21435.    ■  Highlight or unhighlight existing text by moving the cursor over it.
  21436.  
  21437.    To provide these features, we'll construct a library of approximately a
  21438.    dozen BIOS-based functions. Rather than jumping back and forth between
  21439.    program development and BIOS use, we'll develop the entire library first.
  21440.  
  21441.    Incidentally, the QuickC Graphics Library, which we discuss in Chapter
  21442.    15, provides an alternative means for implementing these features. Using
  21443.    the Graphics Library, however, produces executable programs substantially
  21444.    larger than those using the BIOS approach.
  21445.  
  21446.  The Video I/O Interrupt
  21447.  
  21448.    The first step is to find the appropriate interrupt routine. Interrupt
  21449.    0x10, the video I/O interrupt, controls the display. Because maintaining a
  21450.    video display is more complex than monitoring a keyboard, this interrupt
  21451.    turns out to be much more involved than the keyboard I/O interrupt. It
  21452.    provides many subroutines, or functions, and many of them use several
  21453.    registers. Table 13-6 on the following pages lists and describes the
  21454.    functions we use in this book. The table mentions "attributes" and
  21455.    "pages." Attributes, as we saw in our discussion of ANSI.SYS, determine
  21456.    how a character is to be displayed. A page is a screenful of display. Some
  21457.    video modes can store more than one page at once, although only one can be
  21458.    displayed at any given time. We discuss these terms further as needed.
  21459.  
  21460.    When using int86() to invoke these functions, you set AH to the
  21461.    appropriate function code number and initialize any other registers given
  21462.    in the description. The first argument to int86() should be 0x10, the
  21463.    interrupt number.
  21464.  
  21465.    Table 13-6 Selected Video I/O Interrupt 0x10 Functions
  21466.    ──────────────────────────────────────────────────────────────────────────
  21467.    FUNCTION CODE 0: Set the Display Mode
  21468.    Action:            Switches to desired mode and clears display.
  21469.    Register setup:    Place 0 in AH
  21470.                       Place desired mode in AL
  21471.  
  21472.    Choose from the following modes:
  21473.    Mode               Meaning
  21474.    0                  40 x 25 B/W Text
  21475.    1                  40 x 25 Color Text
  21476.    2                  80 x 25 B/W Text
  21477.    3                  80 x 25 Color Text
  21478.    4                  320 x 200 Color Graphics
  21479.    5                  320 x 200 B/W Graphics
  21480.    6                  640 x 200 B/W Graphics
  21481.    7                  80 x 25 Monochrome
  21482.    13                 320 x 200 Color EGA
  21483.    14                 640 x 200 Color EGA
  21484.    15                 640 x 350 B/W EGA
  21485.    16                 640 x 350 Color EGA
  21486.    17                 640 x 480, 2-Color VGA
  21487.    18                 640 x 480, 16-Color VGA
  21488.    19                 320 x 200, 256-Color VGA
  21489.  
  21490.    FUNCTION CODE 2: Select Cursor Position
  21491.    Action:            Moves cursor to the specified row and number.
  21492.    Register setup:    Place 2 in AH
  21493.                       Place row number in DH
  21494.                       Place column number in DL
  21495.                       Place page number in BH
  21496.  
  21497.    Numbering of rows and columns starts with 0, not 1.
  21498.  
  21499.    FUNCTION CODE 3: Read Cursor Position
  21500.    Action:            Reports the row and column of cursor position.
  21501.    Register setup:    Place 3 in AH
  21502.                       Place page number in BH
  21503.    Returns:           Row number is in BH
  21504.                       Column number is in DL
  21505.                       Cursor type is in CH, CL
  21506.  
  21507.    FUNCTION CODE 5: Select Active Display Page
  21508.    Action:            Selects the page for modes supporting multiple pages.
  21509.    Register setup:    Place 5 in AH
  21510.                       Place page number in AL
  21511.  
  21512.    FUNCTION CODE 6: Scroll Up an Area of the Screen
  21513.    Action:            Scrolls up a section of the screen a specified amount.
  21514.    Register setup:    Place 6 in AH
  21515.                       Place number of lines to scroll in AL (0 in AL produces
  21516.                       a blank window)
  21517.                       Place blank-line attribute in BH
  21518.                       Place upper-left row number in CH
  21519.                       Place upper-left column number in CL
  21520.                       Place lower-right row number in DH
  21521.                       Place lower-right column number in DL
  21522.  
  21523.    FUNCTION CODE 8: Read Character and Attribute
  21524.    Action:            Reports the character and attribute code at the current
  21525.                       cursor position.
  21526.    Register setup:    Place 8 in AH
  21527.                       Place page number in BH (text modes)
  21528.    Returns:           Character at cursor is in AL
  21529.                       Attribute at cursor is in AH
  21530.  
  21531.    FUNCTION CODE 9: Write Character and Attribute
  21532.    Action:            Writes a specified character and attribute to the
  21533.                       current cursor position.
  21534.    Register setup:    Place 9 in AH
  21535.                       Place page number in BH (text modes)
  21536.                       Place character in AL
  21537.                       Place attribute (text modes) or color (graphics modes)
  21538.                       in BL
  21539.                       Place number of characters in CX
  21540.  
  21541.    Note: The character is written the indicated number of times starting at
  21542.    the current cursor position; the cursor position remains unchanged.
  21543.  
  21544.    FUNCTION CODE 15: Return Current Video State
  21545.    Action:            Reports the video mode, number of text columns, and the
  21546.                       current page value.
  21547.    Register setup:    Place 15 in AH
  21548.    Returns:           Current mode is in AL
  21549.                       Number of columns is in AH
  21550.                       Current active page number is in BH
  21551.    ──────────────────────────────────────────────────────────────────────────
  21552.  
  21553.  Developing a Library of C Functions
  21554.  
  21555.    Our next step is to develop a set of C functions that use the video I/O
  21556.    interrupt. In this section, we will design several functions, each general
  21557.    enough to be useful for a variety of programs. We'll develop the functions
  21558.    individually but then collect them in one file so that they can share a
  21559.    common set of include files and definitions. You'll find the contents of
  21560.    this combined file, which is called SCRFUN.C, in Listing 13-23 beginning
  21561.    on p. 441. Finally, we'll use the LIB utility to make a library of the
  21562.    video functions.
  21563.  
  21564.    Setting the Cursor
  21565.  
  21566.    First, we need two C functions: one to set the cursor and another to
  21567.    report the current cursor position. We use functions 2 and 3 of the video
  21568.    interrupt to develop our own Setcurs() and Getcurs() functions (Listing
  21569.    13-13).
  21570.  
  21571.    Pass the desired row, column, and page to Setcurs(), and it positions the
  21572.    cursor. Use Getcurs() to place row and column information in variables
  21573.    whose addresses we pass. What about the page variable? For now, use the
  21574.    default value of 0. The following SETCURS.C program (Listing 13-14) is a
  21575.    short example that uses Setcurs() to see if our programming is on the
  21576.    right track.
  21577.  
  21578.    After you type in a row and column in the form 10 20, the program places
  21579.    the cursor there and then prints a message starting at that location. It's
  21580.    not a spectacular program, but it shows that our function is working
  21581.    correctly. As we build this library with other functions, you might want
  21582.    to write similar test programs. With QuickC it doesn't take long to do.
  21583.  
  21584.    ──────────────────────────────────────────────────────────────────────────
  21585.    #include <dos.h>
  21586.    #define VIDEO 0x10
  21587.    #define SETCURSOR 2
  21588.    #define GETCURSOR 3
  21589.  
  21590.    /* Setcurs() -- sets cursor to given row, column */
  21591.    void Setcurs(row, col, page)
  21592.    unsigned char row, col, page;
  21593.    {
  21594.        union REGS reg;
  21595.  
  21596.        reg.h.ah = SETCURSOR;
  21597.        reg.h.dh = row;
  21598.        reg.h.dl = col;
  21599.        reg.h.bh = page;
  21600.        int86(VIDEO, ®, ®);
  21601.    }
  21602.  
  21603.    /* Getcurs() -- reports current cursor position */
  21604.    void Getcurs(pr, pc, page)
  21605.    unsigned char *pr, *pc, page;
  21606.    {
  21607.        union REGS reg;
  21608.  
  21609.        reg.h.ah = GETCURSOR;
  21610.        reg.h.bh = page;
  21611.        int86(VIDEO, ®, ®);
  21612.        *pr = reg.h.dh;  /* row number */
  21613.        *pc = reg.h.dl;   /* column number */
  21614.    }
  21615.    ──────────────────────────────────────────────────────────────────────────
  21616.  
  21617.    Listing 13-13.  The setcurs() function.
  21618.  
  21619.    ──────────────────────────────────────────────────────────────────────────
  21620.    /* setcurs.c -- moves cursor, checks out Setcurs() */
  21621.    #include <dos.h>
  21622.    #include <stdio.h>
  21623.    #define VIDEO 0x10
  21624.    #define SETCURSOR 2
  21625.    void Setcurs(unsigned char, unsigned char,
  21626.                 unsigned char);
  21627.    main()
  21628.    {
  21629.        int row, col;
  21630.  
  21631.        printf("Enter row and column: (q to quit)\n");
  21632.        while (scanf("%d %d", &row, &col) == 2)
  21633.        {
  21634.            Setcurs(row, col, 0);
  21635.            printf("Enter row and column: (q to quit)");
  21636.        }
  21637.    }
  21638.  
  21639.    /* Setcurs() -- sets cursor to row, column, and page */
  21640.    void Setcurs(row, col, page)
  21641.    unsigned char row, col, page;
  21642.    {
  21643.        union REGS reg;
  21644.  
  21645.        reg.h.ah = SETCURSOR;
  21646.        reg.h.dh = row;
  21647.        reg.h.dl = col;
  21648.        reg.h.bh = page;
  21649.        int86(VIDEO, ®, ®);
  21650.    }
  21651.    ──────────────────────────────────────────────────────────────────────────
  21652.  
  21653.    Listing 13-14.  The SETCURS.C program.
  21654.  
  21655.    Setting the page to 0 worked fine in our example; however, we may need to
  21656.    use pages later, so let's look at that topic.
  21657.  
  21658.    Getting and Setting the Page
  21659.  
  21660.    The information displayed on the screen is read from a dedicated section
  21661.    of memory called video memory. The amount of memory available depends upon
  21662.    the video adapter. In some modes, video memory can hold two or more
  21663.    screenfuls of data. In those cases, you can divide video memory into
  21664.    separate pages, one page per screenful. This lets a program alter one page
  21665.    in memory while displaying the other on the screen. To set a page, we will
  21666.    use the Setpage() function (Listing 13-15 on the following page).
  21667.  
  21668.    By default, screen modes start at page 0, and we'll also use that page for
  21669.    a while. But to keep our programming general, we need a function that can
  21670.    tell our code which is the current page. We use function 15 to develop the
  21671.    QuickC Getpage() function (Listing 13-16). The interrupt function places
  21672.    the page number in the BH register, and the function returns that value to
  21673.    the program.
  21674.  
  21675.    ──────────────────────────────────────────────────────────────────────────
  21676.    /* Setpage() -- sets page to given value */
  21677.    #include <dos.h>
  21678.    #define VIDEO 0x10
  21679.    #define SETPAGE 5
  21680.    void Setpage(page)
  21681.    unsigned char page;
  21682.    {
  21683.        union REGS reg;
  21684.  
  21685.        reg.h.ah = SETPAGE;
  21686.        reg.h.al = page;
  21687.        int86(VIDEO, ®, ®);
  21688.    }
  21689.    ──────────────────────────────────────────────────────────────────────────
  21690.  
  21691.    Listing 13-15.  The Setpage() function.
  21692.  
  21693.    ──────────────────────────────────────────────────────────────────────────
  21694.    /* Getpage() -- obtains the currently active page */
  21695.    #include <dos.h>
  21696.    #define VIDEO 0x10
  21697.    #define GETMODE 15
  21698.    unsigned char Getpage()
  21699.    {
  21700.        union REGS reg;
  21701.  
  21702.        reg.h.ah = GETMODE;
  21703.        int86(VIDEO, ®, ®);
  21704.        return reg.h.bh;
  21705.    }
  21706.    ──────────────────────────────────────────────────────────────────────────
  21707.  
  21708.    Listing 13-16.  The Getpage() function.
  21709.  
  21710.    Clearing the Screen
  21711.  
  21712.    Another useful function is one that clears the screen. None of the
  21713.    interrupt functions specialize in that, but the Scroll Up function
  21714.    (function 6) can perform this task. Note in Table 13-6 that if register
  21715.    AL is set to zero, the entire designated area is cleared. However, several
  21716.    other registers also must be set. You define the area to be cleared by
  21717.    giving the coordinates of the upper-left and the lower-right corners.
  21718.  
  21719.    The BIOS routine starts numbering with 0, unlike ANSI.SYS, which starts
  21720.    with 1. This means the upper-left row and column are 0, the lower-right
  21721.    row is 24, and the lower-right column is 79. (We assume you're using an
  21722.    80-by-25 display.) The least straightforward register setting is the
  21723.    attribute setting for blank lines in register BH. An attribute is a value
  21724.    in the range 0 through 255 that modifies the display. The normal attribute
  21725.    is 7 for a "white-on-black" display. ("White" is white on a color display,
  21726.    but on a monochrome monitor "white" usually is green or amber.) Other
  21727.    values produce reverse video, blinking, underlining (on some monitors),
  21728.    and colors (on some monitors). We'll use the value 7.
  21729.  
  21730.    We use these register values to construct the following Clearscr()
  21731.    function (Listing 13-17).
  21732.  
  21733.    ──────────────────────────────────────────────────────────────────────────
  21734.    /*  Clearscr() -- clears the screen          */
  21735.    #include <dos.h>
  21736.    #define VIDEO 0x10
  21737.    #define SCROLLUP 6
  21738.    #define ROWS 25
  21739.    #define COLS 80
  21740.    void Clearscr()
  21741.    {
  21742.        union REGS reg;
  21743.  
  21744.        reg.h.ah = SCROLLUP;
  21745.        reg.h.al = 0;       /* clear the window */
  21746.        reg.h.ch = 0;
  21747.        reg.h.cl = 0;
  21748.        reg.h.dh = ROWS - 1;
  21749.        reg.h.dl = COLS - 1;
  21750.        reg.h.bh = NORMAL;
  21751.        int86(VIDEO, ®, ®);
  21752.    }
  21753.    ──────────────────────────────────────────────────────────────────────────
  21754.  
  21755.    Listing 13-17.  The Clearscr() function.
  21756.  
  21757.    Reading and Writing Characters and Attributes
  21758.  
  21759.    Before we use BIOS routines to read from and write to the screen, you need
  21760.    to know how the video system works. The video adapter has its own memory,
  21761.    which it uses to represent the screen. Let's concentrate for now on the
  21762.    80-by-25 text modes, the ones you probably use most often. All standard
  21763.    IBM video controllers (Monochrome, CGA, EGA, MCGA, and VGA) use the same
  21764.    scheme for their 80-by-25 text modes, so this discussion applies to all.
  21765.  
  21766.    ──────────────────────────────────────────────────────────────────────────
  21767.    Quick Tip
  21768.    If you are ambitious, you can generalize this function to work with
  21769.    40-by-25 displays by using function 15 of the 0x10 interrupt to find the
  21770.    number of columns actually being used. A call to function 15 places that
  21771.    number of columns into the AH register. Subtract 1 from this number (to
  21772.    account for the fact that column numbering begins with column 0), save the
  21773.    result, and assign it to the DL register before you call function 6.
  21774.    ──────────────────────────────────────────────────────────────────────────
  21775.  
  21776.    You can think of an 80-by-25 screen as holding 2000 cells, each capable of
  21777.    displaying a character. Each cell is represented by two bytes in the video
  21778.    memory. One byte holds the code for the character, and the second byte
  21779.    holds the attribute, which determines how the character is displayed. When
  21780.    a program sends output to the screen, the characters actually are first
  21781.    stored in video memory. A microprocessor called a video controller then
  21782.    scans the video memory, mapping the characters it finds there to the
  21783.    screen. Video interrupt 0x10 functions 8 and 9, which read and write
  21784.    characters and attributes to the screen, actually work with the video
  21785.    memory. (The monochrome display system uses a different memory address
  21786.    from the others, but the BIOS calls adjust for that.)
  21787.  
  21788.    The character code consists of the usual ASCII code plus extensions to the
  21789.    code that enable certain non-ASCII characters to be displayed on the
  21790.    screen. (IBM provides 128 such additional characters in its extended
  21791.    character set.) The attribute code also is simple, especially for
  21792.    black-and-white displays. Think of the attribute byte as a series of eight
  21793.    bits, numbers 7 to 0, left to right. To generate the normal
  21794.    black-and-white display, set the bits to 00000111. To produce reverse
  21795.    video, set the bits to 01110000. Note that these binary values translate
  21796.    to 0x7 and 0x70, respectively.
  21797.  
  21798.    In addition, you can intensify the foreground display by setting bit 3 to
  21799.    1 or put the display in "blink" mode by setting bit 7 to 1. The attributes
  21800.    we've discussed here produce white-on-black (or black-on-white) characters
  21801.    for the monochrome display and for color-text displays. We discuss
  21802.    color-related attributes in Chapter 14.
  21803.  
  21804.    To produce both normal and reverse video, our program must write the
  21805.    attribute as well as the character. We use video I/O function 9 instead of
  21806.    putch(), because the latter writes only characters, not attributes. Our
  21807.    Write_ch_atr() C function (Listing 13-18) uses that interrupt routine.
  21808.    This function writes the character-attribute pair num times to display a
  21809.    single pair several times in a row. We will use a num value of 1, but to
  21810.    preserve generality, we did not build that value into the function.
  21811.  
  21812.    One of our program goals was converting normal text to reverse video by
  21813.    passing the cursor over it. You can do that simply by changing the
  21814.    attribute at the cursor location. Because no BIOS function merely changes
  21815.    an attribute, we need to write a character-attribute pair. One way to do
  21816.    this is to read the current character from the screen and to then rewrite
  21817.    it using a different attribute. So let's start by devising a Read_ch_atr()
  21818.    (Listing 13-19) function to read the character and attribute at the
  21819.    current cursor location.
  21820.  
  21821.    Because the function must return two values, we pass it the addresses of
  21822.    the two variables to which the values will be assigned. To read the
  21823.    character and attribute at the current cursor position on page 0 into the
  21824.    variables ch and attr, make this call:
  21825.  
  21826.      Read_ch_atr(&ch, &attr, 0);
  21827.  
  21828.    We also could have the function return a two-member structure.
  21829.  
  21830.    ──────────────────────────────────────────────────────────────────────────
  21831.    /* Write_ch_atr() -- writes characters and attributes */
  21832.    #include <dos.h>
  21833.    #define VIDEO 0x10
  21834.    #define WRITECHATR 9
  21835.    void Write_ch_atr(ch, atr, page, num)
  21836.    unsigned char ch, atr, page;
  21837.    unsigned int num;
  21838.    {
  21839.        union REGS reg;
  21840.  
  21841.        reg.h.ah = WRITECHATR;
  21842.        reg.h.al = ch;
  21843.        reg.h.bl = atr;
  21844.        reg.h.bh = page;
  21845.        reg.x.cx = num;
  21846.        int86(VIDEO, ®, ®);
  21847.    }
  21848.    ──────────────────────────────────────────────────────────────────────────
  21849.  
  21850.    Listing 13-18.  The Write_ch_atr() function.
  21851.  
  21852.    Now we use the last two functions to produce the function our program
  21853.    requires. The Rewrite() function (Listing 13-20 on the following page)
  21854.    reads the current character and rewrites it with a potentially changed
  21855.    attribute.
  21856.  
  21857.    If speed is an issue, which it usually isn't for keyboard input, you can
  21858.    speed up Rewrite() by having it use int86() to call the read and write
  21859.    BIOS functions directly instead of going through Read_ch_atr() and
  21860.    Write_ch_atr().
  21861.  
  21862.    ──────────────────────────────────────────────────────────────────────────
  21863.    /* Read_ch_atr() -- reads character and attribute at     */
  21864.    /*                  cursor location                      */
  21865.    #include <dos.h>
  21866.    #define VIDEO 0x10
  21867.    #define  READCHATR 8
  21868.    void Read_ch_atr(pc, pa, page)
  21869.    unsigned char *pc, *pa;
  21870.    unsigned char page;
  21871.    {
  21872.        union REGS reg;
  21873.  
  21874.        reg.h.ah = READCHATR;
  21875.        reg.h.bh = page;
  21876.        int86(VIDEO, ®, ®);
  21877.        *pc = reg.h.al;  /* character at cursor */
  21878.        *pa = reg.h.ah;  /* attribute at cursor */
  21879.    }
  21880.    ──────────────────────────────────────────────────────────────────────────
  21881.  
  21882.    Listing 13-19.  The Read_ch_atr() function.
  21883.  
  21884.    ──────────────────────────────────────────────────────────────────────────
  21885.    /* Rewrite() -- changes attribute of on-screen  */
  21886.                    character                       */
  21887.    void Read_ch_atr(), Write_ch_atr(); /* used by  */
  21888.                                        /* Rewrite()*/
  21889.    void Rewrite(at, page)
  21890.    unsigned char at, page;
  21891.    {
  21892.        unsigned char ch, atr;
  21893.  
  21894.        Read_ch_atr(&ch, &atr, page);
  21895.        Write_ch_atr(ch, at, page, 1);
  21896.    }
  21897.    ──────────────────────────────────────────────────────────────────────────
  21898.  
  21899.    Listing 13-20.  The Rewrite() function.
  21900.  
  21901.    More Cursor Movement
  21902.  
  21903.    We already have a function to set the cursor at a given row or column. But
  21904.    our primitive text editor really needs functions to move the cursor one
  21905.    column to the right when the Right Arrow key is pushed, and so on. We can
  21906.    use Setcurs() to create such functions. The Cursrt_lim() function (Listing
  21907.    13-21) demonstrates how to construct a right-movement function.
  21908.  
  21909.    Getcurs() and Setcurs() require the current page number; the Cursrt_lim()
  21910.    function uses Getpage() to obtain that information. Also, the function
  21911.    prevents the cursor from going past the column defined by limit. Our
  21912.    program will use a limit of 79, corresponding to the right side of the
  21913.    screen, but the numeric value is not built into the function. This
  21914.    variable limit lets you use the function with a program that confines the
  21915.    cursor to a section of the screen or with one that uses a 40-column
  21916.    screen.
  21917.  
  21918.    ──────────────────────────────────────────────────────────────────────────
  21919.    /* Cursrt_lim() -- moves cursor one space to the       */
  21920.                       right, but not past a set limit     */
  21921.    void Getcurs(), Setcurs();  /* functions used   */
  21922.    unsigned char Getpage();    /* by this function */
  21923.  
  21924.    unsigned char Cursrt_lim(limit)
  21925.    unsigned char limit;
  21926.    {
  21927.        unsigned char row, col, page;
  21928.        unsigned char status = 1;
  21929.  
  21930.        Getcurs(&row, &col, page = Getpage());
  21931.        if (col < limit)
  21932.            Setcurs(row, col + 1, page);
  21933.        else
  21934.            status = 0;
  21935.        return status;
  21936.    }
  21937.    ──────────────────────────────────────────────────────────────────────────
  21938.  
  21939.    Listing 13-21.  The Cursrt_lim() function.
  21940.  
  21941.    Also, the program uses a return value to inform the calling program
  21942.    whether the cursor reached its limit. This gives the calling program the
  21943.    option of responding in some way, such as beeping or moving the cursor to
  21944.    the beginning of the next line, whenever the limit is reached.
  21945.  
  21946.    We can modify Cursrt_lim() to create functions corresponding to the other
  21947.    arrow keys. We'll show you these when we gather all the functions together
  21948.    into one file.
  21949.  
  21950.    Putting the Library Together
  21951.  
  21952.    By now we've created a small library of short, BIOS-based C functions.
  21953.    Before we use them in our intended sample program, let's reflect on how to
  21954.    organize this block of functions. One method is to give each its own file.
  21955.    Then, when we want to use a particular function in a program, we can add
  21956.    its filename to the QuickC programming list. Or we can simply append the
  21957.    function file to the program file. Another approach is to consolidate all
  21958.    the functions into one file and to add that file to the program list. This
  21959.    is more convenient, but it might result in adding code to your program for
  21960.    functions it doesn't use. If you use the functions frequently, the most
  21961.    satisfactory approach is to make a library file for them. (This procedure
  21962.    was described in Chapter 12.)
  21963.  
  21964.    Here's one way to make the library. Open the SCRFUN.C file from QuickC.
  21965.    Choose Compile from the Run menu and specify the Obj option. Then choose
  21966.    Compile File to produce a file called SCRFUN.OBJ. Now go to MS-DOS and
  21967.    enter the LIB command. Answer the prompts as shown:
  21968.  
  21969.      Library name: scrfun
  21970.      Library does not exist: create? y
  21971.      Operations: +scrfun
  21972.      List file: scrfun
  21973.  
  21974.    The LIB command creates a library file called SCRFUN.LIB in the current
  21975.    directory. You can then copy it to your library directory. The LIB command
  21976.    also creates a text file called SCRFUN that lists the names of the
  21977.    functions in the library.
  21978.  
  21979.    To help organize these functions, gather all the defined constants
  21980.    together into an include file. To this file, add function prototypes for
  21981.    all the functions. Then you can use this include file with your program.
  21982.    You still must incorporate the actual code by appending the source files
  21983.    or adding files to the program list or by using a library, but using the
  21984.    include file saves you the trouble of having to declare the functions. It
  21985.    also includes definitions useful to a program. We'll use the scrn.h
  21986.    include file (Listing 13-22 on the following page) for our programs.
  21987.  
  21988.    ──────────────────────────────────────────────────────────────────────────
  21989.    /* scrn.h -- header file for BIOS video I/O functions */
  21990.    /*           contained in scrfun.c and scrfun.lib     */
  21991.    #define VIDEO 0x10
  21992.    #define SETMODE 0
  21993.    #define SETCURSOR 2
  21994.    #define GETCURSOR 3
  21995.    #define SETPAGE 5
  21996.    #define SCROLL 6
  21997.    #define READCHATR 8
  21998.    #define WRITECHATR 9
  21999.    #define GETMODE 15
  22000.    #define NORMAL 0x7
  22001.    #define VIDREV 0x70
  22002.    #define INTENSE 0x8
  22003.    #define BLINK 0x80
  22004.    #define COLS 80
  22005.    #define ROWS 25
  22006.    #define TEXTBW80 2
  22007.    #define TEXTC80 3
  22008.    #define TEXTMONO 7
  22009.  
  22010.    void Clearscr(void),
  22011.         Setvmode(unsigned char),
  22012.         Setpage(unsigned char),
  22013.         Setcurs(unsigned char, unsigned char,
  22014.                 unsigned char),
  22015.         Read_ch_atr(unsigned char *, unsigned char *,
  22016.                     unsigned char),
  22017.         Write_ch_atr(unsigned char, unsigned char,
  22018.                      unsigned char, unsigned int),
  22019.         Rewrite(unsigned char, unsigned char),
  22020.         Getcurs(unsigned char *, unsigned char *,
  22021.                 unsigned char);
  22022.  
  22023.    unsigned char Getvmode(void),
  22024.                  Getpage(void),
  22025.                  Curslt_lim(unsigned char),
  22026.                  Cursrt_lim(unsigned char),
  22027.                  Cursup_lim(unsigned char),
  22028.                  Cursdn_lim(unsigned char);
  22029.  
  22030.    /* macro definitions */
  22031.  
  22032.    #define Home()        Setcurs(0, 0, Getpage())
  22033.    /* the next four macros set cursor limits to the      */
  22034.    /* full screen                                        */
  22035.    #define Curslt()      Curslt_lim(0)
  22036.    #define Cursrt()      Cursrt_lim(COLS - 1)
  22037.    #define Cursdn()      Cursdn_lim(ROWS - 1)
  22038.    #define Cursup()      Cursup_lim(0)
  22039.    ──────────────────────────────────────────────────────────────────────────
  22040.  
  22041.    Listing 13-22.  The scrn.h include file.
  22042.  
  22043.    The scrn.h file includes some function numbers that we won't use until
  22044.    later chapters. It also has some constants that we'll use in our program.
  22045.    Finally, note the macros at the end of the file. The Home() macro homes
  22046.    the cursor, and the cursor-movement macros select a range corresponding to
  22047.    the entire screen.
  22048.  
  22049.    For convenience, we've collected all the new functions together as shown
  22050.    in Figure 13-6 in a file called SCRFUN.C (Listing 13-23). We discuss the
  22051.    Getvmode() and Setvmode() functions in Chapter 15.
  22052.  
  22053.                                     ┌───────────────────┐
  22054.                        ┌─────┐      │                   │
  22055.              Setcurs() │     ├──────┼───────────        │
  22056.                        └─────┘      │                   │
  22057.                  ┌─────┐            │                   │
  22058.        Getcurs() │     ├────────────┼─────              │
  22059.                  └─────┘            │                   │
  22060.                        ┌─────┐      │                   │
  22061.             Setpage()  │     ├──────┼───────────        │
  22062.                        └─────┘      │                   │
  22063.                  ┌─────┐            │                   │
  22064.       Setvmode() │     ├────────────┼─────              │
  22065.                  └─────┘            │                   │
  22066.                        ┌─────┐      │                   │
  22067.             Clearscr() │     ├──────┼───────────        │
  22068.                        └─────┘      │                   │
  22069.                  ┌─────┐            │                   │
  22070.    Read_ch_atr() │     ├────────────┼─────              │
  22071.                  └─────┘            │                   │
  22072.                        ┌─────┐      │                   │
  22073.         Write_ch_atr() │     ├──────┼───────────        │
  22074.                        └─────┘      │                   │
  22075.                  ┌─────┐            │                   │
  22076.        Rewrite() │     ├────────────┼─────              │
  22077.                  └─────┘            │                   │
  22078.                        ┌─────┐      │                   │
  22079.             Getvmode() │     ├──────┼───────────        │
  22080.                        └─────┘      │                   │
  22081.                  ┌─────┐            │                   │
  22082.       Getpage()  │     ├────────────┼─────              │
  22083.                  └─────┘            │                   │
  22084.                        ┌─────┐      │                   │
  22085.           Curslt_lim() │     ├──────┼───────────        │
  22086.                        └─────┘      │                   │
  22087.                  ┌─────┐            │                   │
  22088.      Curst_lim() │     ├────────────┼─────              │
  22089.                  └─────┘            │                   │
  22090.                        ┌─────┐      │                   │
  22091.           Cursup_lim() │     ├──────┼───────────        │
  22092.                        └─────┘      │                   │
  22093.                  ┌─────┐            │                   │
  22094.     Cursdn_lim() │     ├────────────┼─────              │
  22095.                  └─────┘            │                   │
  22096.                                     └───────────────────┘
  22097.                                           SCRFUN.C
  22098.  
  22099.    Figure 13-6. The SCRFUN.C program combines the functions we created
  22100.    previously.
  22101.  
  22102.    ──────────────────────────────────────────────────────────────────────────
  22103.    /*  scrfun.c -- contains several video BIOS calls     */
  22104.    /*  Setcurs() sets the cursor position                */
  22105.    /*  Getcurs() gets the cursor position                */
  22106.    /*  Setpage() sets the current video page             */
  22107.    /*  Setvmode() sets the video mode                    */
  22108.    /*  Clearscr() clears the screen                      */
  22109.    /*  Read_ch_atr() reads the character and             */
  22110.    /*                attribute at the cursor             */
  22111.    /*  Write_ch_atr() writes a character and             */
  22112.    /*                 attribute at the cursor            */
  22113.    /*  Rewrite() rewrites a screen character             */
  22114.    /*            with a new attribute                    */
  22115.    /*  Getvmode() gets the current video mode            */
  22116.    /*  Getpage() gets the current video page             */
  22117.    /*                                                    */
  22118.    /*  The following functions use Setcurs() to move the */
  22119.    /*  cursor one position at a time up to a limit.      */
  22120.    /*  Curslt_lim() moves cursor one column left         */
  22121.    /*  Cursrt_lim() moves cursor one column right        */
  22122.    /*  Cursup_lim() moves cursor one line up             */
  22123.    /*  Cursdn_lim() moves cursor one line down           */
  22124.    /*                                                    */
  22125.    /*  Programs using these functions should include the */
  22126.    /*  scrn.h file                                       */
  22127.  
  22128.    #include <dos.h>
  22129.    #include "scrn.h"
  22130.  
  22131.    /* sets cursor to row, column, and page */
  22132.    void Setcurs(row, col, page)
  22133.    unsigned char row, col, page;
  22134.    {
  22135.        union REGS reg;
  22136.  
  22137.        reg.h.ah = SETCURSOR;
  22138.        reg.h.dh = row;
  22139.        reg.h.dl = col;
  22140.        reg.h.bh = page;
  22141.        int86(VIDEO, ®, ®);
  22142.    }
  22143.  
  22144.    /* gets current cursor row, column for given page */
  22145.    void Getcurs(pr, pc, page)
  22146.    unsigned char *pr, *pc, page;
  22147.    {
  22148.        union REGS reg;
  22149.  
  22150.        reg.h.ah = GETCURSOR;
  22151.        reg.h.bh = page;
  22152.        int86(VIDEO, ®, ®);
  22153.        *pr = reg.h.dh;  /* row number */
  22154.        *pc = reg.h.dl;   /* column number */
  22155.    }
  22156.  
  22157.    /* sets page to given value */
  22158.    void Setpage(page)
  22159.    unsigned char page;
  22160.    {
  22161.        union REGS reg;
  22162.  
  22163.        reg.h.ah = SETPAGE;
  22164.        reg.h.al = page;
  22165.        int86(VIDEO, ®, ®);
  22166.    }
  22167.  
  22168.    /* sets video mode to given mode */
  22169.    void Setvmode(mode)
  22170.    unsigned char mode;
  22171.    {
  22172.        union REGS reg;
  22173.  
  22174.        reg.h.ah = SETMODE;
  22175.        reg.h.al = mode;
  22176.        int86(VIDEO, ®, ®);
  22177.    }
  22178.  
  22179.    /* clear the screen */
  22180.    void Clearscr()
  22181.    {
  22182.        union REGS reg;
  22183.  
  22184.        reg.h.ah = SCROLL;
  22185.        reg.h.al = 0;
  22186.        reg.h.ch = 0;
  22187.        reg.h.cl = 0;
  22188.        reg.h.dh = ROWS - 1;
  22189.        reg.h.dl = COLS - 1;
  22190.        reg.h.bh = NORMAL;
  22191.        int86(VIDEO, ®, ®);
  22192.    }
  22193.  
  22194.    /* reads the character and attribute at the cursor */
  22195.    /* position on a given page                        */
  22196.    void Read_ch_atr(pc, pa, page)
  22197.    unsigned char *pc, *pa;
  22198.    unsigned char page;
  22199.    {
  22200.        union REGS reg;
  22201.  
  22202.        reg.h.ah = READCHATR;
  22203.        reg.h.bh = page;
  22204.        int86(VIDEO, ®, ®);
  22205.        *pc = reg.h.al;  /* character at cursor */
  22206.        *pa = reg.h.ah;  /* attribute at cursor */
  22207.    }
  22208.  
  22209.    /* writes a given character and attribute at the */
  22210.    /* cursor on a given page for num times          */
  22211.    void Write_ch_atr(ch, atr, page, num)
  22212.    unsigned char ch, atr, page;
  22213.    unsigned int num;
  22214.    {
  22215.        union REGS reg;
  22216.  
  22217.        reg.h.ah = WRITECHATR;
  22218.        reg.h.al = ch;
  22219.        reg.h.bl = atr;
  22220.        reg.h.bh = page;
  22221.        reg.x.cx = num;
  22222.        int86(VIDEO, ®, ®);
  22223.    }
  22224.  
  22225.    /* rewrites the character at the cursor using    */
  22226.    /* attribute at                                  */
  22227.    void Rewrite(at, page)
  22228.    unsigned char at, page;
  22229.    {
  22230.        unsigned char ch, atr;
  22231.  
  22232.        Read_ch_atr(&ch, &atr, page);
  22233.        Write_ch_atr(ch, at, page, 1);
  22234.    }
  22235.  
  22236.  
  22237.    /* obtains the current video mode */
  22238.    unsigned char Getvmode()
  22239.    {
  22240.        union REGS reg;
  22241.  
  22242.        reg.h.ah = GETMODE;
  22243.        int86(VIDEO, ®, ®);
  22244.        return reg.h.al;
  22245.    }
  22246.  
  22247.    /* obtains the current video page */
  22248.    unsigned char Getpage()
  22249.    {
  22250.        union REGS reg;
  22251.  
  22252.        reg.h.ah = GETMODE;
  22253.        int86(VIDEO, ®, ®);
  22254.        return reg.h.bh;
  22255.    }
  22256.  
  22257.    /* moves cursor one column left, but not past */
  22258.    /* the given limit                            */
  22259.    unsigned char Curslt_lim(limit)
  22260.    unsigned char limit;
  22261.    {
  22262.        unsigned char row, col, page;
  22263.        unsigned char status = 1;
  22264.        Getcurs(&row, &col, page = Getpage());
  22265.        if (col > limit)
  22266.            Setcurs(row, col - 1, page);
  22267.        else
  22268.            status = 0;
  22269.        return status;
  22270.    }
  22271.  
  22272.    /* moves cursor one column right, but not past */
  22273.    /* the given limit                             */
  22274.    unsigned char Cursrt_lim(limit)
  22275.    unsigned char limit;
  22276.    {
  22277.        unsigned char row, col, page;
  22278.        unsigned char status = 1;
  22279.  
  22280.        Getcurs(&row, &col, page = Getpage());
  22281.        if (col < limit)
  22282.            Setcurs(row, col + 1, page);
  22283.        else
  22284.            status = 0;
  22285.        return status;
  22286.    }
  22287.  
  22288.    /* moves cursor one row down, but not past */
  22289.    /* the given limit                         */
  22290.    unsigned char Cursup_lim(limit)
  22291.    unsigned char limit;
  22292.    {
  22293.        unsigned char row, col, page;
  22294.        unsigned char status = 1;
  22295.  
  22296.        Getcurs(&row, &col, page = Getpage());
  22297.        if (row > limit)
  22298.            Setcurs(row - 1, col, page);
  22299.        else
  22300.            status = 0;
  22301.        return status;
  22302.    }
  22303.  
  22304.    /* moves cursor one row down, but not past */
  22305.    /* the given limit                         */
  22306.    unsigned char Cursdn_lim(limit)
  22307.    unsigned char limit;
  22308.    {
  22309.        unsigned char row, col, page;
  22310.        unsigned char status = 1;
  22311.  
  22312.        Getcurs(&row, &col, page = Getpage());
  22313.        if (row < limit)
  22314.            Setcurs(row + 1, col, page);
  22315.        else
  22316.            status = 0;
  22317.        return status;
  22318.    }
  22319.    ──────────────────────────────────────────────────────────────────────────
  22320.  
  22321.    Listing 13-23.  The SCRFUN.C program.
  22322.  
  22323.    Our small routines certainly create a big file! However, you need only
  22324.    compile it once. After that, you can use the .OBJ or .LIB versions. We
  22325.    assume that you create a library file called SCRFUN.LIB.
  22326.  
  22327.  A Text Program
  22328.  
  22329.    Finally, after much development, we have at hand all the tools we need for
  22330.    our program. The ROAMSCRN.C program (Listing 13-24) shows the results of
  22331.    our efforts. To run the program within the QuickC environment, be sure
  22332.    that Screen Swapping On is active.
  22333.  
  22334.    ──────────────────────────────────────────────────────────────────────────
  22335.    /*   roamscrn.c  -- puts text on screen, positions    */
  22336.    /*                  cursor with arrow keys, uses F1   */
  22337.    /*                  and F2 to control video inverse   */
  22338.    /*   program list -- roamscrn.c, scrfun.lib           */
  22339.    /*   user include files -- keys.h, scrn.h             */
  22340.    /*  Note: Activate Screen Swapping On in Debug menu   */
  22341.    #include <conio.h>
  22342.    #include "keys.h"
  22343.    #include "scrn.h"
  22344.    #define BELL '\a'
  22345.    #define ESC '\033'
  22346.    #define PAGE 0
  22347.  
  22348.    char *Heading =
  22349.    "Use standard keys to enter text. Use arrow keys to "
  22350.    "reposition cursor.\nUse F2 to turn on video inverse "
  22351.    "and F1 to turn it off.\nHit the ESC key to quit.\n";
  22352.  
  22353.    main()
  22354.    {
  22355.        int ch;
  22356.        unsigned char atr = NORMAL;
  22357.  
  22358.        Clearscr();
  22359.        Home();
  22360.        printf("%s", Heading);
  22361.        while ((ch = getch()) != ESC)
  22362.            {
  22363.            if (ch == '\r')
  22364.                {
  22365.                putch('\n');
  22366.                putch('\r');
  22367.                }
  22368.            else if (ch != 0)
  22369.                {
  22370.                Write_ch_atr(ch, atr, PAGE, 1);
  22371.                if (!Cursrt())
  22372.                    putch(BELL);
  22373.                }
  22374.            else
  22375.                {
  22376.                ch = getch();
  22377.                switch (ch)
  22378.                    {
  22379.                    case F1 : atr = NORMAL; break;
  22380.                    case F2 : atr = VIDREV; break;
  22381.                    case UP : Rewrite(atr, PAGE);
  22382.                        if (!Cursup())
  22383.                            putch(BELL);
  22384.                        break;
  22385.                    case DN : Rewrite(atr, PAGE);
  22386.                        if (!Cursdn())
  22387.                            putch(BELL);
  22388.                        break;
  22389.                    case LT : Rewrite(atr, PAGE);
  22390.                        if (!Curslt())
  22391.                            putch(BELL);
  22392.                        break;
  22393.                    case RT : Rewrite(atr, PAGE);
  22394.                        if (!Cursrt())
  22395.                            putch(BELL);
  22396.                        break;
  22397.                    default : break;
  22398.                    }
  22399.                }
  22400.            }
  22401.    }
  22402.    ──────────────────────────────────────────────────────────────────────────
  22403.  
  22404.    Listing 13-24.  The ROAMSCRN.C program.
  22405.  
  22406.    Let's see how it works. The keys.h include file is the one we used earlier
  22407.    in this chapter; it defines the mnemonics for the function keys and the
  22408.    cursor control keys. The scrn.h include file is the one we just presented.
  22409.    We assume that you bring in the BIOS code by including the SCRFUN.LIB file
  22410.    in the program list, but you can also use one of the other methods we
  22411.    mentioned if you prefer.
  22412.  
  22413.    The program begins with the attribute variable atr set to NORMAL. This is
  22414.    defined in scrn.h as 7, which is the normal attribute for white-on-black
  22415.    text. Next, the program clears the screen, homes the cursor, and prints an
  22416.    instructive heading. Finally, in the main part of the program, a large
  22417.    while loop uses getch() to read keyboard input until Esc is pressed to
  22418.    terminate input.
  22419.  
  22420.    Next, the program inspects ch, the input character typed by the user. If
  22421.    it is \r, the carriage return character generated by the Enter key, the
  22422.    program translates that into a newline, that is, into \n\r. If the
  22423.    character is some other ASCII or extended ASCII value, the program uses
  22424.    Write_ch_atr() to display that character. Why not use putch() here?
  22425.    Because putch() has no provision for specifying the attribute. Note, too,
  22426.    the following code fragment:
  22427.  
  22428.      if (!Cursrt())
  22429.          putch(BELL);
  22430.  
  22431.    Write_ch_atr(), like the BIOS call it uses, does not advance the cursor
  22432.    after writing the character. Therefore, we use Cursrt() to move the
  22433.    cursor. Recall that we created Cursrt_lim() to stop when it reaches the
  22434.    right side of the screen and that the macro Cursrt() uses the rightmost
  22435.    column as the limit. If the limit is reached, Cursrt() returns a value of
  22436.    0, or false, causing the if statement to execute the putch(BELL) call. The
  22437.    action, then, is as follows: First the character is printed, then the
  22438.    program attempts to advance the cursor one column to the right. If it can,
  22439.    fine; otherwise, the system beeps. If you like, you can replace the
  22440.    beeping instructions with a Setcurs() command to relocate the cursor at
  22441.    the beginning of the next line.
  22442.  
  22443.    Finally, this sequence of if-else lines processes the case of ch being 0.
  22444.    This means the user entered a non-ASCII character. Another getch() call
  22445.    fetches the scan code for the key, and a switch checks for two of the
  22446.    function keys and for the arrow keys. Let's see what these keys do.
  22447.  
  22448.    If the user presses F1, the attribute variable atr is set to NORMAL; if
  22449.    the user presses F2, atr is set to VIDREV. This constant, defined in
  22450.    scrn.h as 0x70, is the reverse video attribute. The selected value for the
  22451.    variable atr is used in subsequent calls to Write_ch_atr() and Rewrite().
  22452.    The attribute setting holds until another is selected.
  22453.  
  22454.    Next, look at what happens when the Up Arrow key is pressed:
  22455.  
  22456.      case UP : Rewrite(atr, PAGE);
  22457.          if (!Cursup())
  22458.              putch(BELL);
  22459.          break;
  22460.  
  22461.    The Rewrite() function reads the character, if any, at the current cursor
  22462.    position and rewrites it using the current attribute. Then the cursor is
  22463.    moved up a line unless it already is at the top line. In that case, the
  22464.    system beeps. The purpose of the Rewrite() statement is to cause existing
  22465.    text to be replaced by text using the current attribute. For example, if
  22466.    you have selected the inverse attribute, then text passed over by the
  22467.    cursor is rewritten with that attribute. The coding for the other arrow
  22468.    keys is similar.
  22469.  
  22470.    All in all, the main program is fairly simple. Most of the work involved
  22471.    creating C functions to implement the various BIOS calls we needed to
  22472.    make.
  22473.  
  22474.  
  22475.  
  22476.  ────────────────────────────────────────────────────────────────────────────
  22477.  Chapter 14  Monitors and Text Modes
  22478.  
  22479.    Professional application programs, including QuickC itself, use a much
  22480.    fancier screen interface than we have used in our programs. In this
  22481.    chapter we produce some of those screen features in QuickC. First we must
  22482.    overcome the problem posed by the variety of different display systems.
  22483.    IBM supports several monitor-video controller systems: monochrome, CGA,
  22484.    EGA, MCGA, and VGA. In general, these systems use different hardware, and
  22485.    different memory and port addresses. They also provide different colors,
  22486.    resolutions, and graphics capabilities.
  22487.  
  22488.    Writing programs that run on a range of video controller systems can be
  22489.    troublesome, especially if you want something fancier or faster than the
  22490.    teletype-like output produced by standard C Library functions. This
  22491.    chapter concentrates on solving these problems for text-mode programs. We
  22492.    continue using BIOS calls, and we introduce direct memory access and
  22493.    ports. We also look at the IBM "graphics character" set, which lets you
  22494.    create screen graphics without leaving text mode.
  22495.  
  22496.  
  22497.  Monitors and Controllers
  22498.  
  22499.    IBM has developed several different video standards, each involving its
  22500.    own hardware video controller and corresponding monitors. In the PC
  22501.    series, the hardware controllers are on add-on cards called "adapters." In
  22502.    the new PS/2 series, however, the circuitry for controlling the monitor is
  22503.    built into the motherboard. We use the term "video controller" in this
  22504.    book to encompass both the adapter cards and the built-in control
  22505.    circuitry.
  22506.  
  22507.    The most widely used video controller is the Monochrome Display Adapter,
  22508.    or MDA. When coupled with a monitor called the Monochrome Display, it
  22509.    produces a high-resolution, text-only display consisting of 25 rows of 80
  22510.    characters each.
  22511.  
  22512.    The next most commonly used controller is the Color Graphics Adapter, or
  22513.    CGA. It can be used with color or B/W monitors capable of either 40-by-25
  22514.    or 80-by-25 text displays (but not the Monochrome Display). It has seven
  22515.    separate modes of operation. Although the 80-by-25 display shows as many
  22516.    characters as the Monochrome Display, its lower resolution creates coarser
  22517.    text characters.
  22518.  
  22519.    Recently, the Enhanced Graphics Adapter, or EGA, has become popular. It is
  22520.    compatible with the Monochrome Display, with normal CGA displays, and with
  22521.    a high-resolution monitor called the Enhanced Display (ED). Used with a
  22522.    Monochrome Display, it provides a graphics mode in addition to the text
  22523.    mode. Used with CGA-style monitors, it provides more colors than the CGA
  22524.    board does. Used with the Enhanced Display (or equivalent), it emulates
  22525.    the CGA modes with increased text resolution, and it provides three
  22526.    additional graphics modes.
  22527.  
  22528.    The newest controllers are the Multi-Color Graphics Array (MCGA), found on
  22529.    the PS/2 Model 30, and the Video Graphics Array (VGA), found on the PS/2
  22530.    Models 50, 60, 70, and 80. The MCGA matches CGA resolution but offers an
  22531.    enormously greater range of colors. The VGA emulates the EGA modes, adds
  22532.    three new graphics modes, offers higher resolution for all text modes, and
  22533.    provides more colors.
  22534.  
  22535.    Table 14-1 summarizes some of the differences in features offered by the
  22536.    various video controllers we have introduced. Resolution is given in
  22537.    pixels, or picture elements, the elementary display elements from which
  22538.    characters and images are built. The size of a pixel depends on the
  22539.    controller and the mode. A pixel in mode 0, for example, is twice as wide
  22540.    as a pixel in mode 2. However, the VGA controller produces smaller pixels
  22541.    than the CGA controller, even when both are in mode 0. Also, not all
  22542.    monitors have sufficient resolution to support a controller's use of
  22543.    pixels. A CGA monitor, for example, is physically incapable of generating
  22544.    the higher resolution (smaller pixel) modes of the EGA and VGA. In
  22545.    general, all modes cannot produce the maximum number of colors, and only a
  22546.    subset of available colors can be shown at any one time.
  22547.  
  22548.    Table 14-1 Video Controllers
  22549.    Name    Horizontal       Vertical        Colors  Modes    Monitors
  22550.            Resolution       Resolution
  22551.    ──────────────────────────────────────────────────────────────────────────
  22552.    MDA     720              350             2       1        MD
  22553.    CGA     640/320          200             16      7        Color, B/W
  22554.    EGA     640/320          350/200         64      12       ED, MD,
  22555.                                                              Color, B/W
  22556.    MCGA    720/360/640/320  400/480/200     262,    11       PSM, ED, MD,
  22557.                                             144              Color, B/W
  22558.    VGA     720/360/640/320  400/480/350/200 262,    15       PSM, ED, MD,
  22559.                                             144              Color, B/W
  22560.    ──────────────────────────────────────────────────────────────────────────
  22561.  
  22562.  
  22563.  Text Modes and Portability
  22564.  
  22565.    Fortunately, all these video controllers support an 80-by-25 text mode,
  22566.    and that simplifies the task of writing programs to run with all
  22567.    combinations.
  22568.  
  22569.  Controller Similarities
  22570.  
  22571.    A comparison of 80-by-25 text modes for different hardware combinations
  22572.    shows both similarities and differences. In all cases, the screen is
  22573.    treated as an array of characters rather than as an array of pixels. That
  22574.    is, you can only display or alter entire characters, not the individual
  22575.    pixels that comprise the characters.
  22576.  
  22577.    All controllers use two bytes of memory to represent each text-mode
  22578.    character. One byte holds the character's ASCII code, and the other byte
  22579.    holds the character's display attribute. All video controllers also
  22580.    contain random access memory (video RAM) in which character data is mapped
  22581.    to the display. That is, the controller periodically scans the video RAM
  22582.    to determine which characters it should display. Therefore, to change the
  22583.    screen display, you must change the appropriate bytes in the video RAM.
  22584.    Note that text-mode video RAM always consists of 4000 bytes: One screen
  22585.    holds 80 x 25, or 2000, characters, each represented by two bytes.
  22586.  
  22587.    All controllers also maintain a table of character fonts called a
  22588.    "character generator." The controller uses these pixel patterns to
  22589.    physically represent characters on the screen. For example, ASCII code 72
  22590.    in the video RAM tells the controller to put an H at a screen location,
  22591.    and the character font table specifies the particular "H" pixel pattern to
  22592.    use. (See Figure 14-1 on the following page.)
  22593.  
  22594.    These similarities ease the task of writing text programs that are
  22595.    compatible with the various displays.
  22596.  
  22597.        Video RAM                       Font ROM
  22598.    ┌─────────────────┐           ┌─────────────────┐
  22599.    │ 072 (ASCII code)│           │ H (Font info)   │
  22600.    │  ▒              │           │ ▒               │
  22601.    └──▒──────────────┘           └─▒───────────────┘
  22602.       ▒                            ▒
  22603.       ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  22604.                 ▒
  22605.           ╔═════▒═════════════════════╗
  22606.           ║  ┌────────────────────┐  ║
  22607.           ║  │  H                  │  ║
  22608.           ║  │                     │  ║
  22609.           ║  │                     │  ║
  22610.           ║  │                     │  ║
  22611.           ║  │                     │  ║
  22612.           ║  └─────────────────────┘  ║
  22613.           ╚═══════════════════════════╝
  22614.                      Display
  22615.  
  22616.    Figure 14-1. Producing characters with the MDA.
  22617.  
  22618.    Differences between displays complicate the programming process. For
  22619.    example, one powerful video technique called "direct memory access" uses
  22620.    pointers to video RAM to directly alter RAM contents. However, the MDA
  22621.    uses a different video RAM address than other controllers, so your program
  22622.    must always test for its use. Another programming technique uses "ports"
  22623.    to access registers on the controllers. However, the various controllers
  22624.    have different numbers of registers, and each register has a different
  22625.    port address and performs a different function. This makes for very
  22626.    involved hardware programming.
  22627.  
  22628.    Video controllers also contain differing amounts of video RAM. The MDA has
  22629.    only enough memory to hold one screenful, or page, of characters. The
  22630.    other controllers hold enough memory to hold four or more pages of text.
  22631.  
  22632.    Most controllers offer different screen resolutions. Although all the
  22633.    controllers display a maximum of 2000 characters on the screen, some can
  22634.    generate more pixels than others. For example, the CGA screen consists of
  22635.    a matrix of 640 horizontal pixels (for 80 characters) by 200 vertical
  22636.    pixels (for 25 display lines). The net result is that each character is
  22637.    represented by an 8-by-8-pixel grid, or "character box." The MDA, on the
  22638.    other hand, generates 720 horizontal pixels and 350 lines, providing a
  22639.    9-by-14-pixel character box. Thus, MDA characters look better than their
  22640.    CGA counterparts because each character is drawn with more detail, as
  22641.    shown in Figure 14-2.
  22642.  
  22643.    Finally, the color displays can use the attribute byte to specify
  22644.    foreground and background colors for each character. Table 14-2 provides
  22645.    a summary of the different characteristics of video controllers operating
  22646.    in text mode.
  22647.  
  22648.    ┌────────────────────────────────────────────────────────────────────────┐
  22649.    │ Figure 14-2 can be found on p.453 of the printed version of the book.  │
  22650.    └────────────────────────────────────────────────────────────────────────┘
  22651.  
  22652.    Figure 14-2. Character boxes.
  22653.  
  22654.    Table 14-2 Summary of Text-Mode Differences
  22655.    Controller           Video RAM Starting   Pages      Character Color
  22656.                         Address                         Box Size
  22657.    ──────────────────────────────────────────────────────────────────────────
  22658.    MDA                  0xB8000              1          9 x 14    No
  22659.    CGA                  0xB0000              4          8 x 8     Yes
  22660.    EGA (mode 7)         0xB8000              4/8       9 x 14    No
  22661.    EGA (modes 2, 3)     0xB0000              4/8       8 x 14    Yes
  22662.    MCGA                 0xB0000              8          9 x 16    Yes
  22663.    VGA                  0xB0000              8          9 x 16    Yes
  22664.    ──────────────────────────────────────────────────────────────────────────
  22665.  
  22666.  
  22667.  Device-independent Programming
  22668.  
  22669.    When programming for the PC, you have the choice of programming for
  22670.    specific hardware or ignoring the hardware altogether. The direct memory
  22671.    access method discussed later in this chapter uses hardware information
  22672.    explicitly. To write device-independent programs that don't require
  22673.    explicit hardware information, use one or more of the following methods:
  22674.  
  22675.    1.  Program with the standard C Library output functions such as printf()
  22676.        and putchar(). This results in portable code, but it limits the
  22677.        positioning of text and doesn't permit the use of color.
  22678.  
  22679.    2.  Use the ANSI.SYS escape sequences, as described in Chapter 13.
  22680.        However, if your program utilizes the cursor-control keys, for
  22681.        example, you must use console I/O functions, which restrict
  22682.        portability. Also, using ANSI.SYS inhibits some special features of
  22683.        the EGA, such as the 43-line display. The ANSI approach works on all
  22684.        systems that recognize the standard ANSI codes; IBM PCs and clones
  22685.        must have the ANSI.SYS driver installed.
  22686.  
  22687.    3.  Use IBM PC BIOS calls, as described in Chapter 13. The BIOS includes
  22688.        programs for all PC video controllers, and it selects the appropriate
  22689.        code for the display and controller you are using. That's why our
  22690.        examples in Chapter 13 didn't specify a monitor or controller. BIOS
  22691.        calls also support using more than one page of screen memory; but
  22692.        because the MDA has only one page, we suggest you restrict
  22693.        applications to page 0.
  22694.  
  22695.    We thoroughly covered the first two choices in the last chapter. Although
  22696.    we also discussed BIOS calls, we skipped some of the detail until you
  22697.    understood more about the hardware. In the next section we will discuss
  22698.    BIOS calls in greater detail.
  22699.  
  22700.  Working with BIOS Again: Attributes
  22701.  
  22702.    In Chapter 13, we built a small library (SCRFUN.LIB) of BIOS-based C
  22703.    functions that are hardware-independent. In fact, insulating the user from
  22704.    the hardware is one of the primary reasons for having a BIOS. For
  22705.    instance, we can use the same BIOS calls to control the way in which
  22706.    characters are displayed on an MDA, CGA, EGA, or VGA monitor. The
  22707.    attribute of a character controls its appearance. Let's see how we can use
  22708.    the BIOS to investigate and control attributes.
  22709.  
  22710.    An attribute is a 1-byte value in which the individual bits have
  22711.    particular meanings that affect the appearance of the associated
  22712.    character. For example, with the Monochrome Display Adapter, bit 7 of the
  22713.    attribute controls the blink function, bits 6─4 control the background,
  22714.    bit 3 controls the intensify foreground function, and bits 2─0 control the
  22715.    foreground──that is, the pixels constituting the character. (See Figure
  22716.    14-3.) Table 14-3 lists the standard attribute values used by the MDA.
  22717.  
  22718.    Bit numbers ─────7     6     5     4     3     2     1    0
  22719.                  ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
  22720.                  │     │     │     │     │     │     │     │     │
  22721.                  └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
  22722.                     │  └────────┬────────┘  │  └────────┬────────┘
  22723.                     │       Background      │       Foreground
  22724.                 Blink bit             Intensity bit
  22725.  
  22726.    Figure 14-3. Monochrome attribute bits.
  22727.  
  22728.    Table 14-3 Monochrome Attributes
  22729.    Bit Pattern        Hex Value         Meaning
  22730.    ──────────────────────────────────────────────────────────────────────────
  22731.    0000 0000          0x00              No display
  22732.    0000 0111          0x07              Normal display
  22733.    0111 0000          0x70              Reverse video
  22734.    0000 0001          0x01              Underline
  22735.    0111 0111          0x77              Whiteout
  22736.    1xxx xxxx          0x80              Blink mode
  22737.    xxxx 1xxx          0x08              Intensified foreground
  22738.    ──────────────────────────────────────────────────────────────────────────
  22739.  
  22740.    Note: The last two entries are used with different modes. For example,
  22741.    10000111 (0x87) is normal display with blinking, while 11110000 (0xF0) is
  22742.    reverse video with blinking. The x's indicate that those values don't
  22743.    affect blinking or intensity.
  22744.  
  22745.    The other video controllers use bits 6─4 to control the color of the
  22746.    background and bits 2─0 to control the color of the foreground. Bits 7 and
  22747.    3 serve the same function as they do for the MDA. Figure 14-4 shows the
  22748.    color that each bit controls.
  22749.  
  22750.    Bit numbers ─────7     6     5     4     3     2     1    0
  22751.                  ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
  22752.                  │ BL  │  R  │  G  │  B  │  I  │  R  │  G  │  B  │
  22753.                  └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
  22754.                     │  │ Red  Green Blue │  │  │ Red  Green Blue │
  22755.                     │  └────────┬────────┘  │  └────────┬────────┘
  22756.                     │       Background      │       Foreground
  22757.                   Blink                 Intensify
  22758.                                         foreground
  22759.  
  22760.    Figure 14-4. Color attribute bits.
  22761.  
  22762.    ──────────────────────────────────────────────────────────────────────────
  22763.    The EGA BIOS
  22764.    The IBM BIOS was created long before the inception of the EGA. How, then,
  22765.    can you use BIOS routines to control the EGA? The EGA card comes with a
  22766.    set of BIOS interrupt 0x10 video I/O routines in its own ROM. Recall that
  22767.    the address of each interrupt routine is stored in the interrupt vector
  22768.    table. When you boot an EGA system, the entry for video interrupt 0x10 is
  22769.    loaded with the EGA BIOS address instead of the motherboard BIOS address.
  22770.    Thus, the old BIOS routines are bypassed and the new EGA-supplied ones are
  22771.    used.
  22772.    ──────────────────────────────────────────────────────────────────────────
  22773.  
  22774.    To produce a blue character on a red screen, use an attribute of 01000001.
  22775.    This turns on the red background bit and the blue foreground bit. To make
  22776.    the foreground a bright blue, turn on the intensity bit with 01001001.
  22777.  
  22778.    If you set both the blue and green foreground bits, the blue and the green
  22779.    phosphors on the display screen are simultaneously turned on, producing a
  22780.    color called cyan. Setting all three foreground bits turns on all three
  22781.    colors, which, by the laws of video color mixing, produces white.
  22782.    Similarly, clearing all three bits causes no pixels to be turned on,
  22783.    producing black. Therefore, the "normal" monochrome attribute of 00000111
  22784.    also produces white-on-black characters for the CGA, EGA, and VGA. Table
  22785.    14-4 shows the colors generated by the various 3-bit combinations.
  22786.  
  22787.    Table 14-4 Text Color Values
  22788.    Bit Pattern        Hex Foreground    Hex Background     Color
  22789.    ──────────────────────────────────────────────────────────────────────────
  22790.    000                0x0               0x00               Black
  22791.    001                0x1               0x10               Blue
  22792.    010                0x2               0x20               Green
  22793.    011                0x3               0x30               Cyan
  22794.    100                0x4               0x40               Red
  22795.    101                0x5               0x50               Magenta
  22796.    110                0x6               0x60               Dark yellow
  22797.                                                            (brown)
  22798.    111                0x7               0x70               White (light gray)
  22799.    ──────────────────────────────────────────────────────────────────────────
  22800.  
  22801.    Note: The hex value 0x8 intensifies the foreground color, and 0x80 makes
  22802.    the character blink. Also, all attributes can be combined using logical
  22803.    operators.
  22804.  
  22805.    ──────────────────────────────────────────────────────────────────────────
  22806.    Colors
  22807.    All colors can be produced by combining three primary colors together in
  22808.    varying proportions. The three "additive" primary colors are red, green,
  22809.    and blue. For example, when you direct a beam of green light and a beam of
  22810.    red light toward a piece of white paper, the area where the beams overlap
  22811.    (or are "added") appears yellow.
  22812.  
  22813.    A color video screen also creates colors by combining the additive
  22814.    primaries. Each pixel on a color screen contains individual red, green,
  22815.    and blue dots. Turning a pixel blue amounts to turning on the blue dots in
  22816.    the pixel. To produce yellow, you turn on the green and the red dots in a
  22817.    pixel──the eye perceives only the combined light, which is yellow.
  22818.  
  22819.    The PC's system of using numbers to represent color imitates the physical
  22820.    color-mixing process. For example, in binary notation, the color number
  22821.    for red is 100 and the color number for green is 010. Turning on both the
  22822.    red and the green bits corresponds to specifying the binary number 110,
  22823.    which is the code for yellow.
  22824.    ──────────────────────────────────────────────────────────────────────────
  22825.  
  22826.    Suppose you want a yellow character on a blue background. Because yellow
  22827.    is produced by combining red and green light (bits 2 and 1), and
  22828.    background blue is bit 4, the corresponding attribute is 00010110, or
  22829.    0x16. (The actual colors you see depend on your monitor and its
  22830.    adjustments.)
  22831.  
  22832.    It's more interesting to display the attributes on the screen than it is
  22833.    to read about them, so let's develop a program that changes the attribute
  22834.    bits to demonstrate how the colors change. First we must write a function
  22835.    that prints a string using a given attribute. Using the functions from our
  22836.    SCRFUN.LIB library, we produce the following Print_attr() function
  22837.    (Listing 14-1).
  22838.  
  22839.    Print_attr() writes a character-attribute pair and moves the cursor one
  22840.    position to the right. Print_attr() has its limitations. First, it doesn't
  22841.    recognize the end of a line. Second, it doesn't have all the fancy
  22842.    formatting that printf() has. (You can modify the function to handle the
  22843.    end-of-line problem and use the sprintf() function to do the formatting.)
  22844.  
  22845.    Now let's use the Print_attr() string-displaying function in a program to
  22846.    display the various attributes. To demonstrate the role of each attribute
  22847.    bit, the program has you type the attribute byte as a binary number. The
  22848.    comments in the ATTRIB.C program (Listing 14-2 on the following page)
  22849.    explain the workings of the various functions. Before you run the ATTRIB.C
  22850.    program, pull down the Debug menu: Screen Swapping On should be active
  22851.    (indicated by a check to the left of the option). If it is not active,
  22852.    choose it from the menu to activate it.
  22853.  
  22854.    This program works with any of the previously mentioned standard video
  22855.    controllers. If you have a monochrome monitor, check to see what
  22856.    nonstandard combinations such as 00000100 produce. If you have a color
  22857.    monitor, enjoy the many color combinations.
  22858.  
  22859.    ──────────────────────────────────────────────────────────────────────────
  22860.    /* Print_attr() -- prints the string str using */
  22861.    /* attribute attr on the indicated page        */
  22862.    /* It uses functions from the scrfun.c file.   */
  22863.  
  22864.    void Print_attr(str, attr, page)
  22865.    char *str;
  22866.    unsigned char attr, page;
  22867.    {
  22868.        while (*str != '\0')
  22869.            {
  22870.            Write_ch_atr(*str++, attr, page, 1);
  22871.            Cursrt();
  22872.            }
  22873.    }
  22874.    ──────────────────────────────────────────────────────────────────────────
  22875.  
  22876.    Listing 14-1.  The Print_attr() function.
  22877.  
  22878.    ──────────────────────────────────────────────────────────────────────────
  22879.    /* attrib.c -- this program illustrates attributes */
  22880.    /* program list: attrib.c, scrfun.lib              */
  22881.    /* user include files: scrn.h                      */
  22882.    /* Note: activate Screen Swapping On in Debug menu */
  22883.    #include <stdio.h>
  22884.    #include <conio.h>
  22885.    #include "scrn.h"
  22886.    #define PAGE 0
  22887.    #define ESC '\033'
  22888.    char *Format = "This message is displayed using an "
  22889.                   "attribute value of %2X hex (%s).";
  22890.    int Get_attrib(char *);
  22891.    void Print_attr(char *, unsigned char, unsigned char);
  22892.  
  22893.    main()
  22894.    {
  22895.  
  22896.        int attribute;       /* value of attribute   */
  22897.        char attr_str[9];    /* attr. in string form */
  22898.        char mesg[80];
  22899.  
  22900.        Clearscr();
  22901.        Home();
  22902.        printf("Enter an attribute as an 8-digit binary "
  22903.               "number, such as 00000111, and see a\n"
  22904.               "message displayed using that attribute."
  22905.               "Hit <Esc> to quit.\n"
  22906.               "Attribute = ");
  22907.        while ((attribute = Get_attrib(attr_str)) != -1)
  22908.            {
  22909.            Setcurs(10,0,PAGE);
  22910.            sprintf(mesg, Format, attribute, attr_str);
  22911.            Print_attr(mesg, attribute, PAGE);
  22912.            Setcurs(2, 12, PAGE);
  22913.            printf("         ");  /* clear old display */
  22914.            Setcurs(2, 12, PAGE);
  22915.            }
  22916.        Clearscr();
  22917.    }
  22918.  
  22919.    /* The following function reads in a binary number    */
  22920.    /* as a sequence of 1s and 0s. It places the 1 and 0  */
  22921.    /* characters in a string whose address is passed as  */
  22922.    /* an argument. It returns the numeric value of the   */
  22923.    /* binary number. Bad input is summarily rejected.    */
  22924.    /* The function returns -1 when you press Esc.        */
  22925.    int Get_attrib(a_str)
  22926.    char a_str[];     /* attribute as binary string */
  22927.    {
  22928.        int attrib[8];
  22929.        int index = 7;
  22930.        int ch;
  22931.        int attribute = 0; /* attrib. as numeric value */
  22932.        int pow;
  22933.  
  22934.        a_str[8] = '\0';  /* terminate string */
  22935.        while ((index >= 0) && (ch = getch()) != ESC)
  22936.            {
  22937.            if (ch != '0' && ch != '1')  /* bad input */
  22938.                putch('\a');
  22939.            else
  22940.                {
  22941.                putch(ch);
  22942.                a_str[index] = ch;      /* string form */
  22943.                attrib[index--] = ch - '0'; /* numeric */
  22944.                }
  22945.            }
  22946.        if (ch == ESC)
  22947.            return (-1);
  22948.        else            /* convert numeric array to a number */
  22949.            {
  22950.            for(index = 0, pow = 1; index < 8;
  22951.                                      index++, pow *= 2)
  22952.                attribute += attrib[index] * pow;
  22953.            return attribute;
  22954.            }
  22955.    }
  22956.  
  22957.    /* The following function prints the string str using */
  22958.    /* attribute attr on the indicated page.              */
  22959.    /* It uses functions from the scrfun.c file.          */
  22960.  
  22961.    void Print_attr(str, attr, page)
  22962.    char *str;
  22963.    unsigned char attr, page;
  22964.    {
  22965.        while (*str != '\0')
  22966.            {
  22967.            Write_ch_atr(*str++, attr, page, 1);
  22968.            Cursrt();
  22969.            }
  22970.    }
  22971.    ──────────────────────────────────────────────────────────────────────────
  22972.  
  22973.    Listing 14-2.  The ATTRIB.C program.
  22974.  
  22975.  Attributes and Bitwise Operators
  22976.  
  22977.    You can also manipulate attributes with the C bitwise operators that we
  22978.    discussed in Chapter 7. Suppose, for example, a program uses the
  22979.    following definitions:
  22980.  
  22981.      #define NORMAL 0x07
  22982.      #define VIDREV 0x70
  22983.      #define BLINK  0x80
  22984.      #define INTENSE 0x08
  22985.  
  22986.    To set mode to an intense, normal attribute, we can use the bitwise
  22987.    logical OR operator, as follows:
  22988.  
  22989.      mode = NORMAL | INTENSE;
  22990.  
  22991.    Because 1 OR anything is 1, all bits set to 1 are left on. Now, suppose
  22992.    mode has already gone through several changes. At this point it might be
  22993.    normal, reverse video, or have blinking on or off, etc. To turn on the
  22994.    intensify mode regardless of the current state, use an instruction like
  22995.    the following:
  22996.  
  22997.      mode = mode | INTENSE;
  22998.  
  22999.    The only bit this instruction can change is bit 3, the intensity bit,
  23000.    because all the other bits of INTENSE are 0, and 0 OR any bit is merely
  23001.    that bit. (That is, 0 | 0 is 0, and 1 | 0 is 1.) Furthermore, this
  23002.    instruction always sets bit 3 to 1, regardless of its previous value. (0 |
  23003.    1 is 1, and 1 | 1 is 1.) Incidentally, you can also use a combination
  23004.    assignment operator to rewrite the last C statement as follows:
  23005.  
  23006.      mode |= INTENSE;  /*unconditionally turns INTENSE on */
  23007.  
  23008.    Sometimes an instruction must "toggle" a bit. That is, the instruction
  23009.    turns on an off bit or turns off an on bit. For this, we use the EXCLUSIVE
  23010.    OR operator (^). Recall that this operator produces a "true" value (1) if
  23011.    one operand or the other is "true" but not if both are "true." The
  23012.    following expression toggles the intensity bit:
  23013.  
  23014.      mode = mode ^ INTENSE;
  23015.  
  23016.    If the intensity bit in mode is initially off, the expression becomes 0 ^
  23017.    1, which is 1, or on. If the intensity bit in mode is initially on, the
  23018.    expression is 1 ^ 1, which is 0, or off. Again, we can simplify the
  23019.    statement with the following combination assignment operator:
  23020.  
  23021.      mode ^= INTENSE;  /* toggles the intensity bit */
  23022.  
  23023.  Compatible "Graphics"
  23024.  
  23025.    A system with true graphics capability lets you individually control each
  23026.    pixel on the screen. By its very makeup, the MDA lacks that ability. The
  23027.    CGA provides graphics modes, and the EGA and VGA have additional graphics
  23028.    abilities. Therefore, to produce true graphics, a program must address
  23029.    specific hardware.
  23030.  
  23031.    However, IBM has given the PC a limited but more universal graphics
  23032.    capability by extending the character set. The ASCII character set uses
  23033.    the values 0 through 127. But because a byte can store any value through
  23034.    255, IBM added 128 additional characters to the set and assigned them code
  23035.    values 128 through 255. These constitute the IBM Extended Character Set.
  23036.    Many of these characters are mathematical symbols, foreign-language
  23037.    characters, and so on. However, 48 of the characters (codes 176 through
  23038.    223) constitute the "graphics characters," which are useful for drawing
  23039.    and filling rectangular forms.
  23040.  
  23041.    With these characters, you can do a limited amount of hardware-independent
  23042.    graphics. The QuickC screen, for example, uses these characters to draw
  23043.    its boxes and borders. In fact, you can use QuickC to examine the extended
  23044.    ASCII set. Pull down the general Help menu and browse through it until you
  23045.    reach the screen that displays the extended set.
  23046.  
  23047.    You can also display the extended set of characters from the keyboard. To
  23048.    see what character 206 looks like, first press Num Lock; then, at your
  23049.    system prompt, hold down the Alt key and type 206 using the keys in the
  23050.    numeric keypad. When you release Alt, the character appears on the
  23051.    display.
  23052.  
  23053.  Programming with the Graphics Character Set
  23054.  
  23055.    Let's develop a QuickC program to help us investigate the extended
  23056.    character set. Below are some of the features we need to develop in a
  23057.    program that draws with the graphics characters.
  23058.  
  23059.    ■  Key-mapping so that a single keystroke generates a graphics character
  23060.  
  23061.    ■  Cursor control for drawing at different screen locations
  23062.  
  23063.    ■  An erasing feature
  23064.  
  23065.    ■  An auto-drawing feature that generates strings of characters across the
  23066.       screen
  23067.  
  23068.    ■  An attribute manipulator for highlighting text or turning on blinking
  23069.  
  23070.    Many of these goals resemble problems we solved in Chapter 13; therefore,
  23071.    we can put our previously developed tools to good use now. For example, we
  23072.    can use the getch() function and scan codes to use the function keys and
  23073.    the cursor-control keys. We can call the BIOS to clear the screen and to
  23074.    provide cursor-movement functions. And by using the method developed for
  23075.    REKEY.C (Listing 13-7 on p. 411), we can map the keys. In short, we have
  23076.    the tools; now we have to organize them into a workable QuickC program.
  23077.  
  23078.    The User Interface
  23079.  
  23080.    Today it is not enough to design a program that works. Interactive
  23081.    programs require that the programmer think about the user's point of view.
  23082.    In our case, for example, we need to plan how to best use the keyboard to
  23083.    control the graphics characters.
  23084.  
  23085.    For example, which key represents which character? With 48 graphics
  23086.    characters, there is no obvious mnemonic method for assigning keys. And it
  23087.    is unreasonable to expect a user to remember 48 random assignments. To
  23088.    help the user, we display the graphics characters and key assignments at
  23089.    the bottom of the screen. We also list other important keys.
  23090.  
  23091.    Next, we must plan how to manage the drawing process. Drawing with
  23092.    graphics characters often involves repeatedly using the same character.
  23093.    Merely mapping a graphics character to a key is acceptable only for
  23094.    repeating the character left to right because that's the way keyboard
  23095.    input normally works. But drawing characters vertically or from right to
  23096.    left is more difficult. Cursor control helps, but drawing a vertical line
  23097.    would entail pressing the character key, using the Down Arrow key to move
  23098.    down a line, using the Left Arrow key to move under the first character,
  23099.    and then pressing the character key again. Therefore, we must use a
  23100.    different technique.
  23101.  
  23102.    In our solution to the problem, the character keys select, but do not
  23103.    display, a graphics character. To actually display the character, the user
  23104.    must press one of the arrow keys. This places the character at the current
  23105.    position of the cursor, then shifts the cursor in the direction of the
  23106.    arrow key. Until the user selects another character key, the current
  23107.    graphics character remains active. Therefore, repeatedly pressing an arrow
  23108.    key moves the cursor and leaves a display trail of the current graphics
  23109.    character. This simplifies drawing horizontal and vertical lines.
  23110.  
  23111.    Now let's add some refinements. The PgUp key disenables drawing so that
  23112.    the user can move the cursor without displaying characters. The PgDn key
  23113.    restores the drawing mode. The Spacebar represents the program's "eraser."
  23114.    The user can select the Spacebar as the current graphics character and use
  23115.    the cursor keys to delete unwanted characters. Our last refinement lets
  23116.    the user select character attributes with the function keys.
  23117.  
  23118.    We take advantage of QuickC's program list feature to split the program
  23119.    into three file modules. Note that two of the modules use SCRFUN.LIB and
  23120.    scrn.h and one uses keys.h, all developed in Chapter 13. We also collect
  23121.    the define statements for the three modules in an include file called
  23122.    grafchar.h.
  23123.  
  23124.    First, look at the main program, GRAFCHAR.C (Listing 14-3). To run this
  23125.    program within the QuickC environment, be sure that Screen Swapping On is
  23126.    active (on the Debug menu).
  23127.  
  23128.    GRAFCHAR.C is a simple program──it merely calls the other two files in the
  23129.    program list: initstuf.c and drawchar.c. We will discuss these modules in
  23130.    the next two sections. Before you proceed to those sections, however,
  23131.    examine the grafchar.h header file (Listing 14-4).
  23132.  
  23133.    ──────────────────────────────────────────────────────────────────────────
  23134.    /*   grafchar.c -- draws graphics characters with      */
  23135.    /*                 attributes on the screen            */
  23136.    /*  Program list : grafchar.c, initstuf.c, drawchar.c, */
  23137.    /*                  scrfun.lib                         */
  23138.    /*  User include files: keys.h, scrn.h, grafchar.h     */
  23139.    /*  Note: activate Screen Swapping On in Debug menu    */
  23140.  
  23141.    #include "grafchar.h"
  23142.    unsigned char Grchr[NUMCHARS];  /* to store graphics set */
  23143.    void Init_stuff(void);      /* in initstuf.c */
  23144.    void Draw_chars(void);      /* in drawchar.c */
  23145.  
  23146.    main()
  23147.    {
  23148.        Init_stuff();  /* initialize vital elements */
  23149.        Draw_chars();  /* map keys to graphics characters */
  23150.    }
  23151.    ──────────────────────────────────────────────────────────────────────────
  23152.  
  23153.    Listing 14-3.  The GRAFCHAR.C program.
  23154.  
  23155.    ──────────────────────────────────────────────────────────────────────────
  23156.    /* grafchar.h -- header file for grafchar.c program */
  23157.    /*               Version 1                          */
  23158.    #define NUMCHARS 48  /* number of graphics chars  */
  23159.    #define SPACE '\040'
  23160.    #define BOTLINE 19   /* line # for end of drawing space */
  23161.    #define PAGE 0
  23162.    #define GCSTART 0xB0 /* ascii for first graphics char */
  23163.    #define BEEP '\a'
  23164.    #define ESC '\033'
  23165.    #define TRUE 1
  23166.    #define FALSE 0
  23167.    ──────────────────────────────────────────────────────────────────────────
  23168.  
  23169.    Listing 14-4.  The grafchar.h header file.
  23170.  
  23171.    Setting Up the Program: initstuf.c
  23172.  
  23173.    The initstuf.c module (Listing 14-5 on the following page) sets up the
  23174.    GRAFCHAR.C program. It initializes the external array grafchar.c to the 48
  23175.    graphics characters and clears the screen. At the bottom of the screen, it
  23176.    prints the graphics characters and their corresponding keystrokes. Also
  23177.    listed are the following non-ASCII keys and their functions: The F1
  23178.    function key sets the normal white-on-black text attribute; F2 selects
  23179.    reverse video; F3 toggles blinking; and F4 toggles foreground intensity.
  23180.    The program uses Print_attr() to show how the last three attributes appear
  23181.    on screen. For example, the phrase F3 : Blinking is displayed on screen in
  23182.    the blinking mode.
  23183.  
  23184.    ──────────────────────────────────────────────────────────────────────────
  23185.    /*  initstuf.c -- initializing module for grafchar.c */
  23186.    /*  assigns graphics character codes to an array     */
  23187.    /*  and initializes screen                           */
  23188.  
  23189.    #include "scrn.h"   /* Clearscr(), Home(), Setcurs() */
  23190.    #include "grafchar.h"
  23191.    extern unsigned char Grchr[];  /* defined in grafchar.c */
  23192.    void Print_attr(char *, unsigned char, unsigned char);
  23193.     [bn]
  23194.    void Init_stuff()
  23195.    {
  23196.        int i;
  23197.  
  23198.        /* initialize array with graphics characters */
  23199.        for (i = 0; i < NUMCHARS; i++)
  23200.            Grchr[i] = GCSTART + i;
  23201.        Clearscr();
  23202.        Home();
  23203.  
  23204.        /* show key meanings at bottom of screen */
  23205.        Setcurs(BOTLINE + 1, 0, PAGE);
  23206.        for (i = 0; i < 40; i++) /* graphics chars */
  23207.            {
  23208.            putch(Grchr[i]);
  23209.            putch(SPACE);
  23210.            }
  23211.        Setcurs(BOTLINE + 2, 0, PAGE);
  23212.        for (i = 0; i < 40; i++)  /* key assignments */
  23213.            {
  23214.            putch('0' + i);
  23215.            putch(SPACE);
  23216.            }
  23217.        Setcurs(BOTLINE + 3, 0, PAGE);
  23218.        for (i = 40; i < NUMCHARS; i++) /* second row */
  23219.            {
  23220.            putch(Grchr[i]);
  23221.            putch(SPACE);
  23222.            }
  23223.        /* show function key assignments */
  23224.        printf(" SPACE : ERASE  PgUp : No Draw ");
  23225.        printf(" PgDn : Draw  ESC : Quit");
  23226.        Setcurs(BOTLINE + 4, 0, PAGE);
  23227.        for (i = 40; i < NUMCHARS; i++) /* second row */
  23228.            {
  23229.            putch('0' + i);
  23230.            putch(SPACE);
  23231.            }
  23232.        /* more function key assignments */
  23233.        Print_attr("F1 : Normal ", NORMAL, PAGE);
  23234.        Print_attr("F2 : Reverse Video ", VIDREV, PAGE);
  23235.        Setcurs(BOTLINE + 5, 16, PAGE);
  23236.        Print_attr("F3 : Blinking ", NORMAL | BLINK, PAGE);
  23237.        Print_attr("F4 : Intense ", NORMAL | INTENSE, PAGE);
  23238.        Home();
  23239.    }
  23240.  
  23241.    void Print_attr(str, attr, page)
  23242.    char *str;
  23243.    unsigned char attr, page;
  23244.    {
  23245.        while (*str != '\0')
  23246.            {
  23247.            Write_ch_atr(*str++, attr, page, 1);
  23248.            Cursrt();
  23249.            }
  23250.    }
  23251.    ──────────────────────────────────────────────────────────────────────────
  23252.  
  23253.    Listing 14-5.  The initstuf.c module.
  23254.  
  23255.    Drawing the Characters: drawchar.c
  23256.  
  23257.    The final module, drawchar.c (Listing 14-6), contains the code that
  23258.    translates keystrokes into action. First, it maps the 48 keystrokes to the
  23259.    graphics characters. After the program initializes the Spacebar character,
  23260.    it uses a switch statement to process PgUp, PgDn, the cursor control keys,
  23261.    and the four function keys. Figure 14-5 on p. 467 shows some sample
  23262.    output from this program.
  23263.  
  23264.    ──────────────────────────────────────────────────────────────────────────
  23265.    /* drawchar.c -- drawing module for grafdraw.c         */
  23266.    /* translates keystrokes to graphic characters,        */
  23267.    /* manages cursor control and function keys            */
  23268.  
  23269.    #include <conio.h>
  23270.    #include "keys.h"
  23271.    #include "scrn.h"
  23272.    #include "grafchar.h"
  23273.    extern unsigned char Grchr[];  /* defined in grafchar.c */
  23274.  
  23275.    void Draw_chars()
  23276.    {
  23277.        int ch, chout;
  23278.        unsigned char attrib = NORMAL;
  23279.        unsigned char draw = TRUE;
  23280.  
  23281.        chout = Grchr[0];  /* default  graphics character */
  23282.        while ((ch = getch()) != ESC)
  23283.            {
  23284.            if (ch >= '0' && ch <= '_')
  23285.                chout = Grchr[ch - '0'];
  23286.                 /* this maps the 0 key to the first */
  23287.                 /* graphics character, etc.         */
  23288.            else if (ch == SPACE)
  23289.                chout = SPACE;
  23290.            else if (ch == 0) /* process cursor keys */
  23291.                {             /* and function keys   */
  23292.                ch = getch();
  23293.                switch (ch)
  23294.                    {
  23295.                    case PU : draw = FALSE;
  23296.                              break;
  23297.                    case PD : draw = TRUE;
  23298.                              break;
  23299.                    case UP : if (draw)
  23300.                                  Write_ch_atr(chout, attrib,
  23301.                                               PAGE, 1);
  23302.                              if (!Cursup())
  23303.                                  putch(BEEP);
  23304.                              break;
  23305.                    case DN : if (draw)
  23306.                                  Write_ch_atr(chout, attrib,
  23307.                                               PAGE, 1);
  23308.                              if (!Cursdn_lim(BOTLINE))
  23309.                                  putch(BEEP);
  23310.                              break;
  23311.                    case LT : if (draw)
  23312.                                  Write_ch_atr(chout, attrib,
  23313.                                               PAGE, 1);
  23314.                              if (!Curslt())
  23315.                                  putch(BEEP);
  23316.                              break;
  23317.                    case RT : if (draw)
  23318.                                  Write_ch_atr(chout, attrib,
  23319.                                               PAGE, 1);
  23320.                              if (!Cursrt())
  23321.                                  putch(BEEP);
  23322.                              break;
  23323.                    case F1 : attrib = NORMAL; break;
  23324.                    case F2 : attrib = VIDREV; break;
  23325.                    case F3 : attrib ^= BLINK; break;
  23326.                    case F4 : attrib ^= INTENSE; break;
  23327.                    default : putch(BEEP);
  23328.                    }
  23329.                }
  23330.            }
  23331.    }
  23332.    ──────────────────────────────────────────────────────────────────────────
  23333.  
  23334.    Listing 14-6.  The drawchar.c module.
  23335.  
  23336.    ┌────────────────────────────────────────────────────────────────────────┐
  23337.    │ Figure 14-5 can be found on p.467 of the printed version of the book.  │
  23338.    └────────────────────────────────────────────────────────────────────────┘
  23339.  
  23340.    Figure 14-5. Drawing with GRAFCHAR.C.
  23341.  
  23342.  Details of the Program
  23343.  
  23344.    The easiest way to see how the program works is to try it out. Move the
  23345.    cursor around with the arrow keys and use the keyboard to select different
  23346.    graphics characters. (Remember to have Screen Swapping On active if you're
  23347.    working in the QuickC environment.) To help you see why it works the way
  23348.    it does, we'll look at some of the programming details next.
  23349.  
  23350.    In the Draw_chars() function, the following statement maps the keystrokes
  23351.    to the graphics characters:
  23352.  
  23353.      if (ch >= '0' && ch <= '_')
  23354.          chout = Grchr[ch - '0'];
  23355.  
  23356.    In this function, ch is the input character; chout is the output character
  23357.    used when the cursor keys are pressed. When the user presses the 0 key,
  23358.    the program uses the array index of '0' - '0', or 0, which selects the
  23359.    first graphics character in the array. Similarly, the 1 key selects the
  23360.    second graphics character, and so on.
  23361.  
  23362.    Next, look at how the program handles the cursor key:
  23363.  
  23364.      case UP : if (draw)
  23365.                    Write_ch_atr(chout, attrib, PAGE, 1);
  23366.                if (!Cursup())
  23367.                    putch(BEEP);
  23368.                break;
  23369.  
  23370.    If draw is set to TRUE, the program displays the current output character
  23371.    (chout) using the current attribute (attrib). In this example, the cursor
  23372.    then moves up one line unless it already is at the top line, in which case
  23373.    the program issues a beep.
  23374.  
  23375.    The other arrow keys are processed similarly. Note that the Down Arrow key
  23376.    uses Cursdn_lim(BOTLINE) instead of Cursdn(). Recall from Chapter 13 that
  23377.    Cursdn() is a macro that moves the cursor down as far as line 25;
  23378.    Cursdn_lim(), however, is limited by a passed argument. Because we reserve
  23379.    the bottom of the screen for the key table, the BOTLINE limit keeps the
  23380.    cursor from intruding.
  23381.  
  23382.    The program uses the following code for selecting an attribute:
  23383.  
  23384.      case F1 : attrib = NORMAL; break;
  23385.      case F2 : attrib = VIDREV; break;
  23386.      case F3 : attrib ^= BLINK; break;
  23387.      case F4 : attrib ^= INTENSE; break;
  23388.  
  23389.    F1 and F2 set the attribute to the normal and reverse video modes,
  23390.    respectively. F3 and F4 use the EXCLUSIVE OR operator to toggle the
  23391.    intensify and the blink modes. Why directly set two modes and toggle the
  23392.    other two? The toggled intensify and blink modes can be on simultaneously
  23393.    and compounded with the other modes. However, NORMAL must be off when
  23394.    VIDREV is on, and vice versa. If both were on at the same time, the screen
  23395.    would display a white foreground on a white background──that is, a
  23396.    featureless white square. If both were off, the display would be black on
  23397.    black, or no display.
  23398.  
  23399.    Limitations of the Program
  23400.  
  23401.    To make the GRAFCHAR.C program compatible with all monitors (except
  23402.    40-by-25 displays), we must impose some limitations. Most importantly, the
  23403.    program limits attributes to monochrome values; less importantly, it uses
  23404.    only page 0 of memory.
  23405.  
  23406.    If you have a color monitor, you can add color to the program by setting
  23407.    the function keys as follows:
  23408.  
  23409.      case F1 : attrib ^= BLUE; break;
  23410.      case F2 : attrib ^= GREEN; break;
  23411.      case F3 : attrib ^= RED; break;
  23412.      case F4 : attrib ^= BG_BLUE; break;
  23413.      case F5 : attrib ^= BG_GREEN; break;
  23414.      case F6 : attrib ^= BG_RED; break;
  23415.      case F7 : attrib ^= BLINK; break;
  23416.      case F8 : attrib ^= INTENSE; break;
  23417.  
  23418.    Also, make the following definitions:
  23419.  
  23420.      #define BLUE   0x1
  23421.      #define GREEN  0x2
  23422.      #define RED    0x4
  23423.      #define BG_BLUE   0x10
  23424.      #define BG_GREEN  0x20
  23425.      #define BG_RED    0x40
  23426.  
  23427.    This lets you independently toggle each bit of the attribute. When the
  23428.    attribute is initially set to NORMAL, blue, green, and red are all toggled
  23429.    on. Pressing F2, for example, turns green off and leaves the red-blue
  23430.    (magenta) combination.
  23431.  
  23432.    You should also change the key table at the bottom of the screen to
  23433.    reflect the new uses of the function keys.
  23434.  
  23435.  
  23436.  Direct Memory Access
  23437.  
  23438.    Thus far, we've used BIOS routines to place the proper character and
  23439.    attribute bytes into video memory. This method offers two advantages──it
  23440.    saves us work and lets us write hardware-independent programs that run on
  23441.    the MDA, CGA, EGA, VGA, and MCGA. However, we can create faster programs
  23442.    by bypassing the BIOS and placing data directly into video memory. This
  23443.    programming technique is called "Direct Video Memory Access," which we
  23444.    will refer to as DMA for the remainder of this book. (Don't confuse this
  23445.    use of DMA with the DMA chip built into the IBM PC and compatibles, which
  23446.    performs a different function.)
  23447.  
  23448.  DMA Basics
  23449.  
  23450.    To copy information to or from a memory location, you need to use the
  23451.    address of that location. Often, you do so symbolically and indirectly by
  23452.    using variables and array names. Pointers provide a more obvious way to
  23453.    use addresses. So what do you use to access video memory?
  23454.  
  23455.    Because video memory is a large block of bytes, it's natural to think of
  23456.    it as a large array. As you've learned, arrays can often be described by
  23457.    either array notation or pointer notation. But with video memory, you must
  23458.    use pointers. The reason is that the compiler chooses the physical
  23459.    addresses to which an array corresponds, but you can choose the physical
  23460.    address to which a pointer points. In particular, you can choose to have a
  23461.    pointer point to the beginning of video memory.
  23462.  
  23463.    The specific address you use depends on the hardware. The MDA uses 0xB0000
  23464.    (720,896 in decimal), and the CGA uses 0xB8000 (753,664 in decimal). The
  23465.    EGA and VGA use 0xB0000 for the monochrome mode and 0xB8000 for the color
  23466.    text modes.
  23467.  
  23468.    To use the address you must typecast the numeric value to the proper
  23469.    pointer type. Also, in the small and medium memory models, a data pointer
  23470.    is a 16-bit quantity. Neither of the addresses we need fits into 16 bits.
  23471.    The large memory model uses a 32-bit pointer, but not in a way that lets
  23472.    us make our simple assignment. So before we can assign the video RAM
  23473.    address to a pointer, we must first examine how the PC and QuickC handle
  23474.    memory addresses.
  23475.  
  23476.  Segmented Memory
  23477.  
  23478.    The PC has the same problem with large addresses that the small and medium
  23479.    models do. The 8086 chip normally uses a 16-bit register for addresses.
  23480.    However, this permits the register to address a maximum of 64 KB of
  23481.    memory, which falls far short of the address needed to access the video
  23482.    RAM.
  23483.  
  23484.    The 8086 family of microprocessors uses segmented memory to overcome this
  23485.    problem. The maximum size of each segment is 64 KB, the size addressable
  23486.    by an address register. Typically, a program uses one segment for program
  23487.    code and a second segment for data.
  23488.  
  23489.    Addresses for the program code are 16-bit addresses relative to the
  23490.    beginning of the program segment, and data addresses are relative to the
  23491.    beginning of the data segment. These relative addresses are called
  23492.    "offsets." In C, this offset is what is stored in a 16-bit pointer. The
  23493.    following statement:
  23494.  
  23495.      printf("Address of x is %u\n", &x);
  23496.  
  23497.    prints out the offset, in bytes, of x from the beginning of a data
  23498.    segment. To keep track of where the code and data segments are, the PC
  23499.    uses special registers: the CS, or Code Segment register, and the DS, or
  23500.    Data Segment register.
  23501.  
  23502.    To solve the problem of identifying the location of a segment using only
  23503.    16 bits, the PC divides the actual address of the segment by 16 (0x10
  23504.    hex). For example, 0xB0000 divided by 0x10 is 0xB000. This divided
  23505.    quantity is called the "segment value." (See Figure 14-6.) Thus, a
  23506.    segment value of 0xA000 corresponds to a segment address of 0xA0000. As a
  23507.    result of this system, segments must start at addresses that are multiples
  23508.    of 16.
  23509.  
  23510.    Suppose you want to specify the 0x20th byte of video memory. The absolute
  23511.    address of this byte is 0xB0020. The PC represents this by setting the
  23512.    data segment register DS to the segment value of 0xB000 and setting the
  23513.    data offset register to 0x20. The following equation expresses the
  23514.    relationship more generally:
  23515.  
  23516.      absolute address = 0x10 x segment value + offset
  23517.  
  23518.                                          ┌─┌──────────────────────┐
  23519.                                          │ │                      │
  23520.                                          │ │                      │
  23521.                                          │ │                      │
  23522.                                          │ ├──────────────────────┤
  23523.                           Data segment───┤ │  01001101 01001111   │───Data at
  23524.                                (64 KB)   │ ├──────────────────────┤─┐ specifie
  23525.                                          │ │                      │ │ location
  23526.       DS register                        │ │                      │ │
  23527.    ┌───────────────┐                     │ │                      │ │
  23528.    │ Segment value │                     │ │                      │ ├─Offset
  23529.    └──────┬────────┘                     │ │                      │ │
  23530.           │                              │ │                      │ │
  23531.                                         └─└─────────────────────┘─┘
  23532.     Segment value * 16 = Segment address────┘
  23533.  
  23534.    Figure 14-6. Data addresses are represented by a segment value and an
  23535.    offset.
  23536.  
  23537.    Note that you can represent the same physical address in many ways. For
  23538.    example, the absolute address 0xB0020 also can be represented with a
  23539.    segment value of 0xB001 and an offset of 0x10.
  23540.  
  23541.    C, Segments, and Offsets
  23542.  
  23543.    As you already know, C has two classes of pointers──near and far. Near
  23544.    pointers, which are 16 bits, hold only the offset. Far pointers, which are
  23545.    32 bits, use the high 16 bits to hold the segment value and the low 16
  23546.    bits to hold the offset, as shown in Figure 14-7. Compact and large
  23547.    models use far data pointers by default. Small and medium models use near
  23548.    data pointers by default. However, you can use the nonstandard C keyword
  23549.    far to create far pointers in the small and medium models. To use the far
  23550.    keyword in QuickC, choose Language Extensions in the Compile Options
  23551.    dialog box.
  23552.  
  23553.    Using a Far Pointer
  23554.  
  23555.    To access the video memory, we must declare a far pointer, initialize its
  23556.    high bytes to the segment value for the video RAM, and use its low bytes
  23557.    for the offset. Declare a far pointer by using the keyword far, as
  23558.    follows:
  23559.  
  23560.      unsigned short far *far_pnt; /* far pointer */
  23561.  
  23562.    This creates a 32-bit pointer that points to a 2-byte unit. Each 2-byte
  23563.    unit holds the ASCII code and the attribute of a single displayed
  23564.    character.
  23565.  
  23566.    Next, let's set the pointer to an absolute screen address of 0xB0020. This
  23567.    corresponds to a segment value of 0xB000 (0xB0000 / 0x10) and an offset of
  23568.    0x20. To place the segment value into the high bytes, left-shift it 16
  23569.    places; because the offset goes into the lower bytes, you needn't
  23570.    manipulate it at all.
  23571.  
  23572.      far_pnt = (unsigned short far *) (0xB000L << 16) | 0x20;
  23573.  
  23574.    Note that we used a typecast to convert the right side (type long) to the
  23575.    correct type. Next, we used the L suffix to make the segment value type
  23576.    long. Otherwise, 0xB000 would be treated as type int (a 16-bit type on a
  23577.    PC), and the 16-bit left-shift would shift all the bits out, leaving only
  23578.    zeros. (See Figure 14-8 on the following page.)
  23579.  
  23580.    Note also that the bitwise OR (|) operator combines the segment value and
  23581.    the offset. Because one resides entirely in the upper bytes and the other
  23582.    is confined to the lower bytes, this has the same effect as addition, but
  23583.    is faster.
  23584.  
  23585.       Segment value        Offset
  23586.    ┌────────┴────────┬────────┴────────┐
  23587.    ┌────────┬────────┬────────┬────────┐
  23588.    │                 │                 │
  23589.    └────────┴────────┴────────┴────────┘
  23590.        High bytes         Low bytes
  23591.  
  23592.    Figure 14-7. Filling a far pointer.
  23593.  
  23594.                        │ 1 byte │
  23595.                        ┌────────┬────────┐
  23596.                        │  B 8   │  0 0   │
  23597.                        └────────┴────────┘
  23598.                                 ▒
  23599.                            B800 << 16
  23600.                                 ▒
  23601.            ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  23602.            ▒                    ▒
  23603.                       ┌────────────────┐
  23604.       B 8     0 0      │  0 0   │  0 0   │
  23605.      └───────────┘     └────────┴────────┘
  23606.    Discarded Values
  23607.  
  23608.      ┌────────┬────────┬────────┬────────┐
  23609.      │  0 0   │  0 0   │  B 8   │  0 0   │
  23610.      └────────┴────────┴────────┴────────┘
  23611.                        ▒
  23612.                   B800L  << 16
  23613.                        ▒
  23614.      ┌────────┬────────────────┬────────┐
  23615.      │  B 8   │  0 0   │  0 0   │  0 0   │
  23616.      └────────┴────────┴────────┴────────┘
  23617.  
  23618.    Figure 14-8. The left-shift operator.
  23619.  
  23620.    Finally, note that the far pointer does not hold the absolute address. It
  23621.    holds two quantities: segment value and offset. If, for some reason, you
  23622.    want the absolute address, you can obtain it by using the following
  23623.    expression:
  23624.  
  23625.      abs_addr = 0x10 * (far_ptr >> 16) + far_ptr & 0xFFFF;
  23626.  
  23627.    The right-shift produces the segment value; multiplying by 0x10 gives the
  23628.    segment address; and the 0xFFFF mask screens the segment value of the
  23629.    pointer, leaving just the offset. The variable abs_addr should be type
  23630.    long or unsigned long so that it can hold the entire address.
  23631.  
  23632.  Using Direct Memory Access──An Example
  23633.  
  23634.    To use DMA to access video RAM, we must declare a far pointer and
  23635.    initialize it to point to the beginning of video memory. To do so, we must
  23636.    first decide which data type to point to. Think of one page of video
  23637.    memory as 2000 character-attribute units, with each unit describing a
  23638.    particular screen location. In QuickC, two bytes constitute a short value,
  23639.    so our pointer must be a far pointer to unsigned short. Use typedef to
  23640.    make VIDMEM a synonym for that type:
  23641.  
  23642.      typedef unsigned short (far * VIDMEM);
  23643.  
  23644.    Then declare screen as a pointer of that type, as follows:
  23645.  
  23646.      VIDMEM screen;
  23647.  
  23648.    Next, you must decide which segment value to use. For the monochrome mode
  23649.    (mode 7), use 0xB000. For the CGA and CGA-compatible modes (0 through 6),
  23650.    use 0xB800. Because we must left-shift the segment value 16 bits to use it
  23651.    with a C far pointer, we represent our values as follows:
  23652.  
  23653.      #define MONMEM ((VIDMEM) (0xB000L << 16))
  23654.      #define CGAMEM ((VIDMEM) (0xB800L << 16))
  23655.  
  23656.    The L suffix makes the addresses 32-bit quantities, and the typecasting to
  23657.    type VIDMEM gives the numeric values the same type as the screen pointer.
  23658.  
  23659.    Recall that in the character-attribute pair, the low byte holds the
  23660.    character and the high byte holds the attribute. Therefore, if screen is
  23661.    the pointer to the beginning of video memory, if offset is the character
  23662.    position we wish to set, and if ch and attrib are character and attribute
  23663.    values, we use the following statement:
  23664.  
  23665.      *(screen + offset) = (attrib << 8) | ch;
  23666.  
  23667.    The left-shift puts attrib into the high byte, and the bitwise OR operator
  23668.    combines the resulting values, as shown in Table 14-5. Note that in
  23669.    QuickC, attrib must be at least a 16-bit type. If it is an 8-bit type, the
  23670.    significant bits are lost. (With older versions of Microsoft C, type char
  23671.    was converted to int for calculation, and no bits were discarded.)
  23672.  
  23673.    Let's use this information in a simple program. The CH2000.C program
  23674.    (Listing 14-7 on the following page) echoes any pressed ASCII key.
  23675.    However, instead of echoing it once, the program uses DMA to echo it 2000
  23676.    times. Also, the program cycles through all possible attribute values,
  23677.    making the color version more spectacular than the monochrome version. (Be
  23678.    sure Screen Swapping On is active. Also, use CGAMEM instead of MONMEM if
  23679.    you are using a color display.)
  23680.  
  23681.    The program first reads a character. The for loop displays the character
  23682.    at all 2000 positions. By using the increment operator on attrib, we
  23683.    change the attribute at each position and cycle through all 256
  23684.    possibilities.
  23685.  
  23686.    Table 14-5 Manipulating Character and Attribute in RAM
  23687.    Byte(s)            Bit Values                           Hex Equivalents
  23688.    ──────────────────────────────────────────────────────────────────────────
  23689.    attrib             00000000 00000111                    0x0007
  23690.    attrib << 8        00000111 00000000                    0x0700
  23691.    ch                 01000001                             0x41
  23692.    (attrib << 8) | ch 00000111 01000001                    0x0741
  23693.    ──────────────────────────────────────────────────────────────────────────
  23694.  
  23695.    ──────────────────────────────────────────────────────────────────────────
  23696.    /* ch2000.c -- fills screen with 2000 characters       */
  23697.    /*    This program demonstrates direct memory access   */
  23698.    /*    of video memory.  It is set up for the MDA.      */
  23699.    /*    Assign CGAMEM instead of MONMEM to screen for    */
  23700.    /*    CGA and CGA-compatible modes.                    */
  23701.    /*    Press a key to fill; press Esc to quit.          */
  23702.    /* Note: activate Screen Swapping On in Debug menu     */
  23703.  
  23704.    #include <conio.h>
  23705.    #include "scrn.h"
  23706.    typedef unsigned short (far * VIDMEM);
  23707.    #define MONMEM ((VIDMEM) (0xB000L << 16)) /* monochrome */
  23708.    #define CGAMEM ((VIDMEM) (0xB800L << 16)) /* CGA, EGA */
  23709.    #define ESC '\033'
  23710.    #define CHARS 2000
  23711.    #define AMASK 0xFF   /* keep attribute in range */
  23712.    main()
  23713.    {
  23714.        unsigned ch;          /* character to be displayed */
  23715.        unsigned attrib = 7;  /* initial attribute         */
  23716.        VIDMEM screen;        /* pointer to video RAM      */
  23717.        int offset;           /* location on screen        */
  23718.  
  23719.        screen = MONMEM;      /* monochrome initialization */
  23720.        while ((ch = getch()) != ESC)
  23721.            {
  23722.            for (offset = 0; offset < CHARS; offset++)
  23723.                *(screen + offset) = ((attrib++ & AMASK) << 8) | ch;
  23724.            }
  23725.    }
  23726.    ──────────────────────────────────────────────────────────────────────────
  23727.  
  23728.    Listing 14-7.  The CH2000.C program.
  23729.  
  23730.    Notice how quickly the program fills the screen. To appreciate the speed
  23731.    of this program, rewrite it using the BIOS-based Write_ch_atr() function
  23732.    from SCRFUN.LIB and note the difference!
  23733.  
  23734.  Making DMA More Compatible
  23735.  
  23736.    CH2000.C is fast and simple, but it doesn't work with all controllers. The
  23737.    program needs to be able to choose the correct memory value itself.
  23738.    Function 15 of the BIOS 0x10 video I/O interrupt enables it to do so.
  23739.    Because this routine returns the current video mode, the program can use
  23740.    that value to select the right video RAM address. Our SCRFUN.C file
  23741.    includes the Getvmode() function (Listing 14-8) based on that BIOS call.
  23742.    Note that the constant GETMODE is defined in the scrn.h file.
  23743.  
  23744.    Now rewrite CH2000.C as shown in the CH2001.C program (Listing 14-9). The
  23745.    constants TEXTMONO, TEXTBW80, and TEXTC80 are defined in scrn.h; they
  23746.    represent mode 7 (monochrome), mode 2 (CGA 80-by-25 B/W), and mode 3 (CGA
  23747.    80-by-25 Color), respectively.
  23748.  
  23749.    ──────────────────────────────────────────────────────────────────────────
  23750.    #include <dos.h>
  23751.    #include "scrn.h"
  23752.    /* Getvmode() -- obtains the current video mode */
  23753.    unsigned char Getvmode()
  23754.    {
  23755.        union REGS reg;
  23756.  
  23757.        reg.h.ah = GETMODE;
  23758.        int86(VIDEO, ®, ®);
  23759.        return reg.h.al;
  23760.    }
  23761.    ──────────────────────────────────────────────────────────────────────────
  23762.  
  23763.    Listing 14-8.  The Getvmode() function.
  23764.  
  23765.    ──────────────────────────────────────────────────────────────────────────
  23766.    /* ch2001.c -- fills screen with 2000 characters       */
  23767.    /*    This program demonstrates direct memory access   */
  23768.    /*    of video memory.  It uses the current video mode */
  23769.    /*    value to select the proper video RAM address.    */
  23770.    /*    Press a key to fill; press Esc to quit.          */
  23771.    /* Program list: ch2001.c, scrfun.lib                  */
  23772.    /* Note: activate Screen Swapping On in Debug menu     */
  23773.  
  23774.    #include <conio.h>
  23775.    #include "scrn.h"
  23776.    typedef unsigned short (far * VIDMEM);
  23777.    #define MONMEM ((VIDMEM) (0xB000L << 16)) /* monochrome */
  23778.    #define CGAMEM ((VIDMEM) (0xB800L << 16)) /* CGA, EGA */
  23779.    #define ESC '\033'
  23780.    #define CHARS 2000
  23781.    #define AMASK 0xFF
  23782.    main()
  23783.    {
  23784.         unsigned ch, mode;
  23785.         unsigned attrib = 7;
  23786.         VIDMEM screen;         /* pointer to video RAM */
  23787.         int offset;
  23788.  
  23789.         if ((mode = Getvmode()) == TEXTMONO)
  23790.              screen = MONMEM;
  23791.         else if (mode == TEXTC80 || mode == TEXTBW80)
  23792.              screen = CGAMEM;
  23793.         else
  23794.              exit(1);
  23795.         while ((ch = getch()) != ESC)
  23796.              {
  23797.              for (offset = 0; offset < CHARS; offset++)
  23798.                  *(screen + offset) = ((attrib++ & AMASK) << 8) | ch;
  23799.              }
  23800.    }
  23801.    ──────────────────────────────────────────────────────────────────────────
  23802.  
  23803.    Listing 14-9.  The CH2001.C program.
  23804.  
  23805.  Storing and Displaying a Screen
  23806.  
  23807.    Let's use DMA to add some useful capabilities to the GRAFCHAR.C program.
  23808.    Although this program lets you draw on the screen using the graphics
  23809.    character set, when you quit the program, the drawing is lost. The program
  23810.    would be more useful if it let you store the created image in a file so
  23811.    you could use it later.
  23812.  
  23813.    DMA is ideally suited to copying information from the screen to a file and
  23814.    back again. We can incorporate the saving code into the program and make
  23815.    the recall a separate program.
  23816.  
  23817.    Saving the Screen
  23818.  
  23819.    To save the screen, rewrite the main program as SAVEGRAF.C (Listing
  23820.    14-10). In addition, we need to add some new definitions to the
  23821.    grafchar.h file. Listing 14-11 shows the new version. Be sure Screen
  23822.    Swapping On is active (on the Debug menu) before you run the program.
  23823.  
  23824.    ──────────────────────────────────────────────────────────────────────────
  23825.    /* savegraf.c -- uses DMA to save screen of graphics  */
  23826.    /*               characters and attributes            */
  23827.    /* Program list - savegraf.c, initstuf.c, drawchar.c, */
  23828.    /*                savescrn.c, scrfun.lib              */
  23829.    /* User include files - scrn.h, keys.h, grafchar.h    */
  23830.    /* Note: activate Screen Swapping On in Debug menu    */
  23831.  
  23832.    #include "grafchar.h"
  23833.    unsigned char Grchr[NUMCHARS];  /* to store graphics set */
  23834.    void Init_stuff(void);
  23835.    void Draw_chars(void);
  23836.    void Save_screen(void);  /* in savescrn.c */
  23837.  
  23838.    main()
  23839.    {
  23840.        int ch;
  23841.  
  23842.        Init_stuff();  /* initialize vital elements */
  23843.        Draw_chars();  /* map keys to graphics characters */
  23844.        Setcurs(BOTLINE + 1, 0, PAGE);
  23845.        printf("%-80s", "Save screen? <y/n> ");
  23846.        Setcurs(BOTLINE + 1, 20, PAGE);
  23847.        ch = getche();
  23848.        if (ch == 'y' || ch == 'Y')
  23849.            Save_screen();
  23850.        Setcurs(BOTLINE + 2, 0, PAGE);
  23851.        printf("%-80s\n", "BYE!");
  23852.    }
  23853.    ──────────────────────────────────────────────────────────────────────────
  23854.  
  23855.    Listing 14-10.  The SAVEGRAF.C program.
  23856.  
  23857.    ──────────────────────────────────────────────────────────────────────────
  23858.    /* grafchar.h -- definitions for savescrn.c and       */
  23859.    /*               recall.c   Version 2                 */
  23860.    #define NUMCHARS 48
  23861.    #define SPACE '\040'
  23862.    #define BOTLINE 19  /* line # for end of drawing space */
  23863.    #define PAGE 0
  23864.    #define GCSTART 0xB0 /* ascii for first graphics char */
  23865.    #define BEEP '\a'
  23866.    #define ESC '\033'
  23867.    #define TRUE 1
  23868.    #define FALSE 0
  23869.    #define CHARS (BOTLINE + 1) * 80  /*    number of     */
  23870.                                   /* character positions */
  23871.    typedef unsigned short (far * VIDMEM);
  23872.    #define MONMEM ((VIDMEM) (0xB000L << 16)) /* mono */
  23873.    #define CGAMEM ((VIDMEM) (0xB800L << 16)) /* CGA, EGA */
  23874.    ──────────────────────────────────────────────────────────────────────────
  23875.  
  23876.    Listing 14-11.   The revised grafchar.h header file.
  23877.  
  23878.    The SAVEGRAF.C program uses Setcurs() to position the text outside the
  23879.    drawing area. If the user chooses to save the screen, the Save_screen()
  23880.    function (Listing 14-12) does the work.
  23881.  
  23882.    Program Notes
  23883.  
  23884.    Because line numbering starts with 0, there are BOTLINE + 1 total lines.
  23885.    Therefore, the total number of character-attribute pairs that must be
  23886.    saved is that figure times 80; CHARS is defined as that value.
  23887.  
  23888.    ──────────────────────────────────────────────────────────────────────────
  23889.    /* savescrn.c -- saves screen, including attribute    */
  23890.    /*               values, in a file                    */
  23891.    /*               Uses direct memory access.           */
  23892.  
  23893.    #include <stdio.h>  /* for file handling */
  23894.    #include "scrn.h"
  23895.    #include "grafchar.h"
  23896.    void Save_screen()
  23897.    {
  23898.        FILE *save;
  23899.        char filename[80];
  23900.        unsigned char mode;
  23901.        unsigned short char_attr;  /* character, attribute */
  23902.        int offset;
  23903.        VIDMEM screen;
  23904.  
  23905.        if ((mode = Getvmode()) == TEXTMONO)
  23906.            screen = MONMEM;
  23907.        else if (mode == TEXTC80 || mode == TEXTBW80)
  23908.            screen = CGAMEM;
  23909.        else
  23910.            exit(1);
  23911.        Setcurs(BOTLINE + 1, 0, PAGE);
  23912.        printf("Please enter name for save file: ");
  23913.        scanf("%s", filename);
  23914.        if ((save = fopen(filename, "wb")) == NULL)
  23915.            {
  23916.            fprintf(stderr, "Can't open %s\n", filename);
  23917.            exit(1);
  23918.            }
  23919.        for (offset = 0; offset < CHARS; offset++)
  23920.            {
  23921.            char_attr = screen[offset];
  23922.            fwrite(&char_attr, 2, 1, save);
  23923.            }
  23924.        fclose(save);
  23925.    }
  23926.    ──────────────────────────────────────────────────────────────────────────
  23927.  
  23928.    Listing 14-12.  The Save_screen()< function.
  23929.  
  23930.    In general, screen + offset points to the character-attribute offset
  23931.    positions from the beginning of video RAM. The value of that pair is
  23932.    *(screen + offset), which can also be written as screen[offset].
  23933.  
  23934.    The standard I/O function fwrite() copies the contents of screen memory
  23935.    one character-attribute pair at a time. This function takes four
  23936.    arguments: a pointer to a memory location, the number of bytes per display
  23937.    unit (here 2), the number of units to be copied, and a file stream
  23938.    pointer. The program first copies the video pair to char_attr because, in
  23939.    the default medium memory model used by QuickC, fwrite() expects a near
  23940.    pointer. In the large memory model, you could replace the for loop with
  23941.    the following code:
  23942.  
  23943.      fwrite(screen, 2, CHARS, save);  /* large model */
  23944.  
  23945.    Thus, in the large memory model, fwrite() uses a far pointer and can
  23946.    access video RAM directly. By specifying CHARS units to be copied by the
  23947.    function, you can dispense with the loop.
  23948.  
  23949.    Recovering the Screen
  23950.  
  23951.    To recover the stored screen, we need to reverse the storage process. That
  23952.    is, the program should open the file in the read mode. The
  23953.    attribute-character pairs found there should then be copied into the video
  23954.    memory, a natural task for DMA. From these basic techniques we develop the
  23955.    RECALL.C program (Listing 14-13). (To run the program, be sure that
  23956.    Screen Swapping On is active.)
  23957.  
  23958.    ──────────────────────────────────────────────────────────────────────────
  23959.    /* recall.c -- displays previously stored screen,     */
  23960.    /*             including attributes.  Uses DMA.       */
  23961.    /* Program list: recall.c, scrfun.lib                 */
  23962.    /* User include files: scrn.h, grafchar.h             */
  23963.    /* Note: activate Screen Swapping On in Debug menu      */
  23964.  
  23965.    #include <stdio.h>
  23966.    #include <conio.h>
  23967.    #include "scrn.h"
  23968.    #include "grafchar.h"
  23969.  
  23970.    main(ac, ar)
  23971.    int ac;
  23972.    char *ar[];
  23973.    {
  23974.         unsigned char mode;
  23975.         unsigned short char_attr;
  23976.         FILE *save;
  23977.         unsigned int offset;
  23978.         char filename[81];
  23979.         VIDMEM screen;
  23980.  
  23981.         if (ac < 2)
  23982.              {
  23983.              fprintf(stderr, "Usage: %s filename\n", ar[0]);
  23984.              exit(1);
  23985.              }
  23986.  
  23987.         if ((save = fopen(ar[1], "rb")) == NULL)
  23988.              {
  23989.              fprintf(stderr, "Can't open %s\n", ar[1]);
  23990.              exit(1);
  23991.              }
  23992.  
  23993.         if ((mode = Getvmode()) == TEXTMONO)
  23994.              screen = MONMEM;
  23995.         else if (mode == TEXTC80 || mode == TEXTBW80)
  23996.              screen = CGAMEM;
  23997.         else
  23998.              exit(1);
  23999.  
  24000.         Clearscr();
  24001.         for (offset = 0; offset < CHARS; offset++)
  24002.              {
  24003.              fread(&char_attr, 2, 1, save);
  24004.              screen[offset] = char_attr;
  24005.              }
  24006.         fclose(save);
  24007.         Setcurs(23, 0, PAGE);
  24008.         getch();   /* anti-scrolling for QC environment */
  24009.    }
  24010.    ──────────────────────────────────────────────────────────────────────────
  24011.  
  24012.    Listing 14-13.  The RECALL.C program.
  24013.  
  24014.    In the program, fread() recovers from the files what fwrite() placed into
  24015.    them. The Setcurs() call positions the MS-DOS prompt outside the drawing
  24016.    area when the program ends. The getch() call simply requires the user to
  24017.    press a key to terminate the program. Without this code, when you run the
  24018.    program in the QuickC environment, the QuickC prompt causes the screen to
  24019.    scroll up when the program ends. It still causes scrolling with this
  24020.    program, but not until you press a key.
  24021.  
  24022.  
  24023.  Paging
  24024.  
  24025.    Now let's turn to a text topic that lies beyond the scope of the
  24026.    Monochrome Display Adapter── paging. The CGA, EGA, and VGA have enough
  24027.    memory to store more than one screenful, or page, of text. The 16 KB video
  24028.    memory of the CGA, for example, can hold four text pages. The BIOS
  24029.    supports the use of pages by providing routines for setting the page and
  24030.    for determining the current page number. Many other BIOS routines require
  24031.    page information. The SCRFUN.C file we developed in Chapter 13 contains
  24032.    two page-related functions──Getpage() and Setpage(), which are combined in
  24033.    Listing 14-14. As usual, the manifest constants are defined in scrn.h.
  24034.  
  24035.    Paging is very fast, even compared to DMA, because the video RAM doesn't
  24036.    need to be rewritten. The video controller simply changes the section of
  24037.    video memory that it reads. A typical application for paging stores a help
  24038.    screen on one page, while an application uses another page. This permits a
  24039.    rapid transition between the two screens without calling data from program
  24040.    memory or a disk file.
  24041.  
  24042.    ──────────────────────────────────────────────────────────────────────────
  24043.    /* Getpage() -- obtains the current video page */
  24044.    unsigned char Getpage()
  24045.    {
  24046.        union REGS reg;
  24047.  
  24048.        reg.h.ah = GETMODE;
  24049.        int86(VIDEO, ®, ®);
  24050.        return reg.h.bh;
  24051.    }
  24052.    /* Setpage() -- sets page to given value */
  24053.    void Setpage(page)
  24054.    unsigned char page;
  24055.    {
  24056.        union REGS reg;
  24057.  
  24058.        reg.h.ah = SETPAGE;
  24059.        reg.h.al = page;
  24060.        int86(VIDEO, ®, ®);
  24061.    }
  24062.    ──────────────────────────────────────────────────────────────────────────
  24063.  
  24064.    Listing 14-14.  The Getpage() and Setpage() functions.
  24065.  
  24066.    Let's develop a basic program that can switch back and forth between page
  24067.    0 and a help screen on page 1. We could use BIOS calls to write the
  24068.    contents of the two screens, but direct memory access is faster. However,
  24069.    to use direct memory access, we need to supply the address of page 1.
  24070.    Because each page holds 2000 character-attribute pairs, or 4000 bytes, you
  24071.    might expect that page 1 is offset 4000 bytes from the beginning of video
  24072.    memory. But computers relate more to powers of 2 than to powers of 10, so
  24073.    the actual offset is 4096 bytes, 0x1000 in hex. (You can use the extra
  24074.    bytes between pages to color in page borders.)
  24075.  
  24076.    We use the VIDMEM type pointer again to point to video memory. Because we
  24077.    define it to point to a 2-byte unit (the character-attribute pair), the
  24078.    offset in VIDMEM units is 2048 pairs, which is 0x800 in hex.
  24079.  
  24080.    The HELP.C program (Listing 14-15) is fairly simple. (Be sure Screen
  24081.    Swapping On is active before you run it.) The key points to note are its
  24082.    use of Setpage() to change pages and its use of direct memory access to
  24083.    write to the screen. The program uses two direct memory access modules.
  24084.    The writechr.c module (Listing 14-16 on the following page) writes a
  24085.    character-attribute pair a specified number of times beginning at a
  24086.    specified memory location. The writestr.c module (Listing 14-17 on p.
  24087.    483) is similar, but it writes a string once instead of a single character
  24088.    repeatedly. By choosing the appropriate memory location, you can use these
  24089.    functions to write to either page, no matter which one is currently
  24090.    displayed. For convenience, we've collected definitions of the colors in a
  24091.    file called color.h (Listing 14-18 on p. 483).
  24092.  
  24093.    ──────────────────────────────────────────────────────────────────────────
  24094.    /*  help.c -- uses paging and direct memory access    */
  24095.    /*            to display a help screen                */
  24096.    /*  Program list: help.c, writestr.c, writechr.c,     */
  24097.    /*                scrfun.lib                          */
  24098.    /*  User include files: scrn.h, color.h               */
  24099.    /*  Note: activate Screen Swapping On in Debug menu   */
  24100.  
  24101.    #include <stdio.h>
  24102.    #include <conio.h>
  24103.    #include "color.h"
  24104.    #include "scrn.h"
  24105.    typedef unsigned int (far * VIDMEM);
  24106.    #define CGAMEM ((VIDMEM) (0xB800L << 16))
  24107.    #define PAGESIZE 2000
  24108.    #define PAGEOFFSET 0x800L
  24109.    #define ESC '\033'
  24110.    #define ATTR1 (BG_BLUE | YELLOW)
  24111.    #define ATTR2 (BG_YELLOW | BLUE)
  24112.    #define ATTR3 (BG_RED | YELLOW | BLINK | INTENSE)
  24113.    #define CH1 (unsigned short) '\xB1'
  24114.    char *str1 = "Press ? key for help.";
  24115.    char *str2 = "Press Enter key to return.";
  24116.    char *str3 = "Press ESC key to quit.";
  24117.    char *str4 = "\xB1HELP!\xB1";
  24118.    void Write_chars(VIDMEM, unsigned short, unsigned
  24119.                        short, unsigned short);
  24120.    void Write_str(VIDMEM, unsigned short, char *);
  24121.    main()
  24122.    {
  24123.        int ch;
  24124.        unsigned char page = 0;
  24125.        unsigned char mode;
  24126.  
  24127.        mode = Getvmode();
  24128.        if (mode != TEXTC80 && mode != TEXTBW80)
  24129.            {
  24130.            printf("Only modes 2 and 3 supported. Bye.\n");
  24131.            exit(1);
  24132.            }
  24133.        Setpage(page);
  24134.        Write_chars(CGAMEM, '\0', ATTR2, PAGESIZE);
  24135.        Write_str(CGAMEM + 2 * COLS, ATTR1, str1);
  24136.        Write_str(CGAMEM + 2 * COLS, ATTR1, str1);
  24137.        Write_str(CGAMEM + 22 * COLS, ATTR1, str3);
  24138.        Write_chars(CGAMEM + PAGEOFFSET, '\0', ATTR1, PAGESIZE);
  24139.        Write_str(CGAMEM + PAGEOFFSET + 20 * COLS, ATTR2, str2);
  24140.        Write_str(CGAMEM + PAGEOFFSET + 22 * COLS, ATTR1, str3);
  24141.        Write_chars(CGAMEM + PAGEOFFSET + 10 * COLS + 36,
  24142.                    CH1, ATTR3, 7);
  24143.        Write_str(CGAMEM + PAGEOFFSET + 11 * COLS + 36,
  24144.                  ATTR3, str4);
  24145.        Write_chars(CGAMEM + PAGEOFFSET + 12 * COLS + 36,
  24146.                    CH1, ATTR3, 7);
  24147.  
  24148.        while ((ch = getch()) != ESC)
  24149.            {
  24150.            if (ch == '?' && page == 0)
  24151.                Setpage(page = 1);
  24152.            else if (ch == '\r' && page == 1)
  24153.                Setpage(page = 0);
  24154.            }
  24155.        Write_chars(CGAMEM, '\0', NORMAL, PAGESIZE);
  24156.        Write_chars(CGAMEM + PAGEOFFSET, '\0', NORMAL, PAGESIZE);
  24157.    }
  24158.    ──────────────────────────────────────────────────────────────────────────
  24159.  
  24160.    Listing 14-15.  The HELP.C program.
  24161.  
  24162.    ──────────────────────────────────────────────────────────────────────────
  24163.    /* writechr.c -- writes char and attribute repeatedly */
  24164.    /*               using DMA                            */
  24165.    /* write character ch with attribute attr num times   */
  24166.    /* starting at location pstart -- uses array notation */
  24167.  
  24168.    typedef unsigned int (far * VIDMEM);
  24169.  
  24170.    void Write_chars(pstart, ch, attr, num)
  24171.    VIDMEM pstart;
  24172.    unsigned short ch, attr, num;
  24173.    {
  24174.        register count;
  24175.        unsigned short pair;
  24176.        pair = (attr << 8) | (ch & 0x00FF) ;
  24177.        for (count = 0; count < num; count++)
  24178.            pstart[count] = pair;
  24179.    }
  24180.    ──────────────────────────────────────────────────────────────────────────
  24181.  
  24182.    Listing 14-16.  The writechr.c module.
  24183.  
  24184.    ──────────────────────────────────────────────────────────────────────────
  24185.    /*  writestr.c -- writes string and attribute using DMA */
  24186.    /*  Write the string str with attribute attr at         */
  24187.    /*  location pstart -- uses pointer notation.           */
  24188.  
  24189.    typedef unsigned int (far * VIDMEM);
  24190.  
  24191.    void Write_str(pstart, attr, str)
  24192.    VIDMEM pstart;
  24193.    unsigned short attr;
  24194.    char *str;
  24195.    {
  24196.        while (*str != '\0')
  24197.            *pstart++ = (attr << 8) | (*str++ & 0x00FF);
  24198.    }
  24199.    ──────────────────────────────────────────────────────────────────────────
  24200.  
  24201.    Listing 14-17.  The writestr.c module.
  24202.  
  24203.    ──────────────────────────────────────────────────────────────────────────
  24204.    /* color.h -- defines the color attributes  */
  24205.       /* foreground colors */
  24206.    #define  BLACK   0x0
  24207.    #define  BLUE    0x1
  24208.    #define  GREEN   0x2
  24209.    #define  RED     0x4
  24210.    #define  CYAN    0x3
  24211.    #define  MAGENTA 0x5
  24212.    #define  YELLOW  0x6
  24213.    #define  WHITE   0x7
  24214.       /* background colors */
  24215.    #define  BG_BLACK   0x00
  24216.    #define  BG_BLUE    0x10
  24217.    #define  BG_GREEN   0x20
  24218.    #define  BG_RED     0x40
  24219.    #define  BG_CYAN    0x30
  24220.    #define  BG_MAGENTA 0x50
  24221.    #define  BG_YELLOW  0x60
  24222.    #define  BG_WHITE   0x70
  24223.    ──────────────────────────────────────────────────────────────────────────
  24224.  
  24225.    Listing 14-18.  The color.h include file.
  24226.  
  24227.    Most of the HELP.C program involves using the new Write_chars() and
  24228.    Write_str() functions, so let's examine them. The two functions are quite
  24229.    similar in behavior, but to illustrate different programming techniques,
  24230.    one uses array notation and the other uses pointer notation.
  24231.  
  24232.    Write_chars() starts by combining the attribute and character into a
  24233.    2-byte unit. It left-shifts the attribute into the high byte and places
  24234.    the character in the low byte. Next, the function performs a logical AND
  24235.    operation with the character and 0x00FF to limit the character to the
  24236.    range 0 through 0xFF, or 0 through 255. Next, a loop assigns the 2-byte
  24237.    pair to num consecutive locations in memory, beginning with the location
  24238.    pointed to by pstart. Recall that the notation pstart[count] is equivalent
  24239.    to *(pstart + count).
  24240.  
  24241.    In the program, Write_chars() clears the two pages, setting them to yellow
  24242.    and blue, respectively. To clear the screen, the program sets the
  24243.    character part of the byte to a null character; the attribute sets the
  24244.    color.
  24245.  
  24246.    The Write_str() function uses pointer notation to display a string. Like
  24247.    the preceding function, it combines the left-shifted attribute with a
  24248.    masked character value. In this case, str initially points to the first
  24249.    character in the string, so *str represents the value of that character.
  24250.    The while loop continues until it reaches the terminating null character
  24251.    of the string. During each cycle, the increment operator advances the
  24252.    video memory pointer and the string pointer after they are used.
  24253.  
  24254.    In the main program, note how we use addresses to specify locations on the
  24255.    screen. Consider, for example, the following statement:
  24256.  
  24257.      Write_str(CGAMEM + PAGEOFFSET + 11 * COLS + 36,
  24258.                ATTR3, str4);
  24259.  
  24260.    The address CGAMEM locates the beginning of the CGA (and EGA and VGA)
  24261.    memory. The PAGEOFFSET value is the offset to the beginning of the next
  24262.    page. Each line contains COLS characters, so the expression 11 * COLS is
  24263.    the offset to the beginning of line 11 (the twelfth line, because
  24264.    numbering starts with zero). Finally, the 36 gives the offset, or the
  24265.    indention measured in character widths, from the left side of the display.
  24266.  
  24267.    Note that the QuickC Graphics Library provides alternatives to many of our
  24268.    BIOS-based functions, including functions that clear the screen and set
  24269.    the page. However, using the Graphics Library produces final code
  24270.    noticeably larger than that of our examples. We use the Graphics Library
  24271.    only in graphics programs, in which its power and generality become
  24272.    evident.
  24273.  
  24274.  
  24275.  Ports
  24276.  
  24277.    Any discussion of hardware-dependent programming methods must mention
  24278.    "ports," which are information conduits between the CPU and the other
  24279.    devices and processors in a PC. In general, each processor or device has
  24280.    one or more registers of its own. Values placed in these registers can
  24281.    control the operation of the processor or, perhaps, test its state of
  24282.    readiness. In the PC, various registers are assigned "port addresses" that
  24283.    are completely separate from the memory address system and are handled
  24284.    differently. The CPU accesses registers through ports by using special
  24285.    port instructions. (See Figure 14-9.)
  24286.  
  24287.    An 8086 CPU can address as many as 64,000 8-bit ports, but only a small
  24288.    fraction of that number (fewer than 200) are actually used. In assembly
  24289.    language, you access the ports with the instructions IN and OUT: IN reads
  24290.    a register; OUT writes to it. C does not contain these instructions, so
  24291.    QuickC supplies the non-ANSI inp() and outp() functions to serve the same
  24292.    purpose.
  24293.  
  24294.  Reading Ports with inp()
  24295.  
  24296.    As mentioned in Chapter 13, the inp() and outp() functions are defined in
  24297.    conio.h. The following is the syntax for inp():
  24298.  
  24299.      #include <conio.h>
  24300.  
  24301.      int inp(port)
  24302.      unsigned port;    /* port number */
  24303.  
  24304.    This function reads the register at port number port, which can be a value
  24305.    in the range 0 through 65,535. It then returns the byte it reads. With
  24306.    write-only ports, inp() returns the value 255, or all bits set to 1.
  24307.    However, a return value of 255 does not always signal a write-only
  24308.    register because 255 is also a valid register setting.
  24309.  
  24310.                        ┌───────────────────┐
  24311.                        │ Video controller  │
  24312.                        │    ┌─────────┐    │
  24313.                        │    │register │    │
  24314.                        └────┴────╥────┴────┘
  24315.    ┌───────────┐                 ║
  24316.    │         ┌─┤                 ║
  24317.    │         │ │──Port 0x3B8    ║
  24318.    │         │ ╞═════════════════╝
  24319.    │   CPU   └─┤
  24320.    │         ┌─┤
  24321.    │         │ ╞═════════════════╗
  24322.    │         │ │──Port 0x67     ║
  24323.    │         └─┤                 ║
  24324.    └───────────┘                 ║
  24325.                        ┌────┬────╨────┬────┐
  24326.                        │    │register │    │
  24327.                        │    └─────────┘    │
  24328.                        │ Speaker controller│
  24329.                        └───────────────────┘
  24330.  
  24331.    Figure 14-9. Ports and registers.
  24332.  
  24333.    The short PORTINFO.C program (Listing 14-19) lets you access and read
  24334.    various ports. Note that it uses the return value of scanf() to terminate
  24335.    the input loop. We prompt for hexadecimal port numbers because technical
  24336.    manuals usually list them in that form. Note that scanf() returns a value
  24337.    equal to the number of successful reads. Therefore, if it reads a hex
  24338.    value, it returns 1. If it finds input that is not hex, such as the letter
  24339.    q, scanf() returns 0, and the loop terminates.
  24340.  
  24341.    The following is a sample run:
  24342.  
  24343.      Enter number (in hex) of the port you wish to read: 3da
  24344.      Value returned for port 3da is 199 (decimal)  c6 (hex)
  24345.      Next port? (q to quit): 61
  24346.      Value returned for port 61 is 32 (decimal)  31 (hex)
  24347.      Next port? (q to quit): 42
  24348.      Value returned for port 42 is 174 (decimal)  60 (hex)
  24349.      Next port? (q to quit): 3b8
  24350.      Value returned for port 3b8 is 255 (decimal)  ff (hex)
  24351.      Next port? (q to quit): q
  24352.  
  24353.    You may get different values from those in this sample run──some of the
  24354.    registers change values as you use the computer.
  24355.  
  24356.    In the IBM PC and compatibles, the 0x3DA port reports status information
  24357.    about the MDA. Port 61 controls the speaker, and port 42 regulates the
  24358.    frequency of the 8253 timer chip. Finally, port 3B8 is the control port
  24359.    for the 6845 video controller on the MDA. (Because the last port is a
  24360.    write-only port, the reported value is not necessarily the true one.)
  24361.  
  24362.    ──────────────────────────────────────────────────────────────────────────
  24363.    /* portinfo.c -- reads port values                    */
  24364.    /* program list -- portinfo.c (inp() not in core lib) */
  24365.  
  24366.    #include <conio.h>
  24367.    #include <stdio.h>
  24368.    main()
  24369.    {
  24370.        unsigned int portnum;
  24371.        int regvalue;
  24372.  
  24373.        printf("Enter number (in hex) of the port ");
  24374.        printf("you wish to read: ");
  24375.        while (scanf("%x", &portnum) == 1)
  24376.            {
  24377.        regvalue = inp(portnum);
  24378.        printf("\nValue returned for port %x is %d (decimal)"
  24379.               "  %x (hex)\n", portnum, regvalue, regvalue);
  24380.        printf("Next port? (q to quit): ");
  24381.            }
  24382.    }
  24383.    ──────────────────────────────────────────────────────────────────────────
  24384.  
  24385.    Listing 14-19.  The PORTINFO.C program.
  24386.  
  24387.    As you can see, reading a register is a simple procedure. The difficult
  24388.    part is wading through the technical literature to see which