Microsoft QuickC Programming


════════════════════════════════════════════════════════════════════════════


Microsoft(R) QuickC(TM) Programming

The Microsoft(R) Guide to Using the QuickC Compiler

By The Waite Group
   Mitchell Waite, Stephen Prata, Bryan Costales, and Harry Henderson


════════════════════════════════════════════════════════════════════════════


PUBLISHED BY
Microsoft Press
A Division of Microsoft Corporation
16011 NE 36th Way, Box 97017, Redmond, Washington 98073-9717

Copyright (c) 1988 by The Waite Group, Inc.
All rights reserved. No part of the contents of this book may be reproduced
or transmitted in any form or by any means without the written permission of
the publisher.

Library of Congress Cataloging in Publication Data

Microsoft QuickC programming.
Includes index.
1. C (Computer program language)  2. Microsoft QuickC (Computer program)
I. Waite, Mitchell.  II. Title: Microsoft Quick C programming.
QA76.73.C15M53    1988    005.13'3    88-5203
ISBN 1-55615-048-2

Printed and bound in the United States of America.

1 2 3 4 5 6 7 8 9  MLML  3 2 1 0 9 8

Distributed to the book trade in the United States by Harper & Row.

Distributed to the book trade in Canada by General Publishing Company, Ltd.

Distributed to the book trade outside the United States and Canada by
Penguin Books Ltd.

Penguin Books Ltd., Harmondsworth, Middlesex, England
Penguin Books Australia Ltd., Ringwood, Victoria, Australia
Penguin Books N.Z. Ltd., 182-190 Wairau Road, Auckland 10, New Zealand

British Cataloging in Publication Data available

IBM(R) is a registered trademark, and PC/AT(TM) and PC/XT(TM) are trademarks
of International Business Machines Corporation.

Microsoft(R) and MS-DOS(R) are registered trademarks, and QuickC(TM) is a
trademark of Microsoft Corporation.

────────────────────────────────────────────────────────────────────────────
Acquisitions editor: Claudette Moore
Project editor: Eric Stroo
Copy editor: Gary Masters
Technical reviewer: Doug Henderson
────────────────────────────────────────────────────────────────────────────



────────────────────────────────────────────────────────────────────────────
Contents


Preface

Acknowledgments

PART 1  INTRODUCTION TO C

Chapter 1  Introduction
           Why Learn C?
           Why QuickC?
           Hardware Requirements
           Knowledge Requirements
           Conventions and Style

Chapter 2  Starting with QuickC
           Our Book and Their Book
           Directories and Files Used by QuickC
           Running the QuickC SETUP Program
           Setting Up QuickC
           Starting QuickC
           Getting Help
           Fixing Errors
           Preparing for the Next Chapter

PART 2  CORE OF C

Chapter 3  C Fundamentals
           Basic Elements of C Programs
           Punctuation and Spacing in C Programs
           Using Comments in C
           Data Types and Declarations of Variables
           The Power of printf()
           Arithmetic Operators
           Getting Input with scanf()
           Shortcut Assignments, Increments, and Decrements
           Relational Operators
           Logical Operators

Chapter 4  Repetition and Looping
           The for Loop
           The while Loop
           The do Loop
           Debugging and Loops

Chapter 5  Decisions and Branching
           The if Statement
           The Conditional Assignment Statement ?
           Multipath Branching
           The switch Statement
           The break Statement
           The continue Statement
           The goto Statement
           More Complex Conditions for Branching

Chapter 6  Functions and Function Calls
           Functions and Program Design
           Declaring and Defining a Function
           Local and Automatic Variables
           Static Variables
           External Variables
           Register Variables
           Passing Information to a Function
           Functions with Many Parameters
           Functions That Return Information
           Recursion
           Noninteger Functions
           Function Prototypes
           Putting It All Together: A Larger Program

PART 3  ADVANCED C TOPICS

Chapter 7  Arrays
           How Arrays Are Stored in Memory
           How to Declare Arrays
           Referencing and Using Array Items
           Bounds Checking Arrays in Your Code
           How to Initialize Arrays
           Arrays and Functions
           How Array Offsets Advance
           Multidimensional Arrays
           Advanced Topics and Tricks
           The Bitwise Operators, Tiny Arrays

Chapter 8  Addresses and Pointers
           Addresses Reviewed
           What Is a Pointer?
           Accessing Variables with Pointers
           Passing Pointers to Functions
           Pointers and Arrays
           Pointer Arithmetic
           The Interchangeability of *amts and amts[]
           lvalue vs rvalue
           Type Casting Pointers and Addresses
           far Pointers
           Functions That Return Addresses
           Dynamic Arrays
           Advanced Pointer Techniques

Chapter 9  Strings
           Declaring and Initializing Strings
           The String Pool and String Addresses
           Pointers and Initialized Strings
           Formatting Strings with printf()
           String Input and Output
           String Manipulation Routines
           Arrays and Strings
           The Arguments to main()──argv and argc
           Character Classification and Transformation

Chapter 10 Managing Files
           Top-level I/O
           Mid-Level (Unbuffered) File I/O
           The File System
           Advanced Error Handling

Chapter 11 Advanced Data Types
           Structure──An Array of Different Types
           Union──Multiple Types in the Same Space
           Enumerated Data with enum
           Bit Fields
           Advanced typedef

Chapter 12 Large Projects
           Advanced C Preprocessor
           Using QuickC for Large Projects

PART 4  C AND THE HARDWARE

Chapter 13 Keyboard and Cursor Control
           Keyboard Input Functions
           Reading Non-ASCII Keys
           Console I/O Functions
           Keyboard Control with ANSI.SYS
           Using QuickC to Access the BIOS
           Cursor and Screen Control with BIOS Calls

Chapter 14 Monitors and Text Modes
           Monitors and Controllers
           Text Modes and Portability
           Device-independent Programming
           Direct Memory Access
           Paging
           Ports
           The EGA and VGA

Chapter 15 Graphics and QuickC
           The Graphics Modes
           CGA Graphics
           EGA Graphics
           VGA Graphics

Chapter 16 Debugging
           Keyboard-Entry Errors
           Syntax Errors
           Run-Time Errors
           Common Run-Time Errors
           Design Errors

Appendix A  Some Resources for C Programmers

Appendix B  Built-in QuickC Functions

Index



────────────────────────────────────────────────────────────────────────────
Preface

   The Waite Group has written books on all aspects of the C language, from
   primers to advanced texts that mix C with assembly language☼ But when
   Microsoft Press suggested we write a book on Microsoft's then unreleased
   QuickC compiler, we were skeptical. Having spent years trying to teach C
   both in the classroom and through our books, we were painfully aware of
   how difficult a language it is to learn. Despite its power, the Microsoft
   C Compiler has confounded many an eager student. Daunted by the cryptic
   syntax of its command-line interface, they slipped from C's learning curve
   and disappeared beneath its power curve.

   Our first look at the QuickC beta version sparked our attention──this was
   no standard C compiler. QuickC's interface was profoundly different: The
   editor completely integrated into the compiler, optional mouse
   compatibility, drop-down menus, full color display, the list went on and
   on. Finally we had point-and-click compiling. To us, all this meant a
   radical shift in the way we could teach C──we could take a friendly
   approach that would make C accessible to a much larger group of people.

   But was QuickC really a performance program? Were we talking fast object
   code or code more suited to timing traffic signals at snail races? Well,
   after creating hundreds of examples for this book, we can report that
   QuickC lives up to its speedy expectations. A product that can compile
   more than 10,000 lines per minute should satisfy all but the most jaded of
   hackers.

   There was more. QuickC was fully compatible with the libraries of version
   5.0 of the Microsoft C Optimizing Compiler. We could develop our C code in
   QuickC's fast and friendly interface, get the errors out quickly with its
   integrated debugger and tracer, and then optimize our program for
   execution time by compiling it under the standard optimizing compiler.
   With the introduction of QuickC, we felt that C had finally reached the
   point of rivaling BASIC in ease of use. We saw in QuickC a product that
   could vitalize the learning of C and reinforce its dominance in
   professional program development.

   As educators, we saw that QuickC was an opportunity to build a complete
   course in the C language, one that could be pursued without an instructor
   and that would be attractive to beginners and professionals alike. The
   seductive interface made QuickC a breeze to run──we could focus on the
   syntax rather than on complicated command-line options and batch files. On
   top of this, QuickC's large and comprehensive Graphics Library meant that
   we could make our examples visually appealing and challenging. By assuming
   an IBM personal computer running MS-DOS or PC-DOS, we could tackle the
   sensitive issues of the interface between MS-DOS and C while at the same
   time flexing the keyboard, text, and bitmapped displays.

   After all these grandiose thoughts, the next thing we did was very
   natural──we gulped loudly. In the time available, no single author could
   possibly master a product as rich as QuickC with the aim of writing a book
   that examines thoroughly its vast repertoire. The solution was to pool the
   energies of four experienced C authors with over 25 years of combined
   programming and teaching experience, each writer focusing on a different
   section of the book. We think you will find that this book goes beyond
   most C books on the market (including our own). If you have any questions
   or comments, please address them to: The Waite Group, 3220 Sacramento
   Street, San Francisco, California 94115.

   Mitchell Waite
   Stephen Prata
   Bryan Costales
   Harry Henderson



────────────────────────────────────────────────────────────────────────────
Acknowledgments

   The authors would like to take this opportunity to thank the people at
   Microsoft Press for helping to make this book a success: Claudette Moore,
   for acquiring this title and putting up with the authors' numerous
   requests throughout the project; Gary Masters, for editing and blending
   the different styles into one clear message; Doug Henderson, for his
   technical review; Eric Stroo, for coordinating the progress of the final
   manuscript through the production process and for being so diligent about
   the final look of the book; Alison Conn, for her review of the book's
   technical coverage; and Greg Lobdell, for providing a continual flow of
   alpha and beta copies of the QuickC compiler. Also, thanks to Reed Koch
   for his many hours of explaining QuickC's internals to the authors.





                                   Dedication
                               To Bobbie Lee,
                   who touched me in a way no one ever has
                                   Mitchell



────────────────────────────────────────────────────────────────────────────
PART 1  INTRODUCTION TO C
────────────────────────────────────────────────────────────────────────────



────────────────────────────────────────────────────────────────────────────
Chapter 1  Introduction


Why Learn C?

   If you have experience with C, you are probably familiar with its
   advantages over alternatives such as BASIC or Pascal, and you may want to
   skip to the next section, which discusses the specific advantages of
   QuickC for C programmers. Here we compare C with two other popular
   languages, BASIC and Pascal.

   Although Pascal has its enthusiasts, and our old friend BASIC certainly
   has been improved in many ways (Microsoft's QuickBASIC for example), C has
   quickly become the premier language for professional programming both on
   micros, such as the IBM PC family, and on larger machines, such as those
   running the UNIX/XENIX operating system. Why is C so popular?

Portability and Standards

   One reason is portability. The core of standard C is so designed that the
   same program runs on an IBM PC, a VAX mini, and an IBM mainframe.
   Portability comes about from adhering to standards that guarantee common
   features and functions regardless of the vendor, implementation, or
   hardware environment. The first, informal C standard was proclaimed by the
   famous "white book," Brian W. Kernighan and Dennis M. Ritchie's The C
   Programming Language (New Jersey: Prentice-Hall, 1978). The specifications
   in this book have been widely adopted in the design of C compilers, but
   the definitions are not comprehensive and specific enough to provide a
   true standard. Therefore, the American National Standards Institute (ANSI)
   has proposed a draft standard for the C language. (At the time of this
   writing, the standard has not been officially adopted, but most of its
   features seem stable.) Most current and future C compilers will be written
   to conform with the ANSI standard. QuickC is compatible with the ANSI
   standard. It also permits you to verify that your code uses only
   ANSI-compatible functions and definitions or to identify nonstandard
   features, such as those needed to support functions specific to MS-DOS and
   to IBM hardware.

   Another reason for the popularity of C is its close ties to the UNIX
   operating system. UNIX was written in C, and a variety of standards
   support the use of C in the UNIX environment. QuickC is functionally
   compatible with the UNIX System V standard library specifications.

   But what does all of this mean to you, the QuickC programmer?

   A C program written under QuickC on an IBM PC can, if it uses only
   ANSI-standard features, be moved to an Apple Macintosh, and you can
   compile it with an ANSI-standard Macintosh C compiler and run it in the
   new environment.

   This level of standardization is not common in programming languages.
   Pascal is only partially standardized: A Turbo Pascal program for the IBM
   PC, for example, cannot run under standard IBM Pascal without
   modification. In the IBM PC world, the ubiquitous BASICA program has
   offered a kind of standard, but other models of computers are provided
   with quite different dialects of BASIC, and you must do an extensive
   conversion to get a BASIC program written on one machine to run on another
   manufacturer's hardware.

   Notice that this discussion applies specifically to the "core" of C: the
   control structures, data structures, and basic input/output functions.
   Outside of this standard core, however, a number of areas of a C
   implementation are machine-dependent, such as the size of various kinds of
   numbers, keyboard codes, the video screen, graphics, and features of the
   operating system that handle files. To be worth its salt, a C compiler
   that runs on the IBM PC must include functions that give programs access
   to MS-DOS features, the underlying BIOS, and the hardware. Similarly, a C
   compiler for the Macintosh must include functions that give a program
   access to such elements as the machine's system toolbox. These functions
   are hardware-dependent and implementation-specific──by definition, they
   are not portable, but they are essential to getting the most out of your
   machine. C, as you will discover, provides a way to gather the
   machine-dependent parts in an organized manner, something other languages
   can't do.

   BASIC and, to a lesser extent, Pascal approach hardware dependence by
   customizing the language itself to include commands or functions that take
   care of the machine-dependent features. For example, a BASIC statement to
   control the speaker might be called PLAY. Another version of BASIC might
   call it MUSIC. The problem with this approach is apparent when you try to
   convert a program to run on a different machine; you cannot easily find
   the parts of the program that you must change to manipulate proprietary
   features. Also, such hardware-dependent statements may work differently on
   computers with different hardware configurations.

A Modular Approach

   The programmer's task is more manageable with C. Each C compiler includes
   files of definitions, called include files, and collections of precompiled
   functions, called function libraries, which you can use to supplement the
   core of C to take full advantage of the features of a given machine. Your
   QuickC function library includes a rich collection of definitions and
   functions for MDA, CGA, EGA, MCGA, and VGA graphics (as well as Hercules
   graphics, starting with version 1.01); the whole set of MS-DOS function
   calls; and much more.

   The result is that a C programmer has several choices. If you don't need
   graphics or machine-specific features, you can write an ANSI-standard
   text-only C program and easily move it to other machines and operating
   systems. If you do need machine-dependent features in your program, you
   can use the "no-frills" version of the program and then add graphics and
   other hardware-dependent features in easily identified include files and
   libraries. For a particular hardware environment, you can then merge the
   appropriate include files and libraries into your program. Figure 1-1 on
   the following page illustrates the concept of portability.

   Portability requires many trade-offs. In general, the less portable (in
   other words, the more hardware-dependent) a program is, the faster it
   runs, and the more it takes advantage of graphics and other special
   hardware features. On the other hand, the more portable a program is, the
   easier it is to maintain, modify, or convert it to work with new hardware.

   Throughout this book, we point out portability issues and suggest ways to
   deal with them. For example, we note those features of QuickC that are
   compatible with ANSI and UNIX System V. We also look at portability versus
   performance in the MS-DOS world. For example, we discuss alternative ways
   for dealing with devices such as the keyboard and video display on MS-DOS
   machines (standard I/O, console I/O, and BIOS) and point out the
   portability trade-offs involved with each.

   ┌────────────────────────────┐
   │                            │  Not
   │    Customized statements   │  portable
   │                            │
   │┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │
   ├┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┤
   │                            │
   │      MS-DOS and BIOS       │
   │                            │
   ├────────────────────────────┤
   │          Hardware          │
   └────────────────────────────┘

   (A)  BASIC--A SNUG FIT BUT NOT PORTABLE


           ANSI/UNIX
   ┌────────────────────────────┐  Can run on
   │     Standard functions     │  IBM PC, VAX,
   └─────────┐        ┌─────────┘  Macintosh,
           │        │            and others.
           ├────────┤
           └────────┘
               │
   ┌─────────┐   ▼    ┌─────────┐  Implementation
   │         │        │         │  of C, such as
   │         │        │         │  Microsoft C or
   │         └────────┘         │  Quick C.
   │ Machine-specific libraries │
   │┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │
   └┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘
               │
               ▼
   ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐
   ┌┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┐  Specific
   │                            │  machine-
   │      MS-DOS and BIOS       │  IBM PC,
   │                            │  for example.
   ├────────────────────────────┤
   │          Hardware          │
   └────────────────────────────┘

   (B)  C--A PORTABLE CORE

   Figure 1-1.  Portability in C.

C Is Powerful

   Portability is desirable, but you also want to write code that takes full
   advantage of the hardware. In this age of drop-down menus, windows, mice,
   and help screens, users expect a lot more out of software than they did
   only a few years ago. As a programmer you are often pushing the limits of
   the hardware, whether in processing speed, I/O, or graphics.

   When it comes to harnessing the hardware, C really shines. For example,
   other languages try to hide the fact that you are manipulating the
   contents of memory when you write code; with C pointers, you can easily
   manipulate memory directly. With Pascal, you can also directly manipulate
   memory with pointers, but the syntax is not as simple or as powerful as
   that of C. And in BASIC, you can use a PEEK and a POKE to access memory,
   but they lack the flexibility of pointers.

   Another important indicator of the power of a language is its ability to
   use machine resources efficiently. All high-level compiled languages
   translate program statements into machine instructions. With most
   languages you have little control over the efficiency of the resulting
   machine instructions. You are at the mercy of the assumptions the compiler
   or interpreter makes about your program and how it will be used. Suppose,
   for example, that your program uses one or two variables frequently in a
   loop that will be executed many times. In C, you declare register
   variables that are stored, if possible, in internal CPU registers; thus,
   delays in loading or retrieving their values in memory are avoided. The
   result is faster execution speed.

   Another important feature of C is its ability to create a variety of
   memory models. A memory model describes the way RAM is used during
   compilation and the way program code and data are shared in RAM. With most
   older BASICs you can use only 64 KB of memory to hold program code and
   data. Today, most MS-DOS machines have at least 256 KB (and often 640 KB
   of memory or more). Thus, newer compilers for BASIC, Pascal, and other
   languages often allow access to a larger amount of RAM. But C compilers go
   a step further: You──the programmer──decide how the computer will allocate
   memory. Depending on the needs of your program, you can choose to use most
   of the machine's memory for storing compiled instructions, you can use
   most of the memory to store data (such as arrays, structures, or lists),
   or you can allocate varying numbers of 64 KB memory segments to both.
   Figure 1-2 on the following page shows the concepts of register
   variables, pointers, and memory models.

   Pointers, register variables, and memory models are only some of the
   options C gives you for controlling the machine. In addition, most C
   compilers let you improve, or "optimize," the machine code generated from
   your program. You can optimize for program size (a smaller .EXE file) or
   for faster execution or for a combination of these. For example, QuickC
   performs some optimization for you and lets you choose other features as
   appropriate. In addition, you can use QuickC in combination with Microsoft
   C (the professional, industrial-strength C compiler) to provide
   optimization that is truly state of the art.

   Pointers   ┌──────────────────┐              ┌────────────────┐
   for direct │ main ()          │              ├────────────────┤
   access to  │ int * ptr; ──────┼──────┐       ├────────────────┤
   memory     │ ptr ++; ─────────┼───┐  │       ├────────────────┤
               │ ...              │   │  │       ├────────────────┤
               │                  │   │  │       ├────────────────┤
               │                  │   │  │       ├────────────────┤
               └──────────────────┘   │  │       ├────────────────┤
                   Program          │  └──────►├────────────────┤
                                   │          ├────────────────┤
                                   └─────────►├────────────────┤
                                               └────────────────┘
                                                       Memory

   (A)                         POINTERS


   Fast       ┌──────────────────┐              ┌────────────────┐
   register   │ main ()          │─────► CPU    ├────────────────┤
   access     │ register int i;  │◄─────        ├────────────────┤
               │ ...              │              ├────────────────┤
   Regular    │                  │◄─ ─ ─ ─ ─ ─  ├────────────────┤
   memory     │ int regular_varn │  ─ ─ ─ ─ ─►  ├────────────────┤
   access     │ ...              │              ├────────────────┤
               └──────────────────┘              ├────────────────┤
                   Program                     ├────────────────┤
                                               ├────────────────┤
                                               ├────────────────┤
                                               └────────────────┘
                                                       Memory

   (B)                     REGISTER VARIABLES


                                   ┌──────┐
                                   │      │
                   ┌──────┐         │ Code │          ┌──────┐
                   │ Code │         │      │          │      │
   ┌──────┐        ├──────┤         ├──────┤          │ Code │
   │ Code │        │      │         │      │          │      │
   ├──────┤        │ Data │         │ Data │          ├──────┤
   │ Data │        │      │         │      │          │ Data │
   └──────┘        └──────┘         └──────┘          └──────┘

   (C)                        MEMORY MODELS

   Figure 1-2.  C gives you control of the machine.

C Is Extensible

   C also lets you customize the contents of include files and libraries so
   that they contain only the definitions and functions your program needs.
   These custom files can contain functions for anything from manipulating a
   database to formatting text. After you write and test these definitions
   and functions, your main program can use them as easily as it can use the
   standard include files and libraries provided with your compiler. On large
   real-world programming projects, teams of programmers can receive
   specifications for each set of routines needed, and each team can create
   resources that can be used anywhere in the project. Although most
   languages offer a version of this building-block methodology, the C
   approach is the simplest, the most flexible, and the easiest to use.

   The very popularity of C enhances the value of such language extensions.
   Hundreds of vendors have created C function libraries for almost every
   imaginable task. Figure 1-3 shows conceptually how you can use function
   libraries from both QuickC and other vendors in your programs. You can
   easily integrate vendor libraries into your own code, and because they are
   the products of professional C programmers, they are likely to be fast and
   efficient. You can almost always avoid the age-old problem of reinventing
   the wheel.

                               ┌──────────┐
                               │  MS-DOS  │
                               │     ┌──────────┐
                               │     │   I/O    │
                               │     │     ┌──────────┐
                               └─────│     │ Graphics │
   ┌─────────────┐                │     │          │
   │             │                └─────│          │
   │ Included  ◄─┼──────────────────────│          │
   │ definitions │                      └──────────┘
   │ ─────────── │
   │ Your code   │                              Third-           Your
   │ main ()     │           Microsoft          party            custom
   │ ...         │           libraries          libraries        library
   └─────────────┘           ┌─┐┌─┐┌─┐          ┌─┐┌─┐           ┌─┐
           │ Compile          │ ││ ││ │          │ ││ │           │ │
   ┌────────▼──────────┐       └─┘└─┘└─┘          └─┘└─┘           └─┘
   │ Compiled Modules  │───────────┘  │               │             │
   ├───────────────────┤              │               │             │
   │ Standard Library  │──────────────┘               │             │
   ├───────────────────┤                              │             │
   │ Graphics          │──────────────────────────────┘             │
   ├───────────────────┤                                            │
   │ Database          │────────────────────────────────────────────┘
   ├───────────────────┤
   │ Special functions │
   └───────────────────┘
           │ Link
   ┌────────▼──────────┐
   │   Ready-to-run    │
   │      program      │
   └───────────────────┘

   Figure 1-3.  Using include files and libraries.

C Is Structured

   The syntax of the C language itself supports structured programming. C
   provides the control structures of a modern structured language, such as
   if/then/else, for, while, while...do, and switch. (The last is like
   Pascal's case statement.) If you are experienced in Pascal or in one of
   the newer BASICs (such as Microsoft QuickBASIC), you will find these
   control structures conceptually familiar. However, you will have to learn
   syntax differences for C, and boxes in the text point these out. If you
   are used to one of the older BASICs, you will be pleasantly surprised at
   how these structures enable you to avoid nearly all goto statements that
   lead to disorganized "spaghetti code."

C Is Concise

   Although C is a well-structured language, it encourages concise rather
   than verbose statements. For example, it uses braces to begin and end
   blocks of code, rather than Pascal's begin and end. C provides shorthand
   operators for assigning values to variables and for incrementing
   variables. To show the flavor of C, the following table presents a few
   comparisons of C, Pascal, and BASIC assignment statements:

   Some Comparisons of BASIC, Pascal, and C
                           BASIC           Pascal           C
   ──────────────────────────────────────────────────────────────────────────
   1. Set a, b, and c to 0  a = 0           a := 0;          a = b = c = 0;
                           b = 0           b := 0;
                           c = 0           c := 0;
   2. Set i to i + 1        i = i + 1       i := i + 1;      i++;
   3. Set a to a + 5        a = a + 5       a := a + 5;      a += 5;
   ──────────────────────────────────────────────────────────────────────────

   Such conciseness speeds the typing of programs and makes C source files
   more compact and easier to edit. C functions are more accessible than
   their Pascal counterparts and much more efficient than the awkward
   subroutine mechanism of BASIC. With the C preprocessor, you can create
   your own shorthand, or macro, definitions with which you insert
   expressions or whole blocks of code in text by typing the name of the
   definition.

   This brief overview of the general features of C should suggest why the
   language is so popular. Let's now look more closely at the product with
   which this book is concerned, Microsoft QuickC, and see how its particular
   features and advantages make programming in C even more attractive.


Why QuickC?

   Traditionally, C has had one big drawback compared with interpreted
   languages such as BASIC──a complex compilation and debugging process. You
   probably know that C is a compiled language, and MS-DOS─based compiled
   languages traditionally have required that you go through a lengthy series
   of steps to produce an executable file.

   The steps to compiling a traditional C program are the following:

   1.  Start a text editor or word processor and write a program.

   2.  Save the program to disk and exit the editor.

   3.  Run the compiler program by issuing a command line from the DOS
       prompt, usually with several filenames and options included, that tell
       it, for example, what memory model to use and whether to generate a
       listing file.

   4.  Look at the listing produced by the compiler, and study every error
       message.

   5.  Print out this error list for reference.

   6.  Start the editor again, open your C program file, and for each error
       try to find the exact line in which the error occurred and correct the
       program.

   7.  Go back to step 3 and try again until the program compiles without
       errors into an object code file.

   8.  Now run the linker, and tell it what libraries to combine with your
       object code file to produce an executable program (an MS-DOS .EXE
       file). If you used an incorrect function name or failed to specify the
       correct libraries, you will now get a new batch of error messages,
       this time from the linker. (They may, for example, report an
       "unresolved external," which probably means the name you used for a
       function in your code did not match the name of the function defined
       in the library.) To fix these errors, you may need to look at listings
       of include files. Or you may have to go back to the editor and correct
       your program. In any case, you must recompile and then try to link
       again.

   9.  When the code links without errors, you can finally run the program.
       Did it execute as you expected? No? Do you want to make some changes?
       Well, go back to the editor and try again.

   Just reading through these steps suggests how tedious a traditional
   compiled language can be. With interpreted languages, such as BASIC, LOGO,
   or HyperTalk, you can type a line or two of code, execute it immediately,
   and see the results. If your line of code contains errors or if you want
   to add or change something, the interpreter usually provides a simple text
   editor or line editor you can use immediately.

   But interpreted languages have one critical drawback──they're slow. Each
   line in a program in an interpreted language has to be translated into
   machine-executable instructions each time it is encountered. Therefore,
   only the simplest interpreted-language applications run fast enough for
   use in the real world.

   The philosophy behind QuickC is to provide a programming environment that
   is as easy to use as an interpreter, but with the execution speed
   obtainable only through a compiler. With QuickC, writing and testing
   programs is so easy that C can be a beginning programmer's first language.

The QuickC Programming Environment

   With QuickC, you do all of your program development in and from the same
   place──the QuickC integrated programming environment. (Figure 1-4 shows
   the way your screen looks when you start QuickC.) This environment offers
   many advantages:

   1.  You can open a file for editing by using the Open command on the File
       menu, or you can simply start typing a new program. The QuickC
       full-screen editor is immediately available, with insert/delete,
       cut/paste, indention──all the features you need to type a program as
       easily as you type a letter with a word processor. And you never
       really "leave" this editor. You merely select whatever service you
       need from the menus.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 1-4 can be found on p.12 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 1-4.  The initial QuickC screen.

   2.  To run the program you can click on the mouse or type a command. When
       you work with a program that has not yet been compiled, the compiler
       and linker are called as needed. There are no complex command-line
       options to type. If your program is error free, the program runs in
       seconds on the output screen.

       The main reason your programs compile, link, and run so quickly with
       QuickC is that, unlike traditional C compilers that compile and link
       to disk, QuickC by default compiles to memory. Thus, it can compile
       10,000 lines a minute on a standard IBM PC/AT. Another reason is that
       some of the most commonly needed functions are held in memory. You
       also can create libraries that can be loaded into memory. The result
       is that QuickC uses available memory very efficiently.

   3.  As you view an error message, the cursor follows along through your
       program text; you can instantly correct each error with the built-in
       editor. No printed listings to pore over; no error numbers to look up!

   4.  Suppose your program compiles correctly but doesn't work as you
       expected. Without leaving QuickC, you can turn on the debugging and
       trace features, rerun your program, and then watch the changing values
       of selected variables, follow the flow of execution, and check the
       values being passed to and from functions called by your program.

       What about multiple-module programs──C programs that have several
       separately compiled libraries and code files? Traditionally, you had
       to run a special "make" program and give it a file with a unique
       syntax that told the compiler how to rebuild such a complex program
       after any change was made. With QuickC's program list feature, you
       simply tell QuickC what libraries and source code files you want to
       use. QuickC keeps track of all the other details, such as the
       relationship between modules and the date each module was last
       compiled.

   5.  Do you need access to MS-DOS? Need to make a new directory or back up
       some programs? Maybe you want to run some previously compiled C
       programs from MS-DOS. With a traditional, command-line-driven C
       compiler, you exit the compiler, work in MS-DOS, and then run the
       compiler again and figure out where you left off. With QuickC, you
       never leave the integrated programming environment. Using QuickC's DOS
       Shell feature, you exit to MS-DOS, take care of your business, and
       return to QuickC where you left off.

   You can select many other features from the QuickC programming environment
   in the same easy way. With a command-line compiler, most features require
   that you type obscure flags or option switches on the command line or
   create batch files to simplify complicated compiler commands. With QuickC,
   you select with a mouse click or keystroke such features as the error
   warning level, language extensions, and optimization. But don't let the
   convenience deceive you──underneath the covers, QuickC is constructing the
   proper list of options so that you can use the same linker. (QuickC also
   includes a command-line-driven compiler for those times you have a special
   need, such as compiling under certain memory models, or when you want to
   work outside the QuickC environment.)

QuickC Performs

   QuickC is faster in almost all cases than its nearest competitors, and it
   beats them hands down in floating-point operation.

   QuickC also is fully compatible with its "big brother," the Microsoft C
   Optimizing Compiler, versions 5.0 and later. Any program that compiles
   under QuickC compiles under Microsoft C, version 5.0. Therefore, you can
   develop programs with QuickC and then effortlessly recompile them under
   Microsoft C for fine tuning, using a variety of optimization techniques.

QuickC: Standard and Comprehensive

   Earlier we discussed ANSI and other official standards for C. There are
   also unofficial industry standards that are almost as important. When you
   use QuickC, you have the benefits of using a compiler that has become the
   industry standard for PCs: Microsoft C. QuickC is fully compatible with
   that standard. Thus, dozens of third-party C code libraries work with your
   programs because the programs you write are compatible with the ANSI or
   UNIX System V standards or with the MS-DOS─specific features of
   Microsoft C.

   The extras that come with the QuickC product are also impressive. Each
   standard-model library (small, medium, compact, large) supports the 8087
   coprocessor. There are libraries for every kind of PC graphics from
   monochrome and CGA to the latest VGA graphics for the IBM PS/2. The QuickC
   Graphics Library routines feature easy-to-use routines for drawing points
   and lines and manipulating complete images, including filling and
   animation, all with impressive speed. QuickC also has libraries that allow
   your programs complete access to MS-DOS and BIOS calls. And, because of
   QuickC's UNIX compatibility, you can also use UNIX System V functions for
   writing programs that can be ported to work in the UNIX environment.


Hardware Requirements

   To run QuickC you need an IBM PC/XT, PC/AT, PS/2, or compatible computer
   with at least 448 KB of RAM and at least two floppy-disk drives. We
   suggest, however, that you develop QuickC programs on a hard disk.
   Compiling or linking to disk with floppy disks is time-consuming compared
   with hard disks. Also, fitting all the files you need for developing
   programs onto two disks can be tricky. But because some of you will be
   using floppy-disk-based systems, we will give you some tips later that
   should help you make the best of the situation. (And the situation is
   anything but grim: You can certainly develop programs that run great under
   QuickC on a floppy-based system.)

   We also recommend (but don't presuppose) that you use QuickC with a
   compatible mouse. You can handle all QuickC functions from the keyboard,
   but why get bogged down learning the keystroke combinations? With a mouse
   in hand, you simply point at what you want and select it.

   On the other hand, many people don't have (or choose not to use) a mouse.
   With QuickC, you can use short keystroke combinations. For example,
   Alt-r-s selects the Run menu's Start option to compile and run a program.
   (Even if you have a mouse, typing is sometimes faster.)

   Graphics capability is optional for most of this book. Chapter 15, which
   deals with graphics, requires a CGA, of course; for advanced graphics, you
   need an EGA; and the VGA section requires a PS/2, or a VGA board for older
   PCs. (If you have the new VGA, you also have CGA and EGA capability.) Even
   if you have only the basic monochrome adapter, you can create many
   interesting QuickC programs with the built-in IBM graphics character set.

   Finally, we recommend that you have a printer (although a printer is not
   required for this book).


Knowledge Requirements

   Some programming experience──with BASIC or Pascal, for example──will help.
   But thanks to the ease of use of QuickC, C can be your first programming
   language, although you may have to work a bit harder than more experienced
   programmers.

   Because many of you have programmed in BASIC (such as Microsoft's BASICA
   or QuickBASIC) or Pascal (Borland's Turbo Pascal, for example), we scatter
   "asides" throughout the text for BASIC and Pascal programmers. These point
   out the ways in which C is similar to and different from those languages.
   Familiarity with another language is a two-edged sword when it comes to
   learning C. On the one hand, you already know many programming concepts
   used in C. On the other hand, differences in syntax and usage can trip you
   up if you aren't careful.

   If you are a UNIX programmer, you will feel right at home──as soon as you
   get used to QuickC's much more comfortable living room! The QuickC
   environment is far easier to use than the UNIX cc compiler and ln linker,
   and you won't have to write any make scripts. You probably already know
   the fundamentals of C, but watch out for features that are different in
   the IBM PC/MS-DOS environment, especially graphics and MS-DOS system
   calls. But as we noted, with a few minor exceptions, Microsoft C supports
   the standard I/O and other library functions used on UNIX systems.
   Occasional boxes point out matters of interest to UNIX programmers.


Conventions and Style

   We have chosen the following typographical conventions for the
   descriptions of a C program in the text:

   ■  Names of ordinary (local) variables are lowercase italic. Example:
       count, sum

   ■  Names of external or global variables are also italic, but the first
       letter is capitalized. Example: Model

   ■  Underscores join the words of multiple-word variable names. Example:
       Grand_total (an external variable) or line_count (an ordinary variable)

   ■  Constants created with #define are uppercase italic. Example: PI

   ■  Macro definitions are uppercase italic. Example: PRINT_ERROR(MSG)

   ■  Function names are lowercase italic. Underscores join multiple-word
       function names. Examples: main(), count_lines(), printf()

       You'll also notice that names of Microsoft library functions that are
       non-ANSI-standard (such as the graphics functions) are lowercase italic
       and preceded by an underscore. Example: _getvideoconfig() (a Graphics
       Library function)

   ■  In #include statements, names of header files that we create are in
       double quotation marks. Example: #include "chr_graphics"

       Names of header files provided by Microsoft are in angle brackets.
       Example: #include <graphics.h> (This convention affects the way in
       which the compiler searches for header files on disk.)

   ■  Built-in "keywords," or reserved words, of the C language are lowercase
       italic. Examples: int, do, while

   ■  Program names are uppercase roman. Example: HELLO.C

   ■  Filenames and pathnames are uppercase roman. Examples:
       \LIB\GRAPHICS.LIB, SCREEN.DAT

   ■  Names of special keys are spelled as they appear on the standard IBM PC
       extended keyboard. Examples: Enter (not Return), Ctrl-C, the Esc key

Program Listings

   Program listings are set off from the text in a monospace font. Constants,
   variables, and function names are capitalized as indicated in the
   preceding list but are not italicized.

   In many cases, we provide a sample session that demonstrates how a program
   interacts with the user. In these listings, user input is italic.

   guess────────────────────────────────────────────Run the guess.c program
   What number am I thinking of?───────────────────────────Program response
   7─────────────────────────────────────────────────────────────User input
   Wrong! Try Again?
   3
   Right! You win!

   NOTE: The comments at the right in the sample session above are not part
   of actual program dialogue.

Program Style Conventions

   A clear, consistent typographical style makes programs easier to read. No
   single style is universally accepted for C program listings. Ultimately,
   you fashion your own, based on your judgment and the prevailing usage. In
   some cases, more than one kind of syntax can be used. Although C itself
   doesn't care about spacing between the elements of a statement or an
   expression, we use a space between elements unless removing the space is
   clearer. Also, we use a 4-space indention for nested statements and the
   braces that enclose them.

   We always align braces ({ and }) vertically──a major stylistic departure
   from Kernighan and Ritchie. That is, we put

   function_name()
   {
   <body of function>
   }

   rather than

   function_name() {
   <body of function>
   }

   We believe this style enables you to read the listings and identify blocks
   of code more easily. Be warned, however, that you will find lots of C
   listings that contain the second style.

   Finally, because experienced C programmers often make a virtue of saying a
   lot with a little, we point out concise, idiomatic coding styles that you
   are likely to see in program listings from various sources, and we
   sometimes show two or more ways to code a statement.



────────────────────────────────────────────────────────────────────────────
Chapter 2  Starting with QuickC

   You are now ready to explore the QuickC environment. In this chapter we
   describe the environment, show how to set up QuickC on your computer
   system, present an overview of the QuickC menus and dialog boxes, and help
   you create and run your first QuickC program. We also show how to get help
   from QuickC and how to fix program errors. When you finish this chapter,
   you will be comfortable with QuickC and ready to learn the C language
   itself.


Our Book and Their Book

   QuickC comes with an excellent user manual that details the mechanics of
   using QuickC. It explains how to configure the system, how to use the
   menus, the meaning of the options in each menu and dialog box, and how to
   use the programs that comprise the QuickC programming tools. The QuickC
   package also includes two reference guides, the Microsoft QuickC Language
   Reference and the Microsoft QuickC Run-Time Library Reference. The first
   guide describes the rudiments of the C language; the second provides
   specific information for using each of the more than 350 C library
   routines.

   Our book is designed to complement the QuickC user manual by focusing on
   teaching C programming with QuickC rather than rehashing operational
   details from the manual. However, because you need to master QuickC's
   features to write effective C code, we sometimes present a brief overview
   of a procedure or subject and then refer you to the manual for a complete
   discussion. We use this approach particularly when we discuss system setup
   and configuration, for which the manual provides extensive and detailed
   guidance.

   We also do not discuss all the editor commands and keystrokes. You can
   learn these from the QuickC manual and through one of QuickC's excellent
   help screens. However, when we know of some useful tricks that aren't
   covered in the manual, we pass them along immediately.


Directories and Files Used by QuickC

   Programming in C usually involves combining several files to eventually
   form an executable program. These files include definitions of data
   structures and functions (header files), libraries of precompiled
   functions, and your own program code. The QuickC environment uses several
   directories to organize the files into distinct groups, according to
   purpose, such as function libraries, include files, and so on. QuickC also
   uses distinctive filename extensions to identify files that are used or
   created in the compiling and linking process.

Why So Many Files?

   If you use languages such as BASIC or some versions of Pascal, you might
   wonder why QuickC needs such an elaborate system of files and directories.
   With most versions of BASIC, for example, you need only two files: the
   BASIC interpreter program that creates and runs your programs, and the
   file that contains your BASIC program. Although the QuickC environment can
   look quite complicated by comparison, QuickC sets up most of the
   directories and files for you (especially if you have a hard disk) and
   makes it easy for you to move among all the files of a programming
   project. Nevertheless, it is important to understand how QuickC organizes
   files, especially if you need to modify the default organization to avoid
   conflicts with existing directories or for some similar reason.

   To explain the "environment" you work in, we must examine QuickC's
   directories and the files they contain. We use the QuickC default names in
   our discussion, because the actual name and location of the directories
   depend on how you invoke the SETUP program and whether you use a
   floppy-disk or hard-disk system.

Base Directory and Subdirectories

   QuickC installs directories as subdirectories of a "base" directory. If
   you use QuickC by itself, the base directory usually is c:\qc; if you use
   QuickC as part of the Microsoft C 5.0 Optimizing Compiler package, the
   command is usually c:\c5\qc. Thus the actual pathname for the \BIN, or
   base, directory probably is C:\QC\BIN or C:\C5\QC\BIN.

   The most important QuickC directories are \BIN, \INCLUDE, and \LIB. Let's
   look at these and some optional directories that you might find useful.

The \BIN Directory, Compiler, and Linker Programs

   The \BIN directory contains the program QC.EXE, which runs QuickC,
   provides the integrated programming environment, and lets you write,
   compile, link, and execute QuickC programs. (The name "BIN," by the way,
   is short for "binary." The \BIN directory is usually reserved for "binary
   files," or files containing executable programs.)

   The QuickC package actually contains two compiler programs: QC.EXE, which
   comprises the integrated programming environment with its editor, menus,
   and so on; and QCL.EXE, a much shorter program, which generates a
   "command-line" version of the QuickC compiler. (To help you distinguish
   between the programs, think of QCL as "QuickC Line-oriented.") QCL is much
   like the traditional C compiler we described in the Introduction. Rather
   than using menus and dialog boxes, you can compile a program only by going
   to the MS-DOS prompt and typing a command line with options. Another
   program in the \BIN directory, called LINK.EXE, combines your compiled
   programs and stand-alone libraries into a single executable program.
   QuickC usually performs this linking as an invisible process, although
   you can specify linker options when necessary. When you use QCL, you
   control the linker directly with a series of command-line options.

   QC.EXE, with its integrated programming environment, is more convenient to
   use, and we assume in most parts of this book that you will use it to
   compile and run your programs. However, the command-line compiler QCL.EXE
   is very useful for doing what are called batch compilations, for setting
   specific combinations of compile options, for compiling with alternate
   memory models, or for using an alternative program editor with QuickC. QCL
   also lets you use "make" files created with the Microsoft C Optimizing
   Compiler, version 4.0 or 5.0. (Make files are files that keep track of the
   compilation of multiple program modules. QuickC offers an easy-to-use
   alternative called "program lists," which we discuss in Chapter 6.)

The \INCLUDE Directory and Header Files

   The "core" of C is greatly extended by compiler vendors who develop new
   sets of predefined constants, macros, data structures, and functions for
   such areas as graphics, device I/O, and DOS. Some of these are standard
   (proposed ANSI standard or UNIX System V standard) and are found in
   virtually all compilers; others are specific to the IBM PC or to
   Microsoft. The QuickC \INCLUDE directory contains many text files of both
   types. These are known as "include files" because your program can include
   definitions from one or more of these files. (They are also known as
   "header files," because their names must be specified at the beginning, or
   head, of a program.) This is also where you'll put any third-party
   libraries you obtain.

   Include files are not executable files or complete C source programs; they
   are ordinary text files that contain useful function definitions; they
   provide an interface between your program and the compiled code in
   stand-alone libraries. When a program references an include file, the code
   in the include file is inserted into and compiled with the code you
   actually typed in.

   For example, the include file stdio.h contains many of the most commonly
   used input and output functions, and graphics.h contains definitions for
   data structures and functions in the Graphics Library. The following table
   lists the standard QuickC include files. Note that include files have
   filenames with the .h extension. (Don't worry about understanding this
   comprehensive list yet; we will discuss many of them in detail as we use
   them in programs throughout the book.)

   QuickC Include Files
╓┌─┌──────────┌──────────────────────────────────────────────────────────────╖
   File       Main Purpose
   ──────────────────────────────────────────────────────────────────────────
   assert.h   Debugging expressions
   conio.h    PC-specific console (keyboard) and port (device) I/O
   ctype.h    Character testing and conversion
   direct.h   Creating, removing, and changing MS-DOS directories
   dos.h      Setting and reading 8086 registers for MS-DOS calls
   errno.h    System-wide error numbers
   fcntl.h    Opening MS-DOS files with various modes
   float.h    Implementation-dependent values for advanced floating-point
   File       Main Purpose
   ──────────────────────────────────────────────────────────────────────────
   float.h    Implementation-dependent values for advanced floating-point
               operations
   graph.h    Microsoft-specific data structures and functions for monochrome
               (MDA), CGA, EGA, MCGA, and VGA graphics
   io.h       Low-level file-handling and I/O routines
   limits.h   Implementation-dependent values for sizes and ranges for data
               types, etc.
   malloc.h   Memory allocation functions
   math.h     Definitions used by math library
   memory.h   Memory manipulation routines (buffer setup, etc.)
   process.h  Used with routines that allow a program to "spawn" (run)
               another program as a "child process"
   search.h   Sorting and searching routines
   setjmp.h   Used for saving and restoring the program state during a "long
               jump" (jump to a different memory segment)
   share.h    Flags controlling sharing of a file among several users (i.e.
               on a network)
   signal.h   Values for "signals" that can be sent to interrupt handlers,
               etc.
   File       Main Purpose
   ──────────────────────────────────────────────────────────────────────────
               etc.
   stdarg.h   Allows a function to use a variable number of arguments (ANSI
               style)
   stddef.h   Miscellaneous constants, types, and variables
   stdio.h    UNIX-compatible standard I/O, such as functions to get and put
               characters to the console or a file
   stdlib.h   Definitions for miscellaneous library functions
   string.h   Definitions for string manipulation functions
   time.h     Data structures used for accessing system time
   varargs.h  Allows a function to use a variable number of arguments
               (XENIX-style)

   The \SYS subdirectory of \INCLUDE contains:
   locking.h  Flags for locking files (for networks)
   stat.h     Defines structure used to return status of an MS-DOS file or
               directory
   timeb.h    Types used by ftime() (used to get current time)
   types.h    Types used in values returned by functions for time and file
               status information
   File       Main Purpose
   ──────────────────────────────────────────────────────────────────────────
               status information
   utime.h    Used by utime() to update access and modification times for
               MS-DOS files
   ──────────────────────────────────────────────────────────────────────────


   In QuickC, the \INCLUDE directory also contains a subdirectory called
   \SYS. This subdirectory contains "system specific" include files for IBM
   personal computers and compatibles.

The \LIB Directory and Libraries

   Much of C programming involves writing code that uses standard C functions
   to perform such tasks as getting a character from the keyboard or sending
   a text string to the screen. Microsoft has already compiled these
   functions for you and has placed them in files called "libraries." The
   \LIB directory contains these library files, which have either the
   filename extension .LIB or .QLB. As noted earlier, when QuickC starts, it
   includes in memory the code for a considerable number of commonly used
   functions. In addition, Microsoft provides "Quick Library" versions of
   some libraries, and you can specify that these be loaded as well to
   provide fast, in-memory access. You can also create your own custom Quick
   Libraries. Quick Libraries all have the same extension .QLB.

   If you examine the PACKING.LST file on the QuickC Product disk, you will
   see many libraries with similar names, such as SLIBC.LIB, SLIBFP.LIB, or
   MLIBC.LIB. Why are there so many libraries? The architecture of the Intel
   8086 and 80286 processors used by the IBM PC family requires that memory
   be divided into 64 KB segments. As a result, special instructions are
   needed to access program instructions or data that go beyond a single
   segment. The designers of C compilers address this problem by providing
   programmers with multiple memory models, each containing a different
   allocation of segments for code and data. (QuickC uses compact, small,
   medium, and large memory models. Microsoft C 5.0 adds a "huge" model.)
   Additional libraries handle floating-point (decimal) calculations: Some
   use the 8087 floating-point coprocessor chip, others use software that
   emulates its functions. Also included is an optional graphics library,
   GRAPHICS.LIB.

   Combined Libraries

   You can use libraries in two ways. When you compile, you can tell the
   linker to include specified libraries (a memory-model library, a
   floating-point library, a graphics library, and so on). Although this is
   most easily done using a "program list," it can involve a bit of
   bookkeeping. The easier way to use libraries is to use the SETUP program
   (discussed later in this chapter), to build one or more combined
   libraries. A combined library is a package that contains one library for
   the floating-point option, one standard library for the specified memory
   model, some general purpose "helper" libraries, and possibly the optional
   GRAPHICS.LIB. The advantage of creating a combined library is that QuickC
   uses it by default, so you don't have to specify library names when you
   compile and link. The \LIB directory contains any combined libraries you
   create with the setup process.

   Note: If you intend to write graphics programs, use SETUP to combine the
   Graphics Library with your standard library. That way, QuickC always
   includes this library in compilations.

The \TMP Directory

   QuickC uses the \TMP directory to store temporary files created during
   compilation. Normally, QuickC removes these files when it finishes with
   them. However, if something "hangs" the system during a compile, you might
   want to check the \TMP library and delete any vestigial files.

The \SAMPLE Directory

   If your computer has a hard disk, the QuickC SETUP program creates a
   \SAMPLE directory and stores in it several example programs. You can use
   these to practice loading, editing, compiling, and running QuickC
   programs.

The \PROG or \SOURCE Directory

   By default, QuickC stores your programs in the current directory when you
   invoke the compiler. All other files created by the compiling and linking
   process are also stored there. You also can create directories to store
   the source code (the actual program text) for the C programs you write and
   the various files made from your program by QuickC. Although this is
   entirely optional, it makes for a more orderly directory and helps you
   organize and find your programs more easily.

   Whatever your current directory, compiling programs creates the following
   kinds of files, depending on the compiler and linker options you select:

   NAME.C──Source code for the C program name

   NAME.OBJ──Object code produced by the compiler for the C program name

   NAME.MAP──A "map" file showing the addresses used by the linker when it
   linked the program name

   NAME.EXE──The compiled and linked object code for the program name, which
   can be executed by typing name at the MS-DOS prompt

   NAME.MAK──A "make" file containing instructions that QuickC uses to
   recompile or "rebuild" your program if you change it

   Figure 2-1 summarizes our tour of QuickC directories and files. Without
   listing all the QuickC files, the chart shows a typical directory
   structure for QuickC on a hard disk. (The structure of directories on a
   floppy-disk system has several modifications that we will describe in the
   section "Setting Up QuickC for Floppy-Disk Systems" on page 32.)

                                                   C:\
                                               ──┬──
                                                   │
                                                   │
                                               c:\qc
                   ┌─────────────────────┬─────────────────────┬─────────────
                   │                     │                     │
               c:\qc\bin             c:\qc\lib           c:\qc\include
           ┌─────────────────┐         ────┬────         ┌────────────────┐
           │                 │             │             │                │
   c:\qc\bin\sample       qc.exe      mlibce.lib     assert.h    c:\qc\include
   ───────┬────────      qcl.exe      slibc7.lib      bios.h     ────────┬────
           │               qc.hlp     graphics.lib    conio.h             │
       cflow.c          link.exe     graphics.qlb     (etc.)         locking.h
   new-conf.sys        lib.exe        (etc.)                        stat.h
   new-vars.bat                                                     (etc.)

   Figure 2-1. Typical directory structure for QuickC.

From Source to Object: An Overview

   Now that we've surveyed the compiler, linker, include files, and
   libraries, let's see how they work together when you run a program with
   QuickC. Let's assume your program uses two include files, stdio.h and
   graph.h. When you "run" or "start" the QuickC compile/link phase, the
   compiler starts by "reading" your source code in the editor buffer. First,
   it sees the instructions to add the include files. The compiler then loads
   the stdio.h file and compiles the code found there. (The code in an
   include file is not already compiled.) Next it loads and compiles graph.h.
   These include files contain, among other things, definitions of functions
   whose compiled code resides in libraries. (The standard library for each
   memory model contains the code corresponding to standard header files such
   as stdio.h; GRAPHICS.LIB contains graph.h.) As it compiles the include
   file, the compiler notes these references to library code and passes them
   to the linker.

   After the compiler generates the object code for the part of the program
   you wrote yourself, the linker "resolves" all library references: It
   extracts the "modules" that contain the necessary code from the
   appropriate libraries and combines them with the rest of the code. The
   result is a compiled object program. QuickC's default creates an object
   program that runs from within the QuickC environment. This enables you to
   run the program immediately after you link it and lets you quickly test
   programs without leaving the QuickC environment. However, you can also
   create a .EXE file, or executable MS-DOS file, that you can run from the
   MS-DOS prompt. Figure 2-2 on the next page summarizes this process
   graphically.

                   Editor
               ┌───────────────────┐
   Program    │ #include stdio.h  │
   references │ #include graph.h  │
   include    │ ────────────      │
   files      │ ────────────      │
               │ ────────────      │
               │ ────────────      │
               └───────────────────┘
                       │
                       │     Preprocessor     ┌──────────┐
               ┌─────────▼─────────┐            │stdio.h   │
   Included ▒ │ ───────────       │     ┌───── │ ─────    │
   source   ▒ │ ───────────       │     │      │ ─────    │
   code ─── ▒ │ ───────────       │◄────┘      └──────────┘
               │                   │◄────┐      ┌──────────┐
   Your ─── ▒ │ ───────────       │     │      │graph.h   │
   source   ▒ │ ───────────       │     └───── │ ─────    │
   code       └───────────────────┘            │ ─────    │
                       │                      └──────────┘
                       │     Compiler
               ┌─────────▼─────────┐
   Compiled ▒ │ ---------───?     │
   library  ▒ │ ---------───?     │
   references │                   │
               │                   │
   Your ─── ▒ │ ------------      │
   compiled ▒ │ ------------      │
   code       └───────────────────┘
                       │
                       │     Linker
               ┌─────────▼─────────┐          ┌─────────────┐
   Final      │ -----------       │          │ Libraries   │
   object     │ -----------       │◄─────────│ (combined   │
   program    │ -----------       │          │     or      │
   (in memory │ -----------       │          │ separate)   │
   or .EXE)   │ -----------       │          └─────────────┘
               │ -----------       │
               └───────────────────┘

   Figure 2-2. Compiling and linking with include files and libraries.


Running the QuickC SETUP Program

   Microsoft distributes QuickC on five floppy disks. These disks and their
   hundreds of files contain the two compilers (integrated-environment and
   command-line), a full set of libraries for each memory model with a choice
   of 8087 hardware or emulation, a rich assortment of more than 30 include
   files, several utility programs, and many other goodies. The QuickC SETUP
   program lets you set up a working QuickC environment with directories
   containing only those files that you need and provides automatic access to
   directories as you specify.

   SETUP performs the following operations:

   ■  Sets up variables and commands in the MS-DOS environment that tell the
       operating system where to find all QuickC programs and files

   ■  Sets up a home directory for QuickC, creates the \BIN, \INCLUDE, \LIB,
       and \TMP subdirectories, and moves files from the floppy disks to these
       directories

   ■  Creates one or more combined libraries, depending on the memory
       model(s) and form of floating-point support you specify

   Note: SETUP for a floppy-disk system creates only the combined library.
   You must do the rest partly "by hand." See the section "Setting Up QuickC
   for Floppy-Disk Systems" on page 32.

MS-DOS Variables and QuickC

   As we mentioned above, QuickC sets up and uses some MS-DOS commands and
   variables. MS-DOS uses variables (sometimes called MS-DOS "environmental"
   variables) to specify the location of system resources. When you boot an
   MS-DOS disk, the operating system calls on two files to configure the
   system: AUTOEXEC.BAT and CONFIG.SYS. Commands in these files control the
   environment that QuickC uses when you run it.

   When you run the SETUP program for a hard-disk system, QuickC sets
   environmental MS-DOS variables in two files: NEW-VARS.BAT and
   NEW-CONF.SYS. You can use these files as is or insert their contents into
   the AUTOEXEC.BAT and CONFIG.SYS files respectively. We recommend the
   latter procedure unless there are serious conflicts with your existing
   settings.

   You can use any editor (such as SideKick or EDLIN) to insert NEW-VARS.BAT
   in your AUTOEXEC.BAT file. If you have no AUTOEXEC.BAT, use MS-DOS to
   rename NEW-VARS.BAT as AUTOEXEC.BAT. The resulting file might look like
   this:

   setclock────────────────────────────────────────────────Set system clock
   fastopen c:────────────────────────────────────Install file access cache
   sk──────────────────────────────────────────────────────────Run SideKick
   set PATH=c:\;c:\wp;c:\c5\bin;c:\qc\bin;a:\───Combined with your old path
   set INCLUDE=c:\qc\include
   set LIB=c:\qc\lib
   set TMP=c:\qc\tmp

   After you insert the SET commands found in NEW-VARS.BAT, you will probably
   have two PATH= commands in your AUTOEXEC.BAT file. Combine the directories
   in the path provided by SETUP with your existing path, as shown in Figure
   2-3. You can usually use the rest of the SET commands without
   modification. (By default, MS-DOS permits only 128 bytes of space for
   storing MS-DOS variable values.) If this amount proves insufficient,
   modify it as described in the sidebar on the next page.

       AUTOEXEC.BAT               NEW-VARS.BAT
   ┌──────────────────┐     ┌──────────────────────┐
   │ ─────────        │     │set PATH=c:\qc\bin    │
   │ ─────────        │     │set INCLUDE...        │
   │ set PATH=c:\     │     │set LIB...            │
   │                  │     │set TMP...            │
   │                  │     │                      │
   └──────────────────┘     └──────────────────────┘
           │                          │
           └────────────┬─────────────┘
                       │
           ┌─────────────▼──────────────┐
           │ ───────────                │
           │ ───────────                │
           │ set PATH=c:\; c:qc\bin ◄───┼──── Combined paths from
           │ set INCLUDE=c:\qc\include  │▒    AUTOEXEC.BAT and NEW-VARS
           │ set LIB=c:\qc\lib          │▒─── As is, from
           │ set TMP=c:\qc\tmp          │▒    NEW-VARS.BAT
           └────────────────────────────┘


       CONFIG.SYS               NEW-CONF.SYS
   ┌──────────────────┐     ┌──────────────────┐
   │ ─────────        │     │ FILES=20 ◄───────┼── This is larger, so
   │ ─────────        │     │ BUFFERS=10       │   replace existing FILES
   │ ─────────        │     │                  │   command
   │ FILES=10         │     │                  │
   │ BUFFERS=10       │     │                  │
   └──────────────────┘     └──────────────────┘
           │                          │
           └────────────┬─────────────┘
                       │
           ┌─────────────▼──────────────┐
           │ ───────────                │
           │ ───────────                │
           │ ───────────                │
           │ ───────────                │
           │ FILES=20                   │
           │ BUFFERS=10                 │
           └────────────────────────────┘

   Figure 2-3. Editing AUTOEXEC.BAT and CONFIG.SYS.

   Here's what the NEW-VARS.BAT commands do. PATH is an MS-DOS command that
   specifies the directories that MS-DOS searches to execute a program.
   Whenever you tell MS-DOS to execute a program on your hard disk (such as
   the QuickC linker or library manager), it first looks in the root
   directory of drive C:, and then checks the specified directories in the
   order they are listed. The next command tells QuickC that include files
   are in the \INCLUDE subdirectory of the main QuickC directory. Similarly,
   the other variables show that libraries are found in \QC\LIB and temporary
   files are in \QC\TMP.


Setting Up QuickC

   Now let's set up the QuickC working environment. The QuickC manual should
   be your source for detailed information about setup procedures and the
   various options involved, but here are "quick start" instructions that can
   simplify the process and probably save you time.

   The basic steps you should follow are:

   ■  Check the PACKING.LST file on the first QuickC distribution disk. Be
       sure you have a complete set of disks and manuals.

   ■  Back up the QuickC disks to floppy disks (use the MS-DOS DISKCOPY
       command to ensure you have an exact copy). Then use the backups during
       the setup process.

   ■  Run the SETUP program.

   Before you run SETUP and before you use QuickC to develop programs, be
   sure that you have at least 448 KB of free memory. QuickC may appear to
   run fine with somewhat less than 448 KB until you try to compile certain
   programs.

   To verify the amount of free memory, type the CHKDSK command at the MS-DOS
   prompt. To increase the amount of free memory, you might be able to change
   your AUTOEXEC.BAT file so that some memory-resident programs are not
   loaded. Then, reboot to free the memory those programs were reserving.

   ──────────────────────────────────────────────────────────────────────────
   Out of Environment Space?
   If your current AUTOEXEC.BAT has many SET commands or a long PATH=
   statement, you might get an MS-DOS "out of environment space" error when
   you add the QuickC variables. If this happens, expand the available
   environment space by putting this command in your CONFIG.SYS file:

   shell=c:\command.com /e:<size>/p

   For MS-DOS versions 3.0 and 3.1, size is the number of 16-byte
   "paragraphs" you want to reserve for the MS-DOS environmental variables;
   for MS-DOS versions 3.2 and later it is the actual number of bytes. The
   default size is 10 paragraphs, or 160 bytes. To set the environment to 256
   bytes, use:

   shell=command.com /e:16/p──────────────────────MS-DOS version 3.0 or 3.1
   shell=command.com /e:256/p───────────────────MS-DOS version 3.2 or later

   ──────────────────────────────────────────────────────────────────────────

   If you normally use memory-resident programs or a RAM disk, we recommend
   that you reboot without installing them before running SETUP. The SETUP
   program will fail without at least 385 KB of available RAM. After you set
   up the QuickC environment, experiment with memory-resident programs or RAM
   disks if you wish.

   Setting up a hard-disk system for QuickC differs from setting up a
   floppy-disk system. Therefore, we have developed separate walkthroughs for
   hard-disk and floppy-disk users. If you have a floppy-disk system, skip
   the next section and read "Setting Up QuickC for Floppy-Disk Systems" on
   page 32.

Setting Up QuickC for Hard-Disk Systems

   First, put Libraries Disk #1 in drive A and type the SETUP command. The
   following line is a typical SETUP command:

   C>SETUP H C:\QC M EM GR

   The H specifies that your system has a hard disk.

   C:\QC is the pathname of your QuickC "base" directory. By default, QuickC
   creates the following subdirectories under the base directory:

   C:\QC\BIN                     Compiler, linker, and other executable
                               programs
   C:QC\BIN\SAMPLE               Sample C programs
   C:\QC\INCLUDE                 Include (header) files
   C:\QCINCLUDE\SYS              System-specific include files
   C:\QC\LIB                     Libraries
   C:\QC\TMP                     Temporary files
   ──────────────────────────────────────────────────────────────────────────

   ──────────────────────────────────────────────────────────────────────────
   Are You Using both QuickC and Microsoft C 5.0?
   If you use both QuickC and the Microsoft C Optimizing Compiler 5.0, you
   can install both compilers on your hard disk without causing any conflict.
   Because both compilers use the same library and include files, and because
   both compilers use the same environment variable names to locate these
   files, you won't have to create separate directories for each compiler's
   library and include files. The only planning and organizational work
   you'll need to do is to organize the compiler files and the source code
   files.

   Any program that you can compile with QuickC can be recompiled without
   change by Microsoft C 5.0. QuickC's fast compiler can save time in program
   development, and then the sophisticated optimizations of Microsoft C 5.0
   can speed the execution of your program. Furthermore, QuickC provides
   syntax checking for features unique to Microsoft C 5.0. If a program is
   syntactically correct but uses features of the larger compiler (the huge
   memory model, for instance), QuickC simply ignores those features when you
   run the program.
   ──────────────────────────────────────────────────────────────────────────

   Note that SETUP overwrites any file with the same name as a QuickC
   distribution file. If you follow our recommendation to create a new
   directory for QuickC, \QC, in your root directory, you eliminate this
   problem.

   The M option in the SETUP command lets you use the "medium memory model"
   to compile programs. Note that you can specify other or additional memory
   models when you run SETUP. (See the manual for details.) Although we will
   explain all memory models in later chapters, we use the medium model
   throughout this book because it is the only supported model for programs
   compiled in the QuickC environment. (If you use the command-line compiler,
   which assumes a small model, you might want to create a small model
   combined library that conveniently collects all of the functions you
   normally use with QCL. You can create new combined libraries without
   running SETUP again.)

   The EM in the SETUP command specifies that all floating-point arithmetic
   be performed by software "emulation" of the 8087 math coprocessor chip. If
   you have an 8087/80287/80387 chip in your PC, you might prefer to use the
   87 option which directs floating-point calculations to the coprocessor.
   When QuickC builds your core library, it uses this specification to select
   the appropriate floating-point library. Note, however, that any .EXE file
   you create with the 87 option will not run on machines without a math
   coprocessor. If you are concerned about portability, use EM when you set
   up QuickC. The QuickC environment uses only the emulator; if a coprocessor
   is present the emulator detects that fact and uses it.

   Finally, the GR option specifies that QuickC's Graphics Library functions
   be included in your combined libraries. We recommend that you use this
   option so that you can run the graphics programs in this book without
   specifying the GRAPHICS.LIB every time you link. (Of course, if your
   computer has only a monochrome text display, you should not use this
   option. This installation will proceed, but programs that you subsequently
   create that use graphics will not work.)

   After you enter the initial SETUP command, the program asks you if you
   want to delete the "library subcomponents," or parts of libraries that are
   not needed for the configuration you chose. Unless you plan to use memory
   models or floating-point packages other than those specified in the SETUP
   command, you can save a lot of disk space by typing y at this prompt. The
   SETUP program then prompts you to insert the appropriate distribution
   disks in drive A.

   Without any further input, SETUP creates the QuickC directories, places
   header files in the \INCLUDE subdirectory, creates a "combined library"
   for each specified memory model using the floating-point option you
   selected, and places the combined libraries in the \LIB subdirectory. This
   library is called your "standard library" because it contains compiled
   versions of all the standard C routines (with specified options, such as
   graphics).

   If you have already edited your MS-DOS AUTOEXEC.BAT and CONFIG.SYS files,
   your QuickC environment is now set up and ready to use. Please skip the
   next section, which is for floppy-disk users.

Setting Up QuickC for Floppy-Disk Systems

   Setting up QuickC for a floppy-disk system differs from hard-disk setup in
   two principal ways: First, the floppy-disk setup does not create the
   NEW-VARS.BAT and NEW-CONF.SYS files, so you have to set your own MS-DOS
   variables; second, because you have only 720 KB of disk space on two
   floppy drives, you must be more choosy about which files to install. (If
   you have two 1.4 MB 3.5-inch disk drives, as found in the IBM PS/2 line,
   you need not be so constrained.)

   As explained in the Microsoft QuickC Programmer's Guide, you need to
   format at least two floppy disks: one disk for each memory model and one
   "scratch" disk to hold temporary files created during the setup process.

   Insert your copy of the Libraries Disk #1 in drive A and a blank formatted
   disk in drive B. You are now ready to run SETUP. We recommend that you
   type the following command:

   setup f b: m em gr

   This specifies a floppy-disk setup that places the combined library on
   drive B. The M option lets you use the "medium memory model" to compile
   programs. Although we will explain all memory models in later chapters, we
   use the medium model throughout this book because it is the only model
   supported for programs compiled in the QuickC environment.

   The EM in the setup command specifies that all floating-point arithmetic
   be performed by software "emulation" of the 8087 math coprocessor chip. If
   you have an 8087/80287/80387 chip in your PC, you might want to use the 87
   option instead. When QuickC builds your core library, it uses this
   specification to select the appropriate floating-point library. Note,
   however, that any .EXE file you create with the 87 option will not run on
   machines without a math coprocessor. If you are concerned about
   portability, use EM when you set up QuickC.

   Finally, the GR option specifies that QuickC's Graphics Library functions
   be included in your combined libraries. We recommend that you use this
   option so that you can run the graphics programs in this book without
   specifying the library GRAPHICS.LIB every time you link. (Of course, if
   your computer has only a monochrome text display, you should not use this
   option. The installation will proceed, but programs that you subsequently
   create that use graphics will not work.)

   As it builds the QuickC combined library, SETUP prompts you for the
   necessary disks. The setup process on floppy disks can take as long as 15
   minutes, so don't be alarmed at the seemingly interminable grinding of the
   disk drives. To create library disks for additional memory models or other
   floating-point options, run the SETUP program again.

   Setting Up the MS-DOS Environment

   Because the floppy-disk setup procedure does not create the NEW-VARS.BAT
   and NEW-CONFIG.SYS files, you need to set the MS-DOS variables yourself.
   To do this, add the following two variables to your AUTOEXEC.BAT file:

   set include=a:\include
   set lib=b:

   (If you do not have an AUTOEXEC.BAT, create one and type in the preceding
   variables.)

   This tells QuickC to look for include files in A:\INCLUDE and for
   libraries on drive B.

   Also, edit your CONFIG.SYS so that it assigns values of at least:

   files=15
   buffers=20

   Note that you will have to reboot your system if you are planning on
   running QuickC right away, so the new setting will take effect. Figure
   2-4 summarizes how QuickC is set up and run on floppy disks.

           Drive A                      Drive B
       ┌──────────────────┐          ┌──────────────────┐
       │ QC.EXE           │          │ MLIBCE.LIB       │ ───── Libraries
       │                  │          │                  │
       │                  │          │ QCHELLO.C        │ ▒──── Your source
       │                  │ ◄──────► │ CIRCLE.C         │ ▒     files
       │                  │          │                  │
       │                  │          │ QCHELLO.EXE      │ ▒──── Temporary
   ┌──│                  ◄──┐       │ ────────         │ ▒     and object
   │  └──────────────────┘  │       └──────────────────┘       files
   │                        │
   │  Swapped after startup │
   │  ┌──────────────────┐  │
   └──►                  ├──┘
       │ \INCLUDE         │───── Include files
       │                  │
       │ QC.OVL           │───── Overlay file
       │                  │
       │ QC.HLP           │───── Help screens
       │                  │
       │ LINK.EXE         │───── Linker
       └──────────────────┘

   Figure 2-4. Floppy-disk setup for QuickC.

   Differences for Floppy-Disk Users

   The examples in this book assume you have a hard disk with QuickC residing
   in a directory on drive C. Floppy-disk users can use these examples by
   substituting references as follows:

   Hard Disk                            Floppy Disks
   ──────────────────────────────────────────────────────────────────────────
   c:\qc\bin                            a:
   c:\qc\include                        a:\include
   c:\qc\lib                            b:
   ──────────────────────────────────────────────────────────────────────────


Starting QuickC

   Now we're ready to start using QuickC.

   If you have QuickC on a hard disk and have correctly included \QC\BIN in
   the PATH variable in the AUTOEXEC.BAT file, run QuickC by typing

   qc

   at the C> prompt. (If you haven't changed your PATH variable to include
   \QC\BIN, you must change to this directory before you can run QuickC.)

   To use QuickC on a floppy-disk system:

   1.  Boot your system with an MS-DOS disk that contains the new QuickC
       AUTOEXEC.BAT and CONFIG.SYS files

   2.  Put your copy of the Product Disk in drive A

   3.  Start QuickC by typing qc at the A> prompt

   4.  When the QuickC screen appears, replace the disk in drive A with a
       copy of the Work Disk

   Drive A now contains an "overlay" file (this lets QuickC access files
   without further disk swapping), the Help menus, the linker, and the
   \INCLUDE directory.

Improving the QuickC Display

   When you type qc on the MS-DOS command line, QuickC assumes you have a
   color monitor. If you have a monochrome monitor, this default setting can
   reduce the contrast of the characters on your screen and make them hard to
   read. To fix this, exit QuickC by selecting Exit from the File menu, and
   start QuickC in its "black-and-white" mode by typing qc /b.

   If you use a computer that refreshes the screen at a faster rate than
   standard ATs, such as some higher-performance models of COMPAQ computers,
   you can speed screen displays by using the command qc /g to start QuickC.

   If your computer has an EGA card, you can set the screen to display 43
   lines, instead of the normal 25, by starting QuickC with the qc /h
   command. Note that unless you have a high-resolution monitor, text can be
   very hard to read in this mode.

   You can combine these modes by separating them with a space. For example,
   qc /b /g starts QuickC in monochrome mode and accelerates the screen
   refresh rate. You can also put the qc command and options in a batch file
   so you don't have to type them each time you start.

Overview of the QuickC Screen

   If you've used menu-based integrated programming environments such as
   Turbo Pascal and Microsoft QuickBASIC before, the QuickC screen should
   look familiar. (See Figure 2-5.)

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 2-5 can be found on p.35 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 2-5. QuickC startup screen.

   Notice the following screen elements:

   ■  The menu bar across the top of the screen lists the following options:
       File, Edit, View, Search, Run, Debug, Calls, and Help.

   ■  The "title bar" displays the name of the program currently loaded into
       the editor. (Because we haven't written a program yet, it now reads
       untitled.c.)

   ■  The main area of the screen, now blank, is the workspace for your
       program.

   ■  Two "scroll bars," a vertical one on the right side of the screen and a
       horizontal one near the bottom of the screen, let you use an optional
       mouse to scroll text up and down or side to side.

   ■  The status line at the bottom of the screen keeps track of the name of
       the current program, the status of your program, and the current cursor
       position. Note the Context section of the line. QuickC uses this area
       to remind you of your current stage of program development. Because no
       program is loaded, it reads <Program not compiled>.

Making Selections

   The Microsoft QuickC Programmer's Guide gives exhaustive information on
   how to select menu items, move among parts of a dialog box, accept or
   cancel selections, and so on. Following is a brief and convenient summary
   of this material, explaining both keyboard and mouse commands. The QuickC
   manual also discusses several alternative selection methods you might want
   to explore. To save space and time we show only one method each for mouse
   and keyboard.

   Keyboard Shortcuts ("Hot Keys")

   QuickC lets you select certain frequently used menu items without opening
   the menu first. These "shortcut" or "hot" keys are particularly handy when
   you use the editor. Here are some of the most useful ones:

   Key                      Function
   ──────────────────────────────────────────────────────────────────────────
   F2                       Open last file used
   Alt-Backspace            Undo last edit
   Shift-Del                Cut marked text
   Ctrl-Ins                 Copy marked text
   Del                      Clear editor buffer
   F4                       View output screen
   Ctrl-/                   Search for selected text
   F3                       Repeat last search
   Shift-F3                 Find next error
   Shift-F4                 Find previous error
   Shift-F5                 Start program
   F5                       Continue stopped program
   ──────────────────────────────────────────────────────────────────────────

   (The Microsoft QuickC Programmer's Guide contains additional
   combinations.)

   The Mouse

   Although you can select all QuickC functions from the keyboard, you might
   want to try using a mouse if you have one. With a mouse, you need only to
   point and click to select anything on the screen. Because you don't have
   to learn all the keystroke combinations for making selections or using the
   editor, you can concentrate on learning C right away. Further, the mouse
   makes it easier to select items from a dialog box. You might want to learn
   both the mouse and keyboard methods and see which one best suits you. Or
   you can mix them, using the keyboard for making menu selections and the
   mouse for making selections in dialog boxes, for example.

   You must use a Microsoft mouse or a compatible mouse (such as the IBM PS/2
   mouse or the Logitech serial mouse) with QuickC. Before you can use any
   mouse with QuickC, however, you must install a "mouse driver," either in
   your CONFIG.SYS file or as a .COM file in your AUTOEXEC.BAT. (See your
   mouse documentation for instructions.) The driver is the software that
   lets QuickC recognize the mouse and respond to its movements as though
   they were commands. If you currently use a mouse for other programs, your
   system is probably set up correctly already.

Writing a Program

   Now we're ready to write a simple C program, which we will call QCHELLO.C.
   First, select the File menu. If you have a mouse, move the mouse until the
   pointer on the screen is on the File menu, and click the left button. This
   reveals the menu, as shown in Figure 2-6. Now, move the pointer to the
   Open option, and click the left button again. To reveal the File menu
   using the keyboard, press the Alt key and then press the f key. Notice
   that each menu item has a highlighted letter (often, but not always, the
   first letter in the word or phrase). Type this letter to select the menu
   item. Select the Open option by typing o.

   Note the Exit option in the File menu. Choose this option when you're
   ready to end your QuickC session. If you select Exit after changing your
   current program, QuickC first asks if you want to save the changed
   program. When you exit QuickC, you return to the MS-DOS prompt.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 2-6 can be found on p.37 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 2-6. QuickC File menu.

Selecting a File

   When you select the Open option on the File menu, a dialog box appears.
   (See Figure 2-7.) QuickC uses dialog boxes to obtain the information it
   needs to carry out your request.

   You can select a file from a dialog box in two ways. Notice the long
   rectangle near the top of the dialog box with a cursor blinking in it.
   Typing a filename in this rectangle is the most straightforward method of
   selecting a file. Below is a larger rectangle with some names in it. This
   box lists the contents of the current directory. Names in ALL CAPS are
   directories; names in lowercase are files. (The contents of the current
   directory in your system may vary from those in the example.)

   To make a selection from a dialog box:

   ■  With a mouse, move the pointer to the item you want. Click the left
       button to select the item.

   ■  With the keyboard, use the Tab or back-Tab (shifted tab) key to move
       from one section of the dialog box to another. Press Enter to select
       the item.

   When you select a directory, QuickC lists all files and subdirectories in
   that directory. Each list you display also has a .. entry. Selecting this
   entry moves you back to the parent directory of the directory shown. Thus
   you can easily browse through the file system with only a few keystrokes.

   With the back-Tab or your mouse, move the cursor to the File Name text
   box. Type qchello.c and then press the Enter key. Another small dialog box
   appears to inform you that this file does not exist. Accept the default of
   Yes to create it.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 2-7 can be found on p.38 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 2-7. File "Open" dialog box.

Typing in the Program

   You are now ready to type in a program. QuickC's default mode is in fact
   "edit mode," and the large area of the screen with the cursor in it is the
   Edit window. As you type the listing below, use the arrow keys to move the
   cursor, the Backspace key to make corrections, and press Enter at the end
   of each line. After you enter the text shown in Listing 2-1, your screen
   should look like Figure 2-8.

   ──────────────────────────────────────────────────────────────────────────
   /* qchello.c -- a simple C program */

   main()
   {
       printf("Hello, and welcome to QuickC!\n");
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 2-1.  The QCHELLO.C program.

What Does It Do?

   Although we won't look at the structure and anatomy of C until the next
   chapter, this program gives you a hint of C style. The first line
   (enclosed by the characters /* and */) is a comment that briefly describes
   the program. It is optional but highly recommended. The word main()
   indicates the beginning of the main function or related group of
   statements in the program. (Most C programs have many functions in
   addition to the main one.) As the name suggests, printf() prints the
   string in the parentheses that follow. The braces, { and }, set off the
   group of statements (only one in this case) that make up the main
   function. So, it's easy to see what this program does: It prints Hello,
   and welcome to QuickC! on the screen. (The \n at the end of the string
   simply moves the cursor to the beginning of a new line.)

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 2-8 can be found on p.39 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 2-8. QCHELLO.C as typed into the edit window.

Running QCHELLO.C

   Running the program is simple. Select the Run menu. As you probably know,
   before we can run our program we must first compile and link it. The Start
   option in the Run menu executes all of these steps for you.

   When you select Start, a dialog box tells you that the program has been
   "modified" and asks if you want to "rebuild" (compile and link) it.
   Whenever you change a program, you must recompile. QuickC treats this new
   program as a changed program, so press Enter or click on Yes to compile
   it.

   Before you can blink an eye, QuickC compiles and runs the program. QuickC
   is fast, as you will see when you write longer programs, and because this
   little program doesn't use any include files or libraries, it compiles
   instantaneously.

   After the program runs, the screen displays the following:

   Hello, and welcome to QuickC!
   Program returned (13). Press any key

   You are now looking at the "output screen." QuickC keeps track of the
   output screen, which always holds the results of your programs, so you can
   switch back and forth between it and the QuickC environment screen. Press
   any key to return to QuickC. For now, don't worry about the return value
   mentioned in the second output line.

Saving the Program

   To save this program to disk for future reference, open the File menu
   again. Notice the Save and Save As options. Select Save to write the
   program to disk. If you want to save the program with a new name, select
   Save As. When the dialog box appears, type the new name and press Enter.
   (You might try QCHELLO2.C.)

Compiling to a .EXE File

   QuickC compiles programs to memory by default. Because it is fast, this is
   often the best way to compile while developing a new program. However, the
   compiled version of a program compiled to memory disappears when you
   compile another program or quit QuickC. Eventually you need a compiled
   version of the program on disk, so you can run it without recompiling.
   Also, you eventually want to create programs that a user can run directly
   from MS-DOS without QuickC available. To produce an MS-DOS-executable
   file, we need to "compile to .EXE."

   Select the Run menu. Now select the Compile item. The dialog box shown in
   Figure 2-9 appears.

   This large dialog box lets you select many options. (We will explain the
   options later as we use them.) Notice the center column, Output Options.
   The small black dot in the parentheses next to the word Memory indicates
   that it is the currently selected output option. We want to change this
   option to Exe. If you have a mouse, move the pointer between the
   parentheses next to Exe and click. From the keyboard, you can move the
   cursor to this position with the Tab and Down Arrow keys and press Enter.
   But there's an even faster way. Note that the letter x in Exe is
   highlighted. To select this item, you need only type the letter x.

   Now you can compile the program. Note the four small rectangles at the
   bottom of the dialog box. The first one, Build Program, has a double
   border, which signifies that it is the default. You can select it in one
   of three ways: tab to it and press Enter, click on it with a mouse, or
   type b.

   The Compile box displays the numbers of the program lines being processed
   as the program is compiled. Because this program is being compiled as a
   stand-alone .EXE file, it must be linked to various disk files.

   Very quickly, the program returns you to the familiar QuickC environment
   screen. Note that the program didn't run and produce output as it did when
   you compiled it earlier. This compile created a .EXE file, and these
   executable files cannot be run directly from QuickC. However, QuickC
   provides an easy way to run it.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 2-9 can be found on p.41 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 2-9. Compile dialog box.

Escaping to MS-DOS

   At the File menu, select the item DOS Shell. This option switches the
   display to the output screen where the MS-DOS sign-on message and prompt
   appear. You can now run any MS-DOS command, as well as most programs and
   batch files.

   To run QCHELLO.EXE, type:

   C>qchello

   The screen displays the expected output. (No instruction to press a key
   appears, of course, because QuickC is not running. We are at the MS-DOS
   level.)

   Now type:

   C>exit

   to return to QuickC exactly where you left off.


Getting Help

   We will not cover every feature of QuickC in this book so that we can
   devote more time to C itself. Although we occasionally refer you to the
   QuickC manual, there's another source of help as near as your keyboard──
   the QuickC Help facility. In fact, you can select from three levels of
   help: general, topic, and keyword.

General Help Screens

   Press the F1 key to select the General help option (or use the mouse to
   make the selection). The first screen you see is shown in Figure 2-10.
   Notice that it displays a summary of some editor commands as well as some
   other frequently used commands. The small rectangles at the bottom of the
   dialog box let you select the Next or Previous help screen. Next, with its
   double border, is the default. Press Enter or click on the box with the
   mouse to display the next screen. Don't try to memorize or even understand
   these screens. Just get an idea of the general information that is
   available for future reference.

Topic Help

   If you select Topic help, you can page through lists of topics until you
   find the information you are looking for. (See Figure 2-11.) For example,
   you could select "preprocessor directives," and then select the particular
   directive for which you want help. To choose Topic help directly from the
   editor window, press Shift-F1.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 2-10 can be found on p.43 of the printed version of the book.   │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 2-10. A QuickC help box.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 2-11 can be found on p.43 of the printed version of the book.   │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 2-11. Topic help.

Keyword Help

   Return to the editor window, and move the cursor to the word printf.
   Suppose you are writing a program and you are not sure how this C function
   works. By pressing Shift-F1, you can retrieve information about the C
   keyword or standard function currently marked by the cursor. (See Figure
   2-12.)

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 2-12 can be found on p.44 of the printed version of the book.   │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 2-12. Keyword Help screen.


Fixing Errors

   The last section of this chapter discusses how to fix errors in a C
   program. The QCHELLO.C program should still be in the Edit window. Let's
   make some changes in the program so we can practice fixing errors.
   (Normally, we programmers don't have to manufacture errors; we run into
   enough of them on our own!)

   Use the arrow keys or the mouse to move the cursor to the word printf.
   Change it to primtf. Next, go to the end of the line and delete the
   semicolon.

   Now select Run and Start to compile and run the program. QuickC soon
   displays a rectangular error window at the bottom of the screen as shown
   in Figure 2-13.

   The error message tells you that a semicolon is missing before the closing
   }. Notice on your screen that the cursor in the edit window is on the
   character immediately following the error. This makes it easy to find and
   correct the error. (In this case, the next character is on the next line,
   however, so you have to move the cursor to the end of the preceding line
   to insert the semicolon after the ).

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 2-13 can be found on p.45 of the printed version of the book.   │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 2-13. Error window.

   Now run the program again. The next error message, `primtf' : unresolved
   external, is less clear than the preceding one. Simply stated, it means
   that primtf is not one of the standard QuickC functions. When you change
   the m back to an n, the program again runs correctly.


Preparing for the Next Chapter

   In the next chapter we begin our study of the elements of the C language.
   Although we discuss additional QuickC features as needed, we will not
   concentrate on using the QuickC environment. So now is a good time to get
   comfortable with your new QuickC environment.

   We recommend that you try the following:

   ■  Save QCHELLO.C under another name, and then use the Open option in the
       File menu to load it into the editor.

   ■  Practice compiling and running the program to memory and to a .EXE
       file.

   ■  Use the DOS Shell item of the File menu to exit to MS-DOS, run a .EXE
       program, and then use Exit to return to QuickC.

   ■  Make some errors in QCHELLO.C and try running the program. Observe the
       error messages, fix the errors, and run the program again. What happens
       if the last } is missing? What happens if you change the word "Hello"
       to "Hi"?

   ■  Read Chapter 6 in the Microsoft QuickC Programmer's Guide to learn
       about the advanced features of the editor. We suggest you study them
       when you want a break from reading this book. None of these editor
       features are needed for you to use this book, but they make it easier
       to enter and modify long programs. Remember to use the Help screen to
       remind you of common editing functions.



────────────────────────────────────────────────────────────────────────────
PART 2  CORE OF C
────────────────────────────────────────────────────────────────────────────



────────────────────────────────────────────────────────────────────────────
Chapter 3  C Fundamentals

   Now that you feel comfortable in the QuickC environment, we can turn our
   attention to the fundamentals of C. First, let's look at the basic
   elements of a C program.


Basic Elements of C Programs

   The simplest possible C program, which we call TINY.C, is shown in Listing
   3-1 on the following page. Type this program into the QuickC editor; then
   run it with the Start option from the Run menu. (We recommend that you
   enter and run all sample programs in this book──we believe this will help
   you better understand and remember the concepts we discuss.)

   As you probably suspected, this program doesn't actually do anything when
   you run it. QuickC generated the message Program returned 1. Press any
   key, but the program produced no output at all. The main() function
   returns the value 1, in this sample, to the operating system. (The actual
   value might be different on your machine.) This value is significant only
   if you control it deliberately, as you might want to do when you call a C
   program from another program, for example.

   ──────────────────────────────────────────────────────────────────────────
   /* tiny.c -- the smallest possible C */
   /*           program with comments   */

   main() /* function name and argument list */
   {
           /* function definition in braces */
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-1.  The TINY.C program.

A Program Consists of Function Definitions

   As simple as it is, however, this program illustrates a basic element of
   C──A C program is essentially a set of function definitions. A function
   contains statements (instructions) that the program "calls" to perform
   specific tasks. A function definition must contain at least the following
   elements:

   ■  The function name

   ■  An "argument list" enclosed in parentheses

   ■  A group of statements that define the function

   In practice, and especially with programs written in the new ANSI C
   standard, function definitions can be more complicated than this. But this
   simplest definition is all we need until we look at functions in more
   detail in Chapter 6.

   TINY.C has only one function, main(). The argument list, which follows the
   function and is enclosed in parentheses, often contains "parameters," or
   formal descriptions of information, that the function uses when it is
   called (executed). Although an argument list can also be empty, as it is
   in main(), the parentheses are still required. Because main() contains no
   function definition statements, the program does nothing when you run it.

   The QCHELLO.C program we developed in the last chapter is an even better
   example of the elements of a C program. Figure 3-1 identifies the parts
   of QCHELLO.C.

               Function name               Argument list
                   │                         │
                   └──────────┐   ┌──────────┘
                           main ( )
                           ┌─
                           │ {
   Function definition  ───┤     printf("Hello, and welcome to QuickC!\n");
   enclosed in braces      │ }   │                                        │
                           └─    └──────────────────┬─────────────────────┘
                                                   │
                                       Statement in function definition

   Figure 3-1. Parts of the QCHELLO.C program.

A Function Definition Consists of a Group of Statements

   In C, a pair of braces ({ and }) encloses a group of statements. Notice
   the part of the program between the braces in Figure 3-1. The statement
   here defines the function main(). All stand-alone C programs begin with
   main(). The statements within braces are sometimes called the "function
   body," to distinguish them from the function name and argument list, which
   together form the "function header."

   The function body can consist of any number of program statements. Note,
   however, that the braces are still required even if the definition
   contains no statements. Think of braces as symbols that delimit
   "paragraphs" of C code.

   A Statement Is like a Sentence

   A statement in C consists of keywords, variable and function names, and
   operators, and, like an English sentence, describes a complete action.
   Statements always end with a semicolon. Below are some example C
   statements and their meanings:

   printf("This is a statement");─────────────────Print This is a statement
   count = 1;───────────────────────────────────Set the variable count to 1
   getche(ch);───────────────────────────Wait for user to type a character,
                                           assign it to the variable ch, and
                                           echo (display) it on the screen

   QCHELLO.C has only one statement, printf("Hello, and welcome to
   QuickC!\n"); this statement translates as "Print the string `Hello, and
   welcome to QuickC!' and then go to the next line." (The \n specifies a
   newline character that moves the cursor to the next line.) This statement
   completely defines the function main() and describes what happens when the
   program executes the function.

   A Statement Can Contain Expressions

   Can an expression, such as count + 2, be a statement? Well, it doesn't end
   with a semicolon. But more importantly, it is not a complete statement.
   The word and number merely express a quantity ("two more than the value of
   the variable count"): They don't do anything with the quantity.

   Although an expression by itself is not a statement, it can be an
   important element of a C statement. For example, count = count + 2; is a
   complete C statement that assigns the quantity of the expression to the
   variable count.

   A Statement Can Call Functions

   Let's look at QCHELLO.C in more detail. (See Figure 3-2 on the following
   page.) What exactly is the printf() function at the start of the statement
   that defines the main() function? If you know BASIC, you might say, "It's
   the command you use to print in C." This isn't really correct, however. In
   BASIC, PRINT is a built-in BASIC command (or keyword) that prints a string
   or number. In C, printf doesn't execute a built-in command; it calls a
   function named printf() and gives ("passes") it an argument (or parameter)
   that tells it what to print.

               Function name               Argument list
                   │                         │
                   └──────────┐   ┌──────────┘
                           main ( )
                           ┌─
                           │ {
   Definition of main() ───┤     printf ("Hello, and welcome to QuickC!\n");
   function in braces      │ }     │     │                                 │
                           └─      │     └───────────┬─────────────────────┘
                                   │                 │
                               Name of    Argument list (string to print)
                               function
                               being called

   Figure 3-2. Parts of QCHELLO.C revisited.

   Compare the printf() statement with the line containing main(). Both
   consist of a name followed by parentheses: that is, a function name and an
   argument list──the list for main() is empty. (Note that when we show
   function names in text, we use a trailing set of parentheses to
   distinguish them from other C elements.)

   The main() function name with its empty argument list are followed by a
   pair of braces that enclose the function definition. (You'll notice in
   QCHELLO.C that no semicolon follows main() because the line isn't a
   complete statement: It's the header for the function definition that
   follows.) The line with printf(), however, needs no defining group of
   statements because we are not defining printf() here; we're merely using,
   or "calling," the function in a statement. To call a function, simply use
   its name and argument list in a statement. We refer to statements such as
   the printf() line as "function calls."

   Always remember that every function must be defined before you can call
   it, otherwise QuickC would not know what statements to use when it tries
   to compile the function name. So where is the definition of the printf()
   function we called in Figure 3-2? The printf() function is a "core
   library function." Its definition is built into QuickC so that your
   program always has access to it. When you link your program, QuickC
   inserts the appropriate machine code for printing.

   ──────────────────────────────────────────────────────────────────────────
   Quick Tip
   If you know Pascal, you recognize the use of the semicolon to end
   statements in C. However, there is one important difference between its
   use in C and in Pascal. In Pascal, the semicolon can be omitted if the
   statement is the last statement in a group (the statement before the word
   END). In C, every statement ends with a semicolon.

   Also notice that the braces in C serve the same function as the Pascal
   keywords BEGIN and END: They delimit a group of statements.
   ──────────────────────────────────────────────────────────────────────────

   We stress the difference between C's library functions and the built-in
   commands of some other languages to emphasize the all-important role that
   functions play in C. C makes no distinction in syntax between QuickC
   library functions, such as printf(); functions that you define yourself,
   such as main(); and C header files developed by Microsoft or other
   vendors.

The Flow of Execution Starts with main()

   When you run a C program, execution always begins with the function named
   main(), which must be present. What QuickC executes next depends on the
   functions that main() calls in its definition. In QCHELLO.C, execution
   starts with main(). In the definition of main(), QuickC encounters the
   name printf() and executes that function.


Punctuation and Spacing in C Programs

   Generally speaking, QuickC lets you break lines of code almost anywhere or
   insert many spaces (or none) between program elements. For example, you
   could rewrite the QCHELLO.C program as:

   main(){printf("Hello, and welcome to QuickC!\n");}

   or, at the other extreme, you could add line breaks to produce the
   NARROW.C program shown in Listing 3-2. There are, however, some
   exceptions to C's tolerance of white space and "free-form" syntax. You
   can't split a function name across two lines because the compiler reads
   the newline character at the end of the line as part of the function name.
   Also, you can't break a quoted string, such as the "Hello, and welcome to
   QuickC!" in our printf() statement, between two lines because the compiler
   won't let you use the newline character in a "string constant" (although
   you can specify a newline with the escape sequence \n, as we have seen).

   Because C is a somewhat cryptic language, you should use spacing and
   alignment of code to make it easier for other programmers to read and
   revise your programs. (Remember, after a few weeks you, too, are "another
   programmer" when you look at your code.) You'll also find that aligning
   braces vertically helps you avoid errors: The vertical alignment lets you
   easily match beginning and ending braces.

   ──────────────────────────────────────────────────────────────────────────
   /* narrow.c -- a choppy c program */

   main
   (
   )
   {
   printf
   ("Hello, and welcome to QuickC!\n");
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-2.  The NARROW.C program.


Using Comments in C

   Listing 3-1 on p. 50 contains several lines or parts of lines that begin
   with /* and end with */; for example:

   /* tiny.c ── the smallest possible C program */

   These lines are comments, or nonexecuting remarks, that explain how a
   program works. We strongly encourage you to use comments in your programs;
   they make the program much easier for a reader to understand. Because
   QuickC ignores comments, they can follow a program statement on the same
   line or cover many separate lines. The program examples in this book have
   an introductory comment, and we insert other comments where appropriate.

   Below are several different styles you can use for comments:

   /* Comment line one */
   /* Comment line two */

   or

   /* Comment line one
   comment line two */

   or

   /* Comment line one
   /* Comment line two
   /* Comment line three */

   However, you can't insert a comment within a comment as follows:

   /* Comment line one
   /* Nested comment line two */
   Comment line three */

   The reason you can't "nest" comments is that once the compiler sees the
   beginning of a comment (the /*), it considers everything that follows
   (including another /*) to be part of the comment until it sees */. In the
   nested comment above, the compiler considers the comment ended at the */
   after the word two. It then treats the word Comment on the next line as an
   undefined function or variable name.

   ──────────────────────────────────────────────────────────────────────────
   Quick Tip
   Many versions of Pascal use both /*...*/ and {...} to enclose comments. In
   C, you can never use braces for comments: They serve only to begin and end
   groups of statements.
   ──────────────────────────────────────────────────────────────────────────


Data Types and Declarations of Variables

   Variables are names for memory storage areas used by a program. Variables
   come in many shapes and sizes. Many BASIC programmers get along reasonably
   well using only two types of variables: numeric (representing a number)
   and string (representing a series of characters). A BASIC programmer might
   write:

   ITEM$="WIDGET"
   SERIAL=32767

   to define two variables. The $ at the end of ITEM signifies a string
   variable; its absence in SERIAL specifies a numeric variable. A BASIC
   interpreter sets up these variables "on the fly" as it analyzes the lines
   of code, without storing them in a particularly efficient way.

   With C, the situation is more complicated. In order to use computer memory
   more efficiently, the C compiler reserves a specific location in memory
   for each variable. To do this efficiently, it needs to know exactly how
   many bytes of storage to use and how to store the data in those bytes.
   Therefore, C uses many "data types" to specify such things as the range of
   numbers that a variable can hold, whether negative values should be
   accommodated, whether values can be integers only or include decimal
   fractions, and so on. If you are a BASIC programmer, this constant
   attention to data types takes a little getting used to. However, by the
   end of this chapter, you will know all the available types and when each
   should be used.

   Let's begin our survey of data types by considering some different types
   of data we might store in variables:

   ■  30 (the number of students in a class)

   ■  557,617,814 (number of seconds since a date in 1970)

   ■  22.95 (price of a computer book?)

   ■  1,000,000,000,000.00 (future U.S. budget?)

   ■  a (the letter a)

   As you probably know, data is stored in a computer as patterns of bits: 1s
   and 0s, "ons" and "offs." In the IBM PC family of computers, bits are
   organized in groups of eight (called bytes), or in groups of two bytes
   (called words), or in groups of four bytes (double words), depending on
   the operation involved and the processor used. Figure 3-3 on the
   following page shows how many bytes are needed to store the different
   sizes and kinds of numbers in the above list. The figure also shows the
   name of the data type that describes the storage involved. The addresses
   shown are arbitrary, but they demonstrate how successive items are stored
   with lower addresses.

   The QuickC sizeof operator returns the number of bytes that a given data
   type uses. The program VARSIZE.C (see Listing 3-3 on the following page)
   uses this operator and a series of printf() statements to print out the
   sizes (in bytes) of the following data types: char, int, long, float, and
   double.

                                       ADDRESSES   DATA                  TYPE
   Stored          ┌──────────────┐
   "downward"        │              │ 5003
   in memory         ├──────────────┤                                   char
       │      1 ─── ▒│              │ 5002 ▒ ──── a
       │     byte    └──────────────┘
       │             ┌──────────────┐
       │            ▒│              │ 5001 ▒
       │      2 ─── ▒├──────────────┤      ▒ ──── 30                    int
       │    bytes   ▒│              │ 5000 ▒
       ▼             └──────────────┘
                   ┌──────────────┐
                   ▒│              │ 4999 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4998 ▒
               4 ─── ▒├──────────────┤      ▒ ──── 557,617,814           long
           bytes   ▒│              │ 4997 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4996 ▒
                   └──────────────┘
                   ┌──────────────┐
                   ▒│              │ 4995 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4994 ▒
               4 ─── ▒├──────────────┤      ▒ ──── 22.95                 float
           bytes   ▒│              │ 4993 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4992 ▒
                   └──────────────┘
                   ┌──────────────┐
                   ▒│              │ 4991 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4990 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4989 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4988 ▒
               8 ─── ▒├──────────────┤      ▒ ──── 1,000,000,000,000.00  double
           bytes   ▒│              │ 4987 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4986 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4985 ▒
                   ▒├──────────────┤      ▒
                   ▒│              │ 4984 ▒
                   └──────────────┘

   Figure 3-3. Storing information in memory.

   ──────────────────────────────────────────────────────────────────────────
   /* varsize.c -- shows amount of memory */
   /*              by various types       */

   main()
   {
       printf("Size of a char in bytes is %d\n", sizeof(char));
       printf("Size of an int in bytes is %d\n", sizeof(int));
       printf("Size of a long in bytes is %d\n", sizeof(long));
       printf("Size of a float in bytes is %d\n", sizeof(float));
       printf("Size of a double in bytes is %d\n", sizeof(double));
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-3.  The VARSIZE.C program.

   Here's the output of VARSIZE.C:

   Size of a char in bytes is 1
   Size of an int in bytes is 2
   Size of a long in bytes is 4
   Size of a float in bytes is 4
   Size of a double in bytes is 8

Declaring Variables

   To declare a variable, specify the data type and then the variable name.
   Here are some examples:

   int account_no;
   float balance;
   double budget;
   char acct_type;

   The first statement declares account_no as an integer (int) variable. The
   remaining statements declare variables as floating-point decimal (using
   the keyword float), "jumbo" 8-byte floating-point (double), and 1-byte
   character (char) data types.

   When you declare a variable, QuickC sets aside the appropriate number of
   bytes and notes the variable's starting address. The next program,
   VARADDRS.C (Listing 3-4), declares several types of variables and then
   prints out their starting addresses.

   ──────────────────────────────────────────────────────────────────────────
   /* varaddrs.c -- uses & operator to get   */
   /*               addresses of variables   */

   main()
   {
       char c1, c2;
       int i;
       long l;
       float f;
       double d;

       printf("Address of c1 %d\n", &c1);
       printf("Address of c2 %d\n", &c2);
       printf("Address of i  %d\n", &i);
       printf("Address of l  %d\n", &l);
       printf("Address of f  %d\n", &f);
       printf("Address of d  %d\n", &d);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-4.  The VARADDRS.C program.

   Although the output of this program varies with different system
   configurations, it should look something like this:

   Address of c1 6146
   Address of c2 6144
   Address of i  6142
   Address of l  6138
   Address of f  6134
   Address of d  6126

   VARADDRS.C obtains the addresses of the variables by using an ampersand
   (&) prefix with each variable name. The ampersand is the "address
   operator," and it returns the starting address for each variable
   specified. Compare the output of VARADDRS.C with Figure 3-3 to see how
   variables declared with different data types require different amounts of
   memory. When QuickC allocates the required number of bytes for a declared
   data type, the last byte allocated (moving downward in memory) is the
   variable's starting address. For example, the integer variable i has an
   address of 6142, indicating that it uses two bytes (6144 - 6142 = 2); the
   double type variable d uses eight bytes (6134 - 6126 = 8). Note that the
   compiler allocates two bytes for char values c1 and c2, although each
   value requires only one byte. The extra byte is convenient for
   manipulating (2-byte) words in memory.

Rules for Naming Variables

   In C, the names of variables and functions are called "identifiers." An
   identifier can contain any uppercase or lowercase alphabetic characters
   (A-Z or a-z), digits (0-9), and the underscore character (_). However, the
   name must begin with a letter or underscore. Below are some examples of
   legal and illegal names:

   bignum─────────────────────────────────────────────────────────────Legal
   BigNum───────────────────────────────────Legal, and distinct from bignum
   _video───────────────────────────────Legal, can begin with an underscore
   bal_due─────────────────────────Legal, underscore used to separate words
   player2───────────────────────────────────Legal, number in variable name
   8ball─────────────────────────────────Illegal, can't begin with a number
   tally-ho!─────────────────Illegal, contains hyphen and exclamation point
   int───────────────────Illegal, keyword reserved for name of integer type

   As you can see, you have considerable flexibility in choosing names for
   your variables. Because QuickC can distinguish the first 31 characters of
   a variable name, you can use long, descriptive names that help make the
   program easier to understand and modify. (You might want to use shorter
   names if your program must run a compiler that does not support long
   names.) C distinguishes between uppercase and lowercase characters, so
   that BigNum and bignum are different variables. Note that you can't begin
   a variable name with a number, use punctuation marks such as ! or $, or
   use C-language keywords as variable names. (You can embed a keyword in a
   variable name, however: interest is a legal name even though it contains
   the keyword int.) Fortunately, C has few keywords compared to languages
   such as BASIC: Most specify data types (such as int) or control and
   decision-branching operations (such as while and if).

   We use specific conventions for naming variables and functions. (See
   "Conventions and Style" in Chapter 1.) These are not required by QuickC,
   but are used here to differentiate among types of variables and functions.
   We also begin our variable names with a character other than an
   underscore──Microsoft uses the underscore as the initial character for its
   QuickC library functions.

Assignment Statements

   How do you assign values to variables? In C, the simplest assignment
   statement consists of a variable name followed by an equal sign (=) and
   the value to be assigned. Below are some examples:

   a = 5;
   b = a + 5;
   c = a + b;

   In these assignment statements, the value to the right of the equal sign
   is assigned to the variable on the left. The value can be a number or an
   expression involving variables and/or numbers, such as a + 5 or a + b. If
   the value is an expression, QuickC determines the result and then assigns
   it to the variable.

   You can also assign the same value to several variables at once. Usually,
   you do this to initialize variables by setting them all to 0 or 1:

   line_count = word_count = 0;
   line_no = page_no = 1;

Initializing Variables

   Many languages (including most versions of BASIC) automatically initialize
   numeric variables to 0 and character variables to blank or, perhaps,
   "null." C does not. For example, if your program has the following two
   lines:

   int length;
   printf("The length is %d\n", length);

   and you do not initialize length, it might produce the following output:

   The length is -25480

   The default value of a C variable is whatever pattern of bits happens to
   be in the memory locations of the variable when the compiler assigns them.
   Therefore, if you want to use a variable called total, for example, in a
   program that keeps track of some quantity, you should assign that variable
   an initial value of 0. You might modify the declaration above as follows:

   int length = 0;

   Because C is a concise language, it lets you combine the declaration and
   assignment of a variable. That is, you can declare the data type, the
   variables, and their values in the same statement:

   int a = 10, b = 50, c = 100;

Type int

   Now that you know how to declare numeric variables and assign values to
   them, let's look at the int, or integer, data type more closely. An
   integer is a whole number, such as 30, -5, or 93,000,000. In QuickC, an
   int variable can hold numbers in the range of -32,768 through 32,767. This
   rather odd-looking range is established because the int type uses two
   bytes (16 bits) of memory. Two bytes can actually hold a range of 0
   through 65,535. But, in the regular int type, the high (leftmost) bit of
   the 2-byte combination stores the integer's sign (positive or negative),
   leaving only 15 bits for the number.

   If your variable will never store negative integers, use the unsigned int
   type. Because the sign bit is not used, you can use the full two bytes to
   store values from 0 through 65,535.

   Now let's look at the INTVARS.C program (Listing 3-5), which declares
   three integer variables, assigns values to them, and then prints out
   values that describe the World War II German battleship Bismarck.

   We declare the variables length and beam as int types because the length
   and beam (width) of the ship are less than 32,767 feet. For the
   displacement variable (the "weight" of the ship), we use the unsigned int
   type because we need a larger number (41,676) than 32,767 (the int limit)
   but a smaller number than 65,535 (the unsigned int type limit).

   The next three lines assign the values to the variables, and the three
   printf() statements print the values out. Notice that the printf()
   statements use two arguments within the parentheses: a string, such as
   "The battleship Bismarck was %d feet long", followed by a comma and the
   variable name whose value is to be printed. The %d in the string is a
   printf() "format specifier," and the value of the variable is printed in
   its place. (The %d specifier denotes a decimal [base 10] integer. C uses a
   variety of specifiers for different types and formats of numbers and
   characters. We'll discuss them when we look at printf().) When you run
   INTVARS.C, it generates the output that appears below the listing (on the
   following page).

   ──────────────────────────────────────────────────────────────────────────
   Quick Tip
   ANSI C lets you specify any basic variable type as unsigned. It also lets
   you specify signed types. Therefore, although QuickC considers the int
   type to be signed by default, the C language doesn't guarantee that all C
   compilers do so. To write portable programs, you need to specify all
   variables as either signed or unsigned types.
   ──────────────────────────────────────────────────────────────────────────

   ──────────────────────────────────────────────────────────────────────────
   /* intvars.c -- declares, defines, and prints */
   /*              some integer variables        */

   main()
   {
       /* declare variables */
       int length, beam;
       unsigned int displacement;
       /* assign values to variables */
       length = 824;
       beam = 118;
       displacement = 41676;

       /* print out values */
       printf("The battleship Bismarck was %d feet long",
               length);
       printf(" with a beam of %d feet,\n", beam);
       printf("and displaced %u tons.\n", displacement);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-5.  The INTVARS.C program.

   The battleship Bismarck was 824 feet long with a beam of 118 feet,
   and displaced 41676 tons.

Long Integer Type

   We've seen that unsigned int variables can hold values to 65,535. But what
   if you must use larger numbers? Type long uses four bytes (32 bits) of
   memory (1 bit is reserved for the sign), and can store numbers from -2^31
   to +2^31, or -2,147,483,648 to 2,147,483,647 in base 10. Once again, if
   your variable will contain only positive numbers, you can double the high
   end of this range by specifying unsigned long. This lets you assign your
   variable a whole number value in the range 0 through 4,294,967,295.

   The SCORE.C program (Listing 3-6 on the following page) combines the
   declaration and assignment of the int variables home, visitors, inning,
   and attendance. Because total_attendance is a different data type, long,
   you must declare it in a separate statement. Again, the printf()
   statements display the values assigned to the variables and produce the
   following output:

   The score after 7 innings is
   Home team 5, Visitors 2.

   The attendance today is 31300.
   Attendance this year to date is 1135477.

   ──────────────────────────────────────────────────────────────────────────
   /* score.c -- defines and prints   */
   /*            int and long vars    */
   main()
   {
       /* declare some int variables and assign values */
       /* to them in the same statement                */

       int home = 5, visitors = 2, inning = 7, attendance = 31300;
       long total_attendance = 1135477;  /* long int */

       /* print out the values */

       printf("The score after %d innings is \n", inning);
       printf("Home team %d, Visitors %d.\n\n", home, visitors);
       printf("The attendance today is %d.\n", attendance);
       printf("Attendance this year to date is %ld.",
               total_attendance);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-6.  The SCORE.C program.

Floating-Point Types

   You should store whole numbers as integers wherever possible──integers use
   the least amount of memory and integer arithmetic is fast. However, many
   numbers (such as dollars-and-cents amounts) require decimal fractions. In
   computers, these types of numbers are stored in "floating-point format."

   Consider the number 22.95. This number can be stored by dividing it into
   two parts: the digits themselves and an exponent showing the magnitude of
   the number in terms of powers of ten. Thus, 22.95 could be represented as
   22.95 * 10^0. For uniformity in performing operations, however, C always
   expresses the digits with only one digit to the left of the decimal point.
   Therefore, the above number is actually stored as 2.295 * 10^1 (the same
   as 22.95 * 10^0). C represents this notation with the expression
   2.295e+001. The first element, 2.295, is the number's digits (the
   "mantissa"), and the e+001 represents "exponent 1," or 10^1.

Type float

   The most commonly used floating-point type in C is float. In QuickC, type
   float uses three bytes to store digits (the mantissa) and one byte to
   store the exponent. Because exponents can be negative (for example,
   1.4e-002 = .014), one bit of the exponent byte stores the sign. Converted
   into decimal terms, this means you can store a mantissa with seven
   significant digits and an exponent ranging from -38 to +38. In fact, with
   QuickC's float type, you can store numbers as large as 3.4e+038, or 34
   with 37 zeros after it.

   The FLOATS.C program (Listing 3-7) displays three float values, each
   printed in both traditional decimal and exponential notation.

   ──────────────────────────────────────────────────────────────────────────
   /* floats.c  -- shows floating values in regular */
   /*              and exponential format           */

   main()
   {
       float f1 = 2500.125, f2 = 0.0033, f3 = -50.99;

       printf("%f\t %e\n\n", f1, f1);
       printf("%f\t %e\n\n", f2, f2);
       printf("%f\t %e\n", f3, f3);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-7.  The FLOATS.C program.

   The following is the output of the FLOATS.C program:

   2500.125000      2.500125e+003
   0.003300         3.300000e-003
   -50.990002       -5.099000e+001

   Notice that because 0.0033 is less than 1, it has a negative exponent
   (represented by the minus sign after the e). -50.99, on the other hand, is
   a negative number, but because its absolute (unsigned) magnitude is
   greater than 1, it has a positive exponent. FLOATS.C prints each variable
   first in decimal notation and then in exponential notation by varying the
   format specifier in the printf() statement: The %f produces traditional
   decimal format, and the %e produces exponential format.

Type double

   For numbers larger than

   340,000,000,000,000,000,000,000,000,000,000,000,000

   QuickC provides a "jumbo" floating-point type called double (double
   float). It uses eight bytes of storage and has a range of (plus or minus)
   1.7e-308 to 1.7e+308. That's 308 decimal places before or after the
   decimal point, thus accommodating even the most expansive physicist or
   astronomer.

   ──────────────────────────────────────────────────────────────────────────
   Type Variations on Different Machines
   The C language doesn't define the number of bytes used by the int and
   unsigned int types. Instead, the number of bytes is based on the size of
   number a particular processor can handle in a single operation. This way,
   C compilers can always take advantage of a machine's architecture. Because
   the IBM PC uses the Intel 8086, 8088, or 80286 processor, an int uses two
   bytes, or 16 bits, and this is the implementation QuickC uses. However, on
   larger personal computers, such as those using the Intel 80386 processor,
   and on many minicomputers and mainframes, an int uses four bytes, or 32
   bits. Even if you write your program in "standard" C, you must be aware of
   these differences in implementation and machine architecture when you
   "port" the program to another machine.
   ──────────────────────────────────────────────────────────────────────────

Precision for Floating-Point Numbers

   You must consider more than size, however, when storing numbers in a
   computer. We referred to a trillion-dollar budget ($1,000,000,000,000.00)
   earlier in the chapter. If size were the only consideration, we could use
   float to store this number. (A float can handle about 10^38, and a
   trillion is merely 10^12.)

   However, you also must consider the precision available to each data type
   in order to choose the right type for a given variable. Precision refers
   to the number of digits guaranteed to be exactly correct after a
   calculation. The float type has a precision of seven digits. Consider the
   following statements and the resulting output:

   float trillion = 1000000000000.00;
   printf("%f\n", trillion);

   999999995904.000000

   We lost $4,096.00 in this operation. Although we might be happy if the
   government lost only that much of a trillion-dollar budget, we must expect
   full precision in financial calculations and probably an even higher
   precision in most scientific calculations. With its seven-digit precision,
   float can't accurately represent a trillion dollars. We attain the
   required precision by declaring:

   double trillion = 1000000000000.00;

   Because double has 15-digit precision, the result is completely accurate.

Type char

   Let's look at one last data type, char (character). Characters include the
   uppercase and lowercase letters, numerals, punctuation marks, and
   nonprinting control characters. Characters on most computers, including
   the IBM PC, are represented by numbers between 0 and 127, according to the
   ASCII code. The CHARS.C program (Listing 3-8) shows some examples.

   Running CHARS.C produces the following output:

   The character A has ASCII code 65
   If you add ten, you get K
   The character a has ASCII code 97

   The first line of the main() function declares two char type variables,
   ch1 and ch2, and assigns them the values of `A' and `a' respectively. The
   `A' and `a' are called "character constants" or "character literals," and
   you assign them to char variables the same way you assign numeric
   constants. (Note that you must use single quotes around the character
   constant.)

   Consider the first printf() statement in the program:

   printf("The character %c has ASCII code %d\n", ch1, ch1);

   The variable ch1 is specified twice at the end of the argument list. The
   first format specifier, %c, prints the value of ch1 as a character. Then
   the %d specifier prints ch1 as an integer. A character is actually stored
   as a 1-byte version of int, and unless you specify that QuickC treat it as
   a character, it is treated as an integer. This enables us to use the
   expression ch1 + 10 in the second printf() statement. The variable ch1
   contains an integer value (the ASCII code for `A', or 65), so adding 10 to
   it produces 75. When the %c specifier then prints this value, it displays
   the character with the ASCII value of 75, or `K'.

   ──────────────────────────────────────────────────────────────────────────
   /* chars.c -- shows some variables of type char */
   /*            as both characters and integers   */

   main()
   {
       char ch1 = 'A', ch2 = 'a';

       printf("The character %c has ASCII code %d\n", ch1, ch1);
       printf("If you add ten, you get %c\n", ch1 + 10);
       printf("The character %c has ASCII code %d\n", ch2, ch2);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-8.  The CHARS.C program.

Type unsigned char

   A char value is a signed, 1-byte value that stores values in the range of
   -128 to +127. However, the IBM PC's version of ASCII uses the values 0 to
   255 as character codes. The first half of extended ASCII contains the
   regular ASCII character set. Codes from 128 to 255, however, consist of
   special characters and graphics shapes, which together are called the
   "extended character set." You can use the extended character set by
   declaring variables as the unsigned char type. For example:

   unsigned char box = 178;
   printf("%c\n", box);

   displays a rectangular box, or extended ASCII character number 178. (Note
   that two QuickC general help screens show the complete extended ASCII
   character set.)

Using typedef

   C lets you rename any data type with the typedef statement. For example,
   if you use unsigned char type variables to hold characters from the full
   256-character extended set, you could define an easily remembered
   mnemonic:

   typedef xchar unsigned char;
   xchar highlight_char, border_char;

   The typedef statement tells QuickC that the word xchar now represents
   unsigned char. Next, we declare two variables as type xchar. Note that you
   can still declare variables as unsigned char at any time. Also note that
   typedef does not create new data types, it merely provides synonyms for
   existing ones.

   The HARDWARE.C program (Listing 3-9) ends our survey of QuickC data
   types.

   ──────────────────────────────────────────────────────────────────────────
   /* hardware.c -- shows a mixture of int, */
   /*               float, and char types   */

   main()
   {
       int threads    = 8;       /* threads per inch */
       float length   = 1.25,    /* length in inches */
           diameter = 0.425,   /* diameter in inches */
           price    = 0.89;    /* price per hundred */
       char bin = 'A';           /* kept in bin A */
       long quantity = 42300;    /* number in bin */

       printf("Screws: %d threads/inch\n %f inches long\n",
               threads, length);
       printf ("%f diameter\n\n", diameter);
       printf("Price per 100: %f\n", price);
       printf("Stored in bin: %c\n Quantity on hand: %ld",
               bin, quantity);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-9.  The HARDWARE.C program.

   Be sure you understand why we declared the different types. The printf()
   statements display the values of the variables and some descriptive text:

   Screws: eight threads/inch
   1.250000 inches long
   0.425000 diameter

   Price per 100: 0.890000
   Stored in bin: A
   Quantity on hand: 42300

   Although the program works correctly, it would look better if the output
   were formatted more neatly. Also, QuickC printed several extra decimal
   places and filled them with zeros. To gain more control over the
   appearance of program output, we need to study printf() in more detail.

Summary of Data Types

   You don't need to memorize the precise numbers associated with each data
   type; one of QuickC's help screens lets you check which data type you
   should use in a given situation. Display this summary of QuickC data types
   by pressing the F1 key and then proceeding to the appropriate screen. As
   you work with various data types in this chapter, you can always consult
   this chart, shown in Figure 3-4, to refresh your memory.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 3-4 can be found on p.67 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 3-4. Data types help screen.


The Power of printf()

   Thus far we've used printf() statements merely to display values. But
   printf() is actually quite versatile for formatting numbers and character
   strings.

Using Escape Sequences

   Let's look at the parts of the printf() statement from our first program,
   QCHELLO.C:

   printf ("Hello, and welcome to QuickC!\n");

   This is the simplest printf() statement: It merely prints out a string; no
   variables are involved. Earlier, we briefly discussed the one unusual
   feature of this printf() statement, the \n at the end of the string. This
   combination of backslash and following character is called an "escape
   sequence." Escape sequences tell printf() to print special characters as
   part of the given string. The \n, for example, adds the newline character,
   which moves the cursor or printer head to the beginning of the next line.
   Many languages use two kinds of statements for printing: one to print some
   information, and one to print some information and then start a new line.
   With typical conciseness and versatility, C lets you use one function to
   print any ASCII character, including newline, Tab, and carriage-return
   characters, giving you complete control of the position of the cursor or
   printer head.

   One QuickC help screen, shown in Figure 3-5 on the following page, lists
   all of the escape sequences. The newline \n and tab \t sequences are the
   most frequently used. The \a escape sequence causes an "alert," or beep,
   at the terminal.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 3-5 can be found on p.68 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 3-5. Character escape sequences.

   The ONELINE.C program (Listing 3-10) shows what happens when you don't
   use the newline escape sequence. When you run the program, the output is
   all on one line as follows:

   All displayed onthe same line, with no space unless specified.

   Not only do the strings from all three printf() statements end up on the
   same line, the word "on" at the end of the first string runs into the word
   "the" at the start of the second string. To print two strings on the same
   line with a space between them, you must include the space in the string.
   In the third string of ONELINE.C, we added a space before the word
   "unless."

   ──────────────────────────────────────────────────────────────────────────
   /* oneline.c -- shows how printf() continues */
   /*              on the same line             */

   main ()
   {
       printf("All displayed on");
       printf("the same line, with no space");
       printf(" unless specified.");
               /* note added space in line above */
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-10.  The ONELINE.C program.

   The program STRINGS.C (Listing 3-11) demonstrates the two basic ways to
   print strings with printf().

   The first printf() statement has only one argument, the string to be
   printed, and the newline escape sequence. The second statement has two
   arguments, the format specifier %s (for "string") and the string to be
   printed. It replaces the specifier with the string and prints it. This is
   the same procedure we used to print numeric variables and literals with
   specifiers such as %d. The STRINGS.C program produces the following
   output:

   This uses a string literal by itself
   This plugs the literal into %s

   TABS.C (Listing 3-12) illustrates the use of the tab escape sequence \t.

   ──────────────────────────────────────────────────────────────────────────
   /* strings.c -- shows two ways to print */
   /*              a string with printf()  */

   main()
   {
       printf("This uses a string literal by itself\n");
       printf("%s", "This plugs the literal into %s\n");
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-11.  The STRINGS.C program.

   ──────────────────────────────────────────────────────────────────────────
   /* tabs.c -- shows formatting with the \t */
   /*           tab escape sequence          */

   main()
   {
       int    q1 = 338, q2 = 57, q3 = 1048, q4 = 778,
               /* quantity in bin */
               t1 = 6, t2 = 8, t3 = 12, t4 = 16;
               /* threads per inch */

       float  s1 = 0.250, s2 = 0.500, s3 = 0.750, s4 = 1.0;
               /* size in inches */

       /* print table header */
       printf("number\t\t size\t\t threads\n");
       printf("in bin\t\t (inches)\t per inch\n\n");

       /* print lines of table */
       printf("%d\t\t %f\t %d\n", q1, s1, t1);
       printf("%d\t\t %f\t %d\n", q2, s2, t2);
       printf("%d\t\t %f\t %d\n", q3, s3, t3);
       printf("%d\t\t %f\t %d\n", q4, s4, t4);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-12.  The TABS.C program.

   This program prints four sets of data in a neat table. The program prints
   the table headers first, using \t to tab to the next field. Using \t to
   position each item at the next tab stop causes the output to be left-
   justified in each field. To make the table easier to read, we added a
   blank line between the header and the data by including an extra \n in the
   second printf() statement. The program then prints the values of the
   variables in the same tab fields as the headers. The result of all this is
   as follows:

   number          size             threads
   in bin          (inches)         per inch

   338             0.250000         6
   57              0.500000         8
   1048            0.750000         12
   778             1.000000         16

Formatting Numbers with printf()

   The printf() function can also print numbers in a variety of formats.
   Let's look at a printf() statement from SCORE.C, which is analyzed in
   Figure 3-6.

   String to print is
   enclosed in quotes         ┌─────────────────────────────┐
           │                  │                             │
           │                ┌─▼──┐            ┌────┐    ┌───▼────┐
   printf ("The score after │ %d │ innings is │ \n │ ", │ inning │ );
                           └────┘            └────┘    └────────┘
                               │                 │           │
                               │                 │           │
                       Format specifier       Newline     Variable whose
                       for an int value       escape      value is to be
                                           sequence    printed

   Figure 3-6. The printf() statement from SCORE.C.

   ──────────────────────────────────────────────────────────────────────────
   Return and Newline Are Different
   If you program in other languages on MS-DOS machines, you might expect \r
   (carriage return) to move the cursor to the start of a new line. Change
   the \n in TABS.C to \r and run the program again. What happens? Each line
   prints over the preceding one. Although many languages on MS-DOS machines
   incorporate a line feed in a carriage return, C treats newline and return
   as distinct operations. Return moves the cursor to the beginning of the
   current line but does not advance it to a new line. Newline causes output
   to start on the next line. It commences with output at the beginning of
   the next line (rather than directly below the old position) because MS-DOS
   interprets it as though it contains a carriage return as well.
   ──────────────────────────────────────────────────────────────────────────

   Notice the %d in our example, SCORE.C. This, as we have already mentioned,
   is the format specifier for a decimal integer. The string "The score after
   %d innings is" is followed by a comma and the variable inning. Thus, when
   the printf() statement executes, the string is printed with the value of
   inning. You can also print more than one value in the same string. For
   example, if you define int apples = 12, oranges = 9, pears = 3;, then
   execute the following printf() statement:

   printf("I have %d apples, %d oranges, and %d pears. \n", apples, oranges,

   you see the following output:

   I have 12 apples, 9 oranges, and 3 pears.

Specifying Formats with printf()

   Variables are printed according to their type and the format specifiers
   used. One of the QuickC General help screens (Figure 3-7) shows format
   specifiers and additional symbols that can specify formats.

   The program SPECS.C (Listing 3-13 on the following page) prints different
   types of variables with their appropriate specifiers.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 3-7 can be found on p.71 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 3-7. Format specifiers.

   ──────────────────────────────────────────────────────────────────────────
   /* specs.c -- shows printf()format   */
   /*            specifiers for numbers */

   main()
   {
       int    i = 122;       /* ASCII code for 'z' */
       long   l = 93000000;  /* distance to Sun (miles) */
       float  f = 192450.88; /* someone's bottom line */
       double d = 2.0e+030;  /* mass of Sun (kg.) */

       printf("%d\n", i);  /* integer as decimal */
       printf("%x\n", i);  /* integer as hex */
       printf("%ld\n", l); /* long */
       printf("%f\n", f);  /* float as decimal */
       printf("%e\n", f);  /* float as exponential */
       printf("%f\n", d);  /* double as decimal */
       printf("%e\n", d);  /* double as exponential */
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-13.  The SPECS.C program.

   Compare the following output with the printf() statements in the SPECS.C
   program:

   122
   7a
   93000000
   192450.875000
   1.924509e+005
   2000000000000000000000000000000.000000
   2.000000e+030

   The first printf() statement prints the value of the int variable i, 122,
   as an ordinary decimal integer, using the now familiar %d specifier. The
   next statement prints the same value with the %x specifier, which prints
   values in hexadecimal. Next, we print the long integer value 93000000.
   Notice that this specifier, %ld, combines the %l (long) and %d (integer)
   specifiers.

   The SPECS.C program then prints the value of the variable f, 192450.88,
   using the %f floating-point specifier. In the next statement, we use %e to
   print the same number in exponential notation. Which is better? If the
   value represents money, the regular decimal format is more appropriate,
   but remember that both representations are slightly inaccurate because the
   original value, 192450.88, has eight places and float has a maximum
   precision of seven places. (If you want absolute accuracy, use the double
   specifier.)

   We print the final value, 2,000,000,000,000,000,000,000,000,000,000, two
   ways: as a double (note that you can use %f for double as well as for
   float) and as exponential notation with %e. Clearly, the latter is easier
   to read and understand.

Format Specifiers and Data Types

   Remember, the format specifier merely controls how a value is displayed.
   The data type of the value represents how it is actually stored in the
   computer. The program FORMATS.C (Listing 3-14) displays the comedy of
   errors that can occur if you carelessly use the wrong format specifier
   with a data type. The following is the output of the program; compare it
   with the printf() statements in the program.

   As integer:      5
   As long integer: 8519685
   As exponential:  7.084198e-309
   As float:        0.000000

   The program uses four different specifiers to print the value of the int
   variable i, which we set to 5. Only the first representation, using %d, is
   correct. The other results vary widely (even from one run to another). How
   can the last three methods be so far off the mark? Consider the second
   printf() statement, in which we told QuickC to print the value of i as a
   long integer %ld. A long integer uses four bytes of memory, but this
   variable, as an int type, uses only two. When you specify a long integer,
   QuickC takes four bytes starting at the address of i and converts them
   into a long integer. Two of these bytes, however, have nothing to do with
   the variable i. You can see how similar problems arise when we try to
   interpret an integer variable as a float. All of this demonstrates that
   the format specifier must be compatible with the data type being handled.
   Table 3-1 correlates the most commonly encountered specifiers and data
   types.

   ──────────────────────────────────────────────────────────────────────────
   /* formats.c -- shows what happens when format */
   /*              doesn't match data type        */

   main()
   {
       int i = 5;
       printf("As integer:      %d\n", i);
       printf("As long integer: %ld\n", i);
       printf("As exponential:  %e\n", i);
       printf("As float:        %f\n", i);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-14.  The FORMATS.C program.

   Table 3-1. Compatibility of Specifiers and Data Types
   Specifier          Types
   ──────────────────────────────────────────────────────────────────────────
   %d                 int (signed or unsigned); char (ASCII value)
   %ld                long
   %f                 float or double (decimal format)
   %e                 float or double (exponential format)
   %c                 char (as character)
   ──────────────────────────────────────────────────────────────────────────

Field Width Specifiers

   We can also improve the appearance of printf() output by controlling how
   many decimal places are printed and how the number is aligned in the
   output field. To do this, C lets us precede the format specifier with a
   "field specifier." The field specifier takes the following form:

   <field width>.<decimal places>

   The "field width" is the total number of character positions that will be
   printed, and "decimal places" is the number of places printed after the
   decimal point. (Use the decimal place specifier only for float and double
   values.) Following are two examples of field specifiers:

   "5.2f"────────────────────float; 5 places, 2 of which are decimal places
   "8d"───────────────────────────────integer; 8 places (no decimal places)

   The program FIELDS.C (Listing 3-15) shows how field width specifiers
   work.

   The program prints a single variable with varying field specifiers:

       123.456001────────────────────────────────────12.6f (field specifier)
   123.4560────────────────────────────────────────────────────────────8.4f
       123.456────────────────────────────────────────────────────────────8.3f
       123.46────────────────────────────────────────────────────────────8.2f

   In the first printf() statement, the field specifier %12.6f sets up a
   12-character-wide field, 6 characters of which are decimal places. Because
   the variable has only 10 characters to be printed (9 digits and a decimal
   point), printf() indents the number two spaces. By default, numbers are
   right-justified (printed starting in the rightmost position of the
   specified field width). To print numbers that start at the left side of
   the field (left-justified), put a minus sign in front of the field width
   specifier, "%-4.2f".

   ──────────────────────────────────────────────────────────────────────────
   /* fields.c -- shows the same number with different */
   /*             field widths and number of decimals  */

   main()
   {
       float f = 123.4560;

       printf("%12.6f\n", f);
       printf("%8.4f\n", f);
       printf("%8.3f\n", f);
       printf("%8.2f\n", f);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-15.  The FIELDS.C program.

   Note also in the first printf() statement that we asked for six decimal
   places, even though the variable number contained only the first four
   places. Although printf() prints these extra places, they add nothing to
   the precision of the number, and, in fact, give a misleading impression of
   precision. You should specify decimal places only to the expected
   precision of the value. For example, if you know that a value will range
   between 0 and 9999 with decimal places, you might specify %4.3f because
   the value can have as many as four places to the left of the decimal
   point, and a float has only seven places of precision. Thus, a total of
   seven places (4.3) displays an accurate value. Specifying %8.6 for this
   example would give a false impression of precision.

   In the second statement, the specifier establishes a field width of 8
   (with 4 decimal places). The third statement specifies the same field
   width of 8, but with only 3 decimal places. Notice that the variable's
   fourth decimal place, the zero, is dropped, and that the number is
   indented one space because the variable has only 7 characters. The last
   statement specifies the same field width of 8, but with only 2 decimal
   places. The printf() function not only drops the third decimal place, it
   also rounds up the second decimal place to 6. Also, because the number has
   one fewer digit to fit in the 8-character field, printf() indents the
   number another space.


Arithmetic Operators

   Like most languages, C offers a complete set of arithmetic operators: +
   (addition), - (subtraction), * (multiplication), and / (division). C also
   provides a fifth operator that is not quite as common in other languages──
   %, the remainder operator, sometimes called the "modulus" operator. This
   operator returns only the remainder of a division operation. For example,
   5 % 2 is 1 (5 divided by 2 has a remainder of 1), and 9 % 3 is 0 (9
   divided by 3 has no remainder).

   The modulus operator has many uses: You can use it for creating counters
   that cycle within counters or for resetting variables such as line counts
   by checking for a remainder of zero (if line_cnt % page_length = 0, then
   you know that you must start a new page).

   Operators are used with values to form expressions that yield new values.
   Below are some examples:

   10 * 5─────────────────────────────────────────────Multiply two literals
   a / 5─────────────────────────────────────────────Divide value of a by 5
   count + 1────────────────────────────────────────Add 1 to value of count
   (a * 80) + b──────────────Multiply value of a by 80, then add value of b

   In a program, you combine expressions with other elements to form
   statements. The MATH.C program (Listing 3-16 on the following page)
   contains statements that use expressions involving arithmetic operators.

   ──────────────────────────────────────────────────────────────────────────
   /* math.c -- shows arithmetic and       */
   /*           precedence via expressions */

   main()
   {
       int a = 10, b = 4, c = 2;

       /* simple arithmetic expressions */
       printf("99 + 2 = %d\n", 99 + 2);  /* ints */
       printf("5 - 12 = %d\n", 5 - 12);
       printf("7.25 + 3.5 = %f\n", 7.25 + 3.5);
                                           /* floats */

       /* compare precedence on these */
       printf("20 * 20 + 40 = %d\n", 20 * 20 + 40);
       printf("20 * (20 + 40) = %d\n", 20 * (20 + 40));
       printf("a * a - c + b =  %d\n", a * a - c + b);
       printf("a * (a - (c + b)) = %d\n",
               a * (a - (c + b)));

       /* compare integer and float division */

       printf("Integers: 5 / 2 = %d\n", 5 / 2);
       printf("Floats: 5.0 / 2.0 = %f\n", 5.0 / 2.0);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-16.  The MATH.C program.

   Each printf() statement prints the expression and then its value, as
   follows:

   99 + 2 = 101
   5 - 12 = -7
   7.25 + 3.5 = 10.750000
   20 * 20 + 40 = 440
   20 * (20 + 40) = 1200
   a * a - c + b =  102
   a * (a - (c + b)) = 40
   Integers: 5 / 2 = 2
   Floats: 5.0 / 2.0 = 2.500000

   The first three statements simply add and subtract literal numbers and
   print the results. Notice in the third statement that when QuickC sees a
   number with a decimal point, it assumes a float type and prints the answer
   accordingly (10.750000).

Operator Precedence

   The next set of statements in MATH.C illustrates "precedence," or the
   rules that determine the order in which operators are applied. Generally,
   QuickC performs multiplication and division first, then addition and
   subtraction. When operators have equal precedence (such as division and
   multiplication), QuickC performs them from left to right. The following
   QuickC help screen, Figure 3-8, lists all the operators in the language
   (including many covered in later chapters) and arranges them in groups
   from highest to lowest precedence.

   Thus, in Listing 3-16 the first printf() statement in the second group of
   statements multiplies 20 by 20, then adds 40, resulting in 440. However,
   you can use parentheses to impose a different order of precedence, as
   shown in the next statement. To evaluate the expression 20 * (20 + 40),
   QuickC performs the addition first (resulting in 60) and then multiplies
   20 by 60 to produce a value of 1200.

   The next two statements use combinations of variables. As an exercise,
   perform the calculations on paper before you run the program. Remember to
   observe the rules of precedence. Did your answers agree with QuickC's?

   The final two statements in MATH.C illustrate a common problem for the
   unwary beginning C programmer. QuickC divides integer and floating-point
   types differently. When you specify numbers as integers, as in the first
   statement, integer division is performed. Accordingly, 5 divided by 2 is 2
   because this type of division discards any remainder. (A remainder in
   division is a fraction, and int types cannot represent fractions.)
   However, when you specify numbers with decimal points, QuickC treats them
   as float types, resulting in the expected answer of 2.5. Variables of int
   and float types are handled the same way as the literals above.

   The RECEIPTS.C program (Listing 3-17 on the following page) performs
   practical calculations with QuickC's math operators. Notice that we
   declare the units variable as an int type (you can't sell half a unit!)
   and the price and tax rates as float types.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 3-8 can be found on p.77 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 3-8. Operator precedence help screen.

   ──────────────────────────────────────────────────────────────────────────
   /* receipts.c -- calculates gross and net */
   /*               receipts on sales        */

   main()
   {
       int units = 38;       /* number sold */
       float price = 149.99, /* price per item */
       rate = 0.06;          /* sales tax rate */

       /* variables to hold calculated totals */
       float gross, tax, net;

       /* perform calculations */
       net = units * price;
       tax = net * rate;
       gross = net + tax;

       /* print results */
       printf("\tSales Report\n");
       printf("Net sales: \t%6.2f\n", net);
       printf("Tax:\t\t %5.2f\n", tax);
       printf("Gross sales:\t%6.2f\n", gross);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-17.  The RECEIPTS.C program.

   The "calculations" section uses expressions to generate values for the
   variables net, tax, and gross. The printf() statements combine tab escape
   sequences \t and field width specifiers to align the output. Specify only
   two decimal places for money amounts. (Makes cents, doesn't it?) The
   program produces the following report:

           Sales Report
   Net sales:      5699.62
   Tax:             341.98
   Gross sales:    6041.60

Arithmetic with Mixed Types

   The accuracy of a number generated by QuickC depends on its data type and
   the format in which it is printed. An additional problem arises when you
   perform arithmetic operations on literals (constants) or variables of
   different data types: For example, what happens when you divide an int by
   a float?

   For calculations with mixed data types, C ranks data types roughly
   according to the number of bytes of storage they require. From highest to
   lowest, they are:

   double  8 bytes
   float   4 bytes
   long    4 bytes
   int     2 bytes
   char    1 byte

   Generally, QuickC converts the lower-ranking type to the higher-ranking
   one before it performs the calculation. Thus, when QuickC divides 49 by
   12.5, it first converts 49 to 49.0 (a float), then performs the division.
   (If QuickC chose a lower-ranking type, the calculation would lose
   precision. The above calculation, for example, would be 49 / 12 = 4 in
   integer division.) Although the long and float types both use four bytes,
   a float can contain a fractional part that would be lost when converted
   "down" to a long: Therefore, float is ranked as the "higher" type.
   Finally, QuickC converts float types to double types before it calculates
   the result.

   Although it's convenient that QuickC performs conversions for you, some
   real problems can occur if you assign the results of a calculation to a
   variable of an incorrect data type. The following example illustrates such
   a mistake:

   int sales, units = 50;
   float price = 1.99;
   sales = units * price;
   printf("Total sales are %d\n", sales);

   QuickC calculates price * units correctly by converting units from 50 to
   50.0 (to make it a float), and then multiplying it by the float value of
   price (1.99). The value of the expression is now the float value of 99.50.
   So far, so good. However, we assigned this value to the variable sales,
   which we declared as an int type. As a result, the fractional part of the
   value (.50) is dropped, making the value of sales an incorrect 99.00. The
   solution to this problem is simple──consider all of the potential values
   for a variable before you declare it. In this case, you need to declare
   the variable sales as a float.

   QuickC can help remind you of potential problems with data type
   conversions. When you select the Compile option from the Run menu, the
   left side of the dialog box lists four levels of compiler warning messages
   (levels 0 through 3). If you select level 2 before you compile programs,
   QuickC sends a warning message for each program statement that causes a
   data type conversion. A typical message follows:

   warning C4051: (1 of 4)
   data conversion

   When you see this type of message, note the statement the cursor is on,
   examine the data types involved, and look up the meaning of warning (4051)
   in the Microsoft QuickC Programmer's Guide. There you will note that this
   is an advisory message, and QuickC issues it for perfectly legitimate
   conversions, such as the int to float conversion in our earlier division
   example.

   The MIXED.C program (Listing 3-18 on the following page) shows more
   examples of operations with mixed data types.

   ──────────────────────────────────────────────────────────────────────────
   /* mixed.c -- shows the effects of mixing */
   /*            data types in an expression */

   main()
   {
       int     i = 50, iresult;
       long    l = 1000000, lresult;
       float   f = 10.5, fresult;
       double  d = 1000.005, dresult;

       fresult = i + f;         /* int + float to float */
       printf("%f\n", fresult);

       fresult = i * f;         /* int * float to float */
       printf("%f\n", fresult);

       lresult = l + i;         /* long + int to long */
       printf("%ld\n", lresult);

       printf("%f\n", d * f);   /* double * float */
                                   /* to double */
       fresult = d * f;         /* assigned to a float */
       printf("%f\n", fresult); /* loses some precision */

       /* debugging a division problem */

       iresult = i / l;          /* int / long to int*/
       printf("%d\n", iresult);  /* whoops! loses result */
       printf("%ld\n", iresult); /* this won't fix it */
       fresult = i / l;          /* store in float result */
       printf("%f\n", fresult);  /* doesn't work */
       dresult = i / l;          /* try a double */
       printf("%f\n", dresult);  /* doesn't work */
       fresult = (float) i / l;  /* try type cast */
       printf("%f\n", fresult);  /* correct result */
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-18.  The MIXED.C program.

   Compare this output to the program statements:

   60.500000
   525.000000
   1000050
   10500.052500
   10500.052734
   0
   8519680
   0.000000
   0.000000
   0.000050

   The first set of statements adds an int and a float value and prints the
   result, which is 60.5, a float value. This shows QuickC's default type
   conversion at work. The second set of statements shows the same conversion
   with a multiplication operation. The third pair of statements adds a long
   to an int. Note that the result is correct (100,000 + 50 = 100,050), and,
   from its size, you can guess that it must be a long. QuickC converts the
   value 50 to a long before it does the calculation.

   Next, the program works with double and float types. When we specify d * f
   in the printf() statement, QuickC converts the float value f to a double
   and calculates a double result, which we print. (Remember, you can use the
   %f format specifier with either float or double types.) Because the answer
   requires nine places of precision, converting from float to double
   preserves the accuracy of the value.

   Next, we perform the same calculation, but we assign the result to a float
   value, f. Notice that the result, 10,500.052734, becomes inaccurate
   starting at the fourth decimal place. Converting from double to float can
   produce both large and subtle errors, depending on the numbers involved.
   To be safe, use a double variable to hold the result of this type of
   calculation.

   The last lengthy set of statements illustrates various approaches for
   dividing an int value i by a long value l. Only the last method produces
   the correct result.

   Assigning the result of the division to an int variable returns a 0,
   because the result is a very small decimal fraction (50 / 1,000,000), and
   integer division does not recognize remainders.

   In the next statement we assume that the result of the division is a
   decimal fraction and that we can store it in a float. But this doesn't
   work either. When we add more decimal places by using a double variable
   for the result, we still get a result of 0. The problem here is that when
   the two integer variables i and l are divided, the integer portion of the
   result, 0.000050, is 0. At this point, we can't retrieve the decimal
   fraction. Assigning it to a float or a double merely gives you a
   floating-point representation of 0!

Type Casting

   C provides a solution to our division dilemma with a construction called a
   "type cast." A type cast explicitly converts a value to a specified type
   before any operations are done on that value. Consider the following
   example:

   int i1 = 10, i2 = 3;
   printf("%d\n", i1 / i2);
   printf("%f\n", (float) i1 / i2);

   In the first printf() statement, we divide the two integers and produce
   the integer result of 3. In the second printf() statement, we add (float)
   before i1. This is the type cast: It converts the value of i1 to a float.
   Because a type cast has a higher precedence than the arithmetic operators,
   it converts i1 to a float before the division operation. Now the division
   operation contains a float and an int! QuickC's default type conversion
   then converts i2 to a float as well, and the result is the float value
   3.33333. If you look at the last two statements of the MIXED.C program,
   you can see we used a type cast in the same way, with the correct result
   of 0.000050.

   Type casts are useful for handling variables of lower-ranking data types
   (int, for example) that must occasionally be used in calculations to
   produce a result of a "higher" type (such as float). It is more efficient
   in terms of both storage and processing time to declare such variables as
   the lower type and to use type casts when necessary. Later, you will find
   type casts valuable when you must convert values to a specific type.


Getting Input with scanf()

   In order to write programs that have real-world utility, we must first
   understand how a C program gets input from the user. The all-purpose C
   function for getting input and storing it in a variable is called scanf().
   (Like printf(), scanf() is a "built-in" QuickC core library function.)
   Figure 3-9 shows how it works.

   Let's assume we have a program with a declared integer variable named
   acct_no. When the scanf() statement executes, the program waits for input
   from the user. After the user types the number and a carriage return, the
   input is stored in the variable acct_no, as if it had been assigned by an
   assignment statement. Notice that the acct_no variable in the scanf()
   argument list is preceded by an ampersand (&). Do you remember when we
   placed ampersands in front of variable names in the VARADDRS.C program
   (Listing 3-4 on p. 57) to retrieve the storage addresses of the
   variables? The scanf() function requires as its second argument an address
   at which it can store the input. The & returns the address of the
   following variable. If you omit the address operator from the front of the
   variable name, the value of the variable is interpreted as though it were
   an address, and the input is stored at that address. This can produce
   frightful results if it overwrites information that your program needs!

   Format specifier for
   type of value wanted
           │
           ┌┴┐
   scanf ("%d", &acct_no);
               │└────┬─┘
               │     │
       "address of"   Variable name
       └─────────────┬──────────────┘
                   │
       Variable to store input in

   Figure 3-9. Parts of a scanf() statement.

   The first argument in the scanf() statement in Figure 3-9 is "%d". This
   looks and works like the format specifiers we used with printf()──it
   specifies the type of the value that the program expects. As with
   printf(), the "%d" specifies an integer. You can also use most of the
   other specifiers you used with printf(). For example:

   scanf("%f", &deposit);

   gets a value for the float variable deposit.

   Notice that scanf(), by itself, does not print a prompt for the user; it
   merely presents the user with a blinking cursor. Therefore, you should
   precede a scanf() statement with a printf() statement that tells the user
   what information to supply. In the example above, we might precede the
   scanf() statement with:

   printf("How much is your deposit?");

   The cursor now appears following a space after the prompt. You don't need
   to include a newline character: The cursor will move to the next line when
   the user presses Enter after typing the input.

   You can also use scanf() to get values for more than one variable at a
   time:

   printf("What is your age and weight?");
   scanf("%d %d", &age &weight);

   In this example, the user types an age, a space (to separate the values),
   and then a weight. Note that the user can substitute an Enter or a Tab for
   the space.

   The CONVERT.C program (Listing 3-19) uses scanf() to prompt a user for a
   temperature in Fahrenheit and then converts the temperature to Centigrade.

   ──────────────────────────────────────────────────────────────────────────
   /* convert.c  -- converts Fahrenheit temperature     */
   /*               to Centigrade; gets value from user */

   main()
   {
       float ftemp, ctemp;

       printf("What is the temperature in Fahrenheit? ");
       scanf("%f", &ftemp);
       ctemp = (ftemp - 32.0) * 5 / 9.0;

       printf("The temperature in Centigrade is %5.2f", ctemp);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-19.  The CONVERT.C program.

   A sample user dialog with CONVERT.C follows:

   What is the temperature in Fahrenheit? 87
   The temperature in Centigrade is 30.56

   We print the prompt with a printf() statement, then use a scanf()
   statement with a floating-point specifier %f to get the input value for
   the float variable ftemp.

   The AVGTEMP.C program (Listing 3-20) averages the daily high temperatures
   for a week. When you run the program, it prompts for the high temperature
   for each day of the week, beginning with Monday.

   ──────────────────────────────────────────────────────────────────────────
   /* avgtemp.c -- finds average temperature */
   /*              for the week              */

   main()
   {
       int t1, t2, t3, t4, t5, t6, t7;
       float avg;

       printf("Enter the high temperature for:\n");
       printf("Monday: ");
       scanf("%d", &t1);
       printf("Tuesday: ");
       scanf("%d", &t2);
       printf("Wednesday: ");
       scanf("%d", &t3);
       printf("Thursday: ");
       scanf("%d", &t4);
       printf("Friday: ");
       scanf("%d", &t5);
       printf("Saturday: ");
       scanf("%d", &t6);
       printf("Sunday: ");
       scanf("%d", &t7);

       /* calculate and display average */
       avg = (t1 + t2 + t3 + t4 + t5 + t6 + t7) / 7.0;
           /* divide by 7.0 to ensure float result */
       printf("The average high temperature for");
       printf(" this week was %5.2f degrees.\n", avg);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-20.  The AVGTEMP.C program.

   The int variables t1 through t7 store the daily high temperatures, which
   are obtained by a series of scanf() statements. The program then
   calculates an average and prints it out. A sample dialog with this program
   might look as follows:

   Enter the high temperature for:
   Monday: 82
   Tuesday: 91
   Wednesday: 97
   Thursday: 104
   Friday: 95
   Saturday: 88
   Sunday: 78
   The average high temperature for this week was 90.71 degrees.

   Note: It is important to note that scanf() does not check to make certain
   that the input is compatible with the data type of the variable in which
   it is stored.


Shortcut Assignments, Increments, and Decrements

   Now that you know how to assign a value to a variable with the assignment
   operator = and how to use arithmetic operators to calculate new values, we
   can show you a few tricks and shortcuts. In the course of a program, it is
   often useful to add a value to a variable repeatedly or to subtract a
   value from a variable repeatedly. For example, a program that counts lines
   needs to add one to a variable (such as total_lines) each time it counts a
   new line. We could do this as follows:

   total_lines = total_lines + 1;

   That's the way most languages do it. However, because changing the value
   of a variable is such a common occurrence in programming, C provides
   special, concise "arithmetic assignment operators" for the purpose.

Arithmetic Assignment Operators

   The arithmetic operators are the +, -, *, /, and %, and the assignment
   operator is the =. The arithmetic assignment operator, as the name
   suggests, is a combination of an arithmetic operator and the assignment
   operator: for example, +=. When a statement executes, QuickC performs the
   specified arithmetic on the variable's value and then assigns the result
   of the calculation to the variable as its new value. Using an arithmetic
   assignment operator, we can write a shorter version of the statement that
   increases the value of total_lines by one:

   total_lines += 1;

   Below are more examples that use arithmetic assignment operators:

   count -= 1;───────────────────────────Subtract 1 from the value of count
   fare += 0.75;──────────────────────────────────Add 0.75 to value of fare
   value *= 10;────────────────────────────────────────Multiply value by 10

   You can use any arithmetic operator in an arithmetic assignment operation.
   Table 3-2 lists the five possible arithmetic assignment operators. The
   addition and subtraction assignment operators are the most commonly used.

   The OPEQUAL.C program (Listing 3-21) demonstrates the use of arithmetic
   assignment statements. The printf() statements print several arithmetic
   assignment expressions and their results.

   Be sure that when you read the printf() statements in the program you can
   correctly predict the following output:

   Starting values: m = 10 n = 5
   m += 2 makes m 12
   m -= n makes m 7
   m *= 2 makes m 14
   m = m + 1 makes m 15
   m += 1 makes m 16

   Table 3-2. Arithmetic Assignment Operators
   Operator           Meaning
   ──────────────────────────────────────────────────────────────────────────
   +=                 Add to value and assign
   -=                 Subtract from value and assign
   *=                 Multiply by value and assign
   /=                 Divide by value and assign
   %=                 Get remainder from division and assign
   ──────────────────────────────────────────────────────────────────────────

   ──────────────────────────────────────────────────────────────────────────
   /* opequal.c -- shows combination math/assignment */
   /*              operators and increment operators */
   main()
   {
       int m = 10, n = 5;
       printf("Starting values: m = %d n = %d\n",
               m, n);

       /* combination of arithmetic and assignment */
       printf("m += 2 makes m %d\n", m += 2);
       printf("m -= n makes m %d\n", m -= n);
       printf("m *= 2 makes m %d\n", m *= 2);

       /* two ways to increment m */
       printf("m = m + 1 makes m %d\n",
               m = m + 1);
       printf("m += 1 makes m %d\n",
               m += 1);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-21.  The OPEQUAL.C program.

Increment and Decrement Operators

   As the last program demonstrated, both m = m + 1 and m += 1 added one to
   the value of m. If you've done any programming, you know how frequently
   the value of a variable must be increased or decreased by one. This is
   especially true when you create a "counter" variable that keeps track of
   the number of times a statement in a loop executes. C provides an
   ultra-concise operator, the increment operator ++, to add one to the value
   of a variable. Similarly, --, the decrement operator, subtracts one from
   the value of a variable. Consider the following examples:

   count++ ;────────────────────────────────────────Add 1 to value of count
   index-- ;─────────────────────────────────Subtract 1 from value of index

   Note that these increment and decrement operators are really arithmetic
   assignment statements. They add (or subtract) one and assign the resulting
   value to the variable.

   count++;──────────────────is equivalent to───────────────────count += 1;
   index--;──────────────────is equivalent to───────────────────index -= 1;

   (Most programmers do not use a space between the increment [or decrement]
   operator and the variable name. However, in C it is perfectly legal to use
   intervening spaces, as in count + +.) INCDEC.C (Listing 3-22) shows how
   the increment and decrement operators change the value of a variable.
   Compare the program statements to the following output:

   a is 10
   ++a is 11
   --a sets a back to 10

   ──────────────────────────────────────────────────────────────────────────
   /* incdec.c -- shows effect of            */
   /*             increments and decrements  */

   main()
   {
       int a = 10;

       printf("a is %d\n", a);
       printf("++a is %d\n", ++a);
       printf("--a sets a back to %d\n", --a);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-22.  The INCDEC.C program.

Pre-increment vs Post-increment

   In the INCDEC.C program we put the increment or decrement operator in
   front of the variable name. However, you also can use it after the
   variable name. In either case the variable is incremented or decremented;
   but there is one important difference. When you use the operator in front
   of a variable name, the incrementing or decrementing is done immediately.
   When you use the operator after the variable name, the incrementing or
   decrementing is not done until the next use of the variable. The PREPOST.C
   program (Listing 3-23) shows how this works. The output of the program
   illustrates how incrementing is delayed:

   b is 100
   b++ is still 100
   but after it's used, b is incremented to 101

   ++b, on the other hand, is immediately 102

   Notice what happens to b when we use the increment operator after it,
   rather than before it. The first printf() statement with the value b++
   prints the original value of 100, showing that it has not yet been
   incremented. The next printf() statement, however, prints 101.

   As a practical matter, the distinction between pre-increments and
   post-increments (or decrements) is usually important only when the
   variable is incremented or decremented while it is being used with other
   operators in a single expression. For example, suppose you want to
   increment counter and also assign it to total in the same statement.
   Assuming counter is currently 10:

   total = counter++;

   assigns 10 to total, because counter is assigned to total but not
   incremented until the next time it is used. On the other hand:

   total = ++counter;

   assigns 11 to total, because counter is incremented immediately and then
   assigned.

   ──────────────────────────────────────────────────────────────────────────
   /* prepost.c -- shows effect of pre- */
   /*              and post-increments  */
   /*              and decrements       */

   main()
   {
       int b = 100;

       printf("b is %d\n", b);
       printf("b++ is still %d\n", b++);
       printf("but after it's used, ");
       printf("b is incremented to %d\n\n", b);

       printf("++b, on the other hand, ");
       printf("is immediately %d\n", ++b);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-23.  The PREPOST.C program.


Relational Operators

   If you have some programming experience, you know that most programs must
   make decisions based on the values of certain variables. Variables are
   tested or compared, and the result of the test determines which program
   statement will execute next. The next two chapters cover the variety of
   "control structures" that C provides for this purpose. Let's build the
   foundation for those discussions by looking at the operators that C uses
   for testing or comparing values.

   A relational operator compares two values, which can be variables, literal
   numbers, or whole expressions. A combination of relational operators and
   values is called a relational expression. An example is count > 10, which
   translates as "is the value of count greater than 10?" The > in this
   expression is the "greater than" relational operator. The expression is
   true or false depending on the current value of the variable count. If
   count is 8, for example, the expression is false.

   Table 3-3 illustrates the ways we can compare two values, a and b. In
   reality, the values can be constants, variables, or expressions──anything
   that expresses a numeric value. (Remember from our discussion of ASCII
   that characters, too, are essentially numeric values.)

   We described the value of a relational expression as being "true" or
   "false." These terms are useful ways for us to follow the logic of a
   program, but the actual value of a relational statement, like everything
   else in the computer, is numeric. When a statement is true, its value is
   1; when a statement is false, its value is 0. On the following page, the
   RELATION.C program (Listing 3-24) uses printf() statements to show the
   values of some statements that use relational operators.

   The program generates the following output:

   a = 5    b = 3   c = 4
   Expression a > b has a value of 1
   Expression a == c has a value of 0
   Expression a > (b + c) has a value of 0

   Because a is 5 and b is 3, the expression a > b has a value of 1, or true.
   Because c is 4, a == c has a value of 0, or false. The third expression
   combines relational and arithmetic operators: It first calculates the
   quantity (b + c), and then it compares the value to a.

   Table 3-3. Relational Operators
   Expression               Meaning
   ──────────────────────────────────────────────────────────────────────────
   a < b                    Is a less than b?
   a > b                    Is a greater than b?
   a == b                   Is a equal to b?
   a != b                   Is a not equal to b?
   a <= b                   Is a less than or equal to b?
   a >= b                   Is a greater than or equal to b?
   ──────────────────────────────────────────────────────────────────────────

   ──────────────────────────────────────────────────────────────────────────
   /* relation.c  -- shows effect of      */
   /*                relational operators */

   main()
   {
       int a = 5, b = 3, c = 4;
       printf("a = %d\t b = %d\t c = %d\n", a, b, c);

       printf("Expression a > b has a value of %d\n",
               a > b);
       printf("Expression a == c has a value of %d\n",
               a == c);
       printf("Expression a > (b + c) has a value of %d\n",
               a > (b + c));
       printf("Expression a = b has a value of %d\n",
               a = b); /* what happened here? */
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-24.   The RELATION.C program.

Relational == vs Assignment =

   Here's a pitfall to watch out for: In C, a single equal sign = is the
   assignment operator, but a double equal sign == is the relational "equals"
   operator. In some languages (such as BASIC), a single operator, =, serves
   both purposes. So, if you are familiar with the BASIC usage, you might
   make errors with these operators until you get used to the difference. A
   common symptom of this error is a test that always appears to be either
   true or false. For example, if you type the assignment count = 10 instead
   of the relational count == 10 and then use the result in a control
   structure (such as a loop or if statement), QuickC always sees the result
   of the test as "true." Why? Because although relational expressions return
   a value of 1 for "true," QuickC considers any nonzero value to be "true"
   in this type of test. Because the sample statement with = is actually an
   assignment, its value is 10 (the number assigned), which QuickC interprets
   as "true" during a relational test.

   ──────────────────────────────────────────────────────────────────────────
   Assignment and "Equals" Relation
   The following table lets you compare the assignment and relational
   "equals" operators in C to those in other common languages:

   Language               Assignment              Relation
   ──────────────────────────────────────────────────────────────────────
   C
   =
   ==
   BASIC                  =                       =
   Pascal                 :=                      =
   FORTRAN                =                       .EQ.
   Logo                   make                    =
   COBOL                  MOVE                    EQUAL TO
   ──────────────────────────────────────────────────────────────────────

   ────────────────────────────────────────────────────────────────────────

Precedence of Relational Operators

   In RELATION.C, we used parentheses in the expression a > (b + c). If you
   check QuickC's operator precedence help screen (Figure 3-8 on p. 77), you
   will see that relational operators have a lower precedence than arithmetic
   operators. Therefore, even if you don't use parentheses, b + c is
   calculated first, and only then is the result compared to a. Nevertheless,
   it is a good programming practice to use parentheses to visually clarify
   an expression.


Logical Operators

   Sometimes it is necessary or useful to test for more than one thing in the
   same expression or statement. For example, you might want to test to see
   if either the temperature or pressure in a boiler has exceeded the safety
   limit. Let's assume the test for temperature is (temp < 900) and the test
   for pressure is (pressure < 5000). We can combine the two tests as
   follows:

   (temp < 900) && (pressure < 5000)

   The && is called the AND logical operator. It compares the results of two
   relational values and returns a value of true (1) only if both are true.
   QuickC first makes the temp test, then it makes the pressure test (testing
   is from left to right). Then the && operator checks to see if both tests
   were true.

   The OR logical operator, ||, works like the AND operator, except that it
   returns a value of true (1) if either or both of the tests are true. Thus,
   the statement

   (ch == 'q') || (turn > last_turn)

   is true if either the current value of ch is `q' or the current value of
   turn is greater than that of last_turn, or both. You could use this
   statement to check if a game is over.

   Using two relational operators, && and ||, and two possible results of a
   test (true and false), there are four possible results for a relational
   statement involving two tests. The TRUTH.C program (Listing 3-25 on the
   following page) prints these out by making comparisons using ones and
   zeros that represent the result of already completed relational tests.
   Recall that QuickC regards a value of 1 to be "true" and a value of 0 to
   be "false." Thus, 1 AND 1 is 1 means "True and true is true."

   1 AND 1 is 1
   1 AND 0 is 0
   0 AND 0 is 0
   1 OR 1 is 1
   1 OR 0 is 1
   0 OR 0 is 0

   ──────────────────────────────────────────────────────────────────────────
   /* truth.c -- shows logical operators */
   main()
   {
       printf("1 AND 1 is %d\n", 1 && 1);
       printf("1 AND 0 is %d\n", 1 && 0);
       printf("0 AND 0 is %d\n", 0 && 0);
       printf("1 OR 1 is %d\n",  1 || 1);
       printf("1 OR 0 is %d\n",  1 || 0);
       printf("0 OR 0 is %d\n",  0 || 0);
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 3-25.  The TRUTH.C program.

   Once again, if you check the QuickC operator precedence help screen, you
   will notice that logical operators, such as && and ||, have a lower
   precedence than the relational operators, such as < or ==. Therefore, we
   didn't need parentheses around the relational expressions in our examples
   because QuickC evaluated them before it checked the logical operators.
   Again, we used parentheses because they make these complex expressions
   easier to read.

   The last operator we need to discuss is the !, or "not" operator. Its
   function is simple enough──it reverses the truth value of a relational
   expression. For example, if a is 10, a > 5 is true, but !(a > 5) is false.



────────────────────────────────────────────────────────────────────────────
Chapter 4  Repetition and Looping

   In all of our programs so far, QuickC has executed the program statements
   sequentially, from the first statement to the end of the program. However,
   most of a program's important work involves controlled repetition, in
   which a group of statements repeatedly does a particular job until the
   work is done. For example, consider the data-entry routine of a database
   program. This group of statements (used to receive, validate, and store
   data) must be repeated as long as the user wants to enter new data
   records. This set of repeating statements is called a loop because it is
   executed as though the statements were arranged in a circle. However, when
   the user wants to stop entering data, the program must be able to
   recognize a "quit" command and stop repeating the data-entry statements.

   As you study C, you will find many other examples of the need for
   controlled repetition. For example, a program that retrieves data from a
   file must repeatedly read and process data items until it reaches the end
   of the file. If you program in another language, you probably use loops
   regularly to initialize and access elements of an array or a set of
   variables.

   C uses three types of loops: the for loop, the while loop, and the do
   loop. Although these loops are fundamentally similar, they let you control
   the looping action in different ways to suit different needs. This chapter
   focuses on how to use these three types of loops and some of their common
   variations.


The for Loop

   The for loop repeats a group of program statements as long as a specified
   condition is true. Generally, you use it to specify a fixed number of
   repetitions: for example, processing the accounts for each month of the
   year.

   The anatomy of a for loop is as follows:

   for (start; condition; update)
       {
       statements;
       }

   In this generalized for loop, start is one or more statements that
   initialize the variables used by the loop; condition is a relational
   expression that is tested to see whether the loop should continue to run;
   and update is one or more statements that change the values of variables
   in the loop. The group of statements between the braces that follow the
   for line is called the "body" of the loop. These statements execute as
   long as the condition in the parentheses is true. (The body can also
   consist of only one statement, in which case the braces are optional. We
   tend to use braces for even a single statement, however, because they make
   the body of the loop easier to distinguish.)

   The FORLOOP.C program (Listing 4-1) uses a for loop to count from 1 to
   10. After we declare the variable i, we begin the loop structure with the
   keyword for. The parentheses that follow the for contain the control
   statements for the loop. Note that semicolons separate the control
   statements.

   ──────────────────────────────────────────────────────────────────────────
   /* forloop.c -- a simple for loop that   */
   /*              counts to ten            */

   main()
   {
       int i;
       for (i = 1; i <= 10; i++)
           {
           printf("%d\n", i); /* body of loop */
           }
       printf("All done!\n");  /* executed when i > 10 */
   }
   ──────────────────────────────────────────────────────────────────────────

   Listing 4-1.  The FORLOOP.C program.

   The start statement establishes the variable i as the loop's control
   variable. This is the variable whose value is tested to determine when the
   loop will stop running. (Many people use i, j, or k for loop control
   variables. This tradition owes its roots to FORTRAN. However, any legal
   name will do.)

   The next statement, i <= 10, is the loop's test, or condition. It
   specifies that the body of the loop execute repeatedly as long as the
   value of i is less than or equal to 10. The test condition is a relational
   statement that compares the loop control variable to an assigned value and
   returns a value of 1 (true) or 0 (false).

   The last statement in the for loop parentheses is i++. This update
   statement changes the value of the loop control variable each time the
   loop body executes. Here we use the ++ increment operator to increase i by
   one each time it executes, and, in fact, most for loops use update
   statements that either increment or decrement the control value by one.
   Using values other than one, however, is almost as easy: The statement
   value += 10, for example, adds 10 to value each time it executes. You can
   also use multiplication or division rather than addition or subtraction.

   Let's step through FORLOOP.C one statement at a time to see how it works:

   ■  Set i to 1.

   ■  Check i to see if it is less than or equal to 10.

   ■  Because the result of this test is true, execute the body of the loop.
       (The body consists of a printf() statement that prints the value of i.)

   ■  Execute the update statement, i++. (Set i to i + 1, or 2.)

   ■  Check the test statement again to see if i is still less than or equal
       to 10. If it is, execute the body of the loop again. Continue the cycle
       until the test condition is false (when the value of i increases to
       11).

   Figure 4-1 on the following page shows this program as a flowchart. You
   can follow the arrows to trace the flow of execution.

   ──────────────────────────────────────────────────────────────────────────
   Choosing a Control Variable
   If you are used to writing loops in BASIC, remember that with C, you must
   declare the loop control variable before you use it in the loop. Select a
   data type for the control variable that can accommodate the full range of
   values the variable will hold when the loop is run.

   For example, a loop that will run 50,000 times requires a control variable
   of type unsigned int because a signed int value cannot exceed 32,767.
   ──────────────────────────────────────────────────────────────────────────

       ┌────────────────┐
       │  Initialize    │◄▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
       │     i = 1      │                          ┌─────────▒─────────────────
       └───────┼────────┘                          │° for (i = 1; i <= 10; i++°
               │                                   │°               ▒       ▒ °
               ▼           ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒{▒▒▒▒▒▒▒▒▒▒       ▒ °
               /\          ▒         ▬  ▬  ▬       │°     printf("%d\n", i);▒ °
           /    \ ◄▒▒▒▒▒▒▒      ▬           ▬    │°     }        ▒        ▒ °
           /  TEST  \    No     ▬               ▬  │°              ▒        ▒ °
   ┌───►/  i <= 10   \ ──────► ▬      END      ▬  │°              ▒        ▒ °
   │    \     ▬      /         ▬               ▬  │°              ▒        ▒ °
   │      \ ▬ ? ▬  /             ▬           ▬    │°              ▒        ▒ °
   │        \ ▬  /                  ▬  ▬  ▬       │°              ▒        ▒ °
   │          \/                                  │°              ▒        ▒ °
   │          │ Yes                               └───────────────▒────────▒──
   │  ┌───────▼────────┐                                          ▒        ▒
   │Do body of loop │                                          ▒        ▒
   │  │  print f...    │◄▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒        ▒
   │  └───────┬────────┘                                                   ▒
   │          │                                                            ▒
   │  ┌───────▼────────┐                                                   ▒
   │  │  Add 1 to i    │◄▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
   │  └───────┬────────┘
   │          │
   └───◄──────┘

   Figure 4-1. The for loop.

   Why does the loop stop running? Let's look at the situation when i = 10:
   The printf() statement in the body of the loop prints the number 10. The
   update statement then increments the loop by 1 and the test statement
   executes. Because the value of i is now 11, the test fails (returns a
   value of "false"). This causes the program to skip the loop body and
   execute the next statement, which prints the message All done!

for Loop Style

   As with other C statements, the statements within the parentheses of a for
   loop can extend to more than one line if necessary. As noted in our
   discussion of conventions, we align the braces vertically for the loop
   body, as shown in FORLOOP.C. An older style aligns the braces as follows:

   for (i = 1; i <= 10; i++) {
       printf("%d\n",i);
   }

   With this style, the braces can get lost in a long listing, making it
   difficult to find where the body of the loop begins and ends. Aligning the
   braces vertically makes them easier to spot and highlights the body of the
   loop.

   Also note that we indent the body of a C loop to the right of the line
   that specifies it. To indent text in the QuickC editor, simply press the
   Tab key. The default indention in QuickC is eight characters, but you can
   change this value at the Options box of the View menu. We use a tab of
   four characters in our listings.

   Pitfalls to Avoid in for Loops

   An easy mistake to make when writing for loops is to put a semicolon after
   the closing parenthesis:

   for (i = 1; i <= 10; i++);───────────────────────────────Semicolon added

   This does not cause a compiler error: In C, a semicolon by itself is a
   "null statement." Such a statement does nothing, but it counts as a legal
   statement. Using a semicolon after the parenthesis makes the null
   statement the body of the loop. Adding the semicolon to FORLOOP.C causes
   the loop to do "nothing" 10 times; the program then prints the value of i
   (which is 11 after the loop exits) and All Done!

   Also, always remember to put braces before and after a loop body that
   consists of more than one statement. If you do not use braces, only the
   first statement following the parentheses executes as the body of the
   loop. The remaining statements will execute only once, after the loop
   terminates. (This is another reason for adopting the practice of always
   putting braces around the statements in a loop body, even when the body
   has only one statement.)

Multistatement for Loops

   FORLOOP.C has only one statement in the body of the loop, but most
   programs are much more complex. Let's develop a program that will print a
   table of square roots, squares, and cubes for the integers from 1 through
   9. Because this program must calculate and print three values for each
   number, it needs several statements in the body of the for loop.

   Using QuickC Library Functions

   To write such a program, we need a means of producing the square root of a
   number. Although C does not have operators for calculating squares or
   cubes directly, we can get these values simply by multiplying a variable
   by itself two and three times respectively. To get the square root,
   however, we must call on QuickC's sqrt() function. This function returns
   the square root of any value you pass to it. For example, if i = 4, then
   sqrt(i) = 2.

   The square root function, sqrt(), is an example of a QuickC library
   function (sometimes called a "library routine"). We've already used
   several QuickC "core" functions, such as printf() and scanf(). Because
   these functions are part of the QuickC environment, you can use them
   without any special commands. (Appendix B lists all the built-in core
   functions.)

   ──────────────────────────────────────────────────────────────────────────
   Quick Tip
   Sometimes it is convenient to break out of a loop during its execution.
   Perhaps you recognize a problem with its output, or perhaps you find
   yourself in a runaway loop──one whose test will not or cannot fail. To
   break out of a loop, press Ctrl-Break.
   ──────────────────────────────────────────────────────────────────────────

   However, sqrt() is not on this list. It is one of many library routines
   that are defined in the header files (often called "include files") of the
   \INCLUDE directory. One of the early tasks in learning QuickC is becoming
   familiar with its external library functions. Fortunately, QuickC makes it
   easy to explore the function library.

   QuickC's extensive on-line help screens let you call up a summary of any
   function to find out whether it is a core function or an external library
   function. To find out about sqrt(), select Topic from the Help menu. Next,
   select the appropriate topic, math; this produces a list of library
   functions that include the sqrt() function. When you select this function,
   a small help window appears at the top of the QuickC screen. (See Figure
   4-2.) The first entry in this window informs you that sqrt() resides in
   both the float.h and math.h include files.

   QuickC also lets you browse through include files while you are working on
   a program. Simply select Include from the View menu, select the \INCLUDE
   directory from the window (if necessary), and then select the include file
   you want to view. When you finish, select Open Last File from the File
   menu, and QuickC returns you to the program you were working on.

   Of course, the preferred reference for all QuickC library functions is the
   Microsoft QuickC Run-Time Library Reference, one of the manuals that come
   with QuickC. It introduces the library functions by category.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ Figure 4-2 can be found on p.98 of the printed version of the book.    │
   └────────────────────────────────────────────────────────────────────────┘

   Figure 4-2. Library function help window.

   Using an Include File in a Program

   To use functions or other definitions from an include file in your
   program, you must specify the name of the file you want to call before the
   start of main(). For example:

   #include <graph.h>

   includes the file that contains graphics functions and definitions in your
   program. (The angle brackets that enclose the filename tell QuickC to look
   for the file in the default \INCLUDE directory, whose pathname the setup
   procedure stored in the environmental variable INCLUDE.) This statement is
   actually a "directive" to the QuickC preprocessor, a program that examines
   your C program code and looks for special commands that tell it to make
   changes in the program text before compilation begins. In this case, the
   #include preprocessor directive reads the contents of the specified
   include file into the program and compiles it as though you had typed it
   in. Only after it reads and compiles all the include files does QuickC
   compile your program statements. Note that preprocessor statements such as
   #include are not actually C language statements and do not end with a
   semicolon.

   Creating a Program List

   We have seen that we need to use a #include statement if we want to refer
   to the sqrt() function in the program we want to run, TABLE.C (Listing
   4-2).