SlideShare a Scribd company logo
00 C++ For Engineers and Scientists.pdf
Colin Dean
You knew you were a Computer Science major when…
I had that feeling when, somewhat on a whim, I proposed to Westminster’s
information systems department that they lend me nine new, unused computers
in order to build a Folding@Home cluster in the Unix Lab. They approved, and that
cluster ran 24/7 for about six months. (http://www.cs.westminster.edu/folding/).
One piece of advice for first year students:
Ask questions. Don’t be afraid to virtually inundate a professor with questions.
Remember, it’s your education—get what you want out of it. If a professor is
too busy to help you, find another one to help. Don’t share your code with
classmates—don’t even let them look at it unless you get permission from a
professor: it’s against every school’s academic integrity policies. And finally, learn
at least one weird (read: non-major) language like Scheme, Smalltalk, Prolog, or
even Haskell. You never know when it might come in handy.
If you could have dinner with a famous computer scientist, living or dead, who
would you choose?
Tim Berners-Lee, the father of the World Wide Web. His creation has changed
more lives directly than just about any other technology has. It’s enabled
the dissemination of vast amounts of knowledge and enabled collaboration
throughout the world.
What technology blogs do you read on a regular basis?
I find myself on Ars Technica, A List Apart, and The Daily WTF most often, as well as
Engadget and a few politics and technology blogs.
Where do you see yourself in ten years?
I hope to be running my own successful Internet-based company and
contemplating a doctorate, and perhaps holding public office.
Colin Dean of Volant, PA graduated with a B.S. in
Computer Science from Westminster College in
New Wilmington, PA in May 2007. He completed his
M.S. in Business Education in July 2008 at Robert
Morris University and is employed as a developer in
Pittsburgh, PA.
Spotlight on Careers in Computing
C++ for Engineers and Scientists
Third Edition
Gary J. Bronson
G.J. Borse
Contributing Editor
Lehigh University
Australia • Brazil • Japan • Korea • Mexico • Singapore • Spain • United Kingdom • United States
C++ for Engineers and Scientists, Third
Edition
Gary J. Bronson
Managing Editor: Marie Lee
Acquisitions Editor: Amy Jollymore
Senior Product Manager: Alyssa Pratt
Developmental Editor: Lisa M. Lord
Content Product Manager: Matt Hutchinson
Marketing Manager: Bryant Chrzan
Editorial Assistant: Julia Leroux-Lindsey
Art Director: Marissa Falco
Compositor: GEX Publishing Services
© 2010 Course Technology, Cengage Learning
ALL RIGHTS RESERVED. No part of this work covered by the copyright
herein may be reproduced, transmitted, stored or used in any form or by
any means graphic, electronic, or mechanical, including but not limited to
photocopying, recording, scanning, digitizing, taping, Web distribution,
information networks, or information storage and retrieval systems, except
as permitted under Section 107 or 108 of the 1976 United States Copyright
Act, without the prior written permission of the publisher.
For product information and technology assistance, contact us at
Cengage Learning Customer & Sales Support, 1-800-354-9706
For permission to use material from this text or product, submit all
requests online at www.cengage.com/permissions
Further permission questions can be e-mailed to
permissionrequest@cengage.com
ISBN-13: 978-0-324-78643-9
ISBN-10 : 0-324-78643-3
Course Technology
20 Channel Center Street
Boston, Massachusetts 02210
USA
Cengage Learning is a leading provider of customized learning solutions
with office locations around the globe, including Singapore, the United
Kingdom, Australia, Mexico, Brazil, and Japan. Locate your local office at:
international.cengage.com/region
Cengage Learning products are represented in Canada by Nelson
Education, Ltd.
For your lifelong learning solutions, visit www.cengage.com
Purchase any of our products at your local college store or at our preferred
online store www.ichapters.com
Some of the product names and company names used in this book have
been used for identification purposes only and may be trademarks or regis-
tered trademarks of their respective manufacturers and sellers.
Any fictional data related to persons or companies or URLs used through-
out this book is intended for instructional purposes only. At the time this
book was printed, any such data was fictional and not belonging to any real
persons or companies.
The programs in this book are for instructional purposes only.
They have been tested with care but are not guaranteed for any particular
intent beyond educational purposes. The author and the publisher do not
offer any warranties or representations, nor do they accept any liabilities
with respect to the programs.
Printed in the United States of America
1 2 3 4 5 6 7 14 13 12 11 10
BRIEF TABLE OF CONTENTS
Part 1
Fundamentals of C++ Programming 1
Chapter 1
Preliminaries 3
Chapter 2
Problem Solving Using C++ 43
Chapter 3
Assignment, Formatting, and Interactive Input 103
Chapter 4
Selection Structures 177
Chapter 5
Repetition Statements 231
Chapter 6
Modularity Using Functions 293
Chapter 7
Arrays 373
Chapter 8
I/O Streams and Data Files 439
Chapter 9
Completing the Basics 489
Part 2
Object-Oriented Programming 551
Chapter 10
Introduction to Classes 553
Chapter 11
Class Functions and Conversions 597
Brief Table of Contents 3
Part 3
Data Structures 663
Chapter 12
Pointers 665
Chapter 13
Structures 707
Part 4
Additional Topics 749
Chapter 14
Numerical Methods 751
Chapter 15
Bit Operations 787
Appendix A
Operator Precedence Table 801
Appendix B
ASCII Character Codes 803
Appendix C
Floating-Point Number Storage 805
Appendix D
Command-Line Arguments 809
Index 815
4 Brief Table of Contents
CONTENTS
Part 1
Fundamentals of C++ Programming 1
Chapter 1
Preliminaries 3
1.1 Preliminary One: Unit Analysis 4
Engineering and Scientific Units 6
1.2 Preliminary Two: Exponential and Scientific Notations 10
Using Scientific Notation 11
1.3 Preliminary Three: Software Development 14
Phase I: Development and Design 15
Phase II: Documentation 19
Phase III: Maintenance 19
Backup 20
1.4 Preliminary Four: Algorithms 22
1.5 A Closer Look: Software, Hardware, and Computer Storage 28
Machine Language 28
Assembly Languages 28
Low- and High-Level Languages 29
Procedural and Object Orientations 30
Application and System Software 30
The Development of C++ 31
Computer Hardware 33
Computer Storage 34
1.6 Common Programming Errors 37
1.7 Chapter Summary 37
Chapter 2
Problem Solving Using C++ 43
2.1 Introduction to C++ 43
The main() Function 46
The cout Object 48
2.2 Programming Style 53
Comments 55
2.3 Data Types 58
Integer Data Types 59
Determining Storage Size 62
Signed and Unsigned Data Types 64
Floating-Point Types 65
2.4 Arithmetic Operations 68
Expression Types 70
Integer Division 71
Negation 71
Operator Precedence and Associativity 72
2.5 Variables and Declaration Statements 76
Declaration Statements 78
Multiple Declarations 81
Memory Allocation 83
Displaying a Variable’s Address 85
Contents 5
2.6 A Case Study: Radar Speed Traps 90
2.7 Common Programming Errors 94
2.8 Chapter Summary 95
Chapter 3
Assignment, Formatting, and Interactive Input 103
3.1 Assignment Operations 103
Coercion 107
Assignment Variations 108
Accumulating 110
Counting 111
3.2 Formatting Numbers for Program Output 117
3.3 Using Mathematical Library Functions 131
Casts 135
3.4 Program Input Using cin 139
A First Look at User-Input Validation 143
3.5 Symbolic Constants 149
Placement of Statements 151
3.6 A Case Study: Acid Rain 158
3.7 A Closer Look: Programming Errors 164
3.8 Common Programming Errors 167
3.9 Chapter Summary 167
Chapter 4
Selection Structures 177
4.1 Selection Criteria 178
Relational Operators 178
Logical Operators 181
A Numerical Accuracy Problem 183
4.2 The if-else Statement 184
Compound Statements 187
Block Scope 190
One-Way Selection 191
Problems Associated with the if-else Statement 193
4.3 Nested if Statements 199
The if-else Chain 201
4.4 The switch Statement 208
4.5 A Case Study: Solving Quadratic Equations 213
4.6 A Closer Look: Program Testing 220
4.7 Common Programming Errors 222
4.8 Chapter Summary 223
Chapter 5
Repetition Statements 231
5.1 Basic Loop Structures 232
Pretest and Posttest Loops 232
Fixed-Count Versus Variable-Condition Loops 233
5.2 while Loops 234
5.3 Interactive while Loops 245
Sentinels 251
break and continue Statements 253
The Null Statement 254
6 Contents
5.4 for Loops 256
5.5 A Closer Look: Loop Programming Techniques 268
Technique 1: Interactive Input in a Loop 268
Technique 2: Selection in a Loop 269
Technique 3: Evaluating Functions of One Variable 270
Technique 4: Interactive Loop Control 273
5.6 Nested Loops 276
5.7 do while Loops 281
Validity Checks 283
5.8 Common Programming Errors 285
5.9 Chapter Summary 286
Chapter 6
Modularity Using Functions 293
6.1 Function and Parameter Declarations 294
Function Prototypes 295
Calling a Function 296
Defining a Function 297
Placement of Statements 302
Function Stubs 302
Functions with Empty Parameter Lists 303
Default Arguments 305
Reusing Function Names (Overloading) 305
Function Templates 306
6.2 Returning a Single Value 313
Inline Functions 319
6.3 Returning Multiple Values 324
Passing and Using Reference Parameters 324
6.4 A Case Study: Rectangular to Polar Coordinate Conversion 333
6.5 Variable Scope 346
Scope Resolution Operator 349
Misuse of Globals 351
6.6 Variable Storage Categories 354
Local Variable Storage Categories 355
Global Variable Storage Categories 358
6.7 Common Programming Errors 362
6.8 Chapter Summary 364
Chapter 7
Arrays 373
7.1 One-Dimensional Arrays 374
Input and Output of Array Values 378
7.2 Array Initialization 384
7.3 Declaring and Processing Two-Dimensional Arrays 388
Larger Dimensional Arrays 392
7.4 Arrays as Arguments 394
Internal Array Element Location Algorithm 401
7.5 A Case Study: Statistical Analysis 404
7.6 The Standard Template Library (STL) 410
7.7 A Closer Look: Searching and Sorting 418
Search Algorithms 418
Big O Notation 425
Sort Algorithms 426
7
Contents
7.8 Common Programming Errors 432
7.9 Chapter Summary 433
Chapter 8
I/O Streams and Data Files 439
8.1 I/O File Stream Objects and Methods 440
Files 440
File Stream Objects 441
File Stream Methods 442
8.2 Reading and Writing Character-Based Files 454
Reading from a Text File 456
Standard Device Files 461
Other Devices 462
8.3 Random File Access 465
8.4 File Streams as Function Arguments 468
8.5 A Case Study: Pollen Count File Update 472
8.6 A Closer Look: The iostream Class Library 479
File Stream Transfer Mechanism 479
Components of the iostream Class Library 480
In-Memory Formatting 482
8.7 Common Programming Errors 483
8.8 Chapter Summary 484
Chapter 9
Completing the Basics 489
9.1 Exception Handling 490
9.2 Exceptions and File Checking 496
Opening Multiple Files 500
9.3 The string Class 504
string Class Functions 505
String Input and Output 507
String Processing 511
9.4 Character Manipulation Functions 522
Character I/O 526
A Second Look at User-Input Validation 531
9.5 Input Data Validation 533
9.6 A Closer Look: Namespaces and Creating a Personal Library 541
9.7 Common Programming Errors 546
9.8 Chapter Summary 546
Part 2
Object-Oriented Programming 551
Chapter 10
Introduction to Classes 553
10.1 Abstract Data Types in C++ (Classes) 553
Abstract Data Types 555
Class Construction 556
Terminology 563
8 Contents
10.2 Constructors 567
Calling Constructors 570
Overloaded and Inline Constructors 570
Destructors 574
10.3 A Case Study: Constructing a Room Object 576
10.4 A Closer Look: Object Identification and the Unified Modeling Language (UML) 582
Representing Problems with Models 583
Class and Object Diagrams 585
Relationships 588
10.5 Common Programming Errors 592
10.6 Chapter Summary 593
Chapter 11
Class Functions and Conversions 597
11.1 Assignment 597
Copy Constructors 602
Base/Member Initialization 605
11.2 Additional Class Features 607
Class Scope 607
Static Class Members 607
Friend Functions 612
11.3 Operator Functions 616
Operator Functions as Friends 623
11.4 Data Type Conversions 625
Built-in to Built-in Conversion 626
Built-in to Class Conversion 626
Class to Built-in Conversion 628
Class to Class Conversion 630
11.5 A Case Study: Random Numbers and Simulations 635
Scaling 636
Elevator Simulation 637
11.6 Class Inheritance 645
Access Specifications 647
11.7 Polymorphism 653
11.8 Common Programming Errors 658
11.9 Chapter Summary 658
Part 3
Data Structures 663
Chapter 12
Pointers 665
12.1 Addresses and Pointers 666
Storing Addresses 667
Using Addresses 667
Declaring Pointers 668
References and Pointers 671
12.2 Array Names as Pointers 677
Dynamic Array Allocation 682
12.3 Pointer Arithmetic 686
Pointer Initialization 689
12.4 Passing Addresses 690
Passing Arrays 695
Advanced Pointer Notation 699
9
Contents
12.5 Common Programming Errors 702
12.6 Chapter Summary 704
Chapter 13
Structures 707
13.1 Single Structures 708
13.2 Arrays of Structures 714
13.3 Structures as Function Arguments 718
Passing a Pointer 721
Returning Structures 724
13.4 Linked Lists 727
13.5 Dynamic Data Structure Allocation 735
13.6 Unions 742
13.7 Common Programming Errors 744
13.8 Chapter Summary 745
Part 4
Additional Topics 749
Chapter 14
Numerical Methods 751
14.1 Introduction to Root Finding 751
14.2 The Bisection Method 755
14.3 Refinements to the Bisection Method 761
Regula Falsi Method 762
Modified Regula Falsi Method 764
Summary of the Bisection Methods 769
14.4 The Secant Method 770
14.5 Introduction to Numerical Integration 774
14.6 The Trapezoidal Rule 775
Computational Form of the Trapezoidal Rule Equation 776
Example of a Trapezoidal Rule Calculation 777
14.7 Simpson’s Rule 779
Example of Simpson’s Rule as an Approximation to an Integral 781
14.8 Common Programming Errors 783
14.9 Chapter Summary 783
Chapter 15
Bit Operations 787
15.1 The AND Operator 788
15.2 The Inclusive OR Operator 790
15.3 The Exclusive OR Operator 793
15.4 The Complement Operator 795
15.5 Different-Size Data Items 795
15.6 The Shift Operators 796
15.7 Chapter Summary 799
Appendix A
Operator Precedence Table 801
Appendix B
ASCII Character Codes 803
10 Contents
Appendix C
Floating-Point Number Storage 805
Appendix D
Command-Line Arguments 809
Index 815
11
Contents
This page intentionally left blank
PREFACE
The C++ programming language, which includes C as a proper subset, has become the
preeminent programming language in the engineering and scientific fields. For most
engineers and scientists, however, using the full potential of C++, which is a hybrid language
containing both structured and object-oriented features, involves a gradual refinement of
programming skills from a structured approach to an object-oriented one. One reason for this
is that many engineering and scientific problems can be solved efficiently and conveniently
by using only C++’s structured elements.
The refinement approach, from structural to object-oriented programming, is the one
C++ for Engineers and Scientists, Third Edition, takes. Therefore, like the first two editions, this
new edition begins by providing a strong foundation in structured programming. This
foundation is then expanded to a complete object orientation in a pedagogically sound and
achievable progression. Additionally, to keep it current with the current ANSI/ISO C++
standard, this edition has several important changes and added features, including the
following:
• Restructuring Part One to include both arrays and files, which allows using Part One
as the basis for a complete semester course in C++
• Adding more than 40 new engineering and scientific exercises that incorporate the
fields of electrical engineering, mechanical engineering thermodynamics, structural
engineering, numerical applications, physics, heat transfer, chemistry, and fluid
mechanics
• Adding a section on performing a unit analysis
• Adding a new introduction to the Standard Template Library
• Adding a section that introduces the fundamentals of the Unified Modeling
Language (UML)
• Restructuring the case studies throughout the book to emphasize specific engineer-
ing or scientific applications
• Adding end-of chapter programming projects that supplement the exercises at the
end of each section
• Labeling all exercises and programming projects as to application type
The following features have been retained from the second edition:
• Fundamentals of software engineering are discussed from both procedural and
object-oriented viewpoints.
• Common Programming Errors sections have been retained. These sections antici-
pate problems that novice C++ programmers encounter.
• The ANSI/ISO C++ iostream library and namespace mechanism are used in all
programs.
• Exception handling is discussed in a complete section, with practical applications of
exception handling included throughout the book.
• The new C++ string class is covered.
• A thorough discussion is included of input data validation and functions to check the
numerical data type of input items and to allow reentering invalid numerical types.
In practical terms, this book has been written to support both a one- and two-semester
technical C++ programming course; the only prerequisite is that students should be familiar
Preface 13
with fundamental algebra. This book is constructed to be flexible enough so that professors
can mold the book to their preferences for topic presentations. This flexibility is achieved in
the following ways.
Excluding Chapter 1, which includes computer literacy material for those who require
this background, Part One presents the basic structured syntax, flow control, and modularity
topics needed for a thorough understanding of C++’s structural features. With the topics of
arrays (Chapter 7) and files (Chapter 8) having been moved to Part One, this part now
provides a comprehensive one-semester course. As Chapters 7 and 8 have been written
specifically to depend only on Chapters 1 through 6, their order of presentation in the
classroom is entirely up to the professor’s discretion. With time permitting, the basics of
classes, introduced in Chapter 10, can also be covered to complete a one-semester course.
Additionally, depending on time and inclination, the numerical techniques discussed in
Chapter 14 can be presented at any point after Part One has been completed. Figure 1
illustrates this one-semester topic dependency.
An important feature of this book is that Part Two, on object-oriented programming, and
Part Three, on data structures, are interchangeable. So if you want to cover object-oriented
programming early, follow a Part One–Part Two–Part Three progression. On the other hand,
if you want to continue with additional structured programming reinforcement and discuss
object-oriented programming at the end of the course or the start of a second semester, follow
the sequence Part One–Part Three–Part Two. In either case, the material on arrays in
Chapter 7, files in Chapter 8, classes in Chapter 10, and numerical techniques in Chapter 14
can be introduced at any time after covering the first six chapters. Figure 2 shows the topic
dependency chart for the complete book and illustrates the flexibility of introducing different
topics under the umbrella of procedural programming, object-oriented programming, and
data structures.
Part One
Introduction
Chapter 1
Chapters
2 to 6
and 9
Arrays
Chapter 7
Files
Chapter 8
Objects
Chapter 10
Figure 1 Topic dependency for a one-semester course
14 Preface
Distinctive Features of This Book
Writing Style One thing I have found to be essential in my own classes is that after the
professor sets the stage in class, the assigned book must continue to encourage, nurture, and
assist students in acquiring and “owning” the material. To do this, the book must be written
in a manner that makes sense to students. My primary concern, and one of the distinctive
features of this book, is that it has been written for students. Therefore, I believe the writing
style used to convey the concepts is one of the most important aspects of this book.
Modularity To produce readable and maintainable programs, modularity is essential. C++,
by its nature, is a modular language. Therefore, the connection between C++ functions and
modules is made early in Chapter 2 and sustained throughout the book. Similarly, the idea
of parameter passing into modules is discussed early in Chapter 3, using C++’s mathematical
library. Explaining these concepts early introduces students to function and argument passing
as natural programming techniques. With the introduction of object-oriented programming
techniques in Chapter 10, students can build on the basic concept of encapsulating both data
and functions, which strengthens this modular emphasis.
Software Engineering Rather than simply introduce students to programming in C++,
this book introduces students to the fundamentals of software engineering from both a
structured and object-oriented viewpoint. Chapter 1 introduces the software development
procedure, which incorporates one of this book’s main themes: emphasizing problem-solving
techniques. Therefore, the importance of understanding and defining a problem, selecting
and refining a solution, and understanding the relationship between analysis, design, coding,
and testing is stated early and followed through with practical examples in all subsequent
case studies.
Case Studies Starting with Chapter 2, most chapters contain a case study. These case
studies demonstrate and reinforce effective problem solving in the context of the software
Chapter 1
Literacy
Topics
Part One
Procedural
Programming
Part Two
(Chapters 10 and 11)
Object-Oriented
Programming
Part Three
(Chapters 12 and 13)
Data Structures
Part Four
(Chapters 14 and 15)
Figure 2 Topic dependency chart
15
Preface
development procedure explained in Chapter 1 and are extended to object-oriented
development when classes are introduced in Chapter 10.
Program Testing Every C++ program in this book has been compiled and run successfully
and has been quality assurance tested with Microsoft Visual C++ .NET. Source code for all
programs can be found on the Course Technology Web site (www.cengage.com/coursetechnology).
Using the source code permits students to experiment with and extend the existing programs
and modify them more easily, as required for a number of end-of-section exercises.
Pedagogical Features
To facilitate the goal of making C++ accessible as a first-level course, the following
pedagogical features have been incorporated into this book.
End-of-Section Exercises Almost every section in the book contains numerous and
diverse skill-building and programming exercises. Each exercise is identified as to type
(practice, desk check, and so forth) or application (such as electrical engineering, heat
transfer, environmental, and so on). Additionally, solutions to all exercises are provided in the
Instructor Downloads section on www.cengage.com/coursetechnology.
End-of-Chapter Programming Projects Each chapter includes several programming
projects that combine all elements of C++ covered in previous sections and chapters. Projects
are identified as to type (practice, desk check, and so forth) or application (electrical
engineering, heat transfer, environmental, and so on).
Common Programming Errors and Chapter Summary Each chapter ends with a sec-
tion on common programming errors and a summary of the main topics covered in the
chapter.
Enrichment Sections Given the many different emphases that can be used in teaching
C++, several chapters include an enrichment section called “A Closer Look.” These sections
allow you to provide varying emphases with different students in C++ classes.
Point of Information Boxes These boxes present additional clarification of commonly
used or difficult concepts, such as abstraction, lvalues and rvalues, values versus
identities, flags, and stream formatting. In addition, many Point of Information boxes explain
alternative and advanced programming techniques, useful technical points, programming
tips, and programming tricks used by professional programmers.
Pseudocode Descriptions Pseudocode is used throughout the book. Flowchart symbols
are introduced but are used only in illustrating flow-of-control constructs.
Engineering and Scientific Disciplines Many chapters have a box at the end with
information on several engineering and scientific fields, such as electrical, chemical, mechani-
cal, and aeronautical engineering.
16 Preface
Appendixes This book includes four appendixes on operator precedence, ASCII character
codes, floating-point number storage, and command-line arguments. Additionally, Course
Technology provides tutorials for using various C++ compilers at www.cengage.com/coursetechnology.
Supplemental Materials
The following supplemental materials are available when this book is used in a classroom
setting:
Electronic Instructor’s Resources. The Instructor’s Resources that accompany this book
include the following:
• Additional instructional material to assist in class preparation, including suggestions
for lecture topics
• Solutions to all the end-of-chapter materials, including the programming projects
ExamView威. This book is accompanied by ExamView, a powerful testing software
package that allows instructors to create and administer printed, computer (LAN-based), and
Internet exams. ExamView includes hundreds of questions that correspond to the topics
covered in this book, enabling students to generate detailed study guides that include page
references for further review. These computer-based and Internet testing components allow
students to take exams at their computers and save instructors time because each exam is
graded automatically. The Test Bank is also available in WebCT and Blackboard formats.
PowerPoint Presentations. This book comes with Microsoft PowerPoint slides for each
chapter. They are included as a teaching aid for classroom presentations, to make available
to students on the network for chapter review, or to be printed for classroom distribution.
Instructors can add their own slides for additional topics they introduce to the class.
Source Code. The source code for this book is available at www.cengage.com/coursetechnology
and is also available on the Teaching Tools CD.
Solution Files. The solution files for all programming exercises and projects are available
at www.cengage.com/coursetechnology and on the Teaching Tools CD.
17
Preface
To Rochelle, Jeremy, David, and Matthew Bronson
Acknowledgments
The writing of this third edition is a direct result of the success (and limitations) of the
previous two editions. In this regard, my most heartfelt acknowledgment and appreciation is
to the instructors and students who found the previous editions to be of service in their
quests to teach and learn C++.
Next, I would like to thank Alyssa Pratt, my Senior Product Manager at Course
Technology. In addition to her continuous faith and encouragement, her ideas and partner-
ship were instrumental in creating this book. After the writing process was completed, the
task of turning the final manuscript into a book depended on many people other than myself.
For this, I especially want to thank my developmental editor, Lisa Lord, who provided an
outstanding job. Her editing so dovetailed with both the spirit and idiosyncrasies of my own
writing style that it was an absolute pleasure working with her. She stayed true to what I was
attempting to achieve while patiently going through both the technical and grammatical
content. A truly incredible feat! This editing was supplemented by the equally detailed work
of my colleague, Professor Joan Zucker Hoffman, with structural engineering applications
provided by Professors Andy Gregg and Al Branchi and moral support provided by Dr. John
Becker of the Theology Department. Finally, I would like to thank the testers at Course
Technology’s MQA Department as well as GEX Publishing Services, especially the interior
designer, and Camille Kiolbasa, the copyeditor. The dedication of this team of people was
extremely important to me and I am very grateful to them.
The following reviewers provided extensive, extremely useful, and detailed information and
corrections that made this edition better and more accurate. No matter how careful I was, each
reviewer pointed out something that I missed or could be stated better. I am very thankful to
them. Naturally, all errors rest squarely on my shoulders, but these reviewers made the load
much easier: Hyder Ali, California State University, Northridge, and Robert Baird, Salt Lake
Community College. In addition, I’d like to thank the following instructors who reviewed the
proposal for this edition and offered valuable feedback: Randy Bower, Jacksonville University;
Helen Darcey, Cleveland State Community College; Akira Kawaguchi, The City College of New
York; Cynthia Lester, Tuskegee University; and Sherman Wong, Baruch University.
As with the first edition, special acknowledgement goes to Dr. G.J. Borse of Lehigh
University, who provided material that was adapted for this book. Specifically, his contribu-
tion includes almost all of Chapter 14, which Dr. Borse graciously permitted me to adapt from
his FORTRAN 77 text (copyright held by PWS Publishing). I would also like to acknowl-
edge, with extreme gratitude, the wonderful academic environment for learning and teaching
created at Fairleigh Dickinson University—starting with the President, Dr. Michael Adams,
followed through in the academic departments by the university and campus provosts, Dr.
Joseph Kiernan and Dr. Kenneth Greene, and finally to the direct encouragement and
support provided by my dean, Dr. William Moore, and my chairperson, Dr. Paul Yoon.
Without their support, this book could not have been written.
Finally, I deeply appreciate the patience, understanding, and love provided by my friend,
wife, and partner, Rochelle.
Gary Bronson
2009
18 Preface
Part
One
Fundamentals of C++
Programming
1 Preliminaries
2 Problem Solving
Using C++
3 Assignment, Formatting,
and Interactive Input
4 Selection Structures
5 Repetition Statements
6 Modularity Using Functions
7 Arrays
8 I/O Streams and Data Files
9 Completing the Basics
Although C++ is an object-oriented
language, it was developed as an
extension to C, a procedural-oriented
language. As such, C++ is a hybrid
language having both procedural and
object features. Because of this hybrid
nature, not only is it possible to write a
complete C++ program using just
procedural code, but also it’s
impossible to write an object-oriented
program in C++ that doesn’t include
procedural elements. Therefore, a
proper start to learning C++ requires
familiarity with its procedural aspects.
This page intentionally left blank
Chapter
1
Preliminaries
1.1 Preliminary One: Unit Analysis
1.2 Preliminary Two: Exponential
and Scientific Notations
1.3 Preliminary Three: Software
Development
1.4 Preliminary Four: Algorithms
1.5 A Closer Look: Software,
Hardware, and Computer
Storage
1.6 Common Programming Errors
1.7 Chapter Summary
Programming scientific and engineering applications requires a number of basic skills, both in
understanding the underlying applications and in understanding the fundamentals of the programming
process itself. On the applications side, a knowledge of numerical measurements and their corresponding
units, as well as a familiarity with performing calculations, are assumed. Using consistent sets of units
and knowing how to convert between units is a basic prerequisite of these applications.
Additionally, the programming process assumes the programmer starts with a preliminary set of
skills. As you develop your programming abilities in C++, a clear understanding of how programs are
developed, in general, is important. This understanding includes what constitutes a “good” program
and what an algorithm is.
This chapter covers these preliminary requirements and can be used as an introduction or a review.
1.1 Preliminary One: Unit Analysis
In all fields of study, using consistent and correct units when making computations is crucial.
As a simple example, consider calculating the area of a rectangle by using this formula:
Area = length × width [Eq. 1-1]
When using this formula, the units for length and width must be the same. Therefore,
if the length is given as 2 feet and the width as 3 inches, at least one of these units must be
converted to ensure that both length and width are in the same units before the area is
calculated. Converting the length to inches, the rectangle’s area is computed as follows:
Area ft
in
ft
in in
=





 × =
2
12
1
3 36 2
[Eq. 1-1a]
Similarly, if you choose to convert the width from 3 inches to its equivalent feet, the
calculation becomes the following:
Area ft in
ft
in
ft
= ×





 =
2 3
1
12
0 25 2
. [Eq. 1-1b]
In the same manner, if one side of the rectangle is given in centimeters and the other in
meters, a conversion is necessary to compute the area.
Notice that in Equations 1-1a and 1-1b, units for both length and width as well as units
for the conversion factor ([12 in/1 ft] in Eq. 1-1a and [1 ft/12 in] in Eq. 1-1b) are included in
the formula. The reason is that the terms for units can be multiplied and divided to provide
the final unit result. In many cases, this technique is a powerful one for selecting a correct
conversion factor and ensuring that a computation is being calculated correctly.
To see why, continue with the area example. Use Eq. 1-1a, but include only the unit
terms, which yields the following:
Area ft
in
ft
in
=





 × [Eq. 1-1c]
Now a unit of ft divided by a unit of ft is 1. That is, you can cancel the ft units in
Eq. 1-1c as follows, which yields the final units as in multiplied by in, or in2
, which is a correct
unit for the area:
Area ft
in
ft
in in
= /
/
/





 × = 2
Including only the units and conversion factors in an equation, and canceling out
corresponding units in the numerator and denominator, is referred to as performing a unit
analysis. As an example of a unit analysis for selecting a correct form of a conversion factor,
assume you need to convert miles (symbol mi) to kilometers (symbol km), and you have the
information that 1 kilometer = 0.6214 miles. As a conversion factor, this equality can be
written as either of the following fractions:
1
0 6214
0 6214
1
or
km
mi
mi
km
.
.
Deciding which conversion factor to use in converting miles to kilometers is easy when
you consider units. To see why, try both factors with miles, canceling the units that occur
4 Preliminaries
in both the numerator and denominator and concerning yourself only with the final
resulting units:
mi
km
mi
km
×





 =
1
0 6214
.
and
mi
mi
km
mi
km
×





 =
0 6214
1
2
.
.
Because the first factor (1 km/0.6214 mi) provides the correct final units of kilometers,
it’s the form of the conversion factor that must be applied to convert miles to kilometers.
For a slightly more complicated example of performing a unit analysis for selecting
correct conversion factors, consider converting days to seconds. You can determine the correct
form of each conversion factor easily by including the units with each conversion factor, as
you change days to hours, then hours to minutes, and finally minutes to seconds, performing
each conversion one at a time and canceling units as you proceed with each conversion, as
follows:
24 hr
day
×
days
1st conversion:
days to hours
(cross out the days)
The next conversion changes the units of hours to minutes, using the conversion factor
60 min/hr, as follows:
60 min
hr
24 hr
day
×
1st conversion:
days to hours
(cross out the days)
2nd conversion:
hours to minutes
(cross out the hours)
×
days
5
Chapter 1
Preliminary One: Unit Analysis
The final conversion is used to convert minutes to seconds:
60 min
hr
24 hr
day
×
1st conversion:
days to hours
(cross out the days)
2nd conversion:
hours to minutes
(cross out the hours)
60 sec
min
×
3rd conversion:
minutes to seconds
(cross out the minutes)
= sec
×
days
In a single line, the complete conversion appears as follows:
60 min
hr
24 hr
day
×
60 sec
min
× = sec
×
days
Before showing how a unit analysis can help ensure that a complete computation is being
calculated correctly, it’s useful to first summarize the systems of units in common use.
Engineering and Scientific Units
Two unit systems are commonly used in engineering and scientific work: the English
Engineering system and the International System (SI). Both are used in this book. Table 1.1
lists the units used in these two systems.
Table 1.1 Commonly Used Physical Quantities
Quantity Symbol International
System (SI) Units
English
Engineering Units
Conversion
Equalities
Time t seconds (s) seconds (sec)
Length l meters (m) feet (ft) 1 m = 3.2808 ft
Area A sq. meters (m2
) sq. feet (ft2
) 1 m2
=
10.76 ft2
Volume V cubic meters (m3
) cubic feet (ft3
) 1 m3
=
35.31 ft3
Mass m kilograms (kg) pounds-mass (lbm) 1 kg = 2.19 lbm
Force F Newton (1 N =
1 kg-m/s2
)
pounds-force (lbf =
lbm-ft/sec2
)
1 lbf = 4.448 N
Weight W Newton (N) pounds-force (lbf) 1 lbf = 4.448 N
Density ␳ kilograms/cubic
meters (kg/m3
)
pounds-mass/cubic
ft (lbm/ft3
)
1 lbf/ft3
=
16.02 kg/m3
Velocity v meters/sec (m/s) feet/sec (ft/sec) 1 m/s =
3.2808 ft/sec
Acceleration a meters/sec2
(m/s2
) feet/sec2
(ft/sec2
) 1 m/s2
=
3.2808 ft/sec2
6 Preliminaries
Table 1.1 Commonly Used Physical Quantities (continued)
Quantity Symbol International
System (SI) Units
English
Engineering Units
Conversion
Equalities
Pressure P Pascal (Pa) (1 Pa =
1 N/m2
)
lbf/ft2
1 lbf/ft2
=
47.88 Pa
Heat transfer Q Joules (J) (1 J = 1
N.m)
British Thermal
Unit (BTU)
1 BTU = 1055 J
Heat flux Q Joules/sec (J/s) (1
J/s = 1 Watt)
BTU/sec 1 BTU/sec =
1055 J/s
Work W Joules (J) ft-lbf 1 ft-lbf =
1.356 J
Power W Watts (W) (1 W =
1 J/s)
ft-lbf/sec 1 ft-lbf/sec =
1.356 W
Temperature T degrees Celsius
(C) and degrees
Kelvin (K)
degrees Fahrenheit
(F) and degrees
Rankin (R)
The following conversion formulas show the relationships between the various tempera-
ture scales:
°F = 1.8°C + 32 = 9/5°C + 32
°C = (°F - 32)/1.8 = 5/9 (°F - 32)
°K = °C + 273.15
°R = °F + 459.67
°R = 1.8°K
°C = (°R - 491.67) / 1.8 = 5/9 (°R - 491.67)
Using these conversion formulas provides the equivalent boiling and freezing points of
water for each of the temperature scales listed in the following chart:
°C °F °K °R
Freezing point
of water
0 32 273.15 491.67
Boiling point
of water
100 212 373.15 671.67
As an example, using the conversion equalities in Table 1.1 (last column), consider
calculating Newton’s Second Law for a mass of 5 kilograms and an acceleration of 32.2 ft/sec2
.
Newton’s Second Law states that
Force = Mass × Acceleration
Assuming SI units are used, the calculation becomes
Force kg
ft m
ft
= ×
/





 =
5
32 2 1
3 2808
49 07
2
.
sec .
. k
kg m
N
sec
.
2
49 07
=
7
Chapter 1
Preliminary One: Unit Analysis
Notice from the information in Table 1.1 that 1 m = 3.2808 ft is used to create this
conversion factor
1
3 2808
m
ft
.






rather than this conversion factor
3 2808
1
. ft
m






because the first form achieves the desired cancelation of units. If you mistakenly use the
second conversion factor, you would end up with the following final units, which immediately
alert you that an incorrect result would occur:
Force kg
ft ft
m
kg ft
= ×





 =
5
32 2 3 2808
1
2
2
. .
sec se
ec2
m
Finally, you could also achieve the correct conversion by using the following set of
conversions:
2.54 cm
in
32.2 ft
sec
×
×
Force = 5 kg
1 m
100 cm
× = 49.073 kg m/s2
12 in
ft
×
2
1st conversion:
feet to inches
(cross out the ft)
2nd conversion:
inches to centimeters
(cross out the in)
3rd conversion:
centimeters to meters
(cross out the cm)
Frequently, when you don’t know the final conversion factor, making intermediate
conversions, as in this last calculation, can get you to the correct result easily. Notice that by
applying one conversion factor at a time and canceling units as you go along, you avoid the
common mistake of multiplying or dividing by the wrong conversion factor. If the final units,
by themselves, do not yield the correct resulting units, then the resulting numerical answer
must be incorrect. Correspondingly, if correct conversion factors and correct individual mea-
surements are used, the result will be correct in both numerical and unit terms. Using the
correct units and doing a unit analysis certainly can’t protect you against using incorrect
numbers in a calculation or making calculation errors, but by itself, a unit analysis can ensure
that you’re on the right path to computing a final numerical result correctly.
8 Preliminaries
EXERCISES 1.1
1. (Practice) a. To convert inches (in) to feet (ft), the number of inches should be multi-
plied by which of the following conversion factors?
i. 12 in/1 ft ii. 1 ft/12 in
b. To convert meters (m) to kilometers (km), the number of meters should be multiplied
by which of the following conversion factors?
i. 1000 m/1 km ii. 1 km/1000 m
c. To convert minutes (min) to seconds (sec), the number of minutes should be multi-
plied by which of the following conversion factors?
i. 60 sec/1 min ii. 1 min/60 sec
d. To convert seconds (sec) to minutes (min), the number of seconds should be multi-
plied by which of the following conversion factors?
i. 60 sec/1 min ii. 1 min/60 sec
2. (Practice) a. To convert feet (ft) to meters (m), the number of feet should be multiplied
by which of the following conversion factors?
i. 1 m/3.28 ft ii. 3.28 ft/1 m
b. To convert sq.in to sq.ft, the number of sq.in should be multiplied by which of the
following conversion factors?
i. 144 sq.in/1 sq.ft ii. 1 sq.ft/144 sq.in
c. To convert sq.yd to sq.ft, the number of sq.yd should be multiplied by which of the
following conversion factors?
i. 1 sq.yd/9 sq.ft ii. 9 sq.ft/1 sq.yd
3. (Practice) Determine the final units of the following expression:
9.8 m/s2
× 100 cm/1 m × 1 in/2.54 cm × 1 ft/12 in
4. (Practice) a. Determine the conversion factors that can be used to convert miles per
gallon (mpg = mi/gal) to kilometers per liter (km/liter), given that 1 liter = 0.22 gallons
and 1 kilometer = 0.6214 miles.
b. Using the conversion factors you determined in Exercise 4a, convert 25 mpg into
km/liter.
5. (Automotive) a. An automobile engine’s performance can be determined by monitoring
its rotations per minute (rpm). Determine the conversion factors that can be used to con-
vert rpm to frequency in Hertz (Hz), given that 1 rotation = 1 cycle, 1 minute = 60 sec-
onds, and 1 Hz = 1 cycle/sec.
b. Using the conversion factors you determined in Exercise 5a, convert 2000 rpm into Hertz.
6. (Chemistry) a. Determine the final units of the following expression, which provides the
molecular weight of 1.5 moles of hydrogen peroxide:
1.5 moles × 34.0146 grams/mole
9
Chapter 1
Preliminary One: Unit Analysis
b. Determine the final units of the following expression, which provides the molecular
weight of 5.3 moles of water:
5.3 moles × 18 grams/mole
7. (Oceanography) The pressure, P, exerted on an underwater object can be determined
by this formula:
P g h
= ρ
ρ is the density of water, which is 100 kg/m3
.
g is the acceleration caused by Earth’s gravity, which is 9.8 m/s2
.
h is the depth of the object in the water in meters.
a. Determine the units of P by calculating the units resulting from the right side of the
formula. Check that your answer corresponds to the units for pressure listed in Table 1.1.
b. Determine the pressure on a submarine operating at a depth of 500 meters.
8. (Thermodynamics) The work, W, performed by a single piston in an engine can be
determined by this formula:
W F d
=
F is the force provided by the piston in Newtons.
d is the distance the piston moves in meters.
a. Determine the units of W by calculating the units resulting from the right side of the
formula. Check that your answer corresponds to the units for work listed in Table 1.1.
b. Determine the work performed by a piston that provides a force of 1000 N over a dis-
tance of 15 centimeters.
1.2 Preliminary Two: Exponential and Scientific Notations
Many engineering and scientific applications require dealing with extremely large and
extremely small numbers. For example, Avogadro’s number, used in chemistry, has the value
602,214,179,000,000,000,000,000; the universal gravitational constant used in aerospace and
rocketry applications has the value 0.0000000000667428. To make entering these numbers in
a computer program easier, they can be written in a more compact form known as exponential
notation. Similarly, in performing hand calculations for verification purposes, an equivalent
representation known as scientific notation is typically used.
The following examples illustrate how numbers with decimals can be expressed in both
exponential and scientific notation:
Decimal Notation Exponential Notation Scientific Notation
1625. 1.625e3 1.625 × 103
63421. 6.3421e4 6.3421 × 104
.00731 7.31e-3 7.31 × 10-3
.000625 6.25e-4 6.25 × 10-4
10 Preliminaries
In exponential notation, the letter e stands for exponent. The number following the e
represents a power of 10 and indicates the number of places the decimal point should be moved
to obtain the standard decimal value. The decimal point is moved to the right if the number after
e is positive, or it’s moved to the left if the number after e is negative. For example, the e3 in
1.625e3 means move the decimal place three places to the right, so the number becomes 1625.
The e-3 in 7.31e-3 means move the decimal point three places to the left, so 7.31e-3 becomes
.00731. Using these representations, Avogadro’s number is written as 6.02214179e23 and
6.02214179 × 1023
in exponential and scientific notation, and the universal gravitational constant
is written as 6.67428e-11 in exponential notation and 6.67428 × 10-11
in scientific notation.
As noted previously, exponential notation is used to enter very large or very small
numbers in a C++ program and will be used in Section 2.6, where very large numbers are
required for the given application.
Using Scientific Notation
An essential part of engineering and scientific programming is understanding what formulas
are to be used and verifying calculations, typically by hand. For evaluating formulas that use
very large or very small numbers, which isn’t uncommon in the applications you’ll be
programming, scientific notation is convenient. The reason is that scientific notation permits
using the following two basic exponential rules, as they apply to the powers of 10:
Rule 1: 10n
x 10m
= 10n+m
for any values, positive or negative, of n and m
Examples: 102
× 105
= 107
(that is, 100 × 100,000 = 10,000,000)
10-2
× 105
= 103
(that is, .01 × 100,000 = 1,000)
102
× 10-5
= 10-3
(that is, 100 × .00001 = .001)
10-2
× 10-5
= 10-7
(that is, .01 × .00001 = .0000001)
10-23
× 1034
= 1011
Rule 2:
1
10
10
-n
n
= for any positive or negative value of n
Examples:
1
10
10
2
2
-
= (that is,
1
01
100
.
= )
1
10
10
2
2
= -
(that is,
1
100
01
= . )
1
10
10
3
3
-
= (that is,
1
001
1000
.
= )
1
10
10
4
4
= -
(that is,
1
10 000
0001
,
.
= )
Notice that in scientific notation (as in exponential notation), if the exponent is positive,
it represents the actual number of zeros that follow the 1, but if the exponent is negative, is
represents one less than the number of zeros after the decimal point and before the 1.
After you understand the basic rules of using scientific notation, you can combine them
easily, as shown in this computation:
10 10
10
10
10
10 10 10
2 5
4
7
4
7 4 3
×
= = × =
-
11
Chapter 1
Preliminary Two: Exponential and
Scientific Notations
If scientific notation were concerned only with powers of 10, as in the preceding
example, its usefulness would be extremely limited. Fortunately, however, this notation can
be used with any decimal number. For example, take a look at this computation:
236,000 .345 1,345,000
× ×
×
67 8 000007
. .
This computation is calculated more easily by first converting each number to its equivalent
scientific notation, and then combining exponents (using Rules 1 and 2) as follows:
2 36 10 3 45 10 1 345 10
6 78 10 7 0 10
5 1 6
1
. . .
. .
× × × × ×
× × ×
-
-
-6
=
2 36 3 45 1 345 10
6 78 7 0 10
10
5
. . .
. .
× × ×
× ×
=
-
2 36 3 45 1 345 10
6 78 7 0
15
. . .
. .
× × ×
×
Finally, the remaining numbers in the numerator can be multiplied and then divided by
the numbers in the denominator to yield a final result of .2307 × 1015
= 2.307 × 1014
.
Whenever a formula contains one or more extremely small or large numbers, use the
technique of first, converting the number to scientific notation, and second, dealing with the
exponents and remaining numbers individually. This technique can be of great help in the
final computation. (Note that converting all the numbers isn’t necessary.) You’ll make use of
this technique often in performing hand calculations to validate results during the testing
phase of a program.
Scientific Notational Symbols Certain scientific notations occur frequently enough in
science and engineering applications that they have their own symbols. The most commonly
used are listed in Table 1.2.
Table 1.2 Scientific Notational Symbols
Scientific Notation Symbol Name
10-12
p pico
10-9
n nano
10-6
µ micro
10-3
m milli
103
k kilo
106
M mega
109
G giga
1012
T tera
For example, the storage capacities of computer disks and thumb drives are currently
specified in megabytes (MB) and gigabytes (GB), which means they contain millions (106
)
and billions (109
) of bytes, respectively. (See Section 1.5 for the definition of a byte.)Similarly,
computer processing speeds are specified in the nanosecond (nsec) range, which means a
billionth (10-9
) of a second.
12 Preliminaries
EXERCISES 1.2
1. (Practice) Convert the following numbers from exponential form into standard decimal form:
a. 6.34e5
b. 1.95162e2
c. 8.395e1
d. 2.95e-3
e. 4.623e-4
2. (Practice) Convert the following numbers from scientific notation into standard
decimal form:
a. 2.67 × 103
b. 2.67 × 10-3
c. 1.872 × 109
d. 1.872 × 10-9
e. 2.67 × 103
f. 6.6256 × 10-34
(known as Planck’s constant)
3. (Practice) Write the following decimal numbers using scientific notation:
a. 126
b. 656.23
c. 3426.95
d. 4893.2
e. .321
f. .0123
g. .006789
4. (Practice) Compute the following:
a. 104
× 10-6
× 10-3
× 1012
b.
1
10 10 10 10
4 -6 -3 12
× × ×
c.
10 10 10
2 7 4
× ×
× × ×
10 10 10 10
4 -6 -3 12
d.
10 10 10
3 7 4
× ×
×
10 10
- -
-6 -5
5. (Practice) Compute the following:
a. 2.8 × 104
× 1.6 × 10-6
× 3.2 × 10-3
b.
1
4.5 10 1.8 10 6.7 10
4 -6 -3
× × × × ×
c.
1 4 10 2 5 10 5 310
2 7 4
. . .
3.2 10 1.
4
× × × ×
× × 8
8 10 2.7 10
-6 -3
× × ×
d.
7 1 10 8 45 10 3 6710
3 7 4
. . .
9.89 10
- -
× × × ×
× -
-6 -5
6.28 10
× ×
13
Chapter 1
Preliminary Two: Exponential and
Scientific Notations
6. (Aeronautics) The initial acceleration, a, of a rocket fired from earth, with an initial
thrust, T, is given by this formula:
a
T mg
m
=
−
a is the initial acceleration.
T is the thrust in Newtons.
m is the mass in kg.
g is the acceleration caused by gravity in m/s2
.
a. Determine the units of the initial acceleration by calculating the units resulting from the
right side of the equation. (Hint: As listed in Table 1.1, a Newton is N = kg – m/s2
.)
b. Determine the initial acceleration of a rocket having a mass of 5 × 104
kg and an ini-
tial thrust of 6 × 105
Newtons. The value of g is 9.81 m/s2
.
7. (Heat Transfer) The energy radiated from the surface of the sun or a planet in the solar
system can be calculated by using Stephan-Boltzmann’s Law:
E = ␴ T4
E is the energy radiated.
␴ is Stephan-Boltzmann’s constant (5.6697 × 10-8
Watts/m2
K4
).
T is the surface temperature in degrees Kelvin (°K = °C + 273).
a. Determine the units of E by calculating the units resulting from the right side of the
formula.
b. Determine the energy radiated from the sun’s surface, given that the sun’s average
temperature is approximately 6,000°K.
1.3 Preliminary Three: Software Development
A computer is a machine, and like other machines, such as an automobile or a lawnmower,
it must be turned on and then driven, or controlled, to perform the task it was meant to do.
In an automobile, for example, control is provided by the driver, who sits inside the car and
directs it. In a computer, the driver is a set of instructions called a program. More formally,
a computer program is a self-contained set of instructions used to operate a computer to
produce a specific result. Another term for a program or set of programs is software, and both
terms are used interchangeably throughout this book.1
At its most basic level, a program is a solution developed to solve a particular problem,
written in a form that can be executed on a computer. Therefore, writing a program is almost
the last step in a process that first determines the problem to be solved and the method to
be used in the solution. Each field of study has its own name for the systematic method of
designing solutions to solve problems. In science and engineering, the approach is referred
to as the scientific method, and in quantitative analysis, the approach is called the systems
approach. Professional software developers use the software development procedure for
1
More inclusively, the term “software” is also used to denote both the programs and the data on which programs operate.
14 Preliminaries
understanding the problem to be solved and for creating an effective, appropriate software
solution. This procedure, illustrated in Figure 1.1, consists of three overlapping phases:
1. Development and design
2. Documentation
3. Maintenance
As a discipline, software engineering is concerned with creating readable, efficient,
reliable, and maintainable programs and systems, and it uses the software development
procedure to achieve this goal.
Phase I: Development and Design
Phase I begins with a statement of a problem or a specific request for a program, which is
referred to as a program requirement. After a problem has been stated or a specific request for
a program solution has been made, the development and design phase begins. This phase
consists of four well-defined steps, as illustrated in Figure 1.2.
Request for
a program
Time
Program no
longer used
Maintenance
Documentation
Development
and design
Program
life cycle
stages
Figure 1.1 The three phases of program development
Design
Coding
Testing
Development
and
design
steps
Analysis
Time
Figure 1.2 The development and design steps
15
Chapter 1
Preliminary Three: Software Development
Step 1 Analyze the Problem
The analysis of a problem can consist of up to two parts. The first part is a basic analysis that
must be performed on all problems; it consists of extracting the complete input and output
information supplied by the problems. For this analysis, you must
1. Determine and understand the output items the program must produce.
2. Determine the input items.
Together, these two items are referred to as the problem’s input/output (I/O). Only after
determining a problem’s I/O can you select specific steps for transforming inputs into
outputs. At this point, doing a hand calculation to verify that the output(s) can indeed be
obtained from the inputs is sometimes necessary and/or useful. Clearly, if you have a formula
that relates inputs to the output, you can omit this step. If the required inputs are available
and the desired outputs can be produced, the problem is said to be clearly defined and can
be solved.
For a variety of reasons, completing a basic analysis might not be possible. If so, an
extended analysis might be necessary. An extended analysis simply means you must gather
more information about the problem so that you thoroughly understand what’s being asked
for and how to achieve the result. In this book, any additional information required to
understand the problem is supplied along with the problem statement.
Step 2 Develop a Solution
In this step, you select the exact set of steps, called an “algorithm,” to be used to solve the
problem. Typically, you find the solution by a series of refinements, starting with the initial
solution you find in the analysis step, until you have an acceptable and complete solution.
This solution must be checked, if it wasn’t done in the analysis step, to make sure it produces
the required outputs correctly. The check is usually carried out by doing one or more hand
calculations that haven’t been done already.
For small programs, the selected solution might be extremely simple and consist of only
one or more calculations. More typically, you need to refine the initial solution and organize
it into smaller subsystems, with specifications for how the subsystems interface with each
other. To achieve this goal, the solution’s description starts from the highest level (top)
requirement and proceeds downward to the parts that must be constructed to meet this
requirement. To make this explanation more meaningful, consider a computer program that
must track the number of parts in inventory. The required output for this program is a
description of all parts carried in inventory and the number of units of each item in stock; the
given inputs are the initial inventory quantity of each part, the number of items sold, the
number of items returned, and the number of items purchased.
For these specifications, a designer could initially organize the program’s requirements
into the three sections illustrated in Figure 1.3. This figure is referred to as both a top-level
structure diagram and a first-level structure diagram because it represents the first overall
structure of the program the designer has selected.
After an initial structure is developed, it’s refined until the tasks in the boxes are
completely defined. For example, the data entry and report modules shown in Figure 1.3
would be refined further. The data entry module certainly must include provisions for
entering data. Because planning for contingencies and human error is the system designer’s
responsibility, provisions must also be made for changing incorrect data after an entry is made
and for deleting previous entries. Similar subdivisions for the report module can be made.
16 Preliminaries
Figure 1.4 illustrates a second-level structure diagram for an inventory tracking system that
includes these further refinements.
The process of refining a solution continues until the smallest requirement is included.
Notice that the design produces a treelike structure, in which the levels branch out as you
move from the top of the structure to the bottom. When the design is finished, each task
designated in a box is typically coded with separate sets of instructions that are executed as
they’re called on by tasks higher up in the structure.
Step 3 Code the Solution (Write the Program)
This step consists of actually writing a C++ program that corresponds to the solution
developed in Step 2. If the analysis and solution steps have been performed correctly, the
coding step becomes rather mechanical in nature. In a well-designed program, the statements
making up the program, however, conform to certain well-defined patterns or structures that
have been defined in the solution step. These structures control how the program executes
and consist of the following types:
• Sequence
• Selection
Calculation
section
Data
entry
section
Report
section
Inventory
control
program
Figure 1.3 A first-level structure diagram
Calculation
section
Data
entry
section
Report
section
Inventory
control
program
Printer
reports
Screen
reports
Delete
data
Change
data
Enter
data
Figure 1.4 A second-level structure diagram
17
Chapter 1
Preliminary Three: Software Development
• Iteration
• Invocation
Sequence defines the order in which the program executes instructions. Specifying which
instruction comes first, which comes second, and so on is essential if the program is to achieve
a well-defined purpose.
Selection provides the capability to make a choice between different operations, depending
on the result of some condition. For example, the value of a number can be checked before a
division is performed: If the number is not zero, it can be used as the denominator of a division
operation; otherwise, the division isn’t performed and the user is issued a warning message.
Iteration, also referred to as “looping” and “repetition,” makes it possible to repeat the
same operation based on the value of a condition. For example, grades might be entered and
added repeatedly until a negative grade is entered. In this case, the entry of a negative grade
is the condition that signifies the end of the repetitive input and addition of grades. At that
point, an average for all grades entered could be calculated.
Invocation involves invoking, or summoning, a set of statements as it’s needed. For example,
computing a person’s net pay involves the tasks of obtaining pay rates and hours worked,
calculating the net pay, and providing a report or check for the required amount. Each task is
typically coded as a separate unit that’s called into execution, or invoked, as it’s needed.
Step 4 Test and Correct the Program
The purpose of testing is to verify that a program works correctly and actually fulfills its
requirements. In theory, testing would reveal all existing program errors. (In computer
terminology, a program error is called a bug.2) In practice, finding all errors would require
checking all possible combinations of statement execution. Because of the time and effort
required, this goal is usually impossible, except for extremely simple programs. (Section 4.8
explains why this goal is generally considered impossible.)
Because exhaustive testing isn’t feasible for most programs, different philosophies and
methods of testing have evolved. At its most basic level, however, testing requires a conscious
effort to make sure a program works correctly and produces meaningful results. This effort means
giving careful thought to what the test is meant to achieve and to the data used in the test. If
testing reveals an error (bug), the process of debugging, which includes locating, correcting, and
verifying the correction, can be initiated. Realize that although testing might reveal the presence
of an error, it doesn’t necessarily indicate the absence of one. Therefore, the fact that a test revealed one
bug does not indicate that another one isn’t lurking somewhere else in the program.
To catch and correct errors in a program, developing a set of test data for determining
whether the program gives correct answers is important. In fact, often an accepted step in
formal software development is to plan test procedures and create meaningful test data before
writing the code. Doing this step first helps you be more objective about what the program
must do because it circumvents the subconscious temptation after coding to avoid test data
that would reveal a problem with your program. The procedures for testing a program should
examine every possible situation in which the program will be used. The program should be
tested with data in a reasonable range as well as at the limits and in areas where the program
2
The derivation of this term is rather interesting. When a program stopped running on the Mark I at Harvard University in September 1945,
Grace Hopper traced the malfunction to a dead insect that had gotten into the electrical circuits. She recorded the incident in her logbook as
“Relay #70. . . . (moth) in relay. First actual case of bug being found.”
18 Preliminaries
should tell the user that the data is invalid. Developing good test procedures and data for
sophisticated problems can be more difficult than writing the program code itself.
Table 1.3 lists the comparative amount of effort that’s typically expended on each
development and design step in large commercial programming projects. As this listing
shows, coding is not the major effort in Phase I. Many new programmers have trouble
because they spend the majority of their time writing the program and don’t spend enough
time understanding the problem or designing an appropriate solution. To help you avoid
making the same mistake, remember the programming proverb, “It is impossible to write a
successful program for a problem or application that’s not fully understood.” An equally
valuable proverb is, “The sooner you start coding a program, the longer it usually takes to
complete.”
Table 1.3 Effort Expended in Phase I
Step Effort
Analyze the problem 10%
Develop a solution 20%
Code the solution (write the program) 20%
Test the program 50%
Phase II: Documentation
Because of inadequate documentation, so much work becomes useless or lost and many tasks
must be repeated, so documenting your work is one of the most important steps in problem
solving. Many critical documents are created during the analysis, design, coding, and testing
steps. Completing the documentation phase requires collecting these documents, adding
user-operating material, and presenting documentation in a form that’s most useful to you and
your organization.
Although not everybody classifies them in the same way, there are five main documents
for every problem solution:
• Program description
• Algorithm development and changes
• Well-commented program listing
• Sample test runs
• Users’ manual
Putting yourself in the shoes of a person who might use your work—anyone from
secretaries to programmers/analysts and management—should help you strive to make the
content of important documentation clear. The documentation phase formally begins in the
development and design phase and continues into the maintenance phase.
Phase III: Maintenance
This phase is concerned with the ongoing correction of problems, revisions to meet changing
needs, and addition of new features. Maintenance is often the major effort, the primary
source of revenue, and the longest lasting of the engineering phases. Development might
take days or months, but maintenance could continue for years or decades. The better the
documentation is, the more efficiently maintenance can be performed, and the happier
customers and end users will be.
19
Chapter 1
Preliminary Three: Software Development
Backup
Although not part of the formal design process, making and keeping backup copies of the
program at each step of the programming and debugging process are critical. Deleting or
changing a program’s current working version beyond recognition is all too easy. With backup
copies, you can recover the last stage of work with little effort. The final working version of
a useful program should be backed up at least twice. In this regard, another useful
programming proverb is, “Backup is unimportant if you don’t mind starting over again.”
Many organizations keep at least one backup on site, where it can be retrieved easily, and
another backup copy in a fireproof safe or at a remote location.
EXERCISES 1.3
Note: In each of these exercises, a programming problem is given. Read the problem statement first,
and then answer the questions pertaining to the problem. Do not attempt to write a program to
solve the problems. Instead, simply answer the questions following the program specifications.
N
O
T
E
1. (Electrical Eng.) You’ve been asked to write a C++ program to calculate the total resistance
of a series circuit. In this circuit, the total resistance is the sum of all individual resistance
values. The circuit consists of a number of 56-ohm, 33-ohm, and 15-ohm resistors.
a. For this programming problem, how many outputs are required?
b. How many inputs does this problem have?
c. Determine a formula for converting input items into output items. The number of
56-ohm resistors is m, the number of 33-ohm resistors is n, and the number of 15-ohm
resistors is p.
d. Test the formula written for Exercise 1c, using the following sample data: m = 17,
n = 24, and p = 12.
2. (Physics) You’ve been asked to write a program to calculate the value of distance, in
miles, given this relationship:
distance = rate × elapsed time
a. For this programming problem, how many outputs are required?
b. How many inputs does this problem have?
c. Determine a formula for converting input items into output items.
d. Test the formula written for Exercise 2c, using the following sample data: rate is 55
miles per hour and elapsed time is 2.5 hours.
e. How must the formula you determined in Exercise 2c be modified if the elapsed time
is given in minutes instead of hours?
20 Preliminaries
3. (Electrical Eng.) You’ve been asked to write a program that outputs the following
specifications:
Voltage amplification: 35
Power output: 2.5 Watts
Bandwidth: 15 KHz
a. For this programming problem, how many lines of output are required?
b. How many inputs does this problem have?
c. Determine a formula for converting input items into output items.
4. (Physics) You’ve been asked to write a C++ program to determine how far a car has traveled
after 10 seconds, assuming the car is initially traveling at 60 mph and the driver applies the
brakes to decelerate at a uniform rate of 12 mi/sec2
. Use the following formula:
distance = st - (1/2)dt2
s is the initial speed of the car.
d is the deceleration.
t is the elapsed time.
a. For this programming problem, how many outputs are required?
b. How many inputs does this problem have?
c. Determine a formula for converting input items into output items.
d. Test the formula written for Exercise 4c, using the data given in the problem.
5. (General Math) Consider the following programming problem: In 1627, Manhattan
Island was sold to Dutch settlers for $24. If the proceeds of that sale had been deposited
in a Dutch bank paying 5% interest, compounded annually, what would the principal bal-
ance be at the end of 2002? The following display is required: “Balance as of December
31, 2002 is: xxxxxx”; xxxxxx is the amount calculated by your program.
a. For this programming problem, how many outputs are required?
b. How many inputs does this problem have?
c. Determine a formula for converting input items into output items.
d. Test the formula written for Exercise 5c, using the data given in the problem statement.
6. (Electrical Eng.) You’ve been asked to write a program that calculates and displays the
output voltages of two electrical circuits and the sum of the two voltages. The output
voltage for the first circuit is given by this formula:
150
0 38
V
f
.
The output voltage for the second circuit is given by this formula:
230
56 0 98
2 2
V
f
+ ( . )
V is the input voltage to the circuit.
f is the frequency in Hertz.
21
Chapter 1
Preliminary Three: Software Development
a. For this programming problem, how many outputs are required?
b. How many inputs does this problem have?
c. Determine a formula for converting input items into output items.
d. Test the formula written for Exercise 6c, using the following sample data: The first
circuit is operated with an input voltage of 1.2 volts at a frequency of 144 Hertz, and
the second circuit is operated with an input voltage of 2.3 volts at 100 Hertz.
7. (Statistics) Consider the following programming problem: This is the formula for the
standard normal deviate, z, used in statistical applications:
z = (X - µ)/␴
X is a single value.
µ refers to an average value.
␴ refers to a standard deviation.
Using this formula, you need to write a program that calculates and displays the value of
the standard normal deviate when X = 85.3, µ = 80, and ␴ = 4.
a. For this programming problem, how many outputs are required?
b. How many inputs does this problem have?
c. Determine a formula for converting input items into output items.
d. Test the formula written for Exercise 7c, using the data given in the problem.
8. (Electrical Eng.) Read the following problem statement: The electrical resistance, r, of a
metal wire, in ohms, is given by this formula:
r
ml
a
=
m is the resistivity of the metal.
l is the length of the wire in feet.
a is the cross-sectional area of the wire in circular mils.
Using this information, you need to write a C++ program to calculate the resistance of a
wire that’s 125 feet long, has a cross-sectional area of 500 circular mils, and is copper. The
resistivity of copper, m, is 10.4.
a. Determine the outputs required of the program.
b. What inputs does the program require?
c. What is the formula for obtaining the outputs from the inputs?
1.4 Preliminary Four: Algorithms
Before a program is written, the programmer must clearly understand what data are to be
used, the desired result, and the procedure used to produce this result. As mentioned
previously, the procedure, or solution, selected is referred to as an algorithm. More precisely,
an algorithm is defined as a step-by-step sequence of instructions that must terminate and
that describe how the data is to be processed to produce the desired outputs. In essence, an
algorithm answers the question “What method will you use to solve this problem?”
22 Preliminaries
Only after you clearly understand the data you’ll be using and select an algorithm (the
specific steps required to produce the desired result) can you code the program. Seen in this
light, programming is the translation of a selected algorithm into a language the computer
can use.
To understand how an algorithm works, consider a simple problem: A program must
calculate the sum of all whole numbers from 1 through 100. Figure 1.5 illustrates three
methods you could use to find the required sum. Each method constitutes an algorithm.
Clearly, most people wouldn’t bother to list the possible alternatives in a detailed step-by-
step manner, as shown in Figure 1.5, and then select one of the algorithms to solve the problem.
Most people, however, don’t think algorithmically; they tend to think heuristically. For example,
Method 1 - Columns: Arrange the numbers from 1 to 100 in a column and add
them
1
2
3
4
.
.
.
98
99
+100
5050
Method 2 - Groups: Arrange the numbers in groups that sum to 101 and multiply
the number of groups by 101
1 + 100=101
2 + 99=101
3 + 98=101
4 + 97=101
49 + 52=101
50 + 51=101
.
.
50 groups
(50 x 101=5050)
Method 3 - Formula: Use the formula
n= number of terms to added (100)
a= first number to be added (1)
b= last number to be added (100)
n(a + b)
2
sum =
.
.
= 5050
100(1 + 100)
2
sum =
where
Figure 1.5 Summing the numbers 1 through 100
23
Chapter 1
Preliminary Four: Algorithms
if you have to change a flat tire on your car, you don’t think of all the steps required—you simply
change the tire or call someone else to do the job. This is an example of heuristic thinking.
Unfortunately, computers don’t respond to heuristic commands. A general statement
such as “add the numbers from 1 to 100” means nothing to a computer because it can
respond only to algorithmic commands written in a language it understands, such as C++. To
program a computer successfully, you must understand this difference between algorithmic
and heuristic commands. A computer is an “algorithm-responding” machine; it’s not an
“heuristic-responding” machine. You can’t tell a computer to change a tire or to add the
numbers from 1 through 100. Instead, you must give the computer a detailed, step-by-step
set of instructions that collectively form an algorithm. For example, the following set of
instructions forms a detailed method, or algorithm, for determining the sum of the numbers
from 1 through 100:
Set n equal to 100
Set a = 1
Set b equal to 100
Calculate sum = n(a + b)/2
Print the sum
These instructions are not a computer program. Unlike a program, which must be written in
a language the computer can respond to, an algorithm can be written or described in various
ways. When English-like phrases are used to describe the steps in an algorithm, as in this
example, the description is called pseudocode. When mathematical equations are used, the
description is called a formula. When diagrams with the symbols shown in Figure 1.6 are
used, the description is referred to as a flowchart. Figure 1.7 illustrates using these symbols
to depict an algorithm for determining the average of three numbers.
24 Preliminaries
Terminal
Input/output
Process
Flow lines
Decision
Loop
Predefined process
Connector
Report
Indicates the beginning or end of a program
Indicates an input or output operation
Indicates computation or data manipulation
Used to connect the other flowchart symbols
and indicate the logic flow
Indicates a program branch point
Indicates the initial, limit, and increment
values of a loop
Indicates a predefined process, as in calling
a function
Indicates an entry to, or exit from, another
part of the flowchart or a connection point
Indicates a written output report
Symbol Name Description
Figure 1.6 Flowchart symbols
25
Chapter 1
Preliminary Four: Algorithms
Because flowcharts are cumbersome to revise and can support unstructured programming
practices easily, they have fallen out of favor by professional programmers. Using pseudocode
to express the logic of algorithms has gained increasing acceptance. Short English phrases are
used to describe an algorithm with pseudocode. Here’s an example of acceptable pseudocode
for describing the steps to compute the average of three numbers:
Input the three numbers into the computer’s memory
Calculate the average by adding the numbers and dividing the sum by three
Display the average
As stated previously, before you can write an algorithm by using computer-language
statements, you must select an algorithm and understand the required steps. Writing an
algorithm by using computer-language statements is called coding the algorithm, which is the
third step in the program development procedure shown in Figure 1.8. Most of Part One of
this book is devoted to showing you how to develop and code algorithms into C++.
Start
Input
three
values
Calculate
the
average
Display
the
average
End
Figure 1.7 Flowchart for calculating the average of three numbers
Requirements
Select an
algorithm
(step-by-step
procedure)
Translate the
algorithm
into C++
(coding)
Figure 1.8 Coding an algorithm
26 Preliminaries
EXERCISES 1.4
Note: There’s no one correct answer for each task. This exercise is designed is to give you practice
in converting heuristic commands into equivalent algorithms and making the shift between the
processes involved in these two types of thinking.
N
O
T
E
1. (Practice) Determine a step-by-step procedure (list the steps) to do the following tasks:
a. Fix a flat tire.
b. Make a telephone call.
c. Log on to a computer.
d. Roast a turkey.
2. (Practice) Are the procedures you developed for Exercise 1 algorithms? Discuss why or
why not.
3. (Practice) Determine and write an algorithm (list the steps) to interchange the contents
of two cups of liquid. Assume that a third cup is available to hold the contents of either
cup temporarily. Each cup should be rinsed before any new liquid is poured into it.
4. (Electrical Eng.) Write a detailed set of instructions in English to calculate the resis-
tance of the following resistors connected in series: n resistors, each having a resistance of
56 ohms; m resistors, each having a resistance of 33 ohms; and p resistors, each having a
resistance of 15 ohms. Note that the total resistance of resistors connected in series is the
sum of all individual resistances.
5. (Numerical) Write a set of detailed, step-by-step instructions in English to find the
smallest number in a group of three integer numbers.
6. (Numerical) a. Write a set of detailed, step-by-step instructions in English to calculate
the fewest number of dollar bills needed to pay a bill of amount TOTAL. For example,
if TOTAL is $97, the bills would consist of one $50 bill, two $20 bills, one $5 bill, and
two $1 bills. (For this exercise, assume that only $100, $50, $20, $10, $5, and $1 bills are
available.)
b. Repeat Exercise 6a, but assume the bill is to be paid only in $1 bills.
7. (Data Processing) a. Write an algorithm to locate the first occurrence of the name
JEAN in a list of names arranged in random order.
b. Discuss how you could improve your algorithm for Exercise 7a if the list of names
were arranged in alphabetical order.
8. (Data Processing) Determine and write an algorithm to determine the total occurrences
of the letter e in any sentence.
9. (Numerical) Determine and write an algorithm to sort four numbers into ascending
(from lowest to highest) order.
27
Chapter 1
Preliminary Four: Algorithms
1.5 A Closer Look: Software, Hardware, and Computer
Storage3
The process of writing a program, or software, is called programming, and the set of
instructions used to construct a program is called a programming language. Programming
languages come in a variety of forms and types.
Machine Language
At their most fundamental level, the only programs that can actually be used to operate a
computer are machine-language programs. These programs, also referred to as executable
programs (executables, for short), consist of a sequence of instructions composed of binary
numbers, such as:4
11000000 000000000001 000000000010
11110000 000000000010 000000000011
Machine-language instructions consist of two parts: an instruction and an address. The
instruction part, referred to as the opcode (short for operation code), is usually the leftmost set of
bits and tells the computer the operation to be performed, such as add, subtract, multiply, and
so on. The rightmost bits specify the memory addresses of the data to be used. For example,
assume that the eight leftmost bits of the first instruction contain the opcode to add, and the next
two groups of 12 bits are the addresses of the two operands to be added. This instruction would
be a command to “add the data in memory location 1 to the data in memory location 2.”
Similarly, assuming that the opcode 11110000 means multiply, the next instruction is a command
to “multiply the data in memory location 2 by the data in location 3.”
Assembly Languages
Because each class of computers—such as IBM, Apple, and Hewlett-Packard—has its own
particular machine language, writing machine-language programs is tedious and time
consuming.5 One of the first advances in programming was substituting word-like symbols,
such as ADD, SUB, and MUL, for binary opcodes and using decimal numbers and labels for
memory addresses. Using these symbols and decimal values for memory addresses, the
previous two machine-language instructions can now be written as follows:
ADD 1, 2
MUL 2, 3
Programming languages using this type of symbolic notation are referred to as assembly
languages. Because computers can execute only machine-language programs, the instructions
in an assembly-language program must be translated into a machine-language program before
they can be executed on a computer (see Figure 1.9). Translator programs that perform this
function for assembly-language programs are known as assemblers.
3
This topic can be omitted on first reading without loss of subject continuity.
4
Converting binary to decimal numbers is explained at the end of this section.
5
In actuality, the machine-level language is defined for the processor around which the computer is constructed.
28 Preliminaries
Low- and High-Level Languages
Both machine-level and assembly languages are classified as low-level languages because they
use instructions that are tied to one type of computer. Therefore, an assembly-language
program is limited to being used only with the specific computer type for which it’s written.
These programs do, however, permit using special features of a particular computer type and
generally execute at the fastest level possible.
In contrast, a high-level language uses instructions resembling written languages, such as
English, and can be run on a variety of computer types. Visual Basic, C, C++, and Java are
examples of high-level languages. Using C++, an instruction to add two numbers and
multiply the sum by a third number can be written as follows:
result = (first + second) * third;
Programs written in a computer language (high- or low-level) are referred to as both
source programs and source code. Like a low-level assembly program, after a program is
written in a high-level language, it must be translated into the machine language of the
computer on which it will run. This translation can be done in two ways.
When each statement in a high-level source program is translated separately and
executed immediately after translation, the programming language is called an interpreted
language, and the program doing the translation is an interpreter.
When all statements in a high-level source program are translated as a complete unit
before any statement is executed, the programming language is called a compiled language.
In this case, the program doing the translation is a compiler. Both compiled and interpreted
versions of a language can exist, although one typically predominates. C++ is predominantly
a compiled language.
Figure 1.10 illustrates the relationship between a C++ source program and its compilation
into a machine-language executable program. As shown, the source program is entered by
using an editor program, which is a word-processing program that’s part of the development
environment the compiler supplies. Remember, however, that you can begin entering code
only after you have analyzed an application and planned the program’s design carefully.
Translating the C++ source program into a machine-language program begins with the
compiler. The output the compiler produces is called an object program, which is a
machine-language version of the source code. Source code almost always makes use of
existing preprogrammed code—code you have written previously or code the compiler
provides, such as mathematical code for finding a square root. Additionally, a large C++
program might be stored in two or more separate program files. Any additional code must be
combined with the object program before the program can be executed. It’s the task of the
linker to perform this step. The result of the linking process is a machine-language
(executable) program that contains all the code your program requires and is ready for
execution. The last step in the process is to load the machine-language program into the
computer’s main memory for actual execution.
An assembly-
language
program
Translation
program
(assembler)
A machine-
language
program
Figure 1.9 Assembly-language programs must be translated
29
Chapter 1
A Closer Look: Software, Hardware,
and Computer Storage
Procedural and Object Orientations
In addition to being classified as high- or low-level, programming
languages are classified by orientation—procedural or object
oriented. In a procedural language, the instructions are used to create
self-contained units, referred to as procedures. The purpose of a
procedure is to accept data as input and transform the data in some
manner to produce a specific result as an output. Until the 1990s,
most high-level programming languages were procedural.
Currently, object orientation has taken center stage. One moti-
vation for object-oriented languages was the development of graphical
screens and support for graphical user interfaces (GUIs), capable of
displaying windows containing both graphical shapes and text. In a
GUI environment, each window can be considered an object with
associated characteristics, such as color, position, and size. In an
object-oriented approach, a program must first define the objects it’s
manipulating. This definition includes a description of the objects’
general characteristics, such as initial size, shape, and color. Addi-
tionally, specific code must be supplied to manipulate each object,
such as changing its size and position, and transferring data between
objects. Object-oriented languages have also become more promi-
nent because they support reusing existing code more easily, which
removes the need to revalidate and retest new or modified code.
C++, which is classified as an object-oriented language, contains
features of both procedural and object-oriented languages. In this
book, you design and develop both types of code, which is how most
current C++ programs are written. Because object-oriented C++ code
always contains some procedural code, and many simple C++ pro-
grams are written entirely in procedural code, this type of code is
presented in Part One of this book.
Application and System Software
Two logical categories of computer programs are application software
and system software. Application software consists of programs writ-
ten to perform particular tasks that users require. All the programs in
this book are examples of application software.
System software is the collection of programs that must be
readily available to any computer system for it to operate. In the
computer environments of the 1950s and 1960s, users had to load system software by hand
to prepare the computer to do anything at all. This software was loaded by using rows of
switches on a front panel, and the commands entered by hand were said to “boot” the
computer, an expression derived from “pulling yourself up by your bootstraps.” Today, the
so-called bootstrap loader is a permanent, automatically executed component of a computer’s
system software.
Collectively, the set of system programs used to operate and control a computer is called
the operating system (OS). Tasks handled by modern OSs include memory management;
allocation of CPU time; control of input and output units, such as keyboards, screens, and
printers; and management of secondary storage devices. Many OSs handle large programs as
well as multiple users concurrently by dividing programs into segments that are moved
An
executable
program
Other
object
files
(library)
Linker
The
C++
object
program
Compiler
Editor
Type in
the C++ program
The
C++
source
program
Figure 1.10 Creating an
executable C++ program
30 Preliminaries
between the disk and memory as needed. With these OSs, referred to as multiuser systems,
more than one user can run a program on the computer. Additionally, many OSs, including
most windowed environments, enable each user to run multiple programs and are called
multiprogrammed and multitasking systems.
The Development of C++
The purpose of most application programs is to process data to produce specific results. In
a procedural language, a program is constructed from sets of instructions, with each set
referred to as a procedure, as noted previously. Each procedure moves the data one step
closer to the final desired output along the path shown in Figure 1.11.
The programming process in Figure 1.11 mirrors
the input, processing, and output hardware units used
to construct a computer (discussed later in “Computer
Hardware”). This mirroring isn’t accidental because
early programming languages were designed to match
and to control corresponding hardware units.
The first procedural language, FORTRAN
(derived from FORmula TRANslation), was intro-
duced in 1957 and remained popular until the early
1970s. FORTRAN has algebra-like instructions that concentrate on the processing phase
shown in Figure 1.11. It was developed for scientific and engineering applications that
required high-precision numerical outputs, accurate to many decimal places. For example,
calculating a rocket’s trajectory or the bacterial concentration level in a polluted pond, as
illustrated in Figure 1.12, requires evaluating a mathematical equation to a high degree of
numerical accuracy and is typical of FORTRAN-based applications.
The next important high-level application language was COBOL (COmmon Business-
Oriented Language), which was introduced in the 1960s and remained a major procedural
language throughout the 1980s. This language had features geared toward business applica-
tions, which required simpler mathematical calculations than those for engineering
applications. One of COBOL’s main benefits was providing extensive output formats that
made it easy to create reports containing columns of neatly formatted monetary amounts, as
Process
the
data
Input
data
Output
results
Figure 1.11 Basic procedural
operations
Time
Bacteria growth
in a polluted pond
Concentration
level
Figure 1.12 FORTRAN was developed for scientific and engineering applications
31
Chapter 1
A Closer Look: Software, Hardware,
and Computer Storage
illustrated in Figure 1.13. It forced programmers to construct well-defined, structured
procedures that followed a more consistent pattern than was required in FORTRAN.
Another language, BASIC (Beginners All-purpose Symbolic Instruction Code), was
developed at Dartmouth College in the 1960s. BASIC was a scaled-down version of
FORTRAN intended as an introductory language for college students. It was a fairly
straightforward, easy-to-understand language that didn’t require detailed knowledge of a
specific application. Its main drawback was that it didn’t require or enforce a consistent,
structured approach to creating programs.
To remedy this drawback and make understanding and reusing code easier, the Pascal
language (named after the 17th-century mathematician Blaise Pascal) was developed in 1971.
It gave students a firmer foundation in structured programming design than early versions of
BASIC did.
Structured programs are created by using a set of well-defined structures organized into
separate programming sections. Each section performs a specific task that can be tested and
modified without disturbing other program sections. The Pascal language was so rigidly
structured, however, that escapes from the structured sections didn’t exist, even when
escapes would be useful. This limitation was unacceptable for many real-world projects and
is one of the reasons Pascal didn’t become widely accepted in scientific and engineering
fields. Instead, the C language became the dominant engineering applications language of
the 1980s. Ken Thompson, Dennis Ritchie, and Brian Kernighan of AT&T Bell Laboratories
developed this structured, procedural language in the 1970s. C’s extensive capabilities allow
writing programs in a high-level language yet still accessing a computer’s machine-level
features directly.
Finally, C++ was developed in the early 1980s, when Bjarne Stroustrup (also at AT&T)
used his simulation language background to create an object-oriented programming language.
A central feature of simulation languages is that they model real-life situations as objects.
This object orientation, which was ideal for graphical screen objects such as rectangles,
circles, and windows, was combined with existing C features to form the C++ language.
Therefore, C++ retained the extensive structured and procedural capabilities of C but added
its object orientation to become a true general-purpose programming language. C++ can be
used for everything from simple, interactive programs to sophisticated, complex engineering
and scientific programs, within the context of a truly object-oriented structure.
Part No. Description Quantity Price
12225 #4 Nails, Common 25 boxes 1.09
12226 #6 Nails, Common 30 boxes 1.09
12227 #8 Nails, Common 65 boxes 1.29
12228 #10 Nails, Common 57 boxes 1.35
12229 #12 Nails, Common 42 boxes 1.09
12230 #16 Nails, Common 25 boxes 1.09
Figure 1.13 COBOL was developed for business applications
32 Preliminaries
Computer Hardware
All computers, from large supercomputers to desktop PCs, must be capable of at least the
following:
• Accepting input
• Displaying output
• Storing information in a logical, consistent format (traditionally binary)
• Performing arithmetic and logic operations on input or stored data
• Monitoring, controlling, and directing the computer’s overall operation and sequencing
Figure 1.14 illustrates the computer components that support these capabilities and
collectively form a computer’s hardware.
The arithmetic and logic unit (ALU) performs all arithmetic and logic functions, such as
addition and subtraction.
The control unit directs and monitors the computer’s overall operation. It keeps track of
the next instruction’s location in memory, issues the signals for reading data from and writing
data to other units, and controls execution of all instructions.
The memory unit stores information in a logical, consistent format. Typically, both
instructions and data are stored in memory, usually in separate areas.
The input and output (I/O) units provide the interface where peripheral devices, such as
keyboards, monitors, printers, and card readers, are attached.
Because memory in very large quantities is still expensive and volatile (meaning the
information is lost when power is turned off), it’s not practical as a permanent storage area for
programs and data. Secondary (or auxiliary) storage is used for this purpose. Media such as
punched cards were used in the past, but secondary storage is now on magnetic tape,
magnetic disks, USB/flash drives, and CDs/DVDs.
In the first commercially available computers of the 1950s, hardware units were built by
using relays and vacuum tubes. These computers were enormous pieces of equipment
capable of thousands of calculations per second and cost millions of dollars.
Arithmetic
and
logic unit
(ALU)
Output
Input
Memory
Secondary
storage
Control
Central processing unit
(CPU)
Figure 1.14 Basic hardware units of a computer
33
Chapter 1
A Closer Look: Software, Hardware,
and Computer Storage
The introduction of transistors in the 1960s reduced the size and cost of computer
hardware. The transistor’s small size—about one-twentieth the size of vacuum tubes—
allowed manufacturers to combine the ALU with the control unit into a single unit called the
central processing unit (CPU). Combining the ALU and control unit made sense because most
control signals that a program generates are directed to the ALU in response to arithmetic
and logic instructions in the program. Combining the ALU with the control unit also
simplified the interface between these two units and improved processing speed.
Integrated circuits (ICs) were introduced in the mid-1960s, which resulted in another
major reduction in the space required to produce a CPU. Initially, ICs were manufactured
with up to 100 transistors on a single square-centimeter chip of silicon and were called
small-scale integrated (SSI) circuits. Current versions of these chips, called very large-scale
integrated (VLSI) chips, can contain more than a million transistors. With VLSI chip
technology, the giant computers of the 1950s could be transformed into today’s desktop and
notebook PCs. Each unit required to form a computer (CPU, memory, and I/O) is now
manufactured on a single VLSI chip, and a single-chip CPU is referred to as a microprocessor.
Figure 1.15 illustrates how these chips are connected internally in current desktop PCs.
Concurrent with the remarkable reduction in hardware size has been a dramatic decrease
in cost and increase in processing speeds. Computer hardware that cost more than a million
dollars in 1950 can now be purchased for less than $100. If the same reductions occurred in
the automobile industry, for example, a Rolls Royce could now be purchased for $10!
Similarly, current computers’ processing speeds have increased by a factor of thousands over
their 1950s predecessors, with computational speeds now being measured in millions of
instructions per second (MIPS) and billions of instructions per second (BIPS).
Computer Storage
The physical components used in manufacturing a computer preclude using the same
symbols people use for numbers and letters. For example, the number 126 isn’t stored with
the symbols 1, 2, and 6, nor is the letter you recognize as an A stored with this symbol. In
this section, you see why and learn how computers store numbers. In Chapter 2, you see how
letters are stored.
Microprocessor
(CPU) Memory Input Output
Figure 1.15 VLSI chip connections for a desktop PC
34 Preliminaries
The smallest and most basic data item in a computer is called a bit. Physically, a bit is
actually a switch that can be open or closed. The convention followed in this book is that the
open position is represented as a 0, and the closed position is represented as a 1.6
A single bit that can represent the values 0 and 1 has limited usefulness. All computers,
therefore, group a set number of bits together for storage and transmission. Grouping 8 bits
to form a larger unit, called a byte, is an almost universal computer standard. A single byte
consisting of 8 bits, with each bit being a 0 or 1, can represent any one of 256 distinct
patterns. These patterns consist of 00000000 (all eight switches open) to 11111111 (all eight
switches closed) and all possible combinations of 0s and 1s in between. Each pattern can be
used to represent a letter of the alphabet, a character (such as a dollar sign or comma), a single
digit, or a number containing more than one digit. The collection of patterns used to
represent letters, single digits, and other characters is called a character code. (One character
code, called ASCII, is discussed in Section 2.1.) The patterns used to store numbers are
called number codes, one of which is explained in the next section.
Twos Complement Numbers The most common number code for storing integer values
in a computer is called the twos complement representation. Using this code, the integer
equivalent of any bit pattern, such as 10001101, is easy to determine and can be found for
positive or negative integers with no change in the conversion method. For convenience,
assume byte-sized bit patterns consisting of 8 bits each, although the procedure carries over
to larger bit patterns.
The easiest way to determine the integer each bit pattern represents is to construct a simple
device called a value box. Figure 1.16 shows a value box for a single byte. Mathematically, each
value in this box represents an increasing power of two. Because twos complement numbers
must be capable of representing both positive and negative integers, the leftmost position, in
addition to having the largest absolute magnitude, has a negative sign.
To convert any binary number, such as 10001101, simply insert the bit pattern into the
value box and add the values having 1s under them. Therefore, as illustrated in Figure 1.17,
the bit pattern 10001101 represents the integer number -115.
The value box can also be used in reverse to convert a base 10 integer number into its
equivalent binary bit pattern. Some conversions, in fact, can be made by inspection. For
6
This convention, unfortunately, is rather arbitrary, and you often encounter the reverse, in which the open and closed positions are represented
as 1 and 0, respectively.
-128|ƒ64ƒ|ƒ32ƒ|ƒ16ƒ|ƒƒ8ƒ|ƒƒ4ƒ|ƒƒ2ƒ|ƒƒ1
----|----|----|----|----|----|----|---
ƒ |ƒƒƒƒ|ƒƒƒƒ|ƒƒƒƒ|ƒƒƒƒ|ƒƒƒƒ|ƒƒƒƒ|
Figure 1.16 An 8-bit value box
-128ƒ|ƒ64ƒ|ƒ32ƒ|ƒ16ƒ|ƒƒ8ƒ|ƒƒ4ƒ|ƒƒ2ƒ|ƒƒ1
ƒ----|----|----|----|----|----|----|---
ƒ1ƒ|ƒƒ0ƒ|ƒƒ0ƒ|ƒƒ0ƒ|ƒƒ1ƒ|ƒƒ1ƒ|ƒƒ0ƒ|ƒƒ1
-128ƒ+ƒƒ0ƒ+ƒƒ0ƒ+ƒƒ0ƒ+ƒƒ8ƒ+ƒƒ4ƒ+ƒƒ0ƒ+ƒƒ1ƒ=ƒ-115
Figure 1.17 Converting 10001101 to a base 10 number.
35
Chapter 1
A Closer Look: Software, Hardware,
and Computer Storage
example, the base 10 number -125 is obtained by adding 3 to -128. Therefore, the binary
representation of -125 is 10000011, which equals -128 + 2 + 1. Similarly, the twos complement
representation of the number 40 is 00101000, which is 32 + 8.
Although the value box conversion method is deceptively simple, it’s related to the
underlying mathematical basis of twos complement binary numbers. The original name of
the twos complement code was the weighted-sign code, which correlates to the value box. As
the name “weighted sign” implies, each bit position has a weight, or value, of two raised to
a power and a sign. The signs of all bits except the leftmost bit are positive, and the sign of
the leftmost bit is negative.
In reviewing the value box, you can see that any twos complement binary number with
a leading 1 represents a negative number, and any bit pattern with a leading 0 represents a
positive number. Using the value box, it’s easy to determine the most positive and negative
values capable of being stored. The most negative value that can be stored in a single byte
is the decimal number -128, which has the bit pattern 10000000. Any other non-zero bit
simply adds a positive amount to the number. Additionally, a positive number must have a
0 as its leftmost bit. From this, you can see that the largest positive 8-bit twos complement
number is 01111111, or 127.
Words and Addresses One or more bytes can be grouped into larger units, called words,
to facilitate faster and more extensive data access. For example, retrieving a word consisting
of 4 bytes from a computer’s memory results in more information than retrieving a word of
a single byte. This type of retrieval is also faster than four separate 1-byte retrievals.
Achieving this increase in speed and capacity, however, requires increasing the computer’s
cost and complexity.
Early personal computers, such as the Apple IIe and Commodore, stored and transmitted
words consisting of single bytes. The first IBM PCs used word sizes of 2 bytes, and more
current PCs store and process words of 4 to 16 bytes each.
The number of bytes in a word determines the maximum and minimum values the word
can represent. Table 1.4 lists these values for 1-, 2-, and 4-byte words (derived by using 8-,
16-, and 32-bit value boxes, respectively).
Table 1.4 Word Size and Integer Values
Word Size Maximum Integer Value Minimum Integer Value
1 byte 127 -128
2 bytes 32,767 -32,768
4 bytes 2,147,483,647 -2,147,483,648
In addition to representing integer values, computers must also store and transmit numbers
containing decimal points, which are mathematically referred to as real numbers. The codes for
real numbers, which are more complex than those for integers, are in Appendix C.
36 Preliminaries
1.6 Common Programming Errors
The most common errors associated with the material in this chapter are as follows:
1. Forgetting to check that all units for numerical values used in a calculation are
consistent.
2. Using an incorrect form of a conversion factor.
3. Rushing to write and run a program before fully understanding what’s required,
including the algorithms used to produce the required result. A symptom of this
haste to get a program entered into the computer is the lack of any documentation,
even a program outline or a written program. Many problems can be caught by
checking a written copy of the program or even checking a description of the
algorithm written in pseudocode.
4. Not backing up a program. Almost all new programmers make this mistake until they
lose a program that has taken considerable time to code.
5. Not understanding that computers respond only to explicitly defined algorithms.
Telling a computer to add a group of numbers is quite different from telling a friend
to add the numbers. The computer must be given precise instructions in a
programming language to perform the addition.
1.7 Chapter Summary
1. For a calculation to produce a correct and useful numerical value, the units corresponding
to the numerical value must also be correct.
2. To determine correct forms of a conversion factor, perform a unit analysis. This means
multiplying, dividing, and canceling units in the same manner as numerical values are
processed.
3. The programs used to operate a computer are also referred to as software.
4. A computer program is a self-contained unit of instructions and data used to operate a
computer to produce a specific result.
5. As a discipline, software engineering is concerned with creating readable, efficient,
reliable, and maintainable programs and systems.
6. The software development procedure consists of three phases: program development
and design, documentation, and maintenance.
7. The program development and design phase consists of four well-defined steps:
• Analyze the problem.
• Develop a solution.
• Code the solution (write the program).
• Test and correct the solution.
8. An algorithm is a step-by-step procedure that must terminate; it describes how a
computation or task is to be performed.
37
Chapter 1
Chapter Summary
9. The four control structures used in coding a program are sequence, selection, iteration,
and invocation.
Preprogramming Projects for Chapter 1
1. (General Math) The volume of a sphere can be determined by using this formula:
V r
= 4 3 3
π
V is the volume of the sphere.
π is the dimensionless number (no units) having the value 3.1416, accurate to four
decimal places.
r is the radius in centimeters (cm) of the sphere.
a. Determine the units of V by calculating the units resulting from the right side of the
formula. Check that your answer corresponds to the units for work listed in Table 1.1.
b. Determine the volume of a sphere having a radius of 4 cm.
c. If you were required to write a computer program to determine the volume of a
sphere, what inputs, outputs, and algorithm would you use?
2. (Civil Eng.) The stress placed on the fixed end of a symmetrical steel I-beam, shown
in Figure 1.18, can be determined by this formula:
S
Ld c
I
=
S is the stress.
L is weight, in lbs, of the load placed on the beam.
I is the beam’s rectangular moment of inertia in units of in4
.
d is the distance, in inches, the load is placed from the fixed end of the beam
(technically referred to as the “moment arm”).
c is one half the height, in inches, of a symmetrical beam.
L
h
d
Figure 1.18 Determining the stress on an I-beam
38 Preliminaries
a. Determine the units of stress, S, by calculating the units resulting from the right side
of the formula.
b. For a steel beam having a rectangular moment of inertia of 21.4 in4
and a height of 6
inches, determine the stress for a load of 700 lbs placed 8 feet from the fixed end.
c. If you were required to write a computer program to determine the stress placed on
a symmetrical beam, what inputs, outputs, and algorithm would you use?
3. (Physics) Typically, most objects that radiate heat do so at many different wavelengths
(see the Technical Note in Section 3.5 for a description of wavelength). The wavelength
at which an object emits its maximum heat energy can be found by using Wein’s Law:
␭max = W/T
␭max is the maximum wavelength.
T is the object’s temperature in °K.
W is Wein’s constant (2897 microns/°K).
a. Determine the units of ␭max by calculating the units resulting from the right side of
the formula.
b. Determine the maximum heat-radiating wavelength for the sun, assuming a tempera-
ture of 6000°K.
c. If you were required to write a computer program to determine the heat radiated from
a planet, what inputs, outputs, and algorithm would you use?
4. (Physics) The energy, E, of a photon can be determined by using this formula:
E
h c
=
λ
E is the energy of the photon.
h is known as Planck’s constant and has the value 6.6256 × 10-34
Joules/sec.
c is the speed of light, which is 299,792,458 m/s.
␭ is the wavelength of the light in meters.
a. Determine the units of a photon’s energy, E, by calculating the units resulting from
the right side of the formula.
b. Determine the energy of violet light, which has a wavelength of 5.9 × 10-6
meters.
c. If you were required to write a computer program to determine the energy of a photon
of different light wavelengths (such as red, green, and so forth), what inputs, outputs,
and algorithm would you use?
5. (Eng. Mechanics) The minimum radius, r, required of a cylindrical rod, such as that
used on a bicycle pedal (see Figure 1.19), to provide enough support for the pressure
exerted by the rider’s foot, yet not exceed the stress placed on the crank arm’s sprocket
attachment, is determined by this formula:
r
d P
S
3
=
π
r is the radius of the cylindrical rod in inches.
39
Chapter 1
Preprogramming Projects
d is the length of the crank arm in inches.
P is the weight placed on the pedal in lbs.
S is the stress in lbs/in2
.
a. Determine the value of r for a crank arm that’s 7 inches long, must accommodate a
maximum weight of 300 lbs, and be able to sustain a stress of 10,000 lbs/in2
.
b. If you were asked to write a computer program to determine the radius of the
cylindrical rod for a bicycle’s crank arm, what inputs, outputs, and algorithm would
your program require?
6. (Heat Transfer) The following formula is used to determine the heat transferred
through a flat substance, such as a wall, with its two sides maintained at different
temperatures:
q k
T T
d
=






-
-
2 1
q is the heat transfer.
k is the thermal conductivity of the substance in Watts/m°C.
T2 is the higher temperature on one side of the substance in °C.
T1 is the lower temperature on the other side of the wall in °C.
d is the thickness of the substance in meters.
a. Determine the units of q by calculating the units resulting from the right side of the
formula.
b. For a glass window with a thickness of 0.5 centimeters, a thermal conductivity of 0.77
Watts/m°C, and outside and inside temperatures of 36.6°C and 22.2°C, respectively,
determine the value of q.
c. If you were asked to write a computer program to determine the heat transfer through
a substance, what inputs, outputs, and algorithm would your program require?
d
Figure 1.19 Determining the radius of a bicycle’s crank arm
40 Preliminaries
Engineering and Scientific Disciplines
Aeronautical/Aerospace Engineering
Among the youngest of the engineering fields, aeronautical/aerospace engineering is
concerned with all aspects of designing, producing, testing, and using vehicles or
devices that fly in air (aeronautical) or space (aerospace), from hang gliders to space
shuttles. Because the science and engineering principles involved are so broad,
aeroengineers usually specialize in a subarea that might overlap with other engineering
fields, such as mechanical, metallurgical/materials, chemical, civil, or electrical
engineering. These subareas include the following:
앫 Aerodynamics: The study of flight characteristics of various structures or
configurations. Typical considerations are the drag and lift associated with airplane
design or the onset of turbulent flow. A knowledge of fluid dynamics is essential.
Modeling and testing all forms of aircraft are part of this subarea.
앫 Structural design: Designing, producing, and testing aircraft and spacecraft to
withstand the wide range of in-flight demands on these vehicles, such as
underwater vessels, are in the structural engineer’s province.
앫 Propulsion systems: The design of internal combustion, jet, and liquid- and
solid-fuel rocket engines and their coordination in the vehicle’s overall design.
Rocket engines, especially, require innovative engineering to accommodate the
extreme temperatures of storing, mixing, and burning fuels such as liquid oxygen.
앫 Instrumentation and guidance: The aerospace industry has been a leader in
developing and using solid-state electronics in the form of microprocessors to
monitor and adjust the operations of hundreds of aircraft and spacecraft
functions. This field uses the expertise of both electrical engineers and
aeroengineers.
앫 Navigation: Computing orbits within and outside the atmosphere and determin-
ing the orientation of a vehicle with respect to points on Earth or in space.
41
Chapter 1
Preprogramming Projects
This page intentionally left blank
Chapter
2
Problem Solving
Using C++
2.1 Introduction to C++
2.2 Programming Style
2.3 Data Types
2.4 Arithmetic Operations
2.5 Variables and Declaration
Statements
2.6 A Case Study: Radar
Speed Traps
2.7 Common Programming Errors
2.8 Chapter Summary
An integral part of a building’s design is its structure, and the same is true for a program. Constructing
well-designed C++ programs depends on careful planning and execution, if the final design is to ensure
that the completed program accomplishes its intended purpose. A central element of this planning is
using modular program design, which is explained in Section 2.1. In this chapter, you also learn about
different types of data and how to process them in the context of a complete C++ program.
2.1 Introduction to C++
A well-designed program is constructed by using a design philosophy similar to one for
constructing a well-designed building. It doesn’t just happen; it depends on careful planning
and execution, if the final design is to accomplish its intended purpose.
As with buildings, an integral part of designing a program is its structure. Programs with
a structure consisting of interrelated segments (called modules), arranged in a logical, easily
understandable order to form an integrated and complete unit, are referred to as modular
programs (see Figure 2.1). Modular programs are easier to develop, correct, and modify than
programs constructed in some other manner.
Each module is designed and developed to perform a specific task and is actually a small
subprogram. A complete C++ program is constructed by combining as many modules as
necessary to produce the desired result. The advantage of modular construction is that you
can develop the program’s overall design before writing any modules. After finalizing
requirements for each module, you can then program the modules and integrate them into
the overall program as they’re completed.
In C++, modules can be classes or functions. It helps to think of a function as a small
machine that transforms the data it receives into a finished product. For example, Figure 2.2
illustrates a function that accepts two numbers as inputs and multiplies the two numbers to
produce one output. The process of converting inputs to results is encapsulated and hidden
in the function. In this regard, the function can be thought of as a single unit providing a
special-purpose operation.
Module 1
Module 2
Module 4
Module 3
Module 5 Module 6
Figure 2.1 A well-designed program is built by using modules
Result
(a x b)
First
number
Second
number
Figure 2.2 A multiplying function
44 Problem Solving Using C++
A similar analogy is suitable for a class, although it’s a more complicated unit because it
contains both data and functions for manipulating the data. Unlike a function, used to
encapsulate a set of operations, a class encapsulates both data and sets of operations. Each
class contains all the elements required for input, output, and processing its objects and can
be thought of as a small factory containing raw material (the data) and machines (the
functions). In the first part of this book, however, you’re focusing on the more basic function
module. Although you’ll also use capabilities provided by classes, it’s in Part Two that you
learn how to construct and program your own classes.
An important requirement for designing a good function is giving it a name that conveys
some idea of what the function does. The names allowed for functions are also used to name
other elements of the C++ language and are collectively referred to as identifiers. Identifiers
can be made up of any combination of letters, digits, or underscores (_) selected according
to the following rules:
1. The first character of the name must be a letter or an underscore.
2. Only letters, digits, or underscores can follow the first letter. Also, blank spaces aren’t
allowed to separate words in a function name; either use the underscore to separate
words, or capitalize the first letter of words after the first word.
3. A function name can’t be one of the keywords listed in Table 2.1. (A keyword is a
word the language sets aside for a special purpose and can be used only in a specified
manner.1)
4. The maximum number of characters in a function name is 1024.2
Table 2.1 Keywords in C++
auto delete goto public this
break do if register template
case double inline return typedef
catch else int short union
char enum long signed unsigned
class extern new sizeof virtual
const float overload static void
continue for private struct volatile
default friend protected switch while
Examples of valid C++ identifiers are the following:
degToRad intersect addNums slope
bessel1 multTwo findMax density
These are examples of invalid identifiers:
1AB3 Begins with a number, which violates rule 1.
E*6 Contains a special character, which violates rule 2.
while Consists of a keyword, which violates rule 3.
1
Keywords in C++ are also reserved words, which means they must be used only for their specified purpose. Attempting to use them for any
other purpose generates an error message.
2
The ANSI standard requires that C++ compilers provide at least this number of characters.
45
Chapter 2
Introduction to C++
In addition to conforming to C++’s identifier rules, a C++ function name must always be
followed by parentheses. Also, a good function name should be a mnemonic (pronounced
“knee-mon-ic”), which is a word designed as a memory aid. For example, the function name
degToRad() is a mnemonic for a function that converts degrees to radians. The name helps
identify what the function does. Function names that aren’t mnemonics should not be used
because they convey no information about what the function does. Here are some examples
of valid function names that aren’t mnemonics:
easy() c3po() r2d2() theForce() mike()
Function names can also consist of mixed uppercase and lowercase letters, as in
theForce(). This convention is becoming increasingly common in C++, although it’s not
necessary. Identifiers in all uppercase letters are usually reserved for symbolic constants,
covered in Section 3.5.
If you do mix uppercase and lowercase letters, be aware that C++ is a case-sensitive
language, meaning the compiler distinguishes between uppercase and lowercase letters.
Therefore, in C++, the names TOTAL, total, and TotaL are three different identifiers.
The main() Function
As mentioned, a distinct advantage of using functions—and, as you see in Part Two, classes—
is that you can plan the program’s overall structure in advance. You can also test and verify
each function’s operation separately to make sure it meets its objectives.
For functions to be placed and executed in an orderly fashion, each C++ program must have
one, and only one, function named main(). The main() function is referred to as a driver
function because it tells other functions the sequence in which they execute (see Figure 2.3).3
Figure 2.4 shows the main() function’s structure. The first line of the function—in this
case, int main()—is referred to as a function header. This line is always the first line of
a function and contains three pieces of information:
• What type of data, if any, is returned from the function
• The name of the function
• What type of data, if any, is sent to the function
The keyword before the function name defines the type of value the function returns
when it has finished operating. When placed before the function’s name, the keyword int
(listed in Table 2.1) means the function returns an integer value. Similarly, when the
parentheses following the function name are empty, no data is transmitted to the function
when it runs. (Data transmitted to a function at runtime is referred to as arguments of the
function.) The braces, { and }, determine the beginning and end of the function body and
enclose the statements making up the function. The statements inside the braces determine
what the function does, and each statement must end with a semicolon (;).
You’ll be naming and writing many of your own C++ functions. In fact, the rest of Part One
is primarily about the statements required to construct useful functions and how to combine
functions and data into useful classes and programs. Each program, however, must have one and
only one main() function. Until you learn how to pass data to a function and return data from
3
Functions executed from main() can, in turn, execute other functions. Each function, however, always returns to the function that initiated
its execution. This is true even for main(), which returns control to the operating system that was in effect when main() was initiated.
46 Problem Solving Using C++
a function (the topics of Chapter 6), the function header shown in Figure 2.4 serves for all the
programs you need to write. For simple programs, the first two lines
int main()
{
simply designate that “the program begins here,” and the last two lines
return 0;
}
designate the end of the program. Fortunately, many useful functions and classes have
already been written for you. Next, you see how to use an object created from one of these
classes to create your first working C++ program.
2nd
module
3rd
module
Last
module
main()
You go first
I’m done
You go second
I’m done
You go third
I’m done
You go last
I’m done
.
.
.
.
.
.
1st
module
Figure 2.3 The main() function directs all other functions
int main( )
{
program statements in here;
return 0;
}
The function body
Type of returned value
The function name An empty argument list
Figure 2.4 The structure of a main() function
47
Chapter 2
Introduction to C++
The cout Object
One of the most versatile and commonly used C++ resources is an object named cout
(pronounced “see out” and derived from console output).4 It’s an output object that sends data
it receives to the standard display device. For most systems, this display device is a computer
screen. For example, if the data Hello there world! is sent to cout, this data is
displayed on your screen. To send the data Hello there world! to the cout object,
enclose the text in quotation marks ("text in here") and place the insertion symbol, <<,
after the object’s name and before the message, as shown in this line:
cout << "Hello there world!";
Now you see how to put all this together into a working C++ program, Program 2.1, that
can be run on your computer.
Program 2.1
#include <iostream>
using namespace std;
int main()
{
cout << "Hello there world!";
return 0;
}
The first line of the program is a preprocessor command that uses the reserved word
include:
#include <iostream>
Preprocessor commands begin with a pound sign (#) and perform some action before the
compiler translates the source program into machine code. Specifically, the #include
preprocessor command causes the contents of the named file—in this case, iostream—to
be inserted wherever the #include command appears in the program. The iostream file
is part of the standard library that contains, among other code, two classes: istream and
ostream. These two classes provide data declarations and methods for data input and
output, respectively. The iostream file is called a header file because a reference to it is
always placed at the top, or head, of a C++ program by using the #include command. You
might be wondering what the iostream file has to do with this simple program. The answer
is that the cout object is created from the ostream class. Therefore, the iostream header
file must be included in all programs using cout. As shown in Program 2.1, preprocessor
commands don’t end with a semicolon.
4
The cout object is formally created for the ostream class, which is described in detail in Chapter 8.
48 Problem Solving Using C++
Following the preprocessor #include command is a statement containing the reserved
word using. The following statement, for example, tells the compiler where to look to find
header files in the absence of an explicit designation:
using namespace std;
You can think of a namespace as a section of source code the compiler accesses when it’s
looking for prewritten classes or functions. Because the iostream header file is contained
in a namespace named std (for the standard library), the compiler automatically uses
iostream’s cout object from this namespace whenever cout is referenced. By using
namespaces, you can create your own classes and functions with the same names the standard
library provides and place them in differently named namespaces. You can then tell the
program which class or function to use by specifying the namespace where you want the
compiler to look for the class or function. In Chapter 9, you learn how to create your own
namespaces. For now, you’ll use the classes and functions provided by the std namespace.
The using statement is followed by the start of the program’s main() function, which
begins with the function header described previously. The body of the function, enclosed in
braces, consists of only two statements. The first statement in main() sends one message
to the cout object: the string "Hello there world!".
Because cout is an object of a prewritten class, you don’t have to create it; it’s available
for use just by activating it correctly. Like all C++ objects, cout can perform only certain
well-defined actions. For cout, the action is to assemble data for output display. When a
string of characters is sent to cout, the object makes sure the string is displayed onscreen
correctly, as shown in this output from Program 2.1:
Hello there world!
Point of Information
What Is Syntax?
A programming language’s syntax is the set of rules for formulating statements that
are grammatically correct for the language. In practice, it means a C++ statement with
correct syntax has the proper form specified for the compiler. If statements are in the
proper form, the compiler accepts them and doesn’t generate an error message.
Note, however, that a statement or program can be syntactically correct yet logi-
cally incorrect. In other words, the statement or program is structured correctly but pro-
duces an incorrect result. It’s similar to an English statement that’s grammatically correct
but makes no sense, such as “The tree is a ragged cat.”
49
Chapter 2
Introduction to C++
Strings in C++ are any combination of letters, numbers, and special characters enclosed in
quotation marks ("string in here"). The quotation marks delimit (mark) the beginning
and ending of the string and aren’t considered part of the string. Therefore, the string of
characters making up the message sent to cout must be enclosed in quotation marks, as was
done in Program 2.1.
Now examine another program to understand cout’s versatility. Read Program 2.2 to
determine what it does.
Program 2.2
#include <iostream>
using namespace std;
int main()
{
cout << "Computers, computers everywhere";
cout << "n as far as I can C";
return 0;
}
When Program 2.2 is run, the following is displayed:
Computers, computers everywhere
as far as I can C
You might be wondering why the n didn’t appear in the output. The characters  and
n, when used together, are called a newline escape sequence. They tell cout to send
instructions to the display device to move to the beginning of a new line. Otherwise, the
second cout statement would simply append its characters to the previous statement’s
characters; it doesn’t start on a new line by itself. In C++, the backslash () character provides
an “escape” from the normal interpretation of the character following it and alters its
meaning—in this case, the n. If the backslash were omitted from the second cout statement
in Program 2.2, the n would be printed as the letter “n” and the program would output the
following:
Computers, computers everywheren as far as I can C
Newline escape sequences can be placed anywhere in the message sent to cout. See
whether you can determine the display Program 2.3 produces.
50 Problem Solving Using C++
Program 2.3
#include <iostream>
using namespace std;
int main()
{
cout << "Computers everywheren as far asnnI can see";
return 0;
}
This is the output for Program 2.3:
Computers everywhere
as far as
I can see
EXERCISES 2.1
1. (Practice) State whether the following are valid function names and if so, whether
they’re mnemonic names that convey some idea of the function’s purpose. If they are
invalid names, state why.
power density m1234 newamp 1234 abcd
total tangent absval computed b34a 34ab
volts$ a2B3 while minVal sine $sine
cosine speed netdistance sum return stack
2. (Practice) Assume the following functions have been written:
getLength(), getWidth(), calcArea(), displayArea()
a. From the functions’ names, what do you think each function might do?
b. In what order do you think a main() function might execute these functions (based
on their names)?
3. (Practice) Assume the following functions have been written:
speed(), distance(), acceleration()
From the functions’ names, what do you think each function might do?
51
Chapter 2
Introduction to C++
4. (Practice) Determine names for functions that do the following:
a. Find the average of a set of numbers.
b. Find the area of a rectangle.
c. Find the minimum value in a set of numbers.
d. Find the density of a steel door.
e. Sort a set of numbers from lowest to highest.
5. (Program) a. Using cout, write a C++ program that displays your name on one line,
your street address on a second line, and your city, state, and zip code on a third line.
b. Run the program you have written for Exercise 5a. (Note: You must understand the
procedures for entering and running a C++ program on the particular computer instal-
lation you’re using.)
6. (Program) a. Write a C++ program to display the following output:
The cosecant of an angle
is equal to one over
the sine of the angle.
b. Compile and run the program you have written for Exercise 6a.
7. (Program) a. How many cout statements would you use to display the following output?
Degrees Radians
0 0.0000
90 1.5708
180 3.1416
270 4.7124
360 6.2832
b. What’s the minimum number of cout statements that could be used to print the out-
put in Exercise 7a?
c. Write a complete C++ program to produce the output shown in Exercise 7a.
d. Run the program you have written for Exercise 7c.
8. (Program) a. Assuming your compiler isn’t case sensitive, determine which of these pro-
gram unit names are equivalent:
AVERAG averag MODE BESSEL Mode
Total besseL TeMp Densty TEMP
denSTY MEAN total mean mode
b. Redo Exercise 8a, assuming a case-sensitive compiler.
Project Structuring Exercises
Most projects, both programming and nonprogramming, can usually be structured into smaller
subtasks or units of activity. These smaller subtasks can often be delegated to different
people so that when all the tasks are finished and integrated, the project or program is
completed. For Exercises 9 through 14, determine a set of subtasks that, performed together,
complete the project. Be aware that each exercise has many possible solutions. The only
requirement is that the set of subtasks, when performed together, complete the required task.
52 Problem Solving Using C++
Note: The purpose of these exercises is to have you consider the different ways that complex tasks
can be structured. Although there’s no one correct solution to these exercises, there are incorrect
solutions and solutions that are better than others. An incorrect solution is one that doesn’t fully
specify the task. One solution is better than another if it more clearly or easily identifies what must
be done.
N
O
T
E
9. (Practice) You’re given the task of wiring and installing lights in your attic. Determine a
set of subtasks to accomplish this task. (Hint: The first subtask is determining the place-
ment of light fixtures.)
10. (Practice) You’re given the job of preparing a complete meal for five people next
weekend. Determine a set of subtasks to accomplish this task. (Hint: One subtask, not
necessarily the first, is buying the food.)
11. (Practice) You’re a sophomore in college and are planning to go to graduate school for a
master’s degree in electrical engineering after you graduate. List a set of major objectives
you must fulfill to meet this goal. (Hint: One subtask is “Determine the correct courses to
take.”)
12. (Practice) You’re given the job of planting a vegetable garden. Determine a set of sub-
tasks to accomplish this task. (Hint: One subtask is planning the garden’s layout.)
13. (Practice) You’re responsible for planning and arranging the family camping trip this
summer. List a set of subtasks to accomplish this task. (Hint: One subtask is selecting the
campsite.)
14. (Data Processing) a. A national medical testing laboratory wants a new computer system
to analyze its test results. The system must be capable of processing each day’s results as
well as retrieving and outputting a printed report of all results meeting certain criteria,
such as all results for a particular doctor or for hospitals in a certain state. Determine
three or four major program units into which this system could be separated. (Hint: One
possible program unit is “Prepare Daily Results” to create each day’s reports.)
b. Suppose someone enters incorrect data for a test result, and the error is discovered
after the system has entered and stored the data. What program unit is needed to cor-
rect this problem? Discuss why such a program unit might or might not be required
by most systems.
c. Assume a program unit exists that allows users to change data that has been entered
and stored incorrectly. Discuss the need for including an “audit trail” that would allow
reconstructing the changes later as well as when they were made and who made them.
2.2 Programming Style
C++ programs start execution at the beginning of the main() function. Because a program
can have only one starting point, every C++ program must contain one and only one main()
function. As you have seen, all the statements making up the main() function are then
included within the braces following the function name. Although the main() function must
be present in every C++ program, C++ doesn’t require placing the word main, the
parentheses, or the braces in any particular form. The form used in the previous section
53
Chapter 2
Programming Style
int main()
{
program statements in here;
return 0;
}
was chosen strictly for clarity and ease in reading the program but is not required. For
example, the following general form of a main() function would also work:
int main
(
) { first statement;second statement;
third statement;fourth
statement;
return 0;}
Notice that you can put more than one statement on a line or place a statement on more
than one line. Except for strings, quotation marks, identifiers, and keywords, C++ ignores all
white space. (White space refers to any combination of blank spaces, tabs, or new lines.) For
example, changing the white space in Program 2.1 and making sure not to split the string
Hello there world! across two lines results in the following valid program:
#include <iostream>
using namespace std;
int main
(
){
cout <<
"Hello there world!";
return 0;
}
Although this version of main() does work, it’s an example of poor programming style
because it’s difficult to read and understand. For readability, the main() function should
always be written in this standard form:
int main()
{
program statements in here;
return 0;
}
In this standard form, the function name starts at the left margin (call this column 1) and
is placed with the required parentheses on a line by itself. The opening brace of the function
body follows in column 1 on the next line, directly under the first letter of the line containing
the function’s name. Similarly, the closing function brace is placed by itself in column 1 (lined
up with the opening brace) as the last line of the function. This structure highlights the
function as a single unit.
Within the function, all program statements are indented at least two spaces. Indentation
is another sign of good programming practice, especially if the same indentation is used for
similar groups of statements. Review Program 2.2 to see that the same indentation was used
for both cout statements.
54 Problem Solving Using C++
As you progress in your understanding and mastery of C++, you’ll develop your own
indentation standards. Just keep in mind that the final form of your programs should be
consistent and always aid others in reading and understanding your programs.
Comments
Comments are explanatory remarks made in a program. When used carefully, comments can
be helpful in clarifying the overall program’s purpose, explaining what a group of statements
is meant to accomplish, or explaining what one line is intended to do. C++ supports two types
of comments: line and block. Both types can be placed anywhere in a program and have no
effect on program execution. The compiler ignores all comments—they are there strictly for
the convenience of anyone reading the program.
A line comment begins with two slashes (//) and continues to the end of the line. For
example, the following examples are line comments:
// this is a comment
// this program prints out a message
// this program calculates a square root
The symbols //, with no white space between them, designate the start of the line
comment. The end of the line on which the comment is written designates the end of the
comment. A line comment can be written on a line by itself or at the end of the line
containing a program statement. Program 2.4 shows using line comments in a program.
Program 2.4
// this program displays a message
#include <iostream>
using namespace std;
int main()
{
cout << "Hello there world!"; // this produces the display
return 0;
}
The first comment appears on a line by itself at the top of the program, and this location
is a good one for a comment describing the program’s purpose. If more comments are
required, they can be placed one per line, as with the comment after the cout statement.
When a comment is too long to be contained on one line, it can be separated into two or more
line comments, with each comment preceded by the // symbol. For example, the following
comment generates a C++ error message because the second line doesn’t start with the //
symbol:
// this comment is invalid because it
extends over two lines
55
Chapter 2
Programming Style
This comment is correct, written as follows:
// this comment is used to illustrate a
// comment that extends across two lines
Comments that span two or more lines are, however, more conveniently written as
C-type block comments, which begin with the symbols /* and end with the symbols */, as
in this example:
/* This is a block comment that
spans
three lines */
In C++, a program’s structure is intended to make it readable and understandable, so
extensive comments aren’t necessary. This guideline is reinforced by carefully selecting
function names to convey their purpose, as discussed previously. However, if the program
element’s purpose still isn’t clear from its structure, name, or context, include comments
where clarification is needed.
Obscure code with no comments is a sure sign of bad programming, especially when
other people must maintain or read the program. Similarly, excessive comments are a sign of
bad programming because not enough thought was given to making the code self-
explanatory. Typically, any program you write should begin with comments including a short
program description, your name, and the date the program was written or last modified. For
space considerations and because all programs in this book were written by the author, these
initial comments are used only for short program descriptions when they aren’t provided as
part of the accompanying text.
EXERCISES 2.2
1. (Debug) a. Will the following program work?
#include <iostream>
using namespace std;
int main() {cout << "Hello there world!"; return 0;}
b. Even if the program in Exercise 1a works, explain why it’s not a good program.
2. (Modify) Rewrite the following programs to conform to good programming practice and
correct syntax:
a. #include <iostream>
int main(
){
cout <<
"The time has come"
; return 0;}
b. #include <iostream>
using namespace std; int main
( ){cout << "Newark is a cityn";cout <<
56 Problem Solving Using C++
"In New Jerseyn"; cout <<
"It is also a cityn"
; cout << "In Delawaren"
; return 0;}
c. #include <iostream>
using namespace std;
int main() {cout << Reading a programn";cout <<
"is much easiern"
; cout << "if a standard form for main is usedn")
; cout
<<"and each statement is writtenn";cout
<< "on a line by itselfn")
; return 0;}
d. #include <iostream.h>
using namespace std;
int main
( ){ cout << "Every C++ program"
; cout
<<"nmust have one and only one"
;
cout << "main function"
;
cout <<
"n the escape sequence of characters")
; cout <<
"nfor a newline can be placed anywhere"
; cout
<<"n within the message passed to cout"
; return 0;}
3. (For Thought) a. When used in a message, the backslash character alters the meaning of
the character immediately following it. If you want to print the backslash character, you
have to tell cout to escape from the way it normally interprets the backslash. What char-
acter do you think is used to alter the way a single backslash character is interpreted?
b. Using your answer to Exercise 3a, write the escape sequence for printing a backslash.
4. (For Thought) a. A token of a computer language is any sequence of characters, with
no intervening characters or white space, that taken as a unit has a unique meaning.
Using this definition of a token, determine whether escape sequences, function names,
and the keywords listed in Table 2.1 are tokens of the C++ language.
b. Discuss whether adding white space to a message alters the message and whether
messages can be considered tokens of C++.
c. Using the definition of a token in Exercise 4a, determine whether the following state-
ment is true: “Except for tokens of the language, C++ ignores all white space.”
57
Chapter 2
Programming Style
2.3 Data Types
The objective of all programs is to process data, be it numerical, alphabetical, audio, or video.
Central to this objective is classifying data into specific types. For example, calculating a
rocket’s trajectory requires mathematical operations on numerical data, and alphabetizing a
list of names requires comparison operations on character-based data. Additionally, some
operations aren’t applicable to certain types of data. For example, it makes no sense to add
names together. To prevent programmers from attempting to perform an inappropriate
operation, C++ allows performing only certain operations on certain data types.
The types of data permitted and the operations allowed for each type are referred to as
a data type. Formally, a data type is defined as a set of values and a set of operations that can
be applied to these values. For example, the set of all integer (whole) numbers constitutes
a set of values, as does the set of all real numbers (numbers containing a decimal point).
These two sets of numbers, however, don’t constitute a data type until a set of operations is
included—in these examples, mathematical and comparison operations. The combination of
a set of values plus operations becomes a true data type.
C++ categorizes data types in two basic groupings: class data types and built-in data
types. A class data type (referred to as a “class,” for short) is a programmer-created data type,
which means the programmer defines the acceptable values and operations, using C++ code.
This data type is discussed in Part Two.
A built-in data type is provided as part of the C++ compiler and requires no external C++
code. Therefore, a built-in data type can be used without supplementary additions, such as
the iostream header file for the cout object. Built-in data types, also referred to as
primitive types, consist of the basic numerical types shown in Figure 2.5 and the operations
listed in Table 2.2. As shown in this table, most operations for built-in data types are
designated as symbols. For class data types, most operations are provided as functions.
Table 2.2 Built-in Data Type Operations
Built-in Data Type Operations
Integer +, -, *, /, %, =, ==, !=, <=, >=, sizeof(),
and bit operations (see Chapter 15)
Floating point +, -, *, /, =, ==, !=, <=, >=, sizeof()
To introduce C++’s built-in data types, literals are used. A literal is an acceptable value for
a data type. The term “literal” in this context means the value identifies itself. (Another name
for a literal is a literal value or constant.) For example, all numbers, such as 2, 3.6, and -8.2, are
referred to as literal values because they literally display their values. Text, such as "Hello
World!", is also a literal value because the text is displayed. You have been using literal values
Numerical data types
Floating-point
types
Integer types
Figure 2.5 Built-in data types
58 Problem Solving Using C++
throughout your life but have known them as numbers and words. In Section 2.5, you see some
examples of non-literal values—those that don’t display themselves but are stored and accessed
by using identifiers.
Integer Data Types
C++ provides nine built-in integer data types, as shown in Figure 2.6. The essential
difference between these integer data types is the amount of storage used for each type,
which affects the range of values each type is capable of representing. The three most
important and common types used in most applications are int, char, and bool. The other
types were provided to accommodate special situations (such as a small or large range of
numbers) and have been retained for historical reasons. They enabled programmers to
maximize memory usage by selecting the data type using the smallest amount of memory,
consistent with an application’s requirements. When computer memories were small,
compared with today’s computers, and expensive, the amount of memory used was a major
concern. Although no longer a concern for most programs, these types still allow programmers
to optimize memory usage when necessary, typically in special-purpose digital control
systems used in home appliances and automobiles.
The int Data Type The values supported by the int data type are whole numbers,
mathematically known as integers. An integer value consists of digits only and can optionally
be preceded by a plus (+) or minus (-) sign. Therefore, an integer value can be the number
0 or any positive or negative number without a decimal point, as shown in these examples
of valid integers:
0 5 -10 +25 1000 253 -26351 +36
As these examples illustrate, integers can contain a sign. However, no commas, decimal
points, or special symbols, such as the dollar sign, are allowed, as in these examples of invalid
integers:
$255.62 2,523 3. 6,243,892 1,492.89 +6.0
Compilers differ in their internal limits on the largest (most positive) and smallest (most
negative) integer values that can be stored in each data type.5 The most common storage
5
The limits imposed by the compiler are found in the limits header file and defined as the hexadecimal constants int_max and int_min.
bool
char
short int
int
long int
unsigned char
unsigned short int
unsigned int
unsigned long int
Integer data types
Figure 2.6 C++ integer data types
59
Chapter 2
Data Types
allocation is 4 bytes for the int data type, which restricts the values used to represent
integers from -2,147,483,648 to 2,147,483,647.6
The char Data Type The char data type is used to store single characters, including the
letters of the alphabet (uppercase and lowercase), the digits 0 through 9, and special symbols,
such as + $ . , - and !. A character value is any single letter, digit, or special symbol
enclosed by single quotation marks, as shown in these examples:
'A' '$' 'b' '7' 'y' '!' 'M' 'q'
Character values are typically stored in a computer by using ASCII or Unicode codes.
The ASCII (American Standard Code for Information Interchange, pronounced “as-key”)
code provides codes for the English-language character set plus codes for printer and display
control, such as newline and printer paper eject codes. Each character code is contained in
a single byte, which provides 256 distinct codes. Table 2.3 lists the ASCII byte codes for
uppercase letters.
Additionally, C++ provides for the newer Unicode code that uses 2 bytes per character
and can represent 65,536 characters. This code is used for international applications because
it includes character sets for other languages in addition to English. As the first 256 Unicode
codes have the same numerical value as the 256 ASCII codes (the additional byte is coded
with all 0s), you needn’t be concerned with which storage code to use with English-language
characters.
Table 2.3 The ASCII Uppercase Letter Codes
Letter ASCII Code Letter ASCII Code
A 01000001 N 01001111
B 01000010 O 01001110
C 01000011 P 01010000
D 01000100 Q 01010001
E 01000101 R 01010010
F 01000110 S 01010011
G 01000111 T 01010100
H 01001000 U 01010101
I 01001001 V 01010110
J 01001010 W 01010111
K 01001011 X 01011000
L 01001100 Y 01011001
M 01001101 Z 01011010
Using Table 2.3, you can determine how the characters 'B', 'A', 'R', 'T', 'E', and
'R', for example, are stored in a computer by using ASCII codes. This sequence of six
characters requires 6 bytes of storage (1 byte for each letter) and is stored as illustrated in
Figure 2.7.
6
The most negative number is always one higher than the most positive number. Effectively, the “lost” positive number is used for the number 0.
(See the twos complement method of integer storage, described in Section 1.6.)
60 Problem Solving Using C++
The Escape Character As you’ve seen in Section 2.1, the backslash () has a special
meaning in C++ as the escape character. When a backslash is placed in front of a group of
characters, it tells the compiler to escape from the way these characters are normally
interpreted. The combination of a backslash and these characters is called an escape sequence.
Table 2.4 lists C++’s most common escape sequences.
Table 2.4 Escape Sequences
Escape Sequence Character
Represented
Meaning ASCII Code
n Newline Move to a new line 00001010
t Horizontal tab Move to the next
horizontal tab
setting
00001001
v Vertical tab Move to the next
vertical tab setting
00001011
b Backspace Move back one
space
00001000
r Carriage return Move the cursor to
the start of the
current line; used
for overprinting
00001101
f Form feed Issue a form feed 00001100
a Alert Issue an alert
(usually a bell
sound)
00000111
 Backslash Insert a backslash
character (used to
place an actual
backslash character
in a string)
01011100
? Question mark Insert a question
mark character
00111111
' Single quotation Insert a single-
quote character
(used to place an
inner single quote
within a set of
outer single quotes)
00100111
6 bytes of storage
B A R T E R
01000010 01000001 01010010 01010100 01000101 01010010
Figure 2.7 The letters BARTER stored in a computer
61
Chapter 2
Data Types
Table 2.4 Escape Sequences (continued)
Escape Sequence Character
Represented
Meaning ASCII Code
" Double quotation Insert a double-
quote character
(used to place an
inner double quote
within a set of
outer double
quotes)
00100010
nnn Octal number Consider the
number nnn (n is a
digit) an octal
number
Dependent on nnn
xhhhh Hexadecimal
number
Consider the
number hhhh (h is
a digit) a
hexadecimal
number
Dependent on
hhhh
0 Null character Insert the null
character, which is
defined as having
the value 0
00000000
Although each escape sequence in Table 2.4 is made up of two characters, the
combination of these characters, with no intervening white space, causes the compiler to
create the single ASCII code listed in the table.
The bool Data Type In C++, the bool data type is used to represent Boolean (logical)
data, so it’s restricted to one of two values: true or false. This data type is most useful
when a program must examine a condition and take a prescribed course of action, based on
whether the condition is true or false. For example, in a sales application, the condition being
examined might be “is the total purchase for $100 or more.” Only when this condition is true
is a discount applied. Because the bool data type uses an integer storage code, however, it
has useful implications that most professional C++ programmers utilize. The practical uses of
Boolean conditions are covered in Chapter 4, so the bool data type is discussed in more
detail in that chapter.
Determining Storage Size
A unique feature of C++ is that you can see where and how values are stored. As an example,
the C++ operator sizeof() provides the number of bytes used to store values for the data
type named in the parentheses. (Review Section 1.6 if you’re unfamiliar with the concept of
a byte.) This built-in operator doesn’t use an arithmetic symbol to perform its operation.
Program 2.5 uses this operator to determine the amount of storage reserved for the int,
char, and bool data types.
62 Problem Solving Using C++
Program 2.5
#include <iostream>
using namespace std;
int main()
{
cout << "nData Type Bytes"
<< "n--------- -----"
<< "nint " << sizeof(int)
<< "nchar " << sizeof(char)
<< "nbool " << sizeof(bool)
<< 'n';
return 0;
}
In reviewing Program 2.5, notice that a single character value is inserted in the display
by cout by enclosing it in single quotation marks, as in the escape sequence 'n' at the
end of the cout statement. In the first five displayed lines, this character is included in each
output string. Each time the compiler encounters the newline escape sequence, as a single
character or as part of a string, it’s translated as a single character that forces the display to
start at the beginning of a new line. Although quotation marks can be used for the final
newline insertion, as "n", they designate a string. When only a single character is being
transmitted, and to emphasize that single characters are designated by using single quotation
marks, 'n' is used instead of "n". From a practical standpoint, however, both notations
force a new line in the display.
Point of Information
The Character 'n' and the String "n"
The compiler recognizes both 'n' and "n" as containing the newline character. The
difference is in the data type used. Formally, 'n' is a character literal, and "n" is a
string literal. From a practical standpoint, both cause the same thing to happen: A new
line is forced in the output display. In encountering the character value 'n', however,
the compiler translates it by using the ASCII code 00001010 (see Table 2.4). In encoun-
tering the string value "n", the compiler translates it by using the correct character
code but also adds an end-of-string character, which is '0'.
Good programming practice requires ending the last output display with a newline
escape sequence. This practice ensures that the first line of output from one program
doesn’t end up on the last line displayed by the previously executed program.
63
Chapter 2
Data Types
The output of Program 2.5 is compiler dependent, meaning each compiler reports the
amount of storage it provides for the data type under consideration. When run on a computer
using Microsoft’s current Visual C++ .NET compiler, for example, the following output is
produced:
Data Type Bytes
--------- -----
int 4
char 1
bool 1
For this output, which is the typical storage almost all current C++ compilers provide,
you can determine the range of values that can be stored in each data type. To do so,
however, requires understanding the difference between a signed and an unsigned data type,
discussed next.
Signed and Unsigned Data Types
A signed data type permits storing negative values in addition to 0 and positive values, so int
is a signed data type. An unsigned data type provides for only non-negative values (that is, 0
and positive values). Some applications require only unsigned numerical values. For example,
many date applications store dates in the numerical form yearmonthday (storing 12/25/2007
as 20071225, for example) and are concerned only with dates after 0 CE. For these
applications, which never require a negative value, an unsigned data type can be used.
All unsigned integer types, such as unsigned int, provide a range of positive values
that, for all practical purposes, is double the range for their signed counterparts. This extra
positive range is made available by using the negative range of its signed version for
additional positive numbers.
With an understanding of the difference between signed and unsigned data types, you
can use Table 2.5 to determine the range of integer values supported by current C++
compilers. As you can see, a long int uses the same amount of storage (4 bytes) as an int.
The only requirement of the ANSI C++ standard is that an int must provide at least as
much storage as a short int, and a long int must provide at least as much storage as
an int. On early desktop computers with a memory capacity limited to thousands of bytes,
a short int typically used 1 byte of storage, an int 2 bytes, and a long int 4 bytes.
This storage limited the range of int values from -32,768 to +32,767 and unsigned int
values from 0 to 65,535, thus doubling the number of possible positive values, which was
significant. With the current range of int values in the -2 to +2 billion range, doubling
Point of Information
Object-Oriented and Procedural Programs
Except for the bool type, all of C++’s built-in data types are direct carryovers from the
C procedural language. Not surprisingly, programs using only built-in data types can’t
be object-oriented programs. Instead, as in Program 2.5, they become procedural pro-
grams, those based primarily on procedures, such as main().
Only when built-in data types are bundled together to form a packet of data,
which becomes an object, can an object-oriented program come into existence.
64 Problem Solving Using C++
positive values is rarely a consideration. Additionally, a long int is unnecessary now
because it is uses the same storage capacity as an int.
Table 2.5 Integer Data Type Storage
Name of Data Type Storage Size Range of Values
char 1 256 characters
bool 1 true (considered as any positive
value) and false (which is a 0)
short int 2 -32,768 to +32,767
unsigned short int 2 0 to 65,535
int 4 -2,147,483,648 to
+2,147,483,647
unsigned int 4 0 to 4,294,967,295
long int 4 -2,147,483,648 to
+2,147,483,647
unsigned long int 4 0 to 4,294,967,295
Floating-Point Types
A floating-point number, more commonly known as a real number, can be the number 0 or any
positive or negative number containing a decimal point, as shown in these examples:
+10.625 5. -6.2 3251.92 0.0 0.33 -6.67 +2.
Therefore, the numbers 5., 0.0, and +2. are classified as floating-point values, but the same
numbers written without a decimal point (5, 0, +2) are integer values. As with integer values,
special symbols such as the dollar sign and comma aren’t permitted in real numbers, as shown
in these examples of invalid real numbers:
5,326.25 24 6,459 $10.29 7.007.645
C++ supports three floating-point data types: float, double, and long double. The
difference between these data types is the amount of storage the compiler uses. Most
compilers use twice the amount of storage for doubles as for floats, which allows a
double to have approximately twice the precision of a float. For this reason, a float
value is sometimes referred to as a single-precision number and a double value as a
double-precision number. The actual storage allocation for each data type, however, depends
on the compiler. The ANSI C++ standard requires only that a double have at least the same
amount of precision as a float, and a long double have at least the same amount of
storage as a double. Currently, most C++ compilers allocate 4 bytes for floats and 8 bytes
for doubles and long doubles, which produces the range of numbers listed in Table 2.6.
Table 2.6 Floating-Point Data Types
Type Storage Absolute Range of Values (+ and -)
float 4 bytes 1.40129846432481707x10-45
to
3.40282346638528860x1038
double and long
double
8 bytes 4.94065645841246544x10-324
to
1.79769313486231570x10308
65
Chapter 2
Data Types
In compilers using the same amount of storage for double and long double numbers,
these two data types are identical. (The sizeof() operator in Program 2.5 can always be
used to determine the amount of storage your compiler reserves for these data types.) A
float literal is indicated by appending an f or F to the number, and a long double is
created by appending an l or L to the number. In the absence of these suffixes, a
floating-point number defaults to a double. For example, take a look at the following:
9.234 indicates a double literal
9.234F indicates a float literal
9.234L indicates a long double literal
The only difference in these numbers is the amount of storage the computer can use for
them. Appendix C describes the binary storage format used for floating-point numbers and
its impact on number precision.
EXERCISES 2.3
1. (Practice) Determine data types appropriate for the following data:
a. The average of four grades
b. The number of days in a month
Point of Information
What Is Precision?
In numerical theory, the term precision typically refers to numerical accuracy. In this
context, the statement “This computation is accurate, or precise, to the fifth decimal
place” means the fifth digit after the decimal point has been rounded, and the number
is accurate to within ±0.00005.
In computer programming, “precision” can refer to the accuracy of a number or
the amount of significant digits in the number; significant digits are defined as the
number of clearly correct digits plus 1. For example, if the number 12.6874 has been
rounded to the fourth decimal place, it’s correct to say that this number is precise to
the fourth decimal place. In other words, all digits in the number are accurate except
the fourth decimal digit, which has been rounded. Similarly, this same number has a
precision of six digits, which means the first five digits are correct and the sixth digit
has been rounded. Another way of saying this is that the number 12.6874 has six sig-
nificant digits.
The significant digits in a number need not have any relation to the number of
displayed digits. For example, if the number 687.45678921 has five significant digits,
it’s accurate only to the value 687.46; the last digit is assumed to be rounded. Similarly,
dollar values in large financial applications are often rounded to the nearest hundred
thousand dollars. In these applications, a displayed dollar value of $12,400,000, for
example, isn’t accurate to the closest dollar. If this value is specified as having three
significant digits, it’s accurate only to the hundred-thousand digit.
66 Problem Solving Using C++
c. The length of the Golden Gate Bridge
d. The numbers in a state lottery
e. The distance from Brooklyn, N.Y. to Newark, N.J.
f. The single-character prefix that specifies a component type
2. (Practice) Compile and execute Program 2.5.
3. (Modify) Modify Program 2.5 to determine the storage your compiler uses for all the C++
integer data types.
4. (Practice) Show how the name KINGSLEY is stored in a computer that uses the ASCII
code by drawing a diagram similar to Figure 2.7, shown previously.
5. (Practice) Repeat Exercise 4 using the letters of your own last name.
6. (Modify) Modify Program 2.5 to determine how many bytes your compiler assigns to the
float, double, and long double data types.
7. (For Thought) Because computers use different representations for storing integer,
floating-point, double-precision, and character values, discuss how a program might alert
the computer to the data types of various values it will be using.
8. (For Thought) Although you have concentrated on operations involving integer and
floating-point numbers, C++ allows adding and subtracting characters and integers. (These
operations are possible with characters because they’re integer data types and are stored
by using integer codes.) Therefore, characters and integers can be mixed in arithmetic
expressions. For example, if your computer uses ASCII code, the expression 'a' + 1
equals 'b' and 'z' - 1 equals 'y' is valid. Similarly, 'A' + 1 is 'B' and 'Z' - 1
is 'Y'. With this information as background, determine the character results of the fol-
lowing expressions. (Assume all characters are stored by using ASCII codes.)
a. 'm' - 5
b. 'm' + 5
c. 'G' + 6
d. 'G' - 6
e. 'b' - 'a'
f. 'g' - 'a' + 1
g. 'G' - 'A' + 1
Note: To complete the following exercise, you need to understand basic computer storage
concepts. Specifically, if you’re unfamiliar with the concepts of bytes and words, refer to
Section 1.6 before doing the next exercise.
N
O
T
E
9. (Practice) Although the total number of bytes varies from computer to computer, memory
sizes of 65,536 to more than several million bytes are common. In computer language, the
letter K represents the number 1024, which is 2 raised to the 10th power, and M represents
the number 1,048,576, which is 2 raised to the 20th power. Therefore, a memory size of
640 KB is really 640 times 1024 (655,360 bytes), and a memory size of 4 MB is really 4 times
67
Chapter 2
Data Types
1,048,576 (4,194,304 bytes). Using this information, calculate the actual number of bytes in
the following:
a. A memory containing 512 MB
b. A memory consisting of 256 MB words, where each word consists of 2 bytes
c. A memory consisting of 256 MB words, where each word consists of 4 bytes
d. A thumb drive that specifies 2 MB
e. A disk that specifies 250 MB
f. A disk that specifies 8 GB (Hint: See Table 1.2.)
2.4 Arithmetic Operations
The previous section presented the data values corresponding to C++’s built-in data types.
This section explains the arithmetic operations that can be applied to these values.
Integers and real numbers can be added, subtracted, multiplied, and divided. Although
it’s usually better not to mix integers and real numbers when performing arithmetic
operations, you can get predictable results when using different data types in the same
arithmetic expression. Surprisingly, you can add and subtract character data and mix it with
integer data to produce useful results. (For example, 'A' + 1 results in the character 'B'.)
These operations are possible because characters are stored by using integer codes.
The operators used for arithmetic operations are called arithmetic operators and are as
follows:
Operation Operator
Addition +
Subtraction -
Multiplication *
Division /
Modulus division7 %
These operators are also called binary operators, which means the operator requires two
operands to produce a result. An operand can be a literal value or an identifier with an
associated value. A simple binary arithmetic expression consists of a binary operator connecting
two literal values in this form:
literalValue operator literalValue
Examples of simple binary arithmetic expressions are the following:
3 + 7
8 - 3
12.62 + 9.8
0.08 * 12.2
12.6 / 2
7
Don’t be concerned at this stage if you do not understand the term “modulus division.” You learn more about this operator later in “Integer
Division.”
68 Problem Solving Using C++
The spaces around arithmetic operators in these examples are inserted strictly for clarity
and can be omitted without affecting the value of the expression. However, an expression in
C++ must be entered in a straight-line form, as shown in these examples. For example, the
C++expression equivalent to 12.6 divided by 2 must be entered as 12.6 / 2, not as the
algebraic expression shown here:
12 6
2
.
You can use cout to display the value of any arithmetic expression onscreen. To do this, the
value must be sent to the object. For example, the following statement yields the display 21:
cout << (6 + 15);
Strictly speaking, the parentheses surrounding the expression 6 + 15 aren’t required to
indicate that the value of the expression (that is, 21) is being displayed.8 In addition to displaying
a numerical value, cout can display a string identifying the output, as was done in Section 2.1.
For example, the following statement sends two pieces of data, a string and a value, to cout:
cout << "The sum of 6 and 15 is " << (6 + 15);
Each set of data sent to cout must be preceded by its own insertion operator, <<. In the
preceding example, the first data sent for display is the string "The sum of 6 and 15
is ", and the second item sent is the value of the expression 6 + 15. This statement
produces the following display:
The sum of 6 and 15 is 21
The space between the word “is” and the number 21 is caused by the space in the string
sent to cout. As far as cout is concerned, its input is a set of characters sent to be displayed
in the order they’re received. Characters from the input are queued, one behind the other,
and sent to the screen for display. Placing a space in the input makes the space part of the
stream of characters that’s displayed. For example, the statement
cout << "The sum of 12.2 and 15.754 is " << (12.2 + 15.754);
yields the following display:
The sum of 12.2 and 15.754 is 27.954
When multiple insertions are sent to cout, the code can be spread across multiple lines.
Only one semicolon, however, must be used, which is placed after the last insertion and
terminates the complete statement. Therefore, the preceding display is also produced by the
following statement, which spans two lines:
cout << "The sum of 12.2 and 15.754 is "
<< (12.2 + 15.754);
However, when you allow a statement to span multiple lines, two rules must be followed:
A string contained in quotation marks can’t be split across lines, and the terminating
semicolon should appear only on the last line. You can always place multiple insertion
symbols in a line.
8
The parentheses aren’t required because the + operator has a higher precedence than the << operator; therefore, the addition is performed
before the insertion.
69
Chapter 2
Arithmetic Operations
If floating-point numbers have six or fewer decimal digits, they’re displayed with enough
decimal places to accommodate the fractional part of the number. If the number has more
than six decimal digits, the fractional part is rounded to six decimal digits, and if the number
has no decimal digits, neither a decimal point nor any decimal digits are displayed.9
Program 2.6 illustrates using cout to display the results of arithmetic expressions in the
statements of a complete program.
Program 2.6
#include <iostream>
using namespace std;
int main()
{
cout << "15.0 plus 2.0 equals " << (15.0 + 2.0) << endl
<< "15.0 minus 2.0 equals " << (15.0 - 2.0) << endl
<< "15.0 times 2.0 equals " << (15.0 * 2.0) << endl
<< "15.0 divided by 2.0 equals " << (15.0 / 2.0) << endl;
return 0;
}
The output of Program 2.6 is the following:
15.0 plus 2.0 equals 17
15.0 minus 2.0 equals 13
15.0 times 2.0 equals 30
15.0 divided by 2.0 equals 7.5
The only new item used in Program 2.6 is the term endl, which is an example of a C++
manipulator. A manipulator is an item used to change how the output stream of characters is
displayed. In particular, the endl manipulator first causes a newline character ('n') to be
inserted in the display, and then forces all current insertions to be displayed immediately,
instead of waiting for more data. (Section 3.2 lists the most commonly used manipulators.)
Expression Types
An expression is any combination of operators and operands that can be evaluated to yield a
value. An expression containing only integer values as operands is called an integer
expression, and the result of the expression is an integer value. Similarly, an expression
containing only floating-point values (single-precision and double-precision) as operands is
called a floating-point expression (also referred to as a “real expression”), and the result of the
9
None of this output is defined as part of the C++ language. Rather, it’s defined by a set of classes and routines provided with each C++ compiler.
70 Problem Solving Using C++
expression is a floating-point value. An expression containing integer and floating-point
values is called a mixed-mode expression. Although it’s usually better not to mix integer
andfloating-point values in an arithmetic operation, the data type of each operation is
determined by the following rules:
• If both operands are integers, the result of the operation is an integer.
• If one operand is a real value, the result of the operation is a double-precision value.
The result of an arithmetic expression is never a single-precision (float) number. This
is because during execution, a C++ program temporarily converts all single-precision
numbers to double-precision numbers when an arithmetic expression is evaluated.
Integer Division
The division of two integer values can produce rather strange results for the unwary. For
example, the expression 15/2 yields the integer result 7. Because integers can’t contain a
fractional part, a value of 7.5 can’t be obtained. The fractional part resulting when two
integers are divided—the remainder—is always dropped (truncated). Therefore, the value of
9/4 is 2 and 20/3 is 6.
Often, however, you need to retain the remainder of an integer division. To do this, C++
provides the modulus operator (also referred to as the “remainder operator”), which has the
symbol %. This operator captures the remainder when an integer is divided by an integer;
using a non-integer value with the modulus operator results in a compiler error. The
following examples show how the modulus operator is used:
9 % 4 is 1 (the remainder when 9 is divided by 4 is 1)
17 % 3 is 2 (the remainder when 17 is divided by 3 is 2)
15 % 4 is 3 (the remainder when 15 is divided by the 4 is 3)
14 % 2 is 0 (the remainder when 14 is divided by 2 is 0)
Negation
In addition to binary operators, C++ provides unary operators, which operate on a single
operand. One of these unary operators uses the same symbol as binary subtraction (-). With
Point of Information
The endl Manipulator
On many systems, the endl manipulator and the n escape sequence are processed in
the same way and produce the same effect. The one exception is on systems where
output is accumulated internally until enough characters collect to make it advanta-
geous to display them all in one burst onscreen. In these systems, referred to as “buff-
ered,” the endl manipulator forces all accumulated output to be displayed
immediately, without waiting for additional characters to fill the buffer area before
being printed. As a practical matter, you wouldn’t notice a difference in the final
display. As a general rule, however, use the n escape sequence whenever it can be
included in an existing string, and use the endl manipulator whenever a n would
appear by itself or to formally signify the end of a specific group of output.
71
Chapter 2
Arithmetic Operations
this unary operator, the minus sign in front of a single numerical value negates (reverses the
sign of) the number.
Table 2.7 summarizes the six arithmetic operations described so far and lists the data
type for the result each operator produces, based on the data type of the operands involved.
Table 2.7 Summary of Arithmetic Operators
Operation Operator
Symbol
Type Operand(s) Result
Addition + Binary Both are integers
One operand is not
an integer
Integer
Double-
precision
Subtraction - Binary Both are integers
One operand is not
an integer
Integer
Double-
precision
Multiplication * Binary Both are integers
One operand is not
an integer
Integer
Double-
precision
Division / Binary Both are integers
One operand is not
an integer
Integer
Double-
precision
Modulus % Binary Both are integers
One operand is not
an integer
Integer
Double-
precision
Negation - Unary Integer or double Same as
operand
Operator Precedence and Associativity
In addition to simple expressions, such as 5 + 12 and .08 * 26.2, you can create more
complex arithmetic expressions. C++, like most other programming languages, requires following
certain rules when writing expressions containing more than one arithmetic operator:
• Two binary operator symbols must never be placed side by side. For example, 5 *
% 6 is invalid because two operators, * and %, are placed next to each other.
• Parentheses can be used to form groupings, and all expressions enclosed in
parentheses are evaluated first. In this way, you can use parentheses to alter the
evaluation to any desired order. For example, in the expression (6 + 4) / (2 +
3), the 6 + 4 and 2 + 3 are evaluated first to yield 10 / 5. The 10 / 5 is then
evaluated to yield 2.
• Parentheses can be enclosed by other parentheses. For example, the expression (2 *
(3 + 7) ) / 5 is valid and evaluates to 4. When parentheses are included within
parentheses, expressions in the innermost parentheses are always evaluated first. The
evaluation continues from innermost to outermost parentheses until all expressions in
parentheses have been evaluated. The number of closing parentheses, ), must always
equal the number of opening parentheses, (, so that no unpaired sets exist.
72 Problem Solving Using C++
• Parentheses can’t be used to indicate multiplication; instead, the multiplication
operator, *, must be used. For example, the expression (3 + 4) (5 + 1) is
invalid. The correct expression is (3 + 4) * (5 + 1).
Parentheses should specify logical groupings of operands and indicate clearly, to the
compiler and programmers, the intended order of arithmetic operations. Although expres-
sions in parentheses are always evaluated first, expressions containing multiple operators,
whether enclosed in parentheses or not, are evaluated by the priority, or precedence, of the
operators. There are three levels of precedence:
1. P1—All negations are done first.
2. P2—Multiplication, division, and modulus operations are computed next. Expres-
sions containing more than one multiplication, division, or modulus operator are
evaluated from left to right as each operator is encountered. For example, in the
expression 35 / 7 % 3 * 4, all operations have the same priority, so the operations
are performed from left to right as each operator is encountered. The division is done
first, yielding the expression 5 % 3 * 4. The modulus operation, 5 % 3, is
performed next, yielding a result of 2. Finally, the expression 2 * 4 is computed to
yield 8.
3. P3—Addition and subtraction are computed last. Expressions containing more than
one addition or subtraction are evaluated from left to right as each operator is
encountered.
In addition to precedence, operators have an associativity, which is the order in which
operators of the same precedence are evaluated, as described in rule P2. For example, does
the expression 6.0 * 6 / 4 yield 9.0, which is (6.0 * 6) / 4, or 6.0, which is 6.0 *
(6 / 4)? The answer is 9.0 because C++’s operators use the same associativity as in general
mathematics, which evaluates multiplication from left to right, as rule P2 indicates.
Table 2.8 lists the precedence and associativity of the operators discussed in this section.
As you have seen, an operator’s precedence establishes its priority in relation to all other
operators. Operators at the top of Table 2.8 have a higher priority than operators at the
bottom of the table. In expressions with multiple operators of different precedence, the
operator with the higher precedence is used before an operator with lower precedence. For
example, in the expression 6 + 4 / 2 + 3, because the division operator has a higher
precedence (P2) than the addition operator, the division is done first, yielding an interme-
diate result of 6 + 2 + 3. The additions are then performed, left to right, to yield a final
result of 11.
Table 2.8 Operator Precedence and Associativity
Operator Associativity
Unary - Right to left
* / % Left to right
+ - Left to right
Finally, take a look at using Table 2.8 and the precedence rules to evaluate an expression
containing operators of different precedence, such as 8 + 5 * 7 % 2 * 4. Because the
multiplication and modulus operators have a higher precedence than the addition operator,
73
Chapter 2
Arithmetic Operations
these two operations are evaluated first (P2), using their left-to-right associativity, before the
addition is evaluated (P3). Therefore, the complete expression is evaluated as the following:
8 + 5 * 7 % 2 * 4 =
8 + 35 % 2 * 4 =
8 + 1 * 4 =
8 + 4 = 12
EXERCISES 2.4
1. (Practice) For the following correct algebraic expressions and corresponding incorrect
C++ expressions, find the errors and write corrected C++ expressions:
Algebra C++ Expression
a. (2)(3) + (4)(5)
b. 6 18
2
+
c. 4 5
12 2 3 1
.
. .
-
d. 4.6 (3.0 + 14.9)
e. (12.1 + 18.9) (15.3 - 3.8)
(2)(3) + (4)(5)
6 + 18 / 2
4.5 / 12.2 - 3.1
4.6 (3.0 + 14.9)
(12.1 + 18.9) (15.3 - 3.8)
2. (Practice) Determine the values of the following integer expressions:
a. 3 + 4 * 6
b. 3 * 4 / 6 + 6
c. 2 * 3 / 12 * 8 / 4
d. 10 * (1 + 7 * 3)
e. 50 % 20
f. 20 - 2 / 6 + 3
g. 20 - 2 / (6 + 3)
h. (20 - 2) / 6 + 3
i. (20 - 2) / (6 + 3)
j. (10 + 3) % 4
3. (Practice) Determine the value of the following floating-point expressions:
a. 3.0 + 4.0 * 6.0
b. 3.0 * 4.0 / 6.0 + 6.0
c. 2.0 * 3.0 / 12.0 * 8.0 / 4.0
d. 10.0 * (1.0 + 7.0 * 3.0)
e. 20.0 - 2.0 / 6.0 + 3.0
f. 20.0 - 2.0 / (6.0 + 3.0)
g. (20.0 - 2.0) / 6.0 + 3.0
h. (20.0 - 2.0) / (6.0 + 3.0)
4. (Practice) Evaluate the following mixed-mode expressions and list the data type of the
result. In evaluating the expressions, be aware of the data types of all intermediate
calculations.
a. 10.0 + 15 / 2 + 4.3
74 Problem Solving Using C++
b. 10.0 + 15.0 / 2 + 4.3
c. 3.0 * 4 / 6 + 6
d. 3 * 4.0 / 6 + 6
e. 20.0 - 2 / 6 + 3
f. 10 + 17 * 3 + 4
g. 10 + 17 / 3. + 4
h. 3.0 * 4 % 6 + 6
i. 10 + 17 % 3 + 4
5. (Practice) Assume that amount stores the integer value 1, m stores the integer value 50,
n stores the integer value 10, and p stores the integer value 5. Evaluate the following
expressions:
a. n / p + 3
b. m / p + n - 10 * amount
c. m - 3 * n + 4 * amount
d. amount / 5
e. 18 / p
f. -p * n
g. -m / 20
h. (m + n) / (p + amount)
i. m + n / p + amount
6. (Practice) Repeat Exercise 5, assuming that amount stores the value 1.0, m stores the
value 50.0, n stores the value 10.0, and p stores the value 5.0.
7. (Practice) Enter, compile, and run Program 2.6.
8. (Desk Check) Determine the output of the following program:
#include <iostream>
using namespace std;
int main() // a program illustrating integer truncation
{
cout << "answer1 is the integer " << 9/4;
cout << "nanswer2 is the integer " << 17/3;
return 0;
}
9. (Desk Check) Determine the output of the following program:
#include <iostream>
using namespace std;
int main() // a program illustrating the % operator
{
cout << "The remainder of 9 divided by 4 is " << 9 % 4;
cout << "nThe remainder of 17 divided by 3 is " << 17 % 3;
75
Chapter 2
Arithmetic Operations
return 0;
}
10. (Program) Write a C++ program that displays the results of the expressions 3.0 * 5.0,
7.1 * 8.3 - 2.2, and 3.2 / (6.1 * 5). Calculate the value of these expressions
manually to verify that the displayed values are correct.
11. (Program) Write a C++ program that displays the results of the expressions 15 / 4, 15
% 4, and 5 * 3 - (6 * 4). Calculate the value of these expressions manually to
verify that the displayed values are correct.
2.5 Variables and Declaration Statements
All integer, floating-point, and other values used in a program are stored and retrieved from
the computer’s memory. Conceptually, locations in memory are arranged like the rooms in a
large hotel. Like room numbers in a hotel, each memory location has a unique address.
Before high-level languages such as C++, memory locations were referenced by their
addresses. For example, storing the integer values 45 and 12 in the memory locations 1652
and 2548 (see Figure 2.8) required instructions equivalent to the following:
Put a 45 in location 1652
Put a 12 in location 2548
To add the two numbers just stored and save the result in another memory location, such
as 3000, you need an instruction such as the following:
Add the contents of location 1652
to the contents of location 2548
and store the result in location 3000
Clearly, this method of storage and retrieval is cumbersome. In high-level languages such
as C++, symbolic names, called variables, are used in place of memory addresses. A variable
is simply a name the programmer assigns to refer to computer storage locations. The term
“variable” is used because the value stored in the memory locations assigned to the variable
can change, or vary. For each name the programmer uses, the computer keeps track of the
memory address corresponding to that name. In the hotel room analogy, it’s equivalent to
putting a name on a room’s door and referring to the room by this name, such as calling it the
Blue Room instead of Room 205.
1652 2548
12
45
Memory addresses
Storage for one integer Storage for one integer
Figure 2.8 Enough storage for two integers
76 Problem Solving Using C++
In C++, the selection of variable names is the programmer’s choice, as long as the rules
listed in Section 2.1 for selecting identifier names are observed. These rules are summarized
in the following list:
1. The variable name must begin with a letter or underscore (_) and can contain only
letters, underscores, or digits. It can’t contain blank spaces, commas, or special
symbols, such as ( ) & , $ # . !  ?.
2. A variable name can’t be a keyword (see Table 2.1).
3. A variable name can’t consist of more than 1024 characters.
Additionally, variable names should be mnemonics that give some indication of the
variable’s purpose. For a variable used to store a value that’s the total of other values, a good
name is sum or total. Variable names giving no indication of the value stored, such as
r2d2, linda, and getum, shouldn’t be used. As with function names, variable names can
consist of uppercase and lowercase letters.
Assume the first memory location shown in Figure 2.9, which has the address 1652, is
given the name num1. The memory location 2548 is given the variable name num2, and
memory location 3000 is given the variable name total.
Using these variable names, the operation of storing 45 in location 1652, storing 12 in
location 2548, and adding the contents of these two locations is accomplished by these C++
statements:
num1 = 45;
num2 = 12;
total = num1 + num2;
Each of these statements is called an assignment statement because it tells the computer
to assign (store) a value in a variable. Assignment statements always have an equal sign (=)
and one variable name immediately to the left of the =. The value to the right of the equal
sign is determined first; this value is then assigned to the variable to the left of the equal sign.
The blank spaces in assignment statements are inserted for readability. Assignment state-
ments are explained in more detail in Chapter 3, but for now, just know that you can use
them to store values in variables.
A variable name is useful because it frees programmers from having to think about where
data is physically stored in the computer. You simply use the variable name and let the
compiler worry about where in memory the data is actually stored. Before storing a value in
num1
1652 2548 45
num2 total
12
45 57
Variable names
Memory addresses
Figure 2.9 Naming storage locations
77
Chapter 2
Variables and Declaration Statements
a variable, however, C++ requires clearly declaring the type of data to be stored in it. You
must tell the compiler, in advance, the names of variables used for characters, the names used
for integers, and the names used to store other C++ data types.
Declaration Statements
To name a variable and specify the data type that can be stored in it, you use declaration
statements, which have this general form
dataType variableName;
where dataType designates a valid C++ data type, and variableName is the name you
select for the variable. For example, variables used to hold integer values are declared by
using the keyword int to specify the data type and have this form:
int variableName;
Therefore, the following declaration statement declares sum as the name of a variable
capable of storing an integer value:
int sum;
In addition, the keyword long is used to specify a long integer.10 For example, the
statement
long datenum;
declares datenum as a variable used to store a long integer. When you’re using the long
qualifier, you can also include the keyword int, so the previous declaration can also be
written as follows:
long int datenum;
Variables used to hold single-precision values are declared by using the keyword float,
and variables used to hold double-precision values are declared by using the keyword
double. For example, the statement
float firstnum;
declares firstnum as a variable used to store a single-precision number. Similarly, the
statement
double secnum;
declares that the variable secnum is used to store a double-precision number.
Although declaration statements can be placed anywhere in a function, typically they’re
grouped together and placed after the function’s opening brace. However, a variable must
always be declared before using it, and like all C++ statements, declaration statements must
10
Additionally, the keywords unsigned int are used to specify an integer that can store only non-negative numbers, and the keyword short
specifies a short integer.
78 Problem Solving Using C++
end with a semicolon. A simple main() function containing declaration statements right
after the opening function brace has this general form:
#include <iostream>
using namespace std;
int main()
{
// declaration statements;
// other statements;
return 0;
}
Program 2.7 uses this form in declaring and using four double-precision variables, with
the cout object used to display the contents of one of the variables.
Point of Information
Atomic Data
All the variables declared so far have been used to store atomic data values. An atomic
data value is considered a complete entity and can’t be decomposed into a smaller data
type supported by the language. For example, although an integer can be decomposed
into individual digits, C++ doesn’t have a numerical digit type. Instead, each integer is
regarded as a complete value and, therefore, is considered atomic data. Because the inte-
ger data type supports only atomic data values, it’s said to be an atomic data type. As
you might expect, doubles, chars, and bools are atomic data types, too.
79
Chapter 2
Variables and Declaration Statements
Program 2.7
#include <iostream>
using namespace std;
int main()
{
double grade1; // declare grade1 as a double variable
double grade2; // declare grade2 as a double variable
double total; // declare total as a double variable
double average; // declare average as a double variable
grade1 = 85.5;
grade2 = 97.0;
total = grade1 + grade2;
average = total/2.0; // divide the total by 2.0
cout << "The average grade is " << average << endl;
return 0;
}
The placement of the declaration statements in Program 2.7 is straightforward, although
you’ll see shortly that these four declarations can be combined into a single declaration.
When Program 2.7 runs, the following output is displayed:
The average grade is 91.25
Notice that when a variable name is inserted in a cout statement, the value stored in
the variable is placed on the output stream and displayed.
Just as integer and real (single-precision, double-precision, and long double) variables
must be declared before they can be used, a variable used to store a single character must also
be declared. Character variables are declared by using the keyword char. For example, the
following declaration specifies that ch is a character variable:
char ch;
Program 2.8 illustrates this declaration and the use of cout to display the value stored
in a character variable.
80 Problem Solving Using C++
Program 2.8
#include <iostream>
using namespace std;
int main()
{
char ch; // this declares a character variable
ch = 'a'; // store the letter a in ch
cout << "The character stored in ch is " << ch << endl;
ch = 'm'; // now store the letter m in ch
cout << "The character now stored in ch is "<< ch << endl;
return 0;
}
When Program 2.8 runs, this output is produced:
The character stored in ch is a
The character now stored in ch is m
Notice in Program 2.8 that the first letter stored in the variable ch is a and the second
letter stored is m. Because a variable can be used to store only one value at a time, assigning
m to the variable overwrites the a value automatically.
Multiple Declarations
Variables of the same data type can always be grouped together and declared by using a
single declaration statement, which has this common form:
dataType variableList;
For example, the four separate declarations used in Program 2.7
double grade1;
double grade2;
double total;
double average;
can be replaced with this single declaration statement:
double grade1, grade2, total, average;
Similarly, the two character declarations
char ch;
char key;
81
Chapter 2
Variables and Declaration Statements
can be replaced with this single declaration statement:
char ch, key;
Declaring multiple variables in a single declaration statement requires giving the data
type of variables only once, separating all variable names by commas, and using only one
semicolon to terminate the declaration. The space after each comma is inserted for
readability and isn’t required.
Declaration statements can also be used to store a value in declared variables. For
example, the declaration statement
int num1 = 15;
both declares the variable num1 as an integer variable and sets the value of 15 in the variable.
When a declaration statement is used to store a value in a variable, the variable is said to be
initialized. Therefore, in this example, it’s correct to say the variable num1 has been initialized
to 15. Similarly, the declaration statements
double grade1 = 87.0;
double grade2 = 93.5;
double total;
declare three double-precision variables and initialize two of them. When initializations are
used, good programming practice dictates declaring each initialized variable on a line by
itself. Constants, expressions using only constants (such as 87.0 + 12 - 2), and
expressions using constants and previously initialized variables can be used as initializers for
variables declared within a function. For example, Program 2.7 with declaration initialization
becomes Program 2.7a.
Program 2.7a
#include <iostream>
using namespace std;
int main()
{
double grade1 = 85.5;
double grade2 = 97.0;
double total, average;
total = grade1 + grade2;
average = total/2.0; // divide the total by 2.0
cout << "The average grade is " << average << endl;
return 0;
}
82 Problem Solving Using C++
Notice the blank line after the last declaration statement. Inserting a blank line after
variable declarations placed at the top of a function body is a good programming practice. It
improves a program’s appearance and readability.
An interesting feature of C++ is that variable declarations can be intermixed and even
contained in other statements; the only requirement is that a variable must be declared
before its use. For example, the variable total in Program 2.7a could have been declared
when it was first used with the statement double total = grade1 + grade2. In
restricted situations (such as debugging, described in Section 3.7, or in a for loop, described
in Section 5.4), declaring a variable at its first use can be helpful. In general, however, it’s
preferable not to spread out declarations; instead, group them as concisely and clearly as
possible at the top of each function.
Memory Allocation
The declaration statements you have seen so far have performed both software and hardware
tasks. From a software perspective, declaration statements always provide a list of variables
and their data types. In this software role, variable declarations also help control an otherwise
common and troublesome error caused by misspelling a variable’s name in a program. For
example, a variable named distance is declared and initialized by using this statement:
int distance = 26;
Later in the program, the variable is inadvertently misspelled in this statement:
mpg = distnce / gallons;
In languages that don’t require variable declarations, the program treats distnce as a
new variable and assigns it an initial value of 0 or uses whatever value happens to be in the
variable’s storage area. In either case, a value is calculated and assigned to mpg, and finding
the error or even knowing an error occurred could be difficult. These errors are impossible
in C++, however, because the compiler flags distnce as an undeclared variable. The
compiler can’t, of course, detect when one declared variable is mistakenly typed in place of
another declared variable.
In addition to their software role, declaration statements can also perform a hardware
task. Because each data type has its own storage requirements, the computer can allocate
enough storage for a variable only after knowing the variable’s data type. Variable declarations
provide this information, so they can be used to force the compiler to reserve enough physical
memory storage for each variable. Declaration statements used for this hardware task are also
called definition statements because they define or tell the compiler how much memory is
needed for data storage.
All the declaration statements you have encountered so far have also been definition
statements. Later, you’ll see declaration statements that don’t allocate storage and are used
simply to alert the program to the data types of variables created elsewhere in the program.
Figures 2.10a through 2.10d illustrate the operations set in motion by definition
statements. The figures show that definition statements (or declaration statements that also
allocate memory) “tag” the first byte of each set of reserved bytes with a name. This name
is, of course, the variable’s name, and the computer uses it to locate the starting point of a
variable’s reserved memory area.
After a variable has been declared in a program, typically a programmer uses it to refer
to the variable’s contents (its value). The value’s memory location is generally of little
concern to programmers. The compiler, however, must know where each value is stored and
83
Chapter 2
Variables and Declaration Statements
locate each variable correctly. For this task, the compiler uses the variable name to locate the
first byte of storage previously allocated to the variable. Knowing the variable’s data type
then allows the compiler to store or retrieve the correct number of bytes.
Tells the computer to
int total;
Reserve enough room
for an integer number
“Tag” the first byte of
reserved storage with
the name total
Tells the computer to
4 bytes
Figure 2.10a Defining the integer variable named total
Tells the computer to
float slope;
Reserve enough room
for a single-precision number
“Tag” the first byte of
reserved storage with
the name slope
Tells the computer to
4 bytes
Figure 2.10b Defining the floating-point variable named slope
Tells the computer to
double thrust;
Reserve enough room
for a double-precision number
“Tag” the first byte of
reserved storage with
the name thrust
Tells the computer to
8 bytes
Figure 2.10c Defining the double-precision variable named thrust
84 Problem Solving Using C++
Displaying a Variable’s Address11
Every variable has three major items associated with it: its data type, the value stored in it,
and its address. The value stored in the variable is referred to as the variable’s contents, and
the address of the first memory location used for the variable constitutes its address. The
number of locations actually used for the variable, as you have just seen, depends on the
variable’s data type. Figure 2.11 illustrates the relationship between these three items (type,
contents, and location).
Programmers are usually concerned only with the value assigned to a variable (its
contents) and give little attention to where the value is stored (its address). For example, take
a look at Program 2.9.
11
This topic can be omitted on first reading without loss of subject continuity.
Tells the computer to
char key;
Reserve enough room
for a character
“Tag” the first byte of
reserved storage with
the name key
Tells the computer to
1 byte
Figure 2.10d Defining the character variable named key
Variable
contents
Variable address
One or more bytes in memory
Figure 2.11 A typical variable
85
Chapter 2
Variables and Declaration Statements
Program 2.9
#include <iostream>
using namespace std;
int main()
{
int num;
num = 22;
cout << "The value stored in num is " << num << endl;
return 0;
}
The following output is displayed when Program 2.9 is run:
The value stored in num is 22
Program 2.9 merely prints the value 22, which is the contents of the variable num. You
can go further, however, and ask “Where is the number 22 actually stored?” Although the
answer is “in num,” it’s only half the answer. The variable name num is simply a convenient
symbol for actual memory locations, as shown in Figure 2.12.
To determine the address of num, you can use C++’s address operator, &, which means
“the address of.” Except when used in an expression, the address operator placed in front of
a variable’s name refers to the variable’s address.12 For example, &num means “the address
of num.” Program 2.10 shows you an example of using the address operator.
12
When used in declaration statements that create a reference variable or reference argument (see Chapter 6), the ampersand refers to the data
type preceding it. Therefore, the declaration double &num is read as “num is the address of a double” or, more commonly, “num is a reference
to a double.”
22
Contents of num
4 bytes of memory
Address of first
byte used by num
x x x x
Figure 2.12 The variable num stored somewhere in memory
86 Problem Solving Using C++
Program 2.10
#include <iostream>
using namespace std;
int main()
{
int num;
num = 22;
cout << "The value stored in num is " << num << endl;
cout << "The address of num = " << &num << endl;
return 0;
}
This is the output of Program 2.10:
The value stored in num is 22
The address of num = 0012FED4
Figure 2.13 illustrates the additional address information provided by Program 2.10’s output.
Clearly, the address output by Program 2.10 depends
on the computer used to run the program. Every time
Program 2.10 runs, however, it displays the address of the
first memory location used to store num. As Program 2.10’s
output shows, the address display is in hexadecimal
notation. This display has no effect on how the program
uses addresses internally; it merely gives you a means of
displaying addresses that’s helpful in understanding them.
As you’ll see in Chapters 6 and 12, using addresses, instead
of just displaying them, is an important and powerful
programming tool.
EXERCISES 2.5
1. (Practice) State whether the following variable names are valid. If they are invalid, state
the reason.
prod_a c1234 abcd _c3 12345
newamp watts $total new$al a1b2c3d4
9ab6 sum.of average volts1 finvolt
22
Contents of num
4 bytes of memory
Address of first
byte used by num
0012FED4
Figure 2.13 A more complete
picture of the variable num
87
Chapter 2
Variables and Declaration Statements
2. (Practice) State whether the following variable names are valid. If they are invalid, state
the reason. Also, indicate which of the valid variable names shouldn’t be used because
they convey no information about the variable.
current a243 r2d2 firstnum cc_a1
harry sue c3p0 total sum
maximum okay a awesome goforit
3sum for tot.a1 c$five netpower
3. (Practice) a. Write a declaration statement to declare that the variable count will be
used to store an integer.
b. Write a declaration statement to declare that the variable volt will be used to store a
floating-point number.
c. Write a declaration statement to declare that the variable power will be used to store
a double-precision number.
d. Write a declaration statement to declare that the variable keychar will be used to
store a character.
4. (Practice) Write declaration statements for the following variables:
a. num1, num2, and num3 used to store integer number
b. amps1, amps2, amps3, and amps4 used to store double-precision numbers
c. volts1, volts2, and volts3 used to store double-precision numbers
d. codeA, codeB, codeC, codeD, and codeE used to store characters
5. (Practice) Write declaration statements for the following variables:
a. firstnum and secnum used to store integer
b. speed, acceleration, and distance used to store double-precision numbers
c. thrust used to store a double-precision number
6. (Modify) Rewrite each of these declaration statements as three separate declarations:
a. int month, day = 30, year;
b. double hours, volt, power = 15.62;
c. double price, amount, taxes;
d. char inKey, ch, choice = 'f';
7. (Desk Check) a. Determine what each statement causes to happen in the following
program:
#include <iostream>
using namespace std;
int main()
{
int num1, num2, total;
num1 = 25;
88 Problem Solving Using C++
num2 = 30;
total = num1 + num2;
cout << "The total of " << num1 << " and "
<< num2 << " is " << total << endl;
return 0;
}
b. What output will be printed when the program in Exercise 7a runs?
8. (Practice) What are the three items associated with every variable?
Note for Exercises 9 to 11: Assume that a character requires 1 byte of storage, an integer requires
4 bytes, a single-precision number requires 4 bytes, and a double-precision number requires 8
bytes. Variables are assigned storage in the order they’re declared. (Review Section 1.6 if you’re
unfamiliar with the concept of a byte.) Refer to Figure 2.14 for these exercises.
N
O
T
E
9. (Practice) a. Using Figure 2.14 and assuming the variable name rate is assigned to the
byte at memory address 159, determine the addresses corresponding to each variable
declared in the following statements. Also, fill in the correct number of bytes with the
initialization data included in the declaration statements. (Use letters for the characters,
not the computer codes that would actually be stored.)
float rate;
char ch1 = 'M', ch2 = 'E', ch3 = 'L', ch4 = 'T';
double taxes;
int num, count = 0;
b. Repeat Exercise 9a, but substitute the actual byte patterns that a computer using the
ASCII code would use to store characters in the variables ch1, ch2, ch3, and ch4.
(Hint: Use Appendix B.)
10. (Practice) a. Using Figure 2.14 and assuming the variable named cn1 is assigned to the
byte at memory address 159, determine the addresses corresponding to each variable
declared in the following statements. Also, fill in the correct number of bytes with the
initialization data included in the declaration statements. (Use letters for the characters,
not the computer codes that would actually be stored.)
Addresses
159 160 161 162 163 164 165 166
167 168 169 170 171 172 173 174
175 176 177 178 179 180 181 182
183 184 185 186 187 188 189 190
Figure 2.14 Memory bytes for Exercises 9 to 11
89
Chapter 2
Variables and Declaration Statements
char cn1 = 'P', cn2 = 'E', cn3 = 'R', cn4 = 'F', cn5 = 'E';
char cn6 = 'C', cn7 = 'T', key = '', sch = ''', inc = 'A';
char inc1 = 'T';
b. Repeat Exercise 10a, but substitute the actual byte patterns a computer using the ASCII
code would use to store characters in each of the declared variables. (Hint: Use Table 2.3.)
11. (Practice) Using Figure 2.14 and assuming the variable name miles is assigned to the
byte at memory address 159, determine the addresses corresponding to each variable
declared in the following statements:
float miles;
int count, num;
double dist, temp;
2.6 A Case Study: Radar Speed Traps
In this section, the software development procedure explained in Section 1.3 is applied to a
specific programming problem. Although each problem you explore in the case studies in
Part One is different, you’ll see that this software development procedure works for all of
them to produce a complete program. It forms the foundation for all programs developed in
Part One of this book.
A highway-patrol speed detection radar emits a beam of microwaves at a frequency
designated as fe. The beam is reflected off an approaching car, and the radar unit picks up
and analyzes the reflected beam, fr. The reflected beam’s frequency is shifted slightly from
fe to fr because of the car’s motion. The relationship between the speed of the car, v, in miles
per hour (mph), and the two microwave frequencies is
v
f f
f f
mph
r e
r e
= ×
( ) +






6 685 108
.
-
where the emitted waves have a frequency of fe = 2 × 1010
sec-1
. Using the given formula,
you’ll write a C++ program, using the software development procedure, to calculate and
display the speed corresponding to a received frequency of 2.000004 × 1010
sec-1
.
Step 1 Analyze the Problem
For this problem, a single output is required: the speed of the car. The input items required
to solve for the speed are the emitted frequency, fe, and the received frequency, fr.
Step 2 Develop a Solution
The algorithm for transforming the three input items into the required output item is given
by the formula v = 6.685 × 108
(fr - fe) / (fr + fe). Therefore, the complete algorithm for the
program solution is as follows:
Assign values to fr and fe
Calculate the speed using the formula v = 6.685 × 108
(fr - fe) / (fr + fe)
Display the speed
90 Problem Solving Using C++
A hand calculation, using the data fe = 2 × 1010
sec-1
and fr = 2.000004 × 1010
sec-1
, yields
a speed of 66.85 mph.
Step 3 Code the Solution
Program 2.11 provides the necessary code.
Program 2.11
#include <iostream>
using namespace std;
int main()
{
double speed, fe, fr;
fe = 2e10;
fr = 2.0000004e10;
speed = 6.685e8 * (fr - fe) / (fr + fe);
cout << "The speed is " << speed << " miles/hour " << endl;
return 0;
}
Program 2.11 begins with an #include preprocessor command followed by a main()
function. The main() function in Program 2.11 contains one declaration statement, three
assignment statements, and one output statement. The assignment statements fe = 2e10;
and fr = 2.0000004e10; are used to initialize the fe and fr variables. The assignment
statement
speed = 6.685e8 * (fr - fe) / (fr + fe);
calculates a value for the variable speed. When Program 2.11 is compiled and executed, the
following output is produced:
The speed is 66.85 miles/hour
Step 4 Test and Correct the Program
The last step in the development procedure is to test the output. Because the single calculation
and displayed value agree with the previous hand calculation, you have verified that the program
operates correctly. Now you can use the program for different values of received frequencies.
Note that if the parentheses weren’t placed correctly in the assignment statement that calculates
a value for speed, the displayed value wouldn’t agree with your previous hand calculation. This
would alert you to the fact that there’s an error in the program.
91
Chapter 2
A Case Study: Radar Speed Traps
EXERCISES 2.6
1. (Modify) a. Modify Program 2.11 to calculate the speed of a car whose received radar
frequency is 2.00000035 × 1010
sec-1
.
b. Compile and execute the program written for Exercise 1a.
2. (Modify) a. Modify Program 2.11 to determine the frequency returned by a car traveling
at 55 mph. Your program should produce the following display (replacing the underlines
with the values your program calculates):
The returned frequency corresponding to 55 mph is _____
b. Compile and execute the program written for Exercise 2a. Make sure to do a hand
calculation so that you can verify the results your program produces.
c. After verifying the results of the program written in Exercise 2a, modify the program
to calculate the return frequency of a car traveling at 75 mph.
3. (Telephony) In a directly connected telephone network, all telephones are directly con-
nected and don’t require a central switching station to establish calls between two
telephones. The number of lines needed to maintain a directly connected network for n
telephones is given by this formula:
no of lines needed
n n
.
( )
=
-1
2
For example, directly connecting four telephones requires six separate lines (see Figure 2.15).
Adding a fifth telephone to this network requires an additional 4 lines, for a total of 10 lines.
line 6 line 5
line 4
line 3
line 1
line 2
Telephone
#3
Telephone
#4
Telephone
#2
Telephone
#1
Figure 2.15 Directly connecting four telephones
92 Problem Solving Using C++
a. Using the given formula, write a C++ program that determines the number of lines
required for directly connecting 100 telephones. The input for this problem is the
number of telephones, denoted as n in the formula, and the output is the total num-
ber of lines required to directly connect the input number of telephones.
b. Compile and execute the program written for Exercise 3a.
4. (Modify) Modify the program you wrote for Exercise 3 and include a new variable to
represent the additional number of telephones to be connected to an existing network,
and initialize this variable to 10. For this program, two outputs are required: the number
of direct lines for 100 telephones and the additional number of lines needed when 10
telephones are added to the existing network.
5. (Conversion) a. Design, write, compile, and execute a C++ program to convert tempera-
ture in degrees Fahrenheit to degrees Celsius. This is the equation for this conversion:
Celsius = 5.0/9.0 (Fahrenheit - 32.0)
Have your program convert and display the Celsius temperature corresponding to 98.6
degrees Fahrenheit. Your program should produce the following display (replacing the
underlines with the correct values):
For a Fahrenheit temperature of ___ degrees,
the equivalent Celsius temperature is ___ degrees.
b. Check the values computed by your program by hand. After verifying that your pro-
gram is working correctly, modify it to convert 86.5 degrees Fahrenheit to its equiva-
lent Celsius value.
6. (Electrical Eng.) a. Write, compile, and execute a C++ program to calculate the resis-
tance of a series circuit consisting of twelve 56-ohm, twenty 39-ohm, thirty-two 27-ohm,
and twenty-seven 15-ohm resistors. The total resistance of a series circuit is the sum of all
individual resistances. Your program should produce the following display (replacing the
xxxx with the actual resistance value your program calculates):
The total resistance, in ohms, is xxxx
b. Manually check the values computed by your program. After verifying that your pro-
gram is working correctly, modify it to calculate the resistance of a series circuit con-
sisting of seventeen 39-ohm resistors, nineteen 27-ohm resistors, and forty-two 15-ohm
resistors.
7. (Thermodynamics) a. Design, write, compile, and execute a program that determines
the work performed by a piston engine providing a force of 1000 N over a distance of 15
centimeters. The following formula is used to determine the work, W, performed:
W = F d
F is the force provided by the piston in Newtons.
d is the distance the piston moves in meters.
b. Manually check the values computed by your program. After verifying that your pro-
gram is working correctly, modify it to determine the work performed by six pistons,
each providing a force of 1500 N over a distance of 20 centimeters.
8. (Civil Eng.) a. Design, write, compile, and execute a program that determines the stress on
a steel I-beam having a rectangular moment of inertia of 21.4 in4
, and a height of 6 inches,
93
Chapter 2
A Case Study: Radar Speed Traps
when a load of 700 lbs is placed 8 feet from the fixed end. The stress placed on the fixed
end of a symmetrical steel I-beam, as shown in Figure 2.16, can be determined by this
formula:
S
L d c
I
=
S is the stress in lbs/in2
.
L is the weight, in lbs, of the load placed on the beam.
I is the beam’s rectangular moment of inertia in units of in4
.
d is the distance in inches the load is placed from the fixed end of the beam (techni-
cally referred to as the “moment arm”).
c is one-half the height in inches of a symmetrical beam.
b. Check the values computed by your program by hand. After verifying that your pro-
gram is working correctly, modify it to determine the stress when the same load is
placed at the end of an 8-foot 2” x 4” wooden beam, with a rectangular moment of
inertia of 10.67 in4
.
2.7 Common Programming Errors
Part of learning any programming language is making the elementary mistakes commonly
encountered when you begin using the language. These mistakes tend to be quite
frustratingbecause each language has its own set of common programming errors waiting for
the unwary. When you start programming in C++, common errors include the following.
1. Omitting the parentheses after main().
2. Omitting or incorrectly typing the opening brace, {, that signifies the start of a
function body.
3. Omitting or incorrectly typing the closing brace, }, that signifies the end of a function.
4. Misspelling the name of an object or function, such as typing cot instead of cout.
5. Forgetting to enclose a string sent to cout with quotation marks.
L
h
d
Figure 2.16 Determining the stress on a symmetrical I-beam
94 Problem Solving Using C++
6. Forgetting to separate data streams sent to cout with an insertion symbol, <<.
7. Omitting the semicolon at the end of each C++ statement.
8. Adding a semicolon at the end of the #include preprocessor command.
9. Forgetting the n to indicate a new line.
10. Incorrectly typing the letter O for the number 0 or vice versa. Incorrectly typing the
letter l for the number 1 or vice versa.
11. Forgetting to declare all variables used in a program. The compiler detects this error,
and an error message is generated for all undeclared variables.
12. Storing an inappropriate data type in a declared variable. The compiler detects this error,
and the assigned value is converted to the data type of the variable it’s assigned to.
13. Using a variable in an expression before a value has been assigned to the variable.
The value that happens to be in the variable when the variable is used is the value
that’s used when the expression is evaluated. As such, the result of the expression is
meaningless.
14. Dividing integer values incorrectly. This error is usually hidden in a larger expression
and can be troublesome to detect. For example, the expression
3.425 + 2/3 + 7.9
yields the same result as the expression
3.425 + 7.9
because the integer division of 2/3 is 0.
15. Mixing data types in the same expression without clearly understanding the effect.
Because C++ allows expressions with “mixed” data types, understanding the order
of evaluation and the data type of all intermediate calculations is important. As a
general rule, it’s better never to mix data types in an expression unless you want a
specific effect.
Errors 3, 5, 7, 8, and 9 in this list are the most common with beginning programmers, and
even experienced programmers occasionally make error 10. A worthwhile practice is writing
a program and introducing each error, one at a time, to see what error messages, if any, your
compiler produces. When these error messages appear because of inadvertent mistakes,
you’ll have had experience in understanding the messages and correcting the errors.
A major error that all beginning programmers make is rushing to code and running a
program before fully understanding its requirements and the algorithms and procedures used
to produce the desired result. A symptom of this haste is the lack of a written program or
even a program outline. Many problems can be caught just by checking a copy of the program
(handwritten or onscreen) before it’s compiled.
2.8 Chapter Summary
1. A C++ program consists of one or more modules called functions. One of these functions
must be called main(). The main() function identifies the starting point of a C++
program.
2. The simplest C++ program consists of the single function main().
95
Chapter 2
Chapter Summary
3. Following the function name, the body of a function has the following general form:
{
All C++ statements in here;
}
4. All C++ statements must be terminated by a semicolon.
5. Four types of data were introduced in this chapter: integer, floating-point, character, and
Boolean. C++ recognizes each of these data types, in addition to other types you learn
about in later chapters.
6. The cout object can be used to display all C++ data types.
7. When the cout object is used in a program, the preprocessor command #include
<iostream> and the statement using namespace std; must be placed at the top
of the program. The #include <iostream> preprocessor command does not end
with a semicolon.
8. Every variable in a C++ program must be declared and the type of value it can store must
be specified. Declaration statements can be placed anywhere in the function, although
a variable can be used only after it’s declared. Variables can also be initialized when they
are declared. Additionally, variables of the same type can be declared with a single
declaration statement. Variable declaration statements have this general form:
dataType variableName(s);
9. A simple C++ program containing declaration statements has this typical form:
#include <iostream>
using namespace std;
int main()
{
// declaration statements;
// other statements;
return 0;
}
10. Declaration statements always play the software role of informing the compiler of a
function’s valid variable names. When a variable declaration also causes the computer to
set aside memory locations for the variable, the declaration statement is called a
definition statement. (All declarations used in this chapter have also been definition
statements.)
11. The sizeof() operator can be used to determine the amount of storage reserved for
variables.
Programming Projects for Chapter 2
1. (General Math) a. Design, write, compile, and execute a C++ program that calculates
and displays the perimeter of a two-dimensional triangle with sides a = 1 in, b = 1.5 in,
and c = 2 in, as shown in Figure 2.17. The perimeter is given by this formula:
perimeter = a + b + c
96 Problem Solving Using C++
b. Manually check the values computed by your program. After verifying that your
program is working correctly, modify it to determine the perimeter of a two-
dimensional triangle with sides a = 1.62 in, b = 2.13 in, and c = 3.2 in.
2. (General Math) a. Design, write, compile, and execute a C++ program that calculates
and displays the area of a two-dimensional triangle, such as the one in Figure 2.17, with
a base of 1 in and a height of 1.5 in. The area is given by this formula:
Area = ½ (base) × (height)
b. Manually check the values computed by your program. After verifying that your
program is working correctly, modify it to determine the area of a two-dimensional
triangle with a base of 2 in and a height of 1.67 in.
3. (General Math) a. Design, write, compile, and execute a C++ program to calculate the
volume of a sphere with a radius, r, of 3 in. The volume is given by this formula:
Volume
r
=
4
3
3
π
b. Manually check the values computed by your program. After verifying that your
program is working correctly, modify it to determine the volume of a cube with a
radius of 1.67 in.
4. (Physics) a. Design, write, compile, and execute a C++ program to calculate the elapsed
time it takes to make a 183.67 mile trip. This is the formula for computing elapsed time:
elapsed time = total distance / average speed
The average speed during the trip is 58 mph.
b. Manually check the values computed by your program. After verifying that your
program is working correctly, modify it to determine the elapsed time it takes to make
a 372-mile trip at an average speed of 67 mph.
5. (Numerical) a. Design, write, compile, and execute a C++ program to calculate the sum
of the integers from 1 to 100. This is the formula for calculating this sum:
sum = (n/2) (2 × a + (n - 1)d)
n is the number of integers to be added.
a is the first number.
d is the difference between each number.
a c
b
height
base
Figure 2.17 A two-dimensional triangle
97
Chapter 2
Programming Projects
b. Manually check the values computed by your program. After verifying that your
program is working correctly, modify it to determine the sum of the integers from 100
to 1000.
6. (Physics and Electrical) The energy, E, of a photon, in Joules, J, is provided by this
formula:
E = P × f
P is 6.6256 × 10-34
Joules/sec (known as Planck’s constant).
f is frequency in Hertz (Hz) of the photon.
a. Given that the photon frequency of visible light is in the 3.84 × 1014
Hz to 7.69 × 1014
Hz range, design, write, compile, and execute a C++ program to calculate the energy
of light with a photon frequency of 5.7 × 1014
. Verify the result produced by your
program with a hand calculation.
b. After verifying that your program is working correctly, use it to determine the photon
energy output of a 60 Hz power line.
7. (Physics) a. The weight of an object on Earth is a measurement of the downward force
on the object caused by Earth’s gravity. The formula for this force is determined by using
Newton’s Second Law:
F = M × Ae
F is the object’s weight.
M is the object’s mass.
Ae is the acceleration caused by Earth’s gravity (32.2 ft/sec2
= 9.82 m/s2
).
Given this information, design, write, compile, and execute a C++ program to calculate
the weight in lbf of a person having a mass of 4 lbm. Verify the result produced by your
program with a hand calculation.
b. After verifying that your program is working correctly, use it to determine the weight,
on Earth, of a person having a mass of 3.2 lbm.
8. (Physics) a. Rewrite the program you wrote for Exercise 7 to provide the mass of a
person as an output, given his or her weight as an input to the program. Use your program
to determine the mass of a person who weighs 140 lbf on Earth.
b. Modify the program written for Exercise 7a to also output the person’s weight on Mars
and the moon. The pull of gravity on Mars is 12.54 ft/sec2
= 3.728 m/s2
, and on the
moon is 5.33 ft/sec2
= 1.625 m/s2
.
9. (Civil Eng.) The maximum load that can be placed at the end of a symmetrical wooden
beam, such as the rectangular beam shown in Figure 2.18, can be calculated as the following:
L
S I
d c
=
×
×
L is the maximum weight in lbs of the load placed on the beam.
S is the stress in lbs/in2
.
I is the beam’s rectangular moment of inertia in units of in4
.
98 Problem Solving Using C++
d is the distance in inches that the load is placed from the fixed end of the beam (the
“moment arm”).
c is one-half the height in inches of the symmetrical beam.
For a 2” x 4” wooden beam, the rectangular moment of inertia is given by this formula:
I
base height
=
×
=
×
=
3 3
12
2 4
12
10 67
.
c = ½(4 in) = 2 in
a. Using this information, design, write, compile, and execute a C++ program that
computes the maximum load in lbs that can be placed at the end of an 8-foot 2” x 4”
wooden beam so that the stress on the fixed end is 3000 lb/in2
.
b. Use the program developed in Exercise 9a to determine the maximum load in lbs that
can be placed at the end of a 3” x 6” wooden beam so that the stress on the fixed end
is 3000 lbs/in2
.
10. (Civil Eng.) Modify the program written for Exercise 9 to determine the maximum load
that can be placed at the end of an 8-foot I-beam, shown in Figure 2.19, so that the stress
on the fixed end is 20,000 lbs/in2
. Use the fact that this beam’s rectangular moment of
inertia is 21.4in4
and the value of c is 3 in.
11. (Mechanical Eng.) The minimum radius required for a cylindrical rod, such as one
supporting a bicycle pedal (see Figure 2.20), to provide enough support for the pressure
h = 4"
d = 8'
Figure 2.18 Calculating a symmetrical wooden beam’s maximum load
99
Chapter 2
Programming Projects
exerted by the rider’s foot yet not exceed the stress placed on the crank arm’s sprocket
attachment, is provided by this formula:
r
d P
S
3
=
×
×
π
r is the radius of the cylindrical rod in inches.
d is the length of the crank arm in inches.
P is the weight placed on the pedal in lbs.
S is the stress in lbs/in2
.
Using this information, design, write, compile, and execute a C++ program that computes
the value of r for a crank arm that is 7 inches long, accommodates a maximum weight of
300 lbs, and is able to sustain a stress of 10,000 lbs/in2
.
L
h
d
Figure 2.19 Calculating an I-beam’s maximum load
d
Figure 2.20 Determining the minimum radius of a bicycle’s crank arm
100 Problem Solving Using C++
Engineering and Scientific Disciplines
Thermal Science
Thermal science is the field of engineering that includes both thermodynamics and
heat transfer. Thermodynamics developed as a science, starting in the early 19th cen-
tury, in response to the development of steam engines at that time. The intent was to
understand the physical laws governing these engines in an effort to increase their
efficiency. This led to analyzing and understanding the effects of temperature, pressure,
and volume on steam engines and how heat moved from a hot boiler to a colder con-
denser and the maximum amount of work that could be generated from this flow. It
now constitutes a science that includes four basic laws, known as the 0th, 1st, 2nd,
and 3rd laws of thermodynamics.
Using these four laws, thermodynamics more broadly applies to large-scale systems,
such as a class of engines (diesel, gas turbine, jet, rocket, and so forth) or the complete
solar system. The central concept of these thermodynamic laws is energy, which is the
ability to do work, and the relationship between heat, energy, and work. The fields of
chemistry, chemical engineering, aerospace, mechanical engineering, biomedical engi-
neering, material science, fluid mechanics, and physics make use of thermodynamic
effects.
Heat transfer, a field derived from the 1st and 2nd laws of thermodynamics, is
technically defined as the movement of energy between substances of different
temperatures. Central to heat transfer is the concept of temperature, which is a mea-
surement of the motion of atoms and molecules in a substance. Temperature deter-
mines the direction of heat flow between two objects placed in contact. If no heat
flow occurs, the two objects have the same temperature (a consequence of the 1st
law); otherwise, heat flows from the hotter object to the colder object (a consequence
of the 2nd law). Heat transfer uses these three modes of transfer:
앫 Conduction is the transfer of heat through a substance caused by molecular
movement in the substance. Examples are the transfer of heat through a metal
rod if one side of the rod is at a higher temperature than the other, and heat loss
through a heated house when the outside temperature is colder than the inside.
앫 Convection is the transfer of heat by the motion of a heated fluid, such as water
or air. An example is the expansion of hot air into cooler air.
앫 Radiation is the transfer of heat away from an object emitting electromagnetic
waves. An example is the electromagnetic waves emitted by the sun.
Each transfer occurs over time, so heat transfer calculations are typically concerned
with determining the rate of transfer initially. Given the rate, the total amount of heat
transferred over a fixed interval of time can always be calculated.
101
Chapter 2
Programming Projects
This page intentionally left blank
Chapter
3
Assignment,
Formatting, and
Interactive Input
3.1 Assignment Operations
3.2 Formatting Numbers for
Program Output
3.3 Using Mathematical Library
Functions
3.4 Program Input Using cin
3.5 Symbolic Constants
3.6 A Case Study: Acid Rain
3.7 A Closer Look: Programming
Errors
3.8 Common Programming Errors
3.9 Chapter Summary
In Chapter 2, you explored how results are displayed with C++’s cout statement and how numerical
data is stored and processed by using variables and assignment statements. In this chapter, you complete
your introduction to C++ by learning about additional processing and input capabilities.
3.1 Assignment Operations
You learned about simple assignment statements in Chapter 2. An assignment statement is
the most basic C++ statement for assigning values to variables and performing computations.
This statement has the following syntax:
variable = expression;
The simplest expression in C++ is a single constant. In the following assignment
statements, the operand to the right of the equal sign is a constant:
length = 25;
width = 17.5;
In these assignment statements, the value of the constant to the right of the equal sign
is assigned to the variable on the left of the equal sign. Note that the equal sign in C++
doesn’t have the same meaning as an equal sign in algebra. The equal sign in an assignment
statement tells the computer first to determine the value of the operand to the right of the
equal sign, and then to store (or assign) that value in the locations associated with the variable
to the left of the equal sign. For example, the C++ statement length = 25; is read
“length is assigned the value 25.” The blank spaces in the assignment statement are
inserted for readability only.
Recall that a variable can be initialized when it’s declared. If an initialization isn’t done
in the declaration statement, the variable should be assigned a value with an assignment
statement or input operation before it’s used in any computation. Subsequent assignment
statements can, of course, be used to change the value assigned to a variable. For example,
assume the following statements are executed one after another, and slope wasn’t initialized
when it was declared:
slope = 3.7;
slope = 6.28;
The first assignment statement assigns the value of 3.7 to the variable named slope.1
The next assignment statement causes the computer to assign a value of 6.28 to slope. The
3.7 that was in slope is overwritten with the new value of 6.28 because a variable can store
only one value at a time. Sometimes it’s useful to think of the variable to the left of the equal
sign as a temporary parking spot in a huge parking lot. Just as a parking spot can be used by
only one car at a time, each variable can store only one value at a time. “Parking” a new value
in a variable automatically causes the program to remove any value parked there previously.
In addition to being a constant, the operand to the right of the equal sign in an
assignment statement can be a variable or any other valid C++ expression. An expression is
any combination of constants, variables, and function calls that can be evaluated to yield a
result. Therefore, the expression in an assignment statement can be used to perform
calculations by using the arithmetic operators introduced in Section 2.4. The following are
examples of assignment statements using expressions containing these operators:
sum = 3 + 7;
diff = 15 – 6;
product = .05 * 14.6;
tally = count + 1;
newtotal = 18.3 + total;
taxes = .06 * amount;
totalWeight = factor * weight;
average = sum / items;
slope = (y2 - y1) / (x2 - x1);
1
Because it’s the first time a value is explicitly assigned to this variable, it’s often referred to as an “initialization.” This term stems from historical
usage that said a variable was initialized the first time a value was assigned to it. Under this usage, it’s correct to say that “slope is initialized
to 3.7.” From an implementation viewpoint, however, this statement is incorrect because the C++ compiler handles an assignment operation
differently from an initialization; an initialization can happen only when a variable is created by a declaration statement. This difference is
important only when using C++’s class features and is explained in detail in Section 10.1.
104 Assignment, Formatting, and Interactive Input
As always in an assignment statement, the program first calculates the value of the
expression to the right of the equal sign, and then stores this value in the variable to the left
of the equal sign. For example, in the assignment statement totalWeight = factor *
weight;, the arithmetic expression factor * weight is evaluated first to yield a result.
This result, which is a number, is then stored in the variable totalWeight.
In writing assignment expressions, you must be aware of two important considerations.
Because the expression to the right of the equal sign is evaluated first, all variables used in
the expression must previously have been given valid values if the result is to make sense.
For example, the assignment statement totalWeight = factor * weight; causes a
valid number to be stored in totalWeight only if the programmer takes care to assign valid
numbers first to factor and then to weight. Therefore, the following sequence of
statements tells you the values used to obtain the result that will be stored in totalWeight:
factor = 1.06;
weight = 155.0;
totalWeight = factor * weight;
Figure 3.1 illustrates the values stored in the variables factor, weight, and
totalWeight.
The second consideration is that because the value of an expression is stored in the
variable to the left of the equal sign, only one variable can be listed in this position. For
example, the assignment statement
amount + 1892 = 1000 + 10 * 5;
is invalid. The expression on the right evaluates to the integer 1050, which can only be stored
in a variable. Because amount + 1892 isn’t a valid variable name, the compiler doesn’t
know where to store the calculated value.
Program 3.1 illustrates using assignment statements to calculate the volume of a cylinder.
As shown in Figure 3.2, the volume of a cylinder is determined by the formula volume = ␲r 2
h,
where r is the radius of the cylinder, h is the height, and ␲ is the constant 3.1416 (accurate
to four decimal places).
1.06 155.0 164.30
factor weight totalWeight
Figure 3.1 Values stored in variables
h = 16
r = 2.5
Figure 3.2 Determining the volume of a cylinder
105
Chapter 3
Assignment Operations
Program 3.1
// this program calculates the volume of a cylinder,
// given its radius and height
#include <iostream>
using namespace std;
int main()
{
double radius, height, volume;
radius = 2.5;
height = 16.0;
volume = 3.1416 * radius * radius * height;
cout << "The volume of the cylinder is " << volume << endl;
return 0;
}
When Program 3.1 is compiled and executed, this is the output:
The volume of the cylinder is 314.16
Take a look at the flow of control the computer uses in executing Program 3.1. Program
execution begins with the first statement in the body of the main() function and continues
sequentially, statement by statement, until the closing brace of main() is encountered.
This sequential flow of control is true for all programs. The computer works on one
statement at a time, executing that statement with no knowledge of what the next statement
will be. This sequential execution explains why all operands used in an expression must have
values assigned to them before the expression is evaluated. When the computer executes this
statement in Program 3.1,
volume = 3.1416 * radius * radius * height;
it uses whatever value is stored in the variables radius and height at the time the
assignment statement is executed.2 If no values have been specifically assigned to these
variables before they’re used in the assignment statement, the computer uses whatever
values happen to occupy these variables when they are referenced. (Most C++ compilers
initialize all variables to zero automatically.) The computer doesn’t “look ahead” to see
whether you assign values to these variables later in the program.
In C++, the equal sign, =, used in assignment statements is an operator, which differs
from the way most other high-level languages process this symbol. In C++ (as in C), the =
symbol is called the assignment operator, and an expression using this operator, such as
interest = principal * rate, is an assignment expression. Because the assignment
2
Because C++ doesn’t have an exponentiation operator, the square of the radius is obtained by the term radius * radius. Section 3.3
introduces C++’s power function pow(), which allows you to raise a number to a power.
106 Assignment, Formatting, and Interactive Input
operator has a lower precedence than any other arithmetic operator, the value of any
expression to the right of the equal sign is evaluated first, before the assignment.
Like all expressions, an assignment expression has a value, which is the value assigned
to the variable on the left of the assignment operator. For example, the expression a = 5
assigns a value of 5 to the variable a and results in the expression also having a value of 5.
The expression’s value can always be verified by using a statement such as the following:
cout << "The value of the expression is " << (a = 5);
This statement displays the value of the expression, not the contents of the variable a.
Although both the variable’s contents and the expression have the same value, it’s worth
realizing that you’re dealing with two distinct entities.
From a programming perspective, it’s the actual assignment of a value to a variable that’s
important in an assignment expression; the final value of the assignment expression is of little
consequence. However, the fact that assignment expressions have a value has implications
that must be considered when you learn about C++’s relational operators, which are explained
in the next chapter (Section 4.1).
Any expression terminated by a semicolon becomes a C++ statement. The most common
example is the assignment statement, which is simply an assignment expression terminated
with a semicolon. For example, terminating the assignment expression a = 33 with a
semicolon results in the assignment statement a = 33;, which can be used in a program on
a line by itself.
Because the equal sign is an operator in C++, multiple assignments are possible in the
same expression or its equivalent statement. For example, in the expression a = b = c =
25, all the assignment operators have the same precedence. Because the assignment operator
has a right-to-left associativity, the final evaluation proceeds in this sequence:
c = 25
b = c
a = b
This sequence of expressions, which has the effect of assigning the number 25 to each
variable, can be represented as:
a = (b = (c = 25))
Appending a semicolon to the original expression results in this multiple assignment
statement:
a = b = c = 25;
This statement assigns the value 25 to the three variables, equivalent to the following order:
c = 25;
b = 25;
a = 25;
Coercion
When working with assignment statements, keep in mind the data type assigned to values
on both sides of the expression because data type conversions occur across assignment
operators. In other words, the value of the expression to the right of the assignment operator
is converted to the data type of the variable to the left of the assignment operator. This type
107
Chapter 3
Assignment Operations
of conversion is called a coercion because the value assigned to the variable on the left side
of the assignment operator is forced into the data type of the variable to which it’s assigned.
An example of a coercion occurs when an integer value is assigned to a real variable; this
assignment causes the integer to be converted to a real value. Similarly, assigning a real value
to an integer variable forces conversion of the real value to an integer, which always results
in losing the fractional part of the number because of truncation. For example, if temp is an
integer variable, the assignment temp = 25.89 causes the integer value 25 to be stored in
the integer variable temp.3
A more complete example of data type conversions, which includes both mixed-mode
and assignment conversion, is the evaluation of the expression
a = b * d
where a and b are integer variables and d is a single-precision variable. When the mixed-mode
expression b * d is evaluated,4 the value of d used in the expression is converted to a
double-precision number for purposes of computation. (The value stored in d remains
a single-precision number.) Because one of the operands is a double-precision variable, the value
of the integer variable b is converted to a double-precision number for the computation. (Again,
the value stored in b remains an integer.) The resulting value of the expression b * d is a
double-precision number. Finally, data type conversion across the assignment operator comes
into play. Because the left side of the assignment operator is an integer variable, the double-
precision value of the expression (b * d) is truncated to an integer value and stored in the
variable a.
Assignment Variations
Although only one variable is allowed immediately to the left of the equal sign in an
assignment expression, the variable to the left of the equal sign can also be used to the right.
For example, the assignment expression sum = sum + 10 is valid. Clearly, as an algebraic
equation, sum could never be equal to itself plus 10. In C++, however, sum = sum + 10
is not an equation—it’s an expression evaluated in two major steps: First, the value of sum
3
The correct integer portion is retained only when it’s within the range of integers the compiler allows.
4
Review the precedence and associativity rules in Section 2.4 for the evaluation of mixed-mode expressions, if necessary.
Point of Information
lvalues and rvalues
The terms lvalue and rvalue are often used in programming technology. These
terms are language independent and are used to designate the following: An lvalue
can have a value assigned to it, but an rvalue can’t.
In both C and C++, an lvalue can appear on both the left and right sides of an
assignment operator, but an rvalue can appear only to the right of an assignment
operator. All the variables you have encountered can be an lvalue or rvalue, but a
number can be only an rvalue. Not all variables, however, can be lvalues and
rvalues. For example, an array type, introduced in Chapter 7, can’t be an lvalue or
rvalue, but elements in an array can be both.
108 Assignment, Formatting, and Interactive Input
+ 10 is calculated, and second, the computed value is stored in sum. See whether you can
determine the output of Program 3.2.
Program 3.2
#include <iostream>
using namespace std;
int main()
{
int sum;
sum = 25;
cout << "The number stored in sum is " << sum << endl;
sum = sum + 10;
cout << "The number now stored in sum is " << sum << endl;
return 0;
}
In Program 3.2, the assignment statement sum = 25; tells the computer to store the
number 25 in sum, as shown in Figure 3.3.
The first cout statement displays the value stored in sum with the message The number
stored in sum is 25. The second assignment statement, sum = sum + 10;, causes the
program to retrieve the 25 stored in sum and add 10 to this number, yielding 35. The number
35 is then stored in the variable to the left of the equal sign, which is the variable sum. The 25
that was in sum is simply overwritten with the new value of 35 (see Figure 3.4).
25
sum
Figure 3.3 The integer 25 is stored in sum
25
sum New value
(35)
is stored
Old value is
overwritten
Figure 3.4 sum = sum + 10; causes a new value to be stored in sum
109
Chapter 3
Assignment Operations
Assignment expressions such as sum = sum + 25, which use the same variable on both
sides of the assignment operator, can be written by using the following shortcut assignment
operators:
+= –= *= /= %=
For example, the expression sum = sum + 10 can be written as sum += 10. Similarly,
the expression price *= rate is equivalent to the expression price = price * rate.
In using these new assignment operators, note that the variable to the left of the assignment
operator is applied to the complete expression on the right. For example, the expression
price *= rate + 1 is equivalent to the expression price = price * (rate + 1),
not price = price * rate + 1.
Accumulating
Assignment expressions, such as sum += 10 or its equivalent, sum = sum + 10, are
common in programming. These expressions are required in accumulating subtotals when
data is entered one number at a time. For example, if you want to add the numbers 96, 70,
85, and 60 in calculator fashion, the following statements could be used:
Statement Value in sum
sum = 0; 0
sum = sum + 96; 96
sum = sum + 70; 166
sum = sum + 85; 251
sum = sum + 60; 311
The first statement initializes sum to 0, which removes any number stored in sum that
would invalidate the final total (a “garbage value”). As each number is added, the value
stored in sum is increased accordingly. After completion of the last statement, sum contains
the total of all the added numbers. Program 3.3 illustrates the effect of these statements by
displaying sum’s contents after each addition.
110 Assignment, Formatting, and Interactive Input
Program 3.3
#include <iostream>
using namespace std;
int main()
{
int sum;
sum = 0;
cout << "The value of sum is initially set to " << sum << endl;
sum = sum + 96;
cout << " sum is now " << sum << endl;
sum = sum + 70;
cout << " sum is now " << sum << endl;
sum = sum + 85;
cout << " sum is now " << sum << endl;
sum = sum + 60;
cout << " The final sum is " << sum << endl;
return 0;
}
Program 3.3 displays this output:
The value of sum is initially set to 0
sum is now 96
sum is now 166
sum is now 251
The final sum is 311
Although Program 3.3 isn’t a practical program (because adding the numbers by hand is
easier), it does illustrate the subtotaling effect of repeated use of statements having this form:
variable = variable + newValue;
This type of statement is called an accumulation statement. You’ll find many uses for
accumulation statements when you become more familiar with the repetition statements
introduced in Chapter 5.
Counting
The counting statement, which is an assignment statement similar to the accumulating
statement, has the following form:
variable = variable + fixedNumber;
111
Chapter 3
Assignment Operations
Examples of counting statements are as follows:
i = i + 1;
n = n + 1;
count = count + 1;
j = j + 2;
m = m + 2;
kk = kk + 3;
In these examples, the same variable is used on both sides of the equal sign. After the
statement is executed, the value of the variable is increased by a fixed amount. In the first
three examples, the variables i, n, and count have been increased by one. In the next two
examples, the variables have been increased by two, and in the final example, the variable
kk has been increased by three.
For the case in which a variable is increased or decreased by only one, C++ provides two
unary operators: increment and decrement operators. Using the increment operator,5 ++, the
expression variable = variable + 1 can be replaced by the expression variable++
or the expression ++variable. Here are examples of the increment operator:
Expression Alternative
i = i + 1 i++ or ++i
n = n + 1 n++ or ++n
count = count + 1 count++ or ++count
Program 3.4 illustrates the use of the increment operator.
5
As a historical note, the ++ in C++’s name was inspired by the increment operator symbol. It was used to indicate that C++ was the next
increment to the C language.
112 Assignment, Formatting, and Interactive Input
Program 3.4
#include <iostream>
using namespace std;
int main()
{
int count;
count = 0;
cout << "The initial value of count is " << count << endl;
count++;
cout << " count is now " << count << endl;
count++;
cout << " count is now " << count << endl;
count++;
cout << " count is now " << count << endl;
count++;
cout << " count is now " << count << endl;
return 0;
}
This is the output displayed by Program 3.4:
The initial value of count is 0
count is now 1
count is now 2
count is now 3
count is now 4
When the ++ operator appears before a variable, it’s called a prefix increment operator;
when it appears after a variable, it’s called a postfix increment operator. The distinction
between a prefix and postfix increment operator is important when the variable being
incremented is used in an assignment expression. For example, k = ++n, which uses a prefix
increment operator, does two things in one expression: The value of n is incremented by one,
and then the new value of n is assigned to the variable k. Therefore, the statement k =
++n; is equivalent to these two statements:
n = n + 1; // increment n first
k = n; // assign n's value to k
The assignment expression k = n++, which uses a postfix increment operator, reverses
this procedure. A postfix increment operator works after the assignment is completed.
Therefore,the statement k = n++; first assigns the current value of n to k, and then
increments the value of n by one. This process is equivalent to these two statements:
113
Chapter 3
Assignment Operations
k = n; // assign n's value to k
n = n + 1; // and then increment n
C++ also provides the decrement operator, --, in prefix and postfix variations. As you
might expect, both the expressions variable-- and --variable are equivalent to the
expression variable = variable - 1. Here are examples of the decrement operator:
Expression Alternative
i = i - 1 i-- or --i
n = n - 1 n-- or --n
count = count - 1 count-- or –-count
When the -- operator appears before a variable, it’s called a prefix decrement operator.
When this operator appears after a variable, it’s called a postfix decrement operator. For
example, both the expressions n-- and --n reduce the value of n by one and are equivalent
to the longer expression n = n - 1.
As with the increment operators, however, the prefix and postfix decrement operators
produce different results when used in assignment expressions. For example, the expression
k = --n first decrements the value of n by one before assigning the value of n to k, and
the expression k = n-- first assigns the current value of n to k, and then reduces the value
of n by one.
EXERCISES 3.1
1. (General Math) Write an assignment statement to calculate the circumference of a circle
having a radius of 3.3 inches. The formula for determining the circumference, c, of a
circle is c = 2␲r, where r is the radius and ␲ equals 3.1416.
2. (General Math) Write an assignment statement to calculate the area of a circle. The for-
mula for determining the area, a, of a circle is a = ␲r2
, where r is the radius and
␲ = 3.1416.
3. (Conversion) Write an assignment statement to convert temperature in degrees Fahrenheit
to degrees Celsius. The formula for this conversion is Celsius = 5/9 (Fahrenheit - 32).
4. (General Math) Write an assignment statement to calculate the round-trip distance, d, in
feet, of a trip that’s s miles long one way.
5. (Physics) Write an assignment statement to calculate the elapsed time, in minutes, it
takes to make a trip. The formula for computing elapsed time is elapsed time = total
distance / average speed. Assume the distance is in miles and the average speed is in miles
per hour (mph).
6. (Numerical) Write an assignment statement to calculate the nth term in an arithmetic
sequence. This is the formula for calculating the value, v, of the nth term:
v = a + (n - 1)d
114 Assignment, Formatting, and Interactive Input
d is the difference between any two numbers in the sequence.
a is the first number in the sequence.
7. (Civil Eng.) Write an assignment statement to calculate the linear expansion in a steel beam
as a function of temperature increase. The formula for linear expansion, l, is as follows:
l = l0[1 + ␣ (Tf - T0)]
l0 is the length of the beam at temperature T0.
␣ is the coefficient of linear expansion.
Tf is the final temperature of the beam.
8. (Physics) Coulomb’s Law states that the force, F, acting between two electrically charged
spheres is given by this formula:
F
k q q
r
=
1 2
2
q1 is the charge on the first sphere.
q2 is the charge on the second sphere.
r is the distance between the centers of the two spheres.
k is a proportionality constant.
Write an assignment statement to calculate the force, F.
9. (Civil Eng.) Write an assignment statement to determine the maximum bending
moment, M, of a beam, given this formula:
M
X W L X
L
=
( )
-
X is the distance from the end of the beam that a weight, W, is placed.
L is the length of the beam.
10. (Desk Check) Determine the output of the following program:
#include <iostream>
using namespace std;
int main() // a program illustrating integer truncation
{
int num1, num2;
num1 = 9/2;
num2 = 17/4;
cout << "the first integer displayed is " << num1 << endl;
cout << "the second integer displayed is " << num2 << endl;
return 0;
}
115
Chapter 3
Assignment Operations
11. (Debug) Determine and correct the errors in the following programs.
a. #include <iostream>
using namespace std;
int main()
{
width = 15
area = length * width;
cout << "The area is " << area
}
b. #include <iostream>
using namespace std;
int main()
{
int length, width, area;
area = length * width;
length = 20;
width = 15;
cout << "The area is " << area;
return 0;
c. #include <iostream.h>
int main()
{
int length = 20; width = 15, area;
length * width = area;
cout << "The area is " , area;
return 0;
}
12. (Debug) By mistake, a student reordered the statements in Program 3.3 as follows:
#include <iostream>
using namespace std;
int main()
{
int sum;
sum = 0;
sum = sum + 96;
sum = sum + 70;
sum = sum + 85;
sum = sum + 60;
cout << "The value of sum is initially set to " << sum << endl;
cout << " sum is now " << sum << endl;
cout << " sum is now " << sum << endl;
cout << " sum is now " << sum << endl;
cout << " The final sum is " << sum << endl;
return 0;
}
Determine the output this program produces.
116 Assignment, Formatting, and Interactive Input
13. (General Math) Using Program 3.1, complete the following chart by determining the
volume of cylinders having these radii and heights:
Radius (in) Height (in) Volume
1.62 6.23
2.86 7.52
4.26 8.95
8.52 10.86
12.29 15.35
14. (General Math) The area of an ellipse (see Figure 3.5) is given by this formula:
Area = ␲ a b
Using this formula, write a C++ program to calculate the area of an ellipse having a minor
axis, a, of 2.5 inches and a major axis, b, of 6.4 inches.
15. (Modify) Modify Program 3.1 to calculate the weight, in pounds, of the steel cylinder
whose volume was determined in that program. This is the formula for determining the
weight:
weight = 0.28 (␲)(r 2
)(h)
r is the radius (in inches).
h is the height (in inches) of the cylinder.
3.2 Formatting Numbers for Program Output
Besides displaying correct results, a program should present its results attractively. Most
programs are judged on the perceived ease of data entry and the style and presentation of the
output. For example, displaying a monetary result as 1.897 isn’t in keeping with accepted
report conventions. The display should be $1.90 or $1.89, depending on whether rounding or
truncation is used.
a
b
Figure 3.5 The minor axis, a, and the major axis, b, of an ellipse
117
Chapter 3
Formatting Numbers for Program
Output
To control the format of numbers displayed by cout, you can include field width
manipulators in an output stream. Table 3.1 lists the most common stream manipulators for
this purpose.6
Table 3.1 Commonly Used Stream Manipulators
Manipulator Action
setw(n) Set the field width to n.
setprecision(n) Set the floating-point precision to n places. If the fixed
manipulator is designated, n specifies the total number of
displayed digits after the decimal point; otherwise, n specifies
the total number of significant digits displayed (integer plus
fractional digits).
setfill('x') Set the default leading fill character to x. (The default leading
fill character is a space, which is used to fill the beginning of an
output field when the field width is larger than the value being
displayed.)
setiosflags
(flags)
Set the format flags. (See Table 3.3 for flag settings.)
scientific Set the output to display real numbers in scientific notation.
showbase Display the base used for numbers. A leading 0 is displayed for
octal numbers and a leading 0x for hexadecimal numbers.
showpoint Always display six digits total (combination of integer and
fractional parts). Fill with trailing zeros, if necessary. For larger
integer values, revert to scientific notation.
showpos Display all positive numbers with a leading + sign.
boolalpha Display Boolean values as true and false rather than 1 and 0.
dec Set the output for decimal display, which is the default.
endl Output a newline character and display all characters in the buffer.
fixed Always show a decimal point and use a default of six digits after
the decimal point. Fill with trailing zeros, if necessary.
flush Display all characters in the buffer.
left Left-justify all numbers.
hex Set the output for hexadecimal display.
oct Set the output for octal display.
uppercase Display hexadecimal digits and the exponent in scientific notation
in uppercase.
right Right-justify all numbers (the default).
noboolalpha Display Boolean values as 1 and 0 rather than true and false.
noshowbase Don’t display octal numbers with a leading 0 and hexadecimal
numbers with a leading 0x.
6
As noted in Chapter 2, the endl manipulator inserts a new line and then forces all current insertions to be displayed immediately, called
“flushing the stream.”
118 Assignment, Formatting, and Interactive Input
Table 3.1 Commonly Used Stream Manipulators (continued)
Manipulator Action
noshowpoint Don’t use a decimal point for real numbers with no fractional
parts, don’t display trailing zeros in the fractional part of a number,
and display a maximum of six decimal digits only.
noshowpos Don’t display leading + signs (the default).
nouppercase Display hexadecimal digits and the exponent in scientific notation
in lowercase.
For example, the statement cout << "The sum of 6 and 15 is" << setw(3)
<< 21; creates this printout:
The sum of 6 and 15 is 21
The setw(3) field width manipulator included in the data stream sent to cout is used
to set the displayed field width. The 3 in this manipulator sets the default field width for the
next number in the stream to be three spaces. This field width setting causes the 21 to
beprinted in a field of three spaces, which includes one blank and the number 21. As shown
in this output, integers are right-justified in the specified field.
Field width manipulators are useful in printing columns of numbers so that the numbers
align correctly in each column. For example, Program 3.5 shows how a column of integers
aligns in the absence of field width manipulators.
Program 3.5
#include <iostream>
using namespace std;
int main()
{
cout << 6 << endl
<< 18 << endl
<< 124 << endl
<< "---n"
<< (6+18+124) << endl;
return 0;
}
119
Chapter 3
Formatting Numbers for Program
Output
The output of Program 3.5 is the following:
6
18
124
---
148
Because no field width manipulators are used in Program 3.5, cout allocates enough
space for each number as it’s received. Forcing numbers to align on the units digit requires
a field width wide enough for the largest displayed number, which is three for the numbers
in Program 3.5. Program 3.6 shows the use of this field width.
Program 3.6
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << setw(3) << 6 << endl
<< setw(3) << 18 << endl
<< setw(3) << 124 << endl
<< "---n"
<< (6+18+124) << endl;
return 0;
}
The output of Program 3.6 is as follows:
6
18
124
---
148
The field width manipulator must be included for each occurrence of a number inserted
in the data stream sent to cout; the manipulator applies only to the next insertion of data
immediately following it, and the other manipulators remain in effect until they’re changed.
When a manipulator requiring an argument is used, the iomanip header file must be
included as part of the program. To do this, you use the preprocessor command #include
<iomanip>, which is the second line in Program 3.6.
120 Assignment, Formatting, and Interactive Input
Formatting floating-point numbers requires using three field width manipulators. The first
manipulator sets the total width of the display, the second manipulator forces the display of a
decimal point, and the third manipulator determines how many significant digits are displayed
to the right of the decimal point. (See the “Point of Information” box in Chapter 2 for a review
of significant digits.) For example, examine the following statement:
cout << "|" << setw(10) << fixed << setprecision(3) << 25.67 << "|";
It causes the following printout:
| 25.670|
The bar symbol, |, in this example is used to delimit (mark) the beginning and end of
the display field. The setw manipulator tells cout to display the number in a total field of
10. (With real numbers, the decimal point takes up one of these field locations.) The fixed
manipulator forces the display of a decimal point and specifies using the setprecision
manipulator to designate the number of digits displayed after the decimal point. In this case,
setprecision specifies a display of three digits after the decimal point. Without the
explicit designation of a decimal point (which can also be designated as
setiosflags(ios::fixed), explained shortly), the setprecision manipulator speci-
fies the total number of displayed digits, which includes the integer and fractional parts of the
number.
For all numbers (integers, single-precision, and double-precision), cout ignores the
setw manipulator specification if the total specified field width is too small, and it allocates
enough space for printing the integer part of the number. The fractional part of single-
precision and double-precision numbers is displayed up to the precision set with the
setprecision manipulator. (In the absence of setprecision, the default precision is
set to six decimal places.) If the fractional part of the number to be displayed contains more
digits than are called for in the setprecision manipulator, the number is rounded to the
indicated number of decimal places; if the fractional part contains fewer digits than specified,
the number is displayed with fewer digits. Table 3.2 shows the effect of several format
manipulator combinations. For clarity, the bar symbol delimits the beginning and end of
output fields.
Table 3.2 Effect of Format Manipulators
Manipulators Number Display Comments
setw(2) 3 | 3| Number fits in the field.
setw(2) 43 |43| Number fits in the field.
setw(2) 143 |143| Field width is ignored.
setw(2) 2.3 |2.3| Field width is ignored.
setw(5) fixed
setprecision(2)
2.366 | 2.37| Field width of five with two decimal
digits.
setw(5) fixed
setprecision(2)
42.3 |42.30| Number fits in the field with the
specified precision. Note that the
decimal point takes up one location
in the field width.
setw(5)
setprecision(2)
142.364 |1.4e+002| Field width is ignored, and scientific
notation is used with the
setprecision manipulator.
121
Chapter 3
Formatting Numbers for Program
Output
Table 3.2 Effect of Format Manipulators (continued)
Manipulators Number Display Comments
setw(5) fixed
setprecision(2)
142.364 |142.36| Field width is ignored, but precision
specification is used. The
setprecision manipulator
specifies the number of fractional
digits.
setw(5) fixed
setprecision(2)
142.366 |142.37| Field width is ignored, but precision
specification used. The
setprecision manipulator
specifies the number of fractional
digits. (Note the rounding of the last
decimal digit.)
setw(5) fixed
setprecision(2)
142 | 142| Field width is used; fixed and
setprecision manipulators are
irrelevant because the number is an
integer that specifies the total
number of significant digits (integer
plus fractional digits).
In addition to the setw and setprecision manipulators, a field justification manipu-
lator is available. As you have seen, numbers sent to cout are normally right-justified in the
display field, and strings are left-justified. To alter the default justification for a stream of
data, you use the setiosflags manipulator. For example, the statement
cout << "|" << setw(10) << setiosflags(ios::left) << 142 << "|";
causes the following left-justified display:
|142 |
Because data sent to cout can be continued across multiple lines, the previous display
is also produced by this statement:
cout << "|" << setw(10)
<< setiosflags(ios::left)
<< 142 << "|";
As always, the field width manipulator is in effect only for the next set of data displayed
by cout. To right-justify strings in a stream, you use the setiosflags(ios::right)
manipulator. The letters “ios” in the function name and the ios::right argument come
from the first letters of the words “input output stream.”
In addition to the left and right flags that can be used with setiosflags(), other
flags can be used to affect output. Table 3.3 lists the most commonly used flags for this
manipulator function. The flags in this table provide another way of setting the manipulators
listed in Table 3.1.
122 Assignment, Formatting, and Interactive Input
Table 3.3 Format Flags for Use with setiosflags()
Flag Meaning
ios::fixed Always show the decimal point with six digits after the
decimal point. Fill with trailing zeros after the decimal point,
if necessary. This flag takes precedence if it’s set with the
ios::showpoint flag.
ios::scientific Use exponential display in the output.
ios::showpoint Always display a decimal point and six significant digits total
(combination of integer and fractional parts). Fill with trailing
zeros after the decimal point, if necessary. For larger integer
values, revert to scientific notation unless the ios::fixed
flag is set.
ios::showpos Display a leading + sign when the number is positive.
ios::left Left-justify the output.
ios::right Right-justify the output.
Because the flags in Table 3.3 are used as arguments to setiosflags() and the terms
“argument” and “parameter” are synonymous, another name for a manipulator method that
uses arguments is a parameterized manipulator. The following is an example of a parameter-
ized manipulator method:
cout << setiosflags(ios::showpoint) << setprecision(4);
This statement forces all subsequent floating-point numbers sent to the output stream to
be displayed with a decimal point and four decimal digits. If the number has fewer than four
decimal digits, it’s padded with trailing zeros.
Point of Information
What Is a Flag?
In current programming usage, the term flag refers to an item, such as a variable or
argument, that sets a condition usually considered active or nonactive. Although the
exact origin of this term in programming is unknown, it probably came from using real
flags to signal a condition, such as the Stop, Go, Caution, and Winner flags commonly
used at car races.
In a similar manner, each flag argument for the setiosflags() manipulator
function activates a specific condition. For example, the ios::dec flag sets the display
format to decimal, and the ios::oct flag activates the octal display format. Because
these conditions are mutually exclusive (only one can be active at a time), activating
this type of flag deactivates the other flags automatically.
Flags that aren’t mutually exclusive, such as ios::dec, ios::showpoint, and
ios::fixed, can be set simultaneously. You can do this by using three separate
setiosflag() calls or combining all arguments into one call as follows:
cout << setiosflags(ios::dec | ios::fixed | ios::showpoint);
123
Chapter 3
Formatting Numbers for Program
Output
In addition to outputting integers in decimal notation, the oct and hex manipulators are
used for conversions to octal and hexadecimal; Program 3.7 uses these flags. Because decimal
is the default display, the dec manipulator isn’t required in the first output stream.
Program 3.7
// a program that illustrates output conversions
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << "The decimal (base 10) value of 15 is " << 15 << endl;
cout << "The octal (base 8) value of 15 is "
<< showbase << oct << 15 <<endl;
cout << "The hexadecimal (base 16) value of 15 is "
<< showbase << hex << 15 << endl;
return 0;
}
The output produced by Program 3.7 is the following:
The decimal (base 10) value of 15 is 15
The octal (base 8) value of 15 is 017
The hexadecimal (base 16) value of 15 is 0xf
The display of integer values in one of three possible number systems (decimal, octal,
and hexadecimal) doesn’t affect how the number is stored in a computer. All numbers
arestored by using the computer’s internal codes. The manipulators sent to cout tell the
object how to convert the internal code for output display purposes.
Besides displaying integers in octal or hexadecimal form, they can also be written in a
program in these forms. To designate an octal integer, the number must have a leading zero.
The number 023, for example, is an octal number in C++. Hexadecimal numbers are denoted
with a leading 0x. Program 3.8 shows how octal and hexadecimal integer numbers are used
and produces the following output:
The decimal value of 025 is 21
The decimal value of 0x37 is 55
124 Assignment, Formatting, and Interactive Input
Program 3.8
#include <iostream>
using namespace std;
int main()
{
cout << "The decimal value of 025 is " << 025 << endl
<< "The decimal value of 0x37 is "<< 0x37 << endl;
return 0;
}
Point of Information
Formatting cout Stream Data
Floating-point data in a cout output stream can be formatted in precise ways. For
example, a common format requirement is to display monetary amounts with two digits
after the decimal point, such as 123.45. You can do this with the following statement:
cout << setiosflags(ios::fixed)
<< setiosflags(ios::showpoint)
<< setprecision(2);
The first manipulator flag, ios::fixed, forces all floating-point numbers in the
cout stream to be displayed in decimal notation. This flag also prevents using scientific
notation. The next flag, ios::showpoint, tells the stream to always display a deci-
mal point. Finally, the setprecision manipulator tells the stream to always display
two digits after the decimal point. Instead of using manipulators, you can use the
cout stream methods setf() and precision(). For example, the previous format-
ting can also be accomplished with this code:
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(2);
Note the syntax: The name of the object, cout, is separated from the method
with a period. This format is the standard way of specifying a method and connecting
it to a specific object.
Additionally, the flags used in both the setf() method and the setiosflags()
manipulator method can be combined by using the bitwise OR operator, | (explained
in Section 15.2). Using this operator, the following two statements are equivalent:
cout << setiosflags(ios::fixed | ios::showpoint);
cout.setf(ios::fixed | ios::showpoint);
The statement you select is a matter of personal preference or a predefined imposed
standard.
125
Chapter 3
Formatting Numbers for Program
Output
The relationship between input, storage, and display of integers is illustrated in
Figure 3.6.
Finally, you can set the manipulators listed in Tables 3.1 and 3.2 by using the ostream
class functions listed in Table 3.4.
Table 3.4 ostream Class Functions
Method Comment Example
precision(n) Equivalent to setprecision() cout.precision(2)
fill('x') Equivalent to setfill() cout.fill('*')
setf(ios::fixed) Equivalent to
cout.setf(ios::fixed)
setiosflags(ios::
fixed)
setf(ios::
showpoint)
Equivalent to
cout.setf(ios::showpoint)
setiosflags(ios::
showpoint)
setf(iof::left) Equivalent to left cout.setf(ios::
left)
internal
number
code
convert an
octal number
convert a
decimal
number
convert a
hexadecimal
number
convert to
octal
representation
convert to
decimal
representation
convert to
hexadecimal
representation
cout << dec
cout << oct
cout << hex
Display is octal, decimal,
or hexadecimal
Storage is always
in binary
Input is octal, decimal,
or hexadecimal
Integer
with a
leading 0
Integer
with no
leading 0
or 0X
Integer
with a
leading 0X
Octal
display
Decimal
display
Hexadecimal
display
Figure 3.6 Input, storage, and display of integers
126 Assignment, Formatting, and Interactive Input
Table 3.4 ostream Class Functions (continued)
Method Comment Example
setf(ios::right) Equivalent to right cout.setf(ios::
right)
setf(ios::flush) Equivalent to endl cout.setf(ios::
flush)
In the Example column of Table 3.4, the name of the object, cout, is separated from the
function with a period. As mentioned, this format is the standard way of calling a class function
and providing it with an object to operate on.
EXERCISES 3.2
1. (Desk Check) Determine the output of the following program:
#include <iostream>
using namespace std;
int main() // a program illustrating integer truncation
{
cout << "answer1 is the integer " << 9/4
<< "nanswer2 is the integer " << 17/3 << endl;
return 0;
}
2. (Desk Check) Determine the output of the following program:
#include <iostream>
using namespace std;
int main() // a program illustrating the % operator
{
cout << "The remainder of 9 divided by 4 is " << 9 % 4
<< "nThe remainder of 17 divided by 3 is " << 17 % 3 << endl;
return 0;
}
3. (Practice) Write a C++ program that displays the results of the expressions 3.0 * 5.0,
7.1 * 8.3 - 2.2, and 3.2 / (6.1 * 5). Calculate the value of these expressions
manually to verify that the displayed values are correct.
4. (Practice) Write a C++ program that displays the results of the expressions 15 / 4, 15
% 4, and 5 * 3 - (6 * 4). Calculate the value of these expressions manually to
verify that the display your program produces is correct.
127
Chapter 3
Formatting Numbers for Program
Output
5. (Debug) Determine the errors in the following statements:
a. cout << "n << " 15)
b. cout << "setw(4)" << 33;
c. cout << "setprecision(5)" << 526.768;
d. "Hello World!" >> cout;
e. cout << 47 << setw(6);
f. cout << set(10) << 526.768 << setprecision(2);
6. (Desk Check) Determine and write out the display produced by the following
statements:
a. cout << "|" << 5 <<"|";
b. cout << "|" << setw(4) << 5 << "|";
c. cout << "|" << setw(4) << 56829 << "|";
d. cout << "|" << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 5.26 << "|";
e. cout << "|" << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 5.267 << "|";
f. cout << "|" << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 53.264 << "|";
g. cout << "|" << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 534.264 << "|";
h. cout << "|" << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 534. << "|";
7. (Desk Check) Write out the display produced by the following statements:
a. cout << "The number is " << setw(6) << setiosflags(ios::fixed)
<< setprecision(2) << 26.27 << endl;
cout << "The number is " << setw(6) << setiosflags(ios::fixed)
<< setprecision(2) << 682.3 << endl;
cout << "The number is " << setw(6) << setiosflags(ios::fixed)
<< setprecision(2) << 1.968 << endl;
b. cout << setw(6) << setiosflags(ios::fixed)
<< setprecision(2) << 26.27 << endl;
cout << setw(6) << setiosflags(ios::fixed)
<< setprecision(2) << 682.3 << endl;
cout << setw(6) << setiosflags(ios::fixed)
<< setprecision(2) << 1.968 << endl;
cout << "------n";
cout << setw(6) << setiosflags(ios::fixed)
<< setprecision(2)
<< 26.27 + 682.3 + 1.968 << endl;
128 Assignment, Formatting, and Interactive Input
c. cout << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 26.27 << endl;
cout << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 682.3 << endl;
cout << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 1.968 << endl;
cout << "-----n";
cout << setw(5) << setiosflags(ios::fixed)
<< setprecision(2)
<< 26.27 + 682.3 + 1.968 << endl;
d. cout << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 36.164 << endl;
cout << setw(5) << setiosflags(ios::fixed)
<< setprecision(2) << 10.003 << endl;
cout << "-----" << endl;
8. (Desk Check) The following chart lists the equivalent octal and hexadecimal representa-
tions for the decimal numbers 1 through 15:
Decimal: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Octal: 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17
Hexadecimal: 1 2 3 4 5 6 7 8 9 a b c d e f
Using this chart, determine the output of the following program:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << "nThe value of 14 in octal is " << oct << 14
<< "nThe value of 14 in hexadecimal is " << hex << 14
<< "nThe value of 0xA in decimal is " << dec << 0xA
<< "nThe value of 0xA in octal is " << oct << 0xA
<< endl;
return 0;
}
9. (Electrical Eng.) The combined resistance of three resistors connected in parallel, as
shown in Figure 3.7, is given by this formula:
Combined
R R R
resistance =
+ +






1
1 1 1
1 2 3
Using this formula, write a C++ program to calculate and display the combined resistance
when the three resistors R1 = 1000, R2 = 1000, and R3 = 1000 are connected in parallel.
The output should produce this display:
The combined resistance is xxxx.xx ohms
The xxxx.xx denotes placing the calculated value in a field width of seven columns,
with two positions to the right of the decimal point.
129
Chapter 3
Formatting Numbers for Program
Output
10. (General Math) Write a C++ program to calculate and display the value of the slope of
the line connecting two points with the coordinates (3,7) and (8,12). Use the fact that the
slope between two points at the coordinates (x1,y1) and (x2,y2) is slope = (y2 - y1) / (x2 -
x1). Your program should produce this display:
The value of the slope is xxx.xx
The xxx.xx denotes placing the calculated value in a field wide enough for three places
to the left of the decimal point and two places to the right of it.
11. (General Math) Write a C++ program to calculate and display the midpoint coordinates
of the line connecting the two points with coordinates of (3,7) and (8,12). Use the fact
that the midpoint coordinates between two points with the coordinates (x1,y1) and (x2,y2)
are ((x1 + x2)/2, (y1 + y2)/2). Your program should produce this display:
The x coordinate of the midpoint is xxx.xx
The y coordinate of the midpoint is xxx.xx
The xxx.xx denotes placing the calculated value in a field wide enough for three places
to the left of the decimal point and two places to the right of it.
12. (Civil Eng.) Write a C++ program to calculate and display the maximum bending
moment, M, of a beam that’s supported on both ends (see Figure 3.8). The formula is M
= XW (L - X) / L, where X is the distance from the end of the beam that a weight, W, is
placed, and L is the length of the beam. Your program should produce this display:
The maximum bending moment is xxxx.xxxx
The xxxx.xxxx denotes placing the calculated value in a field wide enough for four
places to the right and left of the decimal point. For your program, assign the values 1.2,
1.3, and 11.2 to X, W, and L.
R1
R2
R3
Figure 3.7 Three resistors connected in parallel
W
L
X
Figure 3.8 Calculating the maximum bending moment
130 Assignment, Formatting, and Interactive Input
3.3 Using Mathematical Library Functions
As you have seen, assignment statements can be used to perform arithmetic computations.
For example, the following assignment statement multiplies the value in current by the
value in resistance and assigns the resulting value to volts:
volts = resistance * current;
Although addition, subtraction, multiplication, and division are accomplished easily with
C++’s arithmetic operators, no operators exist for raising a number to a power, finding a
number’s square root, or determining trigonometric values. To perform these calcula-
tions,C++ provides standard preprogrammed functions that can be included in a program.
Before using one of C++’s mathematical functions, you need to know the following:
• The name of the mathematical function
• What the mathematical function does
• The type of data the mathematical function requires
• The data type of the result the mathematical function returns
• How to include the mathematical library
To illustrate the use of C++’s mathematical functions, take a look at the mathematical
function sqrt(), which calculates a number’s square root and uses this form:
sqrt(number)
The function’s name, in this case sqrt, is followed by parentheses containing the number
for which the square root should be calculated. The purpose of the parentheses after the
function name is to provide a funnel through which data can be passed to the function (see
Figure 3.9). The items passed to the function through the parentheses are called arguments
of the function and constitute its input data. For example, the following expressions are used
to compute the square root of the arguments 4., 17.0, 25., 1043.29, and 6.4516:
sqrt(4.)
sqrt(17.0)
sqrt(25.)
sqrt(1043.29)
sqrt(6.4516)
Notice that the argument to the sqrt() function must be a real value, which is an
example of C++’s function overloading capabilities. Function overloading permits using the
sqrt() function
sqrt (a value)
Figure 3.9 Passing data to the sqrt() function
131
Chapter 3
Using Mathematical Library Functions
same function name for arguments of different data types.7 There are actually three functions
named sqrt()—defined for float, double, and long double arguments. The correct
sqrt() function is called depending on the type of value passed to the function when the
call is made. When one of the functions named sqrt() is called (again, the selection
isautomatic, based on the passed argument), the function determines the square root of its
argument and returns the result as a double. The previous expressions return these values:
Expression Value Returned
sqrt(4.) 2.
sqrt(17.0) 4.12311
sqrt(25.) 5.
sqrt(1043.29) 32.2
sqrt(6.4516) 2.54
In addition to the sqrt() function, Table 3.5 lists commonly used mathematical
functions provided in C++. Accessing these functions in a program requires including the
mathematical header file cmath, which contains declarations for mathematical functions. To
use this header file, place the following preprocessor statement at the top of any program
using a mathematical function:
#include <cmath>
Although some mathematical functions in Table 3.5 require more than one argument, all
functions, by definition, can return at most one value. Additionally, all the functions listed are
overloaded, which means the same function name can be used with integer and real arguments.
Table 3.6 shows the value returned by selected functions, using sample arguments.
Table 3.5 Common C++ Functions
Function Name Description Returned Value
abs(a) absolute value Same data type as
argument
pow(a1,a2) a1 raised to the a2 power Same data type as
argument a1
sqrt(a) square root of a real
number
Double-precision
sin(a) sine of a (a in radians) Double
cos(a) cosine of a (a in radians) Double
tan(a) tangent of a (a in radians) Double
7
If it weren’t for overloading, three separate square root functions, each with a different name, would have to be defined—one for each type of
argument.
132 Assignment, Formatting, and Interactive Input
Table 3.5 Common C++ Functions (continued)
Function Name Description Returned Value
log(a) natural logarithm of a Double
log10(a) common log (base 10) of a Double
exp(a) e raised to the a power Double
Table 3.6 Selected Function Examples
Example Returned Value
abs(-7.362) 7.362
abs(-3) 3
pow(2.0,5.0) 32.
pow(10,3) 1000
log(18.697) 2.92836
log10(18.697) 1.27177
exp(-3.2) 0.040762
Each time a mathematical function is used, it’s called into action by giving the name of
the function and passing to it any data in the parentheses following the function’s name (see
Figure 3.10).
The arguments passed to a function need not be single constants. Expressions can also
be arguments, provided the expression can be computed to yield a value of the required data
type. For example, the following arguments are valid for the given functions:
sqrt(4.0 + 5.3 * 4.0) abs(2.3 * 4.6)
sqrt(16.0 * 2.0 - 6.7) sin(theta - phi)
sqrt(x * y - z/3.2) cos(2.0 * omega)
The expressions in parentheses are evaluated first to yield a specific value. Therefore, values
have to be assigned to the variables theta, phi, x, y, z, and omega before their use in the
preceding expressions. After the value of the argument is calculated, it’s passed to the
function.
Functions can also be included as part of larger expressions, as shown in this example:
4 * sqrt(4.5 * 10.0 - 9.0) - 2.0
= 4 * sqrt(36.0) - 2.0
= 4 * 6.0 - 2.0
= 24.0 - 2.0
= 22.0
function-name (data passed to the function);
This passes data to
the function
This identifies
the called
function
Figure 3.10 Using and passing data to a function
133
Chapter 3
Using Mathematical Library Functions
The step-by-step evaluation of an expression such as
3.0 * sqrt(5 * 33 - 13.71) / 5
is as follows:
Step Result
1. Perform multiplication in the argument. 3.0 * sqrt(165 - 13.71) / 5
2. Complete the argument calculation. 3.0 * sqrt(151.29) / 5
3. Return a function value. 3.0 * 12.3 / 5
4. Perform the multiplication. 36.9 / 5
5. Perform the division. 7.38
Program 3.9 illustrates using the sqrt() function to determine the time it takes a ball
to hit the ground after it has been dropped from an 800-foot tower. This is the mathematical
formula for calculating the time in seconds it takes to fall a given distance in feet:
time = sqrt(2 × distance / g)
where g is the gravitational constant, equal to 32.2 ft/sec2
.
Program 3.9
#include <iostream> // this line can be placed second instead of first
#include <cmath> // this line can be placed first instead of second
using namespace std;
int main()
{
int height;
double time;
height = 800;
time = sqrt(2 * height / 32.2);
cout << "It will take " << time << " seconds to fall "
<< height << " feet.n";
return 0;
}
Program 3.9 produces this output:
It will take 7.04907 seconds to fall 800 feet.
134 Assignment, Formatting, and Interactive Input
As used in Program 3.9, the value the sqrt() function returns is assigned to the variable
time. In addition to assigning a function’s returned value to a variable, the returned value
can be included in a larger expression or even used as an argument to another function. For
example, the following expression is valid:
sqrt( sin( abs(theta) ) )
Because parentheses are present, the computation proceeds from the inner to outer pairs
of parentheses. Therefore, the absolute value of theta is computed first and used as
anargument to the sin() function. The value the sin() function returns is then used as
an argument to the sqrt() function.
Note that the arguments of all trigonometric functions (sin(), cos(), and so forth)
must be in radians. Therefore, to calculate the sine of an angle given in degrees, the angle
must be converted to radians first. You can do this easily by multiplying the angle by the term
(3.1416/180.). For example, to obtain the sine of 30 degrees, use the expression sin
(30 * 3.1416/180.).
Casts
You have already seen the conversion of an operand’s data type in mixed-mode arithmetic
expressions (Section 2.4) and with different operators (Section 3.1). In addition to the implicit
data type conversions made automatically in mixed-mode arithmetic and assignment expres-
sions, C++ provides for explicit user-specified type conversions. The operator used to force
converting a value to another type is the cast operator. C++ provides compile-time and
runtime cast operators. The compile-time cast is a unary operator with this syntax:
dataType (expression)
The dataType is the data type to which the expression in parentheses is converted. For
example, the following expression
int (a * b)
converts the value of the expression a * b to an integer value.8
With the introduction of the latest C++ standard, runtime casts are included. In this type
of cast, the requested type conversion is checked at runtime and applied if the conversion
results in a valid value. Although four types of runtime casts are available, the most
commonly used cast and the one corresponding to the compile-time cast has the following
syntax:
staticCast<data-type> (expression)
For example, the runtime cast staticCast<int>(a * b) is equivalent to the compile-
time cast int (a* b).
8
The C type cast syntax, in this case (int)(a * b), also works in C++.
135
Chapter 3
Using Mathematical Library Functions
EXERCISES 3.3
1. (Practice) Write function calls to determine the following:
a. The square root of 6.37
b. The square root of x - y
c. The sine of 30 degrees
d. The sine of 60 degrees
e. The absolute value of a2
- b2
f. The value of e raised to the third power
2. (Practice) For a = 10.6, b = 13.9, and c = -3.42, determine the following
values:
a. int (a)
b. int (b)
c. int (c)
d. int (a + b)
e. int (a) + b + c
f. int (a + b) + c
g. int (a + b + c)
h. float (int (a)) + b
i. float (int (a + b))
j. abs(a) + abs(b)
k. sqrt(abs(a - b))
3. (Practice) Write C++ statements for the following:
a. b = sin x - cos x
b. b = sin2
x - cos2
x
c. area = (c × b × sin a)/2
d. c a b
= +
2 2
e. p m n
= | |
-
f. sum
a r
r
n
=
( )
-
-
1
1
4. (Numerical) Write, compile, and execute a C++ program that calculates and returns the
fourth root of the number 81.0, which is 3. After verifying that your program works cor-
rectly, use it to determine the fourth root of 1,728.896400. Your program should make use
of the sqrt() function.
136 Assignment, Formatting, and Interactive Input
5. (General Math) Write, compile, and execute a C++ program to calculate the distance
between two points with the coordinates (7, 12) and (3, 9). Use the fact that the distance
between two points with the coordinates (x1, y1) and (x2, y2) is given by this formula:
dis ce x y
tan = +
( )
2 2
After verifying that your program works correctly by calculating the distance between the
two points manually, use your program to determine the distance between the points (-12,
-15) and (22, 5).
6. (General Math) If a 20-foot ladder is placed on the side of a building at a 85-degree
angle, as shown in Figure 3.11, the height at which the ladder touches the building can
be calculated as height = 20 × sin 85°. Calculate this height by hand, and then write, com-
pile, and execute a C++ program that determines and displays the value of the height.
After verifying that your program works correctly, use it to determine the height of a
25-foot ladder placed at an angle of 85 degrees.
7. (Physics) The maximum height reached by a ball thrown with an initial velocity, v, in
meters/sec, at an angle of ␪ is given by this formula:
height = (.5 × v2
× sin2
␪) / 9.8
Using this formula, write, compile, and execute a C++ program that determines and dis-
plays the maximum height reached when the ball is thrown at 5 mph at an angle of
60 degrees. (Hint: Make sure to convert the initial velocity into the correct units. There
are 1609 meters in a mile.) Calculate the maximum height manually, and verify the result
your program produces. After verifying that your program works correctly, use it to deter-
mine the height reached by a ball thrown at 7 mph at an angle of 45 degrees.
2
0
'
85°
Figure 3.11 Calculating the height of a ladder against a building
137
Chapter 3
Using Mathematical Library Functions
8. (Numerical) For small values of x, the value of sin(x) can be approximated by this power
series:
x
x x x
− + − +
3 5 7
3 5 7
! ! !
....
As with the sin() function, the value of x must be in radians. Using this power series,
write, compile, and execute a C++ program that approximates the sine of 180/3.1416 degrees,
which equals one radian. Additionally, have your program use the sin() function to calculate
the sine and display both calculated values and the absolute difference of the two results.
Manually verify the approximation your program produces. After verifying that your program
is working correctly, use it to approximate the value of the sine of 62.2 degrees.
9. (Conversion) The polar coordinates of a point consist of the distance, r, from a specified
origin and an angle, ␪, with respect to the x-axis. The point’s x and y coordinates are
related to its polar coordinates by these formulas:
x = r cos ␪
y = r sin ␪
Using these formulas, write a C++ program to calculate the x and y coordinates of a point
with the polar coordinates r = 10 and ␪ = 30 degrees. Verify the results your program pro-
duces by calculating the results manually. After verifying that your program is working
correctly, use it to convert the polar coordinates r = 12.5 and ␪ = 67.8 degrees into rectan-
gular coordinates.
10. (Ecology) A model of worldwide population growth, in billions of people, since 2000 is
given by this formula:
Population = 6.0 e0.02[Year - 2000]
Using this formula, write, compile, and execute a C++ program to estimate the worldwide
population in the year 2012. Verify the result your program produces by calculating the
answer manually. After verifying that your program is working correctly, use it to estimate
the world’s population in the year 2019.
11. (Physics) A model to estimate the number of grams of a radioactive isotope left after
t years is given by this formula:
remaining material = (original material) e-0.00012t
Using this formula, write, compile, and execute a C++ program to determine the amount of
radioactive material remaining after 1000 years, assuming an initial amount of 100 grams.
Verify the display your program produces by using a hand calculation. After verifying that
your program is working correctly, use it to determine the amount of radioactive material
remaining after 275 years, assuming an initial amount of 250 grams.
12. (Physics) The number of years it takes for an isotope of uranium to decay to one-half an
original amount is given by this formula, where ␭, the decay constant (which is equal to
the inverse of the mean lifetime), equals 0.00012:
half-life = ln(2) / ␭
Using this formula, write, compile, and execute a C++ program that calculates and dis-
plays the half-life of this uranium isotope. Verify the result your program produces by
using a hand calculation. After verifying that your program is working correctly, use it to
determine the half-life of a uranium isotope with ␭ = 0.00026.
138 Assignment, Formatting, and Interactive Input
3.4 Program Input Using cin
Data for programs that are going to be executed only once can be included in the program.
For example, if you want to multiply the numbers 30.0 and 0.05, you could use Program 3.10.
Program 3.10
#include <iostream>
using namespace std;
int main()
{
double num1, num2, product;
num1 = 30.0;
num2 = 0.05;
product = num1 * num2;
cout << "30.0 times 0.05 is " << product << endl;
return 0;
}
Program 3.10 produces this output:
30.0 times 0.05 is 1.5
Program 3.10 can be shortened, as shown in Program 3.11. Both programs, however,
suffer from the same basic problem: They must be rewritten to multiply different numbers.
Both programs lack the capability to enter different numbers on which to operate.
Program 3.11
#include <iostream>
using namespace std;
int main()
{
cout << "30.0 times 0.05 is " << 30.0 * 0.05 << endl;
return 0;
}
139
Chapter 3
Program Input Using cin
Except for the programming practice provided by writing, entering, and running the
program, programs that do the same calculation only once, on the same set of numbers,
clearly aren’t very useful. After all, using a calculator to multiply two numbers is simpler than
entering and running Program 3.10 or 3.11.
This section explains the cin statement, used to enter data in a program while it’s
running. Just as a cout statement displays the value stored in a variable, cin allows users
to enter a value at the keyboard (see Figure 3.12), and then the value is stored in a variable.
When a statement such as cin >> num1; is encountered, the computer stops program
execution and accepts data from the keyboard. When a data value is typed, cin causes the
value to be stored in the variable listed after the extraction (“get from”) operator, >>. The
program then continues execution with the next statement after the cin statement. To see
how cin works, take a look at Program 3.12.
Program 3.12
#include <iostream>
using namespace std;
int main()
{
double num1, num2, product;
cout << "Please type in a number: ";
cin >> num1;
cout << "Please type in another number: ";
cin >> num2;
product = num1 * num2;
cout << num1 << " times " << num2 << " is " << product << endl;
return 0;
}
The first cout statement in Program 3.12 displays a string that tells the person at the
keyboard what should be typed. When an output string is used in this manner, it’s called a
prompt. In this case, the prompt tells the user to type a number. The computer then executes
int main()
{
cin >>
cout <<
}
Screen
Keyboard
Figure 3.12 cin is used to enter data; cout is used to display data
140 Assignment, Formatting, and Interactive Input
the next statement, which uses cin. The cin statement puts the computer in a temporary pause
(or wait) state while the user types a value. Then the user signals cin that data entry is finished
by pressing the Enter key. The entered value is stored in the variable to the right of the
extraction operator (num1), and the computer is taken out of its paused state.
Program execution proceeds with the next statement, which in Program 3.12 is another
cout statement that displays a prompt asking the user to type another number. The next
statement uses cin again to put the computer in a temporary wait state while the user types
a second value (stored in the variable num2).
The following sample run was made using Program 3.12:
Please type in a number: 30
Please type in another number: 0.05
30 times 0.05 is 1.5
In Program 3.12, each time cin is invoked, it’s used to store one value in a variable. A
cin statement, however, can be used to enter and store as many values as there are
extraction operators and variables to hold the entered data. For example, the statement
cin >> num1 >> num2;
results in two values being read from the keyboard and assigned to the variables num1 and
num2. If the data entered at the keyboard is
0.052 245.79
the variables num1 and num2 contain the values 0.052 and 245.79, respectively. Notice that
there must be at least one space between numbers when they’re entered to clearly indicate
where one number ends and the next begins. Inserting more than one space between
numbers has no effect on cin.
The same spacing also applies to entering character data; the extraction operator skips
blank spaces and stores the next nonblank character in a character variable. For example, in
response to the statements,
char ch1, ch2, ch3; // declare three character variables
cin >> ch1 >> ch2 >> ch3; // accept three characters
the input
a b c
causes the letter a to be stored in the variable ch1, the letter b to be stored in the variable ch2,
and the letter c to be stored in the variable ch3. Because a character variable can be used to store
only one character, however, the following input, without spaces, can also be used:
abc
You can use any number of cin statements in a program, and any number of values can
be entered with a single cin statement. Program 3.13 shows using a cin statement to input
three numbers from the keyboard. The program then calculates and displays the average of
the entered numbers.
141
Chapter 3
Program Input Using cin
Program 3.13
#include <iostream>
using namespace std;
int main()
{
int num1, num2, num3;
double average;
cout << "Enter three integer numbers: ";
cin >> num1 >> num2 >> num3;
average = (num1 + num2 + num3) / 3.0;
cout << "The average of the numbers is " << average << endl;
return 0;
}
The following sample run was made using Program 3.13:
Enter three integer numbers: 22 56 73
The average of the numbers is 50.3333
The data entered at the keyboard for this sample run consists of 22 56 73. In response
to this stream of input, Program 3.13 stores the value 22 in the variable num1, the value 56
in the variable num2, and the value 73 in the variable num3 (see Figure 3.13). Because the
average of three integer numbers can be a floating-point number, the variable average,
used to store the average of all entered numbers, is declared as a floating-point variable (a
double). Note also that parentheses are needed in the assignment statement average =
(num1 + num2 + num3)/3.0;. Without the parentheses, the only value divided by 3
would be the integer in num3 (because division has a higher precedence than addition).
cin >> num1 >> num2 >> num3;
22 56 73
22
56
73
num1
num2
num3
Figure 3.13 Inputting data in the variables num1, num2, and num3
142 Assignment, Formatting, and Interactive Input
The extraction operator, >>, like the insertion operator, <<, is “clever” enough to make a
few data type conversions. For example, if an integer is entered instead of a double-precision
number, the integer is converted to the correct data type.9 Similarly, if a double-precision number
is entered when an integer is expected, only the integer part of the number is used. For example,
assume the following numbers are typed in response to the statement cin >> num1 >> num2
>> num3;, where num1 and num3 have been declared as double-precision variables and num2
is an integer variable:
56 22.879 33.923
The 56 is converted to 56.0 and stored in the variable num1. The extraction operation
continues, extracting data from the input stream and expecting an integer value. As far as the
<< operator is concerned, the decimal point in 22.879 indicates the end of an integer and the
start of a decimal number. Therefore, the number 22 is assigned to num2. Continuing to
process its input stream, the next << operator takes the .879 as the next floating-point
number and assigns it to num3. As far as cin is concerned, 33.923 is extra input and is
ignored. If, however, you don’t enter enough data initially, the insertion operator causes the
computer to pause, waiting until enough data has been entered.
A First Look at User-Input Validation
A well-constructed program should validate user input and ensure that a program doesn’t
crash or produce nonsensical output caused by unexpected input. The term validate means
checking that the entered value matches the data type of the variable it’s assigned to in a cin
statement and checking that the value is within an acceptable range for the application.
Programs that detect and respond effectively to unexpected user input are formally referred
to as robust programs and informally as “bulletproof” programs. One of your goals as a
programmer is to produce robust programs. As written, Programs 3.12 and 3.13 aren’t robust
programs, and in the following discussion, you see why.
The first problem with these programs becomes evident when a user enters a non-
numerical value. For example, examine the following sample run using Program 3.13:
Enter three integer numbers: 10 20.68 20
The average of the numbers is -2.86331e+008
This output occurs because the conversion of the second entered number results in
assigning the integer value 20 to num2 and the value -858993460 to num3.10 The -858993460
value results because an invalid character, the decimal point, is assigned to a variable that
expects an integer. The average of the numbers 10, 20, and -858993460 is computed correctly
as -286331143.3, which is displayed in scientific notation with six significant digits as
-2.86331e+008. Most users, however, would report this result as a program error.
This same problem occurs when a non-integer value is entered for either of the first two
inputs. (It doesn’t occur for any numerical value entered as the third input because the
integer part of the last input is accepted, and the remaining input ignored.) Your first
response might be “The program clearly asks you to enter integer values.” Programmers with
more experience, however, understand that their responsibility is to make sure a program
9
Strictly speaking, what comes in from the keyboard isn’t any data type, such as an int or a double, but is simply a sequence of characters.
The extraction operation handles the conversion from the character sequence to a defined data type.
10
Some C++ runtime systems accept the .68 as the third input and convert it to the integer value of zero. In all cases, the last value of 20 is
ignored.
143
Chapter 3
Program Input Using cin
anticipates and appropriately handles all inputs users might enter. To achieve this goal, think
about what can go wrong with your program as you develop it, and then have another person
or group test the program.
The basic approach to handling invalid data input is called user-input validation, which
means checking the entered data during or immediately after it has been entered, and then
giving users a way to reenter invalid data. User-input validation is an essential part of any
commercially viable program; if done correctly, it protects a program from attempting to
process data that can cause computational problems. You see how to do this type of validation
in Chapters 4 and 5, when you learn about C++’s selection and repetition statements.
EXERCISES 3.4
1. (Practice) For the following declaration statements, write a cin statement that causes
the computer to pause while the user enters the appropriate data:
a. int firstnum;
b. double grade;
c. double secnum;
d. char keyval;
e. int month, years;
double average;
f. char ch;
int num1, num2;
double grade1, grade2;
g. double interest, principal, capital;
double price, yield;
h. char ch, letter1, letter2;
int num1, num2, num3;
i. double temp1, temp2, temp3;
double volts1, volts2;
2. (Practice) a. Write a C++ program that first displays the following prompt:
Enter the temperature in degrees Celsius:
Have your program accept a value entered from the keyboard and convert the tempera-
ture entered to degrees Fahrenheit, using this formula:
Fahrenheit = (9.0 / 5.0) × Celsius + 32.0
Your program should then display the temperature in degrees Fahrenheit with an appro-
priate message.
144 Assignment, Formatting, and Interactive Input
b. Compile and execute the program written for Exercise 2a. To verify your program, use
the following test data and calculate the Fahrenheit equivalents by hand, and then use
your program to see whether you get the same results:
Test data set 1: 0 degrees Celsius
Test data set 2: 50 degrees Celsius
Test data set 3: 100 degrees Celsius
When you’re sure your program is working correctly, use it to complete the following chart:
Celsius Fahrenheit
45
50
55
60
65
70
3. (Practice) Write, compile, and execute a C++ program that displays the following
prompt:
Enter the radius of a circle:
After accepting a value for the radius, your program should calculate and display the area
of the circle. (Hint: Area = 3.1416 × radius2
.) For testing purposes, verify your program
byusing an input radius of 3 inches. After manually determining that your program’s result
is correct, use your program to complete the following chart:
Radius (in) Area (sq. in)
1.0
1.5
2.0
2.5
3.0
3.5
4. (Practice) a. Write, compile, and execute a C++ program that displays the following
prompts:
Enter the miles driven:
Enter the gallons of gas used:
After each prompt is displayed, your program should use a cin statement to accept data
from the keyboard for the displayed prompt. After the number for gallons of gas used has
been entered, your program should calculate and display the miles per gallon (mpg). This
145
Chapter 3
Program Input Using cin
value should be included in a message and calculated by using the formula miles per gallon
= miles / gallons used. Verify your program by using the following test data:
Test data set 1: miles = 276, gas = 10 gallons
Test data set 2: miles = 200, gas = 15.5 gallons
After finishing your verification, use your program to complete the following chart. (Make
sure to convert the miles driven to kilometers driven and gallons used to liters used, and
then compute the kilometers per liter.)
Miles Driven Gallons Used MPG Km
Driven
Liters
Used
Km/L
250 16.00
275 18.00
312 19.54
296 17.39
b. For the program written for Exercise 4a, determine how many verification runs are
required to make sure the program is working correctly, and give a reason to support
your answer.
5. (Practice) a. Write, compile, and execute a C++ program that displays the following
prompts:
Enter a number:
Enter a second number:
Enter a third number:
Enter a fourth number:
After each prompt is displayed, your program should use a cin statement to accept a
number from the keyboard for the displayed prompt. After the fourth number has been
entered, your program should calculate and display the average of the numbers. The aver-
age should be included in an output message. Check the average your program calculates
by using the following test data:
Test data set 1: 100, 100, 100, 100
Test data set 2: 100, 0, 100, 0
After finishing your verification, use your program to complete the following chart:
Numbers Average
92, 98, 79, 85
86, 84, 75, 86
63, 85, 74, 82
146 Assignment, Formatting, and Interactive Input
b. Repeat Exercise 5a, making sure you use the same variable name, number, for each
number input. Also, use the variable sum for the sum of the numbers. (Hint: To do
this, you can use the statement sum = sum + number after each number is
accepted. Review the material on accumulating in Section 3.1.)
6. (General Math) a. Write, compile, and execute a C++ program to compute and display
the value of the second-order polynomial ax2
+ bx + c for any user-entered values of the
coefficients a, b, and c and the variable x. Have your program display a message first to
inform users what the program does, and then display suitable prompts to alert users to
enter the data. (Hint: Use a prompt such as Enter the coefficient of the
x-squared term:.)
b. Check the result of your program written for Exercise 6a by using the following
test data:
Test data set 1: a = 0, b = 0, c = 22, x = 56
Test data set 2: a = 0, b = 22, c = 0, x = 2
Test data set 3: a = 22, b = 0, c = 0, x = 2
Test data set 4: a = 2, b = 4, c = 5, x = 2
After finishing your verification, use your program to complete the following chart:
a b c x Polynomial Value
2.0 17.0 -12.0 1.3
3.2 2.0 15.0 2.5
3.2 2.0 15.0 -2.5
-2.0 10.0 0.0 2.0
-2.0 10.0 0.0 4.0
-2.0 10.0 0.0 5.0
-2.0 10.0 0.0 6.0
5.0 22.0 18.0 8.3
4.2 -16 -20 -5.2
7. (General Math) The roads of Kansas are laid out in a rectangular grid at exactly one-mile
intervals, as shown in Figure 3.14. Pete drives his pickup x miles east and y miles north to
get to his friend Joe’s farm. Both x and y are integer numbers. Using this information, write,
test, and run a C++ program that prompts the user for the values of x and y, and then uses
this formula to find the shortest driving distance across the fields to Joe’s farm:
dis ce x y
tan = +
( )
2 2
Round the answer to the nearest integer value before it’s displayed.
8. (Numerical) Write, compile, and execute a program that calculates and displays the
square root value of a user-entered real number. Verify your program by calculating the
square roots of this test data: 25, 16, 0, and 2. After finishing your verification, use your
program to determine the square roots of 32.25, 42, 48, 55, 63, and 79.
147
Chapter 3
Program Input Using cin
9. (Numerical) Write, compile, and execute a program to calculate and display the fourth
root of a user-entered number. Recall from elementary algebra that you find the fourth
root of a number by raising the number to the 1/4 power. (Hint: Don’t use integer
division—can you see why?) Verify your program by calculating the fourth roots of this
test data: 81, 16, 1, and 0. When you’re finished, use your program to determine the
fourth roots of 42, 121, 256, 587, 1240, and 16,256.
10. (Electrical Eng.) For the series circuit shown in Figure 3.15, the voltage drop, V2, across
resistor R2 and the power, P2, delivered to this resistor are given by the formulas V2 = I R2
and P2 = I V2, where I = E / (R1 + R2). Using these formulas, write, compile, and execute a
C++ program that prompts users for values of E, R1, and R2; calculates the voltage drop and-
power delivered to R2; and displays the results. Check your program by using the test data E
= 10 volts, R1 = 100 ohms, and R2 = 200 ohms. After finishing your verification, use your pro-
gram to complete the following chart:
E (Volts) R1 (Ohms) R2 (Ohms) Voltage Drop
(Volts)
Power Delivered
(Watts)
10 100 100
10 100 200
10 200 200
20 100 100
20 100 200
20 200 200
Distance
x
y
Pete’s
farm
Joe’s
farm
N
Figure 3.14 Illustration for Exercise 7
148 Assignment, Formatting, and Interactive Input
11. (Data Processing) Program 3.12 prompts users to input two numbers; the first value
entered is stored in num1, and the second value is stored in num2. Using this program as
a starting point, write a program that swaps the values stored in the two variables.
12. (Data Processing) Write a C++ program that prompts users to enter a number. Have
your program accept the number as an integer and display the integer immediately by
using a cout statement. Run your program three times. The first time, enter a valid inte-
ger number; the second time, enter a double-precision number; and the third time, enter
a character. Using the output display, see what number your program actually accepted
from the data you entered.
13. (Data Processing) Repeat Exercise 12, but have your program declare the variable used to
store the number as a double-precision variable. Run the program three times. The first time,
enter an integer; the second time, enter a double-precision number; and the third time, enter
a character. Using the output display, keep track of what number your program actually
accepted from the data you entered. What happened, if anything, and why?
14. (For Thought) a. Why do you think successful programs contain extensive data-input
validity checks? (Hint: Review Exercises 12 and 13.)
b. What do you think is the difference between a data-type check and a data-
reasonableness check?
c. Assume that a program requests users to enter a month, day, and year. What are some
checks that could be made on the data entered?
3.5 Symbolic Constants
Certain constants used in a program have more general meanings that are recognized outside
the program’s context. Examples of these types of constants include the number 3.1416,
which is ␲ accurate to four decimal places; 32.2 ft/sec2
, which is the gravitational constant;
R1
R2
I
E
Figure 3.15 Calculating the voltage drop
149
Chapter 3
Symbolic Constants
and the number 2.71828, which is Euler’s number accurate to five decimal places. The
following list shows other commonly used scientific and engineering constants:
Avagadro’s number = 6.02214179 × 1023
/mole
Boltzmann’s constant = 1.3806 × 10-23
Joules/K
Planck’s constant = 6.6256 × 10-34
Joule/sec
Stephan-Boltzmann’s constant = 5.6697 × 10-8
Watts/m2
K4
Universal gas constant = 8.6314472 × 107
Joules/Kmole
Universal gravitational constant = 6.67428 × 10-11
N m2
/kg2
Certain other constants in a program are defined in the context of the application being
programmed. For example, in a program determining the weight of different sized objects,
the density of an object’s material takes on a special significance. By themselves, density
numbers are quite ordinary, but in this application, they have a special meaning. Program-
mers sometimes refer to these types of numbers as magic numbers. When a magic number
appears repeatedly in a program, it becomes a potential source of error if it has to be changed.
If just one instance of the magic number is overlooked and not changed, when the program
runs the result will be incorrect, and the source of the error will be difficult to locate.
To avoid the problem of having a magic number occur in many places in a program and
to identify universal constants, such as ␲, clearly, C++ enables programmers to give these
constants symbolic names. Then the symbolic name, instead of the magic number, can be
used throughout the program.
If the number ever has to be changed, the change need be made only once, where the
symbolic name is equated to the actual numerical value. To equate numbers to symbolic
names,you use the const declaration qualifier, which specifies that the declared identifier is
read-only after it’s initialized; it can’t be changed. Examples of using this qualifier are as follows:
const double PI = 3.1416;
const double PLANCK = 6.6256e-34;
const double DENSITY = 0.238;
const int MAXNUM = 100;
The first declaration statement creates a double-precision constant named PI and
initializes it to 3.1416, and the second declaration statement creates a double-precision
constant named PLANCK and initializes it to Planck’s constant (accurate to four decimal
places). The third declaration statement creates a constant named DENSITY and initializes
it to 0.238. Finally, the fourth declaration creates an integer constant named MAXNUM and
initializes it with the value 100.
After a const identifier is created and initialized, the value stored in it can’t be changed.
For all practical purposes, the name of the constant and its value are linked for the duration
of the program that declares them.
Although the const identifiers have been shown in uppercase letters, lowercase letters
could have been used. In C++, however, it’s common to use uppercase letters for const
identifiers to identify them easily. When programmers see uppercase letters in a program, they
know a symbolic name is being used, and its value can’t be changed later in the program.
150 Assignment, Formatting, and Interactive Input
After it’s declared, a const identifier can be used in any C++ statement in place of the
number it represents. For example, both these assignment statements are valid:
circum = 2 * PI * radius;
weight = DENSITY * volume;
These statements must, of course, appear after the declarations for all their variables.
Because a const declaration equates a constant value to an identifier, and the identifier can be
used as a replacement for its initializing constant, these identifiers are commonly referred to as
symbolic constants, named constants, or simply constants. These terms are used interchangeably
in this book.
Placement of Statements
At this stage, you have been introduced to a variety of statement types. The general rule in
C++ for statement placement is simply that a variable or symbolic constant must be declared
before it can be used. Although this rule permits placing both preprocessor directives and
declaration statements throughout a program, doing so results in a poor program structure.
For good programming form, the following statement ordering should be used:
preprocessor directives
int main()
{
// symbolic constants
// variable declarations
// other executable statements
return value;
}
As new statement types are introduced, this placement structure will be expanded to
accommodate them. Note that comment statements can be intermixed anywhere within this
basic structure. Program 3.14 illustrates this basic structure and uses a symbolic constant to
calculate the weight of a steel cylinder. The density of the steel is 0.284 lb/in3
(= 7.738 ×
103
kg/m-3
).
151
Chapter 3
Symbolic Constants
Program 3.14
// This program determines the weight of a steel cylinder
// by multiplying the volume of the cylinder times its density.
// The volume of the cylinder is given by the formula PI * pow(radius,2) * height.
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
const double PI = 3.1416;
const double DENSITY = 0.284;
double radius, height, weight;
cout << "Enter the radius of the cylinder (in inches): ";
cin >> radius;
cout << "Enter the height of the cylinder (in inches): ";
cin >> height;
weight = DENSITY * PI * pow(radius,2) * height;
cout << setiosflags(ios:: fixed)
<< setiosflags(ios::showpoint)
<< setprecision(4)
<< "The cylinder weighs " << weight << " pounds" << endl;
return 0;
}
Notice in Program 3.14 that two symbolic constants have been defined: PI and
DENSITY. The following run was made to determine the weight of a cylinder with a radius
of 3 inches and a height of 12 inches.
Enter the radius of the cylinder (in inches): 3
Enter the height of the cylinder (in inches): 12
The cylinder weighs 96.3592 pounds
The advantage of using the named constant PI in Program 3.14 is that it clearly
identifies the value of 3.1416 in terms most people recognize. The advantage of using the
named constant DENSITY is that the programmer can change the value of the density for
another material without having to search through the program to see where DENSITY is
used. If, of course, many different materials are used, DENSITY should be changed from a
symbolic constant to a variable. A natural question, then, is asking what the difference is
between symbolic constants and variables.
152 Assignment, Formatting, and Interactive Input
A variable’s value can be altered anywhere in a program. By its nature, a named constant
is a fixed value that must not be altered after it’s defined. Naming a constant rather than
assigning the value to a variable ensures that the value in the constant can’t be altered later.
Whenever a named constant appears in an instruction, it has the same effect as the constant
it represents. Therefore, DENSITY in Program 3.14 is simply another way of representing the
number 0.284. Because DENSITY and the number 0.284 are equivalent, the value of
DENSITY can’t be subsequently changed in the program. After DENSITY has been defined
as a constant, an assignment statement such as
DENSITY = 0.156;
is meaningless and results in an error message because DENSITY is not a variable. Because
DENSITY is only a stand-in for the value 0.284, this statement is equivalent to writing the
invalid expression 0.284 = 0.156.
In addition to using a const statement to name constants, as in Program 3.14, you can
also use this statement to equate the value of a constant expression to a symbolic name. A
constant expression consists of operators and constants only. For example, the statement
const double DEG_TO_RAD = 3.1416/180.0;
equates the value of the constant expression 3.1416/180.0 to the symbolic name DEG_TO_RAD.
The symbolic name, as always, can be used in any statement following its definition. For
example, because the expression 3.1416/180.0 is required for converting degrees to radians,
the symbolic name for this conversion factor can be used conveniently whenever this
conversion is required. For example, in the assignment statement
height = distance * sin(angle * DEG_TO_RAD);
the symbolic constant DEG_TO_RAD is used to convert the value in angle to a radian
measure.
A previously defined named constant can also be used in a subsequent const statement.
For example, the following sequence of statements is valid:
const double PI = 3.1416;
const double DEG_TO_RAD = PI / 180.0;
Because the constant 3.1416 has been equated to the symbolic name PI, it can be used
legitimately in any subsequent definition, even in another const statement. Program 3.15
uses the named constant DEG_TO_RAD to convert a user-entered angle, in degrees, to its
equivalent radian measure for use by the sin() function.
153
Chapter 3
Symbolic Constants
Program 3.15
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
const double PI = 3.1416;
const double DEG_TO_RAD = PI/180.0;
double angle;
cout << "Enter the angle (in degrees): ";
cin >> angle;
cout << setiosflags(ios:: fixed)
<< setiosflags(ios::showpoint)
<< setprecision(4)
<< "The sine of the angle is " << sin(angle * DEG_TO_RAD)
<< endl;
return 0;
}
The following sample run was made using Program 3.15:
Enter the angle (in degrees): 30
The sine of the angle is 0.5000
Although the const qualifier has been used to construct symbolic constants, you’ll see
this qualifier again in Chapter 6, where you learn it’s useful as a function argument to make
sure the argument isn’t modified in the function.
154 Assignment, Formatting, and Interactive Input
Technical Note
Frequency, Period, and Wavelength
A wave is a repeating pattern in time and space. Examples are sound waves, ocean
waves, and light waves. Figure 3.16 shows a typical wave, which is usually described
with one of these related terms: frequency, period, or wavelength.
Time
Amplitude
T
Figure 3.16 A typical wave
In science and engineering fields, a wave’s frequency is denoted by the letter f, its
period by the letter T, and its wavelength by the Greek letter l (lamda). The frequency
of a wave is the number of repetitions of the wave occurring in one second. For
example, the frequency of the musical note middle C on a piano is 261.64 repetitions
per second, typically denoted as 261.64 cycles/sec. In the SI measurement system, the
synonym for cycles/sec is Hertz (Hz). Therefore, 261.64 cycles/sec = 261.64 Hz, which
means there are 261.64 repetitions of the wave in one second. Audio, radio, and
power line waves are described in terms of their frequencies.
Extremely low frequency waves, such as ocean waves, are typically described by
their period, T, which is the inverse of the wave’s frequency. So mathematically, you
have the following:
T = 1 / f
Therefore, a wave’s period is the time it takes to complete one cycle. For example,
an ocean surface wave with a period of 3 sec/cycle means it takes 3 seconds to com-
plete one wave cycle. What this means is that a person at a fixed location in the ocean
sees a wave crest pass by every 3 seconds. The corresponding frequency of this wave is
1/T, or 1/3 cycles per second, which equals 0.33 Hz.
Extremely high frequency waves, such as light and x-rays, are typically described by
their wavelength. Wavelength, l, and frequency, f, are related by this formula
␭ = speed of the wave / f
where the speed of the wave is the wave’s velocity in the medium through which it’s
traveling. For light traveling in a vacuum, the speed of a light wave is 299,792,458 m/s ⬇
2.998 × 108
m/s. For sound waves traveling in air, the speed of the wave is 345 m/s.
continued...
155
Chapter 3
Symbolic Constants
Technical Note
Frequency, Period, and Wavelength (continued)
Following is a description of waves encountered in science and engineering fields:
Wave Type Frequency or Period Wavelength
Ocean waves Period = 1 to 5
seconds
Not used
European household
current
50 Hz 5.996 × 106
m
American household
current
60 Hz 4.996 × 106
m
Radio frequencies
Low frequency (LF) 3 × 104
to 3 × 105
Hz
(30 to 300 kilohertz, KHz)
104
to 103
m
(10 to 1 km)
Medium
frequency (MF)
3 × 105
to 3 × 106
Hz
(.3 to 3 megahertz, MHz)
103
to 102
m
(1 to .1 km)
High frequency (HF) 3 × 106
to 3 × 107
Hz
(3 to 30 MHz)
100 to 10 m
Very high
frequency (VHF)
3 × 107
to 3 × 109
Hz
(30 to 300 MHz)
10 to 1 m
Ultra high
frequency (UHF)
3 × 109
to 3 × 1012
Hz
(300 to 3000 MHz)
1 to .1 m
Body heat 3 x 1011
Hz 1 × 10-3
m (1 millimeter)
Infrared light 0.04 × 1015
to
.3 × 1015
Hz
750 × 10-9
to
100 × 10-9
nm
(750 to 100 nanometers)
Red visible light 384 × 1012
to
482 × 1012
Hz
78 × 10-9
to
62 × 10-9
nm
(78 to 62 nanometers)
Violet visible light 659 × 1012
to
769 × 1012
Hz
45 × 10-9
to
39.8 × 10-9
nm
(45 to 39 nanometers)
Ultraviolet light 1 × 1015
to
1.5 × 1015
Hz
300 × 10-9
to
200 × 10-9
nm
(300 to 200 nanometers)
X-rays 30 × 1015
to
30 × 1018
Hz
9.9 × 10-9
to
.99 × 10-9
m
156 Assignment, Formatting, and Interactive Input
EXERCISES 3.5
1. (Practice) Modify Program 3.9 to use the named constant GRAV in place of the value
32.2 used in the program. Compile and execute your program to verify that it produces
the same result shown in the text.
2. (Modify) Rewrite the following program to use the named constant FACTOR in place of
the expression (5.0/9.0) used in the program:
#include <iostream>
using namespace std;
int main()
{
double fahren, celsius;
cout << "Enter a temperature in degrees Fahrenheit: ";
cin >> fahren;
celsius = (5.0/9.0) * (fahren - 32.0);
cout << "The equivalent Celsius temperature is "
<< celsius << endl;
return 0;
}
3. (Modify) Rewrite the following program to use the symbolic constant PRIME in place of
the value 0.04 used in the program:
#include <iostream>
using namespace std;
int main()
{
float prime, amount, interest;
prime = 0.04; // prime interest rate
cout << <Enter the amount: ";
cin >> amount;
interest = prime * amount;
cout << "The interest earned is"
<< interest << " dollars" << endl;
return 0;
}
4. (Modify) Rewrite the following program so that the variable volts is changed to a sym-
bolic constant:
#include <iostream>
using namespace std;
int main()
{
double current, resistance, volts;
墌
157
Chapter 3
Symbolic Constants
volts = 12;
cout << " Enter the resistance: ";
cin >> resistance;
current = volts / resistance;
cout << "The current is " << current << endl;
return 0;
}
5. (Heat Transfer) Typically, all objects radiating heat do so at many different wavelengths.
(See the Technical Note in Section 3.5 for a description of wavelength.) The wavelength
at which an object emits its maximum heat energy can be found by using Wein’s Law:
␭max T = W
␭max is the maximum wavelength.
T is the object’s temperature in °K.
W is Wein’s constant = 2897 microns/°K.
a. Using Wein’s Law, write a C++ program that accepts an object’s temperature in
degrees Celsius and outputs the wavelength at which the object radiates its maximum
energy. Have your program declare Wein’s constant as the symbolic constant named
WEINCONSTANT.
b. After verifying that your program is working, use it to determine the maximum heat-
radiating wavelength for the sun, Earth, and Mars, with surface temperatures of 5727,
14, and 0.46 degrees Celsius, respectively.
3.6 A Case Study: Acid Rain
The use of coal as the major source of steam power began with the Industrial Revolution.
Currently, coal is one of the principal sources of electrical power generation in many
industrialized countries. Since the middle of the 19th century, it has been known that the
oxygen used in the burning process combines with the carbon and sulfur in coal to produce
carbon dioxide and sulfur dioxide. When these gases are released into the atmosphere, sulfur
dioxide combines with water and oxygen in the air to form sulfuric acid, which is transformed
into separate hydronium ions and sulfates (see Figure 3.17). The hydronium ions in the
atmosphere that fall to Earth as components of rain are what change the acidity levels of lakes
and forests.
The acid level of rain and lakes is measured on a pH scale by using this formula:
pH = - log10 (concentration of hydronium ions)
The concentration of hydronium ions is measured in units of moles/liter. A pH value of
7 indicates a neutral value (neither acidic nor alkaline), whereas levels below 7 indicate the
presence of an acid, and levels above 7 indicate the presence of an alkaline substance. For
example, sulfuric acid has a pH value of approximately 1, lye has a pH value of approximately
13, and distilled water typically has a pH value of 7. Marine life usually can’t survive in water
with a pH level below 4.
158 Assignment, Formatting, and Interactive Input
Using the formula for pH, you’ll write a C++ program, using the software development
procedure described in Chapter 2, that calculates the pH level of a substance based on a user
input value for the concentration of hydronium ions.
Step 1 Analyze the Problem
Although the problem statement provides technical information on the composition of acid
rain, from a programming viewpoint, this problem is rather simple. You have only one
required output (a pH level) and one input (the concentration of hydronium ions).
coal
smokestack
sulfur and carbon dioxide +
=
acid
rain
sulfates
hydronium
ions
sulfuric
acid
water
and
oxygen
in air
Figure 3.17 The formation of acid rain
159
Chapter 3
A Case Study: Acid Rain
Step 2 Develop a Solution
The algorithm for transforming the input to the required output is a straightforward use of
the pH formula. The pseudocode representation of the algorithm for entering input data,
processing data to produce the required output, and displaying output is as follows:
Display a prompt to enter an ion concentration level.
Read a value for the concentration level.
Calculate a pH level, using the given formula.
Display the calculated value.
To make sure you understand the formula used in the algorithm, do a hand calculation.
You can then use the result of this calculation to verify the result the program produces.
Assuming a hydronium concentration of 0.0001 (although any value would do), the pH level
is calculated as -log10 10-4
. Either by knowing that the logarithm of 10 raised to a power is
the power itself or by using a log table, the value of this expression is -(-4) = 4.
Step 3 Code the Solution
Program 3.16 shows using the algorithm in C++. The variable names were chosen to convey
the variables’ meanings in this application.
Program 3.16
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double hydron, pHlevel;
cout << "Enter the hydronium ion concentration: ";
cin >> hydron;
pHlevel = -log10(hydron);
cout << "The pH level is " << pHlevel << endl;
return 0;
}
Program 3.16 begins with two #include preprocessor statements, followed by the
main() function. Within main(), a declaration statement declares two floating-point
variables, hydron and pHlevel. The program then displays a prompt requesting input data
from the user. After the prompt is displayed, a cin statement is used to store the entered
160 Assignment, Formatting, and Interactive Input
data in the variable hydron. Finally, a value for pHlevel is calculated, using the logarithmic
library function, and displayed. As always, the program is terminated with a closing brace.
Step 4 Test and Correct the Program
A test run using Program 3.16 produced the following:
Enter the hydronium ion concentration level: 0.0001
The pH level is 4
Because the program performs a single calculation, and the result of this test run agrees
with your previous hand calculation, the calculation portion of the program has been tested
completely. It can now be used to calculate the pH level of other hydronium concentrations
with confidence that the results produced are accurate.
EXERCISES 3.6
1. (Practice) Enter, compile, and run Program 3.16 on your computer system.
2. (General Math) The value of ␲ can be approximated by this series:
4 1
1
3
1
5
1
7
− + − +






....
Using this formula, write a program that calculates and displays the value of ␲, using 2, 3,
and 4 terms of the series.
3. (General Math) The exponential function ex
, where e is known as Euler’s number (and
has the value 2.718281828459045 . . .) appears many times in descriptions of natural
phenomena. For example, radioactive decay, population growth, and the normal (bell-
shaped) curve used in statistical applications can be described by using this function. The
value of ex
can be approximated by using this series:
1
1 2 3 4 5 6
2 3 4 5 6
+ + + + + + +
x x x x x x
! ! ! ! ! !
...
Using this formula, write a program that calculates and displays the value of Euler’s num-
ber, using 1, 2, 3, and 4 terms of the series.
4. (General Math) The volume of oil stored in an underground 200-foot deep cylindrical
tank is determined by measuring the distance from the top of the tank to the surface of
the oil. Knowing this distance and the radius of the tank, the volume of oil in the tank
can be determined by using this formula:
volume = ␲ radius2
(200 - distance)
Using this information, write, compile, and execute a C++ program that accepts the radius
and distance measurements, calculates the volume of oil in the tank, and displays the two
161
Chapter 3
A Case Study: Acid Rain
input values and the calculated volume. Verify the results of your program by doing a
hand calculation using the following test data: radius = 10 feet and distance = 12 feet.
5. (General Math) The circumference of an ellipse (review Figure 3.5) is given by this
formula:
Circumference = +
( )
π a b)2
Using this formula, write a C++ program to calculate the circumference of an ellipse with
a minor radius, a, of 2.5 inches and a major radius, b, of 6.4 inches. (Hint: The square root
can be taken by raising the quantity 2[a2
+ b2
] to the 0.5 power.)
6. (General Math) The perimeter, approximate surface area, and approximate volume of an
in-ground pool are given by the following formulas:
perimeter = 2(length + width)
volume = length × width × average depth
underground surface area = 2(length + width)average depth + length × width
Using these formulas as a basis, write a C++ program that accepts the length, width, and
average depth measurements, and then calculates the pool’s perimeter, volume, and
underground surface area. In writing your program, make these two calculations immedi-
ately after entering the input data: length × width and length + width. The results of these
two calculations should be used, as needed, in the assignment statements for determining
the perimeter, volume, and underground surface area without recalculating them for each
equation. Verify your program’s results by doing a hand calculation, using the following
test data: length = 25 feet, width = 15 feet, and average depth = 5.5 feet. After verifying that
your program is working, use it to complete the following chart:
Length Width Depth Perimeter Volume Underground
Surface Area
25 10 5.0
25 10 5.5
25 10 6.0
25 10 6.5
30 12 5.0
30 12 5.5
30 12 6.0
30 12 6.5
7. (Heat Transfer) Radiation is the transfer of heat via electromagnetic wave propagation.
Examples of heat transfer are the heat radiated from the sun, the heat radiated from
Earth, and the heat given off in the evening by objects, such as cars and brick walls,
warmed by the sun during the day. The heat radiated by an object can be calculated by
using Stephan-Boltzmann’s Law:
E = e ␴ T4
162 Assignment, Formatting, and Interactive Input
E is the energy radiated per second per square meter of its surface.
e is the emissivity of the substance (a number between 0 and 1).
␴ is Stephan-Boltzmann’s constant (5.6697 × 10-8
Watts/m2
K4
).
T is the surface temperature in degrees Kelvin (°K = °C + 273).
An ideal radiator, such as the sun, has an emissivity of 1, and the heat generated from the
sun, with a surface temperature of approximately 6000°K, is as follows:
E = 5.6697 × 10-8
Watts/m2
K4
(6 × 103
K4
)
= 5.6697 × 10-8
Watts/m2
K4
(1296 × 1012
K4
) = 7.3 × 107
Watts/m2
= 73,000,000 Watts/m2
Using the formula and this information, write a C++ program that accepts a planet’s tem-
perature (assuming an emissivity of 1) and provides the heat generated from the planet as
its output. After determining that your program is working correctly (make sure it produces
the correct radiation for the sun), use it to complete the following chart (make sure to use
correct units):
Planet Average Surface
Temperature (°Celsius)
Heat Radiated
(Watts/m2
)
Mercury 270
Venus 462
Earth 14
Mars -46
Jupiter -108
Saturn -139
Uranus -197
Neptune -201
8. (Heat Transfer) During the day, heat is absorbed by many objects, such as cars, roofs,
and brick walls. This heat is then radiated back into the environment during the cooler
evening hours. Using Stephan-Boltzmann’s Law, E = e ␴ T4
(see Exercise 7), write a C++
program that determines the amount of radiation for the objects listed in the following
table. Your program should request the object’s average surface temperature and emissiv-
ity, and then calculate and display the heat radiated. Complete the following chart, mak-
ing three runs of the program:
Substance Average Surface
Temperature
(°Celsius)
Emissivity Heat Radiated
(Watts/m2
)
Automobile 47 .3
Brick 45 .9
Commercial roof 48 .05
163
Chapter 3
A Case Study: Acid Rain
9. (Electrical Eng.) a. Write, compile, and execute a C++ program that calculates and dis-
plays the voltage gain of a three-stage amplifier at a frequency of 1000 Hertz. The volt-
age gains of the stages are as follows:
Stage 1 gain: 23/[2.32 + (0.044f)2
]1/2
Stage 2 gain: 12/[6.72 + (0.34f)2
]1/2
Stage 3 gain: 17/[1.92 + (0.45f)2
]1/2
f is the frequency in Hertz. The voltage gain of the amplifier is the product of the gains
of each stage.
b. Redo Exercise 9a, assuming the frequency will be entered when the program runs.
3.7 A Closer Look: Programming Errors
The ideal in programming is to produce readable, error-free programs that work correctly and can
be modified or changed with a minimum of testing. To achieve this ideal, keep in mind the
different types of errors that can occur, when they’re usually detected, and how to correct them.
You can detect an error at any of the following times:
• Before a program is compiled
• While the program is being compiled
• While the program is running
• After the program has been executed and the output is being examined
The method for detecting errors before a program is compiled is called desk checking
because you’re usually sitting at a desk with the code in front of you. It refers to the process
of examining the source code for mistakes immediately after you type it.
Errors detected while the program is being compiled are called compile-time errors, and
errors that occur while the program is running are called runtime errors. Other names for
compile-time errors are syntax errors and parse errors, terms that emphasize the type of error
the compiler detects.
By now, you have probably encountered numerous compile-time errors. Beginning
programmers tend to be frustrated by them, but experienced programmers understand the
compiler is doing a lot of valuable checking, and correcting errors the compiler does detect
is usually easy. Because these errors occur while the program is being developed, not while
a user is performing an important task, no one but the programmer ever knows they occurred.
You fix them, and they go away.
Runtime errors are more troubling because they occur while a user is running the
program; in most commercial systems, the user isn’t the programmer. Many error types can
cause a runtime error, such as a hardware failure. From a programming standpoint, however,
most runtime errors are referred to as logic errors or faulty logic, which encompasses not
analyzing what the program should do or not anticipating how users can make the program
fail. For example, if a user enters data that results in an attempt to divide a number by zero,
a runtime error occurs.
As a programmer, the only way to protect against runtime errors is to anticipate
everything a person might do to cause errors and submit your program to rigorous testing.
Beginning programmers tend to blame users for an error caused by entering incorrect data,
164 Assignment, Formatting, and Interactive Input
but professionals don’t. They understand that a runtime error is a flaw that can damage the
reputation of the program and programmer.
To prevent compile-time and runtime errors, it’s more fruitful to determine what causes
them. As mentioned, compile-time errors are also called syntax errors: mistakes in the
structure or spelling of a statement. For example, examine the following statements:
cout << "There are four syntax errors heren
cot " Can you find tem";
They contain the following syntax errors:
1. A closing quotation mark is missing in line 1.
2. A terminating semicolon (;) is missing in line 1.
3. The keyword cout is misspelled in line 2.
4. The insertion operator, <<, is missing in line 2.
When the program is compiled, the compiler detects all these errors because they’re
syntax errors that violate the basic rules of C++. If they aren’t discovered by desk checking,
the compiler detects them and displays an error message.11 Sometimes the error message is
clear and the error is obvious; at other times, understanding the compiler’s error message
takes a little detective work. Because syntax errors are the only error type that can be
detected at compile time, the terms “compile-time errors” and “syntax errors” are used
interchangeably. Strictly speaking, however, compile-time refers to when the error is
detected, and syntax refers to the type of error detected.
The misspelling of “them” in the second statement isn’t a syntax error. Although this
spelling error results in displaying an undesirable output line, it’s not a violation of C++’s
syntax rules. It’s a typographical error, commonly referred to as a “typo.” The compiler
doesn’t catch this type of typographical error.12
Another error the compiler doesn’t catch is a logic error, which can cause a runtime error
or produce incorrect results. These errors are characterized by erroneous, unexpected, or
unintentional output that’s a direct result of some flaw in the program’s logic. These errors
can be detected by desk checking, by program testing, by accident when a user gets
erroneous output while the program is executing, or not at all. If the error is detected while
the program is executing, a runtime error can occur that generates an error message, causes
premature program termination, or both.
The most serious logic error is caused by not fully understanding the program’s
requirements because the logic in a program reflects the logic on which it’s coded. For
example, if a program’s purpose is to calculate the load-bearing strength of a steel beam and
the programmer doesn’t fully understand how to make the calculation, what inputs are
needed to perform the calculation, or what special conditions exist (such as how temperature
affects the beam), a logic error occurs. Because the compiler doesn’t detect these errors and
they often go undetected at runtime, they are always more difficult to detect than syntax
errors.
11
They might not, however, be detected at the same time. Frequently, one syntax error masks another error, and the second error is detected
after the first error is corrected.
12
The misspelling of a C++ keyword or a declared variable name that results in an undeclared name is caught, however, because it results in a
syntax error or an undeclared variable.
165
Chapter 3
A Closer Look: Programming Errors
If logic errors are detected, typically they’re revealed in one of two main ways. First, the
program executes to completion but produces incorrect results, such as the following:
• No output—This result is caused by omitting an output statement or using a
sequence of statements that inadvertently bypasses an output statement.
• Unappealing or misaligned output—This result is caused by an error in an output
statement.
• Incorrect numerical results—This result is caused by assigning incorrect values to
variables in an expression, using an incorrect arithmetic expression, omitting a
statement, making a round-off error, or using an improper sequence of statements.
Second, a runtime error occurs. Examples of logic errors that cause this result are
attempts to divide by zero or take the square root of a negative number.
Plan your program testing carefully to maximize the possibility of locating errors. In
addition, remember that although a single test can reveal the presence of an error, it does not
verify that another error isn’t lurking somewhere else in the program. Furthermore, the fact
that one test revealed no errors does not mean there are no errors.
After you discover an error, however, you must locate where it occurs and fix it. In
computer jargon, a program error is referred to as a bug, and the process of isolating,
correcting, and verifying the correction is called debugging.
Although no hard-and-fast rules exist for isolating the cause of an error, some useful
techniques can be applied. The first is preventive. Often programmers introduce errors in the
rush to code and run a program before understanding what’s required and how to achieve the
result, as you learned in Chapter 2. Many errors can be eliminated by desk checking the
program before entering or compiling it.
A second useful technique is imitating the computer by executing each statement by
hand as the computer would. This technique, called program tracing, involves writing down
each variable, as it’s encountered in the program, and listing the value that should be stored
in the variable as each input and assignment statement is encountered. Doing this sharpens
your programming skills because it helps you understand what each statement in your
program causes to happen.
A third useful technique is including some temporary code in your program that displays
the values of selected variables. If the displayed values are incorrect, you can determine what
part of your program generated them and make the necessary corrections. You could also add
temporary code that displays the values of all input data. This technique, called echo printing,
is useful in establishing that the program is receiving and interpreting input data correctly.
The most powerful technique is using a special program called a debugger. A debugger
program can control the execution of a C++ program, interrupt the C++ program at any point
in its execution, and display the values of all variables at the point of interruption.
Finally, no discussion of debugging is complete without mentioning the main ingredient
needed for isolating and correcting errors successfully: the attitude you bring to the task.
After you write a program, you naturally assume it’s correct. Taking a step back to be
objective about testing and finding errors in your own software is difficult. As a programmer,
you must remind yourself that just because you think your program is correct doesn’t make
it so. Finding errors in your own programs is a sobering experience but one that helps you
become a better programmer. The process can be exciting and fun if you approach it as a
detection problem, with you as the master detective.
166 Assignment, Formatting, and Interactive Input
3.8 Common Programming Errors
When using the material in this chapter, be aware of the following possible errors:
1. Forgetting to assign or initialize values for all variables before using them in an
expression. Values can be assigned by assignment statements, initialized in a
declaration statement, or assigned interactively by entering values with a cin
statement.
2. Using a mathematical library function without including the preprocessor statement
#include <cmath> (and on a UNIX-based system, forgetting to include the -lm
argument on the cc command line).
3. Using a library function without providing the correct number of arguments of the
proper data type.
4. Applying the increment or decrement operator to an expression. For example, the
expression (count + n)++ is incorrect. The increment and decrement operators
can be applied only to variables.
5. Forgetting to use the extraction operator, >>, to separate variables in a cin
statement.
6. A more unusual error occurs when increment and decrement operators are used with
variables appearing more than once in the same expression. This error occurs
because C++ doesn’t specify the order in which operands are accessed in an
expression. For example, the value assigned to result in the following statement
depends on the compiler:
result = i + i++;
If your compiler accesses the first operand (i) first, the preceding statement is
equivalent to
result = 2 * i;
i++;
However, if your compiler accesses the second operand (i++) first, the value of
the first operand is altered before it’s used the second time, and the value 2i + 1
is assigned to result. As a general rule, don’t use the increment or decrement
operator in an expression when the variable it operates on appears more than once
in the expression.
7. Being unwilling to test a program in depth. Being objective about testing your own
software is difficult, but as a programmer, you must remind yourself that just because
you think your program is correct doesn’t make it so.
3.9 Chapter Summary
1. An expression is a sequence of one or more operands separated by operators. An operand
is a constant, a variable, or another expression. A value is associated with an expression.
2. Expressions are evaluated according to the precedence and associativity of the operators
used in the expression.
167
Chapter 3
Chapter Summary
3. The assignment operator is the = symbol. Expressions using this operator assign a value
to a variable, and the expression also takes on a value. Because assignment is a C++
operation, the assignment operator can be used more than once in the same expression.
4. The increment operator, ++, adds one to a variable, and the decrement operator, --,
subtracts one from a variable. Both operators can be used as prefixes or postfixes. In a prefix
operation, the variable is incremented (or decremented) before its value is used. In a postfix
operation, the variable is incremented (or decremented) after its value is used.
5. C++ provides library functions for calculating square root, logarithmic, and other
mathematical computations. Programs using a mathematical function must include the
statement #include <cmath> or have a function declaration before calling the
mathematical function.
6. Every mathematical library function operates on its arguments to calculate a single value.
To use a library function effectively, you must know the function name, what the
function does, the number and data types of arguments the function expects, and the
data type of the returned value.
7. Values passed to a function are called arguments of the function. Arguments are passed
to a library function by including each argument, separated by commas, in the
parentheses following the function’s name. Each function has its own requirements for
the number and data types of the arguments that must be provided.
8. Functions can be included in larger expressions.
9. A cin statement is used for data input. cin accepts a stream of data from the keyboard
and assigns the data to variables. This is the general form of a statement
using cin:
cin >> var1 >> var2 . . . >> varn;
The extraction operator, >>, must be used to separate variable names in a cin
statement.
10. When a cin statement is encountered, the computer temporarily suspends further
execution until enough data has been entered for the number of variables in the cin
statement.
11. It’s a good programming practice to display a message before a cin statement that alerts
users to the type and number of data items to be entered. This message is called a
prompt. It’s even a better programming practice to permit only one input variable for
each cin statement.
12. Values can be equated to a single constant by using the const keyword. This keyword
creates a named constant that is read-only after it’s initialized in the declaration
statement. This declaration has the syntax
const dataType SymbolicName = initialValue;
and permits using the constant instead of the initialValue anywhere in the program
after the declaration.
168 Assignment, Formatting, and Interactive Input
Programming Projects for Chapter 3
1. (General Math) a. Write a C++ program to calculate and display the value of the slope of
the line connecting two points with the coordinates (3,7) and (8,12). Use the fact that the
slope between two points with the coordinates (x1,y1) and (x2,y2) is (y2 - y1) / (x2 - x1).
b. How do you know the result your program produced is correct?
c. After verifying the output your program produces, modify it to determine the slope of
the line connecting the points (2,10) and (12,6).
d. What do you think will happen if you use the points (2,3) and (2,4), which results in
a division by zero? How do you think this situation can be handled?
e. If your program doesn’t already do so, change its output to this:
The value of the slope is xxx.xx
The xxx.xx denotes placing the calculated value in a field wide enough for three places
to the left of the decimal point and two places to the right of it.
2. (General Math) a. Write a C++ program to calculate and display the midpoint
coordinates of the line segment connecting the two endpoints given in Exercise 1a. Use
the fact that the coordinates of the midpoint between two points with the coordinates
(x1,y1) and (x2,y2) are ((x1+x2)/2, (y1+y2)/2). Your program should produce the following
display (replacing the underscores with values your program calculates):
The x midpoint coordinate is _____
The y midpoint coordinate is _____
b. How do you know the midpoint values your program calculates are correct?
c. After verifying the output your program produces, modify it to determine the
midpoint coordinates of the line connecting the points (2,10) and (12,6).
d. If your program doesn’t already do so, change its output to this:
The x coordinate of the midpoint is xxx.xx
The y coordinate of the midpoint is xxx.xx
The xxx.xx denotes placing the calculated value in a field wide enough for three places
to the left of the decimal point and two places to the right of it.
3. (General Math) Modify the program written for Exercise 2 so that it accepts the x and
y coordinates of two points. Have your program determine and display the midpoints of
the two points (use the formula given in Exercise 2). Verify your program by using the
following test data:
Test data set 1: Point 1 = (0,0) and Point 2 = (16,0)
Test data set 2: Point 1 = (0,0) and Point 2 = (0,16)
Test data set 3: Point 1 = (0,0) and Point 2 = (-16,0)
Test data set 4: Point 1 = (0,0) and Point 2 = (0,-16)
Test data set 5: Point 1 = (-5,-5) and Point 2 = (5,5)
169
Chapter 3
Programming Projects
When you have finished your verification, use your program to complete the following chart:
First Point Second Point Midpoint
(4, 6) (16, 18)
(22, 3) (8, 12)
(-10, 8) (14, 4)
(-12, 2) (14, 3.1)
(3.1,-6) (20, 16)
(3.1, -6) (-16, -18)
4. (Biology) The number of bacteria, B, in a culture that’s subject to refrigeration can be
approximated by this formula:
B = 300000 e-0.032t
e is Euler’s number 2.71828 (rounded to five decimal places).
t is the time in hours the culture has been refrigerated.
Using this formula, write, compile, and execute a single C++ program that prompts the
user for a value of time, calculates the number of bacteria in the culture, and displays the
result. For testing purposes, check your program by using a test input of 10 hours. After
verifying your program, use it to determine the number of bacteria in the culture after
12, 18, 24, 36, 48, and 72 hours.
5. (Heat Transfer) The time it takes for a spherical object to cool from an initial
temperature of Tinit to a final temperature of Tfin, caused entirely by radiation, is
provided by Kelvin’s cooling equation:
t
Nk
e A T T
=






2
1 1
3 3
σ fin init
-
t is the cooling time in years.
N is the number of atoms.
k is Boltzmann’s constant = 1.38 × 10-23
m2
kg/s2
K (note that 1 Joule = 1 m2
kg/s2
).
e is emissivity of the object.
␴ is Stephan-Boltzmann’s constant = 5.6703 × 10-8
Watts/m2
K4
.
A is the surface area.
Tfin is the final temperature.
Tinit is the initial temperature.
Assuming an infinitely hot initial temperature, this formula reduces to
t
Nk
e AT
=
2 3
σ fin
170 Assignment, Formatting, and Interactive Input
Using this second formula, write a C++ program to determine the time it took Earth to cool
to its current surface temperature of 300°K from its initial infinitely hot state, assuming the
cooling is caused only by radiation. Use the information that the area of the Earth’s surface
is 5.15 × 1014
m2
, its emissivity is 1, the number of atoms contained in the Earth is 1.1 × 1050
,
and the radius of the Earth is 6.4 × 106
meters. Additionally, use the relationship that a
sphere’s surface area is given by this formula:
Surface area of a sphere = 4 ␲ r2
6. (Heat Transfer) The formula developed in Exercise 5 can be used to determine the
cooling time, t, caused only by radiation, of each planet in the solar system. For
convenience, this formula is repeated here (see Exercise 5 for a definition of each
symbol):
t
Nk
e AT
=
2 3
σ fin
A = surface area of a sphere = 4 ␲ r2
N = number of atoms = volume of the sphere
volume of an atom
Volume of a sphere = 4
3
␲ radius3
The volume of a single atom is approximately 1 × 10-29
m3
. Using this information and
the current temperatures and radii listed in the following chart, determine the time it
took each planet to cool to its current temperature, caused only by radiation.
Planet Current Average
Surface Temperature
(°Celsius)
Radius (km) Cooling Time
(years)
Mercury 270 2439
Venus 462 6051
Earth 14 6371
Mars -46 3396
Jupiter -108 7.1492 × 104
Saturn -139 6.0268 × 104
Uranus -197 2.5559 × 104
Neptune -201 2.4764 × 104
7. (Physics) When a particular rubber ball is dropped from a given height (in meters), its
impact speed (in meters/second) when it hits the ground is given by the formula
speed gh
= 2
where g is the acceleration caused by gravity and h is the height. The ball then rebounds
to 2/3 the height from which it last fell. Using this information, write, test, and run a C++
program that calculates and displays the impact speed of the first three bounces and the
171
Chapter 3
Programming Projects
rebound height of each bounce. Test your program by using an initial height of
2.0 meters. Run the program twice, and compare the results for dropping the ball on
Earth (g = 9.81 meters/sec2
) and on the moon (g = 1.67 meters/sec2
).
8. (Electrical Eng.) a. The voltage gain of an amplifier is given by this formula:
275
23 0 5
2 2
+








. f
n
voltage gain =
f is the frequency in Hz.
n is the number of stages in the amplifier.
Using this formula, write, compile, and execute a C++ program to determine the value
of the voltage gain for a four-stage amplifier operating at a frequency of 120 Hz. Your
program should produce the following display:
At a frequency of xxxxx Hertz, the voltage gain is yyyyy
Your program should replace xxxxx with the frequency and yyyyy with the voltage gain.
b. Manually check the value your program produces. After verifying that your program
is working correctly, modify it to determine the voltage gain of a 12-stage amplifier
operating at a frequency of 9500 Hz.
9. (Electrical Eng.) Write, compile, and execute a C++ program that calculates and
displays the value of the current flowing through an RC circuit (see Figure 3.18). The
circuit consists of a battery connected in a series to a switch, a resistor, and a capacitor.
When the switch is closed, the current, i, flowing through the circuit is given by this
formula:
i = (E/R) e-t/RC
E is the voltage of the battery in volts.
R is the value of the resistor in ohms.
C is the value of the capacitor in farads.
t is the time in seconds after the switch is closed.
e is Euler’s number, which is 2.71828 (rounded to five decimal places).
Using this formula, write, compile, and run a C++ program to determine the voltage
across the capacitor shown in Figure 3.18 when t is 0.31 seconds. (Note: The value of RC
is referred to as the system’s time constant.)
The program should prompt the user to enter appropriate values and use input
statements to accept the data. In constructing the prompts, use statements such as
172 Assignment, Formatting, and Interactive Input
“Enter the voltage of the battery.” Verify your program’s operation by calculating by hand
the current for the following test data:
Test data set 1: Voltage = 20 volts, R = 10 ohms, RC = 0.044, t = 0.023 seconds.
Test data set 2: Voltage = 35, R = 10 ohms, RC = 0.16, t = 0.067 seconds.
b. Check the value computed by your program by hand. After verifying that your program
is working correctly, use your program to complete the following chart:
Voltage V
(volts)
Resistance R
(ohms)
RC (Time
Constant)
Time t (sec) Current i (amps)
35 10 0.16 0.11
35 10 0.16 0.44
35 10 0.16 0.83
15 10 0.55 0.11
15 10 0.55 0.44
15 10 0.55 0.067
6 1000 2.6 12.4
10. (Electrical Eng.) The amplification of electronic circuits is measured in units of
decibels, which is calculated as
10 LOG (Po/Pi)
where Po is the power of the output signal and Pi is the power of the input signal. Using
this formula, write, compile, and execute a C++ program to calculate and display the
decibel amplification, in which the output power is 50 times the input power. Verify your
program’s result by using a hand calculation. After verifying that your program is working
correctly, use it to determine the amplification of a circuit, where output power is
4.639 Watts and input power is 1 Watt.
R
C
E
Switch
Figure 3.18 A series RC circuit
173
Chapter 3
Programming Projects
11. (Acoustics) The loudness of a sound is measured in units of decibels and is calculated
as shown:
10 LOG (SL/RL)
SL is the intensity of the sound being measured.
RL is a reference sound-intensity level.
Using this formula, write a C++ program that calculates and displays the decibel loudness
of a busy street having a sound intensity of 10,000,000 RL. Verify your program’s result
by using a hand calculation. After verifying that your program is working correctly, use
it to determine the sound level in decibels of the following sounds:
a. A whisper at sound intensity 200 RL
b. A rock band playing at sound intensity 1,000,000,000,000 RL
c. An airplane taking off at sound intensity 100,000,000,000,000 RL
12. (General Math) a. A balance has the following size weights: 100 lb, 50 lb, 10 lb, 5 lb,
and 1 lb. The number of 100 lb and 50 lb weights required to weigh an object weighing
WEIGHT pounds can be calculated by using the following C++ statements:
// Determine the number of 100 lb weights
w100 = int(WEIGHT/100)
// Determine the number of 50 lb weights
w50 = int((WEIGHT - w100 * 100)/50)
Using these statements as a starting point, write a C++ program that calculates the
number of each type of weight needed to weigh a 789 lb object.
b. Without compiling or executing your program, manually check the effect of each
statement in the program and determine what’s stored in each variable as each
statement is encountered.
c. After verifying that your algorithm works correctly, compile and execute your program.
Verify that the results your program produces are correct. After verifying that your
program is working correctly, use it to determine the weights required to weigh a 626 lb
object.
174 Assignment, Formatting, and Interactive Input
Engineering and Scientific Disciplines
Electrical Engineering
Electrical engineering, the largest engineering field, deals with applying the principles of
electricity and electromagnetism to the manufacture of all forms of machines and
devices that use electricity or produce electrical energy. In the mid-1800s, this field was
concerned solely with generating electrical energy, but it has evolved into a broad field
encompassing the following areas, among others:
앫 Power: This area involves generation of electrical energy in large fossil-fuel,
nuclear, solar, and hydroelectric plants as well as efficient use of electrical energy
by means of motors or illumination devices. Also important are transmitting and
distributing electrical energy through overhead lines, microwaves, light pipes, and
superconducting lines.
앫 Solid-state electronics: Through modern physics and materials science, semicon-
ducting materials are developed and used to construct microcircuitry for moni-
toring and controlling the operations of all kinds of devices, from video games to
assembly-line robots. The improved reliability, rapidly shrinking size, and reduced
power requirements of modern miniaturized electrical components have created
limitless opportunities for applications.
앫 Communications: This area involves designing and constructing equipment used
to transmit information via electricity or electromagnetic waves (radio, light,
microwaves, and so on). This field used to include antenna characteristics and
radar, but using laser for communication is the current topic.
앫 Computers and robotics: Although electronics deals with principles associated
with the functions of components, computer engineers are concerned with
designing the complex circuitry that interweaves components into a computer.
Microprocessors, or small computers, are designed to constantly monitor and
control the operations of a piece of equipment, such as a lathe or an autopilot.
175
Chapter 3
Programming Projects
This page intentionally left blank
Chapter
4
Selection Structures
4.1 Selection Criteria
4.2 The if-else Statement
4.3 Nested if Statements
4.4 The switch Statement
4.5 A Case Study: Solving
Quadratic Equations
4.6 A Closer Look: Program
Testing
4.7 Common Programming Errors
4.8 Chapter Summary
The term “flow of control” refers to the order in which a program’s statements are executed. Unless
directed otherwise, the normal, default flow of control for all programs is sequential. This term means
statements are executed in sequence, one after another, in the order in which they’re placed in a program.
In addition to sequential execution, all high-level languages provide three other control structures
to alter the sequential flow of control in precisely defined ways. Here, the term “control structure” simply
means a construction that specifies the order in which statements are to be executed. The three additional
control structures are called selection, repetition, and invocation.
As you might have guessed by its name, a selection structure is used to select statements to be
performed next, and a repetition structure is used to force a repeat execution of a set of statements.
Invocation is a means of invoking, or forcing, a set of statements, which have previously been combined
into a separate function, to be executed at a particular point in a program.
As any algorithm, no matter how complex, can be programmed by using one or more of the four
standardized flow of control structures (sequential, selection, repetition, and invocation), understanding
how each of these structures is constructed and operates is a primary requirement for all programmers.
This chapter discusses C++’s selection control structures, and Chapters 5 and 6 cover repetition and
invocation control structures.
4.1 Selection Criteria
In solving many problems, different actions must be taken, depending on the data’s value.
Examples of simple situations include calculating an area only if the measurements are
positive, performing a division only if the divisor isn’t zero, printing different messages
depending on the value of a grade received, and so on.
The if-else statement in C++ is used to implement such a decision structure in its
simplest form—choosing between two alternatives. The most commonly used pseudocode
syntax of this statement is as follows:
if (condition)
statement executed if the condition is true;
else
statement executed if the condition is false;
When a running program encounters the if statement, the condition is evaluated to determine
its numerical value, which is then interpreted as true or false. If the condition evaluates to
any positive or negative non-zero numerical value, the condition is considered a “true” condition
and the statement following the if is executed. If the condition evaluates to a zero numerical
value, the condition is considered a “false” condition and the statement following the else is
executed. The else part of the statement is optional and can be omitted.
Relational Operators
The condition used in an if statement can be any valid C++ expression (including, as you’ll
see, even an assignment expression). The most commonly used conditions, however, are
simple relational expressions. A simple relational expression consists of a relational operator
that compares two operands, as shown in Figure 4.1.
Although each operand in a relational expression can be a variable or a constant,
relational operators must be one of those listed in Table 4.1. These relational operators can
be used with integer, float, double, or character operands but must be typed exactly as shown
in Table 4.1. For example, although the following examples are all valid,
age > 40 length <= 50 temp > 98.6
3 < 4 flag == done idNum == 682
day != 5 2.0 > 3.3 hours > 40
operand operand
expression
relational
operator
watts < 15.2
Figure 4.1 A simple relational expression
178 Selection Structures
the following are invalid:
length =< 50 // operator out of order
2.0 >> 3.3 // invalid operator
flag = = done // spaces are not allowed
Table 4.1 C++’s Relational Operators
Relational Operator Meaning Example
< Less than age < 30
> Greater than height > 6.2
<= Less than or equal to taxable <= 20000
>= Greater than or equal to temp >= 98.6
== Equal to grade == 100
!= Not equal to number != 250
The terms relational expression and condition are frequently used as synonyms, and both
terms are used interchangeably in this book. Like all C++ expressions, relational expressions
are evaluated to yield a numerical result.1 In a relational expression, the value of the
expression can be only the integer value 1 or 0. These values are interpreted as true and false,
respectively. Conversely, a relational expression that’s true always evaluates to an integer value of
1, and a relational expression that’s false always evaluates to an integer value of 0.
For example, because the relationship 3 < 4 is always true, this expression has a value
of 1, and because the relationship 2.0 > 3.0 is always false, the value of the expression
itself is 0. This rule can be verified by the following statements,
cout << "The value of 3 < 4 is " << (3 < 4) << endl;
cout << "The value of 2.0 > 3.0 is " << (2.0 > 3.0) << endl;
cout << "The value of true is " << true << endl;
cout << "The value of false is " << false << endl;
which result in this display:
The value of 3 < 4 is 1
The value of 2.0 > 3.0 is 0
The value of true is 1
The value of false is 0
The value of a relational expression such as hours > 40 depends on the value stored
in the variable hours. In a C++ program, a relational expression’s value isn’t as important as
the interpretation C++ places on the value when the expression is used as part of a selection
statement. In these statements, which are explained in the next section, you’ll see that C++
uses a zero value to represent a false condition and any non-zero value to represent a true
condition. The selection of which statement to execute next is then based on the value.
In addition to numerical operands, character data can be compared by using relational
operators. For these comparisons, the char values are coerced to int values automatically
for the comparison. For example, in Unicode, the letter 'A' is stored by using a code with
a lower numerical value than the letter 'B', the code for 'B' has a lower value than the
1
In this regard, C++ differs from other high-level languages, which yield a Boolean (true or false) result.
179
Chapter 4
Selection Criteria
code for 'C', and so on. For character sets coded in this manner, the following conditions are
evaluated as shown:
Expression Value Interpretation
'A' > 'C' 0 false
'D' <= 'Z' 1 true
'E' == 'F' 0 false
'g' >= 'm' 0 false
'b' != 'c' 1 true
'a' == 'A' 0 false
'B' < 'a' 1 true
'b' > 'Z' 1 true
Comparing letters is essential in alphabetizing names or using characters to select a
choice in decision-making situations. Strings of characters can also be compared, and two
string expressions can be compared by using relational operators or the string class’s
comparison methods (discussed in Section 9.3). In the ASCII character set, a blank precedes
(and is considered “less than”) all letters and numbers; the letters of the alphabet are stored
in order from A to Z; and digits are stored in order from 0 to 9. In this sequence, lowercase
letters come after (are considered “greater than”) uppercase letters, and letter codes come
after (are “greater than”) digit codes (see Appendix B).
When two strings are compared, their characters are compared one pair at a time (both
first characters, then both second characters, and so on). If no differences are found, the
strings are equal; if a difference is found, the string with the first lower character is considered
the smaller string. Following are examples of string comparisons:
Expression Value Interpretation Comment
"Hello" > "Good-bye" 1 true The first H in Hello is greater
than the first G in Good-bye.
"SMITH" > "JONES" 1 true The first S in SMITH is greater
than the first J in JONES.
"123" > "1227" 1 true The third character in 123,
the 3, is greater than the third
character in 1227, the 2.
"Behop" > "Beehive" 1 true The third character in Behop,
the h, is greater than the third
character in Beehive, the
second e.
"He" == "She" 0 false The first H in He is not equal
to the first S in She.
"plant" < "planet" 0 false The t in plant is greater than
the e in planet.
180 Selection Structures
Logical Operators
In addition to using simple relational expressions as conditions, more complex conditions can
be created by using the logical operators AND, OR, and NOT. These operators are
represented by the symbols &&, ||, and !, respectively.
When the AND operator, &&, is used with two simple expressions, the condition is true
only if both expressions are true by themselves. Therefore, the logical condition
(voltage > 48) && (milliamp < 10)
is true only if voltage is greater than 48 and milliamp is less than 10. Because relational
operators have a higher precedence than logical operators, the parentheses in this logical
expression could have been omitted.
The logical OR operator, ||, is also used with two expressions. When using the OR
operator, the condition is satisfied if one or both of the two expressions are true. Therefore,
the condition
(voltage > 48) || (milliamp < 10)
is true if voltage is greater than 48, milliamp is less than 10, or both conditions are true.
Again, the parentheses surrounding the relational expressions are included to make the
statement easier to read. Because relational operators have a higher precedence than logical
operators, the same evaluation is made even if the parentheses are omitted.
For the declarations
int i, j;
double a, b, complete;
the following are valid conditions:
a > b
(i == j) || (a < b) || complete
(a/b > 5) && (i <= 20)
Before these conditions can be evaluated, the values of a, b, i, j, and complete must
be known. Assuming a = 12.0, b = 2.0, i = 15, j = 30, and complete = 0.0, the previous
expressions yield the following results:
Expression Value Interpretation
a > b 1 true
(i == j) || (a < b) || complete 0 false
(a/b > 5) && (i <= 20) 1 true
The NOT operator, !, is used to change an expression to its opposite state; that is, if the
expression has a non-zero value (true), the statement !expression produces a zero value
(false). If an expression is false to begin with (has a zero value), !expression is true and
evaluates to 1. For example, if the number 26 is stored in the variable age, the expression
age > 40 has a value of 0 (false), and the expression !(age > 40) has a value of 1
(true). Because the NOT operator is used with only one expression, it’s a unary operator.
181
Chapter 4
Selection Criteria
Relational and logical operators have a hierarchy of execution similar to arithmetic
operators. Table 4.2 lists the precedence of these operators in relation to the other operators
you have used.
Table 4.2 Operator Precedence and Associativity
Operator Associativity
! unary – ++ -- Right to left
* / % Left to right
+ – Left to right
< <= > >= Left to right
== != Left to right
&& Left to right
|| Left to right
= += –= *= /= Right to left
The following chart illustrates using an operator’s precedence and associativity to
evaluate relational expressions, assuming the following declarations:
char key = 'm';
int i = 5, j = 7, k = 12;
double x = 22.5;
Expression Equivalent Expression Value Interpretation
i + 2 == k - 1 (i + 2) == (k - 1) 0 false
3 * i - j < 22 (3 * i) - j < 22 1 true
i + 2 * j > k (i + (2 * j)) > k 1 true
k + 3 <= -j + 3 * i (k + 3) <= ((-j) + (3*i)) 0 false
'a' + 1 == 'b' ('a' + 1) == 'b' 1 true
key - 1 > 'p' (key - 1) > 'p' 0 false
key + 1 == 'n' (key + 1) == 'n' 1 true
25 >= x + 1.0 25 >= (x + 1.0) 1 true
As with all expressions, parentheses can be used to alter the assigned operator priority
and improve the readability of relational expressions. By evaluating the expressions in
parentheses first, the following compound condition is evaluated as shown:
(6 * 3 == 36 / 2) || (13 < 3 * 3 + 4) && !(6 - 2 < 5)
(18 == 18) || (13 < 9 + 4) && !(4 < 5)
1 || (13 < 13) && !1
1 || 0 && 0
1 || 0
1
182 Selection Structures
A Numerical Accuracy Problem
In C++’s relational expressions, a subtle numerical accuracy problem related to single-
precision and double-precision numbers can occur. Because of the way computers store these
numbers, you should avoid testing for equality of single-precision and double-precision
values and variables by using the relational operator ==.
The reason is that many decimal numbers, such as 0.1, can’t be represented in binary
with a finite number of bits, so testing for exact equality for these numbers can fail. When
you want equality of noninteger values, it’s better to require that the absolute value ofthe
difference between operands be less than some extremely small value. Therefore, for
single-precision and double-precision operands, the general expression
operandOne == operandTwo
should be replaced by the condition
abs(operandOne – operandTwo) < 0.000001
where the value 0.000001 can be altered to any other acceptably small value. Therefore, if the
difference between the two operands is less than 0.000001 (or another user-selected amount),
the two operands are considered essentially equal. For example, if x and y are single-
precision variables, a condition such as
x/y == 0.35
should be programmed as the following:
abs(x/y - 0.35) < EPSILON
EPSILON can be a constant set to any acceptably small value, such as 0.000001.2 Not
requiring exact equivalence to zero ensures that slight inaccuracies in representing noninte-
ger numbers in binary don’t affect evaluation of the tested condition. Because all computers
have an exact binary representation of 0, comparisons for exact equality to 0 don’t have this
numerical accuracy problem.
EXERCISES 4.1
1. (Practice) Determine the value of the following expressions, assuming a = 5, b = 2, c = 4,
d = 6, and e = 3:
a. a > b
b. a != b
c. d % b == c % b
d. a * c != d * b
e. d * b == c * e
2
Using the abs() function requires including the cmath header file by placing the preprocessor command #include<cmath> before or after
#include<iostream>. UNIX-based systems also require including the math library with the -lm command-line argument.
183
Chapter 4
Selection Criteria
f. !(a * b)
g. !(a % b * c)
h. !(c % b * a)
i. b % c * a
2. (Practice) Using parentheses, rewrite the following expressions to indicate their order of
evaluation correctly. Then evaluate each expression, assuming a = 5, b = 2, and c = 4.
a. a % b * c && c % b * a
b. a % b * c || c % b * a
c. b % c * a && a % c * b
d. b % c * a || a % c * b
3. (Practice) Write relational expressions to express the following conditions (using variable
names of your choosing):
a. The distance is equal to 30 feet.
b. The ambient temperature is 86.4 degrees.
c. A speed is 55 mph.
d. The current month is 12 (December).
e. The letter input is K.
f. A length is greater than 2 feet and less than 3 feet.
g. The current day is the 15th day of the 1st month.
h. The automobile’s speed is 35 mph and its acceleration is greater than 4 mph per second.
i. An automobile’s speed is greater than 50 mph and it has been moving for at least
5 hours.
j. The code is less than 500 characters and takes more than 2 microseconds to transmit.
4. (Practice) Determine the value of the following expressions, assuming a = 5, b = 2,
c = 4, and d = 5:
a. a == 5
b. b * d == c * c
c. d % b * c > 5 || c % b * d < 7
4.2 The if-else Statement
The if-else structure directs the computer to select between two statements based on the
result of a comparison. For example, suppose you need to calculate the area of a circle, given
the radius as an input value. If the input is a negative number, you want to print a message,
using one cout statement, that the radius can’t be a negative value; otherwise, you calculate
and print the circle’s area, using a second cout statement. The if-else structure can be
184 Selection Structures
used in this situation to select the correct operation based on whether the radius is negative.
This is the general syntax of the if-else statement:
if (expression) statement1;
else statement2;
The expression is evaluated first. If its value is non-zero, statement1 is executed.
If its value is zero, the statement after the keyword else is executed. Therefore, one of the
two statements (statement1 or statement2, but not both) is always executed, depending
on the expression’s value. Notice that the tested expression must be enclosed by parentheses
and a semicolon is placed after each statement.
For clarity, the if-else statement is typically written on four lines in this form:
if (expression) no semicolon here
statement1;
else no semicolon here
statement2;
The form of the if-else statement that’s used typically depends on the length of
statement1 and statement2. However, when using this four-line form, don’t put a
semicolon after the parentheses or the else keyword. The semicolons are placed only at the
ends of statements. Figure 4.2 shows the flowchart for the if-else statement.
As a specific example of an if-else structure, take a look at constructing a C++
program for determining a circle’s area by examining the value of the radius first. The
condition to be tested is whether the radius is less than 0, so the following is an appropriate
if-else statement for this situation:
if (radius < 0.0)
cout << "A negative radius is invalid" << endl;
else
cout << "The area of this circle is " << 3.1416 * pow(radius,2) << endl;
The relational operator < is used to represent the condition “less than.” If the value of
radius is less than 0, the condition is true (has a value of 1) and the statement cout <<
"A negative radius is invalid"; is executed. If the condition is not true, the value
of the expression is 0, and the statement after the else keyword is executed. Program 4.1
shows using this statement in a complete program.
185
Chapter 4
The if-else Statement
Program 4.1
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double radius;
cout << "Please type in the radius: ";
cin >> radius;
if (radius < 0.0)
cout << "A negative radius is invalid" << endl;
else
cout << "The area of this circle is " << 3.1416 * pow(radius,2) << endl;
return 0;
}
next
statement
statement 1
is
condition
true?
previous
statement
no
yes
(else part)
statement 2
Figure 4.2 The if-else flowchart
186 Selection Structures
A blank line is inserted before and after the if-else statement to highlight it in the
program. This format is used throughout the book to emphasize the statement being
discussed.
To illustrate selection in action, Program 4.1 is run twice with different input data. These
are the results:
Please type in the radius: -2.5
A negative radius is invalid
and
Please type in the radius: 2.5
The area of this circle is 19.635
In reviewing this output, observe that the radius in the first run is less than 0, and the
if part of the if-else structure executes the cout statement correctly, telling the user
that a negative radius is invalid. In the second run, the radius isn’t negative, and the else
part of the if-else structure is used to yield this correct area computation:
3.1416 * (2.5)2
= 19.635
Although any expression can be tested by an if-else statement, relational expressions
are used most often. However, statements such as the following are valid:
if (num)
cout << "Bingo!";
else
cout << "You lose!";
Because num is a valid expression by itself, the message Bingo! is displayed if num has any
non-zero value, and the message You lose! is displayed if num has a value of zero.
Compound Statements
Although only a single statement is permitted in the if and else parts of the if-else
statement, each single statement can be a compound statement. A compound statement is a
sequence of single statements between braces, as shown in this example:
{
statement1;
statement2;
statement3;
.
.
.
last statement;
}
187
Chapter 4
The if-else Statement
Using braces to enclose a set of statements creates a single block of statements, which
can be used anywhere in a C++ program in place of a single statement. The next example
shows using a compound statement in the general form of an if-else statement:
if (expression)
{
statement1; // as many statements as necessary
statement2; // can be put inside the braces
statement3; // each statement must end with a ;
}
else
{
statement4;
statement5;
.
.
last statement;
}
Program 4.2 shows using a compound statement in an actual program.
Program 4.2 checks whether the value in tempType is f. If so, the compound statement
corresponding to the if part of the if-else statement is executed. Any other letter in
tempType results in execution of the compound statement corresponding to the else part.
A sample run of Program 4.2 follows:
Enter the temperature to be converted: 212
Enter an f if the temperature is in Fahrenheit
or a c if the temperature is in Celsius: f
The equivalent Celsius temperature is 100.00
188 Selection Structures
Program 4.2
#include <iostream>
#include <iomanip>
using namespace std;
// a temperature conversion program
int main()
{
char tempType;
double temp, fahren, celsius;
cout << "Enter the temperature to be converted: ";
cin >> temp;
cout << "Enter an f if the temperature is in Fahrenheit";
cout << "n or a c if the temperature is in Celsius: ";
cin >> tempType;
// set output formats
cout << setiosflags(ios::fixed)
<< setiosflags(ios::showpoint)
<< setprecision(2);
if (tempType == 'f')
{
celsius = (5.0 / 9.0) * (temp - 32.0);
cout << "nThe equivalent Celsius temperature is "
<< celsius << endl;
}
else
{
fahren = (9.0 / 5.0) * temp + 32.0;
cout << "nThe equivalent Fahrenheit temperature is "
<< fahren << endl;
}
return 0;
}
189
Chapter 4
The if-else Statement
Block Scope
All statements contained in a compound statement constitute a single block of code, and any
variable declared in this block has meaning only between its declaration and the closing
braces defining the block. For example, take a look at the following example, which consists
of two blocks of code:
{ // start of outer block
int a = 25;
int b = 17;
cout << "The value of a is " << a
<<" and b is " << b << endl;
{ // start of inner block
double a = 46.25;
int c = 10;
cout << "a is now " << a
<< " b is now " << b
<< " and c is " << c << endl;
} // end of inner block
cout << "a is now " << a
<< " and b is " << b << endl;
} // end of outer block
This section of code produces the following output:
The value of a is 25 and b is 17
a is now 46.25 b is now 17 and c is 10
a is now 25 and b is 17
This output is produced as follows: The first block of code defines two variables named
a and b, which can be used anywhere in this block after their declaration, including any block
inside this outer block. In the inner block, two new variables have been declared, named a
and c. The a defined in the inner block is stored in a different memory location than the a
defined in the outer block. Therefore, at this stage, four different variables have been
created, two with the same name. When a variable is referenced, the compiler attempts to
first access a variable with the correct name that has been declared in the block containing
the reference. If the referenced variable hasn’t been defined in the block, the compiler
attempts to access the variable declared in the next outer block, until a valid access results.
190 Selection Structures
Therefore, the values of the variables a and c referenced in the inner block use the
values of the variables a and c declared in that block. Because no variable named b was
declared in the inner block, the value of b displayed from within the inner block is obtained
from the outer block. Finally, the last cout statement, which is outside the inner block,
displays the value of the variable a declared in the outer block. If an attempt is made
todisplay thevalue of c anywhere in the outer block, the compiler issues an error message
stating that c is an undefined symbol.
The area in a program where a variable can be used is formally referred to as the scope
of the variable, and you delve into this subject in Chapter 6.
One-Way Selection
A useful modification of the if-else statement involves omitting the else part of the
statement and has this shortened and often useful form:
if (expression)
statement;
The statement following if (expression) is executed only if the expression has a
non-zero value (a true condition). As before, the statement can be a compound statement.
Figure 4.3 shows the flowchart for this statement.
Point of Information
Placement of Braces in a Compound Statement
A common practice for some C++ programmers is placing the opening brace of a com-
pound statement on the same line as the if and else statements. Using this conven-
tion, the if statement in Program 4.2 would look like the following example. (This
placement is a matter of style only—both styles are used, and both are acceptable.)
if (tempType == 'f') {
celsius = (5.0 / 9.0) * (temp - 32.0);
cout << "nThe equivalent Celsius temperature is "
<< celsius << endl;
}
else {
fahren = (9.0 / 5.0) * temp + 32.0;
cout << "nThe equivalent Fahrenheit temperature is "
<< fahren << endl;
}
191
Chapter 4
The if-else Statement
This modified form of the if statement is called a one-way if statement. Program 4.3 uses
this statement to display a message only for cars that have been driven more than 3000.0 miles.
To see its one-way selection criteria in action, Program 4.3 was run twice, each time with
different input data. Only the input data for the first run causes the message Car 256 is
over the limit to be displayed.
Please type in car number and mileage: 256 3562.8
Car 256 is over the limit.
End of program output.
and
Please type in car number and mileage: 23 2562.3
End of program output.
next
statement
statement
is
condition
true?
previous
statement
no
yes
Figure 4.3 A one-way if statement
192 Selection Structures
Program 4.3
#include <iostream>
using namespace std;
int main()
{
const double LIMIT = 3000.0;
int idNum;
double miles;
cout << "Please type in car number and mileage: ";
cin >> idNum >> miles;
if(miles > LIMIT)
cout << " Car " << idNum << " is over the limit.n";
cout << "End of program output.n";
return 0;
}
Problems Associated with the if-else Statement
Two of the most common problems encountered in using C++’s if-else statement are the
following:
• Misunderstanding the full implications of what an expression is
• Using the assignment operator, =, in place of the relational operator ==
Recall that an expression is any combination of operands and operators that yields a
result. This definition is much broader and more encompassing than is apparent at first. For
example, all the following are valid C++ expressions:
age + 5
age = 30
age == 40
Assuming the variables are declared correctly, each of the preceding expressions yields a
result. Program 4.4 uses cout statements to display the value of these expressions when
age = 18.
193
Chapter 4
The if-else Statement
Program 4.4
#include <iostream>
using namespace std;
int main()
{
int age = 18;
cout << "The value of the first expression is " << (age + 5) << endl;
cout << "The value of the second expression is " << (age = 30) << endl;
cout << "The value of the third expression is " << (age == 40) << endl;
return 0;
}
The display Program 4.4 produces is as follows:
The value of the first expression is 23
The value of the second expression is 30
The value of the third expression is 0
As the output of Program 4.4 shows, each expression has a value associated with it. The
value of the first expression is the sum of the variable age plus 5, which is 23. The value of
the second expression is 30, which is also assigned to the variable age. The value of the third
expression is 0 because age is not equal to 40, and a false condition is represented in C++
with a value of 0. If the value in age had been 40, the relational expression a == 40 would
be true and have a value of 1.
Now assume that the relational expression age == 40 was intended to be used in this
if statement,
if (age == 40)
cout << "Happy Birthday!";
but was mistyped as age = 40, resulting in the following:
if (age = 40)
cout << "Happy Birthday!";
Because the mistake results in a valid C++ expression, and any C++ expression can be
tested by an if statement, the resulting if statement is valid and causes the message Happy
Birthday! to be displayed regardless of what value was previously assigned to age. Can
you see why?
The condition tested by the if statement doesn’t compare the value in age to the
number 40. It assigns the number 40 to age. That is, the expression age = 40 is not a
relational expression at all; it’s an assignment expression. At the completion of the assign-
ment, the expression itself has a value of 40. Because C++ treats any non-zero value as true,
194 Selection Structures
Point of Information
The Boolean Data Type
Before the current ANSI/ISO C++ standard, C++ didn’t have a built-in Boolean data
type with its two Boolean values, true and false. Because this data type wasn’t
originally part of the language, a tested expression could not evaluate to a Boolean
value. Therefore, the syntax
if(Boolean expression is true)
execute this statement;
also wasn’t built into C or C++. Instead, both C and C++ use the more encompassing
syntax,
if(expression)
execute this statement;
where expression is any expression that evaluates to a numeric value. If the value of
the tested expression is a non-zero value, it’s considered true, and only a zero value is
considered false.
As the ANSI/ISO C++ standard specifies, C++ has a built-in Boolean data type con-
taining the values true and false. As you learned in Chapter 2, Boolean variables
are declared with the bool keyword. As currently implemented, the actual values that
the Boolean values true and false represent are the integer values 1 and 0,
respectively. For example, examine the following program, which declares two Boolean
variables:
#include <iostream>
using namespace std;
int main()
{
bool t1, t2;
t1 = true;
t2 = false;
cout <<"The value of t1 is " << t1
<< "nand the value of t2 is " << t2 << endl;
return 0;
}
This program produces the following output:
The value of t1 is 1
and the value of t2 is 0
continued...
195
Chapter 4
The if-else Statement
the cout statement is executed. Another way of looking at it is to realize that the if
statement is equivalent to the following two statements:
age = 40; // assign 40 to age
if (age) // test the value of age
cout << "Happy Birthday!";
Because a C++ compiler has no means of knowing that the expression being tested isn’t
the one you want, you must be especially careful when writing conditions.
EXERCISES 4.2
1. (Practice) Write appropriate if statements for the following conditions:
a. If an angle is equal to 90 degrees, print the message “The angle is a right angle”;
else, print the message “The angle is not a right angle.”
b. If the temperature is above 100 degrees, display the message “above the boiling point
of water”; else, display the message “below the boiling point of water.”
c. If the number is positive, add the number to the variable positivesum; else, add
the number to the variable negativesum.
d. If the slope is less than 0.5, set the variable flag to zero; else, set flag to one.
Point of Information
The Boolean Data Type (continued)
As shown by this output, the Boolean values true and false are represented by the
integer values 1 and 0 and have the following relationships:
!true= is false
!false= is true
Additionally, applying a postfix or prefix ++ operator to a variable of type bool sets
the Boolean value to true. The postfix and prefix -- operators can’t be applied to
Boolean variables.
Boolean values can also be compared, as shown in the following code:
if (t1 == t2)
cout << "The values are equal" << endl;
else
cout << "The values are not equal" << endl;
Last, assigning any non-zero value to a Boolean variable results in the variable being
set to true (a value of 1), and assigning a zero value to a Boolean results in the vari-
able being set to false (a value of 0).
196 Selection Structures
e. If the difference between volts1 and volts2 is less than 0.001, set the variable
approx to zero; else, calculate approx as the quantity (volts1 - volts2) / 2.0.
f. If the frequency is above 60, display the message “The frequency is too high.”
g. If the difference between temp1 and temp2 exceeds 2.3, calculate the variable
error as (temp1 - temp2) * factor.
h. If x is greater than y and z is less than 20, request that the user input a value for the
variable p.
i. If distance is greater than 20 and less than 35, request that the user input a value for
the variable time.
2. (Practice) Write if statements corresponding to the conditions illustrated in the follow-
ing flowcharts:
a.
sum=
sum +a
count=
count+1
ace<25
false
true
b.
volts=5
pwr=10
volts=16
pwr=25
c==15
false
true
c.
factor=.7
id>22
false
true
d.
average
=sum/count
count==10
false
true
display
average
197
Chapter 4
The if-else Statement
3. (Practice) Write a C++ program that asks the user to input two numbers. If the first
number entered is greater than the second number, the program should print the message
“The first number is greater”; else, it should print the message “The first number is
smaller.” Test your program by entering the numbers 5 and 8 and then using the num-
bers 11 and 2. What do you think your program will display if the two numbers entered
are equal? Test this case.
4. (Practice) a. A certain waveform is 0 volts for time less than 2 seconds and 3 volts for
time equal to or greater than 2 seconds. (These waveforms are referred to as step
functions.) Write a C++ program that accepts time in the variable named time and dis-
plays the appropriate voltage, depending on the input value.
b. How many runs should you make for the program written in Exercise 4a to verify that
it’s operating correctly? What data should you input in each program run?
5. (Practice) An insulation test for a wire requires that the insulation withstand at least 600
volts. Write a C++ program that accepts a test voltage and displays the message “PASSED
VOLTAGE TEST” or the message “FAILED VOLTAGE TEST,” as appropriate.
6. (Practice) a. Write a C++ program to compute the value of pressure in pounds per square
inch (psi) of a waveform described as follows: For time, t, equal to or less than 35 seconds,
the pressure is 0.46t psi, and for time greater than 35 seconds, the pressure is 0.19t + 9.45 psi.
The program should request the time as input and display the pressure as output.
b. How many runs should you make for the program written in Exercise 6a to verify that
it’s operating correctly? What data should you input in each program run?
7. (Practice) a. Write a C++ program to display the message “PROCEED WITH TAKEOFF”
or “ABORT TAKEOFF,” depending on the input. If the character g is entered in the vari-
able code, the first message should be displayed; otherwise, the second message should be
displayed.
b. How many runs should you make for the program written in Exercise 7a to verify that
it’s operating correctly? What data should you input in each program run?
8. (Fluid Mechanics) A fluid particle flowing through a pipe can flow in a smooth, constant
manner, called laminar flow; in a chaotic manner, called turbulent flow; or in an interme-
diate transitional stage between smooth and turbulent flow. As a practical design param-
eter, the Reynolds number can be used to determine the type of flow. For a Reynolds
number below 2000, the flow is laminar, and for a Reynolds number above 3000, the flow
is turbulent. For a Reynolds number between 2000 and 3000, the flow is in transition
from laminar to turbulent. Using this information, write and execute a C++ program that
accepts a Reynolds number as user input; determines whether the flow is laminar, turbu-
lent, or in transition; and displays a message indicating the type of flow based on the
input Reynolds number.
9. (Electrical Eng.) A small factory generates its own power with a 20-kilowatt generator and a
50-kilowatt generator. The plant manager indicates which generator is required by typing a
character code. Write a C++ program that accepts this code as input. If code s is typed, a
message directing the plant foreman to use the smaller generator should be displayed; other-
wise, a message directing the use of the larger generator should be displayed.
198 Selection Structures
4.3 Nested if Statements
As you have seen, an if-else statement can contain any valid C++ simple or compound
statements, including another if-else statement. Therefore, one or more if-else
statements can be included in either part of an if-else statement. Including one or more
if statements inside an existing if statement is called a nested if statement. For example,
substituting the one-way if statement
if (distance > 500)
cout << "snap";
for statement1 in the following if statement
if (hours < 9)
statement1;
else
cout << "pop";
results in this nested if statement:
if (hours < 9)
{
if (distance > 500)
cout << "snap";
}
else
cout << "pop";
The braces around the inner one-way if statement are essential because in their
absence, C++ associates an else with the closest unpaired if. Therefore, without the
braces, the preceding statement is equivalent to the following:
if (hours < 9)
if (distance > 500)
cout << "snap";
else
cout << "pop";
In this example, the else is paired with the inner if, which destroys the meaning of the
original if-else statement. Notice also that the indentation is irrelevant, as far as the compiler
is concerned. Whether the indentation exists or not, the statement is compiled by associating the last
else with the closest unpaired if, unless braces are used to alter the default pairing. The process of
nesting if statements can be extended indefinitely, so the cout << "snap"; statement could
be replaced by a complete if-else statement or another one-way if statement.
199
Chapter 4
Nested if Statements
Figures 4.4a and 4.4b illustrate the general form of a nested if-else statement when
a second if-else statement is nested within a) the if part of an if-else statement and
b) the else part of an if-else statement.
statement 1
no (else part)
yes
is
expression-1
true?
yes
no (else part)
is
expression-2
true?
statement 2 statement 3
Figure 4.4a Nested within the if part
200 Selection Structures
The if-else Chain
In general, the nesting shown in Figure 4.4a tends to be confusing and is best avoided in
practice. However, a useful construction for the nesting in Figure 4.4b has this form:
if (expression_1)
statement1;
else
if (expression_2)
statement2;
else
statement3;
As with all C++ programs, because white space is ignored, this indentation isn’t required.
Typically, the preceding construction is written in the following arrangement:
if (expression_1)
statement1;
else if (expression_2)
statement2;
else
statement3;
statement 2
yes
is
expression-1
true?
yes
no (else part)
no (else part)
statement 3
statement 1
is
expression-2
true?
Figure 4.4b Nested within the else part
201
Chapter 4
Nested if Statements
This useful form of a nested if statement is called an if-else chain. Each condition
is evaluated in order, and if any condition is true, the corresponding statement is executed
and the remainder of the chain is terminated. The statement associated with the final else
is executed only if no previous condition is satisfied. This final else serves as a default or
catch-all case that’s useful for detecting an error condition or processing a condition that’s not
handled specifically by the previous conditions.
The chain can be continued indefinitely by repeatedly making the last statement
another if-else statement. Therefore, the general form of an if-else chain is as follows:
if (expression_1)
statement1;
else if (expression_2)
statement2;
else if (expression_3)
statement3;
.
.
.
else if (expression_n)
statement_n;
else
last_statement;
Each condition is evaluated in the order it appears in the statement. For the first
condition that’s true, the corresponding statement is executed, and the remainder of the
statements in the chain aren’t executed. Therefore, if expression_1 is true, only
statement1 is executed; otherwise, expression_2 is tested. If expression_2 is true,
only statement2 is executed; otherwise, expression_3 is tested, and so on. The final
else and its associated statement(s) in the chain are optional, and last_statement is
executed only if no previous expressions are true.
To illustrate using an if-else chain, Program 4.5 displays an item’s specification status
corresponding to a letter input. The following input codes are used:
Specification Status Input Code
Space exploration S
Military grade M
Commercial grade C
Toy grade T
202 Selection Structures
Program 4.5
#include <iostream>
using namespace std;
int main()
{
char code;
cout << "Enter a specification code: ";
cin >> code;
if (code == 'S')
cout << "The item is space exploration grade.";
else if (code == 'M')
cout << "The item is military grade.";
else if (code == 'C')
cout << "The item is commercial grade.";
else if (code == 'T')
cout << "The item is toy grade.";
else
cout << "An invalid code was entered.";
cout << endl;
return 0;
}
As another example of an if-else chain, take a look at determining the output of a
digital converter unit by using the following input/output relationship:
Input Weight Output Reading
Greater than or equal to 90 lbs 1111
Less than 90 lbs but greater than or equal to 80 lbs 1110
Less than 80 lbs but greater than or equal to 70 lbs 1101
Less than 70 lbs but greater than or equal to 60 lbs 1100
Less than 60 lbs 1011
The following statements can be used to determine the correct output corresponding to
the value input for the variable inlbs:
if (inlbs >= 90)
digout = 1111;
else if (inlbs >= 80)
203
Chapter 4
Nested if Statements
digout = 1110;
else if (inlbs >= 70)
digout = 1101;
else if (inlbs >= 60)
digout = 1100;
else
digout = 1011;
Notice that this example makes use of the chain stopping after a true condition is found
by checking for the highest input weight first. If the input value is less than 90, the if-else
chain continues checking for the next highest weight, and so on, until the correct weight
category is obtained. Program 4.6 uses an if-else chain to calculate and display the correct
output corresponding to the weight input in the cin statement.
Program 4.6
#include <iostream>
using namespace std;
int main()
{
int digout;
double inlbs;
cout << "Enter the input weight: ";
cin >> inlbs;
if (inlbs >= 90)
digout = 1111;
else if (inlbs >= 80)
digout = 1110;
else if (inlbs >= 70)
digout = 1101;
else if (inlbs >= 60)
digout = 1100;
else
digout = 1011;
cout << "The digital output is " << digout << endl;
return 0;
}
204 Selection Structures
The following is a sample run of Program 4.6:
Enter the input weight: 72.5
The digital output is 1101
As with all C++ statements, each statement in an if-else chain can be replaced by a
compound statement bounded by braces.
EXERCISES 4.3
1. (Practice) Modify Program 4.5 to accept both lower and uppercase letters as codes. For
example, if a user enters an m or an M, the program should display the message “The
item is military grade.”
2. (Practice) Write nested if statements corresponding to the conditions illustrated in the
following flowcharts:
a.
t=s+a
bin=1
is
weight >35
no
yes
is
grade=='A'
yes
no
b.
sum=0
no
yes
is
count <5
is
grade <50
fail=
fail+1
yes
no
205
Chapter 4
Nested if Statements
3. (Practice) An acute angle is less than 90 degrees, an obtuse angle is greater than 90
degrees, and a right angle is equal to 90 degrees. Using this information, write a C++ pro-
gram that accepts an angle, in degrees, and displays the type of angle corresponding to
the degrees entered.
4. (Data Processing) The grade level of undergraduate college students is typically deter-
mined according to the following schedule:
Number of Credits Completed Grade Level
Less than 32 Freshman
32 to 63 Sophomore
64 to 95 Junior
96 or more Senior
Using this information, write a C++ program that accepts the number of credits a student
has completed, determines the student’s grade level, and displays the grade level.
5. (Data Processing) A student’s letter grade is calculated according to the following schedule:
Numerical Grade Letter Grade
Greater than or equal to 90 A
Less than 90 but greater than or equal to 80 B
Less than 80 but greater than or equal to 70 C
Less than 70 but greater than or equal to 60 D
Less than 60 F
Using this information, write a C++ program that accepts a student’s numerical grade,
converts the numerical grade to an equivalent letter grade, and displays the letter grade.
6. (Measurement) The tolerance of critical components in a system is determined accord-
ing to the following schedule:
Specification Status Tolerance
Space exploration Less than 0.1%
Military grade Greater than or equal to 0.1% and less than 1%
Commercial grade Greater than or equal to 1% and less than 10%
Toy grade Greater than or equal to 10%
Using this information, write a C++ program that accepts a component’s tolerance reading
and determines the specification that should be assigned to it.
7. (General Math) Write a C++ program that accepts a number followed by one space and
then a letter. If the letter following the number is f, the program is to treat the number
entered as a temperature in degrees Fahrenheit, convert the number to the equivalent
degrees Celsius, and display a suitable message. If the letter following the number is c, the
206 Selection Structures
program is to treat the number entered as a temperature in degrees Celsius, convert the
number to the equivalent degrees Fahrenheit, and display a suitable message. If the letter is
neither f nor c, the program is to display a message that the data entered is incorrect and
terminate. Use an if-else chain in your program and make use of these conversion
formulas:
Celsius = (5.0 / 9.0) × (Fahrenheit - 32.0)
Fahrenheit = (9.0 / 5.0) × Celsius + 32.0
8. (Debugging) Using the relationships in Program 4.6, the following program calculates the
digital output:
int main()
{
int digout;
double inlbs;
cout << "Enter the input weight: ";
cin >> inlbs;
if (inlbs >= 90) digout = 1111;
if (inlbs >= 80) && (inlbs <= 90) digout = 1110;
if (inlbs >= 70) && (inlbs <= 80) digout = 1101;
if (inlbs >= 60) && (inlbs <= 70) digout = 1100;
if (inlbs < 1000) digout = 1011;
cout << "The digital output is " << digout << endl;
return 0;
}
a. Will this program produce the same output as Program 4.6?
b. Which program is better and why?
9. (Debugging) The following program was written to produce the same result as Program 4.6:
int main()
{
int digout;
double inlbs;
cout << "Enter the input weight: ";
cin >> inlbs;
if (inlbs < 60)
digout = 1011;
else if (inlbs >= 60)
digout = 1100;
else if (inlbs >= 70)
digout = 1101;
else if (inlbs >= 80)
digout = 1110;
else if (inlbs >= 90)
digout = 1111;
207
Chapter 4
Nested if Statements
cout << "The digital output is " << digout << endl;
return 0;
}
a. Will this program run?
b. What does this program do?
c. For what values of input pounds does this program calculate the correct digital output?
4.4 The switch Statement
An if-else chain is used in programming applications when one set of instructions must
be selected from many possible alternatives. A switch statement is an alternative to the
if-else chain for situations when the condition involves comparing an integer expression
with a specific value. It has this general form:
switch (expression)
{ // start of compound statement
case value_1: // terminated with a colon
statement1;
statement2;
.
.
break;
case value_2: // terminated with a colon
statementm;
statementn;
.
.
break;
.
.
case value_n: // terminated with a colon
statementw;
statementx;
.
.
break;
default: // terminated with a colon
statementaa;
statementbb;
.
.
} // end of switch and compound statement
The switch statement uses four new keywords: switch, case, break, and default.
The following discussion explains what each of these keywords does.
The switch keyword identifies the start of the switch statement. The expression in
parentheses after switch is then evaluated, and this expression must evaluate to an integer
result, or a compilation error results.
208 Selection Structures
In the switch statement, the case keyword identifies values that are compared with
the switch expression’s value. The case values are compared in the order in which they’re
listed until a match is found, and then execution begins with the statement following the
match. As illustrated in Figure 4.5, the switch expression’s value determines where
execution actually begins.
A switch statement can contain any number of case labels in any order. If the value
of the expression doesn’t match any of the case values, however, no statement is executed
unless the default keyword is encountered. (The default keyword is optional and
operates the same as the last else in an if-else chain.) If the value of the expression
doesn’t match any case value, program execution begins with the statement following the
default keyword.
After the switch statement has located an entry point, all further case value
evaluations are ignored. Execution continues through the end of the compound statement
unless the break keyword is encountered, which identifies the end of a case and causes
an immediate exit from the switch statement. Just as the case keyword identifies possible
entry points in the compound statement, the break keyword determines terminating points.
Start here if
expression equals value_1
Start here if
expression equals value_2
Start here if
expression equals value_3
Start here if
expression equals value_n
Start here if no
previous match
switch (expression) // evaluate expression
{
case value_1:
break;
case value_2:
break;
case value_3:
break;
case value_n:
break;
default:
} // end of switch statement
Figure 4.5 The expression determines an entry point for execution
209
Chapter 4
The switch Statement
If break statements are omitted, all cases following the matching case value, including the
default case, are executed.
When writing a switch statement, you can use multiple case values to refer to the
same set of statements; the default keyword is optional. For example, take a look at the
following:
switch (number)
{
case 1:
cout << "Have a Good Morningn";
break;
case 2:
cout << "Have a Happy Dayn";
break;
case 3:
case 4:
case 5:
cout << "Have a Nice Eveningn";
}
If the value stored in the variable number is 1, the message Have a Good Morning
is displayed. Similarly, if the value of number is 2, the second message is displayed. Finally,
if the value of number is 3, 4, or 5, the last message is displayed. Because the statement to
be executed for the last three cases is the same, the case statements for these values can
be “stacked together,” as shown in the example. Also, because there’s no default keyword,
no message is printed if the value of number isn’t one of the listed case values. Although
listing case values in increasing order is a good programming practice, it’s not required by
the switch statement. A switch statement can have any number of case values, in any
order; only the values you’re testing for must be listed.
Program 4.7 uses a switch statement to select the arithmetic operation (addition,
multiplication, or division) to perform on two numbers, depending on the value of the
opselect variable.
In the following two sample runs, the resulting display clearly identifies the case that
was selected:
Please type in two numbers: 12 3
Enter a select code:
1 for addition
2 for multiplication
3 for division : 2
The product of the numbers entered is 36
and
Please type in two numbers: 12 3
Enter a select code:
1 for addition
2 for multiplication
3 for division : 3
The first number divided by the second is 4
210 Selection Structures
Program 4.7
#include <iostream>
using namespace std;
int main()
{
int opselect;
double fnum, snum;
cout << "Please type in two numbers: ";
cin >> fnum >> snum;
cout << "Enter a select code: ";
cout << "n 1 for addition";
cout << "n 2 for multiplication";
cout << "n 3 for division : ";
cin >> opselect;
switch (opselect)
{
case 1:
cout << "The sum of the numbers entered is " << fnum+snum;
break;
case 2:
cout << "The product of the numbers entered is " << fnum*snum;
break;
case 3:
cout << "The first number divided by the second is " << fnum/snum;
break;
} // end of switch
cout << endl;
return 0;
}
In reviewing Program 4.7, notice the break statement in the last case. Although it’s not
necessary, terminating the last case in a switch statement with a break is a good
programming practice. It prevents a possible program error later if another case is added to
the switch statement. With the addition of a new case, the break keyword between cases
ensures that you won’t forget to include the break at the time of the addition.
211
Chapter 4
The switch Statement
Because character data types are always converted to integers in an expression, a switch
statement can also be used to “switch” based on the value of a character expression. For
example, assuming choice is a character variable, the following switch statement is valid:
switch(choice)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
cout << "The character in choice is a voweln";
break;
default:
cout << "The character in choice is not a voweln";
break; // this break is optional
} // end of switch statement
EXERCISES 4.4
1. (Practice) Rewrite the following if-else chain by using a switch statement:
if (letterGrade == 'A')
cout << "The numerical grade is between 90 and 100n";
else if (letterGrade == 'B')
cout << "The numerical grade is between 80 and 89.9n";
else if (letterGrade == 'C')
cout << "The numerical grade is between 70 and 79.9n";
else if (letterGrade == 'D')
cout << "How are you going to explain this one?n";
else
{
cout << "Of course I had nothing to do with my grade.n";
cout << "It must have been the professor's fault.n";
}
2. (Practice) Rewrite the following if-else chain by using a switch statement:
if (factor == 1)
pressure = 25.0;
else if (factor == 2)
pressure = 36.0;
else if (factor == 3)
pressure = 45.0;
else if (factor == 4) || (factor == 5) || (factor == 6)
pressure = 49.0;
212 Selection Structures
3. (Data Processing) Each disk drive in a shipment is stamped with a code from 1 through
4 to indicate the manufacturer, as follows:
Code Disk Drive Manufacturer
1 3M Corporation
2 Maxell Corporation
3 Sony Corporation
4 Verbatim Corporation
Write a C++ program that accepts the code number as input and, based on the value
entered, displays the correct disk drive manufacturer.
4. (Practice) Rewrite Program 4.5 by using a switch statement.
5. (Debugging) Explain why the if-else chain in Program 4.6 can’t be replaced with a
switch statement.
6. (Debugging) Rewrite Program 4.7 by using a character variable for the select code.
4.5 A Case Study: Solving Quadratic Equations
An important use of C++’s if statements is to validate data by checking for clearly invalid
cases. For example, a date such as 5/33/06 contains an obviously invalid day. Similarly, the
division of any number by zero in a program, such as 14/0, shouldn’t be allowed. Both
examples illustrate the need for a technique called defensive programming, in which the
program includes code to check for improper data before an attempt is made to process it
further. The defensive programming technique of checking user input data for erroneous or
unreasonable data is referred to as input data validation.
A second major use of selection statements is to determine the type of calculation to be
made based on the data. Both uses are shown in this case study, which illustrates a C++
program that determines the roots of a quadratic equation. A quadratic equation has the form
ax2
+ bx + c = 0 or can be algebraically manipulated into this form. In this equation, x is the
unknown variable, and a, b, and c are known constants. Although the constants b and c can
be any numbers, including 0, the value of the constant a can’t be 0. (If a is 0, the equation
would become a linear equation in x.) Here are examples of quadratic equations:
5x2
+ 6x + 2 = 0
x2
- 7x + 20 = 0
34x2
+ 16 = 0
In the first equation, a = 5, b = 6, and c = 2; in the second equation, a = 1, b = -7, and
c = 20; and in the third equation, a = 34, b = 0, and c = 16.
213
Chapter 4
A Case Study: Solving Quadratic
Equations
The real roots of a quadratic equation can be calculated by using these quadratic formulas:
x
b b ac
a
=
+
- -
2
4
2
and
x
b b ac
a
=
- - -
2
4
2
Using these formulas, you’ll write a C++ program, following the software development
procedure, to solve for the roots of a quadratic equation.
Step 1 Analyze the Problem
The problem requires accepting three inputs—the coefficients a, b, and c of a quadratic
equation. The outputs are the roots of the equation, found by using the given formulas.
Step 2 Develop a Solution
A first attempt at a solution is using the user-entered values of a, b, and c to calculate a value
for each root, as described by the following pseudocode:
Display a program purpose message
Accept user-input values for a, b, and c
Calculate the two roots
Display the values of the calculated roots
However, this solution must be refined to account for possible input conditions. For
example, if a user enters a value of 0 for both a and b, the equation is neither quadratic nor
linear and has no solution (referred to as a “degenerate case”). Another possibility is that the
user enters a zero for a and a non-zero value for b. In this case, the equation becomes linear
with a single solution of -c/b. A third possibility is that the value of the term b2
- 4ac, which
is called the discriminant, is negative. Because the square root of a negative number can’t be
taken, the equation has no real roots (referred to as the “imaginary roots case”). Finally, when
the discriminant is 0, both roots are the same (referred to as the “repeated roots case”).
214 Selection Structures
Taking into account all four limiting cases, the following pseudocode shows a refined
solution for determining the roots of a quadratic equation correctly:
Display a program purpose message
Accept user-input values for a, b, and c
If a = 0 and b = 0 then
display a message saying that the equation has no solution
Else if a = zero then
calculate the single root equal to -c/b
display the single root
Else
{
calculate the discriminant
If the discriminant > 0 then
solve for both roots using the given formulas
display the two roots
Else if the discriminant < 0 then
display a message that there are no real roots
Else
calculate the repeated root equal to -b/(2a)
display the repeated root
Endif
}
Endif
Notice that nested if-else statements are used. The outer if-else statement
validates the entered coefficients and determines whether you have a valid quadratic
equation. The inner if-else statement then determines whether the equation has two real
roots (discriminant > 0), two imaginary roots (discriminant < 0), or repeated roots
(discriminant = 0).
Step 3 Code the Solution
Program 4.8 lists the equivalent C++ code for the pseudocode solution.
215
Chapter 4
A Case Study: Solving Quadratic
Equations
Program 4.8
#include <iostream>
#include <cmath>
using namespace std;
// this program solves for the roots of a quadratic equation
int main()
{
double a, b, c, disc, root1, root2;
cout << "This program calculates the roots of an";
cout << " quadratic equation of the formn";
cout << " 2n";
cout << " ax + bx + c = 0nn";
cout << "Please enter values for a, b, and c: ";
cin >> a >> b >> c;
if ( a == 0.0 && b == 0.0)
cout << "The equation is degenerate and has no roots.n";
else if (a == 0.0)
cout << "The equation has the single root x = "
<< -c/b << endl;
else
{ //Start of compound statement for the outer else
disc = pow(b,2.0) - 4 * a * c; // calculate discriminant
if (disc > 0.0)
{
disc = sqrt(disc);
root1 = (-b + disc) / (2 * a);
root2 = (-b - disc) / (2 * a);
cout << "The two real roots are "
<< root1 << " and " << root2 << endl;
}
else if (disc < 0.0)
cout << "Both roots are imaginary.n";
else
cout << "Both roots are equal to " << -b / (2 * a) << endl;
} //end of compound statement for the outer else
return 0;
}
216 Selection Structures
Step 4 Test and Correct the Program
Test values should include values for a, b, and c that result in two real roots, plus limiting
values for a and b that result in a linear equation (a = 0, b ⫽ 0), a degenerate equation
(a = 0, b = 0), and a negative and a zero discriminant. Two test runs of Program 4.8 follow:
This program calculates the roots of a
quadratic equation of the form
2
ax + bx + c = 0
Please enter values for a, b, and c: 1 2 -35
The two real roots are 5 and -7
and
This program calculates the roots of a
quadratic equation of the form
2u
ax + bx + c = 0
Please enter values for a, b, and c: 0 0 16
The equation is degenerate and has no roots.
The first run solves the quadratic equation x2
+ 2x - 35 = 0, which has the real roots
x = 5 and x = -7. The input data for the second run results in the equation 0x2
+ 0x + 16 = 0.
Because it degenerates into the mathematical impossibility of 16 = 0, the program identifies it
correctly as a degenerate equation. As an exercise, you could create test data for the other limiting
cases the program checks for.
EXERCISES 4.5
1. (Data Processing) Write, compile, and execute a C++ program that accepts a user-
entered number and calculates the values of the following:
user-entered number
and
1
user-entered number
Before calculating the square root, validate that the number is not negative, and before
calculating the reciprocal, check that the number is not zero. If either condition occurs,
display a message stating that the operation can’t be calculated.
2. (Data Processing) a. Write a program that accepts two real numbers and a select code from
a user. If the entered select code is 1, have the program add the two previously entered num-
bers and display the result; if the select code is 2, the numbers should be multiplied, and if
the select code is 3, the first number should be divided by the second number.
b. Determine what the program written in Exercise 2a does when the entered numbers
are 3 and 0 and the select code is 3.
217
Chapter 4
A Case Study: Solving Quadratic
Equations
c. Modify the program written in Exercise 2a so that division by 0 is not allowed, and a
message is displayed when this division is attempted.
3. (Data Processing) a. Write a program to display the following two prompts:
Enter a month (use a 1 for Jan, etc.):
Enter a day of the month:
Have your program accept and store a number in the variable month in response to the
first prompt and accept and store a number in the variable day in response to the second
prompt. If the month entered is not between 1 and 12, print a message informing the
user that an invalid month has been entered. If the day entered is not between 1 and 31,
print a message informing the user that an invalid day has been entered.
b. What will your program do if the user enters a number with a decimal point for the
month? How can you make sure your if statements check for an integer number?
c. In a non-leap year, February has 28 days; the months January, March, May, July, August,
October, and December have 31 days; and all other months have 30 days. Using this
information, modify the program written in Exercise 3a to display a message when an
invalid day is entered for a user-entered month. For this program, ignore leap years.
4. (General Math) The quadrant in which a line drawn from the origin resides is deter-
mined by the angle the line makes with the positive x-axis, as follows:
Angle from the Positive X-Axis Quadrant
Between 0 and 90 degrees I
Between 90 and 180 degrees II
Between 180 and 270 degrees III
Between 270 and 360 degrees IV
a. Using this information, write a C++ program that accepts the angle of the line as user
input and determines and displays the correct quadrant for the input data. (Note: If the
angle is exactly 0, 90, 180, or 270 degrees, the corresponding line doesn’t reside in any
quadrant but lies on an axis.)
b. Modify the program written for Exercise 4a to display a message that identifies an
angle of 0 degrees as the positive x-axis, an angle of 90 degrees as the positive y-axis,
an angle of 180 degrees as the negative x-axis, and an angle of 270 degrees as the
negative y-axis.
5. (Data Processing) Years that are evenly divisible by 400 or are evenly divisible by 4 but
not by 100 are leap years. For example, because 1600 is evenly divisible by 400, 1600 was
a leap year. Similarly, because 1988 is evenly divisible by 4 but not by 100, it was also a
leap year. Using this information, write a C++ program that accepts the year as user input,
determines whether the year is a leap year, and displays a message telling the user
whether the entered year is or is not a leap year.
218 Selection Structures
6. (Data Processing) Based on an automobile’s model year and weight, the state of New
Jersey determines the weight class and registration fee by using the following schedule:
Model Year Weight Weight Class Registration
Fee
1970 or earlier Less than 2700 lbs 1 $16.50
2700 to 3800 lbs 2 25.50
More than 3800 lbs 3 46.50
1971 to 1979 Less than 2700 lbs 4 27.00
2700 to 3800 lbs 5 30.50
More than 3800 lbs 6 52.50
1980 or later Less than 3500 lbs 7 19.50
3500 or more lbs 8 52.50
Using this information, write a C++ program that accepts an automobile’s year and weight
and determines and displays its weight class and registration fee.
7. (Data Processing) Modify Program 4.8 so that the imaginary roots are calculated and
displayed when the discriminant is negative. For this case, the two roots of the equation
are the following:
x
b b ac
a
i
1
2
4
2
=
+
- - -
( )
and
x
b b ac
a
i
2
2
4
2
=
- - - -
( )
where i is the imaginary number symbol for the square root of -1. (Hint: Calculate the
real and imaginary parts of each root separately.)
8. (Heat Transfer) The transfer of heat by the movement (currents) of a gas or liquid is
referred to as heat convection. The heat transferred per unit area of a substance is given
by this formula:
q = hA(Ts - Ta)
q is the heat transfer rate (Watts or Joules/sec).
h is the convective heat transfer coefficient (BTU/hrft°F or Watts/m2
°C).
A is the surface area (ft2
or m2
).
Ts is the surface temperature (°F or °C).
Ta is the ambient (surrounding) temperature (°F or °C).
219
Chapter 4
A Case Study: Solving Quadratic
Equations
a. Write, compile, and execute a C++ program that accepts a substance’s surface area, a
substance’s surface temperature, and the ambient air temperature as inputs and dis-
plays the heat transfer rate through air. Users should have three choices for entering
the surface area:
1. A rectangular area
2. An elliptical area
3. Other
If the user selects 1, the program should ask the user to enter the surface’s length and
width, and the program calculates surface area as length times width. If the user selects 2,
the program should ask the user to enter the surface’s major and minor axii, and the pro-
gram calculates the surface area as ␲(major axis)(minor axis). If the user selects 3 (Other),
the program should ask the user to enter the surface area. The heat transfer rate should
then be calculated and displayed, using the convective heat transfer coefficient of 8.7
Watts/m2
°C, which should be defined as the symbolic constant AIRCONV.
b. After verifying that your program is working correctly, determine the heat transfer rate
away from a chip in a computer’s console. The chip has a surface temperature of
44°C, and the ambient temperature maintained by the console’s fan is 40°C. The rect-
angular chip has a length of 2 cm and a width of 2 cm.
4.6 A Closer Look: Program Testing3
In theory, a comprehensive set of test runs would reveal all possible program errors and
ensure that a program works correctly for any combination of input and computed data. In
practice, this level of testing requires checking all possible combinations of statement
execution. Because of the time and effort required, this goal is usually impossible except for
extremely simple programs. To see why this is so, take a look at Program 4.9.
3
This topic can be omitted on first reading without loss of subject continuity.
220 Selection Structures
Program 4.9
#include <iostream>
using namespace std;
int main()
{
int num;
cout << "Enter a number: ";
cin >> num;
if (num == 5)
cout << "Bingo!n";
else
cout << "Bongo!n";
return 0;
}
Program 4.9 has two paths that can be traversed as the program progresses from its
opening brace to its closing brace. The first path, which is executed when the input number
is 5, is in this sequence:
cout << "Enter a number";
cin >> num;
cout << "Bingo!n";
The second path, which is executed when any number except 5 is input, includes this
sequence of instructions:
cout << "Enter a number";
cin >> num;
cout << "Bongo!n";
Testing each possible path through Program 4.9 requires two runs with a judicious
selection of test input data to make sure both paths of the if statement are exercised.
Adding one more if statement in the program increases the number of possible execution
paths by a factor of two and requires four (that is, 22
) runs for complete testing. Similarly, two
additional if statements increase the number of paths by a factor of four and require eight
(that is, 23
) runs for complete testing, and three additional if statements produce a program
that requires 16 (that is, 24
) test runs.
Now consider an application program consisting of only 10 modules, with each module
containing five if statements. Assuming the modules are always called in the same
sequence, there are 32 possible paths through each module (25
) and more than
1,000,000,000,000,000 (250
, representing the number of modules multiplied by the number of
if statements per module) possible paths through the complete program (all modules
executed in sequence). The time needed to create test data to exercise each path and the
221
Chapter 4
A Closer Look: Program Testing
actual computer runtime required to check each path make complete testing of this program
impossible.
The inability to test all combinations of statement execution sequences fully has led to
the programming proverb “There is no error-free program.” Any testing should be well
thought out to maximize the possibility of locating errors. At a minimum, test data should
include appropriate input values, illegal input values the program should reject, and limiting
values checked by selection statements in the program.
4.7 Common Programming Errors
Four programming errors are common with C++’s selection statements:
1. Using the assignment operator, =, in place of the relational operator ==. This error
can cause frustration because any expression can be tested by an if-else
statement, so it is not immediately obvious that an error is being made. For example,
the statement
if (opselect = 2)
cout << "Happy Birthday";
else
cout << "Good Day";
always results in the message Happy Birthday being displayed, regardless of the
initial value in the opselect variable. The reason is that the assignment expres-
sion opselect = 2 has a value of 2, which is considered a true value in C++.
The correct expression to determine the value in opselect is opselect == 2.
2. Placing a semicolon immediately after the condition, as in this example:
if (condition);
statement;
The semicolon after (condition) is an error. It creates a null statement, which
causes the statement following the semicolon to be a stand-alone statement that’s
no longer part of the if statement. This stand-alone statement is always
executed, regardless of the condition tested by the if statement.
3. Letting the if-else statement appear to select an incorrect choice. In this typical
debugging problem, the programmer mistakenly concentrates on the tested condi-
tion as the source of the problem. For example, assume the following if-else
statement is part of your program:
if (key == 'F')
{
contemp = (5.0/9.0) * (intemp - 32.0);
cout << "Conversion to Celsius was done";
}
else
{
222 Selection Structures
contemp = (9.0/5.0) * intemp + 32.0;
cout << "Conversion to Fahrenheit was done";
}
This statement always displays Conversion to Celsius was done when the vari-
able key contains an F. Therefore, if this message is displayed when you believe key
doesn’t contain F, you should investigate key’s value. As a general rule, whenever a
selection statement doesn’t act as you think it should, test your assumptions about
the values assigned to the tested variables by displaying their values. If an unantici-
pated value is displayed, you have at least isolated the source of the problem to the
variables rather than the structure of the if-else statement. From there, you have
to determine where and how the incorrect value was produced.
4. Using nested if statements without including braces to indicate the structure.
Without braces, the compiler defaults to pairing elses with the closest unpaired
ifs, which sometimes destroys the selection statement’s original intent. To avoid
this problem and create code that’s adaptable to change, writing all if-else
statements as compound statements in this form is useful:
if (expression)
{
// one or more statements in here
}
else
{
// one or more statements in here
}
No matter how many statements are added later, this form maintains the if state-
ment’s original intent.
4.8 Chapter Summary
1. Relational expressions, also called conditions, are used to compare operands. If a
relational expression is true, the value of the expression is the integer 1. If the relational
expression is false, it has an integer value of 0. Relational expressions are created by
using the following relational operators:
Relational
Operator
Meaning Example
< Less than age < 30
> Greater than height > 6.2
<= Less than or equal to taxable <= 20000
>= Greater than or equal to temp >= 98.6
== Equal to grade == 100
!= Not equal to number != 250
223
Chapter 4
Chapter Summary
2. More complex conditions can be constructed from relational expressions by using C++’s
logical operators, && (AND), || (OR), and ! (NOT).
3. An if-else statement is used to select between two alternative statements based on
an expression’s value. Although relational expressions are usually used for the tested
expression, any valid expression can be used. In testing an expression, if-else
statements interpret a non-zero value as true and a zero value as false. The general form
of an if-else statement is as follows:
if (expression)
statement1;
else
statement2;
This form is a two-way selection statement. If the expression has a non-zero value, it’s
considered true and statement1 is executed; otherwise, statement2 is executed.
4. An if-else statement can contain other if-else statements. In the absence of
braces, each else is associated with the closest preceding unpaired if.
5. The if-else chain is a multiway selection statement with this general form:
if (expression_1)
statement_1;
else if (expression_2)
statement_2;
else if (expression_3)
statement_3;
.
.
.
else if (expression_m)
statement_m;
else
statement_n;
Each expression is evaluated in the order in which it appears in the chain. If an
expression is true (has a non-zero value), only the statement between this expression and
the next else if or else is executed, and no further expressions are tested. The final
else is optional, and the statement corresponding to the final else is executed only if
no previous expressions are true.
6. A compound statement consists of any number of single statements enclosed by the
brace pair { and }. Compound statements are treated as a single unit and can be used
anywhere a single statement is used.
7. The switch statement is a multiway selection statement with this general form:
switch (expression)
{ // start of compound statement
case value_1: // terminated with a colon
statement1;
statement2;
.
.
break;
case value_2: // terminated with a colon
224 Selection Structures
statementm;
statementn;
.
.
break;
.
.
case value_n: // terminated with a colon
statementw;
statementx;
.
.
break;
default: // terminated with a colon
statementaa;
statementbb;
.
.
} // end of switch and compound statement
For this statement, the value of an integer expression is compared with integer or
character constants or constant expressions. Program execution is transferred to the first
matching case and continues through the end of the switch statement, unless an
optional break statement is encountered. The case values in a switch statement can
appear in any order, and an optional default case can be included. The default case
is executed if no other cases are matched.
Programming Projects for Chapter 4
1. (Data Processing) Write C++ code sections to make the following decisions:
a. Ask for two integer temperatures. If their values are equal, display the temperature;
otherwise, do nothing.
b. Ask for character values letter1 and letter2, representing uppercase letters of
the alphabet, and display them in alphabetical order.
c. Ask for three integer values, num1, num2, and num3, and display them in decreasing
order.
2. (Data Processing) a. Write a program that displays the message I FEEL GREAT
TODAY! or I FEEL DOWN TODAY #$*!, depending on the input. If the character u
is entered in the variable code, the first message should be displayed; otherwise, the
second message should be displayed.
b. How many runs should you make for the program written in Exercise 2a to verify that
it’s operating correctly? What data should you input in each program run?
3. (Data Processing) a. A senior engineer is paid $1700 a week, and a junior engineer,
$900 a week. Write a C++ program that accepts as input an engineer’s status in the
character variable status. If status equals S, the senior engineer’s salary should be
displayed; otherwise, the junior engineer’s salary should be displayed.
225
Chapter 4
Programming Projects
b. How many runs should you make for the program written in Exercise 3a to verify that
it is operating correctly? What data should you input in each program run?
4. (Data Processing) a. Write a C++ program to compute and display a person’s weekly
salary as determined by the following conditions: If the hours worked are less than or
equal to 40, the person receives $8.00 per hour; otherwise, the person receives $320.00
plus $12.00 for each hour worked over 40 hours. The program should request the hours
worked as input and display the salary as output.
b. How many runs should you make for the program written in Exercise 4a to verify that
it’s operating correctly? What data should you input in each program run?
5. (Structural Eng.) Three of the most commonly used beams in structural engineering
are the I-beam, rectangular beam, and cylindrical beam, shown in Figures 4.6 through
4.8. In determining the stress a given weight places on a symmetrical beam, an important
design parameter is the beam’s rectangular moment of inertia, I, which is typically given
in units of in4
. The computation of I depends on the beam’s geometry, and for the three
beam types shown, the values of I are calculated as follows:
For an I-beam: I
BH bh
=
3 3
12
-
where all measurements are in inches
For a rectangular beam: I
bh
=
3
12
For a cylindrical beam: I
r
=
π 4
4
Figures 4.6 through 4.8 show the variables b, h, B, H, and r. Using this information,
design, write, compile, and execute a C++ program that prompts the user for the type of
beam and the necessary data (based on the input), and then computes and displays the
beam’s rectangular moment of inertia.
H h
B
b
⁄2
Figure 4.6 An I-beam
226 Selection Structures
6. (Fluid Mechanics) A key parameter used to determine the type of fluid flow through
a pipe is the Reynolds number, which is given by this formula:
Re =
V d
v
Re is the Reynolds number (a dimensionless value).
V is the velocity (m/s or ft/sec).
d is the diameter of the pipe (m or ft).
␯ is the kinematic viscosity of the fluid (m/s2
or ft/sec2
).
The viscosity, ␯, is a measure of the fluid’s resistance to flow and stress. Except at
extremely high pressures, a liquid fluid’s kinematic viscosity is dependent on tempera-
ture and independent of pressure. The following chart provides the viscosity of water at
three different temperatures:
Temperature (°C) Kinematic Viscosity (m/s2
)
5 1.49 × 10-6
10 1.31 × 10-6
15 1.15 × 10-6
h
b
Figure 4.7 A rectangular beam
r
Figure 4.8 A cylindrical beam
227
Chapter 4
Programming Projects
Using this information, write, compile, and execute a program that requests the velocity
of water flowing through a pipe, the pipe’s diameter, the water’s temperature, and the
water’s kinematic viscosity. Based on the input values, your program should calculate the
Reynolds number. When you have verified that your program is working, use it to
complete the following chart:
Velocity (m/s) Pipe
Diameter (mm)
Temperature (°C) Reynolds
Number
.01 10 5
.03 10 5
.04 10 5
.01 20 10
.03 20 10
.04 20 10
.01 30 15
.03 30 15
.04 30 15
7. (Data Processing) Write a C++ program that accepts a character as input data and
determines whether the character is an uppercase letter. An uppercase letter is any
character that’s greater than or equal to “A” and less than or equal to “Z.” If the entered
character is an uppercase letter, display the message The character just entered
is an uppercase letter. If the entered letter isn’t uppercase, display the message
The character just entered is not an uppercase letter.
8. (Data Processing) Repeat Exercise 7 to determine whether the character entered is a
lowercase letter. A lowercase letter is any character greater than or equal to “a” and less
than or equal to “z.”
9. (General Math) a. Write, run, and test a C++ program that accepts a user-input integer
number and determines whether it’s even or odd. Display the entered number and the
message Even or Odd.
b. Modify the program written for Exercise 9a to determine whether the entered number
is evenly divisible by a user-specified value, with no remainder. That is, is it evenly
divisible by 3, 7, 13, or any other user-specified value?
10. (Data Processing) As a part-time student, you took two courses last term. Write, run, and
test a C++ program that calculates and displays your grade point average (GPA) for the term.
Your program should prompt the user to enter the grade and credit hours for each course.
This information should then be displayed with the lowest grade first, and the GPA for the
term should be calculated and displayed. A warning message should be printed if the GPA
is less than 2.0 and a congratulatory message if the GPA is 3.5 or above.
228 Selection Structures
11. (Debugging) The following program displays the message Hello there! regardless of
the letter input. Determine where the error is.
#include <iostream.h>
using namespace std;
int main()
{
char letter;
cout << "Enter a letter: ";
cin >> letter;
if (letter = 'm')
cout << "Hello there!n";
return 0;
i}
12. (Data Processing) Write, execute, and verify a C++ program that accepts three numbers
as input, and then sorts the three numbers and displays them in ascending order, from
lowest to highest. For example, if the input values are 7 5 1, the program should display
them in the numerical order 1 5 7.
13. (Heat Transfer) The transfer of heat energy through matter, referred to as heat conduction,
is always from a region of higher temperature to one of lower temperature. It occurs by
transferring energy from atom to atom within a substance. With uniform temperatures on
either side of equal-sized surfaces, the rate of heat flow through a substance is provided by
Fourier’s law of heat conduction, which becomes the following formula:
Q
k T T
w
=
( )
2 1
-
Q is heat per unit time per unit area (Watts/m2
or BTU/hrft2
).
k is the thermal conductivity, which is a property of a substance that indicates its
capability to conduct heat (Watts/m°K or BTU/hrft°F).
T2 is the hotter temperature (°F or °K).
T1 is the cooler temperature (°F or °K).
w is the width of the substance (ft or m).
a. Write, compile, and execute a C++ program that calculates and displays the heat
transfer through a substance. The inputs should be the substance’s thermal conduc-
tivity, its width, and temperatures on either side of it. Your program should determine
which unit system is used, item by item, and then convert units as necessary so that
a consistent unit system (SI or English Engineering) is used in the final determination
of Q. The output should display the value of Q in both unit systems.
b. Verify that your program is working by hand-calculating the heat transfer through a
cement wall with a thermal conductivity of .29 Watts/m°K and a thickness of 15 cm.
One side of the wall is at a constant temperature of 32°C, and the other side is -7°C.
229
Chapter 4
Programming Projects
c. After verifying that your program is working correctly, use the following chart of
thermal conductivities to determine the heat transfer rate for the following:
i. A pane of glass that’s ½ cm thick and has an inside temperature of 24°C and an
outside temperature of 15°C.
ii. A column of air 10 cm thick that’s held between two walls, one with a temperature
of 23°C and the other of 14°C.
Substance Thermal Conductivity
(Watts/m°K)
Thermal Conductivity
(BTU/hrft°F)
Air .025 .0015
Cement .29 .17
Glass 1.1 .645
Soil 1.5 .88
Wood, oak .17 .096
Wood, pine .12 .065
14. (General Math) In the game of blackjack, the cards 2 through 10 are counted as their
face values, regardless of suit; all face cards (jack, queen, and king) are counted as 10; and
an ace is counted as a 1 or an 11, depending on the total count of all cards in a player’s
hand. The ace is counted as 11 only if the resulting total value of all cards in a player’s
hand doesn’t exceed 21; otherwise, it’s counted as 1. Using this information, write a C++
program that accepts three card values as inputs (a 1 corresponding to an ace, a 2
corresponding to a two, and so on), calculates the total value of the hand, and displays
the value of the three cards.
Engineering and Scientific Disciplines
Civil Engineering
The field of civil engineering is concerned primarily with large-scale structures and sys-
tems used by a community. A civil engineer designs, constructs, and operates bridges,
dams, tunnels, buildings, airports, roads, and other large-scale public works. Civil engi-
neers are also responsible for the effects these large-scale systems have on society and
the environment, so they are involved in water resources, flood control, waste disposal,
and overall urban planning. The field can be subdivided into three categories:
앫 Structures: Design, construction, and operation of large-scale public works, such
as dams, buildings, and roads. The properties of materials, geology, soil mechan-
ics, and statics and dynamics are important elements of background training. For
example, determining a building’s maximum height before it buckles under its
own weight is a question involving all these subjects.
앫 Urban planning: Planning, designing, and constructing transportation systems
(roads, railroads, river development, airports) and general land use. Surveying and
mapmaking are necessary skills.
앫 Sanitation: Waste treatment, water supply, and sewage systems. Fluid mechanics,
hydrology, pollution control, irrigation, and economics are important areas of study.
230 Selection Structures
Chapter
5
Repetition
Statements
5.1 Basic Loop Structures
5.2 while Loops
5.3 Interactive while Loops
5.4 for Loops
5.5 A Closer Look: Loop
Programming Techniques
5.6 Nested Loops
5.7 do while Loops
5.8 Common Programming Errors
5.9 Chapter Summary
The programs you’ve examined so far have illustrated the programming concepts involved in input,
output, assignment, and selection capabilities. By this time, you should have gained enough experience
to be comfortable with these concepts and the mechanics of implementing them in C++. Many problems,
however, require a repetition capability, in which the same calculation or sequence of instructions is
repeated, over and over, using different sets of data. Examples of this type of repetition include
continual checking of user data entries until an acceptable entry, such as a valid password, is entered;
counting and accumulating running totals; and constant acceptance of input data and recalculation of
output values that stop only at entry of a sentinel value.
This chapter explores the different methods used by programmers in constructing repeating sections
of code and explains how they can be implemented in C++. More commonly, a section of code that’s
repeated is referred to as a loop because after the last statement in the code is executed, the program
branches, or loops, back to the first statement and starts another repetition through the code. Each
repetition is also referred to as an iteration or a pass through the loop.
5.1 Basic Loop Structures
The real power of a program is realized when the same type of operation must be made over and
over. For example, in some programs the same set of instructions is repeated multiple times.
Retyping the same set of instructions in a program is tedious, time consuming, and subject to
error. It certainly would be convenient if you could type repeating instructions only once, and
then have a method of informing the program to repeat execution of these instructions three
times. This method is available by using repeating sections of code.
Constructing a repeating section of code requires using four elements. The first
necessary element is a repetition statement. A repetition statement both defines the
boundaries of the repeating section of code and controls whether the code will be executed.
In general, three different forms of repetition statements are provided in C++:
• while
• for
• do while
Each of these statements must include a condition to be evaluated, which is the second
required element for constructing repeating sections of code. Valid conditions are identical to
those used in selection statements. If the condition is true, the code is executed; otherwise,
it’s not.
The third required element is a statement that initially sets the condition. This
statement must always be placed before the condition is first evaluated to ensure correct loop
execution the first time the condition is evaluated.
Finally, there must be a statement in the repeating section of code that allows the
condition to become false. This statement is necessary to ensure that, at some point, the
repetitions stop.
Pretest and Posttest Loops
The condition being tested can be evaluated at the beginning or end of the repeating section
of code. Figure 5.1 illustrates the test occurring at the beginning of the loop. This type of
loop is referred to as a pretest loop because the condition is tested before any statements in
the loop are executed. If the condition is true, the executable statements in the loop are
executed. If the initial value of the condition is false, the executable statements in the loop
are never executed at all, and control transfers to the first statement after the loop. To avoid
infinite repetitions, the condition must be updated within the loop. Pretest loops are also
referred to as entrance-controlled loops. Both the while and for loop structures are examples
of these loops.
A loop that evaluates a condition at end of the repeating section of code, as illustrated
in Figure 5.2, is referred to as a posttest or exit-controlled loop. These loops always execute
the loop statements at least once before the condition is tested. Because the executable
statements in the loop are executed continuously until the condition becomes false, there
must always be a statement in the loop that updates the condition and permits it to become
false. The do while construct is an example of a posttest loop.
232 Repetition Statements
previous
statement
is the
condition
true?
loop
statements
yes
no
next
statement
previous
statement
is the
condition
true?
loop
statements
yes
no
next
statement
Figure 5.1 A pretest loop Figure 5.2 A posttest loop
Fixed-Count Versus Variable-Condition Loops
In addition to classifying repeating sections of code according to where the condition is tested
(pretest or posttest), they are also classified by the type of condition being tested. In a
fixed-count loop, the condition is used to keep track of how many repetitions have occurred.
For example, you might want to produce a table of 10 numbers, including the numbers’
squares and cubes, or a fixed design, such as the following:
*************************
*************************
*************************
*************************
In these cases, a fixed number of calculations are performed or a fixed number of lines
are printed, at which point the repeating section of code is exited. All of C++’s repetition
statements can be used to produce fixed-count loops.
233
Chapter 5
Basic Loop Structures
In many situations, the exact number of repetitions isn’t known in advance, or the items
are too numerous to count beforehand. For example, when entering a large amount of
experimental data, you might not want to take the time to count the number of actual data
items to be entered. In these cases, a variable-condition loop is used. In a variable-condition
loop, the tested condition doesn’t depend on a count being reached, but on a variable that
can change interactively with each pass through the loop. When a specified value is
encountered, regardless of how many iterations have occurred, repetitions stop. All of C++’s
repetition statements can be used to create variable-condition loops.1 In this chapter, you
encounter examples of both fixed-count and variable-condition loops.
EXERCISES 5.1
1. (For Review) List the three repetition statements provided in C++.
2. (For Review) List the four elements that must be present in a repetition statement.
3. (For Review) a. What is an entrance-controlled loop?
b. Which of C++’s repetition statements produce entrance-controlled loops?
4. (For Review) a. What is an exit-controlled loop?
b. Which of C++’s repetition statements produce exit-controlled loops?
5. (For Review) a. What is the difference between a pretest and posttest loop?
b. If the condition being tested in a pretest loop is false, how many times are statements
in the loop executed?
c. If the condition being tested in a posttest loop is false, how many times are state-
ments in the loop executed?
6. (For Review) What is the difference between a fixed-count and variable-condition loop?
5.2 while Loops
In C++, a while loop is constructed by using a while statement in the following syntax:
while (expression)
statement;
The expression in parentheses is the condition tested to determine whether the
statement following the parentheses is executed. The expression is evaluated in exactly the
same manner as one in an if-else statement; the difference is in how the expression is
used. As you have seen, when the expression in an if-else statement is true (has a non-zero
value), the statement following the expression is executed once. In a while statement, the
1
In loop creation, both C and C++ differ from earlier high-level languages, in which the for statement could be used only to produce fixed-count
loops. C++’s for statement, as you see in Section 5.4, is virtually interchangeable with its while statement.
234 Repetition Statements
statement following the expression is executed repeatedly as long as the expression evaluates
to a non-zero value. Considering just the expression and the statement following the
parentheses, the computer uses this process in evaluating a while statement:
1. Test the expression
2. If the expression has a non-zero (true) value
a. execute the statement following the parentheses
b. go back to Step 1
else
exit the while statement and execute the next executable statement following the
while statement
Notice that Step 2b forces program control to be transferred back to Step 1. This transfer
of control back to the start of a while statement to reevaluate the expression is what forms
the program loop. The while statement literally loops back on itself to recheck the
expression until it evaluates to zero (becomes false). Naturally, this rechecking means that
somewhere in the loop must be a provision that permits altering the value of the tested
expression. As you’ll see, this provision is indeed made.
Figure 5.3 shows the looping process a while statement produces. A diamond shape is
used to show the two entry and two exit points required in the decision part of the while
statement.
To make this looping process more tangible, consider the relational expression count
<= 10 and the statement cout << count;. Using these elements, you can write the
following valid while statement:
while (count <= 10)
cout << count;
Although this statement is valid, the alert reader will realize that it creates a situation in
which the cout statement is either executed forever (or until you stop the program) or not
executed at all. Here’s why this happens: If count has a value less than or equal to 10 when
the expression is first evaluated, the cout statement is executed. The while statement
then automatically loops back on itself and retests the expression. Because you haven’t
changed the value stored in count, the expression is still true, and another execution of the
cout statement is made. This process continues forever, or until the program containing this
statement is stopped prematurely by the user. However, if count starts with a value greater
than 10, the expression is false to begin with, and the cout statement is never executed.
How do you set an initial value in count to control what the while statement does the
first time the expression is evaluated? The answer, of course, is to assign values to each
variable in the tested expression before the while statement is encountered. For example,
the following sequence of instructions is valid:
count = 1;
while (count <= 10)
cout << count;
Using this sequence of instructions ensures that count starts with a value of 1. You could
assign any value to count in the assignment statement. What’s important is to assign some
value. In practice, the assigned value depends on the application.
You must still change the value of count so that you can finally exit the while
statement. Doing this requires an expression such as count = count + 1 to increment
the value of count each time the while statement is executed. The fact that a while
235
Chapter 5
while Loops
statement provides for repetition of a single statement doesn’t prevent including an
additional statement to change the value of count. All you have to do is replace the single
statement with a compound statement, as in this example:
count = 1; // initialize count
while (count <= 10)
{
cout << count;
count++; // increment count
}
Note that, for clarity, each statement in the compound statement is placed on a different line.
This format is consistent with the convention adopted for compound statements in Chapter 4.
Now analyze the preceding sequence of instructions. The first assignment statement sets
count equal to 1. The while statement is then entered, and the expression is evaluated for
the first time. Because the value of count is less than or equal to 10, the expression is true,
and the compound statement is executed. The first statement in the compound statement
uses the cout object to display the value of count. The next statement adds 1 to the value
currently stored in count, making this value equal to 2. The while statement then loops
test
the expression
(step 1)
execute the
statement
after the
parentheses
(step 2a)
loop
enter the
while statement
(a false condition)
expression
evaluates
to zero
exit the
while statement
expression
evaluates
to a non-zero
number
(a true condition)
go back and
reevaluate the
expression
(step 2b)
Figure 5.3 Anatomy of a while loop
236 Repetition Statements
back to retest the expression. Because count is still less than or equal to 10, the compound
statement is executed again. This process continues until the value of count reaches 11.
Program 5.1 illustrates these statements in an actual program.
Program 5.1
#include <iostream>
using namespace std;
int main()
{
int count;
count = 1; // initialize count
while (count <= 10)
{
cout << count << " ";
count++; // increment count
}
return 0;
}
This is the output for Program 5.1:
1 2 3 4 5 6 7 8 9 10
Note that there’s nothing special about the name count used in Program 5.1. Any valid
integer variable could have been used.
Before you look at other examples of the while statement, two comments on Program 5.1
are in order. First, the statement count++ can be replaced with any statement that changes
the value of count. A statement such as count = count + 2, for example, causes every
second integer to be displayed. Second, it’s the programmer’s responsibility to ensure that
count is changed in a way that leads to a normal exit from the while. For example, if you
replace the expression count++ with the expression count--, the value of count never
exceeds 10 and an infinite loop is created. An infinite loop is a loop that never ends; the program
just keeps displaying numbers until you realize it isn’t working as you expected.
Now that you have some familiarity with the while statement, see whether you can read
and determine the output of Program 5.2.
237
Chapter 5
while Loops
Program 5.2
#include <iostream>
using namespace std;
int main()
{
int i;
i = 10;
while (i >= 1)
{
cout << i << " ";
i--; // subtract 1 from i
}
return 0;
}
The assignment statement in Program 5.2 initially sets the int variable i to 10. The
while statement then checks to see whether the value of i is greater than or equal to 1.
While the expression is true, the value of i is displayed by the cout statement, and the
value of i is decremented by 1. When i finally reaches zero, the expression is false, and the
program exits the while statement. Therefore, Program 5.2 produces the following display
when it runs:
10 9 8 7 6 5 4 3 2 1
To illustrate the power of the while statement, consider the task of printing a table of
numbers from 1 to 10 with the numbers’ squares and cubes. You can do this with a simple
while statement, as shown in Program 5.3.
When Program 5.3 runs, the following display is produced:
NUMBER SQUARE CUBE
------ ------ ----
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
238 Repetition Statements
Program 5.3
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int num;
cout << "NUMBER SQUARE CUBEn"
<< "------ ------ ----n";
num = 1;
while (num < 11)
{
cout << setw(3) << num << " "
<< setw(3) << num * num << " "
<< setw(4) << num * num * num << endl;
num++; // increment num
}
return 0;
}
Note that the expression used in Program 5.3 is num < 11. For the integer variable num,
this expression is exactly equivalent to the expression num <= 10. The choice of which to
use is entirely up to you.
If you want to use Program 5.3 to produce a table of 1000 numbers, all you do is change
the expression in the while statement from num < 11 to num < 1001. Changing the 11
to 1001 produces a table of 1000 lines—not bad for a simple five-line while statement.
239
Chapter 5
while Loops
All the program examples of the while statement use fixed-count loops because the
tested condition is a counter that checks for a fixed number of repetitions. In a variation on
the fixed-count loop, the counter is not incremented by one each time through the loop but
by some other value. For example, suppose you have the task of producing a Celsius-to-
Fahrenheit temperature conversion table. Fahrenheit temperatures corresponding to Celsius
temperatures from 5 to 50 degrees are to be displayed in increments of 5 degrees, which can
be done with this series of statements:
celsius = 5; // starting Celsius value
while (celsius <= 50)
{
fahren = (9.0/5.0) * celsius + 32.0;
cout << celsius << " "
<< fahren;
celsius = celsius + 5;
}
As before, the while statement consists of everything from the word while through the
compound statement’s closing brace. Before the program enters the while loop, you must
make sure a value is assigned to the counter being evaluated, and there’s a statement to alter
the value of the counter in the loop (in increments of 5 degrees Celsius) to ensure an exit
from the while loop. Program 5.4 illustrates using similar code in a complete program.
This is the display produced when Program 5.4 is executed:
DEGREES DEGREES
CELSIUS FAHRENHEIT
------- ----------
5 41.00
10 50.00
15 59.00
20 68.00
25 77.00
30 86.00
35 95.00
40 104.00
45 113.00
50 122.00
240 Repetition Statements
Program 5.4
#include <iostream>
#include <iomanip>
using namespace std;
// a program to convert Celsius to Fahrenheit
int main()
{
const int MAX_CELSIUS = 50;
const int START_VAL = 5;
const int STEP_SIZE = 5;
int celsius;
double fahren;
cout << "DEGREES DEGREESn"
<< "CELSIUS FAHRENHEITn"
<< "------- ----------n";
celsius = START_VAL;
// set output formats for floating point numbers only
cout << setiosflags(ios::showpoint)
<< setprecision(2);
while (celsius <= MAX_CELSIUS)
{
fahren = (9.0/5.0) * celsius + 32.0;
cout << setw(4) << celsius << fixed
<< setw(13) << fahren << endl;
celsius = celsius + STEP_SIZE;
}
return 0;
}
241
Chapter 5
while Loops
Technical Note
Fluid Mechanics
The field of fluid mechanics deals with fluids at rest and in motion. Fluids include
both liquids and gases and are defined as substances that conform to the shape of
their holding containers. These are the primary differences between gases and liquids:
앫 Gases are expandable and contractible and always expand or contract to fill all
space in the container holding them.
앫 Liquids occupy a definite volume and have a free surface if they don’t fill the
container holding them.
Fluid statics is the science of fluids at rest, a major subdiscipline of fluid mechanics.
The most important property for fluids at rest is their weight. Fluid dynamics is the sci-
ence of fluids in motion, which is the second major subdiscipline of fluid mechanics and
includes aerodynamics, the study of gases in motion, and hydrodynamics, the study of liq-
uids in motion.
For flowing fluids, the two most important properties are density and viscosity.
Density is the measure of how tightly packed the fluid is (density = mass/volume).
Viscosity is the measure of a liquid’s resistance to shear stress. A fluid begins to flow
when an applied force, known as a shear stress, is large enough to overcome the fluid’s
weight and internal friction, assuming the fluid isn’t totally constrained in the direction of
the force. The three types of fluid flow patterns through a pipe or conduit are as follows:
앫 Laminar—All fluid particles flow in smooth, straight lines parallel to the
pipe’s wall.
앫 Turbulent—Fluid particle paths are irregular, but the average motion is in the
direction of the flow.
앫 In transition—The fluid is between laminar and turbulent flow.
Laminar flow generally occurs only when the fluid’s viscosity is very high, as in
lubricating oils. Most flows, such as water flowing through pipes, are faster and
turbulent.
The Reynolds number provides a quick means of determining flow patterns and
can be calculated by using this formula:
Re =
ρ
µ
Vd
Re = the Reynolds number
ρ = the fluid’s density (kg/m3
)
V = the fluid’s average speed (m/s)
d = the pipe’s diameter (m)
µ = the fluid’s viscosity (kg/ms)
continued...
242 Repetition Statements
EXERCISES 5.2
1. (Practice) Rewrite Program 5.1 to print the numbers 2 to 10 in increments of two. The
output of your program should be the following:
2 4 6 8 10
2. (Practice) Rewrite Program 5.4 to produce a table starting at a Celsius value of -10 and
ending with a Celsius value of 60, in increments of 10 degrees.
3. (Desk Checking) a. For the following program, determine the total number of items
displayed as well as the first and last numbers printed:
#include <iostream>
using namespace std;
int main()
{
int num = 0;
while (num <= 20)
{
num++;
cout << num << " ";
}
return 0;
}
b. Enter and run the program from Exercise 3a on a computer to verify your answers to
the exercise.
Technical Note
Fluid Mechanics (continued)
Essentially, the Reynolds number is equal to the ratio of
fluid speed
viscous forces
A higher Reynolds number correlates with a higher fluid speed. However, when
viscous forces predominate (they are retarding forces), the Reynolds number is lower,
and the fluid flow is slower. In a highly viscous fluid, such as heavy oil, all the fluid’s
particles tend to be kept in line, which is referred to as laminar flow. Critical Reynolds
number values for determining flow type are as follows:
앫 Re < 2000: Fluid flow is laminar (least common type of water flow).
앫 2000 ⱕ Re ⱖ 3000: Fluid flow is in transition.
앫 Re > 3000: Fluid flow is turbulent (most common type of fluid flow).
243
Chapter 5
while Loops
c. How would the output be affected if the two statements in the compound statement
were reversed (that is, if the cout statement came before the num++ statement)?
4. (Conversions) Write a C++ program that converts gallons to liters. The program should
display gallons from 10 to 20 in one-gallon increments and the corresponding liter
equivalents. Use the relationship that 1 gallon = 3.785 liters.
5. (Conversions) Write a C++ program that converts feet to meters. The program should
display feet from 3 to 30 in 3-foot increments and the corresponding meter equivalents.
Use the relationship that 1 meter = 3.28 feet.
6. (Practice) An automobile travels at an average speed of 55 mph for four hours. Write a
C++ program that displays the distance, in miles, the car has traveled after 1, 2, and so on
hours until the end of the trip.
7. (Fluid Mechanics) The maximum laminar flow speed is the speed at which a fluid
begins to change from a smooth, straight flow to turbulent flow within a pipe. It can be
determined by using this formula:
Maximum laminar flow speed = (2000 × pipe diameter × density)/viscosity
Using this formula, write a C++ program that used a fixed-count repetition loop of four.
For each pass through the loop, the program should accept a fluid’s density, its viscosity,
and a pipe diameter as input, and then calculate and output the maximum laminar flow
rate through the pipe. Use the results your program outputs to complete the last column
in this chart:
Fluid Viscosity at 40°C
= 77°F (kg/ms)
Density (kg/m3
) Pipe
Diameter
(m)
Maximum
Laminar
Flow
Speed
(m/s)
Gasoline .4466 × 10-3
.7186 × 103
0.4
Medium
fuel oil
2.9922 × 10-3
.8496 × 103
0.4
Medium
lubricating oil
87.0736 × 10-3
.8865 × 103
0.4
Water .8975 × 10-3
.9973 × 103
0.4
8. (Numerical Analysis) a. The following is an approximate conversion formula for con-
verting Fahrenheit to Celsius temperatures:
Celsius = (Fahrenheit - 30) / 2
Using this formula, and starting with a Fahrenheit temperature of 0 degrees, write a C++
program that determines when the approximate equivalent Celsius temperature differs
from the exact equivalent value by more than four degrees. (Hint: Use a while loop that
terminates when the difference between approximate and exact Celsius equivalents
exceeds 4 degrees.)
244 Repetition Statements
b. Using the approximate Celsius conversion formula given in Exercise 8a, write a C++
program that produces a table of Fahrenheit temperatures, exact Celsius equivalent
temperatures, approximate Celsius equivalent temperatures, and the difference
between the exact and approximate equivalent Celsius values. The table should begin
at 0 degrees Fahrenheit, use 2-degree Fahrenheit increments, and terminate when the
difference between exact and approximate values is more than 4 degrees.
9. (Numerical Analysis) The value of Euler’s number, e, can be approximated by using
this formula:
e = + + + + + +
1
1
1
1
2
1
3
1
4
1
5
! ! ! ! !
...
Using this formula, write a C++ program that approximates the value of e, using a while
loop that terminates when the difference between two successive approximations is less
than 10e-9.
10. (Numerical Analysis) The value of sin x can be approximated by using this formula:
sin( )
! ! ! !
. . .
x x
x x x x
= + +
- -
3 5 7 9
3 5 7 9
Using this formula, determine how many terms are needed to approximate the value
returned by the intrinsic sin() function with an error less than 1e-6, when x = 30
degrees. (Hints: Use a while loop that terminates when the difference between the value
returned by the intrinsic sin() function and the approximation is less than 1e-6. Also,
note that x must first be converted to radian measure, and the alternating sign in the
approximating series can be determined as (-1) × (n + 1), where n is the number of terms
used in the approximation.)
5.3 Interactive while Loops
Combining interactive data entry with the repetition capabilities of the while statement
produces adaptable and powerful programs. To understand the concept, take a look at
Program 5.5, where a while statement is used to accept and then display four user-entered
numbers, one at a time. Although the program uses a simple idea, it highlights the flow of
control concepts needed to produce more useful programs.
The following is a sample run of Program 5.5:
This program will ask you to enter 4 numbers.
Enter a number: 26.2
The number entered is 26.2
Enter a number: 5
The number entered is 5
Enter a number: 103.456
The number entered is 103.456
Enter a number: 1267.89
The number entered is 1267.89
245
Chapter 5
Interactive while Loops
Program 5.5
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const int MAXNUMS = 4;
int count;
double num;
cout << "nThis program will ask you to enter "
<< MAXNUMS << " numbers.n";
count = 1;
while (count <= MAXNUMS)
{
cout << "nEnter a number: ";
cin >> num;
cout << "The number entered is " << num;
count++;
}
cout << endl;
return 0;
}
Review the program so that you understand clearly how the output was produced. The
first message displayed is caused by execution of the first cout statement. This statement
is outside and before the while statement, so it’s executed once before any statement in the
while loop.
After the while loop is entered, the statements in the compound statement are
executed while the tested condition is true. The first time through the compound statement,
the message Enter a number: is displayed. The program then executes the cin
statement, which forces the computer to wait for a number to be entered at the keyboard.
After a number is typed and the Enter key is pressed, the cout statement displays the
number. The variable count is then incremented by one. This process continues until four
passes through the loop have been made and the value of count is 5. Each pass causes the
message Enter a number: to be displayed, causes one cin statement to be executed, and
causes the message The number entered is to be displayed. Figure 5.4 illustrates this
flow of control.
Instead of simply displaying the entered numbers, Program 5.5 can be modified to use
the entered data. For example, you can add the numbers entered and display the total. To
do this, you must be careful about how you add the numbers because the same variable, num,
is used for each number entered. For this reason, the entry of a new number in Program 5.5
246 Repetition Statements
automatically causes the previous number stored in num to be lost. Therefore, each number
entered must be added to the total before another number is entered. This is the required
sequence:
Enter a number
Add the number to the total
add 1 to
count
loop
no
(condition is false)
set count
equal to 1
print a
message
print value
of number
accept a
number
using cin
print the
message
Enter a
number:
is count
less than or
equal to
4?
go back and
retest count
these statements
are executed
each time the loop
is traversed
yes
(condition is true)
end of program
start
stop
Figure 5.4 Flow of control diagram for Program 5.5
247
Chapter 5
Interactive while Loops
How do you add a single number to a total? A statement such as total = total + num
does the job perfectly. It’s the accumulation statement introduced in Section 3.1. After each
number is entered, the accumulating statement adds the number to the total, as shown in
Figure 5.5.
The complete flow of control for adding the numbers is illustrated in Figure 5.6. In
reviewing Figure 5.6, observe that a provision has been made for initially setting the total to
zero before the while loop is entered. If you cleared the total inside the while loop, it
would be set to zero each time the loop was executed, and any value stored previously would
be erased.
total = total + num
new
total
total
the variable total
new number
goes in here
cin
num
new number
accept a new
number
the variable num
add 1 to
count
add num
to total
accept a
num
is count
< 4?
no
set total
to zero
print total
yes
set count
to one
stop
start
Figure 5.5 Accepting and adding Figure 5.6 Accumulation flow of
a number to a total control
Program 5.6 incorporates the necessary modifications to Program 5.5 to total the numbers
entered. As shown, the statement total = total + num; is placed immediately after the
cin statement. Putting the accumulating statement at this point in the program ensures that
the entered number is “captured” immediately into the total.
248 Repetition Statements
Program 5.6
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const int MAXNUMS = 4;
int count;
double num, total;
cout << "nThis program will ask you to enter "
<< MAXNUMS << " numbers.n";
count = 1;
total = 0;
while (count <= MAXNUMS)
{
cout << "nEnter a number: ";
cin >> num;
total = total + num;
cout << "The total is now " << setprecision(7) << total;
count++;
}
cout << "nThe final total is " << setprecision(7) << total << endl;
return 0;
}
To make sure you understand, review Program 5.6. The variable total was created to
store the total of the numbers entered. Before entering the while statement, the value of
total is set to zero to make sure any previous value in the storage location(s) assigned to
the variable total is erased. Inside the while loop, the statement total = total +
num; is used to add the value of the entered number to total. As each value is entered,
it’s added to the existing total to create a new total. Therefore, total becomes a running
subtotal of all the values entered. Only after all numbers are entered does total contain the
final sum of all the numbers. After the while loop is finished, a cout statement is used to
display this sum.
249
Chapter 5
Interactive while Loops
Using the same data entered in the sample run for Program 5.5, the following sample run
of Program 5.6 was made:
This program will ask you to enter 4 numbers.
Enter a number: 26.2
The total is now 26.2
Enter a number: 5
The total is now 31.2
Enter a number: 103.456
The total is now 134.656
Enter a number: 1267.89
The total is now 1402.546
The final total is 1402.546
Having used an accumulating assignment statement to add the numbers entered, you can
go further and calculate the average of the numbers. Where do you calculate the average—
inside the while loop or outside it?
In the case at hand, calculating an average requires that both a final sum and the number
of items in that sum be available. The average is then computed by dividing the final sum
by the number of items. At this point, you must ask, “At what point in the program is the
correct sum available, and at what point is the number of items available?”
In reviewing Program 5.6, you can see that the correct sum needed for calculating the
average is available after the while loop is finished. In fact, the whole purpose of the while
loop is to ensure that the numbers are entered and added correctly to produce a correct sum.
After the loop is finished, you also have a count of the number of items used in the sum.
However, because of the way the while loop was constructed, the number in count (5)
when the loop is finished is one more than the number of items (four) used to obtain the
total. Knowing this, you simply subtract one from count before using it to determine the
average. With this information as background, take a look at Program 5.7.
Program 5.7 is almost identical to Program 5.6, except for the calculation of the average.
The constant display of the total inside and after the while loop has also been removed.
The loop in Program 5.7 is used to enter and add four numbers. Immediately after the loop
is exited, the average is computed and displayed. A sample run of Program 5.7 follows:
This program will ask you to enter 4 numbers.
Enter a number: 26.2
Enter a number: 5
Enter a number: 103.456
Enter a number: 1267.89
The average of the numbers is 350.637
250 Repetition Statements
Program 5.7
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const int MAXNUMS = 4;
int count;
double num, total, average;
cout << "nThis program will ask you to enter "
<< MAXNUMS << " numbers.n";
count = 1;
total = 0;
while (count <= MAXNUMS)
{
cout << "Enter a number: ";
cin >> num;
total = total + num;
count++;
}
count--;
average = total / count;
cout << "nThe average of the numbers is " << average << endl;
return 0;
}
Sentinels
All the loops created so far have been examples of fixed-count loops, in which a counter is used
to control the number of loop iterations. By means of a while statement, variable-condition
loops can also be constructed. For example, when entering grades, you might not want to count
the number of grades that will be entered. Instead, you prefer to enter the grades continuously,
and at the end, type in a special data value to signal the end of data input.
In computer programming, data values used to signal the start or end of a data series are
called sentinels. Sentinel values must, of course, be selected so as not to conflict with
legitimate data values. For example, if you’re constructing a program to process a student’s
grades, and assuming no extra credit is given that could produce a grade higher than 100, you
could use any grade higher than 100 as a sentinel value. Program 5.8 illustrates this concept:
Data is requested and accepted continuously until a number larger than 100 is entered. Entry
251
Chapter 5
Interactive while Loops
of a number higher than 100 alerts the program to exit the while loop and display the sum
of the numbers entered.
Program 5.8
#include <iostream>
using namespace std;
int main()
{
const int HIGHGRADE = 100;
double grade, total;
grade = 0;
total = 0;
cout << "nTo stop entering grades, type in any number";
cout << "n greater than 100.nn";
while (grade <= HIGHGRADE)
{
total = total + grade;
cout << "Enter a grade: ";
cin >> grade;
}
cout << "nThe total of the grades is " << total << endl;
return 0;
}
The following lines show a sample run of Program 5.8. As long as grades less than or
equal to 100 are entered, the program continues to request and accept additional data. When
a number less than or equal to 100 is entered, the program adds this number to the total.
When a number greater than 100 is entered, the loop is exited, and the sum of the grades that
were entered is displayed.
To stop entering grades, type in any number
greater than 100.
Enter a grade: 95
Enter a grade: 100
Enter a grade: 82
Enter a grade: 101
The total of the grades is 277
252 Repetition Statements
break and continue Statements
Two useful statements in connection with repetition statements are the break and continue
statements. You encountered the break statement in Section 4.4 when learning about the
switch statement. This is the format of the break statement:
break;
A break statement, as its name implies, forces an immediate break, or exit, from the
switch, while, for, and do-while statements (discussed in the next sections). For
example, execution of the following while loop is terminated immediately if a number
greater than 76 is entered:
while(count <= 10)
{
cout << "Enter a number: ";
cin >> num;
if (num > 76)
{
cout << "You lose!n";
break; // break out of the loop
}
else
cout << "Keep on trucking!n";
count++
}
// break jumps to here
The break statement violates structured programming principles because it provides a
second, nonstandard exit from a loop. Nevertheless, the break statement is extremely useful
for breaking out of loops when an unusual condition is detected. The break statement is
also used to exit from a switch statement when the matching case value has been
detected and processed.
The continue statement is similar to the break statement but applies only to loops
created with while, do-while, and for statements. This is the general format of a
continue statement:
continue;
When continue is encountered in a loop, the next iteration of the loop begins
immediately. For while loops, this means execution is transferred automatically to the top of the
loop, and reevaluation of the tested expression is initiated. Although the continue statement
has no direct effect on a switch statement, it can be included in a switch statement, which
is contained in a loop. The effect of continue is the same: The next loop iteration begins.
As a general rule, the continue statement is less useful than the break statement, but
it’s convenient for skipping over data that shouldn’t be processed while remaining in a loop.
253
Chapter 5
Interactive while Loops
For example, invalid grades are simply ignored in the following section of code, and only
valid grades are added to the total:2
while (count < 30)
{
cout << "Enter a grade: ";
cin >> grade
if(grade < 0 || grade > 100)
continue;
total = total + grade;
count++;
}
The Null Statement
All statements must be terminated by a semicolon. A semicolon with nothing preceding it is
also a valid statement, called the null statement, as shown:
;
It’s a do-nothing statement used where a statement is required syntactically, but no
action is called for. Typically, null statements are used with while or for statements.
Program 5.10c in Section 5.4 shows an example of a for statement using a null statement.
EXERCISES 5.3
1. (Practice) Rewrite Program 5.6 to compute the total of eight numbers.
2. (Practice) Rewrite Program 5.6 to display this prompt:
Please type in the total number of data values to be added:
In response to this prompt, the program should accept a user-entered number, and then
use this number to control the number of times the while loop is executed. So if the
user enters 5 in response to the prompt, the program should request the input of five
numbers and display the total after five numbers have been entered.
3. (Practice) Rewrite Program 5.7 to compute the average of 10 numbers.
4. (Practice) Rewrite Program 5.7 to display the following prompt:
Please type in the total number of data values to be averaged:
2
The continue statement is not essential, however, and the selection could have been written as follows:
if (gradeⱖ 0 && grade ⱕ 100)
{
total = total + grade;
count++;
}
254 Repetition Statements
In response to this prompt, the program should accept a user-entered number, and then
use this number to control the number of times the while loop is executed. So if the
user enters 6 in response to the prompt, the program should request an input of six num-
bers and display the average of the next six numbers entered.
5. (Debugging) By mistake, a programmer puts the statement average = total /
count; in the while loop immediately after the statement total = total + num;
in Program 5.7. As a result, the while loop becomes the following:
while (count <= MAXNUMS)
{
cout << "Enter a number: ";
cin >> num;
total = total + num;
average = total / count;
count++;
}
a. Will the program yield the correct result with this while loop?
b. From a programming perspective, which while loop is better to use and why?
6. (Conversions) a. Write a C++ program to convert meters to feet. The program should
request the starting meter value, the number of conversions to be made, and the increment
between metric values. The display should have appropriate headings and list the meters and
the corresponding feet value. If the number of iterations is greater than 10, have your pro-
gram substitute a default increment of 10. Use the relationship that 1 meter = 3.281 feet.
b. Run the program written in Exercise 6a on a computer. Verify that your program
begins at the correct starting meter value and contains the exact number of conver-
sions specified in your input data.
7. (Conversions) a. Modify the program written in Exercise 6a to request the starting
meter value, the ending meter value, and the increment. Instead of the condition check-
ing for a fixed count, the condition checks for the ending meter value. If the number of
iterations is greater than 20, have your program substitute a default increment of (ending
value - starting value) / 19.
b. Run the program written in Exercise 7a on a computer. Verify that your output starts
at the correct beginning value and ends at the correct ending value.
8. (Numerical Analysis) An arithmetic series is defined by the following:
a + (a + d) + (a + 2d) + (a + 3d) + ...
+ [(a + (n - 1)d)]
a is the first term.
d is the “common difference.”
n is the number of terms to be added.
Using this information, write a C++ program that uses a while loop to display each term
and determine the sum of the arithmetic series having a = 1, d = 3, and n = 100. Make
sure your program displays the value it has calculated.
9. (Numerical Analysis) A geometric series is defined by the following:
a + ar + ar 2
+ ar 3
+ ...
+ arn - 1
255
Chapter 5
Interactive while Loops
a is the first term.
r is the “common ratio.”
n is the number of terms in the series.
Using this information, write a C++ program that uses a while loop to both display each
term and determine the sum of a geometric series having a = 1, r = .5, and n = 10. Make
sure your program displays the value it has calculated.
10. (Misc. Application) a. The data in the following chart was collected on a recent auto-
mobile trip:
Mileage Gallons
22,495 Full tank
22,841 12.2
23,185 11.3
23,400 10.5
23,772 11.0
24,055 12.2
24,434 14.7
24,804 14.3
25,276 15.2
Write a C++ program that accepts a mileage and gallons value and calculates the miles
per gallon (mpg) for that segment of the trip. The mpg is obtained as the difference in
mileage between fill-ups divided by the number of gallons of gasoline used in the fill-up.
b. Modify the program written for Exercise 10a to also compute and display the cumula-
tive mpg after each fill-up. The cumulative mpg is calculated as the difference
between the mileage at each fill-up and the mileage at the start of the trip divided by
the sum of gallons used to that point in the trip.
5.4 for Loops
In C++, a for loop is constructed by using a for statement. This statement performs the
same functions as the while statement but uses a different form. In many situations,
especially those using a fixed-count condition, the for statement format is easier to use than
its while statement equivalent. This is the syntax of the for statement:
for (initializing list; expression; altering list)
statement;
Although the for statement looks a little complicated, it’s really quite simple if you
consider each part separately. Inside the parentheses of the for statement are three items,
separated by semicolons. Each item is optional and can be described separately, but the
semicolons must always be present, even if you don’t use the items. In the for statement’s
most common form, the initializing list consists of a single statement used to set
the starting (initial) value of a counter, the expression (also called the “condition”)
256 Repetition Statements
contains the maximum or minimum value the counter can have and determines when the
loop is finished, and the altering list provides the increment value that’s added to or
subtracted from the counter each time the loop is executed. Here are two examples of simple
for statements having this form:
for (count = 1; count < 10; count = count + 1)
cout << count;
and
for (i = 5; i <= 15; i = i + 2)
cout << i;
In the first for statement, the counter variable is named count, the initial value
assigned to count is 1, the loop continues as long as the value in count is less than 10, and
the value of count is incremented by 1 each time through the loop.
In the next for statement, the counter variable is named i, the initial value assigned to
i is 5, the loop continues as long as i’s value is less than or equal to 15, and the value of i
is incremented by 2 each time through the loop. In both examples, a cout statement is used
to display the value of the counter. Program 5.9 shows another example of a for loop.
Program 5.9
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
const int MAXCOUNT = 5;
int count;
cout << "NUMBER SQUARE ROOTn";
cout << "------ -----------n";
cout << setiosflags(ios::showpoint);
for (count = 1; count <= MAXCOUNT; count++)
cout << setw(4) << count
<< setw(15) << sqrt(double(count)) << endl;
return 0;
}
257
Chapter 5
for Loops
When Program 5.9 is executed, the following display is produced:
NUMBER SQUARE ROOT
------ -----------
1 1.00000
2 1.41421
3 1.73205
4 2.00000
5 2.23607
The first two lines of this output are produced by the two cout statements placed before
the for statement. The remaining output is produced by the for loop, which begins with
the for statement and is executed as follows: The initial value assigned to the counter
variable count is 1. Because the value in count doesn’t exceed the final value of 5, the
execution of the cout statement in the loop produces this display:
1 1.00000
Control is then transferred back to the for statement, which increments the value in
count to 2, and the loop is repeated, producing this display:
2 1.41421
This process continues until the value in count exceeds the final value of 5, producing
the complete output table.
For comparison purposes, a while loop equivalent to the for loop in Program 5.9 is as
follows:
count = 1
while (count <= MAXCOUNT)
{
cout << setw(4) << count
<< setw(15) << sqrt(count) << endl;
count++;
}
As you can see in this example, the difference between the for and while loops is the
placement of the initialization, condition being tested, and incrementing items. Grouping
these items in the for statement is convenient when you must construct fixed-count loops.
See whether you can determine the output Program 5.10 produces.
258 Repetition Statements
Program 5.10
#include <iostream>
using namespace std;
int main()
{
int count;
for (count = 2; count <= 20; count = count + 2)
cout << count << " ";
return 0;
}
Did you figure it out? The loop starts with count initialized to 2, stops when count
exceeds 20, and increments count in steps of 2. This is the output of Program 5.10:
2 4 6 8 10 12 14 16 18 20
As mentioned, the for statement doesn’t require having an initializing or altering list
inside for’s parentheses; however, the two semicolons must be included in these
parentheses. For example, the construction for ( ; count <= 20 ;) is valid.
If the initializing list is missing, the initialization step is omitted when the for statement is
executed. Therefore, the programmer must provide the required initializations before the for
statement is encountered. Similarly, if the altering list is missing, any expressions needed to alter
the evaluation of the tested expression must be included in the statement part of the loop. The
for statement only ensures that all expressions in the initializing list are executed once, before
evaluation of the tested expression, and all expressions in the altering list are executed at the end
of the loop, before the tested expression is rechecked. Program 5.10 can be rewritten in any of
the three ways shown in Programs 5.10a, 5.10b, and 5.10c.
Program 5.10a
#include <iostream>
using namespace std;
int main()
{
int count;
count = 2; // initializer outside the for statement
for ( ; count <= 20; count = count + 2)
cout << count << " ";
return 0;
}
259
Chapter 5
for Loops
Program 5.10b
#include <iostream>
using namespace std;
int main()
{
int count;
count = 2; // initializer outside the for loop
for( ; count <= 20; )
{
cout << count << " ";
count = count + 2; // alteration statement
}
return 0;
}
Program 5.10c
#include <iostream>
using namespace std;
int main() // all expressions inside for's parentheses
{
int count;
for (count = 2; count <= 20; cout << count << " ", count = count + 2);
return 0;
}
In Program 5.10a, count is initialized outside the for statement, and the first list inside
the parentheses is left blank. In Program 5.10b, both the initializing list and the altering list
are outside the parentheses. Program 5.10b also uses a compound statement in the for loop,
with the expression-altering statement included in the compound statement. Finally,
Program 5.10c has included all items inside the parentheses, so there’s no need for any useful
statement following the parentheses. In this example, the null statement satisfies the
syntactical requirement of one statement to follow for’s parentheses.
Also, observe in Program 5.10c that the altering list (the last set of items in parentheses)
consists of two items, and a comma has been used to separate these items. Using commas to
separate items in both the initializing and altering lists is required if either of these lists
contains more than one item.
260 Repetition Statements
Last, note that Programs 5.10a, 5.10b, and 5.10c are all inferior to Program 5.10, and
although you might encounter them in your programming career, you shouldn’t use them.
Adding items other than loop control variables and their updating conditions in the for
statement tends to make it confusing to read and can result in unwanted effects. Keeping the
loop control structure “clean,” as in Program 5.10, is important and a good programming
practice.
Although the initializing and altering lists can be omitted from a for statement, omitting
the tested expression results in an infinite loop. For example, this statement creates an
infinite loop:
for (count = 2; ; count = count + 1)
cout << count;
As with the while statement, both break and continue statements can be used in
a for loop. A break forces an immediate exit from the for loop, as it does in the while
loop. A continue, however, forces control to be passed to the altering list in a for
statement, after which the tested expression is reevaluated. This action differs from
continue’s action in a while statement, where control is passed directly to reevaluation of
the tested expression.
Figure 5.7 illustrates the internal workings of a for loop. As shown, when the for loop
is completed, control is transferred to the first executable statement following the loop. To
avoid having to illustrate every step, you can use a simplified set of flowchart symbols to
describe for loops. If you use the following flowchart symbol to represent a for statement,
Point of Information
Where to Place the Opening Braces
When the for loop contains a compound statement, professional C++ programmers use
two styles of writing for loops. The style used in this book takes the following form:
for (expression)
{
compound statement in here
}
An equally acceptable style places the compound statement’s opening brace on the
first line. Using this style, a for loop looks like the following:
for (expression) {
compound statement in here
}
The advantage of the first style is that the braces line up under one another, making it
easier to locate brace pairs. The advantage of the second style is that it makes the code
more compact and saves a line, so more code can be viewed in the same display area.
Both styles are used but are almost never intermixed. Select whichever style appeals to you
and be consistent in its use. As always, the indentation you use in the compound state-
ment (two or four spaces or a tab) should also be consistent throughout all your programs.
The combination of styles you select becomes a “signature” for your programming work.
261
Chapter 5
for Loops
you can then illustrate a complete for loop, as shown in Figure 5.8.
for
statement
execute the
altering list
execute the
statement
after the
parentheses
evaluate
the
tested
expression
loop
(false condition)
expression’s value
is non-zero
(true condition)
initializing
statements
enter the
for statement
expression’s value
is zero
exit the
for statement
go back and
retest the condition
Figure 5.7 A for loop flowchart
262 Repetition Statements
To understand the enormous power of for loops, consider the task of printing a table of
numbers from 1 to 10, including their squares and cubes, by using a for statement. This
table was produced previously by using a while loop in Program 5.3. You might want to
review Program 5.3 and compare it to Program 5.11 to get a better sense of the equivalence
between for and while loops.
Point of Information
Do You Use a for or while Loop?
Beginning programmers often ask which loop structure they should use—a for or
while loop. It’s a good question because both loop structures are pretest loops that,
in C++, can be used to construct fixed-count and variable-condition loops.
In most other computer languages, including Visual Basic and Pascal, the answer is
straightforward because the for statement can be used only to construct fixed-count
loops. In these languages, then, for statements are used to construct fixed-count
loops, and while statements are generally used only for variable-condition loops.
In C++, this easy distinction doesn’t hold because both statements can be used to
create both types of loops. The answer is more a matter of style. Because a for and
while loop are interchangeable in C++, either loop is appropriate. Some professional
programmers always use a for statement for pretest loops and almost never use a
while statement; others always use a while statement and rarely use a for
statement. Still a third group tends to retain the convention used in other languages—a
for loop is generally used to create fixed-count loops, and a while loop is used to
create variable-condition loops. In C++, it’s a matter of style, and you’ll encounter all
three styles in your programming career.
for
(expression)
{
statement 1
through
statement n
}
enter the for
statement
expression’s value is non-zero
(true condition)
(false condition)
expression’s value
is zero exit the for
statement
Figure 5.8 A simplified for loop flowchart
263
Chapter 5
for Loops
Program 5.11
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const int MAXNUMS = 10;
int num;
cout << "NUMBER SQUARE CUBEn"
<< "------ ------ ----n";
for (num = 1; num <= MAXNUMS; num++)
cout << setw(3) << num << " "
<< setw(3) << num * num << " "
<< setw(4) << num * num * num << endl;
return 0;
}
When Program 5.11 runs, this is the display produced:
NUMBER SQUARE CUBE
------ ------ ----
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
Simply changing the number 10 in the for statement of Program 5.11 to 1000 creates
a loop that’s executed 1000 times and produces a table of numbers from 1 to 1000. As with
the while statement, this small change produces an immense increase in the program’s
processing and output. Notice also that the expression num++ was used in the altering list in
place of the usual num = num + 1.
264 Repetition Statements
EXERCISES 5.4
1. (Practice) Write a for statement for each of the following cases:
a. Use a counter named i that has an initial value of 1, a final value of 20, and an incre-
ment of 1.
b. Use a counter named icount that has an initial value of 1, a final value of 20, and an
increment of 2.
c. Use a counter named j that has an initial value of 1, a final value of 100, and an
increment of 5.
d. Use a counter named icount that has an initial value of 20, a final value of 1, and an
increment of -1.
e. Use a counter named icount that has an initial value of 20, a final value of 1, and an
increment of -2.
f. Use a counter named count that has an initial value of 1.0, a final value of 16.2, and
an increment of 0.2.
g. Use a counter named xcnt that has an initial value of 20.0, a final value of 10.0, and
an increment of -0.5.
2. (Desk Checking) Determine the number of times each for loop is executed for the
for statements written for Exercise 1.
3. (Desk Checking) Determine the value in total after each of the following loops is
executed:
a. total = 0;
for (i = 1; i <= 10; i = i + 1)
total = total + 1;
b. total = 1;
for (count = 1; count <= 10; count = count + 1)
total = total * 2;
c. total = 0
for (i = 10; i <= 15; i = i + 1)
total = total + i;
d. total = 50
for (i = 1; i <=10; i = i + 1)
total = total – i;
e. total = 1
for (icnt = 1; icnt <= 8; ++icnt)
total = total * icnt;
f. total = 1.0
for (j = 1; j <= 5; ++j)
total = total / 2.0;
265
Chapter 5
for Loops
4. (Desk Checking) Determine the output of the following program:
#include <iostream>
using namespace std;
int main()
{
int i;
for (i = 20; i >= 0; i = i – 4)
cout << i << " ";
return 0;
}
5. (Modify) Modify Program 5.11 to produce a table of the numbers 0 through 20 in incre-
ments of 2, with their squares and cubes.
6. (Modify) Modify Program 5.11 to produce a table of numbers from 10 to 1, instead of 1
to 10, as it currently does.
7. (Conversions) Write a C++ program to convert kilometers/hr to miles/hr. The program
should produce a table of 10 conversions, starting at 60 km/hr and incremented by 5 km/hr.
The display should have appropriate headings and list each km/hr and its equivalent miles/hr
value. Use the relationship that 1 kilometer = 0.6241 miles.
8. (Practice) Write sections of C++ code to do the following:
a. Display the multiples of 3 backward from 33 to 3, inclusive.
b. Display the uppercase letters of the alphabet backward from Z to A.
9. (Practice) Write, run, and test a C++ program to find the value of 2n
by using a for
loop, where n is an integer value the user enters at the keyboard. (Hint: Initialize result
= 1. Accumulate result = 2 * result.)
10. (Fluid Dynamics) Write a C++ program that uses a fixed-count loop of four. For each
pass through the loop, enter a fluid’s viscosity and density from the following chart. Your
program should then determine the kinematic viscosity for each fluid, using the following
formula (see the Technical Note in Section 5.2 for a description of density and viscosity):
Kinematic viscosity = viscosity / density
Use the results output by your program to complete the last column in this chart:
Fluid Viscosity at 40°C =
77°F (kg/ms)
Density (kg/m3
) Kinematic
Viscosity (m2
/s)
Gasoline .4466 × 10-3
.7186 × 103
Medium fuel oil 2.9922 × 10-3
.8496 × 103
Medium
lubricating oil
87.0736 × 10-3
.8865 × 103
Water .8975 × 10-3
.9973 × 103
266 Repetition Statements
11. (Fluid Dynamics) Write a C++ program that calculates the Reynolds number for a pipe
having a diameter of 0.1 meters, in which fluid flows at an average rate of .09 m/s. Your
program should have a fixed-count loop of four and display both the calculated Reynolds
number and the type of fluid flow—laminar, in-transition, or turbulent—for each fluid
listed in the following chart, using the information provided after the chart. Use the
results your program outputs to fill in the last two columns of this chart:
Fluid Kinematic
Viscosity
(m2
/s) at
40°C
Pipe
Diameter (m)
Avg.
Fluid
Speed
(m/s)
Reynolds
Number
Type of Flow
Gasoline 6.215 × 10-7
0.1 .09
Medium
fuel oil
3.523 × 10-6
0.1 .09
Medium
lubricating oil
9.822 × 10-5
0.1 .09
Water 8.999 × 10-5
0.1 .09
The Reynolds number can be calculated by using this formula:
Re =
V d
v
Re is the Reynolds number.
V is the average speed of the fluid (ft/sec or m/s).
d is the pipe diameter (ft or m).
␯ is the kinematic viscosity (ft2
/sec or m2
/sec).
For the determination of flow type, use these facts:
Re < 2000: Fluid flow is smooth (laminar).
2000 ⱕ Re ⱖ 3000: Fluid flow is in transition.
Re > 3000: Fluid flow is turbulent.
12. (Structural Eng.) The expansion of a steel bridge as it’s heated to a final Celsius tem-
perature, TF, from an initial Celsius temperature, T0, can be approximated by using this
formula:
Increase in length = a × L × (TF - T0)
a is the coefficient of expansion (which for steel is 11.7 × 10-6
).
L is the length of the bridge at temperature T0.
Using this formula, write a C++ program that displays a table of expansion lengths for a
steel bridge that’s 7365 meters long at 0 degrees Celsius, as the temperature increases to
40 degrees in 5-degree increments.
267
Chapter 5
for Loops
5.5 A Closer Look: Loop Programming Techniques
This section discusses four common programming techniques associated with pretest (for and
while) loops. All these techniques are common knowledge to experienced programmers.
Technique 1: Interactive Input in a Loop
In Section 5.2, you saw the effect of including a cin statement in a while loop. Entering
data interactively in a loop is a general technique that’s equally applicable to for loops. For
example, in Program 5.12, a cin statement is used to allow a user to interactively input a set
of numbers. As each number is input, it’s added to a total. When the for loop is exited, the
average is calculated and displayed.
The for statement in Program 5.12 creates a loop that’s executed four times. The user
is prompted to enter a number each time through the loop. After each number is entered, it’s
added to the total immediately. Notice that total is initialized to 0 before the initializing
list of the for statement is executed. The loop in Program 5.12 is executed as long as the
value in count is less than 4 and is terminated when count becomes 4. (The increment to
4, in fact, is what causes the loop to end.) The output produced by Program 5.12 is essentially
the same as Program 5.7.
Program 5.12
#include <iostream>
using namespace std;
// This program calculates the average of MAXCOUNT user-entered numbers
int main()
{
const int MAXCOUNT = 4;
int count;
double num, total, average;
total = 0.0;
for (count = 0; count < MAXCOUNT; count++)
{
cout << "Enter a number: ";
cin >> num;
total = total + num;
}
average = total / MAXCOUNT;
cout << "The average of the data entered is "
<< average << endl;
return 0;
}
268 Repetition Statements
Technique 2: Selection in a Loop
Another common programming technique is to use a for or while loop to cycle through a set
of numbers and select numbers meeting one or more criteria. For example, assume you want to
find both the positive and negative sum of a set of numbers. The criterion is whether the number
is positive or negative, and the logic for implementing this program is given by this pseudocode:
While the loop condition is true
Enter a number
If the number is greater than zero
add the number to the positive sum
Else
add the number to the negative sum
Endif
Endwhile
Program 5.13 describes this algorithm in C++ for a fixed-count loop in which five
numbers are to be entered.
Program 5.13
#include <iostream>
using namespace std;
// This program computes the positive and negative sums of a set
// of MAXNUMS user-entered numbers
int main()
{
const int MAXNUMS = 5;
int i;
double usenum, positiveSum, negativeSum;
positiveSum = 0; // this initialization can be done in the declaration
negativeSum = 0; // this initialization can be done in the declaration
for (i = 1; i <= MAXNUMS; i++)
{
cout << "Enter a number (positive or negative) : ";
cin >> usenum;
if (usenum > 0)
positiveSum = positiveSum + usenum;
else
negativeSum = negativeSum + usenum;
}
墌
269
Chapter 5
A Closer Look: Loop Programming
Techniques
cout << "The positive total is " << positiveSum << endl;
cout << "The negative total is " << negativeSum << endl;
return 0;
}
The following is a sample run of Program 5.13:
Enter a number (positive or negative) : 10
Enter a number (positive or negative) : –10
Enter a number (positive or negative) : 5
Enter a number (positive or negative) : –7
Enter a number (positive or negative) : 11
The positive total is 26
The negative total is –17
Technique 3: Evaluating Functions of One Variable
Loops can be constructed to give you a way to determine and display the values of a single
variable mathematical function for a set of values over any specified interval. For example,
you want to know the values of the following function for x between 2 and 6:
y = 10x2
+ 3x - 2
Assuming x has been declared as an integer variable, the following for loop can be used
to calculate the required values:
for (x = 2; x <= 6; x++)
{
y = 10 * pow(x,2.0) + 3 * x – 2;
cout << setw(4) << x
<< setw(11) << y << endl;
}
In this loop, the variable x is used as both the counter variable and the unknown
(independent variable) in the function. For each value of x from 2 to 6, a new value of y is
calculated and displayed. This for loop is used in Program 5.14, which also prints headings
for the displayed values.
270 Repetition Statements
Program 5.14
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
int x, y;
cout << "x value y valuen"
<< "------- --------n"
for (x = 2; x <= 6; x++)
{
y = 10 * pow(x,2.0) + 3 * x – 2;
cout << setw(4) << x
<< setw(11) << y << endl;
}
return 0;
}
The following is displayed when Program 5.14 is executed:
x value y value
------- --------
2 44
3 97
4 170
5 263
6 376
Two items are important here. First, any equation with one unknown can be evaluated
by using a single for or an equivalent while loop. This method requires substituting your
equation in the loop in place of the equation used in Program 5.14 and adjusting the counter
values to match the solution range you want.
Second, you’re not constrained to using integer values for the counter variable. For
example, by specifying a non-integer increment, solutions for fractional values can be
obtained. This technique is shown in Program 5.15, where the equation y = 10x2
+ 3x - 2 is
evaluated in the range x = 2 to x = 6 in increments of 0.5.
271
Chapter 5
A Closer Look: Loop Programming
Techniques
Program 5.15
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
double x, y;
cout << "x value y valuen";
<< "------- ---------n"
cout << setiosflags(ios::fixed)
<< setiosflags(ios::showpoint)
<< setprecision(5);
for (x = 2.0; x <= 6.0; x = x + 0.5)
{
y = 10.0 * pow(x,2.0) + 3.0 * x - 2.0;
cout << setw(7) << x
<< setw(14) << y << endl;
}
return 0;
}
Notice that x and y have been declared as floating-point variables in Program 5.15 to
allow these variables to take on fractional values. The following is the output this program
produces:
x value y value
------- ---------
2.00000 44.00000
2.50000 68.00000
3.00000 97.00000
3.50000 131.00000
4.00000 170.00000
4.50000 214.00000
5.00000 263.00000
5.50000 317.00000
6.00000 376.00000
272 Repetition Statements
Technique 4: Interactive Loop Control
Values used to control a loop can be set by using variables rather than constant values. For
example, these four statements
i = 5;
j = 10;
k = 1;
for (count = i; count <= j; count = count + k)
produce the same effect as this single statement:
for (count = 5; count <= 10; count++)
Similarly, these statements
i = 5;
j = 10;
k = 1;
count = i;
while (count <= j)
count = count + k;
produce the same effect as the following while loop:
count = 5;
while (count <= 10)
count++;
The advantage of using variables in the initialization, condition, and altering expressions
is that it allows you to assign values for these expressions outside the for or while
statement. This method is especially useful when a cin statement is used to set the actual
values. To make this technique a little more tangible, take a look at Program 5.16.
273
Chapter 5
A Closer Look: Loop Programming
Techniques
Program 5.16
#include <iostream>
#include <iomanip>
using namespace std;
// this program displays a table of numbers with their squares and cubes,
// starting from the number 1. The final number in the table is
// input by the user.
int main()
{
int num, final;
cout << "Enter the final number for the table: ";
cin >> final;
cout << "NUMBER SQUARE CUBEn";
cout << "------ ------ ----n";
for (num = 1; num <= final; num++)
cout << setw(3) << num
<< setw(8) << num*num
<< setw(7) << num*num*num << endl;
return 0;
}
In Program 5.16, a variable is used in the for statement to control the condition (middle)
expression. A cin statement has been placed before the loop to allow the user to decide what
the final value should be. Notice that this arrangement permits the user to set the table’s
size at runtime, instead of having the programmer set the table size at compile time. This
arrangement also makes the program more general because it can be used to create a variety
of tables without the need for reprogramming and recompiling.
EXERCISES 5.5
1. (cin within a loop) Write and run a C++ program that accepts six Fahrenheit tempera-
tures, one at a time, and converts each value entered to its Celsius equivalent before the
next value is requested. Use a for loop in your program. The conversion required is
Celsius = (5.0/9.0) × (Fahrenheit - 32).
274 Repetition Statements
2. (cin within a loop) Write and run a C++ program that accepts 10 values of gallons, one
at a time, and converts each value entered to its liter equivalent before the next value is
requested. Use a for loop in your program. Use the fact that 1 gallon = 3.785 liters.
3. (Interactive Loop Control) Modify the program written for Exercise 2 to initially
request the number of data items to be entered and converted.
4. (Interactive Loop Control) Modify Program 5.13 so that the number of entries to be
input is specified by the user when the program is executed.
5. (Selection) Modify Program 5.13 so that it displays the average of the positive and nega-
tive numbers. (Hint: Be careful not to count the number 0 as a negative number.) Test
your program by entering the numbers 17, -10, 19, 0, and -4. The positive average your
program displays should be 18, and the negative average should be -7.
6. (Selection) a. Write a C++ program that selects and displays the maximum value of five
numbers to be entered when the program is executed. (Hint: Use a for loop with both a
cin and if statement inside the loop.)
b. Modify the program written for Exercise 6a so that it displays both the maximum
value and the position in the input set of numbers where the maximum occurs.
7. (Selection) Write a C++ program that selects and displays the first 20 integer numbers
that are evenly divisible by 3. (Hint: Use the modulus operator, %.)
8. (Selection) A child’s parents promised to give the child $10 on her 12th birthday and
double the gift on every subsequent birthday until the annual gift exceeded $1000. Write
a C++ program to determine how old the child will be when the last amount is given and
the total amount the child will have received.
9. (Mathematical Functions) Modify Program 5.15 to produce a table of y values for the
following:
a. y = 3x5
- 2x3
+ x for x between 5 and 10 in increments of 0.2
b. y x
x x x
= + + + +
1
2 3 24
2 3 4
for x between 1 and 3 in increments of 0.1
c. y = 2e0.8t
for t between 4 and 10 in increments of 0.2
10. (Mathematical Functions) A model of worldwide population, in billions of people, is
given by this formula
Population = 6.0e0.02t
where t is the time in years (t = 0 represents January 2000 and t = 1 represents January
2001). Using this formula, write a C++ program that displays a yearly population table for
the years January 2005 though January 2010.
11. (Mathematical Functions) The x and y coordinates, as a function of time, t, of a projec-
tile fired with an initial velocity, v, at an angle of θ with respect to the ground, are given
by these formulas:
x = v t cos(θ )
y = v t sin(θ )
275
Chapter 5
A Closer Look: Loop Programming
Techniques
Using these formulas, write a C++ program that displays a table of x and y values for a
projectile fired with an initial velocity of 500 ft/sec at an angle of 22.8 degrees. (Hint:
Remember to convert to radian measure.) The table should contain values corresponding
to the time interval 0 to 10 seconds in increments of ½ seconds.
5.6 Nested Loops
In many situations, using a loop within another loop, called a nested loop, is convenient.
Here’s a simple example of a nested loop:
for(i = 1; i <= 5; i++) // start of outer loop
{
cout << "ni is now " << i << endl;
for(j = 1; j <= 4; j++) // start of inner loop
cout << " j = " << j; // end of inner loop
} // end of outer loop
The first loop, controlled by the value of i, is called the outer loop. The second loop,
controlled by the value of j, is called the inner loop. Notice that all statements in the inner loop
are contained in the boundaries of the outer loop, and a different variable is used to control each
loop. For each trip through the outer loop, the inner loop runs through its entire sequence.
Therefore, each time the i counter increases by one, the inner for loop executes completely,
and goes through four values (j takes on the values 1 to 4), as shown in Figure 5.9. Program 5.17
includes this type of loop in a working program.
276 Repetition Statements
This is the output of a sample run of Program 5.17:
i is now 1
j = 1 j = 2 j = 3 j = 4
i is now 2
j = 1 j = 2 j = 3 j = 4
i is now 3
j = 1 j = 2 j = 3 j = 4
i is now 4
j = 1 j = 2 j = 3 j = 4
i is now 5
j = 1 j = 2 j = 3 j = 4
inner
loop
inner
loop
inner
loop
i=3
i=2
i=1
j=1
j=2
j=3
j=4
j=4
j=3
j=2 j=1
j=4
j=3
j=2
j=1
Figure 5.9 For each i, j loops
277
Chapter 5
Nested Loops
Program 5.17
#include <iostream>
using namespace std;
int main()
{
const int MAXI = 5;
const int MAXJ = 4;
int i, j;
for(i = 1; i <= MAXI; i++) // start of outer loop <----+
{ // |
cout << "ni is now " << i << endl; // |
// |
for(j = 1; j <= MAXJ; j++) // start of inner loop |
cout << " j = " << j; // end of inner loop |
} // end of outer loop <-----+
cout << endl;
return 0;
}
To understand the usefulness of a nested loop, take a look at using one to compute the
average grade for each student in a class of 20 students. Each student has taken four exams
during the semester. The final grade is calculated as the average of these exam grades. The
pseudocode describing how to compute this average is as follows:
for 20 times
set the student grade total to zero
for 4 times
input a grade
add the grade to the total
endfor // end of inner for loop
calculate student’s average grade
print the student’s average grade
endfor // end of outer for loop
As described by the pseudocode, an outer loop consisting of 20 passes is used to compute
the average grade for each student. The inner loop consists of four passes, and one
examination grade is entered in each inner loop pass. As each grade is entered, it’s added to
the total for the student, and at the end of the loop, the average is calculated and displayed.
Because both the outer and inner loops are fixed-count loops of 20 and 4, respectively, for
statements are used to create these loops. Program 5.18 shows the C++ code corresponding
to the pseudocode.
278 Repetition Statements
Program 5.18
#include <iostream>
using namespace std;
int main()
{
const int NUMGRADES = 4;
const int NUMSTUDENTS = 20;
int i, j;
double grade, total, average;
for (i = 1; i <= NUMSTUDENTS; i++) // start of outer loop
{
total = 0; // clear the total for this student
for (j = 1; j <= NUMGRADES; j++) // start of inner loop
{
cout << "Enter an examination grade for this student: ";
cin >> grade;
total = total + grade; // add the grade to the total
} // end of the inner for loop
average = total / NUMGRADES; // calculate the average
cout << "nThe average for student " << i
<< " is " << average << "nn";
} // end of the outer for loop
return 0;
}
In reviewing Program 5.18, pay particular attention to the initialization of total in the
outer loop, before the inner loop is entered: total is initialized 20 times, once for each
student. Also, notice that the average is calculated and displayed immediately after the inner
loop is finished. Because the statements that compute and display the average are also in the
outer loop, 20 averages are calculated and displayed. The entry and addition of each grade
in the inner loop uses techniques you have seen before and should be familiar with now.
EXERCISES 5.6
1. (Misc. Application) Four experiments are performed, and each experiment has six test
results. The results for each experiment are given in the following list. Write a program
using a nested loop to compute and display the average of the test results for each
experiment.
279
Chapter 5
Nested Loops
1st experiment results: 23.2 31 16.9 27 25.4 28.6
2nd experiment results: 34.8 45.2 27.9 36.8 33.4 39.4
3rd experiment results: 19.4 16.8 10.2 20.8 18.9 13.4
4th experiment results: 36.9 39 49.2 45.1 42.7 50.6
2. (Modify) a. Modify the program written for Exercise 1 so that the number of test results
for each experiment is entered by the user. Write your program so that a different num-
ber of test results can be entered for each experiment.
b. Rewrite the program written for Exercise 2a to eliminate the inner loop.
3. (Electrical Eng.) a. An electrical manufacturer tests five generators by measuring their
output voltages at three different times. Write a C++ program that uses a nested loop to
enter each generator’s test results, and then computes and displays the average voltage for
each generator. Assume the following generator test results:
1st generator: 122.5 122.7 123.0
2nd generator: 120.2 127.0 125.1
3rd generator: 121.7 124.9 126.0
4th generator: 122.9 123.8 126.7
5th generator: 121.5 124.7 122.6
b. Modify the program written for Exercise 3a to calculate and display the average volt-
age for all the generators. (Hint: Use a second variable to store the total of all the gen-
erator’s voltages.)
4. (Modify) Rewrite the program written for Exercise 3a to eliminate the inner loop. To do
this, you have to input three voltages for each generator instead of entering one at a time.
Each voltage must be stored in its own variable before the average is calculated.
5. (Mathematical Functions) Write a program that calculates and displays values for
y when
y = xz / (x - z)
Your program should calculate y for values of x ranging between 1 and 5 and values of z
ranging between 2 and 6. The x variable should control the outer loop and be incre-
mented in steps of 1, and z should be incremented in steps of 1. Your program should
also display the message Function Undefined when the x and z values are equal.
6. (Numerical Analysis) Assembly languages for some microprocessors don’t have a multi-
ply operation. Although there are sophisticated algorithms for performing multiplication in
these languages, a simple method multiplies by repeated addition. In this case, the algo-
rithm’s efficiency can be increased by using nested loops. For example, to multiply a
number by 12, first add the number three times, and then add the result four times. This
calculation requires only 7 additions as opposed to 12. Using this information, write a C++
program that multiplies 33, 47, and 83 by 1001, using three loops, and then displays the
result. (Hint: 1001 = 7 × 11 × 13.)
280 Repetition Statements
5.7 do while Loops
Both while and for statements evaluate an expression at the start of the repetition loop, so
they are always used to create pretest loops. Posttest loops, also referred to as exit-controlled
loops, can also be constructed in C++. Figure 5.10 shows the basic structure of a posttest loop,
which is referred to as a do while loop. Notice that a do while loop continues iterations
through the loop while the condition is true and exits the loop when the condition is false.
In C++, a posttest do while loop is created by using a do statement. As its name
implies, this statement allows you to perform some statements before an expression is
evaluated at the end of the loop. It has this general form in C++:
do
statement;
while (expression); don’t forget the final semicolon, which is required here
As with all C++ programs, the single statement in the do can be replaced with a
compound statement. Figure 5.11 shows a flow-control diagram illustrating the operation of
the do statement.
As shown, all statements within the do statement are executed at least once before the
expression is evaluated. Then, if the expression has a non-zero value, the statements are
previous
statement
is the
condition
true?
loop
statements
no
yes
next
statement
Figure 5.10 The do while loop structure
281
Chapter 5
do while Loops
executed again. This process continues until the expression evaluates to zero (becomes false).
For example, take a look at the following do statement:
do
{
cout << "nEnter a price: ";
cin >> price;
if (abs(price – SENTINEL) < 0.0001)
break;
salestax = RATE * price;
cout << setiosflags(ios::showpoint)
<< setprecision(2)
<< "The sales tax is $ " << salestax;
}
while (price != SENTINEL);
Observe that the prompt and cin statement are included in the loop because the tested
expression is evaluated at the end of the loop.
evaluate
the
expression
loop
(false condition)
expression’s value
is non-zero
(true condition)
execute the
statement
after the
word do
enter the
do statement
expression’s value
is zero
exit the
do statement
go back and
execute the statement
Figure 5.11 The do statement’s flow of control
282 Repetition Statements
As with all repetition statements, the do statement can always replace or be replaced by
an equivalent while or for statement. The choice of which statement to use depends on
the application and the programmer’s preferred style. In general, while and for statements
are preferred because anyone reading the program can clearly see what’s being tested up
front, at the top of the program loop.
Validity Checks
The do statement is particularly useful in filtering user-entered input and providing data
validation checks. For example, an operator is required to enter a valid customer identifica-
tion number between 1000 and 1999. A number outside this range is to be rejected, and a
new request for a valid number is made. The following section of code provides the necessary
data filter to verify the entry of a valid identification number:
do
{
cout << "nEnter an identification number: ";
cin >> id_num;
}
while (id_num < 1000 || id_num > 1999);
In this code, a request for an identification number is repeated until a valid number is
entered. This section of code is “bare bones,” in that it doesn’t alert the operator to the cause
of the new request for data or allow premature exit from the loop if a valid identification
number can’t be found. The following code is an alternative for removing the first drawback:
do
{
cout << "nEnter an identification number: ";
cin >> id_num;
if (id_num < 1000 || id_num > 1999)
{
cout << "An invalid number was just enteredn";
cout << "Please check the ID number and reentern";
}
else
break; // break if a valid id_num was entered
} while(1); // this expression is always true
A break statement is used to exit from the loop. Because the expression the do
statement is evaluating is always 1 (true), an infinite loop has been created that’s exited only
when the break statement is encountered.
EXERCISES 5.7
1. (Practice) a. Using a do statement, write a program to accept a grade. The program
should request a grade continuously as long as an invalid grade is entered. An invalid
283
Chapter 5
do while Loops
grade is any grade less than 0 or greater than 100. After a valid grade has been entered,
your program should display the value of the grade entered.
b. Modify the program written for Exercise 1a so that the user is alerted when an invalid
grade has been entered.
c. Modify the program written for Exercise 1b so that it allows the user to exit the pro-
gram by entering the number 999.
d. Modify the program written for Exercise 1b so that it automatically terminates after
five invalid grades are entered.
2. (Misc. Application) a. Write a program that continuously requests a grade to be entered.
If the grade is less than 0 or greater than 100, your program should print an appropriate
message informing the user that an invalid grade has been entered; else, the grade should
be added to a total. When a grade of 999 is entered, the program should exit the repeti-
tion loop and compute and display the average of the valid grades entered.
b. Run the program written in Exercise 2a on a computer and verify the program by
using appropriate test data.
3. (Misc. Application) a. Write a program to reverse the digits of a positive integer
number. For example, if the number 8735 is entered, the number displayed should be
5378. (Hint: Use a do statement and continuously strip off and display the number’s units
digit. If the variable num initially contains the number entered, the units digit is obtained
as (num % 10). After a units digit is displayed, dividing the number by 10 sets up the
number for the next iteration. Therefore, (8735 % 10) is 5 and (8735 / 10) is 873.
The do statement should continue as long as the remaining number is not zero.
b. Run the program written in Exercise 3a on a computer and verify the program by
using appropriate test data.
4. (Practice) Repeat any of the exercises in Section 5.3, using a do statement rather than a
for statement.
5. (Numerical Analysis) Given a number, n, and an approximation for its square root, a
closer approximation of the actual square root can be obtained by using this formula:
new approximation
n previous approximation
=
+
( / ) p
previous approximation
2
Using this information, write a C++ program that prompts the user for a number and an
initial guess at its square root. Using this input data, your program should calculate an
approximation of the square root that’s accurate to 0.00001. (Hint: Stop the loop when the
difference between the two approximations is less than 0.00001.)
6. (Numerical Analysis) Here’s a challenging problem for those who know a little calculus.
The Newton-Raphson method can be used to find the roots of any equation y(x) = 0. In
this method, the (i + 1)st approximation, xi+1, to a root of y(x) = 0 is given in terms of the
ith approximation, xi, by the following formula, where y' denotes the derivative of y(x)
with respect to x:
xi+1 = xi - y(xi) / y'(xi)
284 Repetition Statements
For example, if y(x) = 3x2
+ 2x - 2, then y'(x) = 6x + 2, and the roots are found by making
a reasonable guess for a first approximation x1 and iterating by using this equation:
xi+1 = xi - (3xi
2
+ 2xi - 2) / (6xi + 2)
a. Using the Newton-Raphson method, find the two roots of the equation 3x2
+ 2x - 2 = 0.
(Hint: There’s one positive root and one negative root.)
b. Extend the program written for Exercise 6a so that it finds the roots of any function
y(x) = 0, when the function for y(x) and the derivative of y(x) are placed in the code.
5.8 Common Programming Errors
When using repetition statements, beginning C++ programmers are prone to making the
following seven errors:
1. The most troublesome error for new programmers is the “off by one” error, in which
the loop executes one too many or one too few times than was intended. For
example, the loop created by the statement for(i = 1; i < 11; i++) executes
10 times, not 11, even though the number 11 is used in the statement. An equivalent
loop can be constructed by using the statement for(i = 1; i <= 10; i ++).
However, if the loop is started with an initial value of i = 0, using the statement
for(i = 0; i < 11; i++), the loop is traversed 11 times, as is a loop con-
structed with the statement for(i = 0; i <= 10; i++). In constructing loops,
you must pay particular attention to both the initial and final conditions used to
control the loop to make sure the number of loop traversals isn’t off by one too
many or one too few executions.
The next two errors pertain to the tested expression, and you have already encountered
them with the if and switch statements:
2. Inadvertently using the assignment operator, =, in place of the equality operator, ==,
in the tested expression—for example, typing the assignment expression a = 5
instead of the correct relational expression a==5. Because the tested expression can
be any valid C++ expression, including arithmetic and assignment expressions, the
compiler doesn’t detect this error.
3. Using the equality operator, ==, when testing floating-point or double-precision
operands. For example, the expression fnum == 0.01 should be replaced by a test
requiring that the absolute value of fnum – 0.01 be less than an acceptable
amount. The reason is that all numbers are stored in binary form. Using a finite
number of bits, decimal numbers such as 0.01 have no exact binary equivalent, so
tests requiring equality with these numbers can fail. (See Section 4.1 for a more
complete description of this numerical accuracy problem.)
The next three errors are particular to the for statement:
4. Placing a semicolon at the end of for’s parentheses, which frequently produces a
do-nothing loop. For example, take a look at these statements:
for(count = 0; count < 10; count++);
total = total + num;
285
Chapter 5
Common Programming Errors
The semicolon at the end of the first line of code is a null statement. It has the
effect of creating a loop that’s executed 10 times with nothing done except incre-
menting and testing count. This error tends to occur because C++ programmers
are used to ending most lines with a semicolon.
5. Using commas are used to separate items in a for statement instead of the required
semicolons, as in this example:
for (count = 1, count < 10, count++)
Commas must be used to separate items in the initializing and altering lists, but
semicolons must be used to separate these lists from the tested expression.
6. Changing the value of the control variable used in the tested condition both inside the
body of a for loop and in its altering list. For example, take a look at this for loop:
for(int i=0; i<10; i++)
cout << i++;
In this code, the value of the variable being tested (in this case, i) is changed in
two places, which is a serious logic error.
7. The final common programming error is omitting the final semicolon from the do
statement. This error is usually made by programmers who have learned to omit the
semicolon after the parentheses of a while statement and carry over this habit when
encountering the reserved word while at the end of a do statement.
5.9 Chapter Summary
1. A section of repeating code is referred to as a loop. A loop is controlled by a repetition
statement that tests a condition to determine whether the code will be executed. Each
pass through the loop is referred to as a repetition or an iteration. The tested condition
must always be set explicitly before its first evaluation by the repetition statement.
Within the loop, there must always be a statement that permits altering the condition so
that the loop, after it’s entered, can be exited.
2. There are three basic type of loops: while, for, and do while. The while and for
loops are pretest or entrance-controlled loops. In this type of loop, the tested condition
is evaluated at the beginning of the loop, which requires setting the tested condition
explicitly before loop entry. If the condition is true, loop repetitions begin; otherwise, the
loop is not entered. Iterations continue as long as the condition remains true. In C++,
while and for loops are constructed by using while and for statements.
The do while loop is a posttest or exit-controlled loop, in which the tested condition
is evaluated at the end of the loop. This type of loop is always executed at least once.
As long as the tested condition remains true, do while loops continue to execute.
3. Loops are also classified according to the type of tested condition. In a fixed-count loop,
the condition is used to keep track of how many repetitions have occurred. In a
variable-condition loop, the tested condition is based on a variable that can change
interactively with each pass through the loop.
286 Repetition Statements
4. In C++, a while loop is constructed by using a while statement. This is the most
commonly used form of this statement:
while (expression)
{
statements;
}
The expression in parentheses is the condition that’s tested to determine whether the
statement following the parentheses, which is generally a compound statement, is
executed. The expression is evaluated in exactly the same manner as one in an if-else
statement; the difference is how the expression is used. In a while statement, the
statement following the expression is executed repeatedly as long as the expression
retains a non-zero value, instead of just once, as in an if-else statement. An example
of a while loop follows:
count = 1; // initialize count
while (count <= 10)
{
cout << count << " ";
count++; // increment count
}
The first assignment statement sets count equal to 1. The while statement is then
entered, and the expression is evaluated for the first time. Because the value of count
is less than or equal to 10, the expression is true, and the compound statement is
executed. The first statement in the compound statement uses the cout statement to
display the value of count.
The next statement adds 1 to the value currently stored in count, making this value
equal to 2. The while statement then loops back to retest the expression. Because
count is still less than or equal to 10, the compound statement is executed again. This
process continues until the value of count reaches 11.
Because the while statement always checks its expression at the top of the loop, any
variables in the tested expression must have values assigned before the while is
encountered. In addition, the while loop must contain a statement that alters the tested
expression’s value.
5. In C++, a for loop is constructed by using a for statement. This statement performs
the same functions as the while statement but uses a different form. In many situations,
especially those using a fixed-count condition, the for statement format is easier to use
than its while statement equivalent. This is the most commonly used form of the for
statement:
for (initializing list; expression; altering list)
{
statements;
}
287
Chapter 5
Chapter Summary
Inside the parentheses of the for statement are three items, separated by semicolons.
Each of these items is optional, but the semicolons must be present.
The initializing list is used to set any initial values before the loop is entered;
generally, it’s used to initialize a counter. Statements in the initializing list are executed
only once. The expression in the for statement is the condition being tested: It’s
tested at the start of the loop and before each iteration. The altering list contains
loop statements that aren’t within the compound statement; generally, it’s used to
increment or decrement a counter each time the loop is executed. Multiple statements
in both an initializing and altering list are separated by commas. Here’s an example of a
for loop:
for (total = 0, count = 1; count < 10; count++)
{
cout << "Enter a grade: ";
total = total + grade;
}
In this for statement, the initializing list is used to initialize both total and count.
The expression determines that the loop executes as long as the value in count is less
than 10, and the altering list specifies that the value of count is incremented by one
each time through the loop.
6. The for statement is extremely useful in creating fixed-count loops because you can
include initializing statements, the tested expression, and statements affecting the tested
expression in parentheses at the top of a for loop for easy inspection and modification.
7. The do statement is used to create posttest loops because it checks its expression at the
end of the loop. Checking at the end of the loop ensures that the body of a do loop is
executed at least once. A do loop must contain at least one statement that alters the
tested expression’s value.
Programming Projects for Chapter 5
1. (Probability) The probability that a telephone call will last less than t minutes can be
approximated by the exponential probability function:
Probability that a call lasts less than t minutes = 1 - e-t/a
a is the average call length.
e is Euler’s number (2.71828).
For example, assuming the average call length is 2 minutes, the probability that a call will
last less than 1 minute is calculated as 1 - e-1/2
= 0.3297. Using this probability equation,
write a C++ program that calculates and displays a list of probabilities of a call lasting less
than 1 minute to less than 10 minutes, in 1-minute increments.
2. (Probability) a. The arrival rate of customers in a busy New York bank can be
estimated by using the Poisson probability function:
P x
e
x
x
( )
!
=
λ λ
-
288 Repetition Statements
x is the number of customer arrivals per minute.
l is the average number of arrivals per minute.
e is Euler’s number (2.71828).
For example, if the average number of customers entering the bank is three customers
per minute, then l is equal to three. Therefore, the probability of one customer arriving
in any one minute is
P x
e
( )
!
.
= = =
1
3
1
0 149561
1 3
-
and the probability of two customers arriving in any one minute is the following:
P x
e
( )
!
.
= = =
2
3
2
0 224454
2 3
-
Using the Poisson probability function, write a C++ program that calculates and displays
the probability of 1 to 10 customer arrivals in any one minute when the average arrival
rate is 3 customers per minute.
b. The formula given in Exercise 2a is also applicable for estimating the arrival rate of
planes at a busy airport. (In this situation, an arriving “customer” is an incoming
plane.) Using this same formula, modify the program written in Exercise 2a to accept
the average arrival rate as an input data item. Then run the modified program to
determine the probability of 0 to 10 planes attempting to land at an airport in any
one-minute period during peak arrival times. Assume that the average arrival rate for
peak arrival times is two planes per minute.
3. (Physics) A golf ball is dropped from an airplane. The distance, d, the ball falls in t seconds
is given by the formula d = ½ gt2
, where g is the acceleration caused by gravity and is equal
to 32 ft/sec2
. Using this information, write and run a C++ program that displays the distance
fallen in each one-second interval for 10 seconds and the total distance the golf ball falls at
the end of each interval. The output should complete the following chart:
Time (sec) Distance in the Current Time
Interval (ft)
Total Distance (ft)
0 0.0
1 16.0
. . .
10
4. (Physics) Assume the airplane in Exercise 3 is flying at a height of 50,000 feet. Modify the
program written for Exercise 3 to determine how long it will take the ball to reach the
ground. To increase the accuracy of your result without an undue number of calculations,
decrease the time interval from 1 second to 0.1 second as the ball nears the ground.
5. (Numerical Analysis) The Fibonacci sequence is 0, 1, 1, 2, 3, 5, 8, 13, . . . ; the first two
terms are 0 and 1, and each term thereafter is the sum of the two preceding terms—that is,
Fib[n] = Fib[n - 1] + Fib[n - 2]. Using this information, write a C++ program that calculates
the nth number in a Fibonacci sequence, where the user enters n into the program
interactively. For example, if n = 6, the program should display the value 5.
289
Chapter 5
Programming Projects
6. (Numerical Analysis) Develop, test, and execute a C++ program that uses a while
loop to determine the smallest integer power of 3 that exceeds 30,000. That is, find the
smallest value of n so that 3n
> 30,000. (Hint: Initialize PowerOfThree = 1, and then
accumulate the expression PowerOfThree = 3 * PowerOfThree.)
7. (Numerical Analysis) A prime integer number is one that has exactly two different
divisors, namely 1 and the number itself. Write, run, and test a C++ program that finds
and prints all the prime numbers less than 100. (Hint: 1 is a prime number. For each
number from 2 to 100, find Remainder = Number % n, where n ranges from 2 to
sqrt(number). If n is greater than sqrt(number), the number is not equally
divisible by n. Why? If any Remainder equals 0, the number is not a prime number.)
8. (Numerical Analysis) The quotient in long division is the number of times the divisor
can be subtracted from the dividend. The remainder is what’s left over after the last
subtraction. Write a C++ program that performs division by using this method.
9. (Conversion) Print the decimal, octal, and hexadecimal values of all characters between
the start and stop characters entered by a user. For example, if the user enters an 'a'
and a 'z', the program should print all the characters between a and z and their
respective values. Make sure the second character the user enters occurs later in the
alphabet than the first character. If it doesn’t, write a loop that asks the user repeatedly
for a valid second character.
10. (Misc. Application) a. An old Arabian legend has it that a fabulously wealthy but
unthinking king agreed to give a beggar one cent and double the amount for 64 days. Using
this information, write, run, and test a C++ program that displays how much the king must
pay the beggar on each day. The output of your program should appear as follows:
Day Amount Owed
--- -----------
1 0.01
2 0.02
3 0.04
. .
. .
. .
64 .
b. Modify the program you wrote for Exercise 10a to determine on which day the king
will have paid the beggar a total of one million dollars.
11. (Misc. Application) According to legend, the island of Manhattan was purchased from
the native Indian population in 1626 for $24. Assuming this money was invested in a
Dutch bank paying 5% simple interest per year, construct a table showing how much
money the native population would have at the end of each 50-year period, starting in
1626 and ending 400 years later.
290 Repetition Statements
Engineering and Scientific Disciplines
Industrial Engineering
Each of the traditional engineering disciplines (civil, mechanical, electrical, chemical, and
metallurgical/mining) relies on a particular area of natural science for its foundation. Indus-
trial engineering, however, incorporates knowledge of the social sciences into designing
improvements in human-machine systems. Industrial engineers are responsible for design-
ing, installing, and evaluating machines and systems and for monitoring their interface with
people to improve overall productivity. This job can also involve understanding human
behavioral characteristics and their effects on the design of machines or the workplace.
Industrial engineers draw heavily on knowledge in economics, business management, and
finance as well as in the natural sciences. The areas of specialization for industrial engineers
can be divided into four categories:
앫 Operations research: This area involves applying analytical techniques and math-
ematical models to phenomena such as inventory control, simulation, decision
theory, and queuing theory to optimize the total systems necessary for the
production of goods.
앫 Management or administrative engineering: The increasingly complex interplay of
management and production skills in modern industrial operations has resulted in a
need for technically trained managers. These managers evaluate and plan corporate
ventures and interact with labor, engineering departments, and subcontractors. A
management engineer can also participate in a company’s financial operations,
drawing on knowledge in economics, business management, and law.
앫 Manufacturing and production engineering: Before a product is produced, the
complete manufacturing process must be designed and set up to optimize the
economics involved and the product’s final quality. This task requires a broad
knowledge of process design, plant layouts, tool design, robotics, and human-
machine interactions.
앫 Information systems: This area involves using computers to gather and analyze data
for decision making and planning and to improve human-machine interaction.
The following list includes the most common responsibilities of industrial engineers
who responded to a recent survey by the American Institute of Industrial Engineers:
Facilities planning and design Cost control
Methods engineering Inventory control
Work systems design Energy conservation
Production engineering Computerized process control
Management information and Product packaging, handling, and testing
control systems Tool and equipment selection
Organization analysis and design Production control
Work measurement Product improvement study
Wage administration Preventive maintenance
Quality control Safety programs
Project management Training programs
291
Chapter 5
Programming Projects
This page intentionally left blank
Chapter
6
Modularity Using
Functions
6.1 Function and Parameter
Declarations
6.2 Returning a Single Value
6.3 Returning Multiple Values
6.4 A Case Study: Rectangular to
Polar Coordinate Conversion
6.5 Variable Scope
6.6 Variable Storage Categories
6.7 Common Programming Errors
6.8 Chapter Summary
Professional programs are designed, coded, and tested much like hardware: as a set of modules
integrated to perform a completed whole. A good analogy is an automobile; one major module is the
engine, another is the transmission, a third the braking system, a fourth the body, and so on. All these
modules are linked together and placed under the driver’s control, which can be compared to a
supervisor or main program module. The whole now operates as a complete unit, able to do useful
work, such as driving to the store. During the assembly process, each module is constructed, tested, and
found to be free of defects (bugs) before it’s installed in the final product.
Now think of what you might do if you wanted to improve your car’s performance. You might alter
the existing engine or remove it and replace it with a new engine, or you might replace the transmission.
You can make each modification separately as your time and budget allow. The majority of the other
modules can stay the same, but the car operates differently after your changes are made.
In this analogy, each major car component can be compared to a function. For example, the driver
calls on the engine when the gas pedal is pressed. The engine accepts inputs of fuel, air, and electricity
to turn the driver’s request into a useful product—power—and then sends this output to the
transmission for further processing. The transmission receives the engine’s output and converts it to a
form the drive axle can use.
The engine, transmission, and other modules “know” only the universe bounded by their inputs and
outputs. The driver doesn’t need to know the internal operation of the modules being controlled. All
that’s required is understanding what each unit does and how to use it. The driver simply “calls” on
a module, such as the brakes, when that module’s output is required. Communication between modules
is restricted to passing inputs to each module as it’s called on to perform its task, and each module
operates in a fairly independent manner. Programmers use this same modular approach to create and
maintain reliable C++ programs by using functions.
As you have seen, each C++ program must contain a main() function. In addition to this
required function, C++ programs can also contain any number of other functions. In this chapter, you
learn how to write these functions, pass data to them, process the passed data, and return a result.
6.1 Function and Parameter Declarations
In creating C++ functions, you must be concerned with the function itself and how it
interacts with other functions, such as main(). Interaction with a function includes passing
data to a function correctly when it’s called and returning values from a function when it
ceases operation. This section describes the first part of the interface, passing data to a
function and having the function receive, store, and process the transmitted data correctly.
As you have already seen with mathematical functions, a function is called, or used, by giving
the function’s name and passing any data to it, as arguments, in the parentheses following the
function name (see Figure 6.1). The called function must be able to accept the data passed to
it by the function doing the calling. Only after the called function receives the data successfully
can the data be manipulated to produce a useful result.
To clarify the process of sending and receiving data, take a look at Program 6.1, which
calls a function named findMax(). The program, as shown, is not yet complete. After the
function findMax() is written and included in Program 6.1, the completed program,
consisting of the functions main() and findMax(), can be compiled and executed.
function-name (data passed to function);
This identifies the
called function
This passes data
to the function
Figure 6.1 Calling and passing data to a function
294 Modularity Using Functions
Program 6.1
#include <iostream>
using namespace std;
void findMax(int, int); // the function declaration (prototype)
int main()
{
int firstnum, secnum;
cout << "nEnter a number: ";
cin >> firstnum;
cout << "Great! Please enter a second number: ";
cin >> secnum;
findMax(firstnum, secnum); // the function is called here
return 0;
}
First, examine the declaration and calling of the findMax() function from main().
You then see how to write findMax() to accept data passed to it and determine the largest
or maximum value of the two passed values.
The function findMax() is referred to as the called function because it’s called or
summoned into action by its reference in main(). The function that does the calling, in this
case main(), is referred to as the calling function. The terms “called” and “calling” come
from standard telephone usage, in which one party calls the other. The person initiating the
call is referred to as the calling party, and the person receiving the call is referred to as the
called party. The same terms describe function calls. The called function, in this case
findMax(), is declared as a function that expects to receive two integer numbers and to
return no value (a void) to main(). This declaration is formally referred to as a function
prototype. The function is then called by the last statement in the program.
Function Prototypes
Before a function can be called, it must be declared to the function that will do the calling.
The declaration statement for a function is referred to as a function prototype. The function
prototype tells the calling function the type of value that will be formally returned, if any, and
the data type and order of the values the calling function should transmit to the called
function. For example, the function prototype previously used in Program 6.1
void findMax(int, int);
295
Chapter 6
Function and Parameter Declarations
declares that the function findMax() expects two integer values to be sent to it and that
this function formally returns no value (void).
Function prototypes can be placed with the variable declaration statements of the calling
function, above the calling function name (as in Program 6.1), or in a separate header file
specified with an #include preprocessor statement. The function prototype for findMax()
could have been placed before or after the statement #include <iostream>, before
main(), or within main(). (The reasons for the choice of placement are explained in
Section 6.3.) The general form of function prototype statements is as follows:
returnDataType functionName(list of argument data types);
The DataType refers to the type of value the function returns. Here are some examples of
function prototypes:
int fmax(int, int);
double swap(int, char, char, double);
void display(double, double);
The function prototype for fmax() declares that this function expects to receive two
integer arguments and returns an integer value. The function prototype for swap() declares
that this function requires four arguments—consisting of an integer, two characters, and a
double-precision argument, in that order—and returns a double-precision number. Finally,
the function prototype for display() declares that this function requires two double-
precision arguments and doesn’t return any value. This function might be used to display the
results of a computation without returning any value to the called function.
The use of function prototypes permits the compiler to error-check data types. If the
function prototype doesn’t agree with data types defined when the function is written, a compiler
warning occurs. The prototype also serves another task: It ensures that all arguments passed to
the function are converted to the declared data type when the function is called.
Calling a Function
Calling a function is rather easy. The only requirements are using the name of the function and
enclosing any data passed to the function in the parentheses following the function name, using
the same order and type declared in the function prototype. The items enclosed in parentheses
are called arguments of the called function (see Figure 6.2).
If a variable is one of the arguments in a function call, the called function receives a copy
of the value stored in the variable. For example, the statement findMax(firstnum,
secnum); calls the findMax() function and causes the values stored in the variables
firstnum and secnum to be passed to findMax(). The variable names in parentheses are
arguments that provide values to the called function. After values are passed, control is
transferred to the called function.
findMax (firstnum, secnum);
This identifies
the findMax()
function
This causes two
values to be passed
to findMax()
Figure 6.2 Calling and passing two values to findMax()
296 Modularity Using Functions
As illustrated in Figure 6.3, the findMax() function does not receive the variables
named firstnum and secnum and has no knowledge of these variable names.1 The
function simply receives the values in these variables and must then determine where to
store these values before it does anything else. Although this procedure for passing data to
a function might seem surprising, it’s actually a safety procedure for ensuring that a called
function doesn’t inadvertently change data stored in a variable. The function gets a copy of
the data to use. It can change its copy and, of course, change any variables declared within
it. However, unless specific steps to do so are taken, a function isn’t allowed to change the
contents of variables declared in other functions.
Next, you begin writing the findMax() function to process the values passed to it.
Defining a Function
A function is defined when it’s written. Each function is defined once (that is, written once) in
a program and can then be used by any other function in the program that declares it suitably.
Like the main() function, every C++ function consists of two parts, a function header
and a function body, as illustrated in Figure 6.4. The function header’s purpose is to identify
the data type of the value the function returns, provide the function with a name, and specify
the number, order, and type of arguments the function expects. The function body’s purpose
is to operate on the passed data and return, at most, one value directly back to the calling
function. (In Section 6.3, you see how a function can be made to return multiple values
indirectly.)
1
In Section 6.3, you see how C++ also permits direct access to the calling function’s variables with reference variables.
findMax (firstnum, secnum);
Get
the
value
stored in secnum
a value
Get
the
value
stored in firstnum
a value
Send the
value to
findMax()
Send the
value to
findMax()
the variable
secnum
the variable
firstnum
Figure 6.3 The findMax() function receives actual values
297
Chapter 6
Function and Parameter Declarations
The function header is always the first line of a function and contains the function’s
returned value type, its name, and the names and data types of its parameters. Because
findMax() doesn’t formally return any value and receives two integer values, the following
function header can be used:
void findMax(int x, int y) no semicolon
The names in parentheses in the header are called the formal parameters of the function
(or parameters, for short).2 Therefore, the parameter x is used to store the first value passed
to findMax(), and the parameter y is used to store the second value passed at the time of
the function call. The function doesn’t know where the values come from when the call is
made from main(). The first part of the call procedure the computer executes involves
going to the variables firstnum and secnum and retrieving the stored values. These values
are then passed to findMax() and stored in the parameters x and y (see Figure 6.5).
2
The portion of the function header containing function names and parameters is formally referred to as a “function declarator.” The items
enclosed in parentheses, the parameters, are specifications for the arguments. The arguments are the values provided when the function is called.
function header line
{
}
Function header
Function body
constant and
any other C++ statements;
variable declarations;
Figure 6.4 The general format of a function
findMax(int x, int y)
findMax(firstnum,secnum); This statement
calls findMax()
The value
in secnum
is passed
The value
in firstnum
is passed
The
parameter
named x
The
parameter
named y
Figure 6.5 Storing values in parameters
298 Modularity Using Functions
The function name and all parameter names in the header—in this case, findMax, x,
and y—are chosen by the programmer. Any names selected according to the rules for
choosing variable names can be used. All parameters listed in the function header must be
separated by commas and have their data types declared separately.
Now that the function header for findMax() has been written, you can construct its body.
The function has been written to select and display the larger of the two numbers passed to it.
A function body begins with an opening brace, {, contains any necessary declarations and
other C++ statements, and ends with a closing brace, }. This structure should be familiar
because it’s the same one used in all the main() functions you’ve seen so far. This required
structure shouldn’t be a surprise because main() is a function and must adhere to the rules
for constructing all legitimate functions, as shown here:
{
symbolic constant declarations,
variable declarations, and
other C++ statements
}
Point of Information
Function Definitions and Function Prototypes
When you write a function, you’re formally creating a function definition. Each defini-
tion begins with a function header that includes a parameter list, if any, enclosed in
parentheses and ends with the closing brace that terminates the function’s body. The
parentheses are required whether or not the function uses any parameters. The follow-
ing is a commonly used syntax for a function definition:
returnDataType functionName(parameter list)
{
constant declarations
variable declarations
other C++ statements
return value
}
A function prototype declares a function. The syntax for a function prototype,
which provides the function’s return data type, the function’s name, and the function’s
parameter list, is as follows:
returnDataType functionName(list of parameter data types);
The prototype, along with pre- and postcondition comments (see the next Point of
Information box), should give users all the programming information needed to call the
function successfully.
Generally, all function prototypes are placed at the top of the program, and all
definitions are placed after the main() function. However, this placement can be
changed. The only requirement in C++ is that a function can’t be called before it has
been declared or defined.
299
Chapter 6
Function and Parameter Declarations
In the body of the findMax() function, one variable is declared to store the maximum of
the two numbers passed to it. An if-else statement is then used to find the maximum of the
two numbers. Finally, a cout statement is used to display the maximum. The following shows
the complete function definition for findMax():
void findMax(int x, int y)
{ // start of function body
int maxnum; // variable declaration
if (x >= y) // find the maximum number
maxnum = x;
else
maxnum = y;
cout << "nThe maximum of the two numbers is "
<< maxnum << endl;
return;
} // end of function body and end of function
Notice that the parameter declarations are made in the function header, and the variable
declaration is made immediately after the function body’s opening brace. This placement is
in keeping with the concept that parameter values are passed to a function from outside the
function, and variables are declared and assigned values from within the function body.
Program 6.2 includes the findMax() function in the program code previously listed in
Program 6.1.
Point of Information
Preconditions and Postconditions
Preconditions are any set of conditions a function requires to be true if it’s to operate
correctly. For example, if a function uses the symbolic constant MAXCHARS, which must
have a positive value, a precondition is that MAXCHARS must be declared with a posi-
tive value before the function is called. Similarly, a postcondition is a condition that
will be true after the function is executed, assuming the preconditions are met.
Pre- and postconditions are typically documented as user comments. For example,
examine the following declaration and comments:
bool leapyr(int)
// Precondition: the integers must represent a year in a four-digit
// form, such as 2009
// Postcondition: a value of true is returned if the year is a leap year;
// otherwise, false is returned
Pre- and postcondition comments should be included with function prototypes and
function definitions whenever clarification is needed.
300 Modularity Using Functions
Program 6.2
#include <iostream>
using namespace std;
void findMax(int, int); // the function prototype
int main()
{
int firstnum, secnum;
cout << "nEnter a number: ";
cin >> firstnum;
cout << "Great! Please enter a second number: ";
cin >> secnum;
findMax(firstnum, secnum); // the function is called here
return 0;
}
// following is the function FindMax()
void findMax(int x, int y)
{ // start of function body
int maxnum; // variable declaration
if (x >= y) // find the maximum number
maxnum = x;
else
maxnum = y;
cout << "nThe maximum of the two numbers is "
<< maxnum << endl;
return;
} // end of function body and end of function
Program 6.2 can be used to select and print the maximum of any two integer numbers
the user enters. A sample run of Program 6.2 follows:
Enter a number: 25
Great! Please enter a second number: 5
The maximum of the two numbers is 25
301
Chapter 6
Function and Parameter Declarations
The placement of the findMax() function after the main() function in Program 6.2
is a matter of choice. Usually, main() is listed first because it’s the driver function that gives
anyone reading the program an idea of what the complete program is about before
encountering the details of each function. In no case, however, can the definition of
findMax() be placed inside main(). This rule applies to all C++ functions, which must be
defined by themselves outside any other function. Each C++ function is a separate and
independent entity with its own parameters and variables; nesting functions is never
permitted.
Placement of Statements
C++ doesn’t impose a rigid statement-ordering structure on programmers. The general rule
for placing statements in a C++ program is simply that all preprocessor directives, named
constants, variables, and functions must be declared or defined before they can be used. As
noted previously, although this rule permits placing both preprocessor directives and
declaration statements throughout a program, doing so results in poor program structure.
As a matter of good programming form, the following statement ordering should form the
basic structure around which all C++ programs are constructed:
preprocessor directives
function prototypes
int main()
{
// symbolic constants
// variable declarations
// other executable statements
// return statement
}
// function definitions
As always, comment statements can be intermixed anywhere in this basic structure.
Function Stubs
An alternative to completing each function required in a complete program is writing the
main() function first and then adding the remaining functions as they’re developed.
302 Modularity Using Functions
The problem with this approach, however, is the same one that occurred with Program 6.1:
The program can’t be run until all the functions are included. For convenience, the code for
Program 6.1 has been reproduced here:
#include <iostream>
using namespace std;
void findMax(int, int); // the function declaration (prototype)
int main()
{
int firstnum, secnum;
cout << "nEnter a number: ";
cin >> firstnum;
cout << "Great! Please enter a second number: ";
cin >> secnum;
findMax(firstnum, secnum); // the function is called here
return 0;
}
This program would be complete if there were a function definition for findMax().
However, you really don’t need a correct findMax() function to test and run what has been
written; you just need a function that acts like it is. A “fake” findMax() that accepts the correct
number and types of parameters and returns values of the proper form for the function call is all
you need for initial testing. This fake function, called a stub, is the beginning of a final function
and can be used as a placeholder for the final unit until the unit is completed. A stub for
findMax() is as follows:
void findMax(int x, int y)
{
cout << "In findMax()n";
cout << "The value of x is " << x << endl;
cout << "The value of x is " << y << endl;
}
This stub function can now be compiled and linked with the previously completed code
to produce an executable program. The code for the function can then be further developed
with the “real” code when it’s completed, replacing the stub portion.
The minimum requirement of a stub function is that it compiles and links with its calling
module. In practice, it’s a good idea to have a stub display a message that it has been entered
successfully and display the values of its received parameters, as in the stub for findMax().
As the function is refined, you let it do more, perhaps allowing it to return intermediate or
incomplete results. This incremental, or stepwise, refinement is an important concept in
efficient program development that gives you the means to run a program that doesn’t yet
meet all its final requirements.
Functions with Empty Parameter Lists
Although useful functions having an empty parameter list are extremely limited, they can
occur. (You see one such function in Exercise 11 at the end of this section.) The function
303
Chapter 6
Function and Parameter Declarations
prototype for such a function requires writing the keyword void or nothing at all between
the parentheses following the function’s name. For example, both these prototypes
int display();
and
int display(void);
indicate that the display() function takes no parameters and returns an integer. A function
with an empty parameter list is called by its name with nothing written inside the required
parentheses following the function’s name. For example, the statement display();
correctly calls the display() function, whose prototype is shown in the preceding example.
Point of Information
Isolation Testing
One of the most successful software testing methods is to embed the code being
tested in an environment of working code. For example, you have two untested func-
tions called in the following order, and the result the second function returns is
incorrect:
function 1
calls
function 2
Returned value
is incorrect
From the information shown in this figure, one or possibly both of the functions
could be operating incorrectly. The first order of business is to isolate the problem to a
specific function.
One powerful method of performing this code isolation is to decouple the
functions. You do this by testing each function separately or by testing one function
first and, only after you know it’s operating correctly, reconnecting it to the second
function. Then, if an error occurs, you have isolated the error to the transfer of data
between functions or the internal operation of the second function.
This procedure is an example of the basic rule of testing, which states that each
function should be tested only in a program in which all other functions are known to
be correct. This rule means one function must first be tested by itself, using stubs if
necessary for any called functions, and a second tested function should be tested by
itself or with a previously tested function, and so on. This testing procedure ensures
that each new function is isolated in a test bed of correct functions, with the final pro-
gram built from tested function code.
304 Modularity Using Functions
Default Arguments3
C++ provides default arguments in a function call for added flexibility. The primary use of
default arguments is to extend the parameter list of existing functions without requiring any
change in the calling parameter lists already used in a program.
Default argument values are listed in the function prototype and transmitted automati-
cally to the called function when the corresponding arguments are omitted from the function
call. For example, the function prototype
void example(int, int = 5, double = 6.78);
provides default values for the last two arguments. If any argument is omitted when the
function is actually called, the C++ compiler supplies the default values. Therefore, all the
following function calls are valid:
example(7, 2, 9.3) // no defaults used
example(7, 2) // same as example(7, 2, 6.78)
example(7) // same as example(7, 5, 6.78)
Four rules must be followed when using default arguments. First, default values should
be assigned in the function prototype.4 Second, if any parameter is given a default value in
the function prototype, all parameters following it must also be supplied with default values.
Third, if one argument is omitted in the actual function call, all arguments to its right must
also be omitted. The second and third rules make it clear to the C++ compiler which
arguments are being omitted and permits the compiler to supply correct default values for the
missing arguments, starting with the rightmost argument and working in toward the left.
Fourth, the default value used in the function prototype can be an expression consisting of
both constants and previously declared variables. If this kind of expression is used, it must
pass the compiler’s check for validly declared variables, even though the expression’s actual
value is evaluated and assigned at runtime.
Default arguments are extremely useful when extending an existing function to include
more features that require additional arguments. Adding new arguments to the right of the
existing arguments and giving each new argument a default value permits all existing
function calls to remain as they are. In this way, the effect of the changes are conveniently
isolated from existing code in the program.
Reusing Function Names (Overloading)5
C++ provides the capability of using the same function name for more than one function,
referred to as function overloading. The only requirement for creating more than one function
with the same name is that the compiler must be able to determine which function to use
based on the parameters’ data types (not the data type of the return value, if any). For
example, take a look at the three following functions, all named cdabs():
void cdabs(int x) //
compute and display the absolute value of an integer
{
if ( x < 0 )
x = -x;
墌
3
This topic can be omitted on first reading without loss of subject continuity.
4
Some compilers accept default assignments in the function definition.
5
This topic can be omitted on first reading without loss of subject continuity.
305
Chapter 6
Function and Parameter Declarations
cout << "The absolute value of the integer is " << x << endl;
}
void cdabs(float x) // compute and display the absolute value of a float
{
if ( x < 0 )
x = -x;
cout << "The absolute value of the float is " << x << endl;
}
void cdabs(double x) //
compute and display the absolute value of a double
{
if ( x < 0 )
x = -x;
cout << "The absolute value of the double is " << x << endl;
}
Which of the three functions named cdabs() is actually called depends on the
argument type supplied at the time of the call. Therefore, the function call cdabs(10);
causes the compiler to use the function named cdabs() that expects an integer argument,
and the function call cdabs(6.28f); causes the compiler to use the function named
cdabs() that uses a single-precision argument.6
Notice that overloading a function’s name simply means using the same name for more
than one function. Each function that uses the name must still be written and exists as a
separate entity. The use of the same function name doesn’t require code in the functions to
be similar, although good programming practice dictates that functions with the same name
should perform essentially the same operations. All that’s required to use the same function
name is that the compiler can distinguish which function to select, based on the data types
of the arguments when the function is called. However, if the only difference in the
overloaded functions is the argument types, a better programming solution is to create a
function template, discussed next. The use of overloaded functions, however, is extremely
useful with constructor functions, explained in Section 10.2.
Function Templates7
In most high-level languages, including C++’s immediate predecessor, C, each function
requires its own unique name. In theory, using unique names makes sense, but in practice,
it can lead to a profusion of function names, even for functions that perform essentially the
same operations. For example, consider determining and displaying a number’s absolute
value. If the number passed to the function can be an integer, a single-precision value, or a
double-precision value, three distinct functions must be written to handle each case correctly.
6
Selection of the correct function is accomplished by a process called “name mangling.” Using this process, the function name the C++ compiler
actually generates differs from the function name used in the source code. The compiler appends information to the source code function,
depending on the type of data being passed, and the resulting name is said to be a “mangled” version of the source code name.
7
This topic can be omitted on first reading without loss of subject continuity.
306 Modularity Using Functions
Certainly, you could give each function a unique name, such as abs(), fabs(), and
dabs(), having the following function prototypes:
void abs(int);
void fabs(float);
void dabs(double);
Each of these functions performs essentially the same operation but on different
parameter data types. A much cleaner solution is writing a general function that handles all
cases, but the compiler can set parameters, variables, and even return type based on the
actual function call. You can write this type of function in C++ by using function templates.
A function template is a single, complete function that serves as a model for a family of
functions. The function from the family that’s actually created depends on subsequent
function calls. To make this concept more concrete, take a look at a function template that
computes and displays the absolute value of a passed argument:
template <class T>
void showabs(T number)
{
if (number < 0)
number = -number;
cout << "The absolute value of the number "
<< " is " << number << endl;
return;
}
For the moment, ignore the first line, template <class T>, and look at the second
line, which consists of the function header void showabs(T number). Notice that this
function header has the same syntax used for all function definitions, except the T where a
data type is usually placed. For example, if the function header were void showabs(int
number), you should recognize it as a function named showabs() that expects one integer
argument to be passed to it and returns no value. Similarly, if the function header were void
showabs(double number), you should recognize it as a function that expects one
double-precision argument to be passed to it when the function is called.
The advantage of using the T in the function template header is that it represents a
general data type that’s replaced by an actual data type, such as int, float, double, and
so forth, when the compiler encounters an actual function call. For example, if a function call
with an integer argument is encountered, the compiler uses the function template to
construct a function that expects an integer parameter. Similarly, if a call is made with a
double-precision argument, the compiler constructs a function that expects a double-
precision parameter. As a specific example, take a look at Program 6.3.
307
Chapter 6
Function and Parameter Declarations
Program 6.3
#include <iostream>
using namespace std;
template <class T>
void showabs(T number)
{
if (number < 0)
number = -number;
cout << "The absolute value of the number is "
<< number << endl;
return;
}
int main()
{
int num1 = -4;
float num2 = -4.23f;
double num3 = -4.23456;
showabs(num1);
showabs(num2);
showabs(num3);
return 0;
}
Notice the three function calls made in the main() function; they call the function
showabs() with an integer, float, and double value. Now review the function template for
showabs() and look at the first line, template <class T>. This line, called a template
prefix, is used to inform the compiler that the function immediately following is a template
using a data type named T. In the function template, the T is used in the same manner as
any other data type, such as int, float, and double. When the compiler encounters an
actual function call for showabs(), the data type of the argument passed in the call is
substituted for T throughout the function. In effect, the compiler creates a specific function,
using the template, that expects the argument type in the call.
Because Program 6.3 makes three calls to showabs(), each with a different argument
data type, the compiler creates three separate showabs() functions. The compiler knows
which function to use based on the arguments passed at the time of the call. This is the
output displayed when Program 6.3 runs:
The absolute value of the number is 4
The absolute value of the number is 4.23
The absolute value of the number is 4.23456
308 Modularity Using Functions
The letter T used in the template prefix template <class T> is simply a placeholder
for a data type that’s defined when the function is actually called. Any letter or non-keyword
identifier can be used instead, so the showabs() function template could just as well have
been defined as follows:
template <class DTYPE>
void abs(DTYPE number)
{
if (number < 0)
number = -number;
cout << "The absolute value of the number is "
<< number << endl;
return;
}
In this regard, sometimes it’s simpler and clearer to read the word class in the template
prefix as the words data type. With this substitution, you can read the template prefix
template <class T> as “I’m defining a function template that has a data type named T.”
Then, in the defined function’s header and body, the data type T (or any other letter or
identifier defined in the prefix) is used in the same manner as any built-in data type, such
as int, float, and double.
Now suppose you want to create a function template to include both a return type and
an internally declared variable. For example, take a look the following function template:
template <class T> // template prefix
T abs(T value) // function header line
{
T absnum; // variable declaration
if (value < 0)
absnum = -value;
else
absnum = value;
return absnum;
}
In this template definition, the date type T is used to declare three items: the return type
of the function, the data type of a single function parameter named value, and one variable
declared in the function. Program 6.4 shows how this function template could be used in the
context of a complete program.
309
Chapter 6
Function and Parameter Declarations
Program 6.4
#include <iostream>
using namespace std;
template <class T> // template prefix
T abs(T value) // header line
{
T absnum; // variable declaration
if (value < 0)
absnum = -value;
else
absnum = value;
return absnum;
}
int main()
{
int num1 = -4;
float num2 = -4.23f;
double num3 = -4.23456;
cout << "The absolute value of " << num1
<< " is " << abs(num1) << endl;
cout << "The absolute value of " << num2
<< " is " << abs(num2) << endl;
cout << "The absolute value of " << num3
<< " is " << abs(num3) << endl;
return 0;
}
In the first call to abs() made within main(), an integer value is passed as an
argument. In this case, the compiler substitutes an int data type for the T data type in the
function template and creates the following function:
int abs(int value) // header line
{
int absnum; // variable declaration
if (value < 0)
absnum = -value;
else
absnum = value;
return absnum;
}
310 Modularity Using Functions
Similarly, in the second and third function calls, the compiler creates two more functions:
one in which the data type T is replaced by the keyword float, and one in which the data
type T is replaced by the keyword double. This is the output produced by Program 6.4:
The absolute value of -4 is 4
The absolute value of -4.23 is 4.23
The absolute value of -4.23456 is 4.23456
The value of using a function template is that one function definition has been used to
create three different functions, each of which uses the same logic and operations but
operates on different data types.
Finally, although both Programs 6.3 and 6.4 define a function template using a single
placeholder data type, function templates with more than one data type can be defined. For
example, the template prefix
template <class DTYPE1, class DTYPE2, class DTYPE3>
can be used to create a function template requiring three different data types. As before, in the
function template’s header and body, the data types DTYPE1, DTYPE2, and DTYPE3 are used in
the same manner as any built-in data type, such as int, float, and double. Also, as noted
previously, the names DTYPE1, DTYPE2, and DTYPE3 can be any non-keyword identifier.
Conventionally, the letter T followed by zero or more digits is used, such as T, T1, T2, T3, and
so forth.
EXERCISES 6.1
1. (Practice) For the following function headers, determine the number, type, and order
(sequence) of the values that must be passed to the function:
a. void factorial(int n)
b. void volts(int res, double induct, double cap)
c. void power(int type, double induct, double cap)
d. void flag(char type, double current, double time)
e. void total(double amount, double rate)
f. void roi(int a, int b, char c, char d, double e, double f)
g. void getVal(int item, int iter, char decflag, char delim)
2. (Practice) a. Write a function named check() that has three parameters. The first
parameter should accept an integer number, and the second and third parameters should
accept a double-precision number. The function body should just display the values of
data passed to the function when it’s called. (Note: When tracing errors in functions, hav-
ing the function display values it has been passed is helpful. Quite often, the error isn’t
in what the function body does with data, but in the data received and stored.)
311
Chapter 6
Function and Parameter Declarations
b. Include the function written in Exercise 2a in a working program. Make sure your
function is called from main(). Test the function by passing various data to it.
3. (Practice) a. Write a function named findAbs() that accepts a double-precision num-
ber passed to it, computes its absolute value, and displays the absolute value. A number’s
absolute value is the number itself if the number is positive and the negative of the num-
ber if the number is negative.
b. Include the function written in Exercise 3a in a working program. Make sure your
function is called from main(). Test the function by passing various data to it.
4. (Practice) a. Write a function called mult() that accepts two floating-point numbers as
parameters, multiplies these two numbers, and displays the result.
b. Include the function written in Exercise 4a in a working program. Make sure your
function is called from main(). Test the function by passing various data to it.
5. (Practice) a. Write a function named sqrIt() that computes the square of the value
passed to it and displays the result. The function should be capable of squaring numbers
with decimal points.
b. Include the function written in Exercise 5a in a working program. Make sure your
function is called from main(). Test the function by passing various data to it.
6. (Practice) a. Write a function named powfun() that raises an integer number passed to
it to a positive integer power and displays the result. The positive integer should be the
second value passed to the function. Declare the variable used to store the result as a
long-integer data type to ensure enough storage for the result.
b. Include the function written in Exercise 6a in a working program. Make sure your
function is called from main(). Test the function by passing various data to it.
7. (Numerical) a. Write a C++ program that computes and displays the fractional part of
any user-entered number. For example, if the number 256.879 is entered, the number
0.879 should be displayed. (Hint: Use an int cast.)
b. Enter, compile, and execute the program written for Exercise 7a.
8. (Numerical) a. Write a C++ program that accepts an integer argument and determines
whether the passed integer is even or odd. (Hint: Use the % operator.)
b. Enter, compile, and execute the program written for Exercise 8a.
9. (Practice) a. Write a function that produces a table of the numbers from 1 to 10, their
squares, and their cubes. The function should produce the same display as Program 5.11.
b. Include the function written in Exercise 9a in a working program. Make sure your
function is called from main(). Test the function by passing various data to it.
10. (Modify) a. Modify the function written for Exercise 9a to accept the starting value of the
table, the number of values to be displayed, and the increment between values. If the incre-
ment isn’t sent explicitly, the function should use a default value of 1. Name your function
selTab(). A call to selTab(6,5,2); should produce a table of five lines, the first line
starting with the number 6 and each succeeding number increasing by 2.
b. Include the function written in Exercise 10a in a working program. Make sure your
function is called from main(). Test the function by passing various data to it.
312 Modularity Using Functions
11. (Numerical) A useful function using no parameters can be constructed to return a value
for ␲ that’s accurate to the maximum number of decimal places your computer allows.
This value is obtained by taking the arcsine of 1.0, which is ␲ / 2, and multiplying the
result by 2. In C++, the required expression is 2.0 * asin(1.0); the asin() func-
tion is provided in the standard C++ mathematics library. (Remember to include cmath
in your preprocessor directives.) Using this expression, write a C++ function named pi()
that calculates and displays the value of ␲. (In the next section, you see how to return
this value to the calling function.)
12. (Practice) a. Write a function template named display() that displays the value of
the single argument passed to it when the function is called.
b. Include the function template created in Exercise 12a in a complete C++ program that
calls the function three times: once with a character argument, once with an integer
argument, and once with a double-precision argument.
13. (Numerical) a. Write a function template named whole() that returns the integer
value of any argument passed to it when the function is called.
b. Include the function template created in Exercise 13a in a complete C++ program that
calls the function three times: once with a character argument, once with an integer
argument, and once with a double-precision argument.
14. (Numerical) a. Write a function template named maximum() that returns the maxi-
mum value of three arguments passed to the function when it’s called. Assume that all
three arguments are the same data type.
b. Include the function template created for Exercise 14a in a complete C++ program
that calls the function with three integers and then with three double-precision
numbers.
15. (Numerical) a. Write a function template named square() that computes and returns
the square of the single argument passed to the function when it’s called.
b. Include the function template created for Exercise 15a in a complete C++ program.
6.2 Returning a Single Value
Using the method of passing data to a function explained in the previous section, the called
function receives only copies of the values contained in arguments at the time of the call.
(Review Figure 6.3 if it’s unclear to you.) When a value is passed to a called function in this
manner, the passed argument is referred to as a passed by value and is a distinct advantage
of C++.8 Because the called function doesn’t have direct access to the variables used as
arguments by the calling function, it can’t inadvertently alter the value stored in one of these
variables.
The function receiving the passed by value arguments can process the values sent to it in any
fashion and return one, and only one, “legitimate” value directly to the calling function (see
Figure 6.6). In this section, you see how this value is returned to the calling function. As you
8
This argument is also referred to as a “call by value.” These terms, however, don’t refer to the function call as a whole, but to how the calling
function passes values to the called function.
313
Chapter 6
Returning a Single Value
might expect, given C++’s flexibility, there’s a way of returning more than a single value, but
that’s the topic of the next section.
As with calling a function, returning a value directly requires handling the interface
between the called and calling functions correctly. From its side of the return transaction, the
called function must provide the following items:
• The data type of the returned value
• The actual value being returned
A function returning a value must specify, in its header, the data type of the value to be
returned. Recall that the function header includes both the function name and a parameter
list. For example, the findMax() function written previously determines the maximum
value of two numbers passed to it. For convenience, the findMax() code is listed again:
void findMax(int x, int y)
{ // start of function body
int maxnum; // variable declaration
if (x >= y) // find the maximum number
maxnum = x;
else
maxnum = y;
cout << "nThe maximum of the two numbers is "
<< maxnum << endl;
return;
} // end of function body and end of function
In this function header, x and y are the names chosen for the function’s parameters:
void findMax(int x, int y)
If findMax() is to return a value, its function header must be amended to include the
data type of the value being returned. For example, if an integer value is to be returned, this
is the correct function header:
int findMax(int x, int y)
A function can receive many values
Only one value can
be directly returned
Figure 6.6 A function directly returns at most one value
314 Modularity Using Functions
Similarly, if the function is to receive two single-precision parameters and return a
single-precision value, this is the correct function header:
float findMax(float x, float y)
If the function is to receive two double-precision parameters and return a double-
precision value, the function header would be the following:9
double findMax(double x, double y)
Now see how to modify the findMax() function to return the maximum value of the
two numbers passed to it. To do this, you must first determine the data type of the value to
be returned and include this data type in the function header. Because the maximum value
determined by findMax() is stored in the integer variable maxnum, the function should
return this variable’s value. Returning an integer value from findMax() requires the
following function declaration:
int findMax(int x, int y)
Observe that it’s the same as the original function header for findMax(), with the
keyword int substituted for the keyword void.
Having declared the data type that findMax() will return, all that remains is including
a statement in the function to cause the return of the correct value. To return a value, a
function must use a return statement, which has this form:10
return expression;
When the return statement is encountered, the expression is evaluated first. The value
of the expression is then automatically converted to the data type declared in the function
header before being sent back to the calling function. After the value is returned, program
control reverts to the calling function. Therefore, to return the value stored in maxnum, all
you need to do is include the statement return maxnum; before the closing brace of the
findMax() function. The complete function code is as follows:
int findMax(int x, int y) // function header
{ // start of function body
int maxnum; // variable declaration
if (x >= y)
maxnum = x;
else
maxnum = y;
return maxnum; // return statement
}
These should
be the same
data type
9
The return data type is related to the parameter data types only as much as the returned value is typically determined by the parameter values.
In this case, because the function is used to return the maximum value of its parameters, it would make little sense to return a data type that
doesn’t match the function’s parameter data types.
10
Many programmers place the expression in parentheses, as in return (expression);. Although either form (with or without parentheses)
can be used, choose one and stay with it for consistency.
315
Chapter 6
Returning a Single Value
In this new code for the findMax() function, note that the data type of the expression
in the return statement matches the data type in the function header. It’s up to the
programmer to ensure this match for every function returning a value. Failure to match the
return value with the function’s declared data type exactly might not result in an error when
your program is compiled, but it could lead to undesired results because the return value is
always converted to the data type declared in the function declaration. Usually, this is a
problem only when the fractional part of a returned floating-point or double-precision
number is truncated because the function was declared to return an integer value.
Having taken care of the sending side of the return transaction, you must now prepare
the calling function to receive the value sent by the called function. On the calling (receiving)
side, the calling function must
• Be alerted to the type of value to expect back from the called function
• Use the returned value correctly
Alerting the calling function to the type of return value to expect is taken care of by the
function prototype. For example, including the function prototype
int findMax(int, int);
before the main() function is enough to alert main() that findMax() is a function that
returns an integer value.
To actually use a returned value, you must provide a variable to store the value or use the
value in an expression. To store the returned value in a variable, you use a standard
assignment statement. For example, the following assignment statement can be used to store
the value returned by findMax() in the variable max:
max = findMax(firstnum, secnum);
This assignment statement does two things. First, the right side of the assignment
statement calls findMax(), and then the result returned by findMax() is stored in the
variable max. Because the value returned by findMax() is an integer, the variable max
should also be declared as an integer variable in the calling function’s variable declarations.
The value a function returns need not be stored in a variable, but it can be used wherever
an expression is valid. For example, the expression 2 * findMax(firstnum, secnum)
multiplies the value returned by findMax() by 2, and the following statement displays the
returned value:
cout << findMax(firstnum, secnum);
Program 6.5 illustrates including prototype and assignment statements for main() to
declare, call, and store a returned value from findMax() correctly. As before, and in keeping
with the convention of placing the main() function first, the findMax() function is placed
after main().
316 Modularity Using Functions
Program 6.5
#include <iostream>
using namespace std;
int findMax(int, int); // the function prototype
int main()
{
int firstnum, secnum, max;
cout << "nEnter a number: ";
cin >> firstnum;
cout << "Great! Please enter a second number: ";
cin >> secnum;
max = findMax(firstnum, secnum); // the function is called here
cout << "nThe maximum of the two numbers is " << max << endl;
return 0;
}
int findMax(int x, int y)
{ // start of function body
int maxnum; // variable declaration
if (x >= y) // find the maximum number
maxnum = x;
else
maxnum = y;
return maxnum; // return statement
}
In reviewing Program 6.5, note the four items introduced in this section. First, the
function prototype for findMax() is a statement ending with a semicolon, as all declaration
statements do; it alerts main() and any subsequent functions using findMax() to the data
type that findMax() returns. Second, an assignment statement is used in main() to store
the returned value from the findMax() call in the variable max. In Program 6.5, max is
declared correctly as an integer in main()’s variable declarations so that it matches the
returned value’s data type.
The third and fourth items concern coding the findMax() function: The first line of
findMax() declares that the function returns an integer value, and the expression in the
return statement evaluates to a matching data type. Therefore, findMax() is internally
317
Chapter 6
Returning a Single Value
consistent in sending an integer value back to main(), and main() has been alerted to
receive and use the returned integer.
In writing your own functions, always keep these four items in mind. For another
example, see whether you can identify these four items in Program 6.6.
Program 6.6
#include <iostream>
using namespace std;
double tempvert(double); // function prototype
int main()
{
const int CONVERTS = 4; // number of conversions to be made
int count;
double fahren;
for(count = 1; count <= CONVERTS; count++)
{
cout << "nEnter a Fahrenheit temperature: ";
cin >> fahren;
cout << "The Celsius equivalent is "
<< tempvert(fahren) << endl;
}
return 0;
}
// convert fahrenheit to celsius
double tempvert(double inTemp)
{
return (5.0/9.0) * (inTemp - 32.0);
}
In reviewing Program 6.6, first analyze the tempvert() function. The function’s
definition begins with the function header and ends with the closing brace after the return
statement. The function is declared as a double, meaning the expression in the function’s
return statement must evaluate to a double-precision number, which it does. Because a
function header is not a statement but the start of the code defining the function, it doesn’t
end with a semicolon.
On the receiving side, main() has a prototype for the tempvert() function that agrees
with tempvert()’s function definition. No variable is declared in main() to store the
318 Modularity Using Functions
returned value from tempvert() because the returned value is passed immediately to
cout for display.
Finally, one purpose of declarations, as you learned in Chapter 2, is to alert the computer
to the amount of internal storage reserved for data. The prototype for tempvert() performs
this task and alerts the compiler to the type of storage needed for the returned value. Because
main() is always the first function in a program, you must include function prototypes for
all functions called by main() and any subsequent functions.
Inline Functions11
Calling a function places a certain amount of overhead on a computer. This overhead consists
of the following steps:
1. Placing argument values in a reserved memory region (called the stack) that the
function has access to
2. Passing control to the function
3. Providing a reserved memory location for any returned value (again, using the stack
for this purpose)
4. Returning to the correct point in the calling program
Paying this overhead is justified when a function is called many times because it can
reduce a program’s size substantially. Instead of the same code being repeated each time it’s
needed, the code is written once, as a function, and called whenever it’s needed.
For small functions that aren’t called many times, however, the overhead of passing and
returning values might not be warranted. It would still be convenient to group repeating lines
of code together under a common function name and have the compiler place this code in
the program wherever the function is called. Inline functions provide this capability.
Telling the C++ compiler that a function is inline causes a copy of the function code to
be placed in the program at the point the function is called. For example, because the
tempvert() function in Program 6.6 is fairly short, it’s an ideal candidate to be an inline
function. To make it, or any other function, an inline one simply requires placing the reserved
keyword inline before the function name and defining the function before any calls are
made to it. Program 6.7 makes tempvert() an inline function.
Observe in Program 6.7 that the inline function is placed ahead of any calls to it. This
placement is a requirement of all inline functions, so a function prototype isn’t needed before
subsequent calling functions. Because the function is now inline, its code is expanded into
the program wherever it’s called.
11
This section is optional and can be omitted on first reading without loss of subject continuity.
319
Chapter 6
Returning a Single Value
Program 6.7
#include <iostream>
using namespace std;
inline double tempvert(double inTemp) // an inline function
{
return (5.0/9.0) * (inTemp - 32.0);
}
int main()
{
const CONVERTS = 4; // number of conversions to be made
int count;
double fahren;
for(count = 1; count <= CONVERTS; count++)
{
cout << "nEnter a Fahrenheit temperature: ";
cin >> fahren;
cout << "The Celsius equivalent is "
<< tempvert(fahren) << endl;
}
return 0;
}
The advantage of using an inline function is an increase in execution speed. Because the
inline function is expanded and included in every expression or statement calling it, no
execution time is lost because of the call and return overhead a non-inline function requires.
The disadvantage is the increase in program size when an inline function is called repeatedly.
Each time an inline function is referenced, the complete function code is reproduced and
stored as an integral part of the program. A non-inline function, however, is stored in memory
only once. No matter how many times the function is called, the same code is used.
Therefore, inline functions should be used only for small functions that aren’t called
extensively in a program.
320 Modularity Using Functions
EXERCISES 6.2
1. (Modify) Rewrite Program 6.5 so that the findMax() function accepts two double-
precision arguments and returns a double-precision value to main(). Make sure to
modify main() to pass two double-precision values to findMax() and to accept and
store the double-precision value returned by findMax().
2. (Practice) For the following function headers, determine the number, type, and order
(sequence) of values that should be passed to the function when it’s called and the data
type of the value the function returns:
a. int factorial(int n)
b. double volts(int res, double induct, double cap)
c. double power(int type, double induct, double cap)
d. char flag(char type, float current, float time)
e. int total(float amount, float rate)
f. float roi(int a, int b, char c, char d, float e, float f)
g. void getVal(int item, int iter, char decflag, char delim)
3. (Practice) Write function headers for the following:
a. A function named check() that has three parameters. The first parameter should
accept an integer number, and the second and third parameters should accept a
double-precision number. The function returns no value.
b. A function named findAbs() that accepts a double-precision number passed to it
and returns its absolute value.
c. A function named mult() that accepts two floating-point numbers as parameters,
multiplies these two numbers, and returns the result.
d. A function named sqrIt() that computes and returns the square of the integer value
passed to it.
e. A function named powfun() that raises an integer number passed to it to a positive
integer (as an argument) power and returns the result as an integer.
f. A function that produces a table of the numbers from 1 to 10, their squares, and their
cubes. No arguments are to be passed to the function, and the function returns no value.
4. (General Math) a. Write a function named rightTriangle() that accepts the
lengths of two sides of a right triangle as the arguments a and b. The subroutine should
determine and return the hypotenuse, c, of the triangle. (Hint: Use Pythagoras’ theorem,
c2
= a2
+ b2
.)
b. Include the function written for Exercise 4a in a working program. The main() function
should call rightTriangle() correctly and display the value the function returns.
5. (General Math) a. Write a C++ function named findAbs() that accepts a double-
precision number passed to it, computes its absolute value, and returns the absolute value
to the calling function. A number’s absolute value is the number itself if the number is
positive and the negative of the number if the number is negative.
321
Chapter 6
Returning a Single Value
b. Include the function written in Exercise 5a in a working program. Make sure your
function is called from main() and returns a value to main() correctly. Have
main() use a cout statement to display the returned value. Test the function by
passing various data to it.
6. (General Math) a. The volume, V, of a cylinder is given by the formula
V = ␲r2
L
where r is the cylinder’s radius and L is its length. Using this formula, write a C++ func-
tion named cylvol() that accepts a cylinder’s radius and length and returns its volume.
b. Include the function written in Exercise 6a in a working program. Make sure your
function is called from main() and returns a value to main() correctly. Have
main() use a cout statement to display the returned value. Test the function by
passing various data to it.
7. (General Math) a. The side surface area, S, of a cylinder is given by the formula
S = 2␲rl
where r is the cylinder’s radius, and l is the length of the cylinder. Using this formula,
write a C++ function named surfarea() that accepts a cylinder’s radius and length and
returns its side surface area.
b. Include the function written in Exercise 7a in a working program. Make sure your
function is called from main() and returns a value to main() correctly. Have
main() use a cout statement to display the returned value. Test the function by
passing various data to it.
8. (Numerical) A second-degree polynomial in x is given by the expression ax2
+ bx + c,
where a, b, and c are known numbers and a is not equal to 0. Write a C++ function
named polyTwo(a,b,c,x) that computes and returns the value of a second-degree
polynomial for any passed values of a, b, c, and x.
9. (Structural Eng.) a. The maximum allowable deflection of a beam depends on its
function. For a floor, the typical maximum allowable deflection, in inches, is Dmax = L /
240, and for a roof beam, Dmax = L / 180, where L is the length of the beam in inches.
Using these formulas, write and test a function named maxDeflect() that accepts the
length of a beam, in feet, and the type of beam (floor or roof) as a character code and
returns the maximum allowable deflection.
b. Include the function written in Exercise 9a in a working program. Make sure your
function is called from main() and returns a value to main() correctly. Have
main() use a cout statement to display the returned value. Test the function by
passing various data to it.
10. (Structural Eng.) a. The load, Pcr, in units of kips, applied to a column that causes the
column to buckle is referred to as the critical buckling load. This load can be determined
by using this formula:
Pcr = ␲2
E A / (L / r)2
322 Modularity Using Functions
E is the modulus of elasticity of the column’s material.
A is the cross-sectional area.
L is the length of the column.
r is the column’s radius of gyration.
Using this formula, write a C++ function named cLoad() that accepts values of E, A, L,
and r and returns the critical buckling load.
b. Include the function written in Exercise 10a in a working program. Make sure your
function is called from main() and returns a value to main() correctly. Have
main() use a cout statement to display the returned value. Test the function by
passing various data to it.
11. (Numerical) a. The following is an extremely useful programming algorithm for round-
ing a real number to n decimal places:
Step 1: Multiply the number by 10n
Step 2: Add 0.5
Step 3: Delete the fractional part of the result
Step 4: Divide by 10n
For example, using this algorithm to round the number 78.374625 to three decimal places
yields:
Step 1: 78.374625 × 103
= 78374.625
Step 2: 78374.625 + 0.5 = 78375.125
Step 3: Retaining the integer part = 78375
Step 4: 78375 divided by 103
= 78.375
Using this algorithm, write a C++ function that accepts a user-entered value and returns
the result rounded to two decimal places.
b. Enter, compile, and execute the program written for Exercise 11a.
12. (Numerical) a. Write a C++ function named whole() that returns the integer part of
any number passed to the function. (Hint: Assign the passed argument to an integer
variable.)
b. Include the function written in Exercise 12a in a working program. Make sure your
function is called from main() and returns a value to main() correctly. Have
main() use a cout statement to display the returned value. Test the function by
passing various data to it.
13. (Numerical) a. Write a C++ function named fracpart() that returns the fractional part of
any number passed to it. For example, if the number 256.879 is passed to fracpart(), the
number 0.879 should be returned. Have fracpart() call the whole() function you wrote
in Exercise 12. The number returned can then be determined as the number passed to
fracpart() less the returned value when the same argument is passed to whole(). The
completed program should consist of main() followed by fracpart() followed by
whole().
b. Include the function written in Exercise 13a in a working program. Make sure your
function is called from main() and returns a value to main() correctly. Have
main() use a cout statement to display the returned value. Test the function by
passing various data to it.
323
Chapter 6
Returning a Single Value
14. (Numerical) Years that are evenly divisible by 400 or are evenly divisible by 4 but not by
100 are leap years. For example, because 1600 is evenly divisible by 400, 1600 was a leap
year. Similarly, because 1988 is evenly divisible by 4 but not by 100, it was also a leap year.
Using this information, write a C++ function that accepts the year as user input and returns a
1 if the passed year is a leap year or a 0 if it isn’t.
6.3 Returning Multiple Values
In a typical function invocation, the called function receives values from its calling function,
stores and manipulates the passed values, and directly returns at most one value. When data
is passed in this manner, it’s referred to as a pass by value.
Calling a function and passing arguments by value is a distinct advantage of C++. It
allows functions to be written as independent entities that can use any variable or parameter
name without concern that other functions might be using the same name. It also alleviates
any concern that altering a parameter or variable in one function could inadvertently alter a
parameter or variable’s value in another function. In this approach, parameters can be
considered initialized variables, or variables assigned values when the function is executed.
At no time, however, does the called function have direct access to any variable defined in
the calling function, even if the variable is used as an argument in the function call.
At times, however, you need to modify this approach by giving a called function direct
access to its calling function’s variables. This approach allows one function—the called
function—to use and change the value of variables that have been defined in the calling
function. Doing this requires passing the variable’s address to the called function. After the
called function has the variable’s address, it “knows where the variable lives,” so to speak,
and can access and change the value stored there.
Passing addresses is referred to as a function pass by reference12 because the called
function can reference, or access, the variable whose address has been passed. C++ provides
two types of address parameters: references and pointers. This section describes the method
that uses reference parameters.
Passing and Using Reference Parameters
As always, when exchanging data between two functions, you must be concerned with both
the sending and receiving sides. From the sending side, calling a function and passing an
address as an argument that’s accepted as a reference parameter is the same as calling a
function and passing a value; the called function is summoned into action by giving its name
and a list of arguments. For example, the statement newval(firstnum, secnum); calls
the function named newval() and passes two arguments to it. Whether a value or an
address is actually passed depends on the parameter types declared for newval(). Now take
a look at writing the newval() function and prototype so that it receives the addresses
rather than the values of the variables firstnum and secnum, which are assumed to be
double-precision variables.
12
It’s also referred to as a “call by reference,” and again, both terms refer only to the argument whose address has been passed.
324 Modularity Using Functions
One of the first requirements in writing newval() is to declare two reference
parameters for accepting passed addresses. In C++, a reference parameter is declared with
this syntax:
dataType& referenceName
For example, the reference declaration
double& num1;
declares that num1 is a reference parameter used to store the address of a double. Similarly,
int& secnum; declares that secnum is a reference to an integer, and char& key;
declares that key is a reference to a character.
Recall from Section 2.4 that the ampersand, &, in C++ means “the address of.”
Additionally, when & is used in a declaration, it refers to “the address of” the preceding data
type. Using this information, declarations such as double& num1 and int& secnum are
sometimes more clearly understood if they are read backward. Reading the declaration
double& num1 in this manner yields the information “num1 is the address of a
double-precision value.”
Because you need to accept two addresses in the parameter list for newval(), the
declarations double& num1 and double& num2 can be used. Including these declarations
in the parameter list for newval(), and assuming the function returns no value (void), the
function header for newval() becomes the following:
void newval(double& num1, double& num2)
For this function header, the following is an appropriate function prototype:
void newval(double&, double&);
This prototype and function header are included in Program 6.8, which uses a newval()
function body that displays and alters the values stored in these reference variables from
within the called function.
In calling the newval() function in Program 6.8, you need to understand the
connection between the arguments, firstnum and secnum, used in the function call and
the parameters, xnum and ynum, used in the function header. Both refer to the same data
items. The significance is that the values in the arguments (firstnum and secnum) can
now be altered from within newval() by using the parameter names (xnum and ynum).
Therefore, the parameters xnum and ynum don’t store copies of the values in firstnum and
secnum; instead, they access the locations in memory set aside for these two arguments.
325
Chapter 6
Returning Multiple Values
Program 6.8
#include <iostream>
using namespace std;
void newval(double&, double&); // prototype with two reference parameters
int main()
{
double firstnum, secnum;
cout << "Enter two numbers: ";
cin >> firstnum >> secnum;
cout << "nThe value in firstnum is: " << firstnum << endl;
cout << "The value in secnum is: " << secnum << "nn";
newval(firstnum, secnum); // call the function
cout << "The value in firstnum is now: " << firstnum << endl;
cout << "The value in secnum is now: " << secnum << endl;
return 0;
}
void newval(double& xnum, double& ynum)
{
cout << "The value in xnum is: " << xnum << endl;
cout << "The value in ynum is: " << ynum << "nn";
xnum = 89.5;
ynum = 99.5;
return;
}
The equivalence of argument names in Program 6.8, which is the essence of a pass by
reference, is illustrated in Figure 6.7. As shown in this figure, the argument names and their
matching parameter names are simply different names referring to the same memory storage
areas. In main(), these memory locations are referenced by the argument names firstnum
and secnum, and in newval(), the same locations are referenced by the parameter names
xnum and ynum.
326 Modularity Using Functions
The following is a sample run of Program 6.8:
Enter two numbers: 22.5 33.0
The value in firstnum is: 22.5
The value in secnum is: 33
The value in xnum is: 22.5
The value in ynum is: 33
The value in firstnum is now: 89.5
The value in secnum is now: 99.5
In reviewing this output, notice that the values initially displayed for the parameters
xnum and ynum are the same as those displayed for the arguments firstnum and secnum.
Because xnum and ynum are reference parameters, however, newval() now has direct
access to the arguments firstnum and secnum. Therefore, any change to xnum in
newval() alters the value of firstnum in main(), and any change to ynum changes
secnum’s value. As the final displayed values show, the assignment of values to xnum and
ynum in newval() is reflected in main() as the altering of firstnum’s and secnum’s
values.
The equivalence between actual calling arguments and function parameters shown in
Program 6.8 provides the basis for returning multiple values from within a function. For
example, say you want to write a function that’s required to accept three values, compute
these values’ sum and product, and return these computed results to the calling routine. By
firstnum
xnum
One value is stored
secnum
ynum
In main() the values
are referenced as
In newval() the same values
are referenced as
One value is stored
Figure 6.7 The equivalence of arguments and parameters in Program 6.8
327
Chapter 6
Returning Multiple Values
naming the function calc() and providing five parameters (three for input data and two
references for returned values), the following function can be used:
void calc(double num1, double num2, double num3, double& total, double&
product)
{
total = num1 + num2 + num3;
product = num1 * num2 * num3;
return;
}
This function has five parameters named num1, num2, num3, total, and product.
Only the last two are declared as references, so the first three arguments are passed by value
and the last two arguments are passed by reference. In this function, only the last two
parameters are altered. The value of the fourth parameter, total, is calculated as the sum
of the first three parameters, and the last parameter, product, is computed as the product
of the parameters num1, num2, and num3. Program 6.9 includes this function in a complete
program.
Program 6.9
#include <iostream>
using namespace std;
void calc(double, double, double, double&, double&); // prototype
int main()
{
double firstnum, secnum, thirdnum, sum, product;
cout << "Enter three numbers: ";
cin >> firstnum >> secnum >> thirdnum;
calc(firstnum, secnum, thirdnum, sum, product); // function call
cout << "nThe sum of the numbers is: " << sum << endl;
cout << "The product of the numbers is: " << product << endl;
return 0;
}
void calc(double num1, double num2, double num3, double& total, double& product)
{
total = num1 + num2 + num3;
product = num1 * num2 * num3;
return;
}
328 Modularity Using Functions
In main(), the function calc() is called with the five arguments firstnum, secnum,
thirdnum, sum, and product. As required, these arguments agree in number and data
type with the parameters declared by calc(). Of the five arguments passed, only
firstnum, secnum, and thirdnum have been assigned values when the call to calc()
is made. The remaining two arguments haven’t been initialized and are used to receive
values back from calc(). Depending on the compiler used, these arguments initially
contain zeros or “garbage” values. Figure 6.8 shows the relationship between actual and
parameter names and the values they contain after the return from calc().
After calc() is called, it uses its first three parameters to calculate values for total and
product and then returns control to main(). Because of the order of its actual calling
arguments, main() knows the values calculated by calc() as sum and product, which
are then displayed. Following is a sample run of Program 6.9:
Enter three numbers: 2.5 6.0 10.0
The sum of the entered numbers is: 18.5
The product of the entered numbers is: 150
As a final example of the usefulness of passing references to a called function, take a look
at constructing a function named swap() that exchanges the values of two of main()’s
double-precision variables. This type of function is useful when sorting a list of numbers.
Because the value of more than one variable is affected, swap() can’t be written as a
pass by value function that returns a single value. The exchange of main()’s variables by
swap() can be accomplished only by giving swap() access to main()’s variables. One way
of doing this is using reference parameters.
You have already seen how to pass references to two variables in Program 6.8. Now you
see how to construct a function to exchange the values in the passed reference parameters.
num2
num3
num1
10.0
6.0
2.5
A value is passed
main()
calc()
Argument names used in main()
Parameter names used in calc()
10.0
thirdnum
6.0
secnum
2.5
firstnum
total
18.5
sum
product
150.0
product
Figure 6.8 The relationship between argument and parameter names
329
Chapter 6
Returning Multiple Values
Exchanging values in two variables is accomplished by using the three-step exchange
algorithm:
1. Save the first parameter’s value in a temporary location (see Figure 6.9a).
2. Store the second parameter’s value in the first variable (see Figure 6.9b).
3. Store the temporary value in the second parameter (see Figure 6.9c).
Following is the swap() function written according to these specifications:
void swap(double& num1, double& num2)
{
double temp;
temp = num1; // save num1's value
num1 = num2; // store num2's value in num1
num2 = temp; // change num2's value
return;
}
Notice that the use of references in swap()’s function header gives swap() access to
equivalent arguments in the calling function. Therefore, any changes to the two reference
parameters in swap() change the values in the calling function’s arguments automatically.
Program 6.10 contains swap() in a complete program.
num1
temp num2
Figure 6.9a Save the first value
num1
temp num2
Figure 6.9b Replace the first value with the second value
num2
num1
temp
Figure 6.9c Change the second value
330 Modularity Using Functions
Program 6.10
#include <iostream>
using namespace std;
void swap(double&, double&); // function receives two references
int main()
{
double firstnum = 20.5, secnum = 6.25;
cout << "The value stored in firstnum is: " << firstnum << endl;
cout << "The value stored in secnum is: "<< secnum << "nn";
swap(firstnum, secnum); // call the function with references
cout << "The value stored in firstnum is now: "
<< firstnum << endl;
cout << "The value stored in secnum is now: "
<< secnum << endl;
return 0;
}
void swap(double& num1, double& num2)
{
double temp;
temp = num1; // save num1's value
num1 = num2; // store num2's value in num1
num2 = temp; // change num2's value
return;
}
The following is a sample run of Program 6.10:
The value stored in firstnum is: 20.5
The value stored in secnum is: 6.25
The value stored in firstnum is now: 6.25
The value stored in secnum is now: 20.5
As shown by Program 6.10’s output, the values stored in main()’s variables have been
modified from within swap(), which was made possible by using reference parameters. If
a pass by value had been used instead, the exchange in swap() would affect only swap()’s
331
Chapter 6
Returning Multiple Values
parameters and accomplish nothing with main()’s variables. A function such as swap() can
be written only by using a reference or some other means that provides access to main()’s
variables. (This other means is with pointers, the topic of Chapter 12.)
In using reference parameters, two cautions need to be mentioned. First, reference
parameters must be variables (that is, they can’t be used to change constants). For example,
calling swap() with two literals, as in the call swap(20.5, 6.5), passes two constants to
the function. Although swap() can execute, it doesn’t change the values of these constants.13
Second, a function call gives no indication that the called function will be using reference
parameters. The default in C++ is to make passes by value rather than passes by reference,
specifically to limit a called function’s ability to alter variables in the calling function. This
calling procedure should be adhered to whenever possible, which means reference param-
eters should be used only in restricted situations that require multiple return values, as in the
swap() function in Program 6.10. The calc() function included in Program 6.9, although
useful for illustration purposes, could also be written as two separate functions, each
returning a single value.
EXERCISES 6.3
1. (Practice) Write parameter declarations for the following:
a. A parameter named slope that will be a reference to a double-precision value
b. A parameter named energy that will be a reference to a double-precision number
c. A parameter named minutes that will be a reference to an integer number
d. A parameter named key that will be a reference to a character
e. A parameter named yield that will be a reference to a double-precision number
2. (Practice) Three integer arguments are to be used in a call to a function named
time(). Write a suitable function header for time(), assuming that time() accepts
these variables as the reference parameters sec, min, and hours and returns no value to
its calling function.
3. (Modify) Rewrite the findMax() function in Program 6.5 so that the variable max,
declared in main(), is used to store the maximum value of the two passed numbers.
The value of max should be set from within findMax(). (Hint: A reference to max has
to be accepted by findMax().)
4. (Practice) Write a function named change() that has an integer parameter and six inte-
ger reference parameters named hundreds, fifties, twenties, tens, fives, and
ones. The function is to consider the passed integer value as a dollar amount and con-
vert the value into the fewest number of equivalent bills. Using the reference parameters,
the function should alter the arguments in the calling function.
5. (Practice) Write a function named time() that has an integer parameter named
seconds and three integer reference parameters named hours, mins, and secs. The
13
Most compilers catch this error.
332 Modularity Using Functions
function is to convert the passed number of seconds into an equivalent number of hours,
minutes, and seconds. Using the reference parameters, the function should alter the argu-
ments in the calling function.
6. (Practice) Write a function named yearCalc() that has an integer parameter represent-
ing the total number of days from the date 1/1/2000 and reference parameters named
year, month, and day. The function is to calculate the current year, month, and day
given the number of days passed to it. Using the reference parameters, the function
should alter the arguments in the calling function. For this problem, assume each year has
365 days, and each month has 30 days.
7. (Desk Check) The following program uses the same argument and parameter names in
both the calling and called functions. Determine whether doing so causes any problem for
the compiler.
#include <iostream>
using namespace std;
void time(int&, int&); // function prototype
int main()
{
int min, hour;
cout << "Enter two numbers :";
cin >> min >> hour;
time(min, hour);
return 0;
}
void time(int& min, int& hour) // accept two references
{
int sec;
sec = (hour * 60 + min) * 60;
cout << "The total number of seconds is " << sec << endl;
return;
6.4 A Case Study: Rectangular to Polar Coordinate
Conversion
Preparing a well-designed computer program is much like preparing a well-designed term
paper, in that both should start with an outline. This outline can be written down or, for very
small programs, simply kept in mind as the program is being developed. As with a term-paper
outline that lists the main topics, a computer program’s initial outline lists the primary tasks
the program is to accomplish.
In written form, a computer program’s initial outline is typically a pseudocode description
or a first-level structure diagram. (Both were described in Section 1.3.) This initial outline
333
Chapter 6
A Case Study: Rectangular to Polar
Coordinate Conversion
begins the process of defining a more complicated problem as a set of smaller, more
manageable tasks. Each of these tasks can be further subdivided or refined into even smaller
tasks, if required. After the tasks are well defined, the actual work of coding can begin,
starting with any task, in any order. If there are more tasks than one programmer can handle,
they can be distributed among as many programmers as necessary. This workload distribution
is equivalent to having many people work on a large research project, with each person
responsible for a topic or project component. A general outline applicable to many
engineering and scientific tasks is the following algorithm:
Get the inputs to the problem
Calculate the desired result
Report the results of the calculation
These three tasks are the primary responsibilities of every program, and this algorithm is
referred to as the problem-solver algorithm. Figure 6.10 shows a first-level structure diagram
of this algorithm.
Each task in the problem-solver algorithm can be worked on independently as a
function—a sort of “mini” C++ program that’s easier to complete than a whole program. Each
function task can be refined and coded in any order, although completing the input section
first usually makes testing and development easier. Next, you apply this development
procedure to the programming problem of converting rectangular coordinates to their polar
equivalents.
Step 1 Problem Definition
A program is to be written to convert a point’s rectangular (x,y) coordinates into polar form.
That is, given an x and y position on a Cartesian coordinate system, shown in Figure 6.11, you
must calculate the distance from the origin, r, and the angle from the x-axis, θ , specified by
the point. The values of r and θ are referred to as the point’s polar coordinates.
When the x and y coordinates of a point are known, the equivalent r and θ coordinates
can be calculated by using these formulas:
r x y
= +
2 2
θ = ≠
tan ( / )
-1
0
y x x
You begin developing your program with an outline of what the program is to accomplish.
You can construct an initial pseudocode description by applying the problem-solver algorithm
Problem-
solver
algorithm
Get
inputs
Calculate
result
Display
result
Figure 6.10 The problem-solver algorithm
334 Modularity Using Functions
to the specifics of the program. The required inputs are x and y coordinates, the calculation
is to convert the input values to their polar coordinate form, and the display is the calculated
polar coordinates. The initial pseudocode description is as follows:
Get the x and y coordinate values
Calculate the polar (r and θ ) coordinate values
Display the polar coordinate values
Figure 6.12 shows the equivalent first- or top-level structure diagram for this algorithm.
As this program is rather simple and each task described by the algorithm is well defined, you
can begin coding each task. To show that any task can be coded independently of any other task,
you start by coding the function that calculates polar coordinates, although you could start with
any function. As an added feature, this function will return the angle θ in degrees rather than
the radian measure the atan() function returns. Because this function must receive two inputs,
the x and y coordinates, and return two outputs, the r and θ coordinates, you provide four
parameters: two for the inputs and two for the outputs. Using the parameter names x, y, r, and
(x,y)
x-axis
y-axis
r
Figure 6.11 The correspondence between polar (distance and angle) and Cartesian (x and y)
coordinates
Rectangular
to polar
coordinate
conversion
Input x and
y coordinates
Calculate
r and
Display
r and
θ θ
Figure 6.12 A top-level structure diagram
335
Chapter 6
A Case Study: Rectangular to Polar
Coordinate Conversion
theta and the function name polar(), the following code performs the required calculation
of polar coordinates:
void polar(double x, double y, double& r, double& theta)
{
const double TODEGREES = 180.0/3.141593;
r = sqrt(x * x + y * y);
theta = atan(y/x) * TODEGREES;
return;
}
The polar() function is straightforward. The function header declares that the
function returns no value, and each of its parameters is declared as a floating-point data type.
The first two parameters are used to accept x and y values, and the last two parameters,
which are reference parameters, are used to pass the converted distance and angle values
back to the calling function.
In the function body, a constant named TODEGREES is defined as the factor 180.0 /
3.142593. The next two assignment statements use the parameters x and y to assign values
to the r and theta parameters. The TODEGREES named constant is used to convert the
radian value returned from the atan() function into degrees. As written, the polar()
function can be compiled to check for any compile-time errors.
To understand how the return values are passed, it’s helpful to think of the reference
parameters r and theta as containers (or variables) through which values can be passed in
either direction. This situation is shown in Figure 6.13, which illustrates the fundamental
characteristics of reference parameters: They simply make it possible for both called functions and
calling functions to access the same storage area with different names. As shown in Figure 6.13, the
calling function can access the values assigned to r and theta in polar() with the
argument names distance and angle or any other programmer-selected argument names.
Step 2 Testing the Function
After polar() is written, it can be tested independently of any other function. For this testing,
you write a dedicated driver function that calls only polar(), as shown in Program 6.11.
r
main()
polar()
main()
polar()
5.0
distance
theta
53.1301
angle
Figure 6.13 Parameter values when polar() is called
336 Modularity Using Functions
Program 6.11
#include <iostream>
#include <cmath>
using namespace std;
void polar(double, double, double&, double&); // function prototype
int main()
{
double distance, angle;
polar(3.0, 4.0, distance, angle);
cout << "r = " << distance << endl;
cout << "angle = " << angle << endl;
return 0;
}
void polar(double x, double y, double& r, double& theta)
{
const double TODEGREES = 180.0/3.141593;
r = sqrt(x * x + y * y);
theta = atan(y/x) * TODEGREES;
return;
}
Notice that in main(), the literals 3.0 and 4.0 are passed to polar(). The function
accepts these inputs as the parameters x and y and uses these parameters in calculating
values for the parameters r and theta. In main(), these last two parameters are known as
distance and angle, and their values are displayed immediately after the call to polar()
is made. This is the output produced when Program 6.11 runs:
r = 5
angle = 53.1301
These results are the same as those you would get from a hand calculation. As the
function performs only two calculations, and the results displayed by the test program agree
with those from a hand calculation, the function has been completely tested. It still remains
to be group tested with the other two functions required for the complete program to make
sure correct argument values are exchanged between each function.
337
Chapter 6
A Case Study: Rectangular to Polar
Coordinate Conversion
Step 3 Completing the Program
The structure diagram for the complete program (shown previously in Figure 6.12) also
requires writing functions for accepting two rectangular coordinates and displaying the
calculated polar coordinates. The following function, getrec(), can be used to accept the
input data:
void getrec(double& x, double& y)
{
cout << "Rectangular to Polar Coordinate"
<< " Conversion Programn" << endl;
cout << "Enter the x coordinate: ";
cin >> x;
cout << "Enter the y coordinate: ";
cin >> y;
return;
}
In this function, the reference parameters x and y are used to return the values entered
in response to the two cin prompts. As with the polar() function, this function can be
tested by using a small dedicated driver program. Program 6.12 shows the function with its
driver program.
Notice that the dedicated driver program, also referred to as a “front-end driver,” has
been used to call getrec() and display the values this function returns. The following
output produced by Program 6.12 verifies the correct operation of the getrec() function:
Rectangular to Polar Coordinate Conversion Program
Enter the x coordinate: 3
Enter the y coordinate: 4
The entered value for x is 3
The entered value for y is 4
338 Modularity Using Functions
Program 6.12
#include <iostream>
using namespace std;
void getrec(double&, double&); // function prototype
int main()
{
double xcoord, ycoord;
getrec(xcoord, ycoord);
cout << "The entered value for x is " << xcoord << endl;
cout << "The entered value for y is " << ycoord << endl;
return 0;
}
void getrec(double& x, double& y)
{
cout << "Rectangular to Polar Coordinate"
<< " Conversion Programn" << endl;
cout << "Enter the x coordinate: ";
cin >> x;
cout << "Enter the y coordinate: ";
cin >> y;
return;
}
The function for displaying polar coordinates is constructed in a similar manner.
Program 6.13 contains both the function, named showit(), and a front-end driver for
testing the function. Notice that the parameter names used in the function header for
showit() need not be the same as those used in any other function. showit() is
constructed to simply display the values in its two parameters, which in this case have been
named radius and angle.
The following output of Program 6.13 verifies that showit() displays the values passed
to it correctly:
The polar coordinates are:
Distance from origin: 5
Angle (in degrees) from x-axis: 53.1301
339
Chapter 6
A Case Study: Rectangular to Polar
Coordinate Conversion
Program 6.13
#include <iostream>
using namespace std;
void showit(double, double); // function prototype
int main()
{
showit(5.0, 53.1301);
return 0;
}
void showit(double radius, double angle)
{
cout << "nThe polar coordinates are: " << endl;
cout << " Distance from origin: " << radius << endl;
cout << " Angle (in degrees) from x-axis: " << angle << endl;
return;
}
It now remains to create one main() program that calls each of the developed functions in
the correct order. This is done in Program 6.14, which also includes the functions getrec(),
polar(), and showit().
Program 6.14
// This program converts rectangular coordinates to polar coordinates
// Functions used: getrec() - obtain the rectangular coordinates
// : polar() - calculate the polar coordinates
// : showit() - display the polar coordinates
#include <iostream>
#include <cmath>
using namespace std;
void getrec(double&, double&); // function prototype
void polar(double, double, double&, double&); // function prototype
void showit(double, double); // function prototype
墌
340 Modularity Using Functions
int main()
{
double x, y, distance, angle;
getrec(x, y);
polar(x, y, distance, angle);
showit(distance, angle);
return 0;
}
void getrec(double& x, double& y)
{
cout << "Rectangular to Polar Coordinate"
<< " Conversion Programn" << endl;
cout << "Enter the x coordinate: ";
cin >> x;
cout << "Enter the y coordinate: ";
cin >> y;
return;
}
void polar(double x, double y, double& r, double& theta)
{
const double TODEGREES = 180.0/3.141593;
r = sqrt(x * x + y * y);
theta = atan(y/x) * TODEGREES;
return;
}
void showit(double radius, double angle)
{
cout << "nThe polar coordinates are: " << endl;
cout << " Distance from origin: " << radius << endl;
cout << " Angle (in degrees) from x-axis: " << angle << endl;
return;
}
341
Chapter 6
A Case Study: Rectangular to Polar
Coordinate Conversion
The following output was produced from one run of Program 6.14:
Rectangular to Polar Coordinate Conversion Program
Enter the x coordinate: 3
Enter the y coordinate: 4
The polar coordinates are:
Distance from origin: 5
Angle (in degrees) from x-axis: 53.1301
Before leaving Program 6.14, note that an alternative to writing driver programs for each
function during program development is writing a main() program first and adding the
functions later as they’re developed. To do this, you use stubs for each function (see Section 6.1)
and then replace each stub, one at a time, with the completed function.
EXERCISES 6.4
1. (Practice) The volume, v, and side surface area, s, of a cylinder are given by the formulas
v= ␲r2
l
s = 2␲rl
where r is the cylinder’s radius, and l is its length. Using these formulas, write and test a
function named cylinder() that accepts a cylinder’s radius and length and returns its
volume and side surface area.
2. (Practice) Write a C++ program that accepts the rectangular coordinates of two points
(x1, y1) and (x2, y2), calculates the distance of each point from the origin, and calculates
the distance between the two points. The distance, d, between two points is given by
this formula:
d x x y y
= ( ) + ( )
2 1
2
2 1
2
- -
3. (Fluid Mechanics) Fluid flowing in a pipe flows in a smooth pattern, known as laminar
flow, or a turbulent pattern, known as turbulent flow. The velocity, V, that produces each
type of flow in the pipe can be determined by using these formulas:
Vlaminar = (2100 µ) / (r d)
Vturbulent = (4000 µ) / (r d)
Vlaminar is the velocity of the fluid, in ft/sec, that produces a definite laminar flow.
Vturbulent is the velocity of the fluid, in ft/sec, that produces a definite turbulent flow.
µ is the fluid’s viscosity in lbf-sec/ft2
.
ρ is the fluid’s density in slug/ft3
.
d is the pipe’s inside diameter in feet.
342 Modularity Using Functions
Using these formulas, write and test a C++ function named flow() that returns both the
laminar flow velocity, Vlaminar , and the turbulent flow velocity, Vturbulent , using reference
parameters. The function should calculate these velocities for water, which has a viscosity,
µ, of 1.9 × 105
lbf-sec/ft2
and a density, r , of 1.94 slug/ft3
. The pipe diameter should be
passed by value to the flow() function.
4. (Fluid Mechanics) The viscosity and density of three common fluids are listed in the
following chart:
Fluid Viscosity (lbf-sec/ft2
) Density (slug/ft3
)
Ethyl alcohol 2.29 × 105
1.527
Methyl alcohol 1.17 × 105
1.531
Propyl alcohol 4.01 × 105
1.556
Using this data, write and test a C++ function named viscDen() that returns the viscos-
ity and density of the selected fluid by using reference parameters. The type of fluid
should be input to the function as a character that’s passed by value.
5. (Numerical) Many algorithms have been developed for generating pseudorandom
numbers. Some use a counting scheme, such as counting bits beginning at an arbitrary
location in a changing memory. Another scheme, which creates pseudorandom numbers by
performing a calculation, is the power residue method.
The power residue method begins with an odd n-digit integer, referred to as the “seed”
number. The seed is multiplied by the value (10n/2
- 3). Using the lowest n digits of the
result (the “residue”) produces a new seed. Continuing this procedure produces a series
of random numbers, with each new number used as the seed for the next number. If the
original seed has four or more digits (n equal to or greater than 4) and is not divisible by
2 or 5, this procedure yields 5 × 10(n-2)
random numbers before a sequence of numbers
repeats itself. For example, starting with a six-digit seed (n = 6), such as 654321, a series
of 5 × 104
= 50,000 random numbers can be generated.
As an algorithm, the steps in generating pseudorandom numbers with a power residue
method consist of the following:
Step 1: Have a user enter a six-digit integer seed that isn’t divisible by 2 or 5—this
means the number should be an odd number not ending in 5.
Step 2: Multiply the seed number by 997, which is 103
- 3.
Step 3: Extract the lower six digits of the result produced by Step 2. Use this random
number as the next seed.
Step 4: Repeat Steps 2 and 3 for as many random numbers as needed.
343
Chapter 6
A Case Study: Rectangular to Polar
Coordinate Conversion
Therefore, if the user-entered seed number is 654321 (Step 1), the first random number
generated is calculated as follows:
Step 2: 654321 × 997 = 652358037
Step 3: Extract the lower six digits of the number obtained in Step 2, using a standard
programming “trick” that involves the following:
Step 3a: Divide the number by 106
= 1000000 (for example, 652358037 / 1000000
= 652.358037).
Step 3b: Take the integer part of the result of Step 3a (for example, the integer part
of 652.358037 = 652).
Step 3c: Multiply the previous result by 106
(for example, 652 × 106
= 652000000).
Step 3d: Subtract this result from the original number (for example, 652358037 -
652000000 = 358037).
The integer part of a floating-point number can be determined by assigning the floating-
point number to an integer variable or using a C++ cast (see Section 3.3). In this proce-
dure, you’ll use the cast mechanism. The algorithm for producing a random number can
be accomplished with the following code:
i = int(997.0 * x / 1.e6); // take the integer part
x = 997.0 * x - i * 1.e6;
Using this information, do the following:
a. Create a function named randnum() that accepts a floating-point “seed” as a param-
eter and returns a floating-point random number between 0 and 1.e6.
b. Incorporate the randnum() function created in Exercise 5a into a working C++ pro-
gram that produces 10 random numbers between 0 and 1.e6.
c. Test the randomness of the randnum() function created in Exercise 5a by using the
method described in Exercise 9. Try some even seed values and odd seed values end-
ing in 5 to determine whether they affect the randomness of the numbers.
6. (Mathematical) Write a C++ function that determines in which quadrant a line drawn
from the origin resides. The determination of the quadrant is made by using the angle
the line makes with the positive x-axis, as follows:
Angle from the Positive X-Axis Quadrant
Between 0 and 90 degrees 1
Between 90 and 180 degrees 2
Between 180 and 270 degrees 3
Between 270 and 360 degrees 4
344 Modularity Using Functions
Note: If the angle is exactly 0, 90, 180, or 270 degrees, the corresponding line doesn’t reside in
any quadrant; it lies on an axis. For this case, your function should return a 0.
N
O
T
E
7. (Simulation) Write a program to simulate the roll of two dice. If the total of the two dice
is 7 or 11, you win; otherwise, you lose. Embellish this program as much as you like, with
betting, different odds, different combinations for win or lose, stopping play when you
have no money left or reach the house limit, displaying the dice, and so forth. (Hint: Cal-
culate the dots showing on each die with the expression dots = int(6.0 * random
number + 1), where the random number is between 0 and 1.)
8. (Desk Check) The following program uses the same variable names in both the calling
and called functions. Determine whether doing so causes any problem for the compiler.
#include <iostream.h>
int time(int, int); // function prototype
int main()
{
int min, hour, sec;
cout << "Enter two numbers: ";
cin >> min, hour;
sec = time(min, hour);
cout << "The total number of seconds is " << sec << endl;
return 0;
}
int time(int min, int hour)
{
int sec;
sec = (hour * 60 + min) * 60;
return sec;
}
9. (Numerical) Write a program that tests the effectiveness of the rand() library function.
Start by initializing 10 counters to 0. Then generate a large number of pseudorandom integers
between 0 and 9. Each time a 0 occurs, increment the variable you have designated as the
zero counter; when a 1 occurs, increment the counter variable that’s keeping count of the 1s
that occur; and so on. Finally, display the number of 0s, 1s, 2s, and so on that occurred and
the percentage of the time they occurred.
345
Chapter 6
A Case Study: Rectangular to Polar
Coordinate Conversion
6.5 Variable Scope
Now that you have begun to write programs containing more than one function, you can look
more closely at the variables declared in each function and their relationship to variables in
other functions. By their nature, C++ functions are constructed to be independent modules.
As you have seen, values are passed to a function by using the function’s parameter list, and
a value is returned from a function by using a return statement. Seen in this light, a
function can be thought of as a closed box, with slots at the top to receive values and a single
slot at the bottom to return a value (see Figure 6.14).
The metaphor of a closed box is useful because it emphasizes that what goes on inside
the function, including all variable declarations in the function body, is hidden from the view
of all other functions. Because the variables created in a function are conventionally available
only to the function, they are said to be local to the function, or local variables. This term
refers to the scope of an identifier; scope is the section of the program where the identifier,
such as a variable, is valid or “known.” This section of the program is also referred to as
where the variable is “visible.”
A variable can have a local scope or a global scope. A variable with a local scope is simply one
with storage locations set aside for it by a declaration statement in a function body. Local
variables are meaningful only when used in expressions or statements inside the function that
declared them. This means the same variable name can be declared and used in more than one
function. For each function that declares the variable, a separate and distinct variable is created.
All the variables you have used until now have been local variables, a result of placing
declaration statements inside functions and using them as definition statements that cause
the computer to reserve storage for the declared variable. As you’ll see in the next section,
declaration statements can be placed outside functions and also need not act as definitions
that reserve new storage areas for the declared variable.
A variable with global scope, more commonly termed a global variable, has storage created
for it by a declaration statement located outside any function. These variables can be used
by all functions that are placed after the global variable declaration. Program 6.15 shows using
a global variable, and the same variable name has been used on purpose inside both functions
in the program.
Values passed to the function
...
...
A single value directly
returned by the function
Figure 6.14 A function can be considered a closed box
346 Modularity Using Functions
Program 6.15
#include <iostream>
using namespace std;
int firstnum; // create a global variable named firstnum
void valfun(); // function prototype (declaration)
int main()
{
int secnum; // create a local variable named secnum
firstnum = 10; // store a value in the global variable
secnum = 20; // store a value in the local variable
cout << "From main(): firstnum = " << firstnum << endl;
cout << "From main(): secnum = " << secnum << endl;
valfun(); // call the function valfun
cout << "nFrom main() again: firstnum = " << firstnum << endl;
cout << "From main() again: secnum = " << secnum << endl;
return 0;
}
void valfun() // no values are passed to this function
{
int secnum; // create a second local variable named secnum
secnum = 30; // affects only this local variable's value
cout << "nFrom valfun(): firstnum = " << firstnum << endl;
cout << "From valfun(): secnum = " << secnum << endl;
firstnum = 40; // changes firstnum for both functions
return;
}
347
Chapter 6
Variable Scope
The variable firstnum in Program 6.15 is a global variable because its storage is created
by a definition statement located outside a function. Because both main() and valfun()
follow the definition of firstnum, both functions can use this global variable with no
further declaration needed.
Program 6.15 also contains two separate local variables, both named secnum. Storage for
the secnum variable named in main() is created by the definition statement in main().
A different storage area for the secnum variable in valfun() is created by the definition
statement in the valfun() function. Figure 6.15 shows the three distinct storage areas
reserved by the three definition statements in Program 6.15.
Each variable named secnum is local to the function in which its storage is created, and
each variable can be used only from within its corresponding function. Therefore, when
secnum is used in main(), the storage area main() reserves for its secnum variable is
accessed, and when secnum is used in valfun(), the storage area valfun() reserves for
its secnum variable is accessed. The following output is produced when Program 6.15 runs:
From main(): firstnum = 10
From main(): secnum = 20
From valfun(): firstnum = 10
From valfun(): secnum = 30
From main() again: firstnum = 40
From main() again: secnum = 20
firstnum
main()
secnum
storage for
one integer
valfun()
secnum
storage for
one integer
Figure 6.15 The three storage areas reserved by Program 6.15
348 Modularity Using Functions
Now analyze this output to see how local and global variables work. Because firstnum
is a global variable, both main() and valfun() can use and change its value. Initially, both
functions print the value of 10 that main() stored in firstnum. Before returning,
valfun() changes the value of firstnum to 40, which is the value displayed when the
firstnum is next displayed from within main().
Because each function “knows” only its own local variables, main() can send only the
value of its secnum to cout, and valfun() can send only the value of its secnum to
cout. Therefore, whenever secnum is obtained from main(), the value of 20 is displayed,
and whenever secnum is obtained from valfun(), the value 30 is displayed.
C++ doesn’t confuse the two secnum variables because only one function can execute
at a time. While a function is executing, only variables and parameters that are “in scope” for
that function (global and local) can be accessed.
The scope of a variable in no way influences or restricts its data type. Just as a local
variable can be a character, an integer, a Boolean, a double, or any other data type that’s been
introduced, global variables can be all these data types, as illustrated in Figure 6.16. A
variable’s scope is determined by the placement of the definition statement that reserves
storage for it and optionally by a declaration statement that makes it visible, whereas a
variable’s data type is determined by using a keyword (char, int, bool, double, and so
on) before the variable’s name in a declaration statement.
Scope Resolution Operator
When a local variable has the same name as a global variable, all references to the variable
name made within the local variable’s scope refer to the local variable. This situation is
illustrated in Program 6.16, where the variable name number is defined as both a global and
local variable.
When Program 6.16 is run, the following output is displayed:
The value of number is 26.4
char int bool double
local
char int bool double
global
Scope
Data type
Figure 6.16 Relating the scope and type of a variable
349
Chapter 6
Variable Scope
Program 6.16
#include <iostream>
using namespace std;
double number = 42.8; // a global variable named number
int main()
{
double number = 26.4; // a local variable named number
cout << "The value of number is " << number << endl;
return 0;
}
As shown by the program’s output, the local variable name takes precedence over the
global variable. In these cases, you can still access the global variable by using C++’s scope
resolution operator, which has the symbol ::. This operator must be placed immediately
before the variable name, as in ::number. When used in this manner, the :: tells the
compiler to use the global variable. As an example, the scope resolution operator is used in
Program 6.16a.
Program 6.16a
#include <iostream>
using namespace std;
double number = 42.5; // a global variable named number
int main()
{
double number = 26.4; // a local variable named number
cout << "The value of number is " << ::number << endl;
return 0;
}
350 Modularity Using Functions
This is the output produced by Program 6.16a:
The value of number is 42.5
As indicated by this output, the scope resolution operator causes the global, rather than
the local, variable to be accessed.
Misuse of Globals
Global variables allow programmers to “jump around” the normal safeguards provided by
functions. Instead of passing variables to a function, it’s possible to make all variables global.
Do not do this. By indiscriminately making all variables global, you destroy the safeguards C++
provides to make functions independent and insulated from each other, including carefully
designating the type of arguments a function needs, the variables used in the function, and
the value returned.
Using only global variables can be especially disastrous in large programs with many
user-created functions. Because all variables in a function must be declared, creating
functions that use global variables requires remembering to write the appropriate global
declarations at the top of each program using the function—they no longer come along with
the function. More devastating, however, is trying to track down an error in a large program
with global variables. Because a global variable can be accessed and changed by any function
following the global declaration, locating the origin of an erroneous value is a time-consuming
and frustrating task.
Global definitions, however, are sometimes useful in creating variables and constants that
must be shared between many functions. Instead of passing the same variable to each
function, defining the variable once as global is easier. Doing so also alerts anyone reading the
program that many functions use the variable. Most large programs almost always make use
of a few global variables or constants. Smaller programs containing a few functions, however,
should almost never contain global variables.
The misuse of globals doesn’t apply to function prototypes, which typically are global. All
the function prototypes you have used have been of global scope, which declares the
prototype to all subsequent functions. Placing a function prototype in a function makes the
prototype a local declaration, which makes it available only to the function it’s declared
within.
EXERCISES 6.5
1. (Practice) a. For the following section of code, determine the data type and scope of all
declared variables on a separate sheet of paper, using the column headings shown in the
following chart. (The entries for the first variable have been filled in.)
Variable Name Data Type Scope
volts int global to main(), roi(), and step()
351
Chapter 6
Variable Scope
#include <iostream>
using namespace std;
int volts;
long int resistance;
double current;
int main()
{
int power;
double factor, time;
.
.
return 0;
}
double roi(int mat1, int mat2)
{
int count;
double weight;
.
.
return weight;
}
int step(double first, double last)
{
int hours;
double fracpart;
.
.
return 10*hours;
}
b. Draw boxes around the appropriate section of the preceding code to enclose each vari-
able’s scope.
c. Determine the data type of parameters that the roi() and step() functions expect
and the data type of the value these functions return.
2. (Practice) a. For the following section of code, determine the data type and scope of all
declared variables on a separate sheet of paper, using the column headings shown in the
following chart. (The entries for the first variable have been filled in.)
Variable Name Data Type Scope
key char global to main(), func1(), and func2()
#include <iostream>
using namespace std;
char key;
long int number;
墌
352 Modularity Using Functions
int main()
{
int a,b,c;
double x,y;
.
.
return 0;
}
double secnum;
int func1(int num1, int num2)
{
int o,p;
float q;
.
.
return p;
}
double func2(double first, double last)
{
int a,b,c,o,p;
double r;
double s,t,x;
.
.
return s * t;
}
b. Draw a box around the appropriate section of the preceding code to enclose the scope
of the variables key, secnum, y, and r.
c. Determine the data type of the arguments that the func1() and func2() functions
expect and the data type of the value these functions return.
3. (Practice) The term “scope” can also apply to a function’s parameters. What do you
think is the scope of all function parameters?
4. (Practice) Define the scope of the parameter p2 and the variables a, b, c, d, m, n, p, d,
q, and r in the following program structure:
#include <iostream>
using namespace std;
int a, b;
double One(float);
void Two(void);
int main()
{
int c, d;
double e, f;
.
.
return 0;
}
墌
353
Chapter 6
Variable Scope
double One(double p2)
{
char m, n;
.
.
}
void Two(void)
{
int p, d;
double q, r;
.
.
}
5. (Desk Check) Determine the values displayed by each cout statement in the following
program:
#include <iostream>
using namespace std;
int firstnum = 10; // declare and initialize a global variable
void display(); // function prototype
int main()
{
int firstnum = 20; // declare and initialize a local variable
cout << "nThe value of firstnum is " << firstnum << endl;
display();
return 0;
}
void display(void)
{
cout << "The value of firstnum is now " << firstnum << endl;
return;
}
6.6 Variable Storage Categories
The scope of a variable defines the location in a program where that variable can be used.
If you draw a box around the section of program code where each variable is valid, the space
inside the box would represent the variable’s scope. From this viewpoint, a variable’s scope
can be thought of as the space in the program where the variable is valid.
In addition to the space dimension represented by scope, variables have a time
dimension that refers to the length of time storage locations are reserved for a variable. This
time dimension is referred to as the variable’s lifetime. For example, all variable storage
354 Modularity Using Functions
locations are released back to the computer when a program is finished running. However,
while a program is still executing, interim variable storage locations are reserved and
subsequently released back to the computer. Where and how long a variable’s storage
locations are kept before they’re released can be determined by the variable’s storage
category.
Besides having a data type and scope, every variable has a storage category. The four
available storage categories are auto, static, extern, and register. If one of these
category names is used, it must be placed before the variable’s data type in a declaration
statement. The following are examples of declaration statements that include a storage
category designation:
auto int num; // auto storage category and int data type
static int miles; // static storage category and int data type
register int dist; // register storage category and int data type
extern int volts; // extern storage category and int data type
auto float coupon; // auto storage category and float data type
static double yrs; // static storage category and double data type
extern float yld; // extern storage category and float data type
auto char inKey; // auto storage category and char variable type
To understand what a variable’s storage category means, next you examine local variables
(created inside a function) and then global variables (created outside a function).
Local Variable Storage Categories
Local variables can be members only of the auto, static, or register storage categories.
If no category description is included in the declaration statement, the variable is assigned to
the auto category automatically, so auto is the default category C++ uses. All the local
variables you have used have been auto variables because the storage category designation
was omitted.
The term auto is short for “automatic.” Storage for automatic local variables is reserved or
created automatically each time a function declaring automatic variables is called. As long as the
function hasn’t returned control to its calling function, all automatic variables local to the function
are “alive”—meaning storage for the variables is available. When the function returns control to
its calling function, its local automatic variables “die”—meaning storage for the variables is
released back to the computer. This process repeats each time a function is called. For example,
in Program 6.17, the testauto() function is called three times from main().
This is the output produced by Program 6.17:
The value of the automatic variable num is 0
The value of the automatic variable num is 0
The value of the automatic variable num is 0
355
Chapter 6
Variable Storage Categories
Program 6.17
#include <iostream>
using namespace std;
void testauto(); // function prototype
int main()
{
int count; // count is a local auto variable
for(count = 1; count <= 3; count++)
testauto();
return 0;
}
void testauto()
{
int num = 0; // num is a local auto variable
// initialized to 0
cout << "The value of the automatic variable num is "
<< num << endl;
num++;
return;
}
Each time testauto() is called, the automatic variable num is created and initialized
to 0. When the function returns control to main(), the variable num is destroyed along with
any value stored in num. Therefore, the effect of incrementing num in testauto(), before
the function’s return statement, is lost when control is returned to main().
For most applications, the use of automatic variables works just fine. In some cases,
however, you want a function to remember values between function calls, which is the
purpose of the static storage category. A local variable declared as static causes the
program to keep the variable and its latest value even when the function that declared it has
finished executing. The following are examples of static variable declarations:
static int rate;
static double resistance;
static char inKey;
356 Modularity Using Functions
A local static variable isn’t created and destroyed each time the function declaring it
is called. After they’re created, local static variables remain in existence for the program’s
lifetime. This means the last value stored in the variable when the function finishes
executing is available to the function the next time it’s called.
Because local static variables retain their values, they aren’t initialized in a declaration
statement in the same way as automatic variables. To understand why, consider the automatic
declaration int num = 0;, which causes the automatic variable num to be created and set
to 0 each time the declaration is encountered. This procedure is called a runtime initialization
because initialization occurs each time the declaration statement is encountered. This type
of initialization would be disastrous for a static variable because resetting the variable’s
value to 0 each time the function is called destroys the very value you’re trying to save.
Initialization of static variables (both local and global) is done only once, when the
program is first compiled. At compile time, the variable is created and any initialization value
is placed in it.14 Thereafter, the value in the variable is kept without further initialization. To
see how this process works, examine Program 6.18.
Program 6.18
#include <iostream>
using namespace std;
void teststat(); // function prototypeint main()
{
int count; // count is a local auto variable
for(count = 1; count <= 3; count++)
teststat();
return 0;
}
void teststat()
{
static int num = 0; // num is a local static variable
cout << "The value of the static variable num is now "
<< num << endl;
num++;
return;
}
14
Some compilers initialize static local variables the first time the definition statement is executed rather than when the program is compiled.
357
Chapter 6
Variable Storage Categories
This is the output produced by Program 6.18:
The value of the static variable num is now 0
The value of the static variable num is now 1
The value of the static variable num is now 2
As this output shows, the static variable num is set to 0 only once. The teststat()
function then increments this variable just before returning control to main(). The value
num has when leaving the teststat() function is retained and displayed when the
function is next called.
Unlike automatic variables that can be initialized by constants or expressions using both
constants and previously initialized variables, static variables can be initialized only by
using constants or constant expressions, such as 3.2 + 8.0. Also, unlike automatic variables,
all static variables are set to 0 when no explicit initialization is given. Therefore, the
specific initialization of num to 0 in Program 6.17 isn’t required.
The remaining storage category available to local variables, register, isn’t used as
extensively as auto or static variables. The following are examples of register
variable declarations:
register int time;
register double diffren;
register float coupon;
The register variables have the same time duration as auto variables; that is, a local
register variable is created when the function declaring it is entered and is destroyed
when the function finishes running. The only difference between register and auto
variables is where storage for the variable is located.
Storage for all variables (local and global), except register variables, is reserved in the
computer’s memory. Most computers also have a few high-speed storage areas, called
registers, located in the CPU that can also be used for variable storage. Because registers are
located in the CPU, they can be accessed faster than the normal memory storage areas
located in the computer’s memory unit. Also, computer instructions referencing registers
typically require less space than instructions referencing memory locations because there are
fewer registers than memory locations that can be accessed. When the compiler substitutes
a register’s location for a variable during program compilation, the instruction needs less space
than address memory having millions of locations.
Besides decreasing a compiled C++ program’s size, using register variables can
increase the program’s execution speed if your computer supports this data type. Application
programs intended to be executed on different types of computers shouldn’t use registers,
however. Generally, the compiler foils attempts to do so by switching variables declared with
the register storage category to the auto storage category automatically. The only
restriction in using the register storage category is that a register variable’s address
can’t be taken by using the address operator, &. This concept is easier to understand when
you realize that registers don’t have standard memory addresses.
Global Variable Storage Categories
Global variables are created by definition statements external to a function. By their nature,
these externally defined variables don’t come and go with the calling of a function. After a
global variable is created, it exists until the program in which it’s declared has finished
executing. Therefore, global variables can’t be declared as auto or register variables that
358 Modularity Using Functions
are created and destroyed as the program is running. Global variables can be declared with
the static or extern storage category (but not both). The following are examples of
declaration statements including these two category descriptions:
extern int sum;
extern double volts;
static double current;
The static and extern storage categories affect only the scope, not the lifetime, of
global variables. As with static local variables, all global variables are initialized to 0 at
compile time. The purpose of the extern storage category is to extend a global variable’s
scope beyond its normal boundaries. To understand this concept, first note that all the
programs written so far have been contained in one file. Therefore, when you have saved or
retrieved programs, you have needed to give the computer only a single name for your
program. C++ doesn’t require doing this, however.
Large programs typically consist of many functions stored in multiple files. For example,
Figure 6.17 shows the three functions main(), func1(), and func2() stored in one file
and the two functions func3() and func4() stored in a second file.
int volts;
double current;
static double power;
.
.
.
int main()
{
func1();
func2();
func3();
func4();
}
int func1()
{
.
.
.
}
int func2()
{
.
.
.
}
file1 file2
double factor;
int func3()
{
.
.
.
}
int func4()
.
.
.
}
Figure 6.17 A program can extend beyond one file
359
Chapter 6
Variable Storage Categories
For the files shown in Figure 6.17, the global variables volts, current, and power
declared in file1 can be used only by the functions main(), func1(), and func2() in
this file. The single global variable, factor, declared in file2 can be used only by the
functions func3() and func4() in file2.
Although the variable volts has been created in file1, you might want to use it in
file2. To do this, you place the declaration statement extern int volts; in file2,
as shown in Figure 6.18. Putting this statement at the top of file2 extends the scope of
volts into file2 so that it can be used by both func3() and func4(). The extern
designation simply declares a global variable that’s defined in another file. So placing the
statement extern double current; in func4() extends the scope of this global
variable, created in file1, into func4(). Additionally, the scope of the global variable
factor, created in file2, is extended into func1() and func2() by the declaration
statement extern double factor; placed before func1(). Notice that factor is not
available to main().
A declaration statement containing the word extern is different from other declaration
statements, in that it doesn’t cause a new variable to be created by reserving new storage for
the variable. An extern declaration statement simply informs the computer that a global
int volts;
double current;
static double power;
.
.
.
int main()
{
func1();
func2();
func3();
func4();
}
extern double factor;
int func1()
{
.
.
.
}
int func2()
{
.
.
.
}
file1 file2
double factor;
extern int volts;
int func3()
{
.
.
.
}
int func4()
{
extern double current;
.
.
.
}
Figure 6.18 Extending the scope of global variables
360 Modularity Using Functions
variable already exists and can now be used. The actual storage for the variable must be
created somewhere else in the program by using one, and only one, global declaration
statement in which the word extern hasn’t been used. The global variable can, of course,
be initialized in its original declaration. Initialization in an extern declaration statement is
not allowed, however, and causes a compilation error.
The existence of the extern storage category is the reason for carefully distinguishing
between the creation and declaration of a variable. Declaration statements containing the
word extern don’t create new storage areas; they only extend the scope of existing global
variables.
The last global storage category, static, is used to prevent extending a global variable
into a second file. Global static variables are declared in the same way as local static
variables, except the declaration statement is placed outside any function.
The scope of a global static variable can’t be extended beyond the file in which it’s
declared. This rule provides a degree of privacy for global static variables. Because they
are “known” and can be used only in the file where they’re declared, other files can’t access
or change their values. Therefore, global static variables can’t subsequently be extended
to a second file by using an extern declaration statement. Trying to do so results in a
compilation error.
EXERCISES 6.6
1. (Practice) a. List the storage categories available to local variables.
b. List the storage categories available to global variables.
2. (Practice) Describe the difference between a local auto variable and a local static
variable.
3. (Practice) What is the difference between the following functions?
void init1()
{
static int yrs = 1;
墌
Point of Information
Storage Categories
Variables of type auto and register are always local variables. Only non-static
global variables can be declared by using the extern keyword. Doing so extends the
variable’s scope into another file or function.
Making a global variable static makes the variable private to the file in which it’s
declared. Therefore, static variables can’t use the extern keyword. Except for
static variables, all variables are initialized each time they come into scope; static
variables are initialized only once, when they’re defined.
361
Chapter 6
Variable Storage Categories
cout << "The value of yrs is " << yrs << endl;
yrs = yrs + 2;
return;
}
void init2()
{
static int yrs;
yrs = 1;
cout << "The value of yrs is " << yrs << endl;
yrs = yrs + 2;
return;
}
4. (Practice) a. Describe the difference between a global static variable and a global
extern variable.
b. If a variable is declared with an extern storage category, what other declaration
statement must be present somewhere in the program?
5. (Practice) The declaration statement static double resistance; can be used to
create a local or global static variable. What determines the scope of the variable
resistance?
6. (Practice) For the function and variable declarations shown in Figure 6.19, place an
extern declaration to accomplish each of the following:
a. Extend the scope of the global variable choice into file2.
b. Extend the scope of the global variable flag into the average() function only.
c. Extend the scope of the global variable date into average() and variance().
d. Extend the scope of the global variable date into roi() only.
e. Extend the scope of the global variable factor into roi() only.
f. Extend the scope of the global variable bondtype into file1.
g. Extend the scope of the global variable resistance into both watts() and
thrust().
6.7 Common Programming Errors
The following programming errors are common when constructing and using functions:
1. An extremely common error related to functions is passing incorrect data types. The
values passed to a function must correspond to the data types of parameters declared
for the function. One way to verify that correct values have been received is to
362 Modularity Using Functions
display all passed values in the function body before any calculations are made. After
this verification has taken place, you can dispense with the display.15
2. Another common error can occur when the same variable is declared locally in both
the calling and called functions. Even though the variable name is the same, a
change to one local variable does not alter the value in the other local variable.
3. A related error is one that can occur when a local variable has the same name as a
global variable. Inside the function declaring it, the use of the variable’s name affects
only the local variable’s contents unless the scope resolution operator, ::, is used.
4. Another common error is omitting the called function’s prototype before or within
the calling function. The called function must be alerted to the type of value to be
returned, and the function prototype provides this information. The prototype can
be omitted if the called function is placed in a program before its calling function.
Although omitting the prototype and return type for functions returning an integer
is permitted, doing so is poor documenting practice. The actual value a function
returns can be verified by displaying it both before and after it’s returned.
5. The last two common errors are terminating a function header with a semicolon and
forgetting to include the data type of a function’s parameters in the function header.
15
In practice, a good debugger program should be used.
char choice;
int flag;
long date, time;
int main()
{
.
.
.
}
double factor;
double watts()
{
.
.
.
}
double thrust()
{
.
.
.
}
file1 file2
char bondtype;
double resistance;
double roi()
{
.
.
.
}
double average()
{
.
.
.
}
double variance
{
.
.
.
}
Figure 6.19 Files for Exercise 6
363
Chapter 6
Common Programming Errors
6.8 Chapter Summary
1. A function is called by giving its name and passing any data to it in the parentheses
following the name. If a variable is one of the arguments in a function call, the called
function receives a copy of the variable’s value.
2. The common form of a user-written function is as follows:
returnDataType functionName(parameter list)
{
// declarations and other C++ statements;
// return expression;
}
The first line of the function is called the function header. The opening and closing
braces of the function and all statements between these braces constitute the function
body. The returned data type is, by default, an integer when no returned data type is
specified. The parameter list is a comma-separated list of parameter declarations.
3. A function’s return type is the data type of the value the function returns. If no type is
declared, the function is assumed to return an integer value. If the function doesn’t
return a value, it should be declared as a void type.
4. Functions can return at most a single data type value to their calling functions. This
value is the value of the expression in the return statement.
5. Arguments passed to a function, when it’s called, must conform to the parameters
specified by the function header in terms of order, number of arguments, and specified
data type.
6. Using reference parameters, a variable’s address is passed to a function. If a called
function is passed an address, it has the capability to access the calling function’s variable.
Using passed addresses permits a called function to return multiple values.
7. Functions can be declared to all calling functions by means of a function prototype. The
prototype provides a declaration for a function that specifies the data type the function
returns, the function’s name, and the data types of the arguments the function expects.
As with all declarations, a function prototype is terminated with a semicolon and can be
included in local variable declarations or as a global declaration. This is the most common
form of a function prototype:
dataType functionName(parameter data type list);
If the called function is placed above the calling function in the program, no further
declaration is required because the function’s definition serves as a global declaration to
all subsequent functions.
8. Every variable in a program has a scope, which determines where in the program the variable
can be used. A variable’s scope is local or global and is determined by where the variable’s
definition statement is placed. A local variable is defined in a function and can be used only
in its defining function or block. A global variable is defined outside a function and can be
used in any function following the variable’s definition. All global variables that aren’t
specifically initialized by the user are initialized to 0 by the compiler, and global variables not
declared as static can be shared between files by using the keyword extern.
364 Modularity Using Functions
9. Every variable also has a storage category, which determines how long the value in the
variable is retained, also known as the variable’s lifetime. auto variables are local
variables that exist only while their defining function is executing; register variables
are similar to auto variables but are stored in a computer’s registers rather than in
memory; and static variables can be global or local and retain their values while the
program is running. All static variables are set to 0 when they’re defined if the user
doesn’t initialize them explicitly.
Programming Projects for Chapter 6
1. (Practice) The volume, V, of a right circular cylinder is given by the formula
V = ␲ r2
h
where r is the cylinder’s radius and h is the cylinder’s height. Write a function that
accepts two double-precision arguments—a cylinder’s radius and height—and returns the
cylinder’s volume.
2. (Practice) a. Write a function that calculates the area, a, of a circle when its circumfer-
ence, c, is given. This function should call a second function that returns the radius, r,
of the circle, given c. The relevant formulas are r = c/2␲ and a = ␲r2
.
b. Write a C++ program that accepts the value of the circumference from the user,
calculates the radius and area, and displays the calculated values. Your program should
use the functions written for Exercise 2a.
3. (Practice) Write a function named pass() that returns a reject or accept code
depending on whether the mean tolerance of a group of parts is less than or greater than
1.0%. If the average is less than 1.0%, the function should return an A for accept;
otherwise, it should return an R for reject.
4. (Practice) A function is defined by the following code:
double FractionToDecimal(double numerator, double denominator)
{
return (numerator/denominator);
}
a. Write the shortest front-end driver you can to test this function and check the passing
of parameters.
b. Complete the FractionToDecimal() function so that it correctly calculates and
returns the decimal value of values passed to it when it’s called.
5. (Data Processing) a. The time in hours, minutes, and seconds is to be passed to a
function named totsec(). Write totsec() to accept these values, determine the total
number of seconds in the passed data, and display the calculated value.
b. Include the totsec() function written for Exercise 5a in a working program. The
main() function should correctly call totsec() and display the value the function
returns. Use the following test data to verify your program’s operation: hours = 10,
minutes = 36, and seconds = 54. Make sure to do a hand calculation to verify the result
your program displays.
365
Chapter 6
Programming Projects
6. (Data Processing) a. Write a function named daycount() that accepts a month, day, and
year as its input arguments; calculates an integer representing the total number of days from
the turn of the century to the date that’s passed; and returns the calculated integer to the
calling function. For this problem, assume each year has 365 days and each month has
30 days. Test your function by verifying that the date 1/1/00 returns a day count of 1.
b. Include the daycount() function written for Exercise 6a in a working program. The
main() function should correctly call daycount() and display the integer returned
by the function.
7. (Data Processing) a. A clever and simple method of preparing to sort dates into
ascending (increasing) or descending (decreasing) order is to convert a date in the form
month/day/year into an integer number with the formula date = year × 10000 + month ×
100 + day. For example, using this formula, the date 12/6/1988 converts to the integer
19881206, and the date 2/28/2010 converts to the integer 20100228. Sorting the resulting
integer numbers puts dates into the correct order automatically. Using this formula, write
a function named convertdays() that accepts a month, day, and year; converts the
passed data into a single date integer; and returns the integer to the calling function.
b. Include the convertdays() function written for Exercise 7a in a working program.
The main() function should call convertdays() correctly and display the integer
the function returns.
8. (Data Processing) Write a program that reads a key pressed on the keyboard and
displays its code on the screen. Use the program to determine the code for the Enter key.
Then write a function named ReadOneChar() that reads a character and ignores any
succeeding characters until the Enter key is pressed. The entered character should be
returned by ReadOneChar().
9. (Conversion) a. Write and test a C++ function named MakeMilesKmTable() to
display a table of miles converted to kilometers. The arguments to the function should
be the starting and stopping values of miles and the increment. The output should be
a table of miles and their equivalent kilometer values. Use the relationship that 1 mile
= 1.61 kilometers.
b. Modify the function written for Exercise 9a so that two columns are printed. For
example, if the starting value is 1 mile, the ending value is 20 miles, and the
increment is 1, the display should look like the following:
Miles = Kilometers Miles = Kilometers
1 1.61 11 17.70
2 3.22 12 19.31
. . . .
. . . .
10 16.09 20 32.18
(Hint: Find split = (start + stop)/2. Let a loop execute from miles = start to split, and
calculate and print across one line the values of miles and kilometers for both miles and
(miles - start + split + 1).)
366 Modularity Using Functions
10. (Conversion) Your company will soon open a new office in France. So that it can do
business there, your manager has asked you to prepare a comprehensive package that
performs the following American-to-metric conversions on demand:
Measure American Metric Formula
distance inch
foot
yard
mile
centimeter
meter
meter
kilometer
2.54 cm/in
0.305 m/ft
0.9144 m/yd
1.6109 km/mi
temperature Fahrenheit Celsius C = (5/9)(F - 32)
weight pound
ounce
kilogram
gram
0.454 kg/lb
28.35 gm/oz
currency dollar franc entered by the user,
about 5 francs/$
capacity quart
teaspoon
liter
milliliter
0.946 liter/qt
4.9 ml/tsp
math degree
degree
radian
grad
rad = (␲/180)(degree)
grad = (200/180)(degree)
11. (Numerical) Heron’s formula for the area, A, of a triangle with sides of length a, b, and
c is
A s s a s b s c
= ( )( )( )

 

- - -
where
s
a b c
=
+ +
( )
2
Write, test, and execute a function that accepts the values of a, b, and c as parameters
from a calling function, and then calculates the values of s and [s(s - a)(s - b)(s - c)]. If
this quantity is positive, the function calculates A. If the quantity is negative, a, b, and
c do not form a triangle, and the function should set A = -1. The value of A should be
returned by the function.
12. (Numerical) A formula to raise a real number, a, to the real power, b, is given by the
formula
a e
b b a
=
× ( )

 

ln
where a must be positive and b must be positive or 0. Using this formula, write a function
named power() that accepts a and b as real values and returns ab
.
13. (Numerical) A fraction-handling program contains this menu:
A. Add two fractions
B. Convert a fraction to decimal
C. Multiply two fractions
Q. Quit
a. Write C++ code for the program with stub functions for the choices.
367
Chapter 6
Programming Projects
b. Insert the FractionToDecimal() function from Exercise 4b into the code with
commands to pass and display the parameters.
c. Complete the program by replacing the stub functions with functions that perform
appropriate operations.
14. (Numerical) A value that’s sometimes useful is the greatest common divisor of two
integers, n1 and n2. Euclid discovered an efficient method to do this more than 2000 years
ago. For this exercise, however, a stub is enough. Write the integer function stub gcd(n1,
n2). Simply have it return a value that suggests it received its arguments correctly. (Hint: N1
+ N2 is a good choice of return values. Why isn’t N1 / N2 a good choice?)
15. (Numerical) a. Euclid’s method for finding the greatest common divisor (GCD) of two
positive integers consists of the following steps:
Step 1: Divide the larger number by the smaller and retain the remainder.
Step 2: Divide the smaller number by the remainder, again retaining the remainder.
Step 3: Continue dividing the previous remainder by the current remainder until the
remainder is zero, at which point the last non-zero remainder is the GCD.
For example, if the two positive integers are 84 and 49, you have the following:
Step 1: 84/49 yields a remainder of 35.
Step 2: 49/35 yields a remainder of 14.
Step 3: 35/14 yields a remainder of 7.
Step 3: 14/7 yields a remainder of 0.
Therefore, the last non-zero remainder, which is 7, is the GCD of 84 and 49.
Using Euclid’s algorithm, replace the stub function written for Exercise 14 with an actual
function that determines and returns the GCD of its two integer arguments.
16. (Data Processing) a. Write a function named date() that accepts a long integer of the
form yyyymmdd, such as 19980412; determines the corresponding month, day, and year;
and returns these three values to the calling function. For example, if date is called by
using the statement
date(20110412, &month, &day, &year)
the number 4 should be returned in month, the number 12 in day, and the number 2011
in year.
b. Include the date() function written for Exercise 16a in a working program. The
main() function should call date() and display the three values returned by the
function.
368 Modularity Using Functions
17. (Numerical) The determinant of the 2 by 2 matrix
a a
a a
11 12
21 22
is defined as the scalar value a11a22 - a21a12. Similarly, the determinant of a 3 by 3 matrix,
defined as
a a a
a a a
a a a
11 12 13
21 22 23
31 32 33
is determined as
a
a a
a a
a
a a
a a
a
a
11
22 23
32 33
21
12 13
32 33
31
12
- +
a
a
a a
13
22 23
a. Using this information, write and test two functions named det2() and det3().
The det2() function should accept the four coefficients of a 2 by 2 matrix and return
its determinant. The det3() function should accept the nine coefficients of a 3 by
3 matrix and return its determinant by calling det2() to calculate the required 2 by
2 determinants.
b. Write and run a C++ program that accepts the nine coefficients of a 3 by 3 matrix in
one function, passes these coefficients to det3(), and uses a third function to display
the calculated determinant.
369
Chapter 6
Programming Projects
Engineering and Scientific Disciplines
Chemical Engineering
Chemical engineering is the application of the knowledge or techniques of science, par-
ticularly chemistry, to industry. Chemical engineers are responsible for designing and
operating large-scale manufacturing plants for materials that undergo chemical changes
in their production. These materials include all the new and improved products that
have so profoundly affected society, such as petrochemicals, rubbers and polymers, new
metal alloys, industrial and fine chemicals, foods, paints, detergents, cements, pesti-
cides, industrial gases, and medicines.
Chemical engineers also play an important role in pollution abatement and man-
agement of existing energy resources. Because the field of chemical engineering has
become so broad, classifying the activities of chemical engineers is difficult. They can be
subdivided roughly into large-scale production systems (chemical processing) and smaller
scale (molecular) systems.
Chemical Processing
Chemical processing concerns all aspects of designing and operating large chemical-
processing plants. It includes the following areas:
앫 Petrochemicals: Distilling and refining fuels, such as gasoline, synthetic natural
gas, and coal liquefaction and gasification, and producing an infinite variety of
petroleum products, from cosmetics to pharmaceuticals.
앫 Synthetic materials: The process of polymerization, joining simple molecules into
large complex molecules, is responsible for many modern materials, such as nylon,
synthetic rubbers, polystyrene, and a wide variety of plastics and synthetic fibers.
앫 Food and biochemical engineering: The manufacture of packaged food, improve-
ment of food additives, sterilization, and use of industrial bacteria, fungi, and
yeasts in processes such as fermentation.
앫 Unit operations: Analyzing the transport of heat or fluid, such as pumping
chemicals through a pipeline or transferring heat between substances. This area
also includes the effect of heat transfer on chemical reactions, such as oxidation,
chlorination, and so on.
앫 Cryogenic engineering: The design of plants operating at temperatures near
absolute zero.
앫 Electrochemical engineering: Using electricity to alter chemical reactions, such as
electroplating, or designing batteries and energy cells.
앫 Pollution control: Monitoring and reducing the harmful effects of chemical
processing on the environment. Topics of concern are wastewater control, air
pollution abatement, and the economics of pollution control.
continued...
370 Modularity Using Functions
Engineering and Scientific Disciplines
Molecular Systems
This field involves applying laboratory techniques to large-scale processes and includes
the following areas:
앫 Biochemical engineering: Application of enzymes, bacteria, and so on to improve
large-scale chemical processes.
앫 Polymer synthesis: Molecular basis for polymer properties and the chemical
synthesis of new polymers adapted for large-scale production.
앫 Research and development in all areas of chemical processing.
Preparation for a career in chemical engineering requires a thorough background in
physics, chemistry, and mathematics and a knowledge of thermodynamics and physical,
analytic, and organic chemistry. Although extensively trained in chemistry, chemical
engineers differ from chemists, in that their main concern is adapting laboratory tech-
niques to large-scale manufacturing plants.
371
Chapter 6
Programming Projects
This page intentionally left blank
Chapter
7
Arrays
7.1 One-Dimensional Arrays
7.2 Array Initialization
7.3 Declaring and Processing Two-
Dimensional Arrays
7.4 Arrays as Arguments
7.5 A Case Study: Statistical
Analysis
7.6 The Standard Template
Library (STL)
7.7 A Closer Look: Searching and
Sorting
7.8 Common Programming Errors
7.9 Chapter Summary
All the variables you have used so far have a common characteristic: Each variable can be used to store
only a single value at a time. For example, although the variables key, count, and grade declared
in the statements
char key;
int count;
double grade;
are of different data types, each variable can store only one value of the declared data type. These types
of variables are called atomic variables (also referred to as scalar variables), which means their
values can’t be further subdivided or separated into a legitimate data type.
Often you have a set of values, all the same data type, that form a logical group. For example, the
following lists show three groups of items: 1) a list of five double-precision temperatures, 2) a list of
four character codes, and 3) a list of six integer voltages:
Temperatures Codes Voltages
95.75 Z 98
83.0 C 87
97.625 K 92
72.5 L 79
86.25 85
72
A simple list containing items of the same data type is called a one-dimensional array. This chapter
describes how one-dimensional arrays are declared, initialized, stored in a computer, and used. You also
explore the use of one-dimensional arrays with sample programs and see the procedures for declaring
and using multidimensional arrays.
7.1 One-Dimensional Arrays
A one-dimensional array, also referred to as a single-dimensional array, is a list of related values,
all having the same data type, that’s stored with a single group name.1 In C++, as in other
computer languages, the group name is referred to as the array name. For example, consider
this list of temperatures:
95.75
83.0
97.625
72.5
86.25
All the temperatures in the list are double-precision numbers and must be declared as
such. However, each item in the list doesn’t have to be declared separately. The items in the
list can be declared as a single unit and stored under a common variable name called the array
name. For example, temp is used as the name for this list, and the declaration statement
double temp[5]; specifies that temp is to store five double-precision values. Notice that
this declaration statement gives the array (or list) name, the data type of items in the array,
and the number of items in the array. It’s a specific example of the general syntax of an array
declaration statement:
dataType arrayName[number-of-items]
1
Lists can be implemented in a variety of ways. An array is simply one list implementation in which all list elements are of the same type, and
each element is stored consecutively in a set of contiguous memory locations.
374 Arrays
Good programming practice requires defining number-of-items in the array as a
constant before declaring the array. So in practice, the previous array declaration for temp
would be declared with two statements, as in these examples:
const int NUMELS = 5; // define a constant for the number of items
double temp[NUMELS]; // declare the array
The following are other examples of array declarations using this two-line syntax:
const int NUMELS = 6;
int volts[NUMELS];
const int ARRAYSIZE = 4;
char code[ARRAYSIZE];
const int SIZE = 100;
double amount[SIZE];
In these declaration statements, each array is allocated enough memory to hold the
number of data items specified in the declaration statement. For example, the array named
volts has storage reserved for six integers, the array named code has storage reserved for
four characters, and the array named amount has storage reserved for 100 double-precision
numbers. The constant identifiers, NUMELS, ARRAYSIZE, and SIZE, are programmer-
selected names. Figure 7.1 illustrates the storage reserved for the volts and code arrays.
Each item in an array is called an element or a component of the array. The elements in
the arrays shown in Figure 7.1 are stored sequentially, with the first element stored in the
first reserved location, the second element stored in the second reserved location, and so on
until the last element is stored in the last reserved location. This contiguous storage
allocation is a key feature of arrays because it provides a simple mechanism for locating any
element in the list easily.
Because elements in the array are stored sequentially, any single element can be accessed
by giving the array’s name and the element’s position. This position is called the element’s
Enough storage for
six integers
an
integer
an
integer
an
integer
an
integer
an
integer
an
integer
volts
array
a
character
a
character
a
character
a
character
code
array
Enough storage for
four characters
Figure 7.1 The volts and code arrays in memory
375
Chapter 7
One-Dimensional Arrays
index or subscript value. (The two terms are synonymous.) For a one-dimensional array, the
first element has an index of 0, the second element has an index of 1, and so on. In C++, the
array name and element index are combined by listing the index in brackets after the array
name. For example, the declaration double temp[5]; creates five elements, with the
following correspondences:
temp[0] refers to the first temperature stored in the temp array
temp[1] refers to the second temperature stored in the temp array
temp[2] refers to the third temperature stored in the temp array
temp[3] refers to the fourth temperature stored in the temp array
temp[4] refers to the fifth temperature stored in the temp array
Figure 7.2 illustrates the temp array in memory with the correct designation for each
array element. Each element is referred to as an indexed variable or a subscripted variable
because both a variable name (the array name, in this case) and an index or a subscript value
must be used to reference the element. Remember that the index or subscript value gives the
element’s position in the array.
The subscripted variable, temp[0], is read as “temp sub zero” or “temp zero.” This is
a shortened way of saying “the temp array subscripted by zero.” Similarly, temp[1] is read
as “temp sub one” or “temp one,” temp[2] as “temp sub two” or “temp two,” and so on.
Although referencing the first element with an index of 0 might seem unusual, doing so
increases the computer’s speed when it accesses array elements. Internally, unseen by the
programmer, the computer uses the index as an offset from the array’s starting position. As
illustrated in Figure 7.3, the index tells the computer how many elements to skip, starting
from the beginning of the array, to get to the desired element.
Subscripted variables can be used anywhere that scalar (atomic) variables are valid. Here
are examples of using the elements of the temp array:
temp[0] = 95.75;
temp[1] = temp[0] - 11.0;
temp[2] = 5.0 * temp[0];
temp[3] = 79.0;
temp[4] = (temp[1] + temp[2] - 3.1) / 2.2;
sum = temp[0] + temp[1] + temp[2] + temp[3] + temp[4];
The subscript in brackets need not be an integer constant; any expression that evaluates
to an integer can be used as a subscript.2 In each case, of course, the value of the expression
2
Some compilers permit floating-point variables as subscripts; in these cases, the floating-point value is truncated to an integer value.
temp[0] temp[1] temp[2] temp[3] temp[4]
temp
array
element 0 element 1 element 2 element 3 element 4
Figure 7.2 Identifying array elements
376 Arrays
must be within the valid subscript range defined when the array is declared. For example,
assuming i and j are int variables, the following subscripted variables are valid:
temp[i]
temp[2*i]
temp[j-i]
An important advantage of using integer expressions as subscripts is that it allows
sequencing through an array by using a loop. This makes statements such as the following
unnecessary:
sum = temp[0] + temp[1] + temp[2] + temp[3] + temp[4];
The subscript values in this statement can be replaced by a for loop counter to access each
element in the array sequentially. For example, the code
sum = 0; // initialize the sum to zero
for (i = 0; i < 5; i++)
sum = sum + temp[i]; // add in a value
retrieves each array element sequentially and adds the element to sum. The variable i is
used as both the counter in the for loop and a subscript. As i increases by one each time
through the loop, the next element in the array is referenced. The procedure for adding array
elements in the for loop is similar to the accumulation procedure you have used before.
The advantage of using a for loop to sequence through an array becomes apparent when
working with larger arrays. For example, if the temp array contains 100 values rather than just
5, simply changing the number 5 to 100 in the for statement is enough to sequence through
the 100 elements and add each temperature to the sum.
As another example of using a for loop to sequence through an array, say you want to
locate the maximum value in an array of 1000 elements named volts. The procedure to
locate the maximum value is to assume initially that the first element in the array is the
largest number. Then, as you sequence through the array, the maximum is compared to each
Start
here
The array name temp
identifies the starting
location of the array
Skip over three elements to
get to the starting location
of element 3
temp[0] temp[1] temp[2] temp[3] temp[4]
element 3
Figure 7.3 Accessing an array element—element 3
377
Chapter 7
One-Dimensional Arrays
element. When an element with a higher value is located, that element becomes the new
maximum. The following code does the job:
const int NUMELS = 1000;
maximum = volts[0]; // set the maximum to element 0
for (i = 1; i < NUMELS; i++) // cycle through the rest of the array
if (volts[i] > maximum) // compare each element to the maximum
maximum = volts[i]; // capture the new high value
In this code, the for statement consists of one if statement. The search for a new
maximum value starts with element 1 of the array and continues through the last element.
Each element is compared to the current maximum, and when a higher value is encountered,
it becomes the new maximum.
Input and Output of Array Values
An array element can be assigned a value interactively by using a cin statement, as shown
in these examples of data entry statements:
cin >> temp[0];
cin >> temp[1] >> temp[2] >> temp[3];
cin >> temp[4] >> volts[6];
In the first statement, a single value is read and stored in the variable temp[0]. The
second statement causes three values to be read and stored in the variables temp[1],
temp[2], and temp[3]. Finally, the last cin statement is used to read values into the
variables temp[4] and volts[6].
Alternatively, a for loop can be used to cycle through the array for interactive data input.
For example, the following code prompts the user for five temperatures:
const int NUMELS = 5;
for(i = 0; i < NUMELS; i++)
{
cout << "Enter a temperature: ";
cin >> temp[i];
}
Point of Information
Aggregate Data Types
In contrast to atomic types, such as integer and floating-point data, there are aggregate
types. An aggregate type, also referred to as both a structured type and a data struc-
ture, is any type whose values can be decomposed and are related by some defined
structure. Additionally, operations must be available for retrieving and updating values
in the data structure.
One-dimensional arrays are examples of a structured type. In a one-dimensional
array, such as an array of integers, the array is composed of integer values, with the
integers related by their position in the list. Indexed variables provide the means of
accessing and modifying values in the array.
378 Arrays
The first temperature entered is stored in temp[0], the second temperature entered is
stored in temp[1], and so on until five temperatures have been entered.
One caution about storing data in an array: C++ doesn’t check the value of the index
being used (called a bounds check). If an array has been declared as consisting of 10 elements,
for example, and you use an index of 12, which is outside the bounds of the array, C++
doesn’t notify you of the error when the program is compiled. The program attempts to
access element 12 by skipping over the appropriate number of bytes from the start of the
array. Usually, this attempt results in a program crash, but not always. If the referenced
location contains a value of the correct data type, the new value simply overwrites the value
in the referenced memory locations. This leads to more errors, which are troublesome to
locate when the variable legitimately assigned to the storage location is used at a different
point in the program.
During output, an array element can be displayed by using a cout statement, or
complete sections of the array can be displayed by including a cout statement in a for loop.
Examples of both methods are shown:
cout << volts[6];
and
cout << "The value of element " << i << " is " << temp[i];
and
const int NUMELS = 20;
for (k = 5; k < NUMELS; k++)
cout << k << " " << amount[k] << endl;
The first statement displays the value of the subscripted variable volts[6]. The
second statement displays the values of subscript i and of temp[i]. Before this statement
can be executed, i must have an assigned value. Finally, the last example includes a cout
statement in a for loop that displays both the value of the index and the value of elements
5 to 20.
Program 7.1 illustrates these input and output techniques, using an array named temp
that’s defined to store five integer numbers. The program includes two for loops. The first
for loop is used to cycle through each array element and allows the user to input array
values. After five values have been entered, the second for loop is used to display the stored
values.
Program 7.1
#include <iostream>
using namespace std;
int main()
{
const int MAXTEMPS = 5;
int i, temp[MAXTEMPS];
墌
379
Chapter 7
One-Dimensional Arrays
A sample run of Program 7.1 follows:
Enter a temperature: 85
Enter a temperature: 90
Enter a temperature: 78
Enter a temperature: 75
Enter a temperature: 92
temperature 0 is 85
temperature 1 is 90
temperature 2 is 78
temperature 3 is 75
temperature 4 is 92
In reviewing the output of Program 7.1, pay attention to the difference between the
index value displayed and the numerical value stored in the corresponding array element.
The index value refers to the element’s location in the array, and the subscripted variable
refers to the value stored in the designated location.
In addition to simply displaying the values stored in each array element, the elements
can also be processed by referencing the desired element. For example, in Program 7.2, the
value of each element is accumulated in a total, which is displayed after all array elements
have been displayed.
for (i = 0; i < MAXTEMPS; i++) // Enter the temperatures
{
cout << "Enter a temperature: ";
cin >> temp[i];
}
cout << endl;
for (i = 0; i < MAXTEMPS; i++) // Print the temperatures
cout << "temperature " << i << " is " << temp[i] << endl;
return 0;
}
380 Arrays
A sample run of Program 7.2 follows:
Enter a temperature: 85
Enter a temperature: 90
Enter a temperature: 78
Enter a temperature: 75
Enter a temperature: 92
The total of the temperatures 85 90 78 75 92 is 420
Notice that in Program 7.2, unlike Program 7.1, only the values stored in each array
element, not the index numbers, are displayed. Although the second for loop is used to
accumulate the total of each element, the accumulation could also have been accomplished
Program 7.2
#include <iostream>
using namespace std;
int main()
{
const int MAXTEMPS = 5;
int i, temp[MAXTEMPS], total = 0;
for (i = 0; i < MAXTEMPS; i++) // Enter the temperatures
{
cout << "Enter a temperature: ";
cin >> temp[i];
}
cout << "nThe total of the temperatures";
for (i = 0; i < MAXTEMPS; i++) // Display and total the temperatures
{
cout << " " << temp[i];
total = total + temp[i];
}
cout << " is " << total << endl;
return 0;
}
381
Chapter 7
One-Dimensional Arrays
in the first for loop by placing the statement total = total + temp[i]; after the cin
statement used to enter a value. Also, the cout statement used to display the total is placed
outside the second for loop so that the total is displayed only once, after all values have
been added to the total. If this cout statement were placed inside the for loop, five totals
would be displayed, with only the last displayed total containing the sum of all array values.
EXERCISES 7.1
1. (Practice) Write array declarations for the following:
a. A list of 100 double-precision voltages
b. A list of 50 double-precision temperatures
c. A list of 30 characters, each representing a code
d. A list of 100 integer years
e. A list of 32 double-precision velocities
f. A list of 1000 double-precision distances
g. A list of 6 integer code numbers
2. (Practice) Write correct notation for the first, third, and seventh elements of the follow-
ing arrays:
a. int grades[20]
b. double volts[10]
c. double amps[16]
d. int dist[15]
e. double velocity[25]
f. double time[100]
3. (Practice) a. Write input statements using cin that can be used to enter values in the
first, third, and seventh elements of each array declared in Exercise 2.
b. Write a for loop that can be used to enter values for each array declared in Exercise 2.
4. (Practice) a. Write output statements using cout that can be used to display values
from the first, third, and seventh elements of each array declared in Exercise 2.
b. Write a for loop that can be used to display values for the complete array declared in
Exercise 2.
5. (Desk Check) List the elements displayed by the following sections of code:
a. for (m = 1; m <= 5; m++)
cout << a[m] << " ";
b. for (k = 1; k <= 5; k = k + 2)
cout << a[k] << " ";
382 Arrays
c. for (j = 3; j <= 10; j++)
cout << b[j] << " ";
d. for (k = 3; k <= 12; k = k + 3)
cout << b[k] << " ";
e. for (i = 2; i < 11; i = i + 2)
cout << c[i] << " ";
6. (Practice) a. Write a program to input the following values in an array named volts:
11.95, 16.32, 12.15, 8.22, 15.98, 26.22, 13.54, 6.45, and 17.59. After the data has been
entered, have your program display the values.
b. Repeat Exercise 6a, but after the data has been entered, have your program display it
in the following form:
11.95 16.32 12.15
8.22 15.98 26.22
13.54 6.45 17.59
7. (Practice) Write a program to input eight integer numbers in an array named temp. As
each number is input, add the numbers to a total. After all numbers are input, display the
numbers and their average.
8. (Data Processing) a. Write a program to input 10 integer numbers in an array named
fmax and determine the maximum value entered. Your program should contain only one
loop, and the maximum should be determined as array element values are being input.
(Hint: Set the maximum equal to the first array element, which should be input before
the loop used to input the remaining array values.)
b. Repeat Exercise 8a, keeping track of both the maximum element in the array and the
index number for the maximum. After displaying the numbers, print these two mes-
sages (replacing the underlines with the correct values):
The maximum value is: ___
This is element number ___ in the list of numbers
c. Repeat Exercise 8b, but have your program locate the minimum of the data entered.
9. (Data Processing) a. Write a program to input the following integer numbers in an
array named grades: 89, 95, 72, 83, 99, 54, 86, 75, 92, 73, 79, 75, 82, and 73. As each
number is input, add the numbers to a total. After all numbers are input and the total is
obtained, calculate the average of the numbers, and use the average to determine the
deviation of each value from the average. Store each deviation in an array named
deviation. Each deviation is obtained as the element value less the average of all the
data. Have your program display each deviation with its corresponding element from the
grades array.
b. Calculate the variance of the data used in Exercise 9a. The variance is obtained by
squaring each deviation and dividing the sum of the squared deviations by the num-
ber of deviations.
10. (Electrical Eng.) Write a program that specifies three one-dimensional arrays named cur-
rent, resistance, and volts. Each array should be capable of holding 10 elements.
383
Chapter 7
One-Dimensional Arrays
Using a for loop, input values for the current and resistance arrays. The entries in
the volts array should be the product of the corresponding values in the current and
resistance arrays (so volts[i] = current [i] * resistance[i]). After all the
data has been entered, display the following output, with the appropriate value under each
column heading:
Current Resistance Volts
7.2 Array Initialization
Array elements can be initialized in their declaration statements in the same manner as scalar
variables, except the initializing elements must be included in braces, as shown in these
examples:
int temp[5] = {98, 87, 92, 79, 85};
char codes[6] = {'s', 'a', 'm', 'p', 'l', 'e'};
double slopes[7] = {11.96, 6.43, 2.58, .86, 5.89, 7.56, 8.22};
Initializers are applied in the order they are written, with the first value used to initialize
element 0, the second value used to initialize element 1, and so on, until all values have been
used. For example, in the declaration
int temp[5] = {98, 87, 92, 79, 85};
temp[0] is initialized to 98, temp[1] is initialized to 87, temp[2] is initialized to 92,
temp[3] is initialized to 79, and temp[4] is initialized to 85.
Because white space is ignored in C++, initializations can be continued across multiple
lines. For example, the following declaration uses four lines to initialize all the array
elements:
int gallons[20] = {19, 16, 14, 19, 20, 18, // initializing values
12, 10, 22, 15, 18, 17, // can extend across
16, 14, 23, 19, 15, 18, // multiple lines
21, 5};
If the number of initializers is less than the declared number of elements listed in square
brackets, the initializers are applied starting with array element 0. Therefore, in the
declaration
double length[7] = {7.8, 6.4, 4.9, 11.2};
only length[0], length[1], length[2], and length[3] are initialized with the listed
values. The other array elements are initialized to 0.
Unfortunately, there’s no method of indicating repetition of an initialization value or of
initializing later array elements without first specifying values for earlier elements.
A unique feature of initializers is that the array size can be omitted when initializing
values are included in the declaration statement. For example, the following declaration
reserves enough storage room for five elements:
int gallons[] = {16, 12, 10, 14, 11};
384 Arrays
Similarly, the following two declarations are equivalent:
char codes[6] = {'s', 'a', 'm', 'p', 'l', 'e'};
char codes[] = {'s', 'a', 'm', 'p', 'l', 'e'};
Both these declarations set aside six character locations for an array named codes. An
interesting and useful simplification can also be used when initializing character arrays. For
example, the following declaration uses the string "sample" to initialize the codes array:
char codes[] = "sample"; // no braces or commas
Recall that a string is any sequence of characters enclosed in quotation marks. The
preceding declaration creates an array named codes with seven elements and fills the array
with the seven characters shown in Figure 7.4. The first six characters, as expected, consist
of the letters s, a, m, p, l, and e. The last character, the escape sequence 0, is called the
null character. The null character is appended automatically to all strings used to initialize a
character array. It’s what distinguishes a C-string from a string class string. This character
has an internal storage code numerically equal to zero. (The storage code for the 0 character
has a numerical value of decimal 48, so the computer can’t confuse the two.) The null
character is used as a sentinel to mark the end of a string.
After values have been assigned to array elements, through initialization in the declara-
tion statement or with interactive input, array elements can be processed as described in the
previous section. For example, Program 7.3 shows the initialization of array elements in the
array declaration statement, and then uses a for loop to locate the maximum value stored
in the array. The following output is produced by Program 7.3:
The maximum value is 27
codes[0] codes[1] codes[2] codes[3] codes[4] codes[5] codes[6]
s a m p l e 0
Figure 7.4 Initializing a character array with a string adds a terminating 0 character
385
Chapter 7
Array Initialization
EXERCISES 7.2
1. (Practice) Write array declarations, including initializers, for the following:
a. A list of 10 integer voltages: 89, 75, 82, 93, 78, 95, 81, 88, 77, and 82.
b. A list of five double-precision slopes: 11.62, 13.98, 18.45, 12.68, and 14.76.
c. A list of 100 double-precision distances; the first six distances are 6.29, 6.95, 7.25, 7.35,
7.40, and 7.42.
d. A list of 64 double-precision temperatures; the first 10 temperatures are 78.2, 69.6,
68.5, 83.9, 55.4, 67.0, 49.8, 58.3, 62.5, and 71.6.
e. A list of 15 character codes; the first seven codes are f, j, m, q, t, w, and z.
2. (Data Processing) Write an array declaration statement that stores the following values
in an array named volts: 16.24, 18.98, 23.75, 16.29, 19.54, 14.22, 11.13, and 15.39.
Include these statements in a program that displays the values in the array.
3. (Data Processing) Write a program that uses an array declaration statement to initialize
the following numbers in an array named slopes: 17.24, 25.63, 5.94, 33.92, 3.71, 32.84,
35.93, 18.24, and 6.92. Your program should locate and display the maximum and mini-
mum values in the array.
Program 7.3
#include <iostream>
using namespace std;
int main()
{
const int MAXELS = 5;
int i, max, nums[MAXELS] = {2, 18, 1, 27, 16};
max = nums[0];
for (i = 1; i < MAXELS; i++)
if (max < nums[i])
max = nums[i];
cout << "The maximum value is " << max << endl;
return 0;
}
386 Arrays
4. (Electrical Eng.) Write a program that stores the following resistance values in an array
named resistance: 16, 27, 39, 56, and 81. Your program should also create two arrays
named current and power, each capable of storing five double-precision numbers. Using a
for loop and a cin statement, have your program accept five user-input numbers in the
current array when the program is run. Your program should store the product of the values
of the squares of the current array and the resistance array in the power array. For
example, use power[1] = resistance[1] * pow(current[1],2). Your program
should then display the following output (fill in the chart):
Resistance Current Power
16
27
39
56
81
Total:
5. (Practice) a. Write a declaration to store the string "This is a test" in an array
named strtest. Include the declaration in a program to display the message, using the
following loop:
for (i = 0; i < NUMDISPLAY; i++)
cout << strtest[i];
NUMDISPLAY is a named constant for the number 14.
b. Modify the for statement in Exercise 5a to display only the array characters t, e, s,
and t.
c. Include the array declaration written in Exercise 5a in a program that uses a cout state-
ment to display characters in the array. For example, the statement cout << strtest;
causes the string stored in the strtest array to be displayed. Using this statement
requires having the end-of-string marker, 0, as the last character in the array.
d. Repeat Exercise 5a, using a while loop. (Hint: Stop the loop when the 0 escape
sequence is detected. The expression while (strtest[i] != '0') can be used.)
387
Chapter 7
Array Initialization
7.3 Declaring and Processing Two-Dimensional Arrays
A two-dimensional array, sometimes referred to as a table, consists of both rows and columns
of elements. For example, the following array of numbers is called a two-dimensional array
of integers:
8 16 9 52
3 15 27 6
14 25 2 10
This array consists of three rows and four columns. To reserve storage for this array, both
the number of rows and the number of columns must be included in the array’s declaration.
Calling the array val, the following is the correct specification for this two-dimensional array:
int val[3][4];
Similarly, the declarations
double volts[10][5];
char code[6][26];
specify that the array volts consists of 10 rows and 5 columns of floating-point numbers,
and the array code consists of 6 rows and 26 columns, with each element capable of holding
one character.
To locate each element in a two-dimensional array, you use its position in the array. As
shown in Figure 7.5, the term val[1][3] uniquely identifies the element in row 1, column
3. As with one-dimensional array variables, two-dimensional array variables can be used
anywhere that scalar variables are valid, as shown in these examples using elements of the
val array:
watts = val[2][3];
val[0][0] = 62;
newnum = 4 * (val[1][0] - 5);
sumRow0 = val[0][0] + val[0][1] + val[0][2] + val[0][3];
The last statement causes the values of the four elements in row 0 to be added and the
sum to be stored in the scalar variable sumRow0.
Row 0
Row 1
Row 2
8
3
14
Col. 0
16
15
25
Col. 1
9
27
2
Col. 2
52
6
10
Col. 3
val[1][3]
Row
position
Column
position
Figure 7.5 Each array element is identified by its row and column position
388 Arrays
As with one-dimensional arrays, two-dimensional arrays can be initialized in their
declaration statements by listing the initial values inside braces and separating them with
commas. Additionally, braces can be used to separate rows. For example, the declaration
int val[3][4] = { {8,16,9,52},
{3,15,27,6},
{14,25,2,10} };
declares val as an array of integers with three rows and four columns, with the initial values
given in the declaration. The first set of internal braces contains values for row 0 of the array,
the second set of internal braces contains values for row 1, and the third set of braces contains
values for row 2.
Although the commas in the initialization braces are always required, the inner braces can
be omitted. Without them, the initialization for val can be written as follows:
int val[3][4] = {8,16,9,52,
3,15,27,6,
14,25,2,10};
Separating initial values into rows in the declaration statement isn’t necessary because
the compiler assigns values beginning with the [0][0] element and proceeds row by row
to fill in the remaining values. Therefore, the initialization
int val[3][4] = {8,16,9,52,3,15,27,6,14,25,2,10};
is equally valid but doesn’t clearly indicate to another programmer where one row ends and
another begins.
As shown in Figure 7.6, a two-dimensional array is initialized in row order. The elements
of row 0 are initialized, then the elements of row 1 are initialized, and so on, until the
initializations are completed. This row ordering is the same ordering used to store two-
dimensional arrays. That is, array element [0][0] is stored first, followed by element
[0][1], then element [0][2], and so on. Following row 1’s elements are row 2’s elements,
and so on for all rows in the array.
Initialization
starts with this
element
val[0][0]=8 val[0][1]=16 val[0][2]=9 val[0][3]=52
val[1][0]=3 val[1][1]=15 val[1][3]=6
val[1][2]=27
val[2][0]=14 val[2][1]=25 val[2][2]=2 val[2][3]=10
Figure 7.6 Storage and initialization of the val array
389
Chapter 7
Declaring and Processing Two-
Dimensional Arrays
As with one-dimensional arrays, two-dimensional arrays can be displayed with element
notation or by using loops (while or for). Program 7.4, which displays all elements of a
3-by-4 two-dimensional array, shows these two techniques. Notice that constants are used to
define the array’s rows and columns.
This is the display produced by Program 7.4:
Display of val array by explicit element
8 16 9 52
3 15 27 6
14 25 2 10
Program 7.4
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const int NUMROWS = 3;
const int NUMCOLS = 4;
int i, j;
int val[NUMROWS][NUMCOLS] = {8,16,9,52,3,15,27,6,14,25,2,10};
cout << "nDisplay of val array by explicit element"
<< endl << setw(4) << val[0][0] << setw(4) << val[0][1]
<< setw(4) << val[0][2] << setw(4) << val[0][3]
<< endl << setw(4) << val[1][0] << setw(4) << val[1][1]
<< setw(4) << val[1][2] << setw(4) << val[1][3]
<< endl << setw(4) << val[2][0] << setw(4) << val[2][1]
<< setw(4) << val[2][2] << setw(4) << val[2][3];
cout << "nnDisplay of val array using a nested for loop";
for (i = 0; i < NUMROWS; i++)
{
cout << endl; // print a new line for each row
for (j = 0; j < NUMCOLS; j++)
cout << setw(4) << val[i][j];
}
cout << endl;
return 0;
}
390 Arrays
Display of val array using a nested for loop
8 16 9 52
3 15 27 6
14 25 2 10
The first display of the val array produced by Program 7.4 is constructed by designating
each array element. The second display of array element values, which is identical to the first,
is produced by using a nested for loop. Nested loops are especially useful when dealing with
two-dimensional arrays because they allow the programmer to designate and cycle through each
element easily. In Program 7.4, the variable i controls the outer loop, and the variable j controls
the inner loop. Each pass through the outer loop corresponds to a single row, with the inner loop
supplying the column elements. After a complete row is printed, a new line is started for the next
row. The result is a display of the array in a row-by-row fashion.
After two-dimensional array elements have been assigned, array processing can begin.
Typically, for loops are used to process two-dimensional arrays because, as noted previously,
they allow the programmer to designate and cycle through each array element easily. For
example, the nested for loop in Program 7.5 is used to multiply each element in the val
array by the scalar number 10 and display the resulting value.
Program 7.5
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const int NUMROWS = 3;
const int NUMCOLS = 4;
int i, j;
int val[NUMROWS][NUMCOLS] = {8,16,9,52,
3,15,27,6,
14,25,2,10};
// multiply each element by 10 and display it
cout << "nDisplay of multiplied elements";
for (i = 0; i < NUMROWS; i++)
{
cout << endl; // start each row on a new line
for (j = 0; j < NUMCOLS; j++)
{
val[i][j] = val[i][j] * 10;
cout << setw(5) << val[i][j];
} // end of inner loop
} // end of outer loop
cout << endl;
return 0;
}
391
Chapter 7
Declaring and Processing Two-
Dimensional Arrays
Following is the output produced by Program 7.5:
Display of multiplied elements
80 160 90 520
30 150 270 60
140 250 20 100
Larger Dimensional Arrays
Although arrays with more than two dimensions aren’t commonly used, C++ does allow declaring
any number of dimensions by listing the maximum size of all dimensions for the array. For
example, the declaration int response [4][10][6]; declares a three-dimensional
array.The first element in the array is designated as response[0][0][0] and the last element
as response[3][9][5].
As shown in Figure 7.7, you can think of a three-dimensional array as a book of data
tables. Using this analogy, think of the first index as the location of the desired row in a table,
the second index value as the desired column, and the third index value, often called the
“rank,” as the page number of the selected table.
Similarly, arrays of any dimension can be declared. Conceptually, a four-dimensional array
can be represented as a shelf of books, with the fourth dimension used to declare a selected
book on the shelf, and a five-dimensional array can be viewed as a bookcase filled with books,
with the fifth dimension referring to a selected shelf in the bookcase. Using the same analogy,
a six-dimensional array can be thought of as a single row of bookcases, with the sixth
dimension referring to the desired bookcase in the row; a seven-dimensional array can be
thought of as multiple rows of bookcases, with the seventh dimension referring to the desired
row, and so on. Alternatively, arrays of three, four, five, six, and so on dimensional arrays can
be viewed as mathematical n-tuples of order three, four, five, six, and so forth.
Row
index
Column
index
Page number
index (rank)
Figure 7.7 Representation of a three-dimensional array
392 Arrays
EXERCISES 7.3
1. (Practice) Write specification statements for the following:
a. An array of integers with 6 rows and 10 columns
b. An array of integers with 2 rows and 5 columns
c. An array of characters with 7 rows and 12 columns
d. An array of characters with 15 rows and 7 columns
e. An array of double-precision numbers with 10 rows and 25 columns
f. An array of double-precision numbers with 16 rows and 8 columns
2. (Desk Check) Determine the output produced by the following program:
#include <iostream>
using namespace std;
int main()
{
int i, j, val[3][4] = {8,16,9,52,3,15,27,6,14,25,2,10};
for (i = 0; i < 3; ++i)
for (j = 0; j < 4; ++j)
cout << " " << val[i][j];
return 0;
}
3. (Practice) a. Write a C++ program that adds the values of all elements in the val array
used in Exercise 2 and displays the total.
b. Modify the program written for Exercise 3a to display the total of each row separately.
4. (Practice) Write a C++ program that adds equivalent elements of the two-dimensional
arrays named first and second. Both arrays should have two rows and three columns.
For example, element [1][2] of the resulting array should be the sum of
first[1][2] and second[1][2]. The first and second arrays should be initialized as
follows:
first second
16 18 23 24 52 77
54 91 11 16 19 59
5. (Data Processing) a. Write a C++ program that finds and displays the maximum value
in a two-dimensional array of integers. The array should be declared as a 4-by-5 array of
integers and initialized with the data 16, 22, 99, 4, 18, -258, 4, 101, 5, 98, 105, 6, 15, 2,
45, 33, 88, 72, 16, and 3.
b. Modify the program written in Exercise 5a so that it also displays the maximum val-
ue’s row and column subscript numbers.
393
Chapter 7
Declaring and Processing Two-
Dimensional Arrays
6. (Data Processing) Write a C++ program that selects the values in a 4-by-5 array of posi-
tive integers in increasing order and stores the selected values in the one-dimensional
array named sort. Use the data statement in Exercise 5a to initialize the two-
dimensional array.
7. (Electrical Eng.) a. An engineer has constructed a two-dimensional array of real num-
bers with three rows and five columns. This array currently contains test voltages of an
amplifier. Write a C++ program that interactively inputs 15 array values, and then deter-
mines the total number of voltages in these ranges: less than 60, greater than or equal to
60 and less than 70, greater than or equal to 70 and less than 80, greater than or equal to
80 and less than 90, and greater than or equal to 90.
b. Entering 15 voltages each time the program written for Exercise 7a runs is cumbersome.
What method could be used for initializing the array during the testing phase?
c. How might the program you wrote for Exercise 7a be modified to include the case of
no voltage being present? That is, what voltage could be used to indicate an invalid
voltage, and how would your program have to be modified to exclude counting such a
voltage?
7.4 Arrays as Arguments
Array elements are passed to a called function in the same manner as scalar variables; they
are simply included as subscripted variables when the function call is made. For example, the
following function call passes the values of the elements volts[2] and volts[6] to the
function findMin():
findMin(volts[2], volts[6]);
Passing a complete array of values to a function is, in many respects, easier than passing
each element. The called function receives access to the actual array rather than a copy of
values in the array. For example, if volts is an array, the function call findMax(volts);
makes the complete volts array available to the findMax() function. This function call
is different from passing a single variable to a function.
Recall that when a single scalar argument is passed to a function (see Section 6.1), the
called function receives only a copy of the passed value, which is stored in one of the
function’s parameters. If arrays were passed in this manner, a copy of the complete array
would have to be created. For large arrays, making copies for each function call would waste
computer storage and frustrate the effort to return multiple-element changes made by the
called program. (Remember that a function returns at most one direct value.)
To avoid these problems, the called function is given direct access to the original array.3
In this way, any changes the called function makes are made directly to the array. For the
following specific examples of function calls, the arrays nums, keys, volts, and current
are declared as shown:
int nums[5]; // an array of five integers
char keys[256]; // an array of 256 characters
double volts[500], current[500]; // two arrays of 500 doubles
3
The called function has access to the original array because the array’s starting address is actually passed as an argument. The formal parameter
receiving this address argument is a pointer. Chapter 12 explains the intimate relationship between array names and pointers.
394 Arrays
For these arrays, the following function calls can be made; note that in each case, the
called function receives direct access to the named array:
findMax(nums);
findCh(keys);
calcTot(nums, volts, current);
On the receiving side, the called function must be alerted that an array is being made
available. For example, the following are suitable function headers for the previous functions:
int findMax(int vals[5])
char findCh(char in_keys[256])
void calcTot(int arr1[5], double arr2[500], double arr3[500])
In each function header, the programmer chooses the names in the parameter list.
However, the parameter names used by the functions still refer to the original array created
outside the function, as Program 7.6 makes clear.
Program 7.6
#include <iostream>
using namespace std;
const int MAXELS = 5;
int findMax(int [MAXELS]); // function prototype
int main()
{
int nums[MAXELS] = {2, 18, 1, 27, 16};
cout << "The maximum value is " << findMax(nums) << endl;
return 0;
}
// find the maximum value
int findMax(int vals[MAXELS])
{
int i, max = vals[0];
for (i = 1; i < MAXELS; i++)
if (max < vals[i]) max = vals[i];
return max;
}
395
Chapter 7
Arrays as Arguments
Notice that the function prototype for findMax() declares that findMax returns an
integer and expects an array of five integers as an actual argument. It’s also important to know
that only one array is created in Program 7.6. In main(), this array is known as nums, and
in findMax(), the array is known as vals. As illustrated in Figure 7.8, both names refer
to the same array, so vals[3] is the same element as nums[3].
The parameter declaration in the findMax() header actually contains extra information
not required by the function. All that findMax() must know is that the parameter vals
references an array of integers. Because the array has been created in main() and no
additional storage space is needed in findMax(), the declaration for vals can omit the
array size. Therefore, the following is an alternative function header:
int findMax(int vals[])
This form of the function header makes more sense when you realize that only one item
is actually passed to findMax() when the function is called: the starting address of the num
array, as shown in Figure 7.9.
Because only the starting address of vals is passed to findMax(), the number of
elements in the array need not be included in the declaration for vals.4 In fact, generally
4
An important consequence of passing the starting address is that findMax() has direct access to the passed array. This access means any change
to an element of the vals array is a change to the nums array. This result is much different from the situation with scalar variables, where the
called function doesn’t receive direct access to the passed variable.
int main()
{
int nums[5];
.
.
.
findMax(nums) ;
returns 0;
}
int findMax(int vals[5])
.
.
.
}
In main(): nums[1] nums[2] nums[3] nums[4]
In findMax(): vals[1] vals[2] vals[3] vals[4]
This creates the array
These reference
the same array
nums[0]
vals[0]
Figure 7.8 Only one array is created
396 Arrays
it’s advisable to omit the array size from the function header. For example, the more general form
of findMax() can be used to find the maximum value of an integer array of arbitrary size:
int findMax(int vals[], int numels) //find the maximum value
{
int i, max = vals[0];
for (i = 1; i < numels; i++)
if (max < vals[i])
max = vals[i];
return max;
}
The more general form of findMax() declares that the function returns an integer
value. The function expects the starting address of an integer array and the number of
elements in the array as arguments. Then, using the number of elements as the boundary for
its search, the function’s for loop causes each array element to be examined in sequential
order to locate the maximum value. Program 7.7 shows using findMax() in a complete
program.
Starting address
of nums array is &nums[0].
This is passed to
the function
nums[0] nums[1] nums[2] nums[3] nums[4]
findMax(nums);
Figure 7.9 The array’s starting address is passed
Program 7.7
#include <iostream>
using namespace std;
int findMax(int [], int); // function prototype
int main()
{
墌
397
Chapter 7
Arrays as Arguments
The following is the output displayed by Programs 7.6 and 7.7:
The maximum value is 27
Passing two-dimensional arrays to a function is identical to passing one-dimensional
arrays. The called function receives access to the entire array. For example, if val is a
two-dimensional array, the function call display(val); makes the complete val array
available to the function display(). Consequently, any changes display() makes are
made directly to the val array. As further examples, if the following two-dimensional arrays
named test, factors, and thrusts are declared as
int test[7][9];
float factors[26][10];
double thrusts[256][52];
then the following function calls are valid:
findMax(test);
obtain(factors);
average(thrusts);
On the receiving side, the called function must be alerted that a two-dimensional array
is being made available. For example, assuming the previous functions return an integer, the
following are suitable function headers:
int findMax(int nums[7][9])
int obtain(float values[26][10])
int average(double vals[256][52])
const int MAXELS = 5;
int nums[MAXELS] = {2, 18, 1, 27, 16};
cout << "The maximum value is "
<< findMax(nums, MAXELS) << endl;
return 0;
}
// find the maximum value
int findMax(int vals[], int numels)
{
int i, max = vals[0];
for (i = 1; i < numels; i++)
if (max < vals[i]) max = vals[i];
return max;
}
398 Arrays
The parameter names chosen are used inside the function body. However, the parameter
names still refer to the original array created outside the function. Program 7.8 shows passing
a two-dimensional array to a function that displays the array’s values.
Only one array is created in Program 7.8. This array is known as val in main() and as
nums in display(). Therefore, val[0][2] refers to the same element as nums[0][2].
Notice the use of the nested for loop in Program 7.8 for cycling through each array
element. The variable rownum controls the outer loop, and the variable colnum controls the
inner loop. For each pass through the outer loop, which corresponds to a single row, the
innerloop makes one pass through the column elements. After a complete row is printed, a
Program 7.8
#include <iostream>
#include <iomanip>
using namespace std;
const int ROWS = 3;
const int COLS = 4;
void display(int [ROWS][COLS]); // function prototype
int main()
{
int val[ROWS][COLS] = {8,16,9,52,
3,15,27,6,
14,25,2,10};
display(val);
return 0;
}
void display(int nums[ROWS][COLS])
{
int rownum, colnum;
for (rownum = 0; rownum < ROWS; rownum++)
{
for(colnum = 0; colnum < COLS; colnum++)
cout << setw(4) <<nums[rownum][colnum];
cout << endl;
}
return;
}
399
Chapter 7
Arrays as Arguments
new line is started for the next row. The result is a display of the array in a row-by-row
fashion:
8 16 9 52
3 15 27 6
14 25 2 10
The parameter declaration for nums in display() contains extra information not
required by the function. The declaration for nums can omit the row size of the array, so the
following is an alternative function prototype:
display(int nums[][4]);
The reason the column size must be included but the row size is optional becomes
obvious when you see how array elements are stored in memory. Starting with element
val[0][0], each succeeding element is stored consecutively, row by row, as val[0][0],
val[0][1], val[0][2], val[0][3], val[1][0], val[1][1], and so on, as illustrated
in Figure 7.10.
As with all array accesses, a single element of the val array is obtained by adding an
offset to the array’s starting location. For example, element val[1][3] of the val array in
Figure 7.10 is located at an offset of 28 bytes from the start of the array. Internally, the
compiler uses the row index, column index, and column size to determine this offset, using
the following calculation (assuming 4 bytes for an int):
The column size is necessary in the offset calculation so that the compiler can determine
the number of positions to skip over to get to the correct row.
val[1][3]
Column 0 Column 1 Column 2 Column3
Row 0
Row 1
Row 2
Figure 7.10 Storage of the val array
No. of bytes in a complete row
Offset = [(3 4)+ [1 (4 4)] = 28 bytes
Bytes per integer
Column size
Row index
Column index
× × ×
400 Arrays
Internal Array Element Location Algorithm5
Internally, each element in an array is obtained by adding an offset to the starting address of
the array. Therefore, the memory address of each array element is calculated internally as
follows:
Address of element i = starting array address + the offset
For one-dimensional arrays, the offset to the element with index i is calculated as
follows:
Offset = i * the size of an element
For two-dimensional arrays, the same address calculation is made, except that the offset
is determined as
Offset = column index value * the size of an element
+ row index value * number of bytes in a complete row
where the number of bytes in a complete row is calculated as follows:
number of bytes in a complete row =
maximum column specification * the size of an element
For example, as illustrated in Figure 7.11, for a one-dimensional array of integers in
which each integer is stored with 4 bytes, the offset to the element with an index value of
5 is 5 * 4 = 20. Using the address operator, &, you can check this address algorithm, as shown
in Program 7.9.
5
This topic is optional and can be omitted without loss of subject continuity.
An integer An integer An integer An integer An integer An integer
Index = 0 Index = 1 Index = 2 Index = 3 Index = 4 Index = 5
Starting address
of the array
4 bytes 4 bytes 4 bytes 4 bytes 4 bytes
Offset to Element 5 = 20 bytes
Address of
Element 5
Figure 7.11 The offset to the element with an index value of 5
401
Chapter 7
Arrays as Arguments
Here is a sample output produced by Program 7.9:
The starting address of the arr array is: 1244796
The storage size of each array element is: 4
The address of element number 5 is: 1244816
The starting address of the array,
displayed using the notation arr, is: 1244796
Notice that the addresses have been displayed in decimal form, and element 5 is 20 bytes
beyond the array’s starting address. Also, the array’s starting address is the same as the address
of element 0, which is coded as &arr[0]. Alternatively, as shown by the displayed line, the
starting array address can also be obtained as arr, which is the array name, because an array
name is a pointer constant, which is an address. (Chapter 12 explains the close association of
array names and pointers.)
Program 7.9
#include <iostream>
using namespace std;
int main()
{
const int NUMELS = 20;
int arr[NUMELS];
cout << "The starting address of the arr array is: "
<< int (&arr[0]) << endl;
cout << "The storage size of each array element is: "
<< sizeof(int) << endl;
cout << "The address of element number 5 is: "
<< int (&arr[5]) << endl;
cout << "The starting address of the array, "
<< "ndisplayed using the notation arr, is: "
<< int (arr) << endl;
return 0;
}
402 Arrays
EXERCISES 7.4
1. (Practice) The following declaration was used to create the volts array:
int volts[500];
Write two different function headers for a function named sortArray() that accepts
the volts array as a parameter named inArray.
2. (Practice) The following declaration was used to create the factors array:
double factors[256];
Write two different function headers for a function named findKey() that accepts the
factors array as a parameter named select.
3. (Practice) The following declaration was used to create the power array:
double power[256];
Write two different function headers for a function named prime() that accepts the
power array as an argument named watts.
4. (Modify) a. Modify the findMax() function in Program 7.6 to locate the minimum
value of the passed array.
b. Include the function written in Exercise 4a in a complete program and run the
program.
5. (Practice) Write a program that has a declaration in main() to store the following num-
bers in an array named temps: 6.5, 7.2, 7.5, 8.3, 8.6, 9.4, 9.6, 9.8, and 10.0. There should
be a function call to show() that accepts the temps array as a parameter named temps
and then displays the numbers in the array.
6. (Electrical Eng.) Write a program that declares three one-dimensional arrays named
volts, current, and resistance. Each array should be declared in main() and be
capable of holding 10 double-precision numbers. The numbers to store in current are
10.62, 14.89, 13.21, 16.55, 18.62, 9.47, 6.58, 18.32, 12.15, and 3.98. The numbers to store
in resistance are 4, 8.5, 6, 7.35, 9, 15.3, 3, 5.4, 2.9, and 4.8. Your program should pass
these three arrays to a function named calc_volts(), which should calculate elements
in the volts array as the product of the corresponding elements in the current and
resistance arrays (for example, volts[1] = current[1] * resistance[1]). After
calc_volts() has passed values to the volts array, the values in the array should be
displayed from within main().
7. (Statistics) Write a program that includes two functions named calcavg() and
variance(). The calcavg() function should calculate and return the average of val-
ues stored in an array named testvals. The array should be declared in main() and
include the values 89, 95, 72, 83, 99, 54, 86, 75, 92, 73, 79, 75, 82, and 73. The
variance() function should calculate and return the variance of the data. The variance
is obtained by subtracting the average from each value in testvals, squaring the values
403
Chapter 7
Arrays as Arguments
obtained, adding them, and dividing by the number of elements in testvals. The val-
ues returned from calcavg() and variance() should be displayed by using cout
statements in main().
7.5 A Case Study: Statistical Analysis
Arrays are extremely useful in applications that require multiple passes through the same set
of data elements. This section uses one such application that’s a statistical data analysis
requiring two passes through the data. The first pass is used to input the list and determine
the average of the data. The second pass uses the average to determine a standard deviation.
This application illustrates one-dimensional array processing and helps you understand
passing an array to a function.
Step 1 Analyze the Problem
The statement of the problem indicates that two output values are required: an average and a
standard deviation. The input item defined in the problem statement is a list of integer numbers.
Because the problem statement doesn’t specify the list size, and to make the application’s
functions as general as possible, both functions will be designed to handle any size list passed to
them. This design also requires passing the exact number of elements in the array to each
function at the time of the function call. This capability means each function must be capable
of receiving at least two input items as parameters: an array of arbitrary size and an integer
number corresponding to the number of elements in the passed array.
Step 2 Develop a Solution
The I/O specifications determined from the problem analysis imply that the each function’s
parameter list must be capable of receiving at least two items: one parameter to accommodate
the integer array and the second parameter to accept an integer. The first function returns the
average of the numbers in the passed array, and the second function returns the standard
deviation. These items are determined as follows:
Calculate the average by adding the grades and dividing by the number of grades that
was added.
Determine the standard deviation by:
Subtracting the average from each grade. (This results in a set of new
numbers, each of which is called a deviation.)
Squaring each deviation found in the previous step.
Adding the squared deviations and dividing the sum by the number of
deviations.
The square root of the number found in the previous step is the standard
deviation.
The standard deviation can be calculated only after the average has been computed.
Therefore, in addition to requiring the array of integers and the number of values in the array,
the standard deviation function also requires that the average be passed to it. Specifying the
algorithm in detail, before any coding is done, ensures that all necessary inputs and
requirements are discovered early in the program development process.
404 Arrays
To make sure you understand the required processing, do a hand calculation, assuming
the average and standard deviation of the following 10 grades are to be determined: 98, 82,
67, 54, 78, 83, 95, 76, 68, and 63. Here’s the average of these grades:
Average = (98 + 82 + 67 + 54 + 78 + 83 + 95 + 76 + 68 + 63)/10 = 76.4
The standard deviation is calculated by first determining the sum of the squared
deviations, and then dividing the resulting sum by 10 and taking its square root, as shown:
- -
= +
( . ) (
98 76 4 82 76
2
.
. )
4 2
- -
+ +
( . ) ( . )
67 76 4 54 76 4
2 2
-
+ +
( . ) (
78 76 4 8
2
3
3 76 4 2
- . )
- -
+ +
( . ) ( . )
95 76 4 76 76 4
2 2
-
+ ( . )
68 76 3 2
2 2
63 76 4 1730 400700
+ =
( . ) .
-
=
= = =
1730 4007 10 173 04007 13 154470
. / . .
Sum of squared deviations
Standard deviation
Having specified the algorithm for both functions, you’re now in a position to code them.
Step 3 Code the Solution
When writing functions, concentrating on the function header first is helpful. You can then
write the function body to process the input parameters correctly to produce the desired
results. Naming the averaging function findAvg() and selecting the parameter names
nums for the passed array and numel for the number of elements, the function header
becomes the following:
double findAvg(int nums[], int numel)
This function header begins the definition of the averaging function and allows the
function to accept an array of integer values and an integer number. As shown by the hand
calculation, the average of a set of integer numbers can be a floating-point number; therefore,
the function is defined as returning a floating-point value. The function body calculates the
average as described by the algorithm developed earlier. The completed findAvg()
function is as follows:
double findAvg(int nums[], int numel)
{
int i;
double sumnums = 0.0;
for (i = 0; i < numel; i++) // calculate the sum of the grades
sumnums = sumnums + nums[i];
return (sumnums / numel); // calculate and return the average
}
The function body contains a for loop to sum the numbers. Notice also that the
termination value of the loop counter in the for loop is numel, the number of integers in
the array passed to the function through the parameter list. Using this parameter gives the
405
Chapter 7
A Case Study: Statistical Analysis
function its generality and allows it to be used for input arrays of any size. For example,
calling the function with the statement
findAvg(values,10)
tells the function that numel is 10 and the values array consists of 10 values, whereas the
statement
findAvg(values,1000)
tells findAvg() that numel is 1000 and the values array consists of 1000 numbers. In
both calls, the actual argument named values corresponds to the parameter named nums
in the findAvg() function.
Using similar reasoning as for the averaging function, the function header for the standard
deviation function, named stdDev(), is as follows:
double stdDev(int nums[], int numel, double av)
This header begins the definition of the stdDev() function. It defines the function as
returning a double-precision value and accepting an array of integers, an integer value, and
a double-precision value as inputs to the function. The body of the stdDev() function must
calculate the standard deviation as described in the algorithm. This is the complete standard
deviation function:
double stdDev(int nums[], int numel, double av)
{
int i;
double sumdevs = 0.0;
for (i = 0; i < numel; i++)
sumdevs = sumdevs + pow((nums[i] - av),2.0);
return(sqrt(sumdevs/numel));
}
Step 4 Test and Correct the Program
Testing a program’s function requires writing a main() function to call the function you’re
testing and display the returned results. Program 7.10 uses a main() function to set up a
grade array with the data previously used in the hand calculation and to call the
findAvg() and stdDev() functions.
406 Arrays
Program 7.10
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
double findAvg(int [], int); // function prototype
double stdDev(int [], int, double); // function prototype
int main()
{
const int NUMELS = 10;
int values[NUMELS] = {98, 82, 67, 54, 78, 83, 95, 76, 68, 63};
double average, sDev;
average = findAvg(values, NUMELS); // call the function
sDev = stdDev(values, NUMELS, average); // call the function
cout << "The average of the numbers is "
<< setw(5) << setiosflags(ios::showpoint)
<< setprecision(2) << average << endl;
cout << "The standard deviation of the numbers is "
<< setw(5) << setiosflags(ios::showpoint)
<< setprecision(2) << sDev << endl;
return 0;
}
double findAvg(int nums[], int numel)
{
int i;
double sumnums = 0.0;
for (i = 0; i < numel; i++) // calculate the sum of the grades
sumnums = sumnums + nums[i];
return (sumnums / numel); // calculate and return the average
}
墌
407
Chapter 7
A Case Study: Statistical Analysis
A test run of Program 7.10 produced the following display:
The average of the numbers is 76.40
The standard deviation of the numbers is 13.15
Although this result agrees with the previous hand calculation, testing isn’t complete
without verifying the calculation at the boundary points. For this program, the test consists
of checking the calculation with all the same values, such as all 0s and all 100s. Another
simple test is to use five 0s and five 100s. You can try these tests on your own as an exercise.
EXERCISES 7.5
1. (Practice) Enter and run Program 7.10 on your computer.
2. (Practice) Run Program 7.10 to determine the average and standard deviation of the fol-
lowing list of 15 grades: 68, 72, 78, 69, 85, 98, 95, 75, 77, 82, 84, 91, 89, 65, and 74.
3. (List Maintenance) A common programming problem is maintaining a list in numerical
or alphabetical order. For example, inventory part numbers are typically kept in numerical
order, but telephone lists are kept in alphabetical order.
For this exercise, write a function that inserts a three-digit part number in a list of part
numbers. The list is maintained in increasing numerical order, and duplicate part numbers
aren’t allowed. Allocate a maximum list size of 100 values, and use a sentinel value of
9999 to indicate the end of the list. For example, if the current list contains nine part
numbers, the 10th position in the list contains the sentinel value. Figure 7.12 shows
double stdDev(int nums[], int numel, double av)
{
int i;
double sumdevs = 0.0;
for (i = 0; i < numel; i++)
sumdevs = sumdevs + pow((nums[i] - av),2);
return(sqrt(sumdevs/numel));
}
408 Arrays
the insertion process for an original list of nine part numbers, using the following process-
ing algorithm:
Determine where in the list the new part number should be placed
This is done by comparing the new part number to each value in the current list
until a match is found, a part number larger than the new part number is
located, or the end of the list is encountered
If the new part number matches an existing part number,
display a message that the part number exists
Else
To make room for the new element in the array, move each element down one
position. This is done by starting from the sentinel value and coping each
item to the next position down until the desired position in the list is vacated.
Insert the new part number in the vacated position
Endif
4. (List Maintenance) a. Write a complete C++ program that can be used to update an
ordered list of numbers. Use the list of numbers shown in Figure 7.12 to test that your
program is working correctly.
b. Test the program you wrote for Exercise 4a, using a new part number of 86 with the
list of numbers shown in Figure 7.12. This test should place this new part number at
the beginning of the existing list.
c. Test the program you wrote for Exercise 4a, using a part number of 200 with the list
of numbers shown in Figure 7.12. This test should place this new part number at the
end of the existing list.
5. (List Maintenance) a. Determine an algorithm for deleting an entry from an ordered
list of numbers.
b. Write a function named delete(), which uses the algorithm determined in Exercise 5a,
to delete a part number from the list shown in Figure 7.12.
The new part number of
142 is to be inserted here
(a) Original list
(b) Elements copied to make room for the new part number
(c) The updated list
185 192 9999
109 122 136 144 157 162 178
185 192 9999
109 122 136 144 157 162 178
144
185 192 9999
109 122 136 144 157 162 178
142
Figure 7.12 Updating an ordered list of part numbers
409
Chapter 7
A Case Study: Statistical Analysis
6. (List Maintenance) The following letters are stored in an alphabet array: B, J, K, M, S,
and Z. Write and test a function named adlet(), which accepts the alphabet array and a
new letter as arguments, and then inserts the new letter in the correct alphabetical order
in the alphabet array.
7. (File Creation) Write a C++ program that creates an array containing the integer num-
bers 60, 40, 80, 90, 120, 150, 130, 160, 170, and 200. Your program should then write the
data in the array to a text file. (Alternatively, you can create the file with a text editor.)
8. (File Update) a. Develop, write, and execute a C++ program that reads in the list of 10
integer numbers from the data file created in Exercise 7.
b. Modify the program you wrote for Exercise 8a so that the program does the following:
앫 Deletes the first number input from the file
앫 Accepts a new integer value that will be placed at the end of the list of numbers
앫 Computes and displays the average of all numbers (not including the deleted value)
앫 Overwrites the old file with the new list of numbers
7.6 The Standard Template Library (STL)6
Many programming applications require expanding and contracting lists as list items are
added and removed. Although expanding and contracting an array can be accomplished by
creating, copying, and deleting arrays, this solution is costly in terms of initial programming,
maintenance, and testing time. To meet the need of providing a tested and generic set of data
structures that can be modified, expanded, and contracted, C++ includes a useful set of
classes in its Standard Template Library (STL).
Additionally, the functions included in the STL provide useful ways of sorting and
searching lists of data. For example, you might need to arrange experimental results in
increasing (ascending) or decreasing (descending) order for a statistical analysis. Perhaps an
array of names, as string data, must be sorted in alphabetical order, or an array of part names
needs to be searched to find a particular part.
Each STL class is coded as a template (see Section 6.1) that permits constructing a
generic data structure, referred to as a container. The terms list and collection are synonyms
for a container, and both these terms refer to a set of data items that form a natural unit or
group. Using this definition, an array can also be considered a container, but not in the
technical sense that it’s created by using the STL; rather, it’s provided as a built-in data type.
Figure 7.13 shows the container types in the STL.
This section discusses the vector container class, along with the most commonly used
algorithms for this class and the arguments, known as iterators, these algorithms require. A
vector is similar to an array, in that it stores elements that can be accessed by using an integer
index starting at 0. However, a vector is different from an array, in that a vector expands
automatically as needed and is provided by several extremely useful class functions7 for
6
This topic can be omitted on first reading without loss of subject continuity.
7
In general computer terminology, functions defined in a class (discussed in Part Two) are referred to as “methods.” In C++, the terms “class
functions” and “class methods” are used interchangeably.
410 Arrays
operating on the vector. Table 7.1 lists these vector class functions, with shading to identify
the functions used in the demonstration program.
Table 7.1 Summary of Vector Class Functions and Operations
Class Functions and Operations Description
vector<DataType> name Creates an empty vector with compiler-dependent
initial size
vector<DataType>
name(source)
Creates a copy of the source vector
vector<DataType> name(n) Creates a vector of size n
vector<DataType> name
(n, elem)
Creates a vector of size n with each element
initialized as elem
vector<DataType>
name(src.beg, src.end)
Creates a vector initialized with elements from
a source container beginning at src.beg and
ending at src.end
~vector(DataType>() Destroys the vector and all elements it contains
name[index] Returns the element at the designated index,
with no bounds checking
name.at(index) Returns the element at the specified index
argument, with bounds checking on the
index value
name.front() Returns the first element in the vector
name.back() Returns the last element in the vector
dest = src Assigns all elements of src vector to dest
vector
name.assign(n, elem) Assigns n copies of elem
name.assign
(src.begin, src.end)
Assigns the elements of the src container (need
not be between the range src.begin and src.
end) to the name vector
STL container
types
vector
deque
list
set
multiset
map
multimap
Figure 7.13 The collection of STL container types
411
Chapter 7
The Standard Template Library (STL)
Table 7.1 Summary of Vector Class Functions and Operations (continued)
Class Functions and Operations Description
insert(pos, elem) Inserts elem at position pos
name.insert
(pos, n, elem)
Inserts n copies of elem starting at position pos
name.insert(pos,
src.begin, src.end)
Inserts elements from src.begin to src.end,
starting at position pos
name.push_back(elem) Appends elem at the end of the vector
name.erase(pos) Removes the element at the specified
position pos
name.erase(begin, end) Removes elements within the specified range
name.resize(value) Resizes the vector to a larger size, with new
elements created by using the default constructor
name.resize(value, elem) Resizes the vector to a larger size, with new
elements created as elem
name.clear() Removes all elements from the vector
name.swap(nameB) Swaps the elements of nameA and nameB
vectors; can be performed by using the swap
algorithm
nameA == nameB Returns a Boolean true if nameA elements equal
nameB elements; otherwise, returns false
nameA != nameB Returns a Boolean false if nameA elements
equal nameB elements; otherwise, returns true;
same as !(nameA == nameB)
nameA < nameB Returns a Boolean true if nameA is less than
nameB; otherwise, returns false
nameA > nameB Returns a Boolean true if nameA is greater than
nameB; otherwise, returns false; same as
nameB < nameA
nameA <= nameB Returns a Boolean true if nameA is less than or
equal to nameB
nameA >= nameB Returns a Boolean true if nameA is greater than
or equal to nameB
name.size() Returns the size of the vector
name.empty() Returns a Boolean true if the vector is empty;
otherwise, returns false
name.max_size() Returns the maximum possible elements as an
integer
name.capacity() Returns the maximum possible elements as an
integer without relocating the vector
In addition to the vector class functions listed in Table 7.1, vectors have access to the
complete set of generic STL functions, referred to in the STL as algorithms. Table 7.2
summarizes the most commonly used STL algorithms.
412 Arrays
Table 7.2 Commonly Used STL Algorithms
Algorithm Name Description
accumulate Returns the sum of the numbers in a specified range
binary_search Returns a Boolean value of true if the specified value
exists within the specified range; otherwise, returns
false. Can be used only on a sorted set of values.
copy Copies elements from a source range to a
destination range
copy_backward Copies elements from a source range to a destination
range in a reverse direction
count Returns the number of elements in a specified range
that match a specified value
equal Compares the elements in one range of elements,
element by element, to the elements in a second range
fill Assigns every element in a specified range to a
specified value
find Returns the position of an element’s first occurrence in
a specified range having a specified value if the value
exists. Performs a linear search, starting with the first
element in a specified range, and proceeds one
element at a time until the complete range has been
searched or the specified element has been found.
max_element Returns the maximum value of elements in the
specified range
min_element Returns the minimum value of elements in the
specified range
random_shuffle Randomly shuffles element values in a specified range
remove Removes a specified value in a specified range without
changing the order of the remaining elements
replace Replaces each element in a specified range having a
specified value with a newly specified value
reverse Reverses elements in a specified range
search Finds the first occurrence of a specified value or
sequence of values within a specified range
sort Sorts elements in a specified range into ascending
order
swap Exchanges element values between two objects
unique Removes duplicate adjacent elements in a
specified range
413
Chapter 7
The Standard Template Library (STL)
Notice that there’s both a swap algorithm (Table 7.2) and a swap() vector function
(Table 7.1). Because a function is targeted to work specifically with its container type and
generally executes faster when a container class provides a function with the same name as
an algorithm, you should use the class functions.
Finally, the STL provides additional items referred to as iterators, used to specify which
elements in a container are to be operated on when an algorithm is called. Two of the most
useful iterators are returned by the STL iterator functions begin() and end(). These
general-purpose functions return the positions of the first and last elements in a container.
To better understand using an STL container class, in this section you see how to use the
vector container class to create a vector for holding a list of part numbers. As you’ll see, a
vector is similar to a C++ array, except it can automatically expand as needed.
Program 7.11 constructs a vector and initializes it with integers stored in an integer array.
After it’s initialized, various vector functions and STL algorithms are used to operate on the
vector. Specifically, one function is used to change an existing value, a second is used to
insert a value into the vector, and a third is used to add a value to the end of the list. After
each function and algorithm are applied, a cout statement is used to display the results.
In reviewing Program 7.11, notice these four header files that precede the using
namespace std; statement:
• The <iostream> header is required to create and use cout.
• The <string> header is required for constructing strings.
• The <vector> header is required to create one or more vector objects.
• The <algorithm> header is required for the sort algorithm that’s applied after
vector elements have been added and replaced.
Point of Information
When to Use an Array or a Vector
An array is the data structure of first choice when you have a list of primitive data
types or objects that don’t have to be expanded or contracted. A vector is the data
structure of first choice when you have a list of primitive data types or objects that can
be grouped as an array but must be expanded or contracted.
Whenever possible, use STL’s algorithms to operate on arrays and vectors. STL
classes and algorithms provide verified and reliable code that can shorten program
development time.
414 Arrays
Program 7.11
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
const int NUMELS = 4;
int n[] ={136, 122, 109, 146};
int i;
// create a vector of strings using the n[] array
vector<int> partnums(n, n + NUMELS);
cout << "nThe vector initially has a size of "
<< int(partnums.size()) << ",n and contains the elements:n";
for (i = 0; i < int(partnums.size()); i++)
cout << partnums[i] << " ";
// modify the element at position 4 (i.e. index = 3) in the vector
partnums[3] = 144;
cout << "nnAfter replacing the fourth element, the vector has a size of "
<< int(partnums.size()) << ",n and contains the elements:n";
for (i = 0; i < int(partnums.size()); i++)
cout << partnums[i] << " ";
// insert an element into the vector at position 2 (i.e. index = 1)
partnums.insert(partnums.begin()+1, 142);
cout << "nnAfter inserting an element into the second position,"
<< "n the vector has a size of " << int(partnums.size()) << ","
<< " and contains the elements:n";
for (i = 0; i < int(partnums.size()); i++)
cout << partnums[i] << " ";
// add an element to the end of the vector
partnums.push_back(157);
墌
415
Chapter 7
The Standard Template Library (STL)
The following statement in Program 7.11 is used to create and initialize the vector named
partnums:
vector<int> partnums(n, n + NUMELS);
The vector partnums is declared as a vector of type int and initialized with elements from
the n array, starting with the first array element (element n[0]) and ending with the last array
element, located at position n + NUMELS. Therefore, the vector size is large enough for four
integer values and has been initialized with the integers 136, 122, 109, and 146.
The next set of statements in Program 7.11 displays the initial values in the vector by
using standard subscripted vector notation that’s identical to the notation for accessing array
elements. Displaying vector values in this manner, however, requires knowing how many
elements each vector contains. As you insert and remove elements, you would like the vector
to track the first and last elements’ locations. This capability is provided automatically by the
two STL iterator functions mentioned previously: begin() and end().
The next major set of statements consists of the following:
// modify the element at position 4 (i.e. index = 3) in the vector
partnums[3] = 144;
// insert an element into the vector at position 2 (i.e. index = 1)
partnums.insert(partnums.begin()+1, 142);
These statements are used to modify an existing vector value and insert a new value into the
vector. Specifically, the partnums[3] notation uses standard indexing, and the insert()
function uses an iterator argument, which is constructed as an offset by using the begin() or
cout << "nnAfter adding an element to the end of the list,"
<< "n the vector has a size of " << int(partnums.size()) << ","
<< " and contains the elements:n";
for (i = 0; i < int(partnums.size()); i++)
cout << partnums[i] << " ";
// sort the vector
sort(partnums.begin(), partnums.end());
cout << "nnAfter sorting, the vector's elements are:n";
for (i = 0; i < int(partnums.size()); i++)
cout << partnums[i] << " ";
cout << endl;
return 0;
}
416 Arrays
end() function. Additionally, you have to specify the value to be inserted at the designated
position. Therefore, partnums[3] specifies changing the fourth element in the vector.
(Vectors, like arrays, begin at index position 0.) The insert() function is used to insert the
integer value 142 in the vector’s second position. Because the begin() function returns a value
corresponding to the start of the vector, adding 1 to it designates the vector’s second position.8
At this position, the new value is inserted. All subsequent values are moved up by one position
in the vector, and the vector expands automatically to accept the inserted value. At this point in
the program, the vector partnums now contains the following elements:
136 142 122 109 144
This arrangement of values was obtained by replacing the original value 146 with 144 and
inserting the 142 into the second position, which moves all subsequent elements up
automatically by one position and increases the total vector size to five integers.
Next, the statement partnums.push_back(157); is used to append the integer 157
to the end of the vector, which results in the following elements:
136 142 122 109 144 157
Finally, the last section of code in Program 7.11 uses the sort() algorithm to sort
elements in the vector. After the algorithm is applied, the vector’s values are displayed again.
Following is the complete output Program 7.11 produces:
The vector initially has a size of 4,
and contains the elements:
136 122 109 146
After replacing the fourth element, the vector has a size of 4,
and contains the elements:
136 122 109 144
After inserting an element into the second position,
the vector has a size of 5, and contains the elements:
136 142 122 109 144
After adding an element to the end of the list,
the vector has a size of 6, and contains the elements:
136 142 122 109 144 157
After sorting, the vector's elements are:
109 122 136 142 144 157
8
More precisely, begin() requires an iterator argument, not an integer index argument. The begin() and end() functions return iterators,
to which offsets can be applied. In this behavior, they are similar to pointers (covered in Chapter 12).
417
Chapter 7
The Standard Template Library (STL)
EXERCISES 7.6
1. (For Review) Define the terms “container” and “Standard Template Library.”
2. (For Review) What include statements should be included with programs using the
Standard Template Library?
3. (Practice) Enter and execute Program 7.11.
4. (Modify) Modify Program 7.11 so that the user inputs the initial set of numbers when
the program executes. Have the program request the number of initial numbers to be
entered.
5. (Modify) Modify Program 7.11 to use and display the results reported by the vector
class’s capacity() and max_size() functions.
6. (Modify) Modify Program 7.11 to use the random_shuffle algorithm.
7. (Modify) Modify Program 7.11 to use the binary_search and find algorithms. Have
your program request the number to be found.
8. (Modify) Using Program 7.11 as a starting point, create an equivalent program that uses a
vector of strings. Initialize the vector by using the array string names[] =
{"Donavan", "Michaels", "Smith", "Jones"};.
9. (Practice) Use the max_element and min_element algorithms to determine the maxi-
mum and minimum values in the vector created for Exercise 8. (Hint: Use the expression
max_element(vectorName.begin(), vectorName.end()) to determine the maxi-
mum value stored in the vector. Then use the same arguments for the min_element
algorithm.)
7.7 A Closer Look: Searching and Sorting9
Most programmers encounter the need to both sort and search a list of data items at some
time in their programming careers. For example, you might have to sort a list of names in
alphabetical order and search this list to find a particular name. Similarly, you might have to
arrange a list of dates in ascending order and search this list to locate a certain date. This
section introduces the fundamentals of sorting and searching lists. Note that sorting a list
before searching it isn’t necessary, although much faster searches are possible if the list is in
sorted order, as you’ll see.
Search Algorithms
A common requirement of many programs is searching a list for a certain element. For
example, in a list of names and telephone numbers, you might search for a specific name so
9
This topic can be omitted on first reading without loss of subject continuity.
418 Arrays
that the corresponding telephone number can be printed, or you might need to search the list
simply to determine whether a name is there. The two most common methods of performing
these searches are the linear and binary search algorithms.
Linear Search In a linear search, also known as a sequential search, each item in the list is
examined in the order in which it occurs until the desired item is found or the end of the list
is reached. This search method is analogous to looking at every name in the phone directory,
beginning with Aardvark, Aaron, until you find the one you want or until you reach Zzxgy,
Zora. Obviously, it’s not the most efficient way to search a long alphabetized list. However,
a linear search has these advantages:
• The algorithm is simple.
• The list need not be in any particular order.
In a linear search, the search begins at the first item in the list and continues sequentially,
item by item, through the list. The pseudocode for a function performing a linear search is
as follows:
For all items in the list
Compare the item with the desired item
If the item is found
Return the index value of the current item
Endif
EndFor
Return -1 if the item is not found
Notice that the function’s return value indicates whether the item was found. If the
return value is -1, the item isn’t in the list; otherwise, the return value in the for loop
provides the index of where the item is located in the list. The linearSearch() function
illustrates this procedure as a C++ function:
// this function returns the location of key in the list
// a -1 is returned if the value is not found
int linearSearch(int list[], int size, int key)
{
int i;
for (i = 0; i < size; i++)
{
if (list[i] == key)
return i;
}
return -1;
}
In reviewing linearSearch(), notice that the for loop is simply used to access each
element in the list, from first element to last, until a match with the desired item is found.
If the item is located, the index value of the current item is returned, which causes the loop
to terminate; otherwise, the search continues until the end of the list is encountered.
To test this function, a main() driver function has been written to call linearSearch()
and display the results it returns. Program 7.12 shows the complete test program.
419
Chapter 7
A Closer Look: Searching and Sorting
Program 7.12
#include <iostream>
using namespace std;
int linearSearch(int [], int, int); //function prototype
int main()
{
const int NUMEL = 10;
int nums[NUMEL] = {5,10,22,32,45,67,73,98,99,101};
int item, location;
cout << "Enter the item you are searching for: ";
cin >> item;
location = linearSearch(nums, NUMEL, item);
if (location > -1)
cout << "The item was found at index location " << location
<< endl;
else
cout << "The item was not found in the listn";
return 0;
}
// this function returns the location of key in the list
// a -1 is returned if the value is not found
int linearSearch(int list[], int size, int key)
{
int i;
for (i = 0; i < size; i++)
{
if (list[i] == key)
return i;
}
return -1;
}
420 Arrays
Sample runs of Program 7.12 follow:
Enter the item you are searching for: 101
The item was found at index location 9
and
Enter the item you are searching for: 65
The item was not found in the list
As noted previously, an advantage of linear searches is that the list doesn’t have to be in
sorted order to perform the search. Another advantage is that if the desired item is toward the
front of the list, only a small number of comparisons are made. The worst case, of course,
occurs when the desired item is at the end of the list. On average, however, and assuming
the item is equally likely to be anywhere in the list, the number of required comparisons is
n/2, where n is the list’s size. Therefore, for a 10-element list, the average number of
comparisons needed for a linear search is 5, and for a 10,000-element list, the average number
of comparisons needed is 5000. As you see next, this number can be reduced significantly by
using a binary search algorithm.
Binary Search In a binary search, the list must be in sorted order. Starting with an ordered
list, the desired item is first compared to the element in the middle of the list. (For lists with
an even number of elements, either of the two middle elements can be used.) There are
three possibilities after the comparison is made: The desired item might be equal to the
middle element, it might be greater than the middle element, or it might be less than the
middle element.
In the first case, the search has been successful, and no further searches are required. In
the second case, because the desired item is greater than the middle element, it must be in
the second half of the list, if it’s found at all. This means the first part of the list, consisting
of all elements from the first to the midpoint, can be discarded from any further search. In
the third case, because the desired item is less than the middle element, it must be in the
first part of the list, if it’s found at all. For this case, the second half of the list, containing all
elements from the midpoint to the last element, can be discarded from any further search.
The algorithm for this search strategy is shown in Figure 7.14 and defined by the
following pseudocode:
Set the lower index to 0
Set the upper index to one less than the size of the list
Begin with the first item in the list
While the lower index is less than or equal to the upper index
Set the midpoint index to the integer average of the lower and upper index values
Compare the desired item to the midpoint element
If the desired item equals the midpoint element
Return the index value of the current item
Else If the desired item is greater than the midpoint element
Set the lower index value to the midpoint value plus 1
Else If the desired item is less than the midpoint element
Set the upper index value to the midpoint value less 1
Endif
EndWhile
Return -1 if the item is not found
421
Chapter 7
A Closer Look: Searching and Sorting
In both the pseudocode and Figure 7.14’s flowchart, a while loop is used to control the
search. The initial list is defined by setting the left index value to 0 and the right index value
to one less than the number of elements in the list. The midpoint element is then taken as
the integerized average of the left and right values.
Set left
index to
midpoint +1
Item
>midpoint
element?
Item
=midpoint
element?
Calculate
midpoint
index value
While
left index <=
right index
Set right
index to list
size -1
Set left
index to zero
No
Return -1
Return index
value
Set right
index to
midpoint -1
No
No
Yes
Yes
Start
Input
item
Yes
Figure 7.14 The binary search algorithm
422 Arrays
After the comparison to the midpoint element is made, the search is subsequently
restricted by moving the left index to one integer value above the midpoint or by moving the
right index one integer value below the midpoint. This process is continued until the desired
element is found or the left and right index values become equal. The binarySearch()
function presents the C++ version of this algorithm:
// this function returns the location of key in the list
// a -1 is returned if the value is not found
int binarySearch(int list[], int size, int key)
{
int left, right, midpt;
left = 0;
right = size -1;
while (left <= right)
{
midpt = (int) ((left + right) / 2);
if (key == list[midpt])
{
return midpt;
}
else if (key > list[midpt])
left = midpt + 1;
else
right = midpt - 1;
}
return -1;
}
For purposes of testing this function, Program 7.13 is used. A sample run of Program 7.13
yielded the following:
Enter the item you are searching for: 101
The item was found at index location 9
Program 7.13
#include <iostream>
using namespace std;
int binarySearch(int [], int, int); //function prototype
int main()
{
const int NUMEL = 10;
墌
423
Chapter 7
A Closer Look: Searching and Sorting
int nums[NUMEL] = {5,10,22,32,45,67,73,98,99,101};
int item, location;
cout << "Enter the item you are searching for: ";
cin >> item;
location = binarySearch(nums, NUMEL, item);
if (location > -1)
cout << "The item was found at index location "
<< location << endl;
else
cout << "The item was not found in the arrayn";
return 0;
}
// this function returns the location of key in the list
// a -1 is returned if the value is not found
int binarySearch(int list[], int size, int key)
{
int left, right, midpt;
left = 0;
right = size -1;
while (left <= right)
{
midpt = (int) ((left + right) / 2);
if (key == list[midpt])
{
return midpt;
}
else if (key > list[midpt])
left = midpt + 1;
else
right = midpt - 1;
}
return -1;
}
424 Arrays
The value of using a binary search algorithm is that the number of elements that must
be searched is cut in half each time through the while loop. So the first time through the
loop, n elements must be searched; the second time through the loop, n/2 of the elements has
been eliminated and only n/2 remain. The third time through the loop, another half of the
remaining elements has been eliminated, and so on.
In general, after p passes through the loop, the number of values remaining to be
searched is n/(2p
). In the worst case, the search can continue until less than or equal to one
element remains to be searched. Mathematically, this procedure can be expressed as n/(2p
) ⱕ
1. Alternatively, it can be rephrased as p is the smallest integer so that 2p
> n. For example,
for a 1000-element array, n is 1000 and the maximum number of passes, p, required for a
binary search is 10. Table 7.3 compares the number of loop passes needed for a linear and
binary search for different list sizes.
Table 7.3 A Comparison of while Loop Passes for Linear and Binary Searches
Array size 10 50 500 5000 50,000 500,000 5,000,000 50,000,000
Average
linear
search
passes
5 25 250 2500 25,000 250,000 2,500,000 25,000,000
Maximum
linear
search
passes
10 50 500 5000 50,000 500,000 5,000,000 50,000,000
Maximum
binary
search
passes
4 6 9 13 16 19 23 26
As shown, the maximum number of loop passes for a 50-item list is almost 10 times more for
a linear search than for binary search, and even more spectacular for larger lists. As a rule of
thumb, 50 elements are usually taken as the switch-over point: For lists smaller than 50 elements,
linear searches are acceptable; for larger lists, a binary search algorithm should be used.
Big O Notation
On average, over a large number of linear searches with n items in a list, you would expect
to examine half (n/2) of the items before locating the desired item. In a binary search, the
maximum number of passes, p, occurs when n/(2)p
= 1. This relationship can be manipulated
algebraically to 2p
= n, which yields p = log2n, which approximately equals 3.33 log10n.
For example, finding a particular name in an alphabetical directory with n = 1000 names
requires an average of 500 (=n/2) comparisons using a linear search. With a binary search, only
about 10 (⬇ 3.33 * log101000) comparisons are required.
A common way to express the number of comparisons required in any search algorithm
using a list of n items is to give the order of magnitude of the number of comparisons
required, on average, to locate a desired item. Therefore, the linear search is said to be of
order n and the binary search of order log2n. Notationally, they’re expressed as O(n) and
O(log2n), where the O is read as “the order of.”
425
Chapter 7
A Closer Look: Searching and Sorting
Sort Algorithms
Two major categories of sorting techniques, called internal and external sorts, are available for
sorting data. Internal sorts are used when the data list isn’t too large and the complete list can
be stored in the computer’s memory, usually in an array. External sorts are used for much
larger data sets that are stored in external disk or tape files and can’t be accommodated in the
computer’s memory as a complete unit. Next, you learn about two internal sort algorithms
that can be used when sorting lists with fewer than approximately 50 elements. For larger
lists, more sophisticated sorting algorithms are typically used.
Selection Sort One of the simplest sorting techniques is the selection sort, in which the
smallest value is selected from the complete list of data and exchanged with the first element in
the list. After this first selection and exchange, the next smallest element in the revised list is
selected and exchanged with the second element in the list. Because the smallest element is
already in the first position in the list, this second pass needs to consider only the second through
last elements. For a list consisting of n elements, this process is repeated n - 1 times, with each
pass through the list requiring one less comparison than the previous pass.
For example, take a look at the list of numbers shown in Figure 7.15. The first pass
through the initial list results in the number 32 being selected and exchanged with the first
element in the list. The second pass, made on the reordered list, results in the number 155
being selected from the second through fifth elements. This value is then exchanged with
the second element in the list. The third pass selects the number 307 from the third through
fifth elements in the list and exchanges this value with the third element. Finally, the fourth
and last pass through the list selects the remaining minimum value and exchanges it with the
fourth list element. Although each pass in this example resulted in an exchange, no exchange
would have been made in a pass if the smallest value were already in the correct location.
Initial list Pass 1 Pass 2 Pass 3 Pass 4
690 32 32 32 32
307 307 155 144 144
32 690 690 307 307
155 155 307 690 426
426 426 426 426 690
Figure 7.15 A sample selection sort
426 Arrays
In pseudocode, the selection sort is described as follows:
Set exchange count to zero (not required, but done to keep track of the exchanges)
For each element in the list, from the first to the next to last
Find the smallest element from the current element being referenced to the last
element by:
Setting the minimum value equal to the current element
Saving (storing) the index of the current element
For each element in the list, from the current element + 1 to the last element in the list
If element[inner loop index] < minimum value
Set the minimum value = element[inner loop index]
Save the index value corresponding to the newfound minimum value
Endif
EndFor
Swap the current value with the new minimum value
Increment the exchange count
EndFor
Return the exchange count
The selection Sort() function incorporates this procedure into a C++ function:
int selectionSort(int num[], int numel)
{
int i, j, min, minidx, temp, moves = 0;
for ( i = 0; i < (numel - 1); i++)
{
min = num[i]; // assume minimum is the first array element
minidx = i; // index of minimum element
for(j = i + 1; j < numel; j++)
{
if (num[j] < min) // if you've located a lower value
{ // capture it
min = num[j];
minidx = j;
}
}
if (min < num[i]) // check whether you have a new minimum
{ // and if you do, swap values
temp = num[i];
num[i] = min;
num[minidx] = temp;
moves++;
}
}
return moves;
}
427
Chapter 7
A Closer Look: Searching and Sorting
The selectionSort() function expects two arguments: the list to be sorted and the
number of elements in the list. As the pseudocode specifies, a nested set of for loops
performs the sort. The outer for loop causes one less pass through the list than the total
number of items in the list. For each pass, the variable min is initially assigned the value
num[i], where i is the outer for loop’s counter variable. Because i begins at 0 and ends
at one less than numel, each element in the list, except the last, is successively designated
as the current element.
The inner loop cycles through the elements below the current element and is used to
select the next smallest value. Therefore, this loop begins at the index value i + 1 and
continues through the end of the list. When a new minimum is found, its value and position
in the list are stored in the variables min and minidx. At completion of the inner loop, an
exchange is made only if a value less than that in the current position is found.
Program 7.14 was constructed to test selectionSort(). This program implements a
selection sort for the same list of 10 numbers used to test the search algorithms. For later
comparison to other sorting algorithms, the number of actual moves the program makes to get
data into sorted order is counted and displayed.
The output Program 7.14 produces is as follows:
The sorted list, in ascending order, is:
5 10 22 32 45 67 73 98 99 101
8 moves were made to sort this list
Clearly, the number of moves displayed depends on the initial order of values in the list.
An advantage of the selection sort is that the maximum number of moves that must be made
is n - 1, where n is the number of items in the list. Further, each move is a final move that
results in an element residing in its final location in the sorted list.
A disadvantage of the selection sort is that n(n - 1)/2 comparisons are always required,
regardless of the initial arrangement of data. This number of comparisons is obtained as
follows: The last pass always requires one comparison, the next-to-last pass requires two
comparisons, and so on, to the first pass, which requires n - 1 comparisons. Therefore, the
total number of comparisons is the following:
1 + 2 + 3 + . . . + n - 1 = n(n - 1)/2 = n2
/2 - n/2
For large values of n, the n2
term dominates, and the order of the selection sort is O(n2
).
428 Arrays
Program 7.14
#include <iostream>
using namespace std;
int selectionSort(int [], int);
int main()
{
const int NUMEL = 10;
int nums[NUMEL] = {22,5,67,98,45,32,101,99,73,10};
int i, moves;
moves = selectionSort(nums, NUMEL);
cout << "The sorted list, in ascending order, is:n";
for (i = 0; i < NUMEL; i++)
cout << " " <<nums[i];
cout << endl << moves << " moves were made to sort this listn";
return 0;
}
int selectionSort(int num[], int numel)
{
int i, j, min, minidx, temp, moves = 0;
for ( i = 0; i < (numel - 1); i++)
{
min = num[i]; // assume minimum is the first array element
minidx = i; // index of minimum element
for(j = i + 1; j < numel; j++)
{
if (num[j] < min) // if you've located a lower value
{ // capture it
min = num[j];
minidx = j;
}
}
if (min < num[i]) // check whether you have a new minimum
{ // and if you do, swap values
墌
429
Chapter 7
A Closer Look: Searching and Sorting
Exchange (Bubble) Sort In an exchange sort, adjacent elements of the list are exchanged
with one another so that the list becomes sorted. One example of this sequence of exchanges
is the bubble sort, in which successive values in the list are compared, beginning with the first
two elements. If the list is to be sorted in ascending (from smallest to largest) order, the
smaller value of the two being compared is always placed before the larger value. For lists
sorted in descending (from largest to smallest) order, the smaller of the two values being
compared is always placed after the larger value.
For example, a list of values is to be sorted in ascending order. If the first element in the list
is larger than the second, the two elements are exchanged. Then the second and third elements
are compared. Again, if the second element is larger than the third, these two elements are
exchanged. This process continues until the last two elements have been compared and
exchanged, if necessary. If no exchanges were made during this initial pass through the data, the
data is in the correct order and the process is finished; otherwise, a second pass is made through
the data, starting from the first element and stopping at the next-to-last element. The reason for
stopping at the next-to-last element on the second pass is that the first pass always results in the
most positive value “sinking” to the bottom of the list.
To see a specific example, examine the list of numbers in Figure 7.16. The first
comparison results in exchanging the first two element values, 690 and 307. The next
comparison, between elements two and three in the revised list, results in exchanging values
between the second and third elements, 690 and 32. This comparison and possible switching
of adjacent values is continued until the last two elements have been compared and possibly
exchanged. This process completes the first pass through the data and results in the largest
number moving to the bottom of the list. As the largest value sinks to the bottom of the list,
the smaller elements slowly rise, or “bubble,” to the top of the list. This bubbling effect of
the smaller elements is what gives rise to the name “bubble sort” for this sorting algorithm.
temp = num[i];
num[i] = min;
num[minidx] = temp;
moves++;
}
}
return moves;
}
690 307 307 307 307
307 690 32 32 32
32 32 690 155 155
155 155 155 690 426
426 426 426 426 690
Figure 7.16 The first pass of an exchange sort
430 Arrays
Because the first pass through the list ensures that the largest value always moves to the
bottom of the list, the second pass stops at the next-to-last element. This process continues
with each pass stopping at one higher element than the previous pass, until n - 1 passes
through the list have been completed or no exchanges are necessary in any single pass. In
both cases, the resulting list is in sorted order. The pseudocode describing this sort is as
follows:
Set exchange count to zero (not required, but done to keep track of the exchanges)
For the first element in the list to one less than the last element (i index)
For the second element in the list to the last element (j index)
If num[j] < num[j - 1]
{
Swap num[j] with num[j - 1]
Increment exchange count
}
EndFor
EndFor
Return exchange count
This sort algorithm is coded in C++ as the bubbleSort() function, which is included in
Program 7.15 for testing purposes. This program tests bubbleSort() with the same list of
10 numbers used in Program 7.14 to test selectionSort(). For comparison to the earlier
selection sort, the number of adjacent moves (exchanges) bubbleSort() makes is also
counted and displayed.
Program 7.15
#include <iostream>
using namespace std;
int bubbleSort(int [], int); // function prototype
int main()
{
const int NUMEL = 10;
int nums[NUMEL] = {22,5,67,98,45,32,101,99,73,10};
int i, moves;
moves = bubbleSort(nums, NUMEL);
cout << "The sorted list, in ascending order, is:n";
for (i = 0; i < NUMEL; ++i)
cout << " " <<nums[i];
cout << endl << moves << " moves were made to sort this listn";
return 0;
}
墌
431
Chapter 7
A Closer Look: Searching and Sorting
Here’s the output produced by Program 7.15:
The sorted list, in ascending order, is:
5 10 22 32 45 67 73 98 99 101
18 moves were made to sort this list
As with the selection sort, the number of comparisons in a bubble sort is O(n2
), and the
number of required moves depends on the initial order of values in the list. In the worst case,
when the data is in reverse sorted order, the selection sort performs better than the bubble
sort. Both sorts require n(n - 1)/2 comparisons, but the selection sort needs only n - 1 moves,
and the bubble sort needs n(n - 1)/2 moves. The additional moves the bubble sort requires
result from the intermediate exchanges between adjacent elements to “settle” each element
into its final position. In this regard, the selection sort is superior because no intermediate
moves are necessary. For random data, such as that used in Programs 7.14 and 7.15, the
selection sort generally performs equal to or better than the bubble sort.
7.8 Common Programming Errors
Four common errors are associated with using arrays:
1. Forgetting to declare the array. This error results in a compiler error message such as
“invalid indirection” each time a subscripted variable is encountered in a program.
int bubbleSort(int num[], int numel)
{
int i, j, temp, moves = 0;
for ( i = 0; i < (numel - 1); i++)
{
for(j = 1; j < numel; j++)
{
if (num[j] < num[j-1])
{
temp = num[j];
num[j] = num[j-1];
num[j-1] = temp;
moves++;
}
}
}
return moves;
}
432 Arrays
Chapter 12 explains the exact meaning of this error message when establishing the
relationship between arrays and pointers.
2. Using a subscript that references a nonexistent array element, such as declaring the
array as size 20 and using a subscript value of 25. Most C++ compilers don’t detect
this error. However, it results in a runtime error that causes a program crash or results
in a value with no relation to the intended element being accessed from memory. In
either case, this error is usually difficult to locate. The only solution is to make sure,
by specific programming statements or by careful coding, that each subscript
references a valid array element.
3. Not using a large enough counter value in a for loop counter to cycle through all the
array elements. This error usually occurs when an array is initially specified as size
n and there’s a for loop in the program of the form for(i = 0; i < n; i++).
The array size is then expanded, but the programmer forgets to change the interior
for loop parameters. Declaring an array’s size with a named constant and consis-
tently using the named constant throughout the function in place of the variable n
eliminates this problem.
4. Forgetting to initialize the array. Although many compilers set all elements of integer
and real value arrays to 0 automatically, and all elements of character arrays to blanks,
it’s up to the programmer to make sure each array is initialized correctly before
processing of array elements begins.
7.9 Chapter Summary
1. A one-dimensional array is a data structure that can be used to store a list of values of the
same data type. These arrays must be declared by giving the data type of values stored
in the array and the array size. For example, the declaration
int num[100];
creates an array of 100 integers. A preferable approach is first using a named constant to
set the array size, and then using this constant in the array definition, as shown in these
examples:
const int MAXSIZE = 100;
and
int num[MAXSIZE];
2. Array elements are stored in contiguous locations in memory and referenced by using the
array name and a subscript (or index), such as num[22]. Any non-negative integer value
expression can be used as a subscript, and the subscript 0 always refers to the first
element in an array.
3. A two-dimensional array is declared by listing a row and a column size with the data type
and array name. For example, the following declaration creates a two-dimensional array
consisting of five rows and seven columns of integer values:
int mat[5][7];
4. Arrays can be initialized when they are declared. For two-dimensional arrays, you list the
initial values, row by row, inside braces and separate them with commas. For example,
the declaration
433
Chapter 7
Chapter Summary
int vals[3][2] = { {1, 2},
{3, 4},
{5, 6} };
produces the following three-row-by-two-column array:
1 2
3 4
5 6
As C++ uses the convention that initialization proceeds in row order, the inner braces can
be omitted. Therefore, the following statement is an equivalent initialization:
int vals[3][2] = { 1, 2, 3, 4, 5, 6};
5. Arrays are passed to a function by passing the array name as an argument. The value
actually passed is the address of the first array storage location. Therefore, the called
function receives direct access to the original array, not a copy of the array elements. A
formal argument must be declared in the called function to receive the passed array
name. The declaration of the formal argument can omit the array’s row size.
Programming Projects for Chapter 7
1. (Statistics) a. Write a C++ program that reads a list of double-precision grades from the
keyboard into an array named grade. The grades are to be counted as they’re read, and
entry is to be terminated when a negative value has been entered. After all grades have
been input, your program should find and display the sum and average of the grades.
The grades should then be listed with an asterisk (*) placed in front of each grade that’s
below the average.
b. Extend the program written for Exercise 1a to display each grade and its letter
equivalent, using the following scale:
Between 90 and 100 = A.
Greater than or equal to 80 and less than 90 = B.
Greater than or equal to 70 and less than 80 = C.
Greater than or equal to 60 and less than 70 = D.
Less than 60 = F.
2. (Practice) Define an array named peopleTypes that can store a maximum of 50
integer values entered at the keyboard. Enter a series of 1s, 2s, 3s, and 4s into the array
to represent people at a local school function; 1 represents an infant, 2 represents a child,
3 represents a teenager, and 4 represents an adult. No other integer value should be
accepted as valid input, and data entry should stop when a negative value is entered.
Your program should count the number of each 1, 2, 3, and 4 in the array and display a
list of how many infants, children, teenagers, and adults were at the school function.
3. (Numerical) Given a one-dimensional array of integer numbers, write and test a
function that prints the array elements in reverse order.
4. (Numerical) Write and test a function that returns the position of the largest and
smallest values in an array of double-precision numbers.
434 Arrays
5. (Sorting) Read a set of numerical grades from the keyboard into an array. The maximum
number of grades to be entered is 50, and data entry should be terminated when a
negative number is entered. Have your program sort and print the grades in descending
order.
6. (Numerical) a. Define an array with a maximum of 20 integer values, and fill the array
with numbers input from the keyboard or assigned by the program. Then write a
function named split() that reads the array and places all zeros or positive numbers
in an array named positive and all negative numbers in an array named negative.
Finally, have your program call a function that displays the values in both the positive
and negative arrays.
b. Extend the program written for Exercise 6a to sort the positive and negative
arrays into ascending order before they are displayed.
7. (Numerical) Using the srand() and rand() C++ library functions, fill an array of
1000 floating-point numbers with random numbers that have been scaled to the range 1
to 100. Then determine and display the number of random numbers having values
between 1 and 50 and the number having values greater than 50. What do you expect the
output counts to be?
8. (Statistical) In many statistical analysis programs, data values considerably outside the
range of the majority of values are simply dropped from consideration. Using this
information, write a C++ program that accepts up to 10 floating-point values from a user
and determines and displays the average and standard deviation of the input values. All
values more than four standard deviations away from the computed average are to be
displayed and dropped from any further calculation, and a new average and standard
deviation should be computed and displayed.
9. (Data Processing) Your professor has asked you to write a C++ program that determines
grades at the end of the semester. For each student, identified by an integer number
between 1 and 60, four exam grades must be kept, and two final grade averages must be
computed. The first grade average is simply the average of all four grades. The second grade
average is computed by weighting the four grades as follows: The first grade gets a weight
of 0.2, the second grade gets a weight of 0.3, the third grade gets a weight of 0.3, and the
fourth grade gets a weight of 0.2. That is, the final grade is computed as follows:
0.2 * grade1 + 0.3 * grade2 + 0.3 * grade3 + 0.2 * grade4
Using this information, construct a 60-by-7 two-dimensional array, in which the first
column is used for the student number, the next four columns for the grades, and the last
two columns for the computed final grades. The program’s output should be a display of
the data in the completed array. For testing purposes, the professor has provided the
following data:
Student Grade 1 Grade 2 Grade 3 Grade 4
1 100 100 100 100
2 100 0 100 0
3 82 94 73 86
4 64 74 84 94
5 94 84 74 64
435
Chapter 7
Programming Projects
10. (Modify) Modify the program written for Exercise 9 by adding an eighth column to the
array. The grade in the eighth column should be calculated by computing the average of
the top three grades only.
11. (Data Processing) a. Create a two-dimensional list of integer part numbers and
quantities of each part in stock, and write a function that displays data in the array in
decreasing quantity order. No more than 100 different parts are being kept track of. Test
your program with the following data:
Part No. Quantity
1001 62
949 85
1050 33
867 125
346 59
1025 105
b. Modify the function written in Exercise 11a to display the data in part number order.
12. (Data Processing) The answers to a true-false test are as follows: T T F F T. Given a
two-dimensional answer array, in which each row corresponds to the answers provided on
one test, write a function that accepts the two-dimensional array and number of tests as
parameters and returns a one-dimensional array containing the grades for each test. (Each
question is worth 5 points so that the maximum possible grade is 25.) Test your function
with the following data:
Test 1: T F T T T
Test 2: T T T T T
Test 3: T T F F T
Test 4: F T F F F
Test 5: F F F F F
Test 6: T T F T F
13. (Modify) Modify the function you wrote for Exercise 12 so that each test is stored in
column order rather than row order.
14. (Data Processing) A three-dimensional weather array for the months July and August
2008 has planes labeled by the month numbers 7 and 8. In each plane, there are rows
numbered 1 through 31, representing the days, and two columns labeled H and L,
representing the day’s high and low temperatures. Use this information to write a C++
program that assigns the high and low temperatures for each element of the arrays. Then
allow the user to request the following:
• Any day’s high and low temperatures
• Average high and low temperatures for a given month
436 Arrays
• Month and day with the highest temperature
• Month and day with the lowest temperature
15. (Computational) A magic square is a square of numbers with N rows and N columns,
in which each integer value from 1 to (N * N) appears exactly once, and the sum of each
column, each row, and each diagonal is the same value. For example, Figure 7.17 shows
a magic square in which N = 3, and the sum of the rows, columns, and diagonal is 15.
Write a program that constructs and displays a magic square for any given odd number
N. This is the algorithm:
Insert the value 1 in the middle of the first row (element [0][N%2]).
After a value, x, has been placed, move up one row and to the right one column.
Place the next number, x + 1, there, unless:
(1) You move off the top (row = -1) in any column. Then move to the
bottom row and place the next number, x + 1, in the bottom row of that
column.
(2) You move off the right end (column = N) of a row. Then place the
next number, x + 1, in the first column of that row.
(3) You move to a position that is already filled or out of the upper-right
corner. Then place the next number, x + 1, immediately below x.
Stop when you have placed as many elements as there are in the array.
16. (Computational) Among other applications, Pascal’s triangle (see Figure 7.18) provides
a means of determining the number of possible combinations of n things taken r at a
time. For example, the number of possible combinations of five people (n = 5) taken two
at a time (r = 2) is 10.
Each row of the triangle begins and ends with 1. Every other element in a row is the sum
of the element directly above it with the element to the left of the one above it. That is,
element[n][r] = element[n-1][r] + element[n-1][r-1]
Using this information, write and test a C++ program to create the first 11 rows of a
two-dimensional array representing Pascal’s triangle. For any given value of n less than
11 and r less than or equal to n, the program should display the correct element. Use your
program to determine in how many ways a committee of 8 can be selected from a group
of 10 people.
8 1 6
0 1 2
3 5 7
4
0
1
2 9 2
Column
Row
Figure 7.17 A magic square
437
Chapter 7
Programming Projects
1
1
1
1
1
1
0
1
2
3
4
5
1
1
4
10
3
1
5
4
1
5
0
1
2
3
4
5
n
1
3
6
10
2
r
Figure 7.18 Pascal’s triangle
Engineering and Scientific Disciplines
Mechanical Engineering
Generally speaking, mechanical engineers are concerned with machines or systems that
produce or apply energy. The range of technological activities considered part of
mechanical engineering is probably broader than in any other engineering field. The
field can be roughly subdivided into four categories:
앫 Power: Designing power-generating machines and systems, such as boiler-turbine
engines for generating electricity, solar power, heating systems, and heat
exchanges.
앫 Design: Innovative design of machine parts or components, from the most
intricate and small to the gigantic. For example, mechanical engineers work
alongside electrical engineers to design automatic control systems, such as robots.
앫 Automotive: Designing and testing transportation vehicles and the machines used
to manufacture them.
앫 Heating, ventilation, air conditioning, and refrigeration: Designing systems to
control the environment, both indoors and outside, and to control pollution.
Mechanical engineers usually have a thorough background in subjects such as ther-
modynamics, heat transfer, statics and dynamics, and fluid mechanics.
438 Arrays
Chapter
8
I/O Streams and
Data Files
8.1 I/O File Stream Objects and
Methods
8.2 Reading and Writing
Character-Based Files
8.3 Random File Access
8.4 File Streams as Function
Arguments
8.5 A Case Study: Pollen Count
File Update
8.6 A Closer Look: The iostream
Class Library
8.7 Common Programming Errors
8.8 Chapter Summary
The data for the programs you have used so far has been assigned internally in the programs or entered
by the user during program execution. As such, data used in these programs is stored in the computer’s
main memory and ceases to exist after the program using it has finished executing. This type of data
entry is fine for small amounts of data. However, imagine a company having to pay someone to type
in the names and addresses of hundreds or thousands of customers every month when bills are prepared
and sent.
As you learn in this chapter, storing large amounts of data outside a program on a convenient
storage medium is more sensible. Data stored together under a common name on a storage medium other
than the computer’s main memory is called a data file. Typically, data files are stored on disks, USB
drives, or CD/DVDs. Besides providing permanent storage for data, data files can be shared between
programs, so the data one program outputs can be input in another program. In this chapter, you learn
how data files are created and maintained in C++.
8.1 I/O File Stream Objects and Methods
To store and retrieve data outside a C++ program, you need two things:
• A file
• A file stream object
You learn about these important topics in this section.
Files
A file is a collection of data stored together under a common name, usually on a disk,
magnetic tape, USB drive, or CD/DVD. For example, the C++ programs you store on disk
are examples of files. The stored data in a program file is the code that becomes input data
to the C++ compiler. In the context of data processing, however, a C++ program isn’t usually
considered data, and the term “file” or “data file” typically refers only to external files
containing the data used in a C++ program.
A file is physically stored on an external medium, such as a disk. Each file has a unique
filename, referred to as the file’s external name. The external name is how the operating
system (OS) knows the file. When you review the contents of a directory or folder (for
example, in Windows Explorer), you see files listed by their external names. Each computer
OS has its own specification for the maximum number of characters permitted for an external
filename. Table 8.1 lists these specifications for commonly used OSs.
Table 8.1 Maximum Allowable Filename Characters
OS Maximum Filename Length
DOS 8 characters plus an optional period and
3-character extension
Windows 98, 2000, XP, Vista 255 characters
UNIX
Early versions
Current versions
14 characters
255 characters
To make sure examples in this book are compatible with all the OSs listed in Table 8.1,
the more restrictive DOS specification has been adhered to generally (but not always). If
you’re using one of the other OSs, however, you can take advantage of the increased length
specification to create descriptive filenames, but avoid using extremely long filenames
because they take more time to type and can result in typing errors. A manageable length for
a filename is usually 12 to 14 characters, with a maximum of 25 characters.
Using the DOS convention, all the following are valid data filenames:
prices.dat records info.txt
exper1.dat scores.dat math.mem
Choose filenames that indicate the type of data in the file and the application for which
it’s used. Typically, the first eight characters describe the data, and an extension (the
characters after the decimal point) describes the application used to create the file. For
example, the Excel program adds the .xls or .xlsx extension automatically to all
spreadsheet files, Microsoft Word and WordPerfect use the extensions .doc (or .docx) and
440 I/O Streams and Data Files
.wpx (x refers to the version number), and C++ compilers require a program file with the
extension .cpp. When creating your own filenames, you should adhere to this practice. For
example, using the DOS convention, the name exper1.dat is suitable for describing a file
of data corresponding to experiment number 1.
Two basic types of files exist: text files, also known as character-based files, and
binary-based files. Both file types store data by using a binary code; the difference is in what
the codes represent. Briefly, text files store each character, such as a letter, digit, dollar sign,
decimal point, and so on, by using a character code (typically ASCII or Unicode). With a
character code, a word processing program or text editor can display the files so that a person
can read them.
Binary-based files use the same code the C++ compiler uses for primitive data types.
This means numbers appear in their true binary form, and strings retain their ASCII or
Unicode form. The advantage of binary-based files is compactness; storing numbers with
their binary code usually takes less space than with character values. In general, programmers
use text files more often because the file’s data can be displayed by word processing
programs and simple text editors. The default file type in C++ is always a text file and is the
file type discussed in this chapter.
File Stream Objects
A file stream is a one-way transmission path used to connect a file stored on a physical device,
such as a disk or CD, to a program. Each file stream has its own mode that determines the
direction of data on the transmission path—that is, whether the path moves data from a file to
a program or from a program to a file. A file stream that receives or reads data from a file to a
program is an input file stream. A file stream that sends or writes data to a file is an output file
stream. The direction, or mode, is defined in relation to the program, not the file; data going into
a program is considered input data, and data sent out from a program is considered output data.
Figure 8.1 illustrates the data flow from and to a file, using input and output file streams.
For each file your program uses, regardless of the file’s type (text or binary), a distinct file
stream object must be created. If you want your program to read from and write to a file, both
input and output file stream objects are required. Input file stream objects are declared to be
Point of Information
Functions and Methods
C++ programmers can make full use of the many functions C++ classes provide with-
out knowing the internal details of how the function is constructed or even how to
construct a class. Functions provided as part of a class are formally referred to as class
methods (or methods, for short). Therefore, a method can be referred to as a func-
tion, although the term “method” provides more information in telling you the func-
tion is available as part of a class.
Part Two (Chapters 10 and 11) explains classes and their construction in detail. As
you’ll see, a class is constructed from C++ code that includes both data and functions
(although the functions are more accurately referred to as methods). An object is simply
a specific item constructed from a class. For example, a specific car is an object, which
is a specific item from the class of all cars, or the book you’re reading now is an
object, which is a specific item from the class of all third editions of the book C++ For
Engineers and Scientists.
441
Chapter 8
I/O File Stream Objects and Methods
of type ifstream, and output file stream objects are declared to be of type ofstream. For
example, the following declaration statement declares an input file stream object named
inFile to be an object of the ifstream class:
ifstream inFile;
Similarly, the following declaration statement declares an output file stream object named
outFile to be an object of the ofstream class:
ofstream outFile;
In a C++ program, a file stream is accessed by its stream object name: one name for
reading the file and one name for writing to the file. Object names, such as inFile and
outFile, can be any programmer-selected name that conforms to C++’s identifier rules.
File Stream Methods
Each file stream object has access to the methods defined for its ifstream or ofstream
class. These methods include connecting a stream object name to an external filename
(called opening a file), determining whether a successful connection has been made, closing
a connection (called closing a file), getting the next data item into the program from an input
stream, putting a new data item from the program onto an output stream, and detecting when
the end of a file has been reached.
Opening a file connects a file stream object to a specific external filename by using a file
stream’s open() method, which accomplishes two purposes. First, opening a file establishes
the physical connecting link between a program and a file. Because details of this link are
handled by the computer’s OS and are not visible to the program, normally the programmer
doesn’t need to consider them.
From a coding perspective, the second purpose of opening a file is more relevant. Besides
establishing the actual physical connection between a program and a data file, opening a file
connects the file’s external name to the stream object name that the program uses internally.
The method that performs this task, open(), is provided by the ifstream and ofstream
classes.
Disk
Input file stream
#include <fstream>
int main()
{
return 0;
}
Program
Output file stream
File
Figure 8.1 Input and output file streams
442 I/O Streams and Data Files
In using the open() method to connect the file’s external name to its internal object
stream name, only one argument is required: the external filename. For example, the
following statement connects the external file named prices.dat to the internal file
stream object named inFile:
inFile.open("prices.dat");
This statement assumes, of course, that inFile has been declared as an ifstream or
ofstream object. If a file has been opened with the preceding statement, the program
accesses the file by using the internal object name inFile, and the computer saves the file
under the external name prices.dat. The external filename argument passed to open()
is a string enclosed in double quotation marks. Calling the open() method requires standard
object notation, in which the method name, in this case open(), is preceded by an object
name (inFile, in this example) followed by a period.
When an existing file is connecting to an input file stream, the file’s data is made
available for input, starting at the first data item in the file. Similarly, a file connected to an
output file stream creates a new file, said to be in output mode, and makes the file available
for output. If a file exists with the same name as a file opened in output mode, the old file
is erased (overwritten) and all its data is lost.
When opening a file for input or output, good programming practice requires checking
that the connection has been established before attempting to use the file. You can do this
with the fail() method, which returns a true value if the file was opened unsuccessfully
(that is, it’s true the open failed) or a false value if the open succeeded. Typically, the
fail() method is used in code similar to the following, which attempts to open a file named
Point of Information
Input and Output Streams
A stream is a one-way transmission path between a source and a destination. In data
transmission, a stream of bytes is sent down this transmission path, similar to a stream
of water providing a one-way path for water to travel from a source to a destination.
Stream objects are created from stream classes. You have already used two stream
objects extensively: the input stream object named cin and the output stream object
named cout. The cin object, created from the istream stream class, provides a
transmission path from keyboard to program. The cout object, created from the
ostream stream class, provides a transmission path from program to screen. The
istream and ostream stream classes are parent classes to the iostream class.
When the iostream header file is included in a program with the #include
<iostream> directive, the cin and cout stream objects are declared automatically
and opened by the C++ compiler.
File stream objects provide the same capabilities as the cin and cout objects,
except they connect a program to a file rather than the keyboard or screen. File stream
objects must be declared explicitly as objects of the ifstream class (for input) or
objects of the ofstream class (for output). The ifstream and ofstream classes are
made available by including the fstream header file with the directive #include
<fstream>. The fstream class is derived from the ifstream and ofstream
classes.
443
Chapter 8
I/O File Stream Objects and Methods
prices.dat for input, checks that a valid connection was made, and reports an error
message if the file wasn’t opened for input successfully:
ifstream inFile; // any object name can be used here
inFile.open("prices.dat"); // open the file
// check that the connection was successfully opened
if (inFile.fail())
{
cout << "nThe file was not successfully opened"
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
If the fail() method returns a true, indicating the open failed, this code displays an
error message. In addition, the exit() function, which is a request to the OS to end
program execution immediately, is called. The cstdlib header function must be included
in any program using exit(), and exit()’s single-integer argument is passed directly to
the OS for any further program action or user inspection. Throughout the remainder of the
book, this type of error checking is included whenever a file is opened. (Section 9.2 shows
how to use exception handling for the same type of error checking.) In addition to the
fail() method, C++ provides three other methods, listed in Table 8.2, for detecting a file’s
status.
Table 8.2 File Status Methods
Prototype Description
fail() Returns a Boolean true if the file hasn’t been opened
successfully; otherwise, returns a Boolean false value.
eof() Returns a Boolean true if a read has been attempted past
the end-of-file; otherwise, returns a Boolean false value.
The value becomes true only when the first character
after the last valid file character is read.
good() Returns a Boolean true value while the file is available for
program use. Returns a Boolean false value if a read has
been attempted past the end-of-file. The value becomes
false only when the first character after the last valid file
character is read.
bad() Returns a Boolean true value if a read has been
attempted past the end-of-file; otherwise, returns a false.
The value becomes true only when the first character
after the last valid file character is read.
Program 8.1 shows the statements required to open a file for input, including an
error-checking routine to ensure that the open was successful. A file opened for input is said
to be in read mode or input mode. (These two terms are synonymous.)
444 I/O Streams and Data Files
A sample run of Program 8.1 produces the following output:
The file has been successfully opened for reading.
A different check is required for output files (files that are written to) because if a file
exists with the same name as the file to be opened in output mode, the existing file is erased
and all its data is lost. To avoid this situation, the file is first opened in input mode to see
whether it exists. If it does, the user is given the choice of permitting it to be overwritten
when it’s opened later in output mode. The code to accomplish this check is shaded in
Program 8.2.
Program 8.1
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
using namespace std;
int main()
{
ifstream inFile;
inFile.open("prices.dat"); // open the file with the
// external name prices.dat
if (inFile.fail()) // check for a successful open
{
cout << "nThe file was not successfully opened"
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
cout << "nThe file has been successfully opened for reading."
<< endl;
// statements to read data from the file would be placed here
return 0;
}
445
Chapter 8
I/O File Stream Objects and Methods
Program 8.2
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
using namespace std;
int main()
{
ifstream inFile;
ofstream outFile;
inFile.open("prices.dat"); // attempt to open the file for input
char response;
if (!inFile.fail()) // if it doesn't fail, the file exists
{
cout << "A file by the name prices.dat exists.n"
<< "Do you want to continue and overwrite itn"
<< " with the new data (y or n): ";
cin >> response;
if (tolower(response) == 'n')
{
cout << "The existing file will not be overwritten." << endl;
exit(1); //terminate program execution
}
}
outFile.open("prices.dat"); // now open the file for writing
if (inFile.fail()) // check for a successful open
{
cout << "nThe file was not successfully opened"
<< endl;
exit(1);
}
cout << "The file has been successfully opened for output."
<< endl;
// statements to write to the file would be placed here
return 0;
}
446 I/O Streams and Data Files
The following two runs were made with Program 8.2:
A file by the name prices.dat exists.
Do you want to continue and overwrite it
with the new data (y or n): n
The existing file will not be overwritten.
and
A file by the name prices.dat exists.
Do you want to continue and overwrite it
with the new data (y or n): y
The file has been successfully opened for output.
Although Programs 8.1 and 8.2 can be used to open an existing file for reading and
writing, both programs lack statements to perform a read or write and close the file. These
topics are discussed shortly. Before moving on, however, it’s possible to combine the
declaration of an ifstream or ofstream object and its associated open statement into one
statement. For example, examine the following two statements in Program 8.1:
ifstream inFile;
inFile.open("prices.dat");
They can be combined into a single statement:
ifstream inFile("prices.dat");
Embedded and Interactive Filenames Programs 8.1 and 8.2 have two problems:
• The external filename is embedded in the program code.
• There’s no provision for a user to enter the filename while the program is running.
As both programs are written, if the filename is to change, a programmer must modify the
external filename in the call to open() and recompile the program. Both these problems can
be avoided by assigning the filename to a string variable.
A string variable, as used in this book, is a variable that can hold a string value, which is
any sequence of zero or more characters enclosed in quotation marks, such as "Hello
World" and "". Remember that the quotation marks delimit the beginning and end of a
string but aren’t stored as part of the string.
In declaring and initializing a string variable for use in an open() method, the string is
considered a C-string. (See the Point of Information “Using C-Strings as Filenames” for
precautions when using a C-string.) A safer alternative, and one used throughout this book,
is to use a string class object and convert it to a C-string by using the c_str() method.
447
Chapter 8
I/O File Stream Objects and Methods
After a string variable is declared to store a filename, it can be used in one of two ways.
First, as shown in Program 8.3a, it can be placed at the top of a program to clearly identify
a file’s external name, instead of embedding it in an open() method call.
Point of Information
Using C-Strings as Filenames
If you use a C-string (which is simply a one-dimensional array of characters) to store an
external filename, you must specify the C-string’s maximum length in brackets immedi-
ately after it’s declared. For example, examine the following declaration:
char filename[21] = "prices.dat";
The number in brackets (21) is one more than the maximum number of characters
that can be assigned to the variable filename because the compiler adds an end-of-
string character to terminate the string. Therefore, the string value "prices.dat",
which consists of 10 characters, is actually stored as 11 characters. In this example, the
maximum value that can be assigned to the string variable filename is a string value
consisting of 20 characters.
Program 8.3a
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
#include <string>
using namespace std;
int main()
{
string filename = "prices.dat"; // place the filename up front
ifstream inFile;
inFile.open(filename.c_str()); // open the file
if (inFile.fail()) // check for successful open
{
cout << "nThe file named " << filename
<< " was not successfully opened"
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
cout << "nThe file has been successfully opened for reading.n";
return 0;
}
448 I/O Streams and Data Files
In Program 8.3a, the string object is declared and initialized with the name filename.
This name is placed at the top of main() for easy file identification. When a string object
is used, as opposed to a string literal, the variable name isn’t enclosed in quotation marks in
the open() method call. In the open() call, the value of the string object, which is a
C-string, is provided by the expression filename.c_str().
Finally, in the fail() method, the file’s external name is displayed by inserting the
string object’s name in the cout output stream. External names of files are identified in this
manner in this book.
Another useful role string objects play is to permit users to enter the filename as the
program is executing. For example, the code
string filename;
cout << "Please enter the name of the file you wish to open: ";
cin >> filename;
allows a user to enter a file’s external name at runtime. The only restriction in this code is that
the user must not enclose the entered string value in quotation marks, and the entered string
value can’t contain any blanks. The reason no blanks can be included is that when cin is used,
the compiler terminates the string when it encounters a blank. Program 8.3b uses this code in the
context of a complete program.
Program 8.3b
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
#include <string>
using namespace std;
int main()
{
string filename;
ifstream inFile;
cout << "Please enter the name of the file you wish to open: ";
cin >> filename;
inFile.open(filename.c_str()); // open the file
if (inFile.fail()) // check for successful open
{
cout << "nThe file named " << filename
<< " was not successfully opened"
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
cout << "nThe file has been successfully opened for reading.n";
return 0;
}
449
Chapter 8
I/O File Stream Objects and Methods
Point of Information
Using fstream Objects
In using ifstream and ofstream objects, the input or output mode is indicated by
the object. Therefore, ifstream objects must be used for input, and ofstream
objects must be used for output. Another means of creating file streams is to use
fstream objects that can be used for input or output, but this method requires an
explicit mode designation. An fstream object is declared by using the following
syntax:
fstream objectName;
When using the fstream class’s open() method, two arguments are required: a
file’s external name and a mode indicator. Here are the permissible mode indicators:
Indicator Description
ios::in Open a text file in input mode
ios::out Open a text file in output mode
ios::app Open a text file in append mode
ios::ate Go to the end of the opened file
ios::binary Open a binary file in input mode (default is text file)
ios::trunc Delete file contents if it exists
ios::nocreate If file doesn’t exist, open fails
ios::noreplace If file exists, open for output fails
As with ofstream objects, an fstream object in output mode creates a new file
and makes the file available for writing. If a file exists with the same name as a file
opened for output, the old file is erased. For example, the following statement declares
file1 as an object of type fstream:
fstream file1;
The following statement attempts to open the text file prices.dat for output:
file1.open("prices.dat",ios::out);
After this file has been opened, the program accesses the file by using the internal
object name file1, and the computer saves the file under the external name
prices.dat.
An fstream file object opened in append mode means an existing file is avail-
able for data to be added to the end of the file. If the file opened for appending
doesn’t exist, a new file with the designated name is created and made available to
receive output from the program. For example, the following statement declares file1
to be of type fstream and attempts to open a text file named prices.dat and
make it available for data to be added to the end of the file:
file1.open("prices.dat",ios::app);
continued...
450 I/O Streams and Data Files
The following is a sample output of Program 8.3b:
Please enter the name of the file you wish to open: foobar
The file named foobar was not successfully opened
Please check that the file currently exists.
Closing a File A file is closed by using the close() method. This method breaks the
connection between the file’s external name and the file stream object, which can be used
for another file. Examine the following statement, which closes the inFile stream’s
connection to its current file:
inFile.close();
As indicated, the close() method takes no argument.
Because all computers have a limit on the maximum number of files that can be open at
one time, closing files that are no longer needed makes good sense. Any open files existing
at the end of normal program execution are closed automatically by the OS.
EXERCISES 8.1
1. (Practice) Write declaration and open statements that link the following external filenames
to their corresponding internal object names. All files are text-based.
Point of Information
Using fstream Objects (continued)
Finally, an fstream object opened in input mode means an existing external file
has been connected and its data is available as input. For example, the following state-
ment declares file1 to be of type fstream and attempts to open a text file named
prices.dat for input:
file1.open("prices.dat",ios::in);
The mode indicators can be combined by the bitwise OR operator, | (see
Section 15.2). For example, the following statement opens the file1 stream, which
can be an fstream or ifstream, as an input binary stream:
file1.open("prices.dat", ios::in | ios::binary)
If the mode indicator is omitted as the second argument for an ifstream object,
the stream is opened as a text input file by default; if the mode indicator is omitted for
an ofstream object, the stream is opened as a text output file by default.
451
Chapter 8
I/O File Stream Objects and Methods
External Filename Internal Object Name Mode
coba.mem memo output
book.let letter output
coupons.bnd coups append
yield.bnd yield append
prices.dat priFile input
rates.dat rates input
2. (Practice) a. Write a set of two statements that declares the following objects as
ifstream objects, and then opens them as text input files: inData.txt, prices.txt,
coupons.dat, and exper.dat.
b. Rewrite the two statements for Exercise 2a, using a single statement.
3. (Practice) a. Write a set of two statements that declares the following objects as
ofstream objects, and then opens them as text output files: outDate.txt, rates.txt,
distance.txt, and file2.txt.
b. Rewrite the two statements for Exercise 3a, using a single statement.
4. (Practice) Enter and execute Program 8.1 on your computer.
5. (Practice) Enter and execute Program 8.2 on your computer.
6. (Practice) a. Enter and execute Program 8.3a on your computer.
b. Add a close() method to Program 8.3a, and then execute the program.
7. (Practice) a. Enter and execute Program 8.3b on your computer.
b. Add a close() method to Program 8.3b, and then execute the program.
8. (Practice) Using the reference manuals provided with your computer’s OS, determine the
following:
a. The maximum number of characters the computer can use to name a file for storage
b. The maximum number of data files that can be open at the same time
9. (Practice) Would it be appropriate to call a saved C++ program a file? Why or why not?
10. (Practice) a. Write declaration and open statements to link the following external file-
names to their corresponding internal object names. Use only ifstream and ofstream
objects.
External Name Internal Object Name Mode
coba.mem memo binary and output
coupons.bnd coups binary and append
prices.dat priFile binary and input
b. Redo Exercise 10a, using only fstream objects.
c. Write close statements for each file opened in Exercise 10a.
452 I/O Streams and Data Files
Point of Information
Checking for a Successful Connection
You must check that the open() method established a connection between a file
stream and an external file successfully because the open() call is a request to the OS
that can fail for various reasons. Chief among these reasons is a request to open an
existing file for reading that the OS can’t locate or a request to open a file for output
in a nonexistent folder. If the OS can’t satisfy the open request, you need to know
about it and terminate your program. Failure to do so can result in abnormal program
behavior or a program crash.
There are two styles of coding for checking the return value. The most common
method for checking that a fail didn’t occur when attempting to use a file for input is
the one coded in Program 8.1. It’s used to distinguish the open() request from the
check made via the fail() call and is repeated here for convenience:
inFile.open("prices.dat"); // request to open the file
if (inFile.fail()) // check for a failed connection
{
cout << "nThe file was not successfully opened"
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
Similarly, the check made in Program 8.2 is typically included when a file is being
opened in output mode. Alternatively, you might encounter programs that use
fstream objects in place of ifstream and ofstream objects (see the previous Point
of Information box). When using fstream’s open() method, two arguments are
required: a file’s external name and an explicit mode indication. Using an fstream
object, the open request and check for an input file typically appear as follows:
fstream inFile;
inFile.open("external name", ios::in);
if (inFile.fail())
{
cout << "nThe file was not successfully opened"
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
Many times, the conditional expression inFile.fail() is replaced by the
equivalent expression !inFile. Although ifstream and ofstream objects are
always used in this book, be prepared to encounter styles that use fstream objects.
453
Chapter 8
I/O File Stream Objects and Methods
8.2 Reading and Writing Character-Based Files
Reading or writing character-based files involves almost the identical operations for reading
input from the keyboard and writing data to the screen. For writing to a file, the cout object
is replaced by the ofstream object name declared in the program. For example, if
outFile is declared as an object of type ofstream, the following output statements are
valid:
outFile << 'a';
outFile << "Hello World!";
outFile << descrip << ' ' << price;
The filename in each of these statements, in place of cout, directs the output stream to
a specific file instead of to the standard display device (the screen). Program 8.4 shows using
the insertion operator, <<, to write a list of descriptions and prices to a file.
Program 8.4
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
#include <string>
#include <iomanip> // needed for formatting
using namespace std;
int main()
{
string filename = "prices.dat"; // put the filename up front
ofstream outFile;
outfile.open(filename.c_str());
if (outFile.fail())
{
cout << "The file was not successfully opened" << endl;
exit(1);
}
// set the output file stream formats
outFile << setiosflags(ios::fixed)
<< setiosflags(ios::showpoint)
<< setprecision(2);
墌
454 I/O Streams and Data Files
When Program 8.4 runs, the, prices.dat file is created and saved by the computer as
a text file. It’s a sequential file consisting of the following data:
Mats 39.95
Bulbs 3.22
Fuses 1.08
The actual storage of characters in the file depends on the character codes the computer
uses. Although only 30 characters appear to be stored in the file—corresponding to the
descriptions, blanks, and prices written to the file—the file contains 36 characters.
The extra characters consist of the newline escape sequence at the end of each line
created by the endl manipulator, which is created as a carriage return character (cr) and
linefeed (lf). Assuming characters are stored with the ASCII code, the prices.dat file is
physically stored as shown in Figure 8.2. For convenience, the character corresponding to
each hexadecimal code is listed below the code. A code of 20 represents the blank character.
Additionally, C and C++ append the low-value hexadecimal byte 0x00 as the end-of-file
(EOF) sentinel when the file is closed. This EOF sentinel is never counted as part of the file.
// send data to the file
outFile << "Mats " << 39.95 << endl
<< "Bulbs " << 3.22 << endl
<< "Fuses " << 1.08 << endl;
outFile.close();
cout << "The file " << filename
<< " has been successfully written." << endl;
return 0;
}
4D
M
61
a
74
t
73
s
20 33
3
39
9
2E
.
39
9
35
5
0D
cr
0A
1f
42
B
75
u
6C
l
62
b
73
s
20
33
3
2E
.
32
2
32
2
0D
cr
0A
1f
46
F
75
u
73
s
65
e
73
s
20 31
1
2E
.
30
0
38
8
0D
cr
0A
1f
Figure 8.2 The prices.dat file as stored by the computer
455
Chapter 8
Reading and Writing Character-
Based Files
Reading from a Text File
Reading data from a character-based file is almost identical to reading data from a standard
keyboard, except the cin object is replaced by the ifstream object declared in the
program. For example, if inFile is declared as an object of type ifstream that’s opened
for input, the following statement reads the next two items in the file and stores them in the
variables descrip and price:
inFile >> descrip >> price;
The file stream name in this statement, in place of cin, directs the input to come from
the file stream rather than the standard input device stream. Table 8.3 lists other methods
that can be used for stream input. These methods must be preceded by a stream object
name. All these methods, except getline(), are defined in the iostream class. The
getline() method is defined in the string class.
Point of Information
Formatting Text File Output Stream Data
Output file streams can be formatted in the same manner as the cout standard output
stream. For example, if an output stream named fileOut has been declared, the fol-
lowing statement formats all data inserted in the fileOut stream in the same way
these parameterized manipulators work for the cout stream:
fileOut << setiosflags(ios::fixed)
<< setiosflags(ios::showpoint)
<< setprecision(2);
The first manipulator parameter, ios::fixed, causes the stream to output all num-
bers as though they were floating-point values. The next parameter, ios::showpoint,
tells the stream to provide a decimal point. Therefore, a value such as 1.0 appears as 1.0,
not 1. Finally, the setprecision() manipulator tells the stream to display two decimal
values after the decimal point. Therefore, the number 1.0, for example, appears as 1.00.
Instead of using manipulators, you can use the stream methods setf() and
precision(). For example, the previous formatting can be accomplished with the
following code:
fileOut.setf(ios::fixed);
fileOut.setf(ios::showpoint);
fileOut.precision(2);
Which style you select is a matter of preference. In both cases, the formats need
be specified only once and remain in effect for every number subsequently inserted in
the file stream.
456 I/O Streams and Data Files
Table 8.3 Stream Input Class Methods
Method Name Description
get() Returns the next character extracted from the input
stream as an int.
get(charVar) Overloaded version of get() that extracts the next
character from the input stream and assigns it to the
specified character variable, charVar.
getline(fileObject,
strObj, termChar)
Extracts characters from the specified input stream,
fileObject, until the terminating character,
termChar, is encountered. Assigns the characters to
the specified string class object, strObj.
peek() Returns the next character in the input stream
without extracting it from the stream.
ignore(int n) Skips over the next n characters. If n is omitted, the
default is to skip over the next single character.
Program 8.5 shows how the prices.dat file created in Program 8.4 can be read. This
program illustrates one way of detecting the EOF marker by using the good() method (see
Table 8.2). Because this method returns a Boolean true value before the EOF marker has
been read or passed over, it can be used to verify that the data read is valid file data. Only
after the EOF marker has been read or passed over does this method return a Boolean false.
Therefore, the notation while(inFile.good()) used in Program 8.5 ensures that the
data is read from the file before the EOF has been read.
Point of Information
The put() Method
All output streams have access to the fstream class’s put() method, which permits
character-by-character output to a stream. This method works in the same manner as
the character insertion operator, <<. The syntax of this method call is the following:
ofstreamName.put(characterExpression);
The characterExpression can be a character variable or literal value. For
example, the following code can be used to output an 'a' to the standard output
stream:
cin.put('a');
In a similar manner, if outFile is an ofstream object file that has been opened,
the following code outputs the character value in the character variable named
keycode to this output:
char keycode;
.
.
outFile.put(keycode);
457
Chapter 8
Reading and Writing Character-
Based Files
Program 8.5 produces the following display:
Mats 39.95
Bulbs 3.22
Fuses 1.08
Program 8.5
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
#include <string>
using namespace std;
int main()
{
string filename = "prices.dat"; // put the filename up front
string descrip;
double price;
ifstream inFile;
inFile.open(filename.c_str());
if (inFile.fail()) // check for successful open
{
cout << "nThe file was not successfully opened"
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
// read and display the file's contents
inFile >> descrip >> price;
while (inFile.good()) // check next character
{
cout << descrip << ' ' << price << endl;
inFile >> descrip >> price;
}
inFile.close();
return 0;
}
458 I/O Streams and Data Files
Point of Information
A Way to Identify a File’s Name and Location
During program development, test files are usually placed in the same directory as the
program. Therefore, a method call such as inFile.open("exper.dat") causes no
problems to the OS. In production systems, however, it’s not uncommon for data files
to reside in one directory and program files to reside in another. For this reason, includ-
ing the full pathname of any file that’s opened is always a good idea.
For example, if the exper.dat file resides in the C:testfiles directory, the
open() call should include the full pathname: inFile.open("C:test
filesexper.dat"). Then, no matter where the program is run from, the OS
knows where to locate the file. Note the use of double backslashes, which is required.
Another important convention is to list all filenames at the top of a program
instead of embedding the names deep in the code. You can do this easily by using
string variables to store each filename. For example, if the statement
string filename = "c:testfilesexper.dat";
is placed at the top of a program file, the declaration statement clearly lists both the
name of the file and its location. Then, if some other file is to be tested, all that’s
required is a simple one-line change at the top of the program.
Using a string variable for the file’s name is also useful for the fail() method
check. For example, take a look at the following code:
string filename;
ifstream infile;
inFile.open(filename.c_str());
if (inFile.fail())
{
cout << "n The file named " << filename
<< was not successfully opened"
<<n Please check that this file currently exists.";
exit(1);
}
In this code, the name of the file that failed to open is displayed in the error mes-
sage without the name being embedded as a string value.
459
Chapter 8
Reading and Writing Character-
Based Files
Examine the expression inFile.good() used in the while statement. This expres-
sion is true as long as the EOF marker hasn’t been read. Therefore, as long as the item read
is good, the loop continues to read the file. Within the loop, the items just read are displayed,
and then a new string and a double-precision number are input to the program. When the
EOF has been detected, the expression returns a Boolean value of false and the loop
terminates. This termination ensures that data is read and displayed up to, but not including,
the EOF marker.
A replacement for the statement while(inFile.good()) is while(!inFile.
eof()), which is read as "while the end of file has not been reached." This replacement
works because the eof() method returns a true only after the EOF marker has been read
or passed over. In effect, the relational expression checks that the EOF hasn’t been
read—hence, the use of the NOT operator, !.
Another means of detecting the EOF is to use the fact that the extraction operation, >>,
returns a Boolean value of true if data is extracted from a stream; otherwise, it returns a
Boolean false value. Using this return value, the following code can be used in Program 8.5
to read the file:
// read and display the file's contents
while (inFile >> descrip >> price) // check next character
cout << descrip << ' ' << price << endl;
Although this code seems a bit cryptic at first glance, it makes perfect sense when you
understand that the expression being tested extracts data from the file and returns a Boolean
value to indicate whether the extraction was successful.
Finally, in the previous while statement or in Program 8.5, the expression inFile >>
descrip >> price can be replaced by a getline() method (see Table 8.3). For file
input, this method has the following syntax:
getline(fileObject, strObj, terminatingChar)
fileObject is the name of the ifstream file, strObj is a string class object, and
terminatingChar is an optional character constant or variable specifying the terminating
character. If this optional third argument is omitted, the default terminating character is the
newline ('n') character. Program 8.6 shows using getline() in the context of a complete
program.
Program 8.6 is a line-by-line text-copying program, which reads a line of text from the file
and then displays it on the screen. The output of Program 8.6 is the following:
Mats 39.95
Bulbs 3.22
Fuses 1.08
If obtaining the description and price as separate variables were necessary, either Program 8.5
should be used, or the string returned by getline() in Program 8.6 must be processed further
to extract the separate data items. (See Section 8.6 for parsing procedures.)
460 I/O Streams and Data Files
Standard Device Files
The file stream objects you have seen so far have been logical file objects. A logical file object
is a stream that connects a file of logically related data, such as a data file, to a program. In
addition to logical file objects, C++ supports physical file objects. A physical file object is a
stream that connects to a hardware device, such as a keyboard, screen, or printer.
The actual physical device assigned to your program for data entry is formally called the
standard input file. Usually, it’s the keyboard. When a cin object method call is encountered
in a C++ program, it’s a request to the OS to go to this standard input file for the expected
input. Similarly, when a cout object method call is encountered, the output is automatically
displayed or “written to” a device that has been assigned as the standard output file. For most
systems, it’s a computer screen, although it can also be a printer.
Program 8.6
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
#include <string>
using namespace std;
int main()
{
string filename = "prices.dat"; // put the filename up front
string line;
ifstream inFile;
inFile.open(filename.c_str());
if (inFile.fail()) // check for successful open
{
cout << "nThe file was not successfully opened"
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
// read and display the file's contents
while (getline(inFile,line))
cout << line << endl;
inFile.close();
return 0;
}
461
Chapter 8
Reading and Writing Character-
Based Files
When a program is executed, the standard input stream cin is connected to the standard
input device. Similarly, the standard output stream cout is connected to the standard output
device. These two object streams are available for programmer use, as are the standard error
stream, cerr, and the standard log stream, clog. Both these streams connect to the screen.
Other Devices
The keyboard, display, error, and log streams are connected automatically to the stream objects
cin, cout, cerr, and clog when the iostream header file is included in a program. Other
devices can be used for input or output if the name assigned by the system is known. For
example, most IBM or IBM-compatible PCs assign the name prn to the printer connected to the
computer. For these computers, a statement such as outFile.open("prn") connects the
Point of Information
The get() and putback() Methods
All input streams have access to the fstream class’s get() method, used for
character-by-character input from an input stream. This method works similarly to char-
acter extraction, using the >> operator, with two important differences: If a newline
character, 'n', or a blank character, ' ', is encountered, these characters are read in
the same manner as any other alphanumeric character. The syntax of this method call is
the following:
istreamName.get(characterVariable);
For example, the following code can be used to read the next character from the
standard input stream and store the character in the variable ch:
char ch;
cin.get(ch);
Similarly, if inFile is an ifstream object that has been opened to a file, the
following code reads the next character in the stream and assigns it to the character
variable keycode:
char keycode;
inFile.get(keycode);
In addition to the get() method, all input streams have a putback() method
for putting the last character read from an input stream back on the stream. This
method has the following syntax (with characterExpression representing any
character variable or character value):
ifstreamName.putback(characterExpression);
The putback() method provides output capability to an input stream. The put-
back character need not be the last character read; it can be any character. All putback
characters, however, have no effect on the data file. They affect only the open input
stream. Therefore, the data file characters remain unchanged, although the characters
subsequently read from the input stream can change.
462 I/O Streams and Data Files
printer to the ofstream object named outFile. A subsequent statement, such as outFile
<< "Hello World!";, would cause the string Hello World! to be output directly to the
printer. As the name of an actual file, prn must be enclosed in quotation marks in the open()
method call.
EXERCISES 8.2
1. (Practice and Modify) a. Enter and execute Program 8.5.
b. Modify Program 8.5 to use the expression !inFile.eof() in place of the expression
inFile.good(), and execute the program to see whether it operates correctly.
2. (Practice and Modify) a. Enter and execute Program 8.6.
b. Modify Program 8.6 by replacing cout with cerr, and verify that the output for the
standard error stream is the screen.
c. Modify Program 8.6 by replacing cout with clog, and verify that the output for the
standard log stream is the screen.
3. (Practice and Modify) a. Write a C++ program that accepts lines of text from the key-
board and writes each line to a file named text.dat until an empty line is entered. An
empty line is a line with no text that’s created by pressing the Enter (or Return) key.
b. Modify Program 8.6 to read and display the data stored in the text.dat file created
in Exercise 3a.
4. (Practice) Determine the OS command or procedure your computer provides to display
the contents of a saved file.
5. (Data Processing) a. Create a text file named employee.dat containing the
following data:
Anthony A 10031 7.82 12/18/2008
Burrows W 10067 9.14 06/9/2006
Fain B 10083 8.79 05/18/2007
Janney P 10095 10.57 09/28/2008
Smith G 10105 8.50 12/20/2007
b. Write a C++ program to read the employee.dat file created in Exercise 5a and pro-
duce a duplicate copy of the file named employee.bak.
c. Modify the program written in Exercise 5b to accept the names of the original and
duplicate files as user input.
d. The program written for Exercise 5c always copies data from an original file to a duplicate
file. What’s a better method of accepting the original and duplicate filenames, other than
prompting the user for them each time the program runs?
463
Chapter 8
Reading and Writing Character-
Based Files
6. (Data Processing) a. Write a C++ program that opens a file and displays its contents with
line numbers. That is, the program should print the number 1 before displaying the first line,
print the number 2 before displaying the second line, and so on for each line in the file.
b. Modify the program written in Exercise 6a to list the file’s contents on the printer
assigned to your computer.
7. (Data Processing) a. Create a text file containing the following data (without the
headings):
Name Social Security Number Hourly Rate Hours Worked
B Caldwell 555-88-2222 7.32 37
D Memcheck 555-77-4444 8.32 40
R Potter 555-77-6666 6.54 40
W Rosen 555-99-8888 9.80 35
b. Write a C++ program that reads the data file created in Exercise 7a and computes and
displays a payroll schedule. The output should list the Social Security number, name,
and gross pay for each person, calculating gross pay as Hourly Rate × Hours Worked.
8. (Data Processing) a. Create a text file containing the following data (without the
headings):
Car Number Miles Driven Gallons of Gas Used
54 250 19
62 525 38
71 123 6
85 1322 86
97 235 14
b. Write a C++ program that reads the data in the file created in Exercise 8a and displays
the car number, miles driven, gallons of gas used, and miles per gallon (mpg) for each car.
The output should contain the total miles driven, total gallons of gas used, and average
mpg for all cars. These totals should be displayed at the end of the output report.
9. (Data Processing) a. Create a text file with the following data (without the headings):
Part Number Initial Amount Quantity Sold Minimum Amount
QA310 95 47 50
CM145 320 162 200
MS514 34 20 25
EN212 163 150 160
464 I/O Streams and Data Files
b. Write a C++ program to create an inventory report based on the data in the file cre-
ated in Exercise 9a. The display should consist of the part number, current balance,
and the amount needed to bring the inventory to the minimum level. The current
balance is the initial amount minus the quantity sold.
8.3 Random File Access
The term file access refers to the process of retrieving data from a file. There are two types
of file access: sequential access and random access. To understand file access types, first you
need to understand how data is organized in a file.
The term file organization refers to the way data is stored in a file. The files you have
used, and will continue to use, have a sequential organization, meaning characters in the file
are stored in a sequential manner. In addition, each open file has been read in a sequential
manner, meaning characters are accessed one after another, which is called sequential access.
Although characters are stored sequentially, they don’t have to be accessed the same way. In
fact, you can skip over characters and read a sequentially organized file in a nonsequential
manner.
In random access, any character in the opened file can be read without having to
sequentially read all characters stored ahead of it first. To provide random access to files, each
ifstream object creates a file position marker automatically. This marker is a long integer
representing an offset from the beginning of the file and keeps track of where the next
character is to be read from or written to. Table 8.4 lists the methods used to access and
change the file position marker. The suffixes g and p in these method names denote get
and put; get refers to an input (get from) file, and put refers to an output (put to) file.
Table 8.4 File Position Marker Methods
Name Description
seekg(offset, mode) For input files, move to the offset position indicated by
the mode.
seekp(offset, mode) For output files, move to the offset position indicated
by the mode.
tellg(void) For input files, return the current value of the file
position marker.
tellp(void) For output files, return the current value of the file
position marker.
The seek() methods allow the programmer to move to any position in the file. To
understand these methods, you must understand how data is referenced in the file by using
the file position marker.
Each character in a data file is located by its position in the file. The first character in the
file is located at position 0, the next character at position 1, and so forth. A character’s position
is referred to as its offset from the start of the file. Therefore, the first character has a 0 offset,
the second character has an offset of 1, and so on, for each character in the file.
The seek() methods require two arguments: the offset, as a long integer, in the file and
where the offset is to be calculated from, determined by the mode. The three alternatives for the
mode are ios::beg, ios::cur, and ios::end, which denote the beginning of the file,
465
Chapter 8
Random File Access
current position, and end of the file. Therefore, the mode ios::beg means the offset is the true
offset from the start of the file. The mode ios::cur means the offset is relative to the current
position in the file, and the mode ios::end means the offset is relative to the end of the file.
A positive offset means move forward in the file, and a negative offset means move backward.
Examples of seek() method calls are shown in the following code. In these examples,
inFile has been opened as an input file and outFile as an output file. The offset passed
to seekg() and seekp() must be a long integer, hence the uppercase L appended to each
number in the method calls.
inFile.seekg(4L,ios::beg); // go to the fifth character in the input file
outFile.seekp(4L,ios::beg); // go to the fifth character in the output file
inFile.seekg(4L,ios::cur); // move ahead five characters in the input file
outFile.seekp(4L,ios::cur); // move ahead five characters in the output file
inFile.seekg(-4L,ios::cur); // move back five characters in the input file
outFile.seekp(-4L,ios::cur); // move back five characters in the output file
inFile.seekg(0L,ios::beg); // go to start of the input file
outfile.seekp(0L,ios::beg); // go to start of the output file
inFile.seekg(0L,ios::end); // go to end of the input file
outFile.seekp(0L,ios::end); // go to end of the output file
inFile.seekg(-10L,ios::end); // go to 10 characters before the input file's end
outFile.seekp(-10L,ios::end); // go to 10 characters before the output file's end
As opposed to seek() methods that move the file position marker, the tell()
methods return the file position marker’s offset value. For example, if 10 characters have
been read from an input file named inFile, the method call returns the long integer 10:
inFile.tellg();
This means the next character to be read is offset 10 byte positions from the start of the
file and is the 11th character in the file.
Program 8.7 shows using seekg() and tellg() to read a file in reverse order, from last
character to first. As each character is read, it’s also displayed.
Assume the test.dat file contains the following characters:
The grade was 92.5
The output of Program 8.7 is the following:
5 : . : 2 : 9 : : s : a : w : : e : d : a : r : g : : e : h : T :
466 I/O Streams and Data Files
Program 8.7
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
int main()
{
string filename = "test.dat";
char ch;
long offset, last;
ifstream inFile(filename.c_str());
if (inFile.fail()) // check for successful open
{
cout << "nThe file was not successfully opened"
<< "n Please check that the file currently exists"
<< endl;
exit(1);
}
inFile.seekg(0L,ios::end); // move to the end of the file
last = inFile.tellg(); // save the offset of the last character
for(offset = 1L; offset <= last; offset++)
{
inFile.seekg(-offset, ios::end);
ch = inFile.get();
cout << ch << " : ";
}
inFile.close();
cout << endl;
return 0;
}
467
Chapter 8
Random File Access
Program 8.7 initially goes to the last character in the file. The offset of this character, the
EOF character, is saved in the variable last. Because tellg() returns a long integer, last
has been declared as a long integer.
Starting from the end of the file, seekg() is used to position the next character to be
read, referenced from the end of the file. As each character is read, the character is displayed,
and the offset is adjusted to access the next character. The first offset used is -1, which
represents the character immediately preceding the EOF marker.
EXERCISES 8.3
1. (Practice) a. Create a file named test.dat containing the data in the test.dat file
used in Program 8.7. (You can use a text editor or copy the test.dat file from this
book’s Web site.)
b. Enter and execute Program 8.7 on your computer.
2. (Modify) Rewrite Program 8.7 so that the origin for the seekg() method used in the
for loop is the start of the file rather than the end.
3. (Modify) Modify Program 8.7 to display an error message if seekg() attempts to refer-
ence a position beyond the end of the file.
4. (Practice) Write a program that reads and displays every second character in a file named
test.dat.
5. (Practice) Using the seek() and tell() methods, write a function named
fileChars() that returns the total number of characters in a file.
6. (Practice) a. Write a function named readBytes() that reads and displays n characters
starting from any position in a file. The function should accept three arguments: a file object
name, the offset of the first character to be read, and the number of characters to be read.
(Note: The prototype for readBytes() should be void readBytes(fstream&,
long, int).)
b. Modify the readBytes() function written in Exercise 6a to store the characters read
into a string or an array. The function should accept the storage address as a fourth
argument.
8.4 File Streams as Function Arguments
A file stream object can be used as a function argument. The only requirement is that the
function’s formal parameter be a reference (see Section 6.3) to the appropriate stream, either
ifstream& or ofstream&. For example, in Program 8.8, an ofstream object named
outFile is opened in main(), and this stream object is passed to the inOut() function.
The function prototype and header for inOut() declare the formal parameter as a reference
to an ostream object type. The inOut() function is then used to write five lines of
user-entered text to the file.
468 I/O Streams and Data Files
Program 8.8
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
using namespace std;
int main()
{
string fname = "list.dat"; // here is the file you are working with
void inOut(ofstream&); // function prototype
ofstream outFile;
outFile.open(fname.c_str());
if (outFile.fail()) // check for a successful open
{
cout << "nThe output file " << fname << " was not successfully opened"
<< endl;
exit(1);
}
inOut(outFile); // call the function
return 0;
}
void inOut(ofstream& fileOut)
{
const int NUMLINES = 5; // number of lines of text
string line;
int count;
cout << "Please enter five lines of text:" << endl;
for (count = 0; count < NUMLINES; count++)
{
getline(cin,line);
fileOut << line << endl;
}
cout << "nThe file has been successfully written." << endl;
return;
}
469
Chapter 8
File Streams as Function Arguments
In main(), the file is an ofstream object named outFile. This object is passed to
the inOut() function and accepted as the formal parameter fileOut, which is declared to
be a reference to an ofstream object type. The inOut() function then uses its reference
parameter outFile as an output file stream name in the same manner that main() would
use the fileOut stream object. Program 8.8 uses the getline() method introduced in
Section 8.2 (see Table 8.3).
Program 8.9 expands on Program 8.8 by adding a getOpen() function to perform the open.
Like inOut(), getOpen() accepts a reference argument to an ofstream object. After the
getOpen() function finishes executing, this reference is passed to inOut(), as in Program 8.8.
Although you might be tempted to write getOpen() to return a reference to an ofstream, it
won’t work because it results in an attempt to assign a returned reference to an existing one.
Program 8.9
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
using namespace std;
int getOpen(ofstream&); // function prototype - pass a reference to an fstream
void inOut(ofstream&); // function prototype - pass a reference to an fstream
int main()
{
ofstream outFile; // filename is an fstream object
getOpen(outFile); // open the file
inOut(outFile); // write to it
return 0;
}
墌
470 I/O Streams and Data Files
Program 8.9 allows the user to enter a filename from the standard input device and then
opens the ofstream connection to the external file. If an existing data file’s name is
entered, the file is destroyed when it’s opened for output. A useful trick for preventing this
mishap is to open the entered file by using an input file stream. If the file exists, the fail()
method indicates a successful open (that is, the open doesn’t fail), which indicates the file is
available for input. This technique can be used to alert the user that a file with the entered
name exists in the system and to request confirmation that data in the file can be destroyed
and the file opened for output. Before the file is reopened for output, the input file stream
should be closed. Implementing this trick is left for you to try in Exercise 4.
int getOpen(ofstream& fileOut)
{
string name;
cout << "nEnter a file name: ";
getline(cin,name);
fileOut.open(name.c_str()); // open the file
if (fileOut.fail()) // check for successful open
{
cout << "Cannot open the file" << endl;
exit(1);
}
else
return 1;
}
void inOut(ofstream& fileOut)
{
const int NUMLINES = 5; // number of lines
int count;
string line;
cout << "Please enter five lines of text:" << endl;
for (count = 0; count < NUMLINES; ++count)
{
getline(cin,line);
fileOut << line << endl;
}
cout << "nThe file has been successfully written.";
return;
}
471
Chapter 8
File Streams as Function Arguments
EXERCISES 8.4
1. (Practice) A function named pFile() is to receive a filename as a reference to an
ifstream object. What declarations are required to pass a filename to pFile()?
2. (Practice) Write a function named fcheck() that checks whether a file exists. The
function should accept an ifstream object as a formal reference parameter. If the file
exists, the function should return a value of 1; otherwise, the function should return a
value of 0.
3. (Practice) A data file consisting of a group of lines has been created. Write a function
named printLine() that reads and displays any line of the file. For example, the func-
tion called printLine(fstream& fName,5); should display the fifth line of the
passed object stream.
4. (Modify) Rewrite the getOpen() function used in Program 8.9 to incorporate the file-
checking procedures described in this section. Specifically, if the entered filename exists,
an appropriate message should be displayed. The user should be presented with the
option of entering a new filename or allowing the program to overwrite the existing file.
Use the function written for Exercise 2 in your program.
8.5 A Case Study: Pollen Count File Update
After a data file has been created, application programs are typically written to read and
update the file with current data. In this case study, a file is used as a database for storing the
10 most recent pollen counts, which are used in the summer as allergy “irritability” measures.
As a new reading is obtained, it’s added to the file, and the oldest stored reading is deleted.
Step 1 Analyze the Problem
Pollen count readings, which are taken from August through September in the northeastern
United States, measure the number of ragweed pollen grains in the air. Pollen counts in the
range of 10 to 200 grains per cubic meter of air are normal during this time of year. Typically,
pollen counts above 10 begin affecting a small percentage of hay fever sufferers, counts in the
range of 30 to 40 noticeably bother approximately 30% of hay fever sufferers, and counts
between 40 and 50 adversely affect more than 60% of all hay fever sufferers.
A program is to be written that updates a file containing the 10 most recent pollen counts.
As a new count is obtained, it’s added to the end of the file, and the oldest count is deleted
from the file.1 Additionally, the average of the new file’s data is calculated and displayed. The
existing file, named pollen.in, contains the data shown in Figure 8.3.
The input data for this problem consist of a file of 10 integer numbers and a user-input
value of the most recent integer value pollen count. There are two required outputs:
• A file of the 10 most recent integer values
• The average of the data in the updated file
1
This type of data storage is formally referred to as a first-in/first-out (FIFO) list, also called a “queue.” If the list is maintained in last-in/first-out
order (LIFO), it’s called a “stack.”
472 I/O Streams and Data Files
Step 2 Develop a Solution
The algorithm for solving this problem is straightforward and is described by the following
pseudocode:
main() function
Display a message indicating what the program does.
Call the Input stream function.
Call the Output stream function.
Call the Update function.
Display the new 10-week average.
Input stream function
Request the name of the input data file.
Open an input file stream and validate a successful connection.
Output stream function
Request the name of the output data file.
Open an output file stream and validate a successful connection.
Update function
Request a new pollen count reading.
Read the oldest pollen count from the input data file.
For the remaining input file pollen counts:
Read an input value.
Add the value to a total.
Write the input value to the output file stream.
Endfor
Write the new pollen count to the output file stream.
Add the new pollen count to the total.
Calculate the average as total / (number of pollen counts).
Return the new 10-week average.
Close all files.
In reviewing this algorithm, notice that the oldest pollen count is read but never used in
any computation. The remaining pollen counts are read, “captured” in a total, and written to
the output data file. The last pollen count is then added to the total and also written to the
output data file. Finally, the average of the most recent pollen counts is computed and
displayed, and all file streams are closed.
30
60
40
80
90
120
150
130
160
170
Oldest pollen count
(to be deleted)
Last pollen count
Figure 8.3 Data currently in the pollen.in file
473
Chapter 8
A Case Study: Pollen Count File
Update
Step 3 Code the Solution
Program 8.10 presents a C++ representation of the selected design; the algorithm has been
coded as the pollenUpdate() function.
Program 8.10
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
using namespace std;
void openInput(ifstream&); // pass a reference to an ifstream
void openOutput(ofstream&); // pass a reference to an ofstream
double pollenUpdate(ifstream&, ofstream&); // pass two references
int main()
{
ifstream inFile; // inFile is an istream object
ofstream outFile; // outFile is an ofstream object
double average;
// display a user message
cout << "nnThis program reads the old pollen count file, "
<< "creates a current pollen"
<< "n count file, and calculates and displays "
<< "the latest 10-week average.";
openInput(inFile);
openOutput(outFile);
average = pollenUpdate(inFile, outFile);
cout << "nThe new 10-week average is: " << average << endl;
return 0;
}
墌
474 I/O Streams and Data Files
// this function gets an external filename and opens the file for input
void openInput(ifstream& fname)
{
string filename;
cout << "nnEnter the input pollen count filename: ";
cin >> filename;
fname.open(filename.c_str());
if (fname.fail()) // check for a successful open
{
cout << "nFailed to open the file named " << filename << "for input"
<< "n Please check that this file exists"
<< endl;
exit(1);
}
return;
}
// this function gets an external filename and opens the file for output
void openOutput(ofstream& fname)
{
string filename;
cout << "Enter the output pollen count filename: ";
cin >> filename;
fname.open(filename.c_str());
if (fname.fail()) // check for a successful open
{
cout << "nFailed to open the file named " << filename << "for output"
<< endl;
exit(1);
}
return;
}
墌
475
Chapter 8
A Case Study: Pollen Count File
Update
// the following function reads the pollen file,
// writes a new file,
// and returns the new weekly average
double pollenUpdate(ifstream& inFile, ofstream& outFile)
{
const int POLNUMS = 10; // maximum number of pollen counts
int i, polreading;
int oldreading, newcount;
double sum = 0;
double average;
// get the latest pollen count
cout << "Enter the latest pollen count reading: ";
cin >> newcount;
// read the oldest pollen count
inFile >> oldreading;
// read, sum, and write out the rest of the pollen counts
for(i = 0; i < POLNUMS; i++)
{
inFile >> polreading;
sum += polreading;
outFile << polreading << endl;
}
// write out the latest reading
outFile << newcount << endl;
// compute and display the new average
average = (sum + newcount) / double(POLNUMS);
inFile.close();
outFile.close();
cout << "nThe output file has been written.n";
return average;
}
476 I/O Streams and Data Files
Step 4 Test and Correct the Program
Testing Program 8.10 requires providing both valid and invalid input data for the program.
Invalid data consists of a nonexistent input data filename and a data file containing fewer than
10 items. Valid data consists of a file containing 10 integers. A sample run of Program 8.10
follows with a valid input file:
This program reads the old pollen count file, creates a current
pollen count file, and calculates and displays the latest
10-week average.
Enter the input pollen count filename: pollen.in
Enter the output pollen count filename: pollen.out
Enter the latest pollen count reading: 200
The output file has been written.
The new 10-week average is: 120
The updated file Program 8.10 creates is shown in Figure 8.4. In reviewing this file’s
contents, notice that the most current reading has been added to the end of the file, and
other pollen readings from the original file shown in Figure 8.3 have been moved up one
position in the new file. Also, notice that the output of the sample run calculates the new
10-week average correctly.
EXERCISES 8.5
1. (Practice) Write a C++ program to create the pollen.in file shown in Figure 8.3.
2. (Practice) Using the file created in Exercise 1 or the pollen.in file provided on this
book’s Web site, enter and run Program 8.10 on your computer.
60
40
80
90
120
150
130
160
170
200
Oldest pollen count
Most recent reading
Figure 8.4 The updated pollen.in file
477
Chapter 8
A Case Study: Pollen Count File
Update
3. (Conversion) a. A file named polar.dat contains the polar coordinates needed in a
graphics program. Currently, this file contains the following data:
Distance (Inches) Angle (Degrees)
2.0 45.0
6.0 30.0
10.0 45.0
4.0 60.0
12.0 55.0
8.0 15.0
Write a C++ program to create this file on your computer.
b. Using the polar.dat file created in Exercise 3a, write a C++ program that accepts
distance and angle data from the user and adds the data to the end of the file.
c. Using the polar.dat file created in Exercise 3a, write a C++ program that reads this
file and creates a second file named xycord.dat. The entries in the new file should
contain the rectangular coordinates corresponding to the polar coordinates in the
polar.dat file. Polar coordinates are converted to rectangular coordinates by using
these formulas:
x = r (cos θ )
y = r (sin θ )
The r is the distance coordinate and θ is the radian equivalent of the angle coordi-
nate in the polar.dat file.
4. (Data Processing) a. Write a C++ program to create a data file containing the following
information:
Student ID
Number
Student Name Course Code Course
Credits
Course
Grade
2333021 BOKOW, R. NS201 3 A
2333021 BOKOW, R. MG342 3 A
2333021 BOKOW, R. FA302 1 A
2574063 FALLIN, D. MK106 3 C
2574063 FALLIN, D. MA208 3 B
2574063 FALLIN, D. CM201 3 C
2574063 FALLIN, D. CP101 2 B
2663628 KINGSLEY, M. QA140 3 A
2663628 KINGSLEY, M. CM245 3 B
2663628 KINGSLEY, M. EQ521 3 A
2663628 KINGSLEY, M. MK341 3 A
2663628 KINGSLEY, M. CP101 2 B
478 I/O Streams and Data Files
b. Using the file created in Exercise 4a, write a C++ program that creates student grade
reports. The grade report for each student should contain the student’s name and ID
number, a list of courses taken, the credits and grade for each course, and a semester
grade point average (GPA). For example, this is the grade report for the first student:
Student Name: BOKOW, R.
Student ID Number: 2333021
Course Code Course Credits Course Grade
NS201 3 A
MG342 3 A
FA302 1 A
Total Semester Course Credits Completed: 7
Semester GPA: 4.0
The semester GPA is computed in two steps. First, each course grade is assigned a
numerical value (A = 4, B = 3, C = 2, D = 1, F = 0), and the sum of each course’s
grade value times the credits for each course is computed. This sum is then divided
by the total number of credits taken during the semester.
5. (File Update) a. Write a C++ program to create a data file containing the following
information:
Student ID Number Student Name Course Credits Course GPA
2333021 BOKOW, R. 48 4.0
2574063 FALLIN, D. 12 1.8
2663628 KINGSLEY, M. 36 3.5
b. Write a C++ program to update the file created in Exercise 5a with the data from the
file created in Exercise 4a.
8.6 A Closer Look: The iostream Class Library2
As you have seen, the classes in the iostream class library access files by using entities
called streams. For most systems, the data bytes transferred on a stream represent ASCII
characters or binary numbers. The mechanism for reading a byte stream from a file or writing
a byte stream to a file is hidden when using a high-level language, such as C++. Nevertheless,
understanding this mechanism is useful so that you can place the services provided by the
iostream class library in context.
File Stream Transfer Mechanism
Figure 8.5 illustrates the mechanism for transferring data between a program and a file. As
shown, this transfer involves an intermediate file buffer contained in the computer’s memory.
2
This topic can be omitted on first reading without loss of subject continuity.
479
Chapter 8
A Closer Look: The iostream
Class Library
Each opened file is assigned its own file buffer, which is a storage area used by the data
transferred between the program and the file.
The program either writes a set of data bytes to the file buffer or reads a set of data bytes
from the file buffer by using a stream object. The data transfer between the device storing
the data file (usually a disk or CD/DVD) and the file buffer is handled by special OS
programs. These programs, called device drivers, aren’t stand-alone programs; they’re an
integral part of the OS. A device driver is a section of OS code that accesses a hardware device,
such as a disk, and handles the data transfer between the device and the computer’s memory.
Because the computer’s internal data transfer rate is generally much faster than any device
connected to it, the device driver must correctly synchronize the data transfer speed between
the computer and the device sending or receiving data.
Typically, a disk device driver transfers data between the disk and file buffer only in fixed
sizes, such as 1024 bytes at a time. Therefore, the file buffer is a convenient means of
permitting a device driver to transfer data in blocks of one size, and the program can access
them by using a different size (typically, as separate characters or as a fixed number of
characters per line).
Components of the iostream Class Library
The iostream class library consists of two primary base classes: streambuf and ios. The
streambuf class provides the file buffer, illustrated in Figure 8.5, and general routines for
transferring binary data. The ios class contains a pointer to the file buffers provided by the
streambuf class and general routines for transferring text data. From these two base classes,
several other classes are derived and included in the iostream class library.
Figure 8.6 is an inheritance diagram for the ios family of classes as it relates to the
ifstream, ofstream, and fstream classes. Figure 8.7 is an inheritance diagram for the
streambuf family of classes. In these diagrams, the arrows point from a derived class to a
base class.
Table 8.5 lists the correspondence between the classes shown in Figures 8.6 and 8.7,
including the header files defining these classes.
Disk, tape, or
CD/DVD
Computer memory
Transfer handled
by a device driver
Transfer handled
by iostream library
Program
Buffer
File
Figure 8.5 The data transfer mechanism
480 I/O Streams and Data Files
Table 8.5 Correspondence Between Classes in Figures 8.6 and 8.7
ios Class streambuf Class Header File
istream
ostream
iostream
streambuf iostream or fstream
ifstream
ofstream
fstream
filebuf fstream
Therefore, the ifstream, ofstream, and fstream classes you have used for file
access use a buffer provided by the filebuf class and defined in the fstream header file.
Similarly, the cin, cout, cerr, and clog iostream objects use a buffer provided by the
streambuf class and defined in the iostream header file.
frstream
iostream
fstream
istream ostream
ios
ifstream ofstream
Figure 8.6 The base class ios and its derived classes
streambuf
filebuf strstreambuf
Figure 8.7 The base class streambuf and its derived classes
481
Chapter 8
A Closer Look: The iostream
Class Library
In-Memory Formatting
In addition to the classes shown in Figure 8.7, a class named strstream is derived from the
ios class. This class uses the strstreambuf class shown in Figure 8.7, requires the
strstream header file, and provides capabilities for writing and reading strings to and from
in-memory defined streams.
As an output stream, these streams are typically used to “assemble” a string from smaller
pieces until a complete line of characters is ready to be written to cout or to a file. Attaching
a strstream object to a buffer for this purpose is similar to attaching an fstream object
to an output file. For example, the statement
strstream inmem(buf, 72, ios::out);
attaches a strstream object to an existing buffer of 72 bytes in output mode. Program 8.11
shows how this statement is used in the context of a complete program.
Program 8.11
#include <iostream>
#include <strstream>
#include <iomanip>
using namespace std;
int main()
{
const int MAXCHARS = 81; // one more than the maximum characters in a line
int units = 10;
double price = 36.85;
char buf[MAXCHARS];
strstream inmem(buf, MAXCHARS, ios::out); // open an in-memory stream
// write to the buffer through the stream
inmem << "No. of units = "
<< setw(3) << units
<< " Price per unit = $"
<< setw(6) << setprecision(2) << fixed << price << '0';
cout << '|' << buf << '|';
cout << endl;
return 0;
}
482 I/O Streams and Data Files
Program 8.11 produces the following output:
|No. of units = 10 Price per unit = $ 36.85|
This output illustrates that the character buffer has been filled in correctly by insertions to
the inmem stream. (Note that the end-of-string NULL, '0', which is the last insertion to the
stream, is required to close off the C-string correctly.) After the character array has been filled, it’s
written to a file as a single string.
In a similar manner, a strstream object can be opened in input mode. This stream
would be used as a working storage area, or buffer, for storing a complete line of text from
a file or standard input. After the buffer has been filled, the extraction operator would be
used to “disassemble” the string into component parts and convert each data item into its
designated data type. Doing this permits inputting data from a file on a line-by-line basis
before assigning data items to their respective variables.
8.7 Common Programming Errors
The common programming errors with files are as follows:
1. Forgetting to open a file before attempting to read from it or write to it.
2. Using a file’s external name in place of the internal file stream object name when
accessing the file. The only stream method that uses the data file’s external name is
the open() method. As always, all stream methods discussed in this chapter must
be preceded by a stream object name followed by a period (the dot operator).
3. Opening a file for output without first checking that a file with the same name
already exists. If it does and you didn’t check for a preexisting filename, the file is
overwritten.
4. Not understanding that the end of a file is detected only after the EOF marker has
been read or passed over.
5. Attempting to detect the end of a file by using character variables for the EOF
marker. Any variable used to accept the EOF must be declared as an integer variable.
For example, if ch is declared as a character variable, the following expression
produces an infinite loop:3
while ( (ch = in.file.peek()) != EOF )
This problem occurs because a character variable can never take on an EOF code.
EOF is an integer value (usually -1) with no character representation, which ensures
that the EOF code can’t be confused with a legitimate character encountered as
normal data in the file. To terminate the loop created by the preceding expression,
the variable ch must be declared as an integer variable.
6. Using an integer argument with the seekg() and seekp() functions. This offset
must be a long integer constant or variable. Any other value passed to these functions
can have unpredictable results.
3
This infinite loop doesn’t occur on UNIX systems, where characters are stored as signed integers.
483
Chapter 8
Common Programming Errors
8.8 Chapter Summary
1. A data file is any collection of data stored together in an external storage medium under
a common name.
2. A data file is connected to a file stream by using fstream’s open() method. This
method connects a file’s external name with an internal object name. After the file is
opened, all subsequent accesses to the file require the internal object name.
3. A file can be opened in input or output mode. An opened output file stream creates a
new data file or erases the data in an existing opened file. An opened input file stream
makes an existing file’s data available for input. An error condition results if the file
doesn’t exist and can be detected by using the fail() method.
4. All file streams must be declared as objects of the ifstream or ofstream class.
Therefore, a declaration similar to either of the following must be included with the
declaration to open the file:
ifstream inFile;
ofstream outfile;
The stream object names inFile and outfile can be replaced with any user-selected
object name.
5. In addition to any files opened in a function, the standard stream objects cin, cout, and
cerr are declared and opened automatically when a program runs. cin is an input file
stream object used for data entry (usually from the keyboard), cout is an output file stream
object used for data display (usually on screen), and cerr is an output file stream object
used for displaying system error messages (usually on screen).
6. Data files can be accessed randomly by using the seekg(), seekp(), tellg(), and
tellp() methods. The g versions of these methods are used to alter and query the file
position marker for input file streams, and the p versions do the same for output file
streams.
7. Table 8.6 lists class-supplied methods for file manipulation. The getline() method is
defined in the string class, and all other methods are defined in the fstream class.
Table 8.6 File Manipulation Methods
Method Name Description
get() Extract the next character from the
input stream and return it as an int.
get(chrVar) Extract the next character from the
input stream and assign it to chrVar.
getline(fileObject, strObj,
termChar)
Extract the next string of characters
from the input file stream object and
assign them to strObj until the
specified terminating character is
detected. If omitted, the default
terminating character is a newline.
484 I/O Streams and Data Files
Table 8.6 File Manipulation Methods (continued)
Method Name Description
getline(C-stringVar,int n,'n') Extract and return characters from the
input stream until n-1 characters are
read or a newline is encountered
(terminates the input with a '0').
peek() Return the next character in the input
stream without extracting it from the
stream.
put(chrExp) Put the character specified by chrExp
on the output stream.
putback(chrExp) Push the character specified by chrExp
back onto the input stream. Does not
alter the data in the file.
ignore(int n) Skip over the next n characters; if n is
omitted, the default is to skip over the
next single character.
eof() Returns a Boolean true value if a read
has been attempted past the end of
file; otherwise, it returns a Boolean
false value. The value becomes true
only when the first character after the
last valid file character is read.
good() Returns a Boolean true value while the
file is available for program use. Returns
a Boolean false value if a read has
been attempted past the end of file.
The value becomes false only when
the first character after the last valid file
character is read.
bad() Returns a Boolean true value if a read
has been attempted past the end of
file; otherwise, it returns a false. The
value becomes true only when the
first character after the last valid file
character is read.
fail() Returns a Boolean true if the file
hasn’t been opened successfully;
otherwise, it returns a Boolean false
value.
485
Chapter 8
Chapter Summary
Programming Projects for Chapter 8
1. (Data Processing) a. Create a text file containing the following data (without the
headings):
Name Rate Hours
Callaway, G. 6.00 40
Hanson, P. 5.00 48
Lasard, D. 6.50 35
Stillman, W. 8.00 50
b. Write a C++ program that uses the information in the file created in Exercise 1a to
produce the following pay report for each employee:
Name Pay Rate Hours Regular Pay Overtime Pay Gross Pay
Compute regular pay as any hours worked up to and including 40 hours multiplied by
the pay rate. Compute overtime pay as any hours worked above 40 hours times a pay
rate of 1.5 multiplied by the regular rate. The gross pay is the sum of regular and
overtime pay. At the end of the report, the program should display the totals of the
regular, overtime, and gross pay columns.
2. (Data Processing) a. Store the following data in a file:
5 96 87 78 93 21 4 92 82 85 87 6 72 69 85 75 81 73
b. Write a C++ program to calculate and display the average of each group of numbers
in the file created in Exercise 2a. The data is arranged in the file so that each group
of numbers is preceded by the number of data items in the group. Therefore, the first
number in the file, 5, indicates that the next five numbers should be grouped
together. The number 4 indicates that the following four numbers are a group, and the
6 indicates that the last six numbers are a group. (Hint: Use a nested loop. The outer
loop should terminate when the end of file has been encountered.)
3. (Data Processing) Write a C++ program that allows the user to enter the following
information from the keyboard for each student in a class (up to 20 students):
Name Exam 1 Grade Exam 2 Grade Homework Grade Final Exam Grade
For each student, your program should first calculate a final grade, using this formula:
Final Grade = 0.20 × Exam 1 + 0.20 × Exam 2 + 0.35 × Homework + 0.25 × Final Exam
Then assign a letter grade on the basis of 90–100 = A, 80–89 = B, 70–79 = C, 60–69 = D, and
less than 60 = F. All the information, including the final grade and the letter grade, should
then be displayed and written to a file.
4. (Data Processing) Write a C++ program that permits users to enter the following
information about your small company’s 10 employees, sorts the information in ascending
ID number, and then writes the sorted information to a file:
ID No. Sex(M/F) Hourly Wage Years with the Company
5. (Data Processing) Write a C++ program that reads the file created in Exercise 4,
changes the hourly wage or years for each employee, and creates a new updated file.
486 I/O Streams and Data Files
6. (Data Processing) Write a C++ program that reads the file created in Exercise 4 one
record at a time, asks for the number of hours each employee worked each month, and
calculates and displays each employee’s total pay for the month.
7. (Data Processing) a. You have collected information about cities in your state. You
decide to store each city’s name, population, and mayor in a file. Write a C++ program
to accept the data for a number of cities from the keyboard and store the data in a file
in the order in which they’re entered.
b. Read the file created in Exercise 7a, sort the data alphabetically by city name, and
display the data.
8. (Data Processing) A bank’s customer records are to be stored in a file and read into a
set of arrays so that a customer’s record can be accessed randomly by account number.
Create the file by entering five customer records, with each record consisting of an
integer account number (starting with account number 1000), a first name (maximum of
10 characters), a last name (maximum of 15 characters), and a double-precision number
for the account balance.
After the file is created, write a C++ program that requests a user-input account number
and displays the corresponding name and account balance from the file.
9. (Inventory) Create an ASCII file with the following data or use the shipped.txt file
provided on this book’s Web site. The headings are not part of the file but indicate what
the data represents.
Shipped
Date
Tracking
Number
Part
Number
First
Name
Last Name Company
04/12/97 D50625 74444 James Lehoff Rotech
04/12/97 D60752 75255 Janet Lezar Rotech
04/12/97 D40295 74477 Bill McHenry Rotech
04/12/97 D23745 74470 Diane Kaiser Rotech
04/12/97 D50892 75155 Helen Richardson NapTime
The format of each line in the file is identical, with fixed-length fields defined as follows:
Field Position Field Name Starting
Col. No.
Ending
Col. No.
Field
Length
1 Shipped Date 1 8 8
2 Tracking Number 12 17 6
3 Part Number 22 26 5
4 First Name 31 35 5
5 Last Name 39 48 10
6 Company 51 64 14
Using this data file, write a C++ program that reads the file and produces a report listing
the shipped date, part number, first name, last name, and company name.
487
Chapter 8
Programming Projects
Engineering and Scientific Disciplines
Environmental Science and Technology
Two of the newest areas of science and engineering are the related fields of environ-
mental science and technology. Environmental science began as an extension of ecol-
ogy, a biological field that gained prominence in the 1960s. Ecology studies the
interrelationships between specific biological organisms and their environment.
In the 1970s, the study of the larger interplay among physical, chemical, and bio-
logical components of the environment, both locally and globally, began and became
the field known as environmental science. This field now includes study of the follow-
ing areas, among others:
앫 Climate change
앫 Ozone depletion
앫 Weather pattern changes
앫 Water quality
앫 Air pollution
앫 Noise pollution
앫 Conservation of natural resources
앫 Disposal of toxic substances
The impact of human activities on these environmental areas is a chief concern of
environmental science. Typically, many different scientific and engineering experts are
needed to work as a team in analyzing and solving environmental issues.
Applying engineering and scientific expertise to solving environmental problems
falls within the purview of environmental technology. This field is concerned with pre-
serving the natural environment and its resources by providing solutions in areas such
as water purification, human waste management, renewable energy, and recycling,
among others.
488 I/O Streams and Data Files
Chapter
9
Completing the
Basics
9.1 Exception Handling
9.2 Exceptions and File Checking
9.3 The string Class
9.4 Character Manipulation
Functions
9.5 Input Data Validation
9.6 A Closer Look: Namespaces
and Creating a Personal
Library
9.7 Common Programming Errors
9.8 Chapter Summary
The current ANSI/ISO C++ standard introduces two new features that weren’t part of the original C++
specification: exception handling and the string class. This chapter covers both these new features.
Exception handling is a means of error detection and processing, which has gained increasing
acceptance in programming technology. It permits detecting an error at the point in the code where the
error has occurred and provides a means of processing the error and returning control to the line that
generated the error. Although error detection and code correction are possible by using if statements and
functions, exception handling gives you another useful programming tool targeted at error detection and
processing.
With the new ANSI/ISO C++ standard, the string class is now part of the standard C++
library. This class provides an expanded set of class functions, including easy insertion and removal
of characters from a string, automatic string expansion when a string’s original capacity is exceeded,
string contraction when characters are removed from a string, and range checking to detect invalid
character positions.
In addition to discussing these two new C++ features, this chapter shows how exception handling,
when applied to strings, is a useful means of validating user input.
9.1 Exception Handling
The traditional C++ approach to error handling uses a function to return a specific value to
indicate specific operations. Typically, a return value of 0 or 1 is used to indicate successful
completion of the function’s task, whereas a negative value indicates an error condition. For
example, with a function used to divide two numbers, a return value of -1 could indicate that
the denominator is zero, and the division can’t be performed. When multiple error conditions
can occur, different return values can be used to indicate specific errors.
Although this approach is still available and often used, a number of problems can occur.
First, the programmer must check the return value to detect whether an error did occur.
Next, the error-handling code that checks the return value frequently becomes intermixed
with normal processing code, so sometimes it’s difficult to determine which part of the code
is handling errors. Finally, returning an error condition from a function means the condition
must be the same data type as a valid returned value; hence, the error code must be a
specified value that can be identified as an error alert. This means the error code is
embedded as one of the possible nonerror values the function might require and is available
only at the point where the function returns a value. In addition, a function returning a
Boolean value has no additional values for reporting an error condition.
None of these problems are insurmountable, and many times this approach is simple and
effective. However, the latest C++ compilers have added a technique designed for error
detection and handling referred to as exception handling. With this technique, when an error
occurs while a function is executing, an exception is created. An exception is a value, a
variable, or an object containing information about the error at the point the error occurs.
This exception is immediately passed, at the point it was generated, to code called the
exception handler, which is designed to deal with the exception. The process of generating
and passing the exception is referred to as throwing an exception. The exception is thrown
from within the function while it’s still executing, which permits handling the error and then
returning control back to the function so that it can complete its assigned task.
In general, two fundamental types of errors can cause C++ exceptions: those resulting
from a program’s inability to obtain a required resource and those resulting from flawed data.
Examples of the first error type are attempts to obtain a system resource, such as locating and
finding a file for input. These errors are the result of external resources over which the
programmer has no control.
The second type of error can occur when a program prompts the user to enter an integer,
and the user enters a string, such as e234, that can’t be converted to a numerical value.
Another example is the attempt to divide two numbers when the denominator has a 0 value,
a condition referred to as a “division by zero error.” These errors can always be checked and
handled in a manner that doesn’t result in a program crash. Before seeing how to use
exception handling, review Table 9.1 to familiarize yourself with the terminology used with
processing exceptions.
Table 9.1 Exception-Handling Terminology
Terminology Description
Exception A value, a variable, or an object that identifies a specific error
that has occurred while a program is executing
Throw an exception Send the exception to a section of code that processes the
detected error
490 Completing the Basics
Table 9.1 Exception-Handling Terminology (continued)
Terminology Description
Catch or handle an
exception
Receive a thrown exception and process it
Catch clause The section of code that processes the error
Exception handler The code that throws and catches an exception
The general syntax of the code required to throw and catch an exception is the following:
try
{
// one or more statements,
// at least one of which should
// be capable of throwing an exception
}
catch(exceptionDataType parameterName)
{
// one or more statements
}
This example uses two new keywords: try and catch. The try keyword identifies the
start of an exception-handling block of code. At least one of the statements inside the braces
defining this block of code should be capable of throwing an exception. As an example,
examine the try block in the following section of code:
try
{
cout << "Enter the numerator (whole numbers only): ";
cin >> numerator;
cout << "Enter the denominator (whole numbers only):";
cin >> denominator;
result = numerator/denominator;
}
The try block contains five statements, three of which might result in an error you want
to catch. In particular, a professionally written program would make sure valid integers are
entered in response to both prompts and the second entered value is not a zero. For this
example, you just check that the second value entered isn’t zero.
From the standpoint of the try block, only the value of the second number matters. The
try block is altered to say “Try all the statements within me to see whether an exception,
which in this case is a zero second value, occurs.” To check that the second value isn’t zero,
you add a throw statement in the try block, as follows:
try
{
cout << "Enter the numerator: (whole number only): ";
cin >> numerator;
cout << "Enter the denominator: (whole number only): ";
cin >> denominator;
if (denominator == 0)
throw denominator;
else
result = numerator/denominator;
}
491
Chapter 9
Exception Handling
In this try block, the thrown item is an integer value. A string literal, a variable, or an
object could have been used, but only one of these items can be thrown by any single throw
statement. The first four statements in the try block don’t have to be included in the code;
however, doing so keeps all the relevant statements together. Keeping related statements
together makes it easier to add throw statements in the same try block to ensure that both
input values are integer values.
A try block must be followed by one or more catch blocks, which serve as exception
handlers for any exceptions thrown by statements in the try block. Here’s a catch block
that handles the thrown exception, which is an integer:
catch(int e)
{
cout << "A denominator value of " << e << " is invalid." << endl;
exit (1);
}
The exception handling this catch block provides is an output statement that identifies
the caught exception and then terminates program execution. Notice the parentheses
following the catch keyword. Inside the parentheses are the data type of the exception
that’s thrown and a parameter name used to receive the exception. This parameter, which is
a programmer-selected identifier but conventionally uses the letter e for exception, is used
to hold the exception value generated when an exception is thrown.
Multiple catch blocks can be used as long as each block catches a unique data type. The
only requirement is providing at least one catch block for each try block. The more
exceptions that can be caught with the same try block, the better. Program 9.1 provides a
complete program that includes a try block and a catch block to detect a division by zero error.
Following are two sample runs of Program 9.1. Note that the second output indicates that
an attempt to divide by a zero denominator has been detected successfully before the
operation is performed.
Enter the numerator (whole number only): 12
Enter the denominator(whole number only): 3
12/3 = 4
and
Enter the numerator (whole number only): 12
Enter the denominator(whole number only): 0
A denominator value of 0 is invalid.
492 Completing the Basics
Instead of terminating program execution when a zero denominator is detected, a more
robust program can give the user the opportunity to reenter a non-zero value. To do this, the
try block is included in a while statement, and then the catch block returns program
control to the while statement after informing the user that a zero value has been entered.
Program 9.2 accomplishes this task.
Program 9.1
#include <iostream>
using namespace std;
int main()
{
int numerator, denominator;
try
{
cout << "Enter the numerator (whole number only): ";
cin >> numerator;
cout << "Enter the denominator(whole number only): ";
cin >> denominator;
if (denominator == 0)
throw denominator; // an integer value is thrown
else
cout << numerator <<'/' << denominator
<< " = " << double(numerator)/ double(denominator) << endl;
}
catch(int e)
{
cout << "A denominator value of " << e << " is invalid." << endl;
exit (1);
}
return 0;
}
493
Chapter 9
Exception Handling
In reviewing this code, notice that it’s the continue statement in the catch block that
returns control to the top of the while statement. (See Section 5.3 for a review of the
continue statement.) Following is a sample run of Program 9.2:
Enter a numerator (whole number only): 12
Enter a denominator (whole number only): 0
A denominator value of 0 is invalid.
Please reenter the denominator (whole number only): 5
12/5 = 2.4
Program 9.2
#include <iostream>
using namespace std;
int main()
{
int numerator, denominator;
bool needDenominator = true;
cout << "Enter a numerator (whole number only): ";
cin >> numerator;
cout << "Enter a denominator (whole number only): ";
while(needDenominator)
{
cin >> denominator;
try
{
if (denominator == 0)
throw denominator; // an integer value is thrown
}
catch(int e)
{
cout << "A denominator value of " << e << " is invalid." << endl;
cout << "Please reenter the denominator (whole number only): ";
continue; // this sends control back to the while statement
}
cout << numerator <<'/' << denominator
<< " = " << double(numerator)/ double(denominator) << endl;
needDenominator = false;
}
return 0;
}
494 Completing the Basics
One caution should be mentioned when throwing string literals as opposed to numeric
values. When a string literal is thrown, it’s a C-string, not a string class object, that is thrown.
This means the catch statement must declare the received argument as a C-string (which is a
character array) rather than a string. As an example, take a look at using the following statement
instead of throwing the value of the denominator variable in Programs 9.1 and 9.2:
throw "***Invalid input - A denominator value of zero is not
permitted***";
Here’s a correct catch statement for the preceding throw statement:
catch(char e[])
An attempt to declare the exception as a string class variable results in a compiler error.
EXERCISES 9.1
1. (Practice) Define the following terms:
a. exception
b. try block
c. catch block
d. exception handler
e. throw an exception
f. catch an exception
2. (Practice) Enter and execute Program 9.1.
3. (Practice) Replace the following statement in Program 9.1
cout << numerator <<'/' << denominator
<< " = " << double (numerator)/ double (denominator) << endl;
with the statement
cout << numerator <<'/' << denominator
<< " = " << numerator/denominator << endl;
and execute the modified program. Enter the values 12 and 5, and explain why the result
is incorrect from the user’s viewpoint.
4. (Modify) Modify Program 9.1 so that it throws and catches the message ***Invalid
input -A denominator value of zero is not permitted***. (Hint: Review
the caution at the end of this section.)
5. (Practice) Enter and execute Program 9.2.
6. (Modify) Modify Program 9.2 so that it continues to divide two numbers until the user
enters the character q (as a numerator or denominator) to terminate program execution.
495
Chapter 9
Exception Handling
7. (Validation) Include the exception-handling code provided in this section in Program 9.1
to ensure that the user enters a valid integer value for both the numerator and
denominator.
9.2 Exceptions and File Checking
Error detection and processing with exception handling is used extensively in C++ programs
that use one or more files. For example, if a user deletes or renames a file by using an OS
command, this action causes a C++ program to fail when an open() method call attempts
to open the file with its original name. Exception handling is typically used when opening
a data file to ensure that the file opens successfully before attempting any processing of data
in the file.
Recall from Section 9.1 that the code for general exception handling looks like this:
try
{
// one or more statements,
// at least one of which should
// throw an exception
}
catch(exceptionDataType parameterName)
{
// one or more statements
}
In this code, the try block statements are executed. If no error occurs, the catch block
statements are omitted, and processing continues with the statement following the catch
block. However, if any statement in the try block throws an exception, the catch block
with the exception data type matching the exception is executed. If no catch block is
defined for a try block, a compiler error occurs. If no catch block exists that catches a
thrown data type, a program crash occurs if the exception is thrown. Most times, the catch
block displays an error message and terminates processing with a call to the exit()
function. Program 9.3 shows the statements required to open a file in read mode and includes
exception handling.
Program 9.3
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
#include <string>
using namespace std;
墌
496 Completing the Basics
This is the exception message Program 9.3 displays when the prices.dat file isn’t
found:
The file prices.dat was not successfully opened.
Please check that the file currently exists.
int main()
{
string filename = "prices.dat"; // put the filename up front
string descrip;
double price;
ifstream inFile;
try // this block tries to open the file, read it,
// and display the file's data
{
inFile.open(filename.c_str());
if (inFile.fail()) throw filename; // this is the exception being checked
// read and display the file's contents
inFile >> descrip >> price;
while (inFile.good()) // check next character
{
cout << descrip << ' ' << price << endl;
inFile >> descrip >> price;
}
inFile.close();
return 0;
}
catch (string e)
{
cout << "nThe file "<< e << " was not successfully opened."
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
}
497
Chapter 9
Exceptions and File Checking
Although the exception-handling code in Program 9.3 can be used to check for a
successful file open for input and output, a more rigorous check is usually required for an
output file because a file opened for output is almost guaranteed to be found. If it exists, the
file will be found; if it doesn’t exist, the operating system creates it (unless append mode is
specified and the file exists, or the operating system can’t find the indicated folder). Knowing
that the file has been found and opened, however, isn’t enough for output purposes when an
existing output file must not be overwritten. In these cases, the file can be opened for input,
and, if the file is found, a further check can be made to ensure that the user explicitly
approves overwriting it. The shaded code in Program 9.4 shows how to make this check.
Point of Information
Checking That a File Was Opened Successfully
Using exception handling, the most common method for checking that the operating
system located the designated file is the one coded in Program 9.3. The key coding
points are repeated here for convenience:
try // this block tries to open the file, read it,
// and display the file's data
{
// open the file, throwing an exception if the open fails
// perform all required file processing
// close the file
}
catch (string e)
{
cout << "nThe file "<< e << " was not successfully opened."
<< "n Please check that the file currently exists."
<< endl;
exit(1);
}
Program 9.4
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
#include <string>
#include <iomanip> // needed for formatting
using namespace std;
int main()
{
char response;
string filename = "prices.dat"; // put the filename up front
ifstream inFile;
ofstream outfile;
墌
498 Completing the Basics
try // open a basic input stream simply to check whether the file exists
{
inFile.open(filename.c_str());
if (inFile.fail()) throw 1; // this means the file doesn't exist
// only get here if the file is found;
// otherwise, the catch block takes control
cout << "A file by the name " << filename << " currently exists.n"
<< "Do you want to overwrite it with the new data (y or n): ";
cin >> response;
if (tolower(response) == 'n')
{
inFile.close();
cout << "The existing file has not been overwritten." << endl;
exit(1);
}
}
catch(int e) {}; // a do-nothing block that permits
// processing to continue
try
{
// open the file in write mode and continue with file writes
outfile.open(filename.c_str());
if (outfile.fail()) throw filename;
// set the output file stream formats
outfile << setiosflags(ios::fixed)
<< setiosflags(ios::showpoint)
<< setprecision(2);
// write the data to the file
outfile << "Mats " << 39.95 << endl
<< "Bulbs " << 3.22 << endl
<< "Fuses " << 1.08 << endl;
outfile.close();
cout << "The file " << filename
<< " has been successfully written." << endl;
return 0;
}
catch(string e)
{
cout << "The file " << filename
<< " was not opened for output and has not been written."
<< endl;
}
}
499
Chapter 9
Exceptions and File Checking
In Program 9.4, the try blocks are separate. Because a catch block is affiliated with the
closest previous try block, there’s no ambiguity about unmatched try and catch blocks.
Opening Multiple Files
To understand how to apply exception handling to opening two files at the same time,
assume you want to read data from a character-based file named info.txt, one character
at a time, and write this data to a file named info.bak. Essentially, this application is a
file-copying program that reads data from one file in a character-by-character manner and
writes the data to a second file. Figure 9.1 shows the characters stored in the input file.
Figure 9.2 illustrates the structure of the streams needed to produce the file copy. In this
figure, an input stream object referenced by the variable inFile reads data from the
info.txt file, and an output stream object referenced by the variable outfile writes data
to the info.bak file.
Now examine Program 9.5, which creates the info.bak file as a duplicate of the
info.txt file, using the procedure shown in Figure 9.2.
Now is the time for all good people
to come to the aid of their party.
Please call (555) 888-6666 for
further information.
Figure 9.1 The data stored in the info.txt file
Computer
Program
Read
Write
Disk
OS interface info.txt
info.bak
OS interface
Figure 9.2 The file copy stream structure
Program 9.5
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
#include <string>
using namespace std;
墌
500 Completing the Basics
int main()
{
string fileOne = "info.txt"; // put the filename up front
string fileTwo = "info.bak";
char ch;
ifstream inFile;
ofstream outfile;
try //this block tries to open the input file
{
// open a basic input stream
inFile.open(fileOne.c_str());
if (inFile.fail()) throw fileOne;
} // end of outer try block
catch (string in) // catch for outer try block
{
cout << "The input file " << in
<< " was not successfully opened." << endl
<< " No backup was made." << endl;
exit(1);
}
try // this block tries to open the output file and
{ // perform all file processing
outfile.open(fileTwo.c_str());
if (outfile.fail())throw fileTwo;
while ((ch = inFile.get())!= EOF)
outfile.put(ch);
inFile.close();
outfile.close();
}
catch (string out) // catch for inner try block
{
cout << "The backup file " << out
<< " was not successfully opened." << endl;
exit(1);
}
cout << "A successful backup of " << fileOne
<< " named " << fileTwo << " was successfully made." << endl;
return 0;
}
501
Chapter 9
Exceptions and File Checking
For simplicity, Program 9.5 attempts to open the input and output files in separate and
unnested try blocks. More generally, the second file is opened in a nested inner try block,
so the attempt to open this second file wouldn’t be made if opening the first file threw an
exception. (The Point of Information box explains how to nest try blocks.)
In reviewing Program 9.5, pay particular attention to this statement:
while((ch = inFile.get())!= EOF)
This statement reads a value from the input stream continuously until the EOF value is
detected. As long as the returned value doesn’t equal the EOF value, the value is written to
the output object stream. The parentheses surrounding the expression (ch = inFile.
get()) are necessary to make sure a value is read and assigned to the variable ch before the
retrieved value is compared to the EOF value. Without parentheses, the complete expression
would be ch = inFile.get()!= EOF. Given the precedence of operations, the relational
expression inFile.get()!= EOF would be executed first. Because it’s a relational
expression, its result is a Boolean true or false value based on the data the get() method
retrieves. Attempting to assign this Boolean result to the character variable ch is an invalid
conversion across an assignment operator.
Point of Information
Nesting try Blocks
When more than one file stream is involved, opening each file stream in its own try
block permits isolating and identifying exactly which file caused an exception, if one
occurs. The try blocks can be nested. For example, Program 9.5 has been rewritten
with nested try blocks. Notice that the catch block for the inner try block must be
nested in the same block scope as the try block:
#include <iostream>
#include <fstream>
#include <cstdlib> // needed for exit()
#include <string>
using namespace std;
int main()
{
string fileOne = "info.txt"; // put the filename up front
string fileTwo = "info.bak";
char ch;
ifstream inFile;
ofstream outfile;
try //this block tries to open the input file
{
// open a basic input stream
inFile.open(fileOne.c_str());
if (inFile.fail()) throw fileOne;
try // this block tries to open the output file and
continued...
502 Completing the Basics
EXERCISES 9.2
1. (For Review) List two conditions that cause a fail condition when a file is opened for
input.
2. (For Review) List two conditions that cause a fail condition when a file is opened for
output.
3. (For Review) If a file that exists is opened for output in write mode, what happens to
the data currently in the file?
Point of Information
Nesting try Blocks (continued)
{ // perform all file processing
// open a basic output stream
outfile.open(fileTwo.c_str());
if (outfile.fail())throw fileTwo;
while ((ch = inFile.get()) != EOF)
outfile.put(ch);
inFile.close();
outfile.close();
} // end of inner try block
catch (string out) // catch for inner try block
{
cout << "The backup file " << out
<< " was not successfully opened." << endl;
exit(1);
}
} // end of outer try block
catch (string in) // catch for outer try block
{
cout << "The input file " << in
<< " was not successfully opened." << endl
<< " No backup was made." << endl;
exit(1);
}
cout << "A successful backup of " << fileOne
<< " named " << fileTwo << "was successfully made." << endl;
return 0;
}
The important point to notice is nesting the try blocks. If the two try blocks
aren’t nested and the input stream declaration, ifstream inFile;, is placed in the
first block, it can’t be used in the second try block without producing a compiler
error. The reason is that all variables declared in a block of code (defined by an open-
ing and closing brace pair) are local to the block in which they’re declared.
503
Chapter 9
Exceptions and File Checking
4. (Modify) Modify Program 9.3 to use an identifier of your choice, in place of the letter e,
for the catch block’s exception parameter name.
5. (Practice) Enter and execute Program 9.4.
6. (Debug) Determine why the two try blocks in Program 9.4, which are not nested, cause
no problems in compilation or execution. (Hint: Place the declaration for the filename in
the first try block and compile the program.)
7. (Debug) a. If the nested try blocks in the Point of Information on nested try blocks
are separated into unnested blocks, the program won’t compile. Determine why this is so.
b. What additional changes have to be made to the program in Exercise 7a that would
allow it to be written with unnested blocks? (Hint: See Exercise 6.)
9.3 The string Class
The programs in this book have used the istream class’s cout object extensively, but you
haven’t investigated this class in detail or learned how the cout object is created. However,
an advantage of object-oriented program design is that you can use thoroughly tested classes
without knowing how the class is constructed. In this section, you use another class provided
by C++’s standard library: the string class. However, you’re going to create objects from
the class before using them instead of using an existing object, such as cout.
A class is a user-created data type. Like built-in data types, a class defines a valid set of
data values and a set of operations that can be used on them. The difference between a
user-created class and a built-in data type is how the class is constructed. A built-in data type
is provided as an integral part of the compiler, and a class is constructed by a programmer
using C++ code. Other than that and the terminology, the two data types are used in much
the same manner. The key difference in terminology is that storage areas for built-in data
types are referred to as variables, whereas storage areas declared for a class are referred to as
objects.
The values the string class permits are referred to as string literals. A string literal is any
sequence of characters enclosed in quotation marks. A string literal is also referred to as a
string value, a string constant, and, more conventionally, a string. Examples of strings are
"This is a string", "Hello World!", and "xyz 123 *!#@&". The quotation marks
indicate the beginning and ending points of the string and are never stored with the string.
Figure 9.3 shows the programming representation of the string Hello when it’s created
as an object of the string class. By convention, the first character in a string is always
designated as position 0. This position value is also referred to as both the character’s index
value and its offset value.
H e l
3
l
4
2
1
0
Position:
o
Figure 9.3 The storage of a string as a sequence of characters
504 Completing the Basics
string Class Functions
The string class provides a number of functions for declaring, creating, and initializing a
string. In earlier versions of C++, the process of creating a new object is referred to as
instantiating an object, which in this case becomes instantiating a string object, or creating a
string, for short. Table 9.2 lists the functions the string class provides for creating and
initializing a string object. In class terminology, functions are formally referred to as methods,
and the methods that perform the tasks of creating and initializing are called constructor
methods, or constructors, for short.
Table 9.2 string Class Constructors (Require the Header File string)
Constructor Description Examples
string objectName = value Creates and
initializes a string
object to a value
that can be a
string literal, a
previously declared
string object, or an
expression
containing string
literals and string
objects
string str1 = "Good
Morning";
string str2 = str1;
string str3 = str1 +
str2;
string objectName(stringValue) Produces the same
initialization as the
preceding item
string str1("Hot");
string str1(str1 +
"Dog");
string objectName(str, n) Creates and
initializes a string
object with a
substring of string
object str,
starting at index
position n of str
string str1(str2, 5)
If str2 contains the string
Good Morning, then str1
becomes the string
Morning
string objectName(str, n, p) Creates and
initializes a string
object with a
substring of string
object str,
starting at index
position n of str
and containing p
characters
string str1(str2, 5,2)
If str2 contains the string
Good Morning, then str1
becomes the string Mo
string objectName(n, char) Creates and
initializes a string
object with n
copies of char
string str1(5,'*')
This makes str1 =
"*****"
505
Chapter 9
The string Class
Table 9.2 string Class Constructors (Require the Header File string) (continued)
Constructor Description Examples
string objectName Creates and
initializes a string
object to represent
an empty character
sequence (same as
string
objectName =
"";, so the length
of the string is 0)
string message;
Program 9.6 shows examples of each constructor the string class provides.
Program 9.6
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1; // an empty string
string str2("Good Morning");
string str3 = "Hot Dog";
string str4(str3);
string str5(str4, 4);
string str6 = "linear";
string str7(str6, 3, 3);
cout << "str1 is: " << str1 << endl;
cout << "str2 is: " << str2 << endl;
cout << "str3 is: " << str3 << endl;
cout << "str4 is: " << str4 << endl;
cout << "str5 is: " << str5 << endl;
cout << "str6 is: " << str6 << endl;
cout << "str7 is: " << str7 << endl;
return 0;
}
506 Completing the Basics
Here is the output created by Program 9.6:
str1 is:
str2 is: Good Morning
str3 is: Hot Dog
str4 is: Hot Dog
str5 is: Dog
str6 is: linear
str7 is: ear
Although this output is straightforward, str1 is an empty string consisting of no
characters; because the first character in a string is designated as position 0, not 1, the
character position of the D in the string Hot Dog is position 4, which is shown in Figure 9.4.
String Input and Output
In addition to a string being initialized with the constructors listed in Table 9.2, strings can
be input from the keyboard and displayed on screen. Table 9.3 lists the basic functions and
objects for input and output of string values.
Table 9.3 string Class Input and Output
C++ Object or Function Description
cout General-purpose screen output object
cin General-purpose keyboard input object that stops
reading string input when white space is encountered
getline(cin, strObj) General-purpose keyboard input function that inputs all
characters entered, stores them in the string strObj,
and stops accepting characters when it receives a
newline character (n)
In addition to the standard cout and cin objects you have been using throughout the
book, the string class provides the getline() function for string input. For example, the
expression getline(cin, message) accepts and stores characters typed at the terminal
continuously until the Enter key is pressed. Pressing the Enter key generates a newline
character, 'n', which getline() interprets as the end-of-line entry. All the characters
encountered by getline(), except the newline character, are stored in the string
message, as illustrated in Figure 9.5.
Program 9.7 shows using the getline() function and cout statement to input and output
a string that’s entered at the user’s terminal. Although cout is used in Program 9.7 for string
output, cin generally can’t be used in place of getline() for string input because cin reads
a set of characters up to a blank space or a newline character. Therefore, attempting to enter the
characters This is a string by using the statement cin >> message; results in only the
H o t
2
1
0 5 6
4
D o g
3
Character position:
Figure 9.4 The character positions of the string Hot Dog
507
Chapter 9
The string Class
word This being assigned to message. Because a blank terminates a cin extraction operation,
cin’s usefulness for entering string data is restricted; therefore, getline() is used.
The following is a sample run of Program 9.7:
Enter a string:
This is a test input of a string of characters.
The string just entered is:
This is a test input of a string of characters.
In its most general form, the getline() function has the syntax
getline(cin, strObj, terminatingChar)
where strObj is a string variable name and terminatingChar is an optional character
constant, or variable, specifying the terminating character. For example, the expression
getline(cin, message, '!') accepts all characters entered at the keyboard, including
a newline character, until an exclamation point is entered. The exclamation point isn’t stored
as part of the string.
getline()
characters n characters
Figure 9.5 Inputting a string with getline()
Program 9.7
#include <iostream>
#include <string>
using namespace std;
int main()
{
string message; // declare a string object
cout << "Enter a string:n";
getline(cin, message);
cout << "The string just entered is:n"
<< message << endl;
return 0;
}
508 Completing the Basics
If the optional third argument, terminatingChar, is omitted when getline() is
called, the default terminating character is the newline ('n') character. Therefore, the
statement getline(cin,message,'n'); can be used in place of the statement
getline(cin, message);. Both these statements stop reading characters when the
Enter key is pressed. In all the programs used from this point forward, input is terminated
by pressing the Enter key, which generates a newline character. For this reason, the optional
third argument passed to getline(), which is the terminating character, is omitted.
Caution: The Phantom Newline Character Seemingly strange results can happen when
the cin input stream object and getline() function are used together to accept data or
when cin is used by itself to accept characters. To see how this result can occur, take a look
at Program 9.8, which uses cin to accept an integer entered at the keyboard. The integer is
then stored in the variable value, and a getline() function call follows.
When Program 9.8 runs, the number entered in response to the prompt Enter a
number: is stored in the variable value. At this point, everything seems to be working fine.
Notice, however, that in entering a number, you enter the number and press the Enter key.
On almost all computer systems, this entered data is stored in a temporary holding area called
a buffer immediately after the characters are entered, as shown in Figure 9.6.
Program 9.8
#include <iostream>
#include <string>
using namespace std;
int main()
{
int value;
string message;
cout << "Enter a number: ";
cin >> value;
cout << "The number entered is:n"
<< value << endl;
cout << "Enter text:n";
getline(cin, message);
cout << "The text entered is:n"
<< message << endl;
cout << int(message.length());
return 0;
}
509
Chapter 9
The string Class
The cin input stream in Program 9.8 first accepts the number entered but leaves the
'n' in the buffer. The next input statement, which is a call to getline(), picks up
thecode for the Enter key as the next character and terminates any further input. Following
is a sample run of Program 9.8:
Enter a number: 26
The number entered is 26
Enter text:
The text entered is
In this output, no text is accepted in response to the prompt Enter text:. No text
occurs because, after the program accepts the number 26, the code for the Enter key, which
is a newline escape sequence, remains in the buffer and is picked up and interpreted by the
getline() function as the end of its input. This result occurs whether an integer (as in
Point of Information
The string and char Data Types
A string can consist of zero, one, or more characters. When the string has no charac-
ters, it’s said to be an empty string with a length of zero. A string with a single charac-
ter, such as "a", is a string of length one and is stored differently from a char data
type, such as 'a'.
However, for many practical purposes, a string of length one and a char respond
in the same manner; for example, both cout >> "n" and cout >> 'n' produce
a new line on the screen. It’s important to understand that they are different data
types; for example, both these declarations
string s1 = 'a'; // INVALID INITIALIZATION
char key = "n"; // INVALID INITIALIZATION
produce a compiler error because they attempt to initialize one data type with literal
values of another type.
2 6 n
Each character is
sent to a buffer
as it’s typed
Buffer
(temporary storage)
Keyboard
Figure 9.6 Typed characters are first stored in a buffer
510 Completing the Basics
Program 9.8), a string, or any other input is accepted by cin and then followed by a
getline() function call. There are three solutions to this “phantom” Enter key problem:
• Don’t mix cin with getline() inputs in the same program.
• Follow the cin input with the call to cin.ignore().
• Accept the Enter key in a character variable and then ignore it.
The preferred solution is the first one. All solutions, however, center on the fact that the
Enter key is a legitimate character input and must be recognized as such. You encounter this
problem again when you learn about accepting char data types in Section 9.4.
String Processing
Strings can be manipulated by using string class functions or the character-at-a-time functions
described in Section 9.4. Table 9.4 lists the most commonly used string class functions plus
the standard arithmetic and comparison operators that can also be used with strings.
Table 9.4 The string Class Processing Functions (Require the Header File string)
Function/Operation Description Example
int length() Returns the
length of
the string
string.length()
int size() Same as the
preceding item
string.size()
at(int index) Returns the
character at the
specified index
and throws an
exception if the
index is
nonexistent
string.at(4)
int compare(str) Compares the
given string to
str; returns a
negative value if
the given string is
less than str, a
0 if they are
equal, and a
positive value if
the given string is
greater than str
string1.compare(string2)
c_str() Returns the string
as a null-
terminated
C-string
string1.c_str()
bool empty Returns true if
the string is
empty; otherwise,
returns false
string1.empty()
511
Chapter 9
The string Class
Table 9.4 The string Class Processing Functions (Require the Header File
string) (continued)
Function/Operation Description Example
erase(ind,n) Removes n
characters from
the string,
starting at
index ind
string1.erase(2,3)
erase(ind) Removes all
characters from
the string,
starting from
index ind until
the end of the
string, and the
length of the
remaining string
becomes ind
string1.erase(4)
int find(str) Returns the index
of the first
occurrence of
str in the
complete string
string1.find("the")
int find(str, ind) Returns the index
of the first
occurrence of
str in the
complete string,
with the search
beginning at
index ind
string1.find("the",5)
int find_first_of(str, ind) Returns the index
of the first
occurrence of any
character in str
in the complete
string, with the
search starting at
index ind
string1.find_first_of("lt",6)
int find_first_not_of(str, ind) Returns the index
of the first
occurrence of any
character not in
str in the
complete string,
with the search
starting at
index ind
string1.find_first_not_of("lt",6)
512 Completing the Basics
Table 9.4 The string Class Processing Functions (Require the Header File
string) (continued)
Function/Operation Description Example
void insert(ind, str) Inserts the string
str into the
complete string,
starting at index
ind
string.insert(4, "there")
void replace(ind, n, str) Removes n
characters in the
string object,
starting at index
position ind, and
inserts the string
str at index
position ind
string1.replace(2,4,"okay")
string substr(ind,n) Returns a string
consisting of n
characters
extracted from
the string,
starting at index
ind; if n is
greater than the
remaining
number of
characters, the
rest of the string
is used
string2 = string1.substr(0,10)
void swap(str) Swaps characters
in str with
those in the first
string
string1.swap(string2)
[ind] Returns the
character at index
x, without
checking whether
ind is a valid
index
string1[5]
= Assignment (also
converts a
C-string to a
string)
string1 = string
+ Concatenates
two strings
string1 + string2
513
Chapter 9
The string Class
Table 9.4 The string Class Processing Functions (Require the Header File
string) (continued)
Function/Operation Description Example
+= Concatenation
and assignment
string2 += string1
== !=
< <=
> >=
Relational
operators
Return true if
the relation is
satisfied;
otherwise, return
false
string1 == string2
string1 <= string2
string1 > string2
The most commonly used function in Table 9.4 is length(). It returns the number of
characters in the string, which is referred to as the string’s length. For example, the value
returned by the function call "Hello World!".length() is 12. As always, the quotation
marks surrounding a string value aren’t considered part of the string. Similarly, if the string
referenced by string1 contains the value "Have a good day.", the value returned by the
call string1.length() is 16.
Two string expressions can be compared for equality by using the standard relational
operators. Each character in a string is stored in binary with the ASCII or Unicode code.
Although these codes are different, they have some characteristics in common. In both, a
blank precedes (is less than) all letters and numbers; letters of the alphabet are stored in
order from A to Z; and digits are stored in order from 0 to 9. In addition, digits come before
(are less than) uppercase characters, which are followed by lowercase characters. Therefore,
uppercase characters are mathematically less than lowercase characters.
When two strings are compared, their characters are compared a pair at a time (both first
characters, then both second characters, and so on). If no differences are found, the strings
are equal; if a difference is found, the string with the first lower character is considered the
smaller string, as shown in these examples:
• "Hello" is greater than "Good Bye" because the first H in Hello is greater than
the first G in Good Bye.
• "Hello" is less than "hello" because the first H in Hello is less than the first
h in hello.
• "SMITH" is greater than "JONES" because the first S in SMITH is greater than the
first J in JONES.
• "123" is greater than "1227" because the third character in 123, the 3, is greater
than the third character in 1227, the 2.
• "Behop" is greater than "Beehive" because the third character in Behop, the h,
is greater than the third character in Beehive, the e.
Program 9.9 uses length() and several relational expressions in the context of a
complete program.
514 Completing the Basics
Following is a sample output produced by Program 9.9:
string1 is the string: Hello
The number of characters in string1 is 5
string2 is the string: Hello there
The number of characters in string2 is 11
Hello is less than Hello there
墌
Program 9.9
#include <iostream>
#include <string>
using namespace std;
int main()
{
string string1 = "Hello";
string string2 = "Hello there";
cout << "string1 is the string: " << string1 << endl;
cout << "The number of characters in string1 is " << int(string1.length())
<< endl << endl;
cout << "string2 is the string: " << string2 << endl;
cout << "The number of characters in string2 is " << int(string2.length())
<< endl << endl;
if (string1 < string2)
cout << string1 << " is less than " << string2 << endl << endl;
else if (string1 == string2)
cout << string1 << " is equal to " << string2 << endl << endl;
else
cout << string1 << " is greater than " << string2 << endl << endl;
string1 = string1 + " there world!";
cout << "After concatenation, string1 contains the characters:
" << string1 << endl;
cout << "The length of this string is " << int(string1.length()) << endl;
return 0;
}
515
Chapter 9
The string Class
After concatenation, string1 contains the characters:
Hello there world!
The length of this string is 18
When reviewing this program’s output, refer to Figure 9.7, which shows how the
characters in string1 and string2 are stored in memory. The length of each string refers
to the total number of characters in the string, and the first character in each string is located
at index position 0. Therefore, the length of a string is always one more than the index
number of the last character’s position in the string.
Although you use the concatenation operator and length() function most often, at
times you’ll find the other string functions in Table 9.4 useful. One of the most useful is the
at() function, which enables you to retrieve separate characters in a string. Program 9.10
uses this function to select one character at a time from the string, starting at string position
0 and ending at the index of the last character in the string. This last index value is always
one less than the number of characters (that is, the string’s length) in the string.
The expression str.at(i) in the switch statement retrieves the character at position i
in the string. This character is then compared to five different character values. The switch
statement uses the fact that selected cases “drop through” in the absence of break statements.
Therefore, all selected cases result in an increment to vowelCount. Program 9.10 displays the
following output:
The string: Counting the number of vowels
has 9 vowels.
Location of
a string
string2
string1
Character part of a string object
Character part of a string object
Location of
a string
H e l l o
H e l l o t h e r e
Figure 9.7 The initial strings used in Program 9.9
516 Completing the Basics
As an example of inserting and replacing characters in a string with the functions listed
in Table 9.4, assume you start with a string created by the following statement:
string str = "This cannot be";
Figure 9.8 illustrates how this string is stored in the buffer created for it. As indicated, the
length of the string is 14 characters.
Now assume the following statement is executed:
str.insert(4," I know");
Program 9.10
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Counting the number of vowels";
int i, numChars;
int vowelCount = 0;
cout << "The string: " << str << endl;
numChars = int(str.length());
for (i = 0; i < numChars; i++)
{
switch(str.at(i)) // here is where a character is retrieved
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
vowelCount++;
}
}
cout << "has " << vowelCount << " vowels." << endl;
return 0;
}
517
Chapter 9
The string Class
This statement inserts the designated seven characters in " I know", beginning with
a blank, in the existing string starting at index position 4. Figure 9.9 shows the string after
the insertion.
If the statement str.replace(12, 6, "to"); is executed next, the existing
characters in index positions 12 through 17 are deleted, and the two characters contained in
to are inserted starting at index position 12. Figure 9.10 shows the net effect of this
replacement. The number of replacement characters (in this case, two) can be fewer than,
equal to, or greater than the number of characters being replaced, which in this case is six.
Finally, if you append the string "correct" to the string shown in Figure 9.10 by using
the concatenation operator, +, you get the string shown in Figure 9.11. Program 9.11 uses
these statements in a complete program.
Character position:
T h i
2
1
0 5 6
4
3
s
8
7 11 12
10
9 13
c a n n o b e
t
Length = 14
Figure 9.8 Initial storage of a string object
Character position:
T h i
2
1
0 5 6
4
3
s
8
7 11 12
10
9 13
I k n o w
Length = 21
15
14 18 19
17
16 20
a n
c n o t b e
Figure 9.9 The string after the insertion
Character position:
T h i
2
1
0 5 6
4
3
s
8
7 11 12
10
9 13
I k n o w
Length = 17
15
14 16
o
t b e
Figure 9.10 The string after the replacement
Character position:
T h i
2
1
0 5 6
4
3
s
8
7 11 12
10
9 13
I k n o w
Length = 25
15
14 18 19
17
16 20
o
t b e c o r
22 23
21 24
e c t
r
Figure 9.11 The string after the append
518 Completing the Basics
The following output produced by Program 9.11 matches the strings shown in Figures 9.8
to 9.11:
The original string is: This cannot be
and has 14 characters.
The string, after insertion, is: This I know cannot be
and has 21 characters.
The string, after replacement, is: This I know to be
and has 17 characters.
The string, after appending, is: This I know to be correct
and has 25 characters.
Program 9.11
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "This cannot be";
cout << "The original string is: " << str << endl
<< " and has " << int(str.length()) << " characters." << endl;
// insert characters
str.insert(4," I know");
cout << "The string, after insertion, is: " << str << endl
<< " and has " << int(str.length()) << " characters." << endl;
// replace characters
str.replace(12, 6, "to");
cout << "The string, after replacement, is: " << str << endl
<< " and has " << int(str.length()) << " characters." << endl;
// append characters
str = str + " correct";
cout << "The string, after appending, is: " << str << endl
<< " and has " << int(str.length()) << " characters." << endl;
return 0;
}
519
Chapter 9
The string Class
Of the remaining string functions listed in Table 9.4, the most commonly used are those
that locate specific characters in a string and create substrings. Program 9.12 shows how some
of these other functions are used.
Program 9.12
#include <iostream>
#include <string>
using namespace std;
int main()
{
string string1 = "LINEAR PROGRAMMING THEORY";
string s1, s2, s3;
int j, k;
cout << "The original string is " << string1 << endl;
j = int(string1.find('I'));
cout << " The first position of an 'I' is " << j << endl;
k = int(string1.find('I', (j+1)));
cout << " The next position of an 'I' is " << k << endl;
j = int(string1.find("THEORY"));
cout << " The first location of "THEORY" is " << j << endl;
k = int(string1.find("ING"));
cout << " The first index of "ING" is " << k << endl;
// now extract three substrings
s1 = string1.substr(2,5);
s2 = string1.substr(19,3);
s3 = string1.substr(6,8);
cout << "The substrings extracted are:" << endl
<< " " << s1 + s2 + s3 << endl;
return 0;
}
520 Completing the Basics
Here is the output produced by Program 9.12:
The original string is LINEAR PROGRAMMING THEORY
The first position of an 'I' is 1
The next position of an 'I' is 15
The first location of "THEORY" is 19
The first index of "ING" is 15
The substrings extracted are:
NEAR THE PROGRAM
The main point shown in Program 9.12 is that characters and sequences of characters can
be located and extracted from a string.
EXERCISES 9.3
1. (Practice) Enter and execute Program 9.7.
2. (Practice) Determine the value of text.at(0), text.at(3), and text.at(10),
assuming for each one that text is each of the following strings:
a. Now is the time
b. Rocky raccoon welcomes you
c. Happy Holidays
d. The good ship
3. (Practice) Enter and execute Program 9.10.
4. (Modify) Modify Program 9.10 to count and display the numbers of each vowel contained
in the string.
5. (Modify) Modify Program 9.10 to display the number of vowels in a user-entered string.
6. (Program) Using the at() function, write a C++ program that reads in a string by using
getline() and then displays the string in reverse order. (Hint: After the string has been
entered and saved, retrieve and display characters, starting from the end of the string.)
7. (Program) Write a C++ program that accepts both a string and a single character from
the user. The program should determine how many times the character is contained in
the string. (Hint: Search the string by using the find(str, ind) function. This func-
tion should be used in a loop that starts the index value at 0 and then changes the index
value to one past the index of where the char was last found.)
8. (Practice) Enter and execute Program 9.11.
9. (Practice) Enter and execute Program 9.12.
521
Chapter 9
The string Class
9.4 Character Manipulation Functions
In addition to the string functions provided by the string class, the C++ language provides
several useful character class functions, listed in Table 9.5. The function declaration
(prototype) for each function is contained in the header file string or cctype, which must
be included in any program using these functions.
Table 9.5 Character Library Functions (Require the Header File string or cctype)
Function Prototype Description Example
int isalpha(charExp) Returns a true (non-zero integer)
if charExp evaluates to a letter;
otherwise, it returns a false (zero
integer)
isalpha('a')
int isalnum(charExp) Returns a true (non-zero integer)
if charExp evaluates to a letter or
a digit; otherwise, it returns a
false (zero integer)
char key;
cin >> key;
isalnum(key);
int isupper(charExp) Returns a true (non-zero integer)
if charExp evaluates to an
uppercase letter; otherwise, it
returns a false (zero integer)
isupper('a')
int islower(charExp) Returns a true (non-zero integer)
if charExp evaluates to a
lowercase letter; otherwise, it
returns a false (zero integer)
islower('a')
int isdigit(charExp) Returns a true (non-zero integer)
if charExp evaluates to a digit (0
through 9); otherwise, it returns a
false (zero integer)
isdigit('a')
int isascii(charExp) Returns a true (non-zero integer)
if charExp evaluates to an ASCII
character; otherwise, returns a
false (zero integer)
isascii('a')
int isspace(charExp) Returns a true (non-zero integer)
if charExp evaluates to a space;
otherwise, returns a false (zero
integer)
isspace(' ')
int isprint(charExp) Returns a true (non-zero integer)
if charExp evaluates to a
printable character; otherwise,
returns a false (zero integer)
isprint('a')
int isctrl(charExp) Returns a true (non-zero integer)
if charExp evaluates to a control
character; otherwise, it returns a
false (zero integer)
isctrl('a')
522 Completing the Basics
Table 9.5 Character Library Functions (Require the Header File string or
cctype) (continued)
Function Prototype Description Example
int ispunct(charExp) Returns a true (non-zero integer)
if charExp evaluates to a
punctuation character; otherwise,
returns a false (zero integer)
ispunct('!')
int isgraph(charExp) Returns a true (non-zero integer)
if charExp evaluates to a
printable character other than
white space; otherwise, returns a
false (zero integer)
isgraph(' ')
int toupper(charExp) Returns the uppercase equivalent if
charExp evaluates to an
lowercase character; otherwise, it
returns the character code without
modification
toupper('a')
int tolower(charExp) Returns the lowercase equivalent if
charExp evaluates to an
uppercase character; otherwise, it
returns the character code without
modification
tolower('A')
Because all the istype() functions listed in Table 9.5 return a non-zero integer (a Boolean
true value) when the character meets the condition and a zero integer (a Boolean false value)
when the condition is not met, these functions are typically used in an if statement. For
example, the following code segment assumes ch is a character variable:
if(isdigit(ch))
cout << "The character just entered is a digit" << endl;
else if(ispunct(ch))
cout << "The character just entered is a punctuation mark" << endl;
In this example, if ch contains a digit character, the first cout statement is executed; if
the character is a letter, the second cout statement is executed. In both cases, however, the
character to be checked is included as an argument to the function. Program 9.13 illustrates
this type of code in a program that counts the number of letters, digits, and other characters
in a string. The characters to be checked are obtained by using the string class’s at()
function. In Program 9.13, this function is used in a for loop that cycles through the string
from the first character to the last.
The output produced by Program 9.13 is the following:
The original string is: This -123/ is 567 A ?<6245> Test!
This string contains 33 characters, which consist of
11 letters
10 digits
12 other characters.
As indicated by this output, each of the 33 characters in the string has been categorized
correctly as a letter, a digit, or other character.
523
Chapter 9
Character Manipulation Functions
Program 9.13
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main()
{
string str = "This -123/ is 567 A ?<6245> Test!";
char nextChar;
int i;
int numLetters = 0, numDigits = 0, numOthers = 0;
cout << "The original string is: " << str
<< "nThis string contains " << int(str.length())
<< " characters," << " which consist of" << endl;
// check each character in the string
for (i = 0; i < int(str.length()); i++)
{
nextChar = str.at(i); // get a character
if (isalpha(nextChar))
numLetters++;
else if (isdigit(nextChar))
numDigits++;
else
numOthers++;
}
cout << " " << numLetters << " letters" << endl;
cout << " " << numDigits << " digits" << endl;
cout << " " << numOthers << " other characters." << endl;
cin.ignore();
return 0;
}
524 Completing the Basics
Typically, as in Program 9.13, the functions in Table 9.5 are used in a character-by-
character manner on each character in a string. You see this again in Program 9.14, where each
lowercase string character is converted to its uppercase equivalent by using the toupper()
function. This function converts only lowercase letters, leaving all other characters
unaffected.
In Program 9.14, pay particular attention to the statement for (i = 0; i <
int(str.length()); i++) used to cycle through each character in the string. Typically,
this cycling through the string, a character at a time, is how each element in a string is
accessed, using the length() function to determine when the end of the string has been
reached. (Review Program 9.13 to see that it’s used in the same way.) The only real
difference is that in Program 9.14, each element is accessed by using the subscript notation
str[i]; in Program 9.13, the at() function is used. Although these two notations are
interchangeable—and which one you use is a matter of choice—for consistency, the two
notations shouldn’t be mixed in the same program.
A sample run of Program 9.14 produced the following output:
Type in any sequence of characters: this is a test of 12345.
The characters just entered, in uppercase, are: THIS IS A TEST OF 12345.
Program 9.14
#include <iostream>
#include <string>
using namespace std;
int main()
{
int i;
string str;
cout << "Type in any sequence of characters: ";
getline(cin,str);
// cycle through all elements of the string
for (i = 0; i < int(str.length()); i++)
str[i] = toupper(str[i]);
cout << "The characters just entered, in uppercase, are: "
<< str << endl;
cin.ignore();
return 0;
}
525
Chapter 9
Character Manipulation Functions
Character I/O
Although you have used cin and getline() to accept data entered from the keyboard in a
more or less “cookbook” manner, you need to understand what data is being sent to the program
and how the program must react to process the data. At a fundamental level, all input (as well
as output) is done on a character-by-character basis, as illustrated in Figure 9.12.
As Figure 9.12 shows, the entry of every piece of data, whether it’s a string or a number,
consists of typing characters. For example, entry of the string Hello consists of pressing and
releasing the five character keys H, e, l, l, o, and the Enter key. Similarly, output of the
number 26.95 consists of displaying the five characters 2, 6, ., 9, and 5. Although
programmers typically don’t think of data in this manner, programs are restricted to this
character-by-character I/O, and all of C++’s higher-level I/O functions and stream objects are
based on lower-level character I/O functions. These more elemental character functions,
which can be used by a programmer, are listed in Table 9.6.
H e l l o
Assemble
into a
string
Is
it 'n'?
get()
int
Replace with
getline()
Stream of data
'H' 'e' 'l' 'l' 'o' <Enter>
No
Stop reading
Yes
value
Figure 9.12 Accepting keyboard-entered characters
526 Completing the Basics
Table 9.6 Basic Character I/O Functions (Require the Header File cctype)
Function Description Example
cout.put(charExp) Places the character value
of charExp on the
output stream.
cout.put('A');
cin.get(charVar) Extracts the next character
from the input stream
and assigns it to the
variable charVar.
cin.get(key);
cin.peek(charVar) Assigns the next character
from the input stream to
the variable charVar
without extracting the
character from the
stream.
cin.peek(nextKey);
cin.putback(charExp) Pushes a character value
of charExp back onto
the input stream.
cin.putback(cKey);
Point of Information
Why the char Data Type Uses Integer Values
In C++, a character is stored as an integer value, which is sometimes confusing to
beginning programmers. The reason is that, in addition to standard English letters and
characters, a program needs to store special characters that have no printable
equivalents. One is the end-of-file (EOF) sentinel that all computer systems use to desig-
nate the end of a data file. The EOF sentinel can be transmitted from the keyboard. For
example, on UNIX-based systems, it’s generated by holding down the Ctrl key and
pressing the D key; on Windows-based systems, it’s generated by holding down Ctrl
and pressing Z. On both systems, the EOF sentinel is stored as the integer number -1,
which has no equivalent character value. (You can check this by displaying the integer
value of each entered character [see Program 9.15] and typing Ctrl+D or Ctrl+Z,
depending on the system you’re using.)
By using a 16-bit integer value, more than 64,000 different characters can be
represented. This number of characters provides enough storage for multiple character
sets, including Arabic, Chinese, Hebrew, Japanese, and Russian, and almost all known
language symbols. Therefore, storing a character as an integer value has a practical
value.
An important consequence of using integer codes for string characters is that char-
acters can be compared easily for alphabetical ordering. For example, as long as each
subsequent letter in an alphabet has a higher value than its preceding letter, the com-
parison of character values is reduced to the comparison of numeric values. Storing
characters in sequential numerical order ensures that adding one to a letter produces
the next letter in the alphabet.
527
Chapter 9
Character Manipulation Functions
Table 9.6 Basic Character I/O Functions (Require the Header File cctype) (continued)
Function Description Example
cin.ignore(n, char) Ignores a maximum of the
next n input characters, up
to and including the
detection of char. If no
arguments are specified,
ignores the next single
character on the input
stream.
cin.ignore(80,'n');
cin.ignore();
The get() function reads the next character in the input stream and assigns it to the
function’s character variable. For example, examine this statement:
cin.get(nextChar);
It causes the next character entered at the keyboard to be stored in the character variable
nextChar. This function is useful for inputting and checking characters before they are
assigned to a complete string or C++ data type.
The character output function corresponding to get() is put(). This function expects
a single-character argument and displays the character passed to it on the screen. For
example, the statement cout.put('A') causes the letter A to be displayed on the screen.
Of the last three functions listed in Table 9.6, the cin.ignore() function is the most
useful. This function permits skipping over input until a designated character, such as 'n', is
encountered. For example, the statement cin.ignore(80, 'n') skips up to a maximum
of the next 80 characters or stops skipping if the newline character is encountered. This
statement can be useful in skipping all further input on a line, up to a maximum of 80 characters,
or until the end of the current line is encountered. Input would begin with the next line.
The peek() function returns the next character on the stream but doesn’t remove it from
the stream’s buffer (see Table 9.6). For example, the expression cin.peek(nextChar)
returns the next character input on the keyboard but leaves it in the buffer. This action is
sometimes useful for peeking ahead and seeing what the next character is but leaving it in place
for the next input.
Finally, the putback() function places a character back on the stream so that it’s the
next character read. The argument passed to putback() can be any character expression
that evaluates to a legitimate character value; it doesn’t have to be the last input character.
The Phantom Newline Character Revisited As you saw in Section 9.3, sometimes you
get seemingly strange results when a cin input stream is followed by a getline() function
call. This same result can occur when characters are inputted by using the get() character
function. To see how it can occur, take a look at Program 9.15, which uses the get()
function to accept the next character entered at the keyboard and stores the character in the
variable fkey.
528 Completing the Basics
When Program 9.15 runs, the character entered in response to the prompt Type in a
character: is stored in the character variable fkey, and the decimal code for the character
is displayed by explicitly casting the character into an integer to force its display as an integer
value. The following sample run illustrates this technique:
Type in a character: m
The key just accepted is 109
At this point, everything seems to be working, although you might be wondering why the
decimal value of m is displayed instead of the character. In typing m, two keys are usually pressed,
the m key and the Enter key. As in the previous section, these two characters are stored in a
buffer after they’re pressed (refer back to Figure 9.12). The first key pressed, m in this case, is
taken from the buffer and stored in fkey, but the code for the Enter key is still in the buffer.
Therefore, a subsequent call to get() for a character input picks up the code for the Enter key
as the next character automatically. For example, take a look at Program 9.16.
Point of Information
A Notational Inconsistency
All the character class functions listed in Table 9.6 use the standard object-oriented
notation of preceding the function’s name with an object name, as in cin.get().
However, the string class getline() function uses the notation getline(cin,
strVar). In this notation, the object (cin) appears as an argument, which is how
procedural-based functions pass variables. For consistency, you would expect
getline() to be called as cin.getline(). Unfortunately, this notation was already
in use for a getline() function created for C-style strings (which are simply one-
dimensional arrays of characters, as discussed in Section 7.2), so a notational inconsis-
tency was created.
Program 9.15
#include <iostream>
using namespace std;
int main()
{
char fkey;
cout << "Type in a character: ";
cin.get(fkey);
cout << "The key just accepted is " << int(fkey) << endl;
return 0;
}
529
Chapter 9
Character Manipulation Functions
The following is a sample run of Program 9.16:
Type in a character: m
The key just accepted is 109
Type in another character: The key just accepted is 10
After entering the letter m in response to the first prompt, the Enter key is also pressed.
From a character standpoint, this input represents the entry of two distinct characters. The
first character is m, which is coded and stored as the integer 109. The second character also
gets stored in the buffer with the numerical code for the Enter key. The second call to
get() picks up this code immediately, without waiting for another key to be pressed. The
last cout stream displays the code for this key. The reason for displaying the numerical code
rather than the character is that the Enter key has no printable character associated with it
that can be displayed.
Remember that every key has a numerical code, including Enter, the spacebar, Esc, and
Ctrl. These keys generally have no effect when entering numbers because the input
functions ignore them as leading or trailing input with numerical data. These keys also don’t
affect the entry of a single character requested as the first user data to be inputted, as in
Program 9.15. Only when a character is requested after the user has already input other data,
as in Program 9.16, does the usually invisible Enter key become noticeable.
In Section 9.1, you learned some ways to prevent the Enter key from being accepted as
a legitimate character input when the getline() function is used. You can use the
following ways when the get() function is used in a program:
• Follow the cin.get() input with the call cin.ignore().
• Accept the Enter key in a character variable, and then don’t use it again.
Program 9.16
#include <iostream>
using namespace std;
int main()
{
char fkey, skey;
cout << "Type in a character: ";
cin.get(fkey);
cout << "The key just accepted is " << int(fkey) << endl;
cout << "Type in another character: ";
cin.get(skey);
cout << "The key just accepted is " << int(skey) << endl;
return 0;
}
530 Completing the Basics
Program 9.17 applies the first solution to Program 9.16. Ignoring the Enter key after the
first character is read and displayed clears the buffer of the Enter key and gets it ready to
store the next valid input character as its first character.
In Program 9.17, observe that when the user types the letter m and presses the Enter key,
the m is assigned to fkey and the code for the Enter key is ignored. The next call to get()
stores the code for the next key pressed in the variable skey. From the user’s standpoint, the
Enter key has no effect, except to signal the end of each character input. The following is
a sample run of Program 9.17:
Type in a character: m
The key just accepted is 109
Type in another character: b
The key just accepted is 98
A Second Look at User-Input Validation
As mentioned in the first look at user-input validation (in Section 3.4), programs that respond
effectively to unexpected user input are formally referred to as robust programs and
informally as “bulletproof” programs. Code that validates user input and ensures that a
program doesn’t produce unintended results caused by unexpected input is a sign of a
well-constructed, robust program. One of your jobs as a programmer is to produce robust
Program 9.17
#include <iostream>
using namespace std;
int main()
{
char fkey, skey;
cout << "Type in a character: ";
cin.get(fkey);
cout << "The key just accepted is " << int(fkey) << endl;
cin.ignore();
cout << "Type in another character: ";
cin.get(skey);
cout << "The key just accepted is " << int(skey) << endl;
cin.ignore();
return 0;
}
531
Chapter 9
Character Manipulation Functions
programs. To see how unintended results can occur, examine the following two code
examples. First, assume your program contains the following statements:
cout << "Enter an integer: ";
cin >> value;
By mistake, a user enters the characters e4. In earlier versions of C++, this input would
cause the program to terminate unexpectedly, or crash. Although a crash can still occur with
the current ANSI/ISO standard, it doesn’t in this case. Instead, a meaningless integer value
is assigned to the variable value. This assignment, of course, invalidates any results
obtained by using this variable.
As a second example, take a look at the following code, which causes an infinite loop if
the user enters a non-numeric value. (The program can be halted by holding down Ctrl and
pressing C.)
double value;
do
{
cout << "Enter a number (enter 0 to exit): ";
cin >> value;
cout << "The square root of this number is: " << sqrt(value) << endl;
}while (value !=0);
The basic technique for handling invalid data input and preventing seemingly innocuous
code, as in these two examples, from producing unintended results is referred to as user-input
validation. This term means validating the entered data during or after data entry and giving
the user a way of reentering data, if it’s invalid. User-input validation is an essential part of
any commercially viable program, and if done correctly, it protects a program from attempting
to process data types that can cause a program to crash, create infinite loops, or produce more
invalid results.
The central element in user-input validation is checking each entered character to verify
that it qualifies as a legitimate character for the expected data type. For example, if an integer
is required, the only acceptable characters are a leading plus (+) or minus (-) sign and the
digits 0 through 9. These characters can be checked as they’re being typed, which means the
get() function is used to input a character at a time, or after all the characters can be
accepted in a string, and then each string character is checked for validity. After all the
entered characters have been validated, the entered string can be converted into the correct
data type.
Two basic techniques can be used to verify the validity of entered characters. Section 9.5
explains one of these techniques: character-by-character checking. A second technique,
which encompasses a broader scope of data-processing tasks using exception handling, is
discussed at the end of Section 9.5.
EXERCISES 9.4
1. (Practice) Enter and execute Program 9.13.
2. (Practice) Enter and execute Program 9.14.
532 Completing the Basics
3. (Practice) Write a C++ program that counts the number of words in a string. A word is
encountered whenever a transition from a blank space to a nonblank character is
encountered. The string contains only words separated by blank spaces.
4. (Practice) Generate 10 random numbers in the range 0 to 129. If the number represents
a printable character, print the character with an appropriate message that indicates the
following:
The character is a lowercase letter.
The character is an uppercase letter.
The character is a digit.
The character is a space.
If the character is none of these, display its value in integer format.
5. (Practice) a. Write a function named length() that determines and returns the length
of a string without using the string class length() function.
b. Write a simple main() function to test the length() function written for Exercise 5a.
6. (Practice) a. Write a function named countlets() that returns the number of letters
in a string passed as an argument. Digits, spaces, punctuation, tabs, and newline charac-
ters should not be included in the returned count.
b. Include the countlets() function written for Exercise 6a in an executable C++ pro-
gram, and use the program to test the function.
7. (Practice) Write a program that accepts a string from the console and displays the hexa-
decimal equivalent of each character in the string.
8. (Practice) Write a C++ program that accepts a string from the console and displays the
string one word per line.
9. (Debug) In response to the following code, suppose a user enters the data 12e4:
cout << "Enter an integer: ";
cin >> value;
What value will be stored in the integer variable value?
9.5 Input Data Validation
One of the major uses of strings in programs is for user-input validation. Validating user input
is essential: Even though a program prompts the user to enter a specific type of data, such
as an integer, the prompt doesn’t ensure that the user will comply. What a user enters is, in
fact, totally out of the programmer’s control. What is in your control is how you deal with the
entered data.
It certainly does no good to tell a frustrated user that “The program clearly tells you to
enter an integer, and you entered a date.” Successful programs anticipate invalid data and
prevent it from being accepted and processed. Typically, this is accomplished by first
validating that data is of the correct type. If it is, the data is accepted; otherwise, the user is
requested to reenter the data, with an explanation of why the entered data was invalid.
533
Chapter 9
Input Data Validation
A common method of validating numerical input data is accepting all numbers as strings.
Each character in the string can then be checked to make sure it complies with the requested
data type. After this check is made and data is verified to be the correct type, the string is
converted to an integer or double-precision value by using the conversion functions listed in
Table 9.7. (For data accepted with string class objects, the c_str() function must be
applied to the string before the conversion function is called.)
As an example, consider inputting an integer number. To be valid, the data entered must
adhere to the following conditions:
• The data must contain at least one character.
• If the first character is a + or - sign, the data must contain at least one digit.
• Only digits from 0 to 9 are acceptable following the first character.
Table 9.7 C-String Conversion Functions
Function Description Example
int atoi(stringExp) Converts stringExp to an
integer. Conversion stops at
the first non-integer character.
atoi("1234")
double atof(stringExp) Converts stringExp to a
double-precision number.
Conversion stops at the first
character that can’t be
interpreted as a double.
atof("12.34")
char[] itoa(integerExp) Converts integerExp to a
character array. The space
allocated for the returned
characters must be large
enough for the converted
value.
itoa(1234)
The following function, isvalidInt(), can be used to check that an entered string
complies with these conditions. This function returns the Boolean value of true if the
conditions are satisfied; otherwise, it returns a Boolean false value.
bool isvalidInt(string str)
{
int start = 0;
int i;
bool valid = true; // assume a valid
bool sign = false; // assume no sign
// check for an empty string
if (int(str.length()) == 0) valid = false;
// check for a leading sign
if (str.at(0) == '-'|| str.at(0) == '+')
{
sign = true;
start = 1; // start checking for digits after the sign
}
墌
534 Completing the Basics
// check that there is at least one character after the sign
if (sign && int(str.length()) == 1) valid = false;
// now check the string, which you know
// has at least one non-sign character
i = start;
while(valid && i < int(str.length()))
{
if(!isdigit(str.at(i))) valid = false; //found a non-digit character
i++; // move to next character
}
return valid;
}
In the code for the isvalidInt() function, pay attention to the conditions being
checked. They are commented in the code and consist of the following:
• The string is not empty.
• A valid sign (+ or -) is present.
• If a sign is present, at least one digit follows it.
• All the remaining characters in the string are digits.
Only if all these conditions are met does the function return a Boolean true value. After
this value is returned, the string can be converted into an integer safely with the assurance
that no unexpected value will result to hamper further data processing. Program 9.18 uses this
function in the context of a complete program.
Program 9.18
#include <iostream>
#include <string>
using namespace std;
int main()
{
bool isvalidInt(string); // function prototype (declaration)
string value;
int number;
cout << "Enter an integer: ";
getline(cin, value);
墌
535
Chapter 9
Input Data Validation
if (!isvalidInt(value))
cout << "The number you entered is not a valid integer.";
else
{
number = atoi(value.c_str());
cout << "The integer you entered is " << number;
}
return 0;
}
bool isvalidInt(string str)
{
int start = 0;
int i;
bool valid = true; // assume a valid
bool sign = false; // assume no sign
// check for an empty string
if (int(str.length()) == 0) valid = false;
// check for a leading sign
if (str.at(0) == '-'|| str.at(0) == '+')
{
sign = true;
start = 1; // start checking for digits after the sign
}
// check that there is at least one character after the sign
if (sign && int(str.length()) == 1) valid = false;
// now check the string, which you know
// has at least one non-sign character
i = start;
while(valid && i < int(str.length()))
{
if(!isdigit(str.at(i))) valid = false; //found a non-digit character
i++; // move to next character
}
return valid;
}
536 Completing the Basics
Two sample runs of Program 9.18 produced the following output:
Enter an integer: 12e45
The number you entered is not a valid integer.
and
Enter an integer: -12345
The integer you entered is -12345
As shown by this output, the program successfully determines that an invalid character
was entered in the first run.
A second line of defense is to provide error-processing code in the context of exception-
handling code. This type of code is typically used to permit the user to correct a problem,
such as invalid data entry, by reentering a new value. The means of providing this code in
C++ is referred to as exception handling.
Using exception handling, you can construct a complete means of ensuring that the user
enters an integer number in response to a request for an integer value. The technique
involves extending the isvalidInt() function in Program 9.18 to ensure that not only is
an invalid integer value detected, but also the program gives the user the option of reentering
values until a valid integer is entered. This technique can be applied easily to ensure the
entry of a valid double-precision number, which is the other numerical data type often
requested as user-entered data.
Using the isvalidInt() function from Program 9.18, a more comprehensive function
named getanInt() is developed that uses exception processing to accept user input
continuously until a string corresponding to a valid integer is detected. After a valid string is
entered, the getanInt() function converts the string to an integer and returns the integer
value. This technique ensures that the program requesting an integer actually receives
aninteger and prevents any unwarranted effects, such as a program crash caused by an invalid
data type being entered. The algorithm used to perform this task is as follows:
Set a Boolean variable named notanint to true
while (notanint is true)
try
Accept a string value
If the string value does not correspond to an integer, throw an exception
catch the exception
Display the error message "Invalid integer - Please reenter: "
Send control back to the while statement
Set notanint to false (causes the loop to terminate)
End while
Return the integer corresponding to the entered string
The code corresponding to this algorithm is shaded in Program 9.19.
537
Chapter 9
Input Data Validation
Program 9.19
#include <iostream>
#include <string>
using namespace std;
int main()
{
int getanInt(); // function declaration (prototype)
int value;
cout << "Enter an integer value: ";
value = getanInt();
cout << "The integer entered is: " << value << endl;
return 0;
}
int getanInt()
{
bool isvalidInt(string); // function declaration (prototype)
bool notanint = true;
string svalue;
while (notanint)
{
try
{
cin >> svalue; // accept a string input
if (!isvalidInt(svalue)) throw svalue;
}
catch (string e)
{
cout << "Invalid integer - Please reenter: ";
continue; // send control to the while statement
}
notanint = false;
}
return atoi(svalue.c_str()); // convert to an integer
}
墌
538 Completing the Basics
Following is a sample output produced by Program 9.19:
Enter an integer value: abc
Invalid integer - Please reenter: 12.
Invalid integer - Please reenter: 12e
Invalid integer - Please reenter: 120
The integer entered is: 120
As this output shows, the getanInt() function works correctly. It requests input
continuously until a valid integer is entered.
bool isvalidInt(string str)
{
int start = 0;
int i;
bool valid = true; // assume a valid
bool sign = false; // assume no sign
// check for an empty string
if (int(str.length()) == 0) valid = false;
// check for a leading sign
if (str.at(0) == '-'|| str.at(0) == '+')
{
sign = true;
start = 1; // start checking for digits after the sign
}
// check that there is at least one character after the sign
if (sign && int(str.length()) == 1) valid = false;
// now check the string, which you know
// has at least one non-sign character
i = start;
while(valid && i < int(str.length()))
{
if(!isdigit(str.at(i))) valid = false; // found a non-digit character
i++; // move to next character
}
return valid;
}
539
Chapter 9
Input Data Validation
EXERCISES 9.5
1. (Practice) Write a C++ program that prompts the user to type in an integer. Have your
program use cin to accept the number as an integer and use cout to display the value
your program actually accepted from the data entered. Run your program four times. The
first time you run the program, enter a valid integer number; the second time, enter a
double-precision number; the third time, enter a character; and the fourth time, enter the
value 12e34.
2. (Modify) Modify the program you wrote for Exercise 1, but have your program use a
double-precision variable. Run the program four times: First, enter an integer; second,
enter a decimal number; third, enter a decimal number with an f as the last character
entered; and fourth, enter a character. Using the output display, keep track of what num-
ber your program actually accepted from the data you entered. What happened, if any-
thing, and why?
3. (For Thought) a. Why do you think successful application programs contain extensive
data input validity checks? (Hint: Review Exercises 1 and 2.)
b. What do you think is the difference between a data-type check and a data-
reasonableness check?
c. A program requests that the user enter a month, day, and year. What are some reason-
ableness checks that could be made on the data entered?
4. (Practice) a. Enter and execute Program 9.18.
b. Run Program 9.18 four times, using the data referred to in Exercise 1 for each run.
5. (Modify) Modify Program 9.18 to display any invalid characters that were entered.
6. (Modify) Modify Program 9.18 to request an integer continuously until a valid number is
entered.
7. (Modify) Modify Program 9.18 to remove all leading and trailing spaces from the entered
string before it’s checked for validity.
8. (Useful Utility) Write a function that checks each digit as it’s entered, instead of check-
ing the completed string, as in Program 9.18.
9. (Practice) Enter and execute Program 9.19.
10. (Modify) Modify the isvalidInt() function used in Program 9.19 to remove all lead-
ing and trailing blank spaces from its string argument before determining whether the
string corresponds to a valid integer.
11. (Modify) Modify the isvalidInt() function used in Program 9.19 to accept a string
that ends in a decimal point. For example, the input 12. should be accepted and con-
verted to the integer number 12.
540 Completing the Basics
9.6 A Closer Look: Namespaces and Creating a Personal
Library
Until the introduction of PCs in the early 1980s, with their extensive use of integrated
circuits and microprocessors, computer speed and available memory were severely restricted.
For example, the most advanced computers had speeds measured in milliseconds; current
computers have speeds measured in nanoseconds and higher. Similarly, the memory capacity
of early desktop computers consisted of 4000 bytes of internal memory, but today’s computer
memories are in the 512 MB range and higher.
With these early hardware restrictions, programmers had to use every possible trick to
save memory space and make programs run more efficiently. Almost every program was
hand-crafted and included what was called “clever code” to minimize runtime and maximize
use of memory storage. Unfortunately, this individualized code became a liability. New
programmers had to spend considerable time to understand existing code; even the original
programmer had trouble figuring out code written only months before. This complexity in
code made modifications time consuming and costly and precluded cost-effective reuse of
existing code for new installations.
The inability to reuse code efficiently, combined with expanded hardware capabilities,
prompted the discovery of more efficient programming. This discovery began with structured
programming concepts incorporated into procedural languages, such as Pascal, and led to the
object-oriented techniques that form the basis of C++. An early criticism of C++, however,
was that it didn’t have a comprehensive library of classes, but with the current ANSI/ISO
standard, an extensive C++ library is available.
No matter how many useful classes and functions the standard library provides, however,
each major type of programming application, such as engineering, scientific, and financial, has
its own specialized requirements. For example, the ctime header file in C++ provides good
date and time functions. However, for specialized needs, such as scheduling problems, these
functions must be expanded to include finding the number of working days between two
dates, taking into account weekends and holidays, among other tasks. These functions could
be provided as part of a more complete Date class or as non-class functions.
To meet these specialized needs, programmers create and share their own libraries of
classes and functions with other programmers working on the same or similar projects. After
the classes and functions have been tested, they can be incorporated into any program
without further coding time.
At this stage in your programming career, you can begin building your own library of
specialized functions and classes. Section 9.5 described how to do this with the input validation
functions, isvalidInt() and getanInt(), which are reproduced here for convenience:
bool isvalidInt(string str)
{
int start = 0;
int i;
bool valid = true; // assume a valid
bool sign = false; // assume no sign
// check for an empty string
if (int(str.length()) == 0) valid = false;
墌
541
Chapter 9
A Closer Look: Namespaces and
Creating a Personal Library
// check for a leading sign
if (str.at(0) == '-'|| str.at(0) == '+')
{
sign = true;
start = 1; // start checking for digits after the sign
}
// check that there is at least one character after the sign
if (sign && int(str.length()) == 1) valid = false;
// now check the string, which you know
// has at least one non-sign character
i = start;
while(valid && i < int(str.length()))
{
if(!isdigit(str.at(i))) valid = false; // found a
// non-digit character
i++; // move to next character
}
return valid;
}
int getanInt()
{
bool isvalidInt(string); // function declaration (prototype)
bool notanint = true;
string svalue;
while (notanint)
{
try
{
cin >> svalue; // accept a string input
if (!isvalidInt(svalue)) throw svalue;
}
catch (string e)
{
cout << "Invalid integer - Please reenter: ";
continue; // send control to the while statement
}
notanint = false;
}
return atoi(svalue.c_str()); // convert to an integer
}
The first step in creating a library is to encapsulate all the specialized functions and
classes into one or more namespaces and then store the complete code (with or without using
a namespace) into one or more files. For example, you can create one namespace,
dataChecks, and save it in the file named dataChecks.cpp. Note that the namespace’s
filename need not be the same as the namespace name used in the code.
The syntax for creating a namespace is the following:
namespace name
{
// functions and/or classes in here
} // end of namespace
542 Completing the Basics
The following code includes the two functions isvalidInt() and getanInt() in the
namespace dataChecks, adds the appropriate include files, and uses a declaration statement
needed by the new namespace. The syntax required to create the namespace has been shaded:
#include <iostream>
#include <string>
using namespace std;
namespace dataChecks
{
bool isvalidInt(string str)
{
int start = 0;
int i;
bool valid = true; // assume a valid
bool sign = false; // assume no sign
// check for an empty string
if (int(str.length()) == 0) valid = false;
// check for a leading sign
if (str.at(0) == '-'|| str.at(0) == '+')
{
sign = true;
start = 1; // start checking for digits after the sign
}
// check that there is at least one character after the sign
if (sign && int(str.length()) == 1) valid = false;
// now check the string, which you know
// has at least one non-sign character
i = start;
while(valid && i < int(str.length()))
{
if(!isdigit(str.at(i))) valid = false; // found a
// non-digit character
i++; // move to next character
}
return valid;
}
int getanInt()
{
bool isvalidInt(string); // function declaration (prototype)
bool notanint = true;
string svalue;
while (notanint)
{
try
{
cin >> svalue; // accept a string input
if (!isvalidInt(svalue)) throw svalue;
}
墌
543
Chapter 9
A Closer Look: Namespaces and
Creating a Personal Library
catch (string e)
{
cout << "Invalid integer - Please reenter: ";
continue; // send control to the while statement
}
notanint = false;
}
return atoi(svalue.c_str()); // convert to an integer
}
} // end of dataChecks namespace
After the namespace has been created and stored in a file, it can be included in another
file by supplying a preprocessor directive to inform the compiler where the namespace is
found and by including a using directive that tells the compiler which namespace in the file
to use. For the dataChecks namespace, which is stored in a file named dataChecks.
cpp, the following statements perform these tasks:
#include <c:mylibrarydataChecks.cpp>
using namespace dataChecks;
The first statement provides the full pathname for the source code file. Notice that two
backslashes are used to separate items in pathnames. The double backslashes are required
when providing a relative or full pathname. The only time backslashes aren’t required is
when the library code is in the same directory as the program being executed. As indicated,
the dataChecks source file is saved in the mylibrary folder. The second statement tells
the compiler to use the dataChecks namespace in the designated file. Program 9.20
includes these two statements in an executable program.
The only requirement for the include statement in Program 9.20 is that the filename
and location must correspond to an existing file with the same name in the designated path;
Program 9.20
#include <c:mylibrarydataChecks.cpp>
using namespace dataChecks;
int main()
{
int value;
cout << "Enter an integer value: ";
value = getanInt();
cout << "The integer entered is: " << value << endl;
return 0;
}
544 Completing the Basics
otherwise, a compiler error occurs. If you want to name the source code file with a file
extension, any extension can be used as long as these rules are followed:
• The filename under which the code is stored includes the extension.
• The same filename, including extension, is used in the include statement.
Therefore, if the filename used to store the functions is dataLib.cpp, the include
statement in Program 9.20 would be the following:
#include <c:mylibrarydataLib.cpp>
Additionally, a namespace isn’t required in the file. Using a namespace permits you to
isolate the data-checking functions in one area and add more namespaces to the file as
needed. Designating a namespace in the using statement tells the compiler to include only
the code in the specified namespace rather than all code in the file. In Program 9.20, if the
data-checking functions weren’t enclosed in a namespace, the using statement for the
dataChecks namespace would have to be omitted.
Including the previously written and tested data-checking functions in Program 9.20 as
a separate file enables you to focus on the program code using these functions instead of
being concerned with function code that’s already been written and tested. In Program 9.20,
the main() function exercises the data-checking functions and produces the same output as
Program 9.19. In creating the dataChecks namespace, you have included source code for
the two functions. Including this code isn’t required, and a compiled version of the source
code can be saved instead. Finally, additions to a namespace defined in one file can be made
in another file by using the same namespace name in the new file and including a using
statement for the first file’s namespace.
EXERCISES 9.6
1. (Practice) Enter and compile Program 9.20. (Hint: The namespace file dataChecks and
the program file are available with the source code provided on this book’s Web site.)
2. (For Thought) Why would a programmer supply a namespace file in its compiled form
rather than as source code?
3. (For Thought) a. What is an advantage of namespaces?
b. What is a possible disadvantage of namespaces?
4. (For Thought) What types of classes and functions would you include in a personal
library? Why?
5. (Useful Utility) a. Write a C++ function named whole() that returns the integer part
of any number passed to the function. (Hint: Assign the passed argument to an integer
variable.)
b. Include the function written in Exercise 5a in a working program. Make sure your
function is called from main() and correctly returns a value to main(). Have
main() use a cout statement to display the returned value. Test the function by
passing various data to it.
545
Chapter 9
A Closer Look: Namespaces and
Creating a Personal Library
c. When you’re confident that the whole() function written for Exercise 5a works cor-
rectly, save it in a namespace and a personal library of your choice.
6. (Useful Utility) a. Write a C++ function named fracpart() that returns the fractional
part of any number passed to the function. For example, if the number 256.879 is passed
to fracpart(), the number .879 should be returned. Have the fracpart() function
call the whole() function you wrote in Exercise 5a. The number returned can then be
determined as the number passed to fracpart() less the returned value when the
same argument is passed to whole().
b. Include the function written in Exercise 6a in a working program. Make sure the
function is called from main() and correctly returns a value to main(). Have
main() use a cout statement to display the returned value. Test the function by
passing various data to it.
c. When you’re confident the fracpart() function written for Exercise 6a works cor-
rectly, save it in the same namespace and personal library selected for Exercise 5c.
9.7 Common Programming Errors
Here are the common errors associated with defining and processing strings:
1. Forgetting to include the string header file when using string class objects.
2. Forgetting that the newline character, 'n', is a valid data input character.
3. Forgetting to convert a string class object by using the c_str() function when
converting string class objects to numerical data types.
9.8 Chapter Summary
1. A string literal is any sequence of characters enclosed in quotation marks. It’s referred to
as a string value, a string constant, and, more conventionally, a string.
2. A string can be constructed as an object of the string class.
3. The string class is commonly used for constructing strings for input and output
purposes, such as for prompts and displayed messages. Because of its capabilities, this
class is used when strings need to be compared or searched or specific characters in a
string need to be examined or extracted as a substring. It’s also used in more advanced
situations when characters in a string need to be replaced, inserted, or deleted regularly.
4. Strings can be manipulated by using the functions of the class they’re objects of or by
using the general-purpose string and character functions.
5. The cin object, by itself, tends to be of limited usefulness for string input because it
terminates input when a blank is encountered.
6. For string class data input, use the getline() function.
7. The cout object can be used to display string class strings.
546 Completing the Basics
Programming Projects for Chapter 9
1. (Practice) Enter the data for the info.txt file in Figure 9.1 or download it from this
book’s Web site. Then enter and execute Program 9.5 and verify that the backup file was
written.
2. (Modify) Modify Program 9.5 to use a getline() function in place of the get()
method currently in the program.
3. (Useful Utility) a. Write a C++ function that accepts a string and two character values.
The function should return the string with each occurrence of the first character replaced
by the second character.
b. Test the function written for Exercise 3a by writing a program that accepts a string from
the user, calls the function written for Exercise 3a to replace all occurrences of the letter
e with the letter x from the user-entered string, and then displays the changed string.
4. (Useful Utility) Modify the function written for Exercise 3a to search for the first
occurrence of a user-entered sequence of characters, and then replace this sequence,
when it’s found in the string, with a second user-entered sequence. For example, if the
entered string is Figure 4-4 illustrates the output of Program 4-2 and
the user enters that 4- is to be replaced by 3-, the resulting string is Figure 3-4
illustrates the output of Program 4-2. (Only the first occurrence of the
searched for sequence has been changed.)
5. (Useful Utility) Modify the program written for Exercise 4 to replace all occurrences of
the designated sequence of characters with the new sequence of characters. For example,
if the entered string is Figure 4-4 illustrates the output of Program 4-2
and the user enters that 4- is to be replaced by 3-, the resulting string is Figure 3-4
illustrates the output of Program 3-2.
6. (Data Processing) a. Write a C++ program that stops reading a line of text when a
period is entered and displays the sentence with correct spacing and capitalization. For
this program, correct spacing means only one space between words, and all letters should
be lowercase, except the first letter. For example, if the user enters the text i am going
to Go TO THe moVies., the displayed sentence should be I am going to go to
the movies.
b. Determine what characters, if any, aren’t displayed correctly by the program you
created for Exercise 6a.
7. (Data Processing) Write a C++ program that accepts a name as first name followed by
last name, and then displays the name as last name, first name. For example, if the user
enters Gary Bronson, the output should be Bronson, Gary.
8. (Data Processing) Modify the program written for Exercise 7 to include an array of
five names.
547
Chapter 9
Programming Projects
9. (Useful Utility) a. Write a C++ function named isvalidReal() that checks for a
valid double-precision number. This kind of number can have an optional + or - sign, at
most one decimal point (which can be the first character), and at least one digit between
0 and 9. The function should return a Boolean value of true if the entered number is
a real number; otherwise, it should return a Boolean value of
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf
00 C++ For Engineers and Scientists.pdf

More Related Content

PDF
Experimental Research
PDF
4. Formulating research problems
PPTX
Presentation computer FOR THE PYTHON PROGRAM
PDF
M256 Unit 1 - Software Development with Java
PDF
Algorithms and Application Programming
DOCX
Chapter 10 Modeling and Analysis Heuristic Search Methods
DOCX
ACCOUNTING INFORMATION SYSTEMSAccess and Data Analytics Test.docx
PDF
Analysis Of Algorithms An Active Learning Approach 1st Edition Jeffrey J Mcco...
Experimental Research
4. Formulating research problems
Presentation computer FOR THE PYTHON PROGRAM
M256 Unit 1 - Software Development with Java
Algorithms and Application Programming
Chapter 10 Modeling and Analysis Heuristic Search Methods
ACCOUNTING INFORMATION SYSTEMSAccess and Data Analytics Test.docx
Analysis Of Algorithms An Active Learning Approach 1st Edition Jeffrey J Mcco...

Similar to 00 C++ For Engineers and Scientists.pdf (20)

PDF
Digicrome Data Science & AI 11 Month Course PDF.pdf
PDF
The Python Workshop.pdf
DOCX
1. Text mining – Text mining or text data mining is a process to e.docx
PPTX
Thripp EME 2040 Slides on Microsoft Education Badges, PowerPoint Quiz, Comput...
PDF
Investing in ai driven startups
PDF
A Philosophy Of Software Design Ousterhout John
PDF
Chapter 1
DOCX
Business intelligence and analyticssystems for dec
PPTX
Supervised learning
PDF
A Philosophy Of Software Design John Ousterhout
PDF
Early_TranscEndEnTals_EighTh_EdiTion.pdf
PDF
Machine Learning Activities for Students|ashokveda.com.pdf
PDF
(Effective Software Development Series) Bill Wagner - Effective C# (Covers C#...
PDF
Probability and Statistics for Engineering and the Sciences 9th Edition Devor...
PDF
C Plus Data Structures Subsequent Dale Nell B
PDF
Introduction to SCM.pdf
PDF
(eBook PDF) C++ How to Program 10th Edition by Paul J. Deitel
PDF
Data Modeling Essentials 3rd Ed Graeme C Simsion Graham C Witt
PDF
Supply_Chain_Management_STRATEGY_PLANNIN.pdf
PDF
Projects-in-Computing-and-Information-Systems-A-Student’s-Guide-2nd-Edition-A...
Digicrome Data Science & AI 11 Month Course PDF.pdf
The Python Workshop.pdf
1. Text mining – Text mining or text data mining is a process to e.docx
Thripp EME 2040 Slides on Microsoft Education Badges, PowerPoint Quiz, Comput...
Investing in ai driven startups
A Philosophy Of Software Design Ousterhout John
Chapter 1
Business intelligence and analyticssystems for dec
Supervised learning
A Philosophy Of Software Design John Ousterhout
Early_TranscEndEnTals_EighTh_EdiTion.pdf
Machine Learning Activities for Students|ashokveda.com.pdf
(Effective Software Development Series) Bill Wagner - Effective C# (Covers C#...
Probability and Statistics for Engineering and the Sciences 9th Edition Devor...
C Plus Data Structures Subsequent Dale Nell B
Introduction to SCM.pdf
(eBook PDF) C++ How to Program 10th Edition by Paul J. Deitel
Data Modeling Essentials 3rd Ed Graeme C Simsion Graham C Witt
Supply_Chain_Management_STRATEGY_PLANNIN.pdf
Projects-in-Computing-and-Information-Systems-A-Student’s-Guide-2nd-Edition-A...
Ad

More from KirubelWondwoson1 (6)

PDF
Chapter 4 (Part I) - Array and Strings.pdf
PDF
Chapter 1 - Basic concepts of programming.pdf
PDF
Chapter 5 - Modular Programming.pdf
PDF
Chapter 4 (Part II) - Array and Strings.pdf
PDF
Chapter 3 - Flow of Control Part II.pdf
PDF
Chapter 2 - Flow of Control Part I.pdf
Chapter 4 (Part I) - Array and Strings.pdf
Chapter 1 - Basic concepts of programming.pdf
Chapter 5 - Modular Programming.pdf
Chapter 4 (Part II) - Array and Strings.pdf
Chapter 3 - Flow of Control Part II.pdf
Chapter 2 - Flow of Control Part I.pdf
Ad

Recently uploaded (20)

PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PPTX
Monitoring Stack: Grafana, Loki & Promtail
PDF
Tally Prime Crack Download New Version 5.1 [2025] (License Key Free
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Digital Systems & Binary Numbers (comprehensive )
PDF
Designing Intelligence for the Shop Floor.pdf
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
Salesforce Agentforce AI Implementation.pdf
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
17 Powerful Integrations Your Next-Gen MLM Software Needs
PDF
CCleaner Pro 6.38.11537 Crack Final Latest Version 2025
PPTX
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
PPTX
Operating system designcfffgfgggggggvggggggggg
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
medical staffing services at VALiNTRY
PDF
Nekopoi APK 2025 free lastest update
PPTX
history of c programming in notes for students .pptx
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Download FL Studio Crack Latest version 2025 ?
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
wealthsignaloriginal-com-DS-text-... (1).pdf
Monitoring Stack: Grafana, Loki & Promtail
Tally Prime Crack Download New Version 5.1 [2025] (License Key Free
Design an Analysis of Algorithms II-SECS-1021-03
Digital Systems & Binary Numbers (comprehensive )
Designing Intelligence for the Shop Floor.pdf
Design an Analysis of Algorithms I-SECS-1021-03
Salesforce Agentforce AI Implementation.pdf
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
17 Powerful Integrations Your Next-Gen MLM Software Needs
CCleaner Pro 6.38.11537 Crack Final Latest Version 2025
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
Operating system designcfffgfgggggggvggggggggg
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
medical staffing services at VALiNTRY
Nekopoi APK 2025 free lastest update
history of c programming in notes for students .pptx
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Download FL Studio Crack Latest version 2025 ?

00 C++ For Engineers and Scientists.pdf

  • 2. Colin Dean You knew you were a Computer Science major when… I had that feeling when, somewhat on a whim, I proposed to Westminster’s information systems department that they lend me nine new, unused computers in order to build a Folding@Home cluster in the Unix Lab. They approved, and that cluster ran 24/7 for about six months. (http://www.cs.westminster.edu/folding/). One piece of advice for first year students: Ask questions. Don’t be afraid to virtually inundate a professor with questions. Remember, it’s your education—get what you want out of it. If a professor is too busy to help you, find another one to help. Don’t share your code with classmates—don’t even let them look at it unless you get permission from a professor: it’s against every school’s academic integrity policies. And finally, learn at least one weird (read: non-major) language like Scheme, Smalltalk, Prolog, or even Haskell. You never know when it might come in handy. If you could have dinner with a famous computer scientist, living or dead, who would you choose? Tim Berners-Lee, the father of the World Wide Web. His creation has changed more lives directly than just about any other technology has. It’s enabled the dissemination of vast amounts of knowledge and enabled collaboration throughout the world. What technology blogs do you read on a regular basis? I find myself on Ars Technica, A List Apart, and The Daily WTF most often, as well as Engadget and a few politics and technology blogs. Where do you see yourself in ten years? I hope to be running my own successful Internet-based company and contemplating a doctorate, and perhaps holding public office. Colin Dean of Volant, PA graduated with a B.S. in Computer Science from Westminster College in New Wilmington, PA in May 2007. He completed his M.S. in Business Education in July 2008 at Robert Morris University and is employed as a developer in Pittsburgh, PA. Spotlight on Careers in Computing
  • 3. C++ for Engineers and Scientists Third Edition Gary J. Bronson G.J. Borse Contributing Editor Lehigh University Australia • Brazil • Japan • Korea • Mexico • Singapore • Spain • United Kingdom • United States
  • 4. C++ for Engineers and Scientists, Third Edition Gary J. Bronson Managing Editor: Marie Lee Acquisitions Editor: Amy Jollymore Senior Product Manager: Alyssa Pratt Developmental Editor: Lisa M. Lord Content Product Manager: Matt Hutchinson Marketing Manager: Bryant Chrzan Editorial Assistant: Julia Leroux-Lindsey Art Director: Marissa Falco Compositor: GEX Publishing Services © 2010 Course Technology, Cengage Learning ALL RIGHTS RESERVED. No part of this work covered by the copyright herein may be reproduced, transmitted, stored or used in any form or by any means graphic, electronic, or mechanical, including but not limited to photocopying, recording, scanning, digitizing, taping, Web distribution, information networks, or information storage and retrieval systems, except as permitted under Section 107 or 108 of the 1976 United States Copyright Act, without the prior written permission of the publisher. For product information and technology assistance, contact us at Cengage Learning Customer & Sales Support, 1-800-354-9706 For permission to use material from this text or product, submit all requests online at www.cengage.com/permissions Further permission questions can be e-mailed to permissionrequest@cengage.com ISBN-13: 978-0-324-78643-9 ISBN-10 : 0-324-78643-3 Course Technology 20 Channel Center Street Boston, Massachusetts 02210 USA Cengage Learning is a leading provider of customized learning solutions with office locations around the globe, including Singapore, the United Kingdom, Australia, Mexico, Brazil, and Japan. Locate your local office at: international.cengage.com/region Cengage Learning products are represented in Canada by Nelson Education, Ltd. For your lifelong learning solutions, visit www.cengage.com Purchase any of our products at your local college store or at our preferred online store www.ichapters.com Some of the product names and company names used in this book have been used for identification purposes only and may be trademarks or regis- tered trademarks of their respective manufacturers and sellers. Any fictional data related to persons or companies or URLs used through- out this book is intended for instructional purposes only. At the time this book was printed, any such data was fictional and not belonging to any real persons or companies. The programs in this book are for instructional purposes only. They have been tested with care but are not guaranteed for any particular intent beyond educational purposes. The author and the publisher do not offer any warranties or representations, nor do they accept any liabilities with respect to the programs. Printed in the United States of America 1 2 3 4 5 6 7 14 13 12 11 10
  • 5. BRIEF TABLE OF CONTENTS Part 1 Fundamentals of C++ Programming 1 Chapter 1 Preliminaries 3 Chapter 2 Problem Solving Using C++ 43 Chapter 3 Assignment, Formatting, and Interactive Input 103 Chapter 4 Selection Structures 177 Chapter 5 Repetition Statements 231 Chapter 6 Modularity Using Functions 293 Chapter 7 Arrays 373 Chapter 8 I/O Streams and Data Files 439 Chapter 9 Completing the Basics 489 Part 2 Object-Oriented Programming 551 Chapter 10 Introduction to Classes 553 Chapter 11 Class Functions and Conversions 597 Brief Table of Contents 3
  • 6. Part 3 Data Structures 663 Chapter 12 Pointers 665 Chapter 13 Structures 707 Part 4 Additional Topics 749 Chapter 14 Numerical Methods 751 Chapter 15 Bit Operations 787 Appendix A Operator Precedence Table 801 Appendix B ASCII Character Codes 803 Appendix C Floating-Point Number Storage 805 Appendix D Command-Line Arguments 809 Index 815 4 Brief Table of Contents
  • 7. CONTENTS Part 1 Fundamentals of C++ Programming 1 Chapter 1 Preliminaries 3 1.1 Preliminary One: Unit Analysis 4 Engineering and Scientific Units 6 1.2 Preliminary Two: Exponential and Scientific Notations 10 Using Scientific Notation 11 1.3 Preliminary Three: Software Development 14 Phase I: Development and Design 15 Phase II: Documentation 19 Phase III: Maintenance 19 Backup 20 1.4 Preliminary Four: Algorithms 22 1.5 A Closer Look: Software, Hardware, and Computer Storage 28 Machine Language 28 Assembly Languages 28 Low- and High-Level Languages 29 Procedural and Object Orientations 30 Application and System Software 30 The Development of C++ 31 Computer Hardware 33 Computer Storage 34 1.6 Common Programming Errors 37 1.7 Chapter Summary 37 Chapter 2 Problem Solving Using C++ 43 2.1 Introduction to C++ 43 The main() Function 46 The cout Object 48 2.2 Programming Style 53 Comments 55 2.3 Data Types 58 Integer Data Types 59 Determining Storage Size 62 Signed and Unsigned Data Types 64 Floating-Point Types 65 2.4 Arithmetic Operations 68 Expression Types 70 Integer Division 71 Negation 71 Operator Precedence and Associativity 72 2.5 Variables and Declaration Statements 76 Declaration Statements 78 Multiple Declarations 81 Memory Allocation 83 Displaying a Variable’s Address 85 Contents 5
  • 8. 2.6 A Case Study: Radar Speed Traps 90 2.7 Common Programming Errors 94 2.8 Chapter Summary 95 Chapter 3 Assignment, Formatting, and Interactive Input 103 3.1 Assignment Operations 103 Coercion 107 Assignment Variations 108 Accumulating 110 Counting 111 3.2 Formatting Numbers for Program Output 117 3.3 Using Mathematical Library Functions 131 Casts 135 3.4 Program Input Using cin 139 A First Look at User-Input Validation 143 3.5 Symbolic Constants 149 Placement of Statements 151 3.6 A Case Study: Acid Rain 158 3.7 A Closer Look: Programming Errors 164 3.8 Common Programming Errors 167 3.9 Chapter Summary 167 Chapter 4 Selection Structures 177 4.1 Selection Criteria 178 Relational Operators 178 Logical Operators 181 A Numerical Accuracy Problem 183 4.2 The if-else Statement 184 Compound Statements 187 Block Scope 190 One-Way Selection 191 Problems Associated with the if-else Statement 193 4.3 Nested if Statements 199 The if-else Chain 201 4.4 The switch Statement 208 4.5 A Case Study: Solving Quadratic Equations 213 4.6 A Closer Look: Program Testing 220 4.7 Common Programming Errors 222 4.8 Chapter Summary 223 Chapter 5 Repetition Statements 231 5.1 Basic Loop Structures 232 Pretest and Posttest Loops 232 Fixed-Count Versus Variable-Condition Loops 233 5.2 while Loops 234 5.3 Interactive while Loops 245 Sentinels 251 break and continue Statements 253 The Null Statement 254 6 Contents
  • 9. 5.4 for Loops 256 5.5 A Closer Look: Loop Programming Techniques 268 Technique 1: Interactive Input in a Loop 268 Technique 2: Selection in a Loop 269 Technique 3: Evaluating Functions of One Variable 270 Technique 4: Interactive Loop Control 273 5.6 Nested Loops 276 5.7 do while Loops 281 Validity Checks 283 5.8 Common Programming Errors 285 5.9 Chapter Summary 286 Chapter 6 Modularity Using Functions 293 6.1 Function and Parameter Declarations 294 Function Prototypes 295 Calling a Function 296 Defining a Function 297 Placement of Statements 302 Function Stubs 302 Functions with Empty Parameter Lists 303 Default Arguments 305 Reusing Function Names (Overloading) 305 Function Templates 306 6.2 Returning a Single Value 313 Inline Functions 319 6.3 Returning Multiple Values 324 Passing and Using Reference Parameters 324 6.4 A Case Study: Rectangular to Polar Coordinate Conversion 333 6.5 Variable Scope 346 Scope Resolution Operator 349 Misuse of Globals 351 6.6 Variable Storage Categories 354 Local Variable Storage Categories 355 Global Variable Storage Categories 358 6.7 Common Programming Errors 362 6.8 Chapter Summary 364 Chapter 7 Arrays 373 7.1 One-Dimensional Arrays 374 Input and Output of Array Values 378 7.2 Array Initialization 384 7.3 Declaring and Processing Two-Dimensional Arrays 388 Larger Dimensional Arrays 392 7.4 Arrays as Arguments 394 Internal Array Element Location Algorithm 401 7.5 A Case Study: Statistical Analysis 404 7.6 The Standard Template Library (STL) 410 7.7 A Closer Look: Searching and Sorting 418 Search Algorithms 418 Big O Notation 425 Sort Algorithms 426 7 Contents
  • 10. 7.8 Common Programming Errors 432 7.9 Chapter Summary 433 Chapter 8 I/O Streams and Data Files 439 8.1 I/O File Stream Objects and Methods 440 Files 440 File Stream Objects 441 File Stream Methods 442 8.2 Reading and Writing Character-Based Files 454 Reading from a Text File 456 Standard Device Files 461 Other Devices 462 8.3 Random File Access 465 8.4 File Streams as Function Arguments 468 8.5 A Case Study: Pollen Count File Update 472 8.6 A Closer Look: The iostream Class Library 479 File Stream Transfer Mechanism 479 Components of the iostream Class Library 480 In-Memory Formatting 482 8.7 Common Programming Errors 483 8.8 Chapter Summary 484 Chapter 9 Completing the Basics 489 9.1 Exception Handling 490 9.2 Exceptions and File Checking 496 Opening Multiple Files 500 9.3 The string Class 504 string Class Functions 505 String Input and Output 507 String Processing 511 9.4 Character Manipulation Functions 522 Character I/O 526 A Second Look at User-Input Validation 531 9.5 Input Data Validation 533 9.6 A Closer Look: Namespaces and Creating a Personal Library 541 9.7 Common Programming Errors 546 9.8 Chapter Summary 546 Part 2 Object-Oriented Programming 551 Chapter 10 Introduction to Classes 553 10.1 Abstract Data Types in C++ (Classes) 553 Abstract Data Types 555 Class Construction 556 Terminology 563 8 Contents
  • 11. 10.2 Constructors 567 Calling Constructors 570 Overloaded and Inline Constructors 570 Destructors 574 10.3 A Case Study: Constructing a Room Object 576 10.4 A Closer Look: Object Identification and the Unified Modeling Language (UML) 582 Representing Problems with Models 583 Class and Object Diagrams 585 Relationships 588 10.5 Common Programming Errors 592 10.6 Chapter Summary 593 Chapter 11 Class Functions and Conversions 597 11.1 Assignment 597 Copy Constructors 602 Base/Member Initialization 605 11.2 Additional Class Features 607 Class Scope 607 Static Class Members 607 Friend Functions 612 11.3 Operator Functions 616 Operator Functions as Friends 623 11.4 Data Type Conversions 625 Built-in to Built-in Conversion 626 Built-in to Class Conversion 626 Class to Built-in Conversion 628 Class to Class Conversion 630 11.5 A Case Study: Random Numbers and Simulations 635 Scaling 636 Elevator Simulation 637 11.6 Class Inheritance 645 Access Specifications 647 11.7 Polymorphism 653 11.8 Common Programming Errors 658 11.9 Chapter Summary 658 Part 3 Data Structures 663 Chapter 12 Pointers 665 12.1 Addresses and Pointers 666 Storing Addresses 667 Using Addresses 667 Declaring Pointers 668 References and Pointers 671 12.2 Array Names as Pointers 677 Dynamic Array Allocation 682 12.3 Pointer Arithmetic 686 Pointer Initialization 689 12.4 Passing Addresses 690 Passing Arrays 695 Advanced Pointer Notation 699 9 Contents
  • 12. 12.5 Common Programming Errors 702 12.6 Chapter Summary 704 Chapter 13 Structures 707 13.1 Single Structures 708 13.2 Arrays of Structures 714 13.3 Structures as Function Arguments 718 Passing a Pointer 721 Returning Structures 724 13.4 Linked Lists 727 13.5 Dynamic Data Structure Allocation 735 13.6 Unions 742 13.7 Common Programming Errors 744 13.8 Chapter Summary 745 Part 4 Additional Topics 749 Chapter 14 Numerical Methods 751 14.1 Introduction to Root Finding 751 14.2 The Bisection Method 755 14.3 Refinements to the Bisection Method 761 Regula Falsi Method 762 Modified Regula Falsi Method 764 Summary of the Bisection Methods 769 14.4 The Secant Method 770 14.5 Introduction to Numerical Integration 774 14.6 The Trapezoidal Rule 775 Computational Form of the Trapezoidal Rule Equation 776 Example of a Trapezoidal Rule Calculation 777 14.7 Simpson’s Rule 779 Example of Simpson’s Rule as an Approximation to an Integral 781 14.8 Common Programming Errors 783 14.9 Chapter Summary 783 Chapter 15 Bit Operations 787 15.1 The AND Operator 788 15.2 The Inclusive OR Operator 790 15.3 The Exclusive OR Operator 793 15.4 The Complement Operator 795 15.5 Different-Size Data Items 795 15.6 The Shift Operators 796 15.7 Chapter Summary 799 Appendix A Operator Precedence Table 801 Appendix B ASCII Character Codes 803 10 Contents
  • 13. Appendix C Floating-Point Number Storage 805 Appendix D Command-Line Arguments 809 Index 815 11 Contents
  • 15. PREFACE The C++ programming language, which includes C as a proper subset, has become the preeminent programming language in the engineering and scientific fields. For most engineers and scientists, however, using the full potential of C++, which is a hybrid language containing both structured and object-oriented features, involves a gradual refinement of programming skills from a structured approach to an object-oriented one. One reason for this is that many engineering and scientific problems can be solved efficiently and conveniently by using only C++’s structured elements. The refinement approach, from structural to object-oriented programming, is the one C++ for Engineers and Scientists, Third Edition, takes. Therefore, like the first two editions, this new edition begins by providing a strong foundation in structured programming. This foundation is then expanded to a complete object orientation in a pedagogically sound and achievable progression. Additionally, to keep it current with the current ANSI/ISO C++ standard, this edition has several important changes and added features, including the following: • Restructuring Part One to include both arrays and files, which allows using Part One as the basis for a complete semester course in C++ • Adding more than 40 new engineering and scientific exercises that incorporate the fields of electrical engineering, mechanical engineering thermodynamics, structural engineering, numerical applications, physics, heat transfer, chemistry, and fluid mechanics • Adding a section on performing a unit analysis • Adding a new introduction to the Standard Template Library • Adding a section that introduces the fundamentals of the Unified Modeling Language (UML) • Restructuring the case studies throughout the book to emphasize specific engineer- ing or scientific applications • Adding end-of chapter programming projects that supplement the exercises at the end of each section • Labeling all exercises and programming projects as to application type The following features have been retained from the second edition: • Fundamentals of software engineering are discussed from both procedural and object-oriented viewpoints. • Common Programming Errors sections have been retained. These sections antici- pate problems that novice C++ programmers encounter. • The ANSI/ISO C++ iostream library and namespace mechanism are used in all programs. • Exception handling is discussed in a complete section, with practical applications of exception handling included throughout the book. • The new C++ string class is covered. • A thorough discussion is included of input data validation and functions to check the numerical data type of input items and to allow reentering invalid numerical types. In practical terms, this book has been written to support both a one- and two-semester technical C++ programming course; the only prerequisite is that students should be familiar Preface 13
  • 16. with fundamental algebra. This book is constructed to be flexible enough so that professors can mold the book to their preferences for topic presentations. This flexibility is achieved in the following ways. Excluding Chapter 1, which includes computer literacy material for those who require this background, Part One presents the basic structured syntax, flow control, and modularity topics needed for a thorough understanding of C++’s structural features. With the topics of arrays (Chapter 7) and files (Chapter 8) having been moved to Part One, this part now provides a comprehensive one-semester course. As Chapters 7 and 8 have been written specifically to depend only on Chapters 1 through 6, their order of presentation in the classroom is entirely up to the professor’s discretion. With time permitting, the basics of classes, introduced in Chapter 10, can also be covered to complete a one-semester course. Additionally, depending on time and inclination, the numerical techniques discussed in Chapter 14 can be presented at any point after Part One has been completed. Figure 1 illustrates this one-semester topic dependency. An important feature of this book is that Part Two, on object-oriented programming, and Part Three, on data structures, are interchangeable. So if you want to cover object-oriented programming early, follow a Part One–Part Two–Part Three progression. On the other hand, if you want to continue with additional structured programming reinforcement and discuss object-oriented programming at the end of the course or the start of a second semester, follow the sequence Part One–Part Three–Part Two. In either case, the material on arrays in Chapter 7, files in Chapter 8, classes in Chapter 10, and numerical techniques in Chapter 14 can be introduced at any time after covering the first six chapters. Figure 2 shows the topic dependency chart for the complete book and illustrates the flexibility of introducing different topics under the umbrella of procedural programming, object-oriented programming, and data structures. Part One Introduction Chapter 1 Chapters 2 to 6 and 9 Arrays Chapter 7 Files Chapter 8 Objects Chapter 10 Figure 1 Topic dependency for a one-semester course 14 Preface
  • 17. Distinctive Features of This Book Writing Style One thing I have found to be essential in my own classes is that after the professor sets the stage in class, the assigned book must continue to encourage, nurture, and assist students in acquiring and “owning” the material. To do this, the book must be written in a manner that makes sense to students. My primary concern, and one of the distinctive features of this book, is that it has been written for students. Therefore, I believe the writing style used to convey the concepts is one of the most important aspects of this book. Modularity To produce readable and maintainable programs, modularity is essential. C++, by its nature, is a modular language. Therefore, the connection between C++ functions and modules is made early in Chapter 2 and sustained throughout the book. Similarly, the idea of parameter passing into modules is discussed early in Chapter 3, using C++’s mathematical library. Explaining these concepts early introduces students to function and argument passing as natural programming techniques. With the introduction of object-oriented programming techniques in Chapter 10, students can build on the basic concept of encapsulating both data and functions, which strengthens this modular emphasis. Software Engineering Rather than simply introduce students to programming in C++, this book introduces students to the fundamentals of software engineering from both a structured and object-oriented viewpoint. Chapter 1 introduces the software development procedure, which incorporates one of this book’s main themes: emphasizing problem-solving techniques. Therefore, the importance of understanding and defining a problem, selecting and refining a solution, and understanding the relationship between analysis, design, coding, and testing is stated early and followed through with practical examples in all subsequent case studies. Case Studies Starting with Chapter 2, most chapters contain a case study. These case studies demonstrate and reinforce effective problem solving in the context of the software Chapter 1 Literacy Topics Part One Procedural Programming Part Two (Chapters 10 and 11) Object-Oriented Programming Part Three (Chapters 12 and 13) Data Structures Part Four (Chapters 14 and 15) Figure 2 Topic dependency chart 15 Preface
  • 18. development procedure explained in Chapter 1 and are extended to object-oriented development when classes are introduced in Chapter 10. Program Testing Every C++ program in this book has been compiled and run successfully and has been quality assurance tested with Microsoft Visual C++ .NET. Source code for all programs can be found on the Course Technology Web site (www.cengage.com/coursetechnology). Using the source code permits students to experiment with and extend the existing programs and modify them more easily, as required for a number of end-of-section exercises. Pedagogical Features To facilitate the goal of making C++ accessible as a first-level course, the following pedagogical features have been incorporated into this book. End-of-Section Exercises Almost every section in the book contains numerous and diverse skill-building and programming exercises. Each exercise is identified as to type (practice, desk check, and so forth) or application (such as electrical engineering, heat transfer, environmental, and so on). Additionally, solutions to all exercises are provided in the Instructor Downloads section on www.cengage.com/coursetechnology. End-of-Chapter Programming Projects Each chapter includes several programming projects that combine all elements of C++ covered in previous sections and chapters. Projects are identified as to type (practice, desk check, and so forth) or application (electrical engineering, heat transfer, environmental, and so on). Common Programming Errors and Chapter Summary Each chapter ends with a sec- tion on common programming errors and a summary of the main topics covered in the chapter. Enrichment Sections Given the many different emphases that can be used in teaching C++, several chapters include an enrichment section called “A Closer Look.” These sections allow you to provide varying emphases with different students in C++ classes. Point of Information Boxes These boxes present additional clarification of commonly used or difficult concepts, such as abstraction, lvalues and rvalues, values versus identities, flags, and stream formatting. In addition, many Point of Information boxes explain alternative and advanced programming techniques, useful technical points, programming tips, and programming tricks used by professional programmers. Pseudocode Descriptions Pseudocode is used throughout the book. Flowchart symbols are introduced but are used only in illustrating flow-of-control constructs. Engineering and Scientific Disciplines Many chapters have a box at the end with information on several engineering and scientific fields, such as electrical, chemical, mechani- cal, and aeronautical engineering. 16 Preface
  • 19. Appendixes This book includes four appendixes on operator precedence, ASCII character codes, floating-point number storage, and command-line arguments. Additionally, Course Technology provides tutorials for using various C++ compilers at www.cengage.com/coursetechnology. Supplemental Materials The following supplemental materials are available when this book is used in a classroom setting: Electronic Instructor’s Resources. The Instructor’s Resources that accompany this book include the following: • Additional instructional material to assist in class preparation, including suggestions for lecture topics • Solutions to all the end-of-chapter materials, including the programming projects ExamView威. This book is accompanied by ExamView, a powerful testing software package that allows instructors to create and administer printed, computer (LAN-based), and Internet exams. ExamView includes hundreds of questions that correspond to the topics covered in this book, enabling students to generate detailed study guides that include page references for further review. These computer-based and Internet testing components allow students to take exams at their computers and save instructors time because each exam is graded automatically. The Test Bank is also available in WebCT and Blackboard formats. PowerPoint Presentations. This book comes with Microsoft PowerPoint slides for each chapter. They are included as a teaching aid for classroom presentations, to make available to students on the network for chapter review, or to be printed for classroom distribution. Instructors can add their own slides for additional topics they introduce to the class. Source Code. The source code for this book is available at www.cengage.com/coursetechnology and is also available on the Teaching Tools CD. Solution Files. The solution files for all programming exercises and projects are available at www.cengage.com/coursetechnology and on the Teaching Tools CD. 17 Preface
  • 20. To Rochelle, Jeremy, David, and Matthew Bronson Acknowledgments The writing of this third edition is a direct result of the success (and limitations) of the previous two editions. In this regard, my most heartfelt acknowledgment and appreciation is to the instructors and students who found the previous editions to be of service in their quests to teach and learn C++. Next, I would like to thank Alyssa Pratt, my Senior Product Manager at Course Technology. In addition to her continuous faith and encouragement, her ideas and partner- ship were instrumental in creating this book. After the writing process was completed, the task of turning the final manuscript into a book depended on many people other than myself. For this, I especially want to thank my developmental editor, Lisa Lord, who provided an outstanding job. Her editing so dovetailed with both the spirit and idiosyncrasies of my own writing style that it was an absolute pleasure working with her. She stayed true to what I was attempting to achieve while patiently going through both the technical and grammatical content. A truly incredible feat! This editing was supplemented by the equally detailed work of my colleague, Professor Joan Zucker Hoffman, with structural engineering applications provided by Professors Andy Gregg and Al Branchi and moral support provided by Dr. John Becker of the Theology Department. Finally, I would like to thank the testers at Course Technology’s MQA Department as well as GEX Publishing Services, especially the interior designer, and Camille Kiolbasa, the copyeditor. The dedication of this team of people was extremely important to me and I am very grateful to them. The following reviewers provided extensive, extremely useful, and detailed information and corrections that made this edition better and more accurate. No matter how careful I was, each reviewer pointed out something that I missed or could be stated better. I am very thankful to them. Naturally, all errors rest squarely on my shoulders, but these reviewers made the load much easier: Hyder Ali, California State University, Northridge, and Robert Baird, Salt Lake Community College. In addition, I’d like to thank the following instructors who reviewed the proposal for this edition and offered valuable feedback: Randy Bower, Jacksonville University; Helen Darcey, Cleveland State Community College; Akira Kawaguchi, The City College of New York; Cynthia Lester, Tuskegee University; and Sherman Wong, Baruch University. As with the first edition, special acknowledgement goes to Dr. G.J. Borse of Lehigh University, who provided material that was adapted for this book. Specifically, his contribu- tion includes almost all of Chapter 14, which Dr. Borse graciously permitted me to adapt from his FORTRAN 77 text (copyright held by PWS Publishing). I would also like to acknowl- edge, with extreme gratitude, the wonderful academic environment for learning and teaching created at Fairleigh Dickinson University—starting with the President, Dr. Michael Adams, followed through in the academic departments by the university and campus provosts, Dr. Joseph Kiernan and Dr. Kenneth Greene, and finally to the direct encouragement and support provided by my dean, Dr. William Moore, and my chairperson, Dr. Paul Yoon. Without their support, this book could not have been written. Finally, I deeply appreciate the patience, understanding, and love provided by my friend, wife, and partner, Rochelle. Gary Bronson 2009 18 Preface
  • 21. Part One Fundamentals of C++ Programming 1 Preliminaries 2 Problem Solving Using C++ 3 Assignment, Formatting, and Interactive Input 4 Selection Structures 5 Repetition Statements 6 Modularity Using Functions 7 Arrays 8 I/O Streams and Data Files 9 Completing the Basics Although C++ is an object-oriented language, it was developed as an extension to C, a procedural-oriented language. As such, C++ is a hybrid language having both procedural and object features. Because of this hybrid nature, not only is it possible to write a complete C++ program using just procedural code, but also it’s impossible to write an object-oriented program in C++ that doesn’t include procedural elements. Therefore, a proper start to learning C++ requires familiarity with its procedural aspects.
  • 23. Chapter 1 Preliminaries 1.1 Preliminary One: Unit Analysis 1.2 Preliminary Two: Exponential and Scientific Notations 1.3 Preliminary Three: Software Development 1.4 Preliminary Four: Algorithms 1.5 A Closer Look: Software, Hardware, and Computer Storage 1.6 Common Programming Errors 1.7 Chapter Summary Programming scientific and engineering applications requires a number of basic skills, both in understanding the underlying applications and in understanding the fundamentals of the programming process itself. On the applications side, a knowledge of numerical measurements and their corresponding units, as well as a familiarity with performing calculations, are assumed. Using consistent sets of units and knowing how to convert between units is a basic prerequisite of these applications. Additionally, the programming process assumes the programmer starts with a preliminary set of skills. As you develop your programming abilities in C++, a clear understanding of how programs are developed, in general, is important. This understanding includes what constitutes a “good” program and what an algorithm is. This chapter covers these preliminary requirements and can be used as an introduction or a review.
  • 24. 1.1 Preliminary One: Unit Analysis In all fields of study, using consistent and correct units when making computations is crucial. As a simple example, consider calculating the area of a rectangle by using this formula: Area = length × width [Eq. 1-1] When using this formula, the units for length and width must be the same. Therefore, if the length is given as 2 feet and the width as 3 inches, at least one of these units must be converted to ensure that both length and width are in the same units before the area is calculated. Converting the length to inches, the rectangle’s area is computed as follows: Area ft in ft in in =       × = 2 12 1 3 36 2 [Eq. 1-1a] Similarly, if you choose to convert the width from 3 inches to its equivalent feet, the calculation becomes the following: Area ft in ft in ft = ×       = 2 3 1 12 0 25 2 . [Eq. 1-1b] In the same manner, if one side of the rectangle is given in centimeters and the other in meters, a conversion is necessary to compute the area. Notice that in Equations 1-1a and 1-1b, units for both length and width as well as units for the conversion factor ([12 in/1 ft] in Eq. 1-1a and [1 ft/12 in] in Eq. 1-1b) are included in the formula. The reason is that the terms for units can be multiplied and divided to provide the final unit result. In many cases, this technique is a powerful one for selecting a correct conversion factor and ensuring that a computation is being calculated correctly. To see why, continue with the area example. Use Eq. 1-1a, but include only the unit terms, which yields the following: Area ft in ft in =       × [Eq. 1-1c] Now a unit of ft divided by a unit of ft is 1. That is, you can cancel the ft units in Eq. 1-1c as follows, which yields the final units as in multiplied by in, or in2 , which is a correct unit for the area: Area ft in ft in in = / / /       × = 2 Including only the units and conversion factors in an equation, and canceling out corresponding units in the numerator and denominator, is referred to as performing a unit analysis. As an example of a unit analysis for selecting a correct form of a conversion factor, assume you need to convert miles (symbol mi) to kilometers (symbol km), and you have the information that 1 kilometer = 0.6214 miles. As a conversion factor, this equality can be written as either of the following fractions: 1 0 6214 0 6214 1 or km mi mi km . . Deciding which conversion factor to use in converting miles to kilometers is easy when you consider units. To see why, try both factors with miles, canceling the units that occur 4 Preliminaries
  • 25. in both the numerator and denominator and concerning yourself only with the final resulting units: mi km mi km ×       = 1 0 6214 . and mi mi km mi km ×       = 0 6214 1 2 . . Because the first factor (1 km/0.6214 mi) provides the correct final units of kilometers, it’s the form of the conversion factor that must be applied to convert miles to kilometers. For a slightly more complicated example of performing a unit analysis for selecting correct conversion factors, consider converting days to seconds. You can determine the correct form of each conversion factor easily by including the units with each conversion factor, as you change days to hours, then hours to minutes, and finally minutes to seconds, performing each conversion one at a time and canceling units as you proceed with each conversion, as follows: 24 hr day × days 1st conversion: days to hours (cross out the days) The next conversion changes the units of hours to minutes, using the conversion factor 60 min/hr, as follows: 60 min hr 24 hr day × 1st conversion: days to hours (cross out the days) 2nd conversion: hours to minutes (cross out the hours) × days 5 Chapter 1 Preliminary One: Unit Analysis
  • 26. The final conversion is used to convert minutes to seconds: 60 min hr 24 hr day × 1st conversion: days to hours (cross out the days) 2nd conversion: hours to minutes (cross out the hours) 60 sec min × 3rd conversion: minutes to seconds (cross out the minutes) = sec × days In a single line, the complete conversion appears as follows: 60 min hr 24 hr day × 60 sec min × = sec × days Before showing how a unit analysis can help ensure that a complete computation is being calculated correctly, it’s useful to first summarize the systems of units in common use. Engineering and Scientific Units Two unit systems are commonly used in engineering and scientific work: the English Engineering system and the International System (SI). Both are used in this book. Table 1.1 lists the units used in these two systems. Table 1.1 Commonly Used Physical Quantities Quantity Symbol International System (SI) Units English Engineering Units Conversion Equalities Time t seconds (s) seconds (sec) Length l meters (m) feet (ft) 1 m = 3.2808 ft Area A sq. meters (m2 ) sq. feet (ft2 ) 1 m2 = 10.76 ft2 Volume V cubic meters (m3 ) cubic feet (ft3 ) 1 m3 = 35.31 ft3 Mass m kilograms (kg) pounds-mass (lbm) 1 kg = 2.19 lbm Force F Newton (1 N = 1 kg-m/s2 ) pounds-force (lbf = lbm-ft/sec2 ) 1 lbf = 4.448 N Weight W Newton (N) pounds-force (lbf) 1 lbf = 4.448 N Density ␳ kilograms/cubic meters (kg/m3 ) pounds-mass/cubic ft (lbm/ft3 ) 1 lbf/ft3 = 16.02 kg/m3 Velocity v meters/sec (m/s) feet/sec (ft/sec) 1 m/s = 3.2808 ft/sec Acceleration a meters/sec2 (m/s2 ) feet/sec2 (ft/sec2 ) 1 m/s2 = 3.2808 ft/sec2 6 Preliminaries
  • 27. Table 1.1 Commonly Used Physical Quantities (continued) Quantity Symbol International System (SI) Units English Engineering Units Conversion Equalities Pressure P Pascal (Pa) (1 Pa = 1 N/m2 ) lbf/ft2 1 lbf/ft2 = 47.88 Pa Heat transfer Q Joules (J) (1 J = 1 N.m) British Thermal Unit (BTU) 1 BTU = 1055 J Heat flux Q Joules/sec (J/s) (1 J/s = 1 Watt) BTU/sec 1 BTU/sec = 1055 J/s Work W Joules (J) ft-lbf 1 ft-lbf = 1.356 J Power W Watts (W) (1 W = 1 J/s) ft-lbf/sec 1 ft-lbf/sec = 1.356 W Temperature T degrees Celsius (C) and degrees Kelvin (K) degrees Fahrenheit (F) and degrees Rankin (R) The following conversion formulas show the relationships between the various tempera- ture scales: °F = 1.8°C + 32 = 9/5°C + 32 °C = (°F - 32)/1.8 = 5/9 (°F - 32) °K = °C + 273.15 °R = °F + 459.67 °R = 1.8°K °C = (°R - 491.67) / 1.8 = 5/9 (°R - 491.67) Using these conversion formulas provides the equivalent boiling and freezing points of water for each of the temperature scales listed in the following chart: °C °F °K °R Freezing point of water 0 32 273.15 491.67 Boiling point of water 100 212 373.15 671.67 As an example, using the conversion equalities in Table 1.1 (last column), consider calculating Newton’s Second Law for a mass of 5 kilograms and an acceleration of 32.2 ft/sec2 . Newton’s Second Law states that Force = Mass × Acceleration Assuming SI units are used, the calculation becomes Force kg ft m ft = × /       = 5 32 2 1 3 2808 49 07 2 . sec . . k kg m N sec . 2 49 07 = 7 Chapter 1 Preliminary One: Unit Analysis
  • 28. Notice from the information in Table 1.1 that 1 m = 3.2808 ft is used to create this conversion factor 1 3 2808 m ft .       rather than this conversion factor 3 2808 1 . ft m       because the first form achieves the desired cancelation of units. If you mistakenly use the second conversion factor, you would end up with the following final units, which immediately alert you that an incorrect result would occur: Force kg ft ft m kg ft = ×       = 5 32 2 3 2808 1 2 2 . . sec se ec2 m Finally, you could also achieve the correct conversion by using the following set of conversions: 2.54 cm in 32.2 ft sec × × Force = 5 kg 1 m 100 cm × = 49.073 kg m/s2 12 in ft × 2 1st conversion: feet to inches (cross out the ft) 2nd conversion: inches to centimeters (cross out the in) 3rd conversion: centimeters to meters (cross out the cm) Frequently, when you don’t know the final conversion factor, making intermediate conversions, as in this last calculation, can get you to the correct result easily. Notice that by applying one conversion factor at a time and canceling units as you go along, you avoid the common mistake of multiplying or dividing by the wrong conversion factor. If the final units, by themselves, do not yield the correct resulting units, then the resulting numerical answer must be incorrect. Correspondingly, if correct conversion factors and correct individual mea- surements are used, the result will be correct in both numerical and unit terms. Using the correct units and doing a unit analysis certainly can’t protect you against using incorrect numbers in a calculation or making calculation errors, but by itself, a unit analysis can ensure that you’re on the right path to computing a final numerical result correctly. 8 Preliminaries
  • 29. EXERCISES 1.1 1. (Practice) a. To convert inches (in) to feet (ft), the number of inches should be multi- plied by which of the following conversion factors? i. 12 in/1 ft ii. 1 ft/12 in b. To convert meters (m) to kilometers (km), the number of meters should be multiplied by which of the following conversion factors? i. 1000 m/1 km ii. 1 km/1000 m c. To convert minutes (min) to seconds (sec), the number of minutes should be multi- plied by which of the following conversion factors? i. 60 sec/1 min ii. 1 min/60 sec d. To convert seconds (sec) to minutes (min), the number of seconds should be multi- plied by which of the following conversion factors? i. 60 sec/1 min ii. 1 min/60 sec 2. (Practice) a. To convert feet (ft) to meters (m), the number of feet should be multiplied by which of the following conversion factors? i. 1 m/3.28 ft ii. 3.28 ft/1 m b. To convert sq.in to sq.ft, the number of sq.in should be multiplied by which of the following conversion factors? i. 144 sq.in/1 sq.ft ii. 1 sq.ft/144 sq.in c. To convert sq.yd to sq.ft, the number of sq.yd should be multiplied by which of the following conversion factors? i. 1 sq.yd/9 sq.ft ii. 9 sq.ft/1 sq.yd 3. (Practice) Determine the final units of the following expression: 9.8 m/s2 × 100 cm/1 m × 1 in/2.54 cm × 1 ft/12 in 4. (Practice) a. Determine the conversion factors that can be used to convert miles per gallon (mpg = mi/gal) to kilometers per liter (km/liter), given that 1 liter = 0.22 gallons and 1 kilometer = 0.6214 miles. b. Using the conversion factors you determined in Exercise 4a, convert 25 mpg into km/liter. 5. (Automotive) a. An automobile engine’s performance can be determined by monitoring its rotations per minute (rpm). Determine the conversion factors that can be used to con- vert rpm to frequency in Hertz (Hz), given that 1 rotation = 1 cycle, 1 minute = 60 sec- onds, and 1 Hz = 1 cycle/sec. b. Using the conversion factors you determined in Exercise 5a, convert 2000 rpm into Hertz. 6. (Chemistry) a. Determine the final units of the following expression, which provides the molecular weight of 1.5 moles of hydrogen peroxide: 1.5 moles × 34.0146 grams/mole 9 Chapter 1 Preliminary One: Unit Analysis
  • 30. b. Determine the final units of the following expression, which provides the molecular weight of 5.3 moles of water: 5.3 moles × 18 grams/mole 7. (Oceanography) The pressure, P, exerted on an underwater object can be determined by this formula: P g h = ρ ρ is the density of water, which is 100 kg/m3 . g is the acceleration caused by Earth’s gravity, which is 9.8 m/s2 . h is the depth of the object in the water in meters. a. Determine the units of P by calculating the units resulting from the right side of the formula. Check that your answer corresponds to the units for pressure listed in Table 1.1. b. Determine the pressure on a submarine operating at a depth of 500 meters. 8. (Thermodynamics) The work, W, performed by a single piston in an engine can be determined by this formula: W F d = F is the force provided by the piston in Newtons. d is the distance the piston moves in meters. a. Determine the units of W by calculating the units resulting from the right side of the formula. Check that your answer corresponds to the units for work listed in Table 1.1. b. Determine the work performed by a piston that provides a force of 1000 N over a dis- tance of 15 centimeters. 1.2 Preliminary Two: Exponential and Scientific Notations Many engineering and scientific applications require dealing with extremely large and extremely small numbers. For example, Avogadro’s number, used in chemistry, has the value 602,214,179,000,000,000,000,000; the universal gravitational constant used in aerospace and rocketry applications has the value 0.0000000000667428. To make entering these numbers in a computer program easier, they can be written in a more compact form known as exponential notation. Similarly, in performing hand calculations for verification purposes, an equivalent representation known as scientific notation is typically used. The following examples illustrate how numbers with decimals can be expressed in both exponential and scientific notation: Decimal Notation Exponential Notation Scientific Notation 1625. 1.625e3 1.625 × 103 63421. 6.3421e4 6.3421 × 104 .00731 7.31e-3 7.31 × 10-3 .000625 6.25e-4 6.25 × 10-4 10 Preliminaries
  • 31. In exponential notation, the letter e stands for exponent. The number following the e represents a power of 10 and indicates the number of places the decimal point should be moved to obtain the standard decimal value. The decimal point is moved to the right if the number after e is positive, or it’s moved to the left if the number after e is negative. For example, the e3 in 1.625e3 means move the decimal place three places to the right, so the number becomes 1625. The e-3 in 7.31e-3 means move the decimal point three places to the left, so 7.31e-3 becomes .00731. Using these representations, Avogadro’s number is written as 6.02214179e23 and 6.02214179 × 1023 in exponential and scientific notation, and the universal gravitational constant is written as 6.67428e-11 in exponential notation and 6.67428 × 10-11 in scientific notation. As noted previously, exponential notation is used to enter very large or very small numbers in a C++ program and will be used in Section 2.6, where very large numbers are required for the given application. Using Scientific Notation An essential part of engineering and scientific programming is understanding what formulas are to be used and verifying calculations, typically by hand. For evaluating formulas that use very large or very small numbers, which isn’t uncommon in the applications you’ll be programming, scientific notation is convenient. The reason is that scientific notation permits using the following two basic exponential rules, as they apply to the powers of 10: Rule 1: 10n x 10m = 10n+m for any values, positive or negative, of n and m Examples: 102 × 105 = 107 (that is, 100 × 100,000 = 10,000,000) 10-2 × 105 = 103 (that is, .01 × 100,000 = 1,000) 102 × 10-5 = 10-3 (that is, 100 × .00001 = .001) 10-2 × 10-5 = 10-7 (that is, .01 × .00001 = .0000001) 10-23 × 1034 = 1011 Rule 2: 1 10 10 -n n = for any positive or negative value of n Examples: 1 10 10 2 2 - = (that is, 1 01 100 . = ) 1 10 10 2 2 = - (that is, 1 100 01 = . ) 1 10 10 3 3 - = (that is, 1 001 1000 . = ) 1 10 10 4 4 = - (that is, 1 10 000 0001 , . = ) Notice that in scientific notation (as in exponential notation), if the exponent is positive, it represents the actual number of zeros that follow the 1, but if the exponent is negative, is represents one less than the number of zeros after the decimal point and before the 1. After you understand the basic rules of using scientific notation, you can combine them easily, as shown in this computation: 10 10 10 10 10 10 10 10 2 5 4 7 4 7 4 3 × = = × = - 11 Chapter 1 Preliminary Two: Exponential and Scientific Notations
  • 32. If scientific notation were concerned only with powers of 10, as in the preceding example, its usefulness would be extremely limited. Fortunately, however, this notation can be used with any decimal number. For example, take a look at this computation: 236,000 .345 1,345,000 × × × 67 8 000007 . . This computation is calculated more easily by first converting each number to its equivalent scientific notation, and then combining exponents (using Rules 1 and 2) as follows: 2 36 10 3 45 10 1 345 10 6 78 10 7 0 10 5 1 6 1 . . . . . × × × × × × × × - - -6 = 2 36 3 45 1 345 10 6 78 7 0 10 10 5 . . . . . × × × × × = - 2 36 3 45 1 345 10 6 78 7 0 15 . . . . . × × × × Finally, the remaining numbers in the numerator can be multiplied and then divided by the numbers in the denominator to yield a final result of .2307 × 1015 = 2.307 × 1014 . Whenever a formula contains one or more extremely small or large numbers, use the technique of first, converting the number to scientific notation, and second, dealing with the exponents and remaining numbers individually. This technique can be of great help in the final computation. (Note that converting all the numbers isn’t necessary.) You’ll make use of this technique often in performing hand calculations to validate results during the testing phase of a program. Scientific Notational Symbols Certain scientific notations occur frequently enough in science and engineering applications that they have their own symbols. The most commonly used are listed in Table 1.2. Table 1.2 Scientific Notational Symbols Scientific Notation Symbol Name 10-12 p pico 10-9 n nano 10-6 µ micro 10-3 m milli 103 k kilo 106 M mega 109 G giga 1012 T tera For example, the storage capacities of computer disks and thumb drives are currently specified in megabytes (MB) and gigabytes (GB), which means they contain millions (106 ) and billions (109 ) of bytes, respectively. (See Section 1.5 for the definition of a byte.)Similarly, computer processing speeds are specified in the nanosecond (nsec) range, which means a billionth (10-9 ) of a second. 12 Preliminaries
  • 33. EXERCISES 1.2 1. (Practice) Convert the following numbers from exponential form into standard decimal form: a. 6.34e5 b. 1.95162e2 c. 8.395e1 d. 2.95e-3 e. 4.623e-4 2. (Practice) Convert the following numbers from scientific notation into standard decimal form: a. 2.67 × 103 b. 2.67 × 10-3 c. 1.872 × 109 d. 1.872 × 10-9 e. 2.67 × 103 f. 6.6256 × 10-34 (known as Planck’s constant) 3. (Practice) Write the following decimal numbers using scientific notation: a. 126 b. 656.23 c. 3426.95 d. 4893.2 e. .321 f. .0123 g. .006789 4. (Practice) Compute the following: a. 104 × 10-6 × 10-3 × 1012 b. 1 10 10 10 10 4 -6 -3 12 × × × c. 10 10 10 2 7 4 × × × × × 10 10 10 10 4 -6 -3 12 d. 10 10 10 3 7 4 × × × 10 10 - - -6 -5 5. (Practice) Compute the following: a. 2.8 × 104 × 1.6 × 10-6 × 3.2 × 10-3 b. 1 4.5 10 1.8 10 6.7 10 4 -6 -3 × × × × × c. 1 4 10 2 5 10 5 310 2 7 4 . . . 3.2 10 1. 4 × × × × × × 8 8 10 2.7 10 -6 -3 × × × d. 7 1 10 8 45 10 3 6710 3 7 4 . . . 9.89 10 - - × × × × × - -6 -5 6.28 10 × × 13 Chapter 1 Preliminary Two: Exponential and Scientific Notations
  • 34. 6. (Aeronautics) The initial acceleration, a, of a rocket fired from earth, with an initial thrust, T, is given by this formula: a T mg m = − a is the initial acceleration. T is the thrust in Newtons. m is the mass in kg. g is the acceleration caused by gravity in m/s2 . a. Determine the units of the initial acceleration by calculating the units resulting from the right side of the equation. (Hint: As listed in Table 1.1, a Newton is N = kg – m/s2 .) b. Determine the initial acceleration of a rocket having a mass of 5 × 104 kg and an ini- tial thrust of 6 × 105 Newtons. The value of g is 9.81 m/s2 . 7. (Heat Transfer) The energy radiated from the surface of the sun or a planet in the solar system can be calculated by using Stephan-Boltzmann’s Law: E = ␴ T4 E is the energy radiated. ␴ is Stephan-Boltzmann’s constant (5.6697 × 10-8 Watts/m2 K4 ). T is the surface temperature in degrees Kelvin (°K = °C + 273). a. Determine the units of E by calculating the units resulting from the right side of the formula. b. Determine the energy radiated from the sun’s surface, given that the sun’s average temperature is approximately 6,000°K. 1.3 Preliminary Three: Software Development A computer is a machine, and like other machines, such as an automobile or a lawnmower, it must be turned on and then driven, or controlled, to perform the task it was meant to do. In an automobile, for example, control is provided by the driver, who sits inside the car and directs it. In a computer, the driver is a set of instructions called a program. More formally, a computer program is a self-contained set of instructions used to operate a computer to produce a specific result. Another term for a program or set of programs is software, and both terms are used interchangeably throughout this book.1 At its most basic level, a program is a solution developed to solve a particular problem, written in a form that can be executed on a computer. Therefore, writing a program is almost the last step in a process that first determines the problem to be solved and the method to be used in the solution. Each field of study has its own name for the systematic method of designing solutions to solve problems. In science and engineering, the approach is referred to as the scientific method, and in quantitative analysis, the approach is called the systems approach. Professional software developers use the software development procedure for 1 More inclusively, the term “software” is also used to denote both the programs and the data on which programs operate. 14 Preliminaries
  • 35. understanding the problem to be solved and for creating an effective, appropriate software solution. This procedure, illustrated in Figure 1.1, consists of three overlapping phases: 1. Development and design 2. Documentation 3. Maintenance As a discipline, software engineering is concerned with creating readable, efficient, reliable, and maintainable programs and systems, and it uses the software development procedure to achieve this goal. Phase I: Development and Design Phase I begins with a statement of a problem or a specific request for a program, which is referred to as a program requirement. After a problem has been stated or a specific request for a program solution has been made, the development and design phase begins. This phase consists of four well-defined steps, as illustrated in Figure 1.2. Request for a program Time Program no longer used Maintenance Documentation Development and design Program life cycle stages Figure 1.1 The three phases of program development Design Coding Testing Development and design steps Analysis Time Figure 1.2 The development and design steps 15 Chapter 1 Preliminary Three: Software Development
  • 36. Step 1 Analyze the Problem The analysis of a problem can consist of up to two parts. The first part is a basic analysis that must be performed on all problems; it consists of extracting the complete input and output information supplied by the problems. For this analysis, you must 1. Determine and understand the output items the program must produce. 2. Determine the input items. Together, these two items are referred to as the problem’s input/output (I/O). Only after determining a problem’s I/O can you select specific steps for transforming inputs into outputs. At this point, doing a hand calculation to verify that the output(s) can indeed be obtained from the inputs is sometimes necessary and/or useful. Clearly, if you have a formula that relates inputs to the output, you can omit this step. If the required inputs are available and the desired outputs can be produced, the problem is said to be clearly defined and can be solved. For a variety of reasons, completing a basic analysis might not be possible. If so, an extended analysis might be necessary. An extended analysis simply means you must gather more information about the problem so that you thoroughly understand what’s being asked for and how to achieve the result. In this book, any additional information required to understand the problem is supplied along with the problem statement. Step 2 Develop a Solution In this step, you select the exact set of steps, called an “algorithm,” to be used to solve the problem. Typically, you find the solution by a series of refinements, starting with the initial solution you find in the analysis step, until you have an acceptable and complete solution. This solution must be checked, if it wasn’t done in the analysis step, to make sure it produces the required outputs correctly. The check is usually carried out by doing one or more hand calculations that haven’t been done already. For small programs, the selected solution might be extremely simple and consist of only one or more calculations. More typically, you need to refine the initial solution and organize it into smaller subsystems, with specifications for how the subsystems interface with each other. To achieve this goal, the solution’s description starts from the highest level (top) requirement and proceeds downward to the parts that must be constructed to meet this requirement. To make this explanation more meaningful, consider a computer program that must track the number of parts in inventory. The required output for this program is a description of all parts carried in inventory and the number of units of each item in stock; the given inputs are the initial inventory quantity of each part, the number of items sold, the number of items returned, and the number of items purchased. For these specifications, a designer could initially organize the program’s requirements into the three sections illustrated in Figure 1.3. This figure is referred to as both a top-level structure diagram and a first-level structure diagram because it represents the first overall structure of the program the designer has selected. After an initial structure is developed, it’s refined until the tasks in the boxes are completely defined. For example, the data entry and report modules shown in Figure 1.3 would be refined further. The data entry module certainly must include provisions for entering data. Because planning for contingencies and human error is the system designer’s responsibility, provisions must also be made for changing incorrect data after an entry is made and for deleting previous entries. Similar subdivisions for the report module can be made. 16 Preliminaries
  • 37. Figure 1.4 illustrates a second-level structure diagram for an inventory tracking system that includes these further refinements. The process of refining a solution continues until the smallest requirement is included. Notice that the design produces a treelike structure, in which the levels branch out as you move from the top of the structure to the bottom. When the design is finished, each task designated in a box is typically coded with separate sets of instructions that are executed as they’re called on by tasks higher up in the structure. Step 3 Code the Solution (Write the Program) This step consists of actually writing a C++ program that corresponds to the solution developed in Step 2. If the analysis and solution steps have been performed correctly, the coding step becomes rather mechanical in nature. In a well-designed program, the statements making up the program, however, conform to certain well-defined patterns or structures that have been defined in the solution step. These structures control how the program executes and consist of the following types: • Sequence • Selection Calculation section Data entry section Report section Inventory control program Figure 1.3 A first-level structure diagram Calculation section Data entry section Report section Inventory control program Printer reports Screen reports Delete data Change data Enter data Figure 1.4 A second-level structure diagram 17 Chapter 1 Preliminary Three: Software Development
  • 38. • Iteration • Invocation Sequence defines the order in which the program executes instructions. Specifying which instruction comes first, which comes second, and so on is essential if the program is to achieve a well-defined purpose. Selection provides the capability to make a choice between different operations, depending on the result of some condition. For example, the value of a number can be checked before a division is performed: If the number is not zero, it can be used as the denominator of a division operation; otherwise, the division isn’t performed and the user is issued a warning message. Iteration, also referred to as “looping” and “repetition,” makes it possible to repeat the same operation based on the value of a condition. For example, grades might be entered and added repeatedly until a negative grade is entered. In this case, the entry of a negative grade is the condition that signifies the end of the repetitive input and addition of grades. At that point, an average for all grades entered could be calculated. Invocation involves invoking, or summoning, a set of statements as it’s needed. For example, computing a person’s net pay involves the tasks of obtaining pay rates and hours worked, calculating the net pay, and providing a report or check for the required amount. Each task is typically coded as a separate unit that’s called into execution, or invoked, as it’s needed. Step 4 Test and Correct the Program The purpose of testing is to verify that a program works correctly and actually fulfills its requirements. In theory, testing would reveal all existing program errors. (In computer terminology, a program error is called a bug.2) In practice, finding all errors would require checking all possible combinations of statement execution. Because of the time and effort required, this goal is usually impossible, except for extremely simple programs. (Section 4.8 explains why this goal is generally considered impossible.) Because exhaustive testing isn’t feasible for most programs, different philosophies and methods of testing have evolved. At its most basic level, however, testing requires a conscious effort to make sure a program works correctly and produces meaningful results. This effort means giving careful thought to what the test is meant to achieve and to the data used in the test. If testing reveals an error (bug), the process of debugging, which includes locating, correcting, and verifying the correction, can be initiated. Realize that although testing might reveal the presence of an error, it doesn’t necessarily indicate the absence of one. Therefore, the fact that a test revealed one bug does not indicate that another one isn’t lurking somewhere else in the program. To catch and correct errors in a program, developing a set of test data for determining whether the program gives correct answers is important. In fact, often an accepted step in formal software development is to plan test procedures and create meaningful test data before writing the code. Doing this step first helps you be more objective about what the program must do because it circumvents the subconscious temptation after coding to avoid test data that would reveal a problem with your program. The procedures for testing a program should examine every possible situation in which the program will be used. The program should be tested with data in a reasonable range as well as at the limits and in areas where the program 2 The derivation of this term is rather interesting. When a program stopped running on the Mark I at Harvard University in September 1945, Grace Hopper traced the malfunction to a dead insect that had gotten into the electrical circuits. She recorded the incident in her logbook as “Relay #70. . . . (moth) in relay. First actual case of bug being found.” 18 Preliminaries
  • 39. should tell the user that the data is invalid. Developing good test procedures and data for sophisticated problems can be more difficult than writing the program code itself. Table 1.3 lists the comparative amount of effort that’s typically expended on each development and design step in large commercial programming projects. As this listing shows, coding is not the major effort in Phase I. Many new programmers have trouble because they spend the majority of their time writing the program and don’t spend enough time understanding the problem or designing an appropriate solution. To help you avoid making the same mistake, remember the programming proverb, “It is impossible to write a successful program for a problem or application that’s not fully understood.” An equally valuable proverb is, “The sooner you start coding a program, the longer it usually takes to complete.” Table 1.3 Effort Expended in Phase I Step Effort Analyze the problem 10% Develop a solution 20% Code the solution (write the program) 20% Test the program 50% Phase II: Documentation Because of inadequate documentation, so much work becomes useless or lost and many tasks must be repeated, so documenting your work is one of the most important steps in problem solving. Many critical documents are created during the analysis, design, coding, and testing steps. Completing the documentation phase requires collecting these documents, adding user-operating material, and presenting documentation in a form that’s most useful to you and your organization. Although not everybody classifies them in the same way, there are five main documents for every problem solution: • Program description • Algorithm development and changes • Well-commented program listing • Sample test runs • Users’ manual Putting yourself in the shoes of a person who might use your work—anyone from secretaries to programmers/analysts and management—should help you strive to make the content of important documentation clear. The documentation phase formally begins in the development and design phase and continues into the maintenance phase. Phase III: Maintenance This phase is concerned with the ongoing correction of problems, revisions to meet changing needs, and addition of new features. Maintenance is often the major effort, the primary source of revenue, and the longest lasting of the engineering phases. Development might take days or months, but maintenance could continue for years or decades. The better the documentation is, the more efficiently maintenance can be performed, and the happier customers and end users will be. 19 Chapter 1 Preliminary Three: Software Development
  • 40. Backup Although not part of the formal design process, making and keeping backup copies of the program at each step of the programming and debugging process are critical. Deleting or changing a program’s current working version beyond recognition is all too easy. With backup copies, you can recover the last stage of work with little effort. The final working version of a useful program should be backed up at least twice. In this regard, another useful programming proverb is, “Backup is unimportant if you don’t mind starting over again.” Many organizations keep at least one backup on site, where it can be retrieved easily, and another backup copy in a fireproof safe or at a remote location. EXERCISES 1.3 Note: In each of these exercises, a programming problem is given. Read the problem statement first, and then answer the questions pertaining to the problem. Do not attempt to write a program to solve the problems. Instead, simply answer the questions following the program specifications. N O T E 1. (Electrical Eng.) You’ve been asked to write a C++ program to calculate the total resistance of a series circuit. In this circuit, the total resistance is the sum of all individual resistance values. The circuit consists of a number of 56-ohm, 33-ohm, and 15-ohm resistors. a. For this programming problem, how many outputs are required? b. How many inputs does this problem have? c. Determine a formula for converting input items into output items. The number of 56-ohm resistors is m, the number of 33-ohm resistors is n, and the number of 15-ohm resistors is p. d. Test the formula written for Exercise 1c, using the following sample data: m = 17, n = 24, and p = 12. 2. (Physics) You’ve been asked to write a program to calculate the value of distance, in miles, given this relationship: distance = rate × elapsed time a. For this programming problem, how many outputs are required? b. How many inputs does this problem have? c. Determine a formula for converting input items into output items. d. Test the formula written for Exercise 2c, using the following sample data: rate is 55 miles per hour and elapsed time is 2.5 hours. e. How must the formula you determined in Exercise 2c be modified if the elapsed time is given in minutes instead of hours? 20 Preliminaries
  • 41. 3. (Electrical Eng.) You’ve been asked to write a program that outputs the following specifications: Voltage amplification: 35 Power output: 2.5 Watts Bandwidth: 15 KHz a. For this programming problem, how many lines of output are required? b. How many inputs does this problem have? c. Determine a formula for converting input items into output items. 4. (Physics) You’ve been asked to write a C++ program to determine how far a car has traveled after 10 seconds, assuming the car is initially traveling at 60 mph and the driver applies the brakes to decelerate at a uniform rate of 12 mi/sec2 . Use the following formula: distance = st - (1/2)dt2 s is the initial speed of the car. d is the deceleration. t is the elapsed time. a. For this programming problem, how many outputs are required? b. How many inputs does this problem have? c. Determine a formula for converting input items into output items. d. Test the formula written for Exercise 4c, using the data given in the problem. 5. (General Math) Consider the following programming problem: In 1627, Manhattan Island was sold to Dutch settlers for $24. If the proceeds of that sale had been deposited in a Dutch bank paying 5% interest, compounded annually, what would the principal bal- ance be at the end of 2002? The following display is required: “Balance as of December 31, 2002 is: xxxxxx”; xxxxxx is the amount calculated by your program. a. For this programming problem, how many outputs are required? b. How many inputs does this problem have? c. Determine a formula for converting input items into output items. d. Test the formula written for Exercise 5c, using the data given in the problem statement. 6. (Electrical Eng.) You’ve been asked to write a program that calculates and displays the output voltages of two electrical circuits and the sum of the two voltages. The output voltage for the first circuit is given by this formula: 150 0 38 V f . The output voltage for the second circuit is given by this formula: 230 56 0 98 2 2 V f + ( . ) V is the input voltage to the circuit. f is the frequency in Hertz. 21 Chapter 1 Preliminary Three: Software Development
  • 42. a. For this programming problem, how many outputs are required? b. How many inputs does this problem have? c. Determine a formula for converting input items into output items. d. Test the formula written for Exercise 6c, using the following sample data: The first circuit is operated with an input voltage of 1.2 volts at a frequency of 144 Hertz, and the second circuit is operated with an input voltage of 2.3 volts at 100 Hertz. 7. (Statistics) Consider the following programming problem: This is the formula for the standard normal deviate, z, used in statistical applications: z = (X - µ)/␴ X is a single value. µ refers to an average value. ␴ refers to a standard deviation. Using this formula, you need to write a program that calculates and displays the value of the standard normal deviate when X = 85.3, µ = 80, and ␴ = 4. a. For this programming problem, how many outputs are required? b. How many inputs does this problem have? c. Determine a formula for converting input items into output items. d. Test the formula written for Exercise 7c, using the data given in the problem. 8. (Electrical Eng.) Read the following problem statement: The electrical resistance, r, of a metal wire, in ohms, is given by this formula: r ml a = m is the resistivity of the metal. l is the length of the wire in feet. a is the cross-sectional area of the wire in circular mils. Using this information, you need to write a C++ program to calculate the resistance of a wire that’s 125 feet long, has a cross-sectional area of 500 circular mils, and is copper. The resistivity of copper, m, is 10.4. a. Determine the outputs required of the program. b. What inputs does the program require? c. What is the formula for obtaining the outputs from the inputs? 1.4 Preliminary Four: Algorithms Before a program is written, the programmer must clearly understand what data are to be used, the desired result, and the procedure used to produce this result. As mentioned previously, the procedure, or solution, selected is referred to as an algorithm. More precisely, an algorithm is defined as a step-by-step sequence of instructions that must terminate and that describe how the data is to be processed to produce the desired outputs. In essence, an algorithm answers the question “What method will you use to solve this problem?” 22 Preliminaries
  • 43. Only after you clearly understand the data you’ll be using and select an algorithm (the specific steps required to produce the desired result) can you code the program. Seen in this light, programming is the translation of a selected algorithm into a language the computer can use. To understand how an algorithm works, consider a simple problem: A program must calculate the sum of all whole numbers from 1 through 100. Figure 1.5 illustrates three methods you could use to find the required sum. Each method constitutes an algorithm. Clearly, most people wouldn’t bother to list the possible alternatives in a detailed step-by- step manner, as shown in Figure 1.5, and then select one of the algorithms to solve the problem. Most people, however, don’t think algorithmically; they tend to think heuristically. For example, Method 1 - Columns: Arrange the numbers from 1 to 100 in a column and add them 1 2 3 4 . . . 98 99 +100 5050 Method 2 - Groups: Arrange the numbers in groups that sum to 101 and multiply the number of groups by 101 1 + 100=101 2 + 99=101 3 + 98=101 4 + 97=101 49 + 52=101 50 + 51=101 . . 50 groups (50 x 101=5050) Method 3 - Formula: Use the formula n= number of terms to added (100) a= first number to be added (1) b= last number to be added (100) n(a + b) 2 sum = . . = 5050 100(1 + 100) 2 sum = where Figure 1.5 Summing the numbers 1 through 100 23 Chapter 1 Preliminary Four: Algorithms
  • 44. if you have to change a flat tire on your car, you don’t think of all the steps required—you simply change the tire or call someone else to do the job. This is an example of heuristic thinking. Unfortunately, computers don’t respond to heuristic commands. A general statement such as “add the numbers from 1 to 100” means nothing to a computer because it can respond only to algorithmic commands written in a language it understands, such as C++. To program a computer successfully, you must understand this difference between algorithmic and heuristic commands. A computer is an “algorithm-responding” machine; it’s not an “heuristic-responding” machine. You can’t tell a computer to change a tire or to add the numbers from 1 through 100. Instead, you must give the computer a detailed, step-by-step set of instructions that collectively form an algorithm. For example, the following set of instructions forms a detailed method, or algorithm, for determining the sum of the numbers from 1 through 100: Set n equal to 100 Set a = 1 Set b equal to 100 Calculate sum = n(a + b)/2 Print the sum These instructions are not a computer program. Unlike a program, which must be written in a language the computer can respond to, an algorithm can be written or described in various ways. When English-like phrases are used to describe the steps in an algorithm, as in this example, the description is called pseudocode. When mathematical equations are used, the description is called a formula. When diagrams with the symbols shown in Figure 1.6 are used, the description is referred to as a flowchart. Figure 1.7 illustrates using these symbols to depict an algorithm for determining the average of three numbers. 24 Preliminaries
  • 45. Terminal Input/output Process Flow lines Decision Loop Predefined process Connector Report Indicates the beginning or end of a program Indicates an input or output operation Indicates computation or data manipulation Used to connect the other flowchart symbols and indicate the logic flow Indicates a program branch point Indicates the initial, limit, and increment values of a loop Indicates a predefined process, as in calling a function Indicates an entry to, or exit from, another part of the flowchart or a connection point Indicates a written output report Symbol Name Description Figure 1.6 Flowchart symbols 25 Chapter 1 Preliminary Four: Algorithms
  • 46. Because flowcharts are cumbersome to revise and can support unstructured programming practices easily, they have fallen out of favor by professional programmers. Using pseudocode to express the logic of algorithms has gained increasing acceptance. Short English phrases are used to describe an algorithm with pseudocode. Here’s an example of acceptable pseudocode for describing the steps to compute the average of three numbers: Input the three numbers into the computer’s memory Calculate the average by adding the numbers and dividing the sum by three Display the average As stated previously, before you can write an algorithm by using computer-language statements, you must select an algorithm and understand the required steps. Writing an algorithm by using computer-language statements is called coding the algorithm, which is the third step in the program development procedure shown in Figure 1.8. Most of Part One of this book is devoted to showing you how to develop and code algorithms into C++. Start Input three values Calculate the average Display the average End Figure 1.7 Flowchart for calculating the average of three numbers Requirements Select an algorithm (step-by-step procedure) Translate the algorithm into C++ (coding) Figure 1.8 Coding an algorithm 26 Preliminaries
  • 47. EXERCISES 1.4 Note: There’s no one correct answer for each task. This exercise is designed is to give you practice in converting heuristic commands into equivalent algorithms and making the shift between the processes involved in these two types of thinking. N O T E 1. (Practice) Determine a step-by-step procedure (list the steps) to do the following tasks: a. Fix a flat tire. b. Make a telephone call. c. Log on to a computer. d. Roast a turkey. 2. (Practice) Are the procedures you developed for Exercise 1 algorithms? Discuss why or why not. 3. (Practice) Determine and write an algorithm (list the steps) to interchange the contents of two cups of liquid. Assume that a third cup is available to hold the contents of either cup temporarily. Each cup should be rinsed before any new liquid is poured into it. 4. (Electrical Eng.) Write a detailed set of instructions in English to calculate the resis- tance of the following resistors connected in series: n resistors, each having a resistance of 56 ohms; m resistors, each having a resistance of 33 ohms; and p resistors, each having a resistance of 15 ohms. Note that the total resistance of resistors connected in series is the sum of all individual resistances. 5. (Numerical) Write a set of detailed, step-by-step instructions in English to find the smallest number in a group of three integer numbers. 6. (Numerical) a. Write a set of detailed, step-by-step instructions in English to calculate the fewest number of dollar bills needed to pay a bill of amount TOTAL. For example, if TOTAL is $97, the bills would consist of one $50 bill, two $20 bills, one $5 bill, and two $1 bills. (For this exercise, assume that only $100, $50, $20, $10, $5, and $1 bills are available.) b. Repeat Exercise 6a, but assume the bill is to be paid only in $1 bills. 7. (Data Processing) a. Write an algorithm to locate the first occurrence of the name JEAN in a list of names arranged in random order. b. Discuss how you could improve your algorithm for Exercise 7a if the list of names were arranged in alphabetical order. 8. (Data Processing) Determine and write an algorithm to determine the total occurrences of the letter e in any sentence. 9. (Numerical) Determine and write an algorithm to sort four numbers into ascending (from lowest to highest) order. 27 Chapter 1 Preliminary Four: Algorithms
  • 48. 1.5 A Closer Look: Software, Hardware, and Computer Storage3 The process of writing a program, or software, is called programming, and the set of instructions used to construct a program is called a programming language. Programming languages come in a variety of forms and types. Machine Language At their most fundamental level, the only programs that can actually be used to operate a computer are machine-language programs. These programs, also referred to as executable programs (executables, for short), consist of a sequence of instructions composed of binary numbers, such as:4 11000000 000000000001 000000000010 11110000 000000000010 000000000011 Machine-language instructions consist of two parts: an instruction and an address. The instruction part, referred to as the opcode (short for operation code), is usually the leftmost set of bits and tells the computer the operation to be performed, such as add, subtract, multiply, and so on. The rightmost bits specify the memory addresses of the data to be used. For example, assume that the eight leftmost bits of the first instruction contain the opcode to add, and the next two groups of 12 bits are the addresses of the two operands to be added. This instruction would be a command to “add the data in memory location 1 to the data in memory location 2.” Similarly, assuming that the opcode 11110000 means multiply, the next instruction is a command to “multiply the data in memory location 2 by the data in location 3.” Assembly Languages Because each class of computers—such as IBM, Apple, and Hewlett-Packard—has its own particular machine language, writing machine-language programs is tedious and time consuming.5 One of the first advances in programming was substituting word-like symbols, such as ADD, SUB, and MUL, for binary opcodes and using decimal numbers and labels for memory addresses. Using these symbols and decimal values for memory addresses, the previous two machine-language instructions can now be written as follows: ADD 1, 2 MUL 2, 3 Programming languages using this type of symbolic notation are referred to as assembly languages. Because computers can execute only machine-language programs, the instructions in an assembly-language program must be translated into a machine-language program before they can be executed on a computer (see Figure 1.9). Translator programs that perform this function for assembly-language programs are known as assemblers. 3 This topic can be omitted on first reading without loss of subject continuity. 4 Converting binary to decimal numbers is explained at the end of this section. 5 In actuality, the machine-level language is defined for the processor around which the computer is constructed. 28 Preliminaries
  • 49. Low- and High-Level Languages Both machine-level and assembly languages are classified as low-level languages because they use instructions that are tied to one type of computer. Therefore, an assembly-language program is limited to being used only with the specific computer type for which it’s written. These programs do, however, permit using special features of a particular computer type and generally execute at the fastest level possible. In contrast, a high-level language uses instructions resembling written languages, such as English, and can be run on a variety of computer types. Visual Basic, C, C++, and Java are examples of high-level languages. Using C++, an instruction to add two numbers and multiply the sum by a third number can be written as follows: result = (first + second) * third; Programs written in a computer language (high- or low-level) are referred to as both source programs and source code. Like a low-level assembly program, after a program is written in a high-level language, it must be translated into the machine language of the computer on which it will run. This translation can be done in two ways. When each statement in a high-level source program is translated separately and executed immediately after translation, the programming language is called an interpreted language, and the program doing the translation is an interpreter. When all statements in a high-level source program are translated as a complete unit before any statement is executed, the programming language is called a compiled language. In this case, the program doing the translation is a compiler. Both compiled and interpreted versions of a language can exist, although one typically predominates. C++ is predominantly a compiled language. Figure 1.10 illustrates the relationship between a C++ source program and its compilation into a machine-language executable program. As shown, the source program is entered by using an editor program, which is a word-processing program that’s part of the development environment the compiler supplies. Remember, however, that you can begin entering code only after you have analyzed an application and planned the program’s design carefully. Translating the C++ source program into a machine-language program begins with the compiler. The output the compiler produces is called an object program, which is a machine-language version of the source code. Source code almost always makes use of existing preprogrammed code—code you have written previously or code the compiler provides, such as mathematical code for finding a square root. Additionally, a large C++ program might be stored in two or more separate program files. Any additional code must be combined with the object program before the program can be executed. It’s the task of the linker to perform this step. The result of the linking process is a machine-language (executable) program that contains all the code your program requires and is ready for execution. The last step in the process is to load the machine-language program into the computer’s main memory for actual execution. An assembly- language program Translation program (assembler) A machine- language program Figure 1.9 Assembly-language programs must be translated 29 Chapter 1 A Closer Look: Software, Hardware, and Computer Storage
  • 50. Procedural and Object Orientations In addition to being classified as high- or low-level, programming languages are classified by orientation—procedural or object oriented. In a procedural language, the instructions are used to create self-contained units, referred to as procedures. The purpose of a procedure is to accept data as input and transform the data in some manner to produce a specific result as an output. Until the 1990s, most high-level programming languages were procedural. Currently, object orientation has taken center stage. One moti- vation for object-oriented languages was the development of graphical screens and support for graphical user interfaces (GUIs), capable of displaying windows containing both graphical shapes and text. In a GUI environment, each window can be considered an object with associated characteristics, such as color, position, and size. In an object-oriented approach, a program must first define the objects it’s manipulating. This definition includes a description of the objects’ general characteristics, such as initial size, shape, and color. Addi- tionally, specific code must be supplied to manipulate each object, such as changing its size and position, and transferring data between objects. Object-oriented languages have also become more promi- nent because they support reusing existing code more easily, which removes the need to revalidate and retest new or modified code. C++, which is classified as an object-oriented language, contains features of both procedural and object-oriented languages. In this book, you design and develop both types of code, which is how most current C++ programs are written. Because object-oriented C++ code always contains some procedural code, and many simple C++ pro- grams are written entirely in procedural code, this type of code is presented in Part One of this book. Application and System Software Two logical categories of computer programs are application software and system software. Application software consists of programs writ- ten to perform particular tasks that users require. All the programs in this book are examples of application software. System software is the collection of programs that must be readily available to any computer system for it to operate. In the computer environments of the 1950s and 1960s, users had to load system software by hand to prepare the computer to do anything at all. This software was loaded by using rows of switches on a front panel, and the commands entered by hand were said to “boot” the computer, an expression derived from “pulling yourself up by your bootstraps.” Today, the so-called bootstrap loader is a permanent, automatically executed component of a computer’s system software. Collectively, the set of system programs used to operate and control a computer is called the operating system (OS). Tasks handled by modern OSs include memory management; allocation of CPU time; control of input and output units, such as keyboards, screens, and printers; and management of secondary storage devices. Many OSs handle large programs as well as multiple users concurrently by dividing programs into segments that are moved An executable program Other object files (library) Linker The C++ object program Compiler Editor Type in the C++ program The C++ source program Figure 1.10 Creating an executable C++ program 30 Preliminaries
  • 51. between the disk and memory as needed. With these OSs, referred to as multiuser systems, more than one user can run a program on the computer. Additionally, many OSs, including most windowed environments, enable each user to run multiple programs and are called multiprogrammed and multitasking systems. The Development of C++ The purpose of most application programs is to process data to produce specific results. In a procedural language, a program is constructed from sets of instructions, with each set referred to as a procedure, as noted previously. Each procedure moves the data one step closer to the final desired output along the path shown in Figure 1.11. The programming process in Figure 1.11 mirrors the input, processing, and output hardware units used to construct a computer (discussed later in “Computer Hardware”). This mirroring isn’t accidental because early programming languages were designed to match and to control corresponding hardware units. The first procedural language, FORTRAN (derived from FORmula TRANslation), was intro- duced in 1957 and remained popular until the early 1970s. FORTRAN has algebra-like instructions that concentrate on the processing phase shown in Figure 1.11. It was developed for scientific and engineering applications that required high-precision numerical outputs, accurate to many decimal places. For example, calculating a rocket’s trajectory or the bacterial concentration level in a polluted pond, as illustrated in Figure 1.12, requires evaluating a mathematical equation to a high degree of numerical accuracy and is typical of FORTRAN-based applications. The next important high-level application language was COBOL (COmmon Business- Oriented Language), which was introduced in the 1960s and remained a major procedural language throughout the 1980s. This language had features geared toward business applica- tions, which required simpler mathematical calculations than those for engineering applications. One of COBOL’s main benefits was providing extensive output formats that made it easy to create reports containing columns of neatly formatted monetary amounts, as Process the data Input data Output results Figure 1.11 Basic procedural operations Time Bacteria growth in a polluted pond Concentration level Figure 1.12 FORTRAN was developed for scientific and engineering applications 31 Chapter 1 A Closer Look: Software, Hardware, and Computer Storage
  • 52. illustrated in Figure 1.13. It forced programmers to construct well-defined, structured procedures that followed a more consistent pattern than was required in FORTRAN. Another language, BASIC (Beginners All-purpose Symbolic Instruction Code), was developed at Dartmouth College in the 1960s. BASIC was a scaled-down version of FORTRAN intended as an introductory language for college students. It was a fairly straightforward, easy-to-understand language that didn’t require detailed knowledge of a specific application. Its main drawback was that it didn’t require or enforce a consistent, structured approach to creating programs. To remedy this drawback and make understanding and reusing code easier, the Pascal language (named after the 17th-century mathematician Blaise Pascal) was developed in 1971. It gave students a firmer foundation in structured programming design than early versions of BASIC did. Structured programs are created by using a set of well-defined structures organized into separate programming sections. Each section performs a specific task that can be tested and modified without disturbing other program sections. The Pascal language was so rigidly structured, however, that escapes from the structured sections didn’t exist, even when escapes would be useful. This limitation was unacceptable for many real-world projects and is one of the reasons Pascal didn’t become widely accepted in scientific and engineering fields. Instead, the C language became the dominant engineering applications language of the 1980s. Ken Thompson, Dennis Ritchie, and Brian Kernighan of AT&T Bell Laboratories developed this structured, procedural language in the 1970s. C’s extensive capabilities allow writing programs in a high-level language yet still accessing a computer’s machine-level features directly. Finally, C++ was developed in the early 1980s, when Bjarne Stroustrup (also at AT&T) used his simulation language background to create an object-oriented programming language. A central feature of simulation languages is that they model real-life situations as objects. This object orientation, which was ideal for graphical screen objects such as rectangles, circles, and windows, was combined with existing C features to form the C++ language. Therefore, C++ retained the extensive structured and procedural capabilities of C but added its object orientation to become a true general-purpose programming language. C++ can be used for everything from simple, interactive programs to sophisticated, complex engineering and scientific programs, within the context of a truly object-oriented structure. Part No. Description Quantity Price 12225 #4 Nails, Common 25 boxes 1.09 12226 #6 Nails, Common 30 boxes 1.09 12227 #8 Nails, Common 65 boxes 1.29 12228 #10 Nails, Common 57 boxes 1.35 12229 #12 Nails, Common 42 boxes 1.09 12230 #16 Nails, Common 25 boxes 1.09 Figure 1.13 COBOL was developed for business applications 32 Preliminaries
  • 53. Computer Hardware All computers, from large supercomputers to desktop PCs, must be capable of at least the following: • Accepting input • Displaying output • Storing information in a logical, consistent format (traditionally binary) • Performing arithmetic and logic operations on input or stored data • Monitoring, controlling, and directing the computer’s overall operation and sequencing Figure 1.14 illustrates the computer components that support these capabilities and collectively form a computer’s hardware. The arithmetic and logic unit (ALU) performs all arithmetic and logic functions, such as addition and subtraction. The control unit directs and monitors the computer’s overall operation. It keeps track of the next instruction’s location in memory, issues the signals for reading data from and writing data to other units, and controls execution of all instructions. The memory unit stores information in a logical, consistent format. Typically, both instructions and data are stored in memory, usually in separate areas. The input and output (I/O) units provide the interface where peripheral devices, such as keyboards, monitors, printers, and card readers, are attached. Because memory in very large quantities is still expensive and volatile (meaning the information is lost when power is turned off), it’s not practical as a permanent storage area for programs and data. Secondary (or auxiliary) storage is used for this purpose. Media such as punched cards were used in the past, but secondary storage is now on magnetic tape, magnetic disks, USB/flash drives, and CDs/DVDs. In the first commercially available computers of the 1950s, hardware units were built by using relays and vacuum tubes. These computers were enormous pieces of equipment capable of thousands of calculations per second and cost millions of dollars. Arithmetic and logic unit (ALU) Output Input Memory Secondary storage Control Central processing unit (CPU) Figure 1.14 Basic hardware units of a computer 33 Chapter 1 A Closer Look: Software, Hardware, and Computer Storage
  • 54. The introduction of transistors in the 1960s reduced the size and cost of computer hardware. The transistor’s small size—about one-twentieth the size of vacuum tubes— allowed manufacturers to combine the ALU with the control unit into a single unit called the central processing unit (CPU). Combining the ALU and control unit made sense because most control signals that a program generates are directed to the ALU in response to arithmetic and logic instructions in the program. Combining the ALU with the control unit also simplified the interface between these two units and improved processing speed. Integrated circuits (ICs) were introduced in the mid-1960s, which resulted in another major reduction in the space required to produce a CPU. Initially, ICs were manufactured with up to 100 transistors on a single square-centimeter chip of silicon and were called small-scale integrated (SSI) circuits. Current versions of these chips, called very large-scale integrated (VLSI) chips, can contain more than a million transistors. With VLSI chip technology, the giant computers of the 1950s could be transformed into today’s desktop and notebook PCs. Each unit required to form a computer (CPU, memory, and I/O) is now manufactured on a single VLSI chip, and a single-chip CPU is referred to as a microprocessor. Figure 1.15 illustrates how these chips are connected internally in current desktop PCs. Concurrent with the remarkable reduction in hardware size has been a dramatic decrease in cost and increase in processing speeds. Computer hardware that cost more than a million dollars in 1950 can now be purchased for less than $100. If the same reductions occurred in the automobile industry, for example, a Rolls Royce could now be purchased for $10! Similarly, current computers’ processing speeds have increased by a factor of thousands over their 1950s predecessors, with computational speeds now being measured in millions of instructions per second (MIPS) and billions of instructions per second (BIPS). Computer Storage The physical components used in manufacturing a computer preclude using the same symbols people use for numbers and letters. For example, the number 126 isn’t stored with the symbols 1, 2, and 6, nor is the letter you recognize as an A stored with this symbol. In this section, you see why and learn how computers store numbers. In Chapter 2, you see how letters are stored. Microprocessor (CPU) Memory Input Output Figure 1.15 VLSI chip connections for a desktop PC 34 Preliminaries
  • 55. The smallest and most basic data item in a computer is called a bit. Physically, a bit is actually a switch that can be open or closed. The convention followed in this book is that the open position is represented as a 0, and the closed position is represented as a 1.6 A single bit that can represent the values 0 and 1 has limited usefulness. All computers, therefore, group a set number of bits together for storage and transmission. Grouping 8 bits to form a larger unit, called a byte, is an almost universal computer standard. A single byte consisting of 8 bits, with each bit being a 0 or 1, can represent any one of 256 distinct patterns. These patterns consist of 00000000 (all eight switches open) to 11111111 (all eight switches closed) and all possible combinations of 0s and 1s in between. Each pattern can be used to represent a letter of the alphabet, a character (such as a dollar sign or comma), a single digit, or a number containing more than one digit. The collection of patterns used to represent letters, single digits, and other characters is called a character code. (One character code, called ASCII, is discussed in Section 2.1.) The patterns used to store numbers are called number codes, one of which is explained in the next section. Twos Complement Numbers The most common number code for storing integer values in a computer is called the twos complement representation. Using this code, the integer equivalent of any bit pattern, such as 10001101, is easy to determine and can be found for positive or negative integers with no change in the conversion method. For convenience, assume byte-sized bit patterns consisting of 8 bits each, although the procedure carries over to larger bit patterns. The easiest way to determine the integer each bit pattern represents is to construct a simple device called a value box. Figure 1.16 shows a value box for a single byte. Mathematically, each value in this box represents an increasing power of two. Because twos complement numbers must be capable of representing both positive and negative integers, the leftmost position, in addition to having the largest absolute magnitude, has a negative sign. To convert any binary number, such as 10001101, simply insert the bit pattern into the value box and add the values having 1s under them. Therefore, as illustrated in Figure 1.17, the bit pattern 10001101 represents the integer number -115. The value box can also be used in reverse to convert a base 10 integer number into its equivalent binary bit pattern. Some conversions, in fact, can be made by inspection. For 6 This convention, unfortunately, is rather arbitrary, and you often encounter the reverse, in which the open and closed positions are represented as 1 and 0, respectively. -128|ƒ64ƒ|ƒ32ƒ|ƒ16ƒ|ƒƒ8ƒ|ƒƒ4ƒ|ƒƒ2ƒ|ƒƒ1 ----|----|----|----|----|----|----|--- ƒ |ƒƒƒƒ|ƒƒƒƒ|ƒƒƒƒ|ƒƒƒƒ|ƒƒƒƒ|ƒƒƒƒ| Figure 1.16 An 8-bit value box -128ƒ|ƒ64ƒ|ƒ32ƒ|ƒ16ƒ|ƒƒ8ƒ|ƒƒ4ƒ|ƒƒ2ƒ|ƒƒ1 ƒ----|----|----|----|----|----|----|--- ƒ1ƒ|ƒƒ0ƒ|ƒƒ0ƒ|ƒƒ0ƒ|ƒƒ1ƒ|ƒƒ1ƒ|ƒƒ0ƒ|ƒƒ1 -128ƒ+ƒƒ0ƒ+ƒƒ0ƒ+ƒƒ0ƒ+ƒƒ8ƒ+ƒƒ4ƒ+ƒƒ0ƒ+ƒƒ1ƒ=ƒ-115 Figure 1.17 Converting 10001101 to a base 10 number. 35 Chapter 1 A Closer Look: Software, Hardware, and Computer Storage
  • 56. example, the base 10 number -125 is obtained by adding 3 to -128. Therefore, the binary representation of -125 is 10000011, which equals -128 + 2 + 1. Similarly, the twos complement representation of the number 40 is 00101000, which is 32 + 8. Although the value box conversion method is deceptively simple, it’s related to the underlying mathematical basis of twos complement binary numbers. The original name of the twos complement code was the weighted-sign code, which correlates to the value box. As the name “weighted sign” implies, each bit position has a weight, or value, of two raised to a power and a sign. The signs of all bits except the leftmost bit are positive, and the sign of the leftmost bit is negative. In reviewing the value box, you can see that any twos complement binary number with a leading 1 represents a negative number, and any bit pattern with a leading 0 represents a positive number. Using the value box, it’s easy to determine the most positive and negative values capable of being stored. The most negative value that can be stored in a single byte is the decimal number -128, which has the bit pattern 10000000. Any other non-zero bit simply adds a positive amount to the number. Additionally, a positive number must have a 0 as its leftmost bit. From this, you can see that the largest positive 8-bit twos complement number is 01111111, or 127. Words and Addresses One or more bytes can be grouped into larger units, called words, to facilitate faster and more extensive data access. For example, retrieving a word consisting of 4 bytes from a computer’s memory results in more information than retrieving a word of a single byte. This type of retrieval is also faster than four separate 1-byte retrievals. Achieving this increase in speed and capacity, however, requires increasing the computer’s cost and complexity. Early personal computers, such as the Apple IIe and Commodore, stored and transmitted words consisting of single bytes. The first IBM PCs used word sizes of 2 bytes, and more current PCs store and process words of 4 to 16 bytes each. The number of bytes in a word determines the maximum and minimum values the word can represent. Table 1.4 lists these values for 1-, 2-, and 4-byte words (derived by using 8-, 16-, and 32-bit value boxes, respectively). Table 1.4 Word Size and Integer Values Word Size Maximum Integer Value Minimum Integer Value 1 byte 127 -128 2 bytes 32,767 -32,768 4 bytes 2,147,483,647 -2,147,483,648 In addition to representing integer values, computers must also store and transmit numbers containing decimal points, which are mathematically referred to as real numbers. The codes for real numbers, which are more complex than those for integers, are in Appendix C. 36 Preliminaries
  • 57. 1.6 Common Programming Errors The most common errors associated with the material in this chapter are as follows: 1. Forgetting to check that all units for numerical values used in a calculation are consistent. 2. Using an incorrect form of a conversion factor. 3. Rushing to write and run a program before fully understanding what’s required, including the algorithms used to produce the required result. A symptom of this haste to get a program entered into the computer is the lack of any documentation, even a program outline or a written program. Many problems can be caught by checking a written copy of the program or even checking a description of the algorithm written in pseudocode. 4. Not backing up a program. Almost all new programmers make this mistake until they lose a program that has taken considerable time to code. 5. Not understanding that computers respond only to explicitly defined algorithms. Telling a computer to add a group of numbers is quite different from telling a friend to add the numbers. The computer must be given precise instructions in a programming language to perform the addition. 1.7 Chapter Summary 1. For a calculation to produce a correct and useful numerical value, the units corresponding to the numerical value must also be correct. 2. To determine correct forms of a conversion factor, perform a unit analysis. This means multiplying, dividing, and canceling units in the same manner as numerical values are processed. 3. The programs used to operate a computer are also referred to as software. 4. A computer program is a self-contained unit of instructions and data used to operate a computer to produce a specific result. 5. As a discipline, software engineering is concerned with creating readable, efficient, reliable, and maintainable programs and systems. 6. The software development procedure consists of three phases: program development and design, documentation, and maintenance. 7. The program development and design phase consists of four well-defined steps: • Analyze the problem. • Develop a solution. • Code the solution (write the program). • Test and correct the solution. 8. An algorithm is a step-by-step procedure that must terminate; it describes how a computation or task is to be performed. 37 Chapter 1 Chapter Summary
  • 58. 9. The four control structures used in coding a program are sequence, selection, iteration, and invocation. Preprogramming Projects for Chapter 1 1. (General Math) The volume of a sphere can be determined by using this formula: V r = 4 3 3 π V is the volume of the sphere. π is the dimensionless number (no units) having the value 3.1416, accurate to four decimal places. r is the radius in centimeters (cm) of the sphere. a. Determine the units of V by calculating the units resulting from the right side of the formula. Check that your answer corresponds to the units for work listed in Table 1.1. b. Determine the volume of a sphere having a radius of 4 cm. c. If you were required to write a computer program to determine the volume of a sphere, what inputs, outputs, and algorithm would you use? 2. (Civil Eng.) The stress placed on the fixed end of a symmetrical steel I-beam, shown in Figure 1.18, can be determined by this formula: S Ld c I = S is the stress. L is weight, in lbs, of the load placed on the beam. I is the beam’s rectangular moment of inertia in units of in4 . d is the distance, in inches, the load is placed from the fixed end of the beam (technically referred to as the “moment arm”). c is one half the height, in inches, of a symmetrical beam. L h d Figure 1.18 Determining the stress on an I-beam 38 Preliminaries
  • 59. a. Determine the units of stress, S, by calculating the units resulting from the right side of the formula. b. For a steel beam having a rectangular moment of inertia of 21.4 in4 and a height of 6 inches, determine the stress for a load of 700 lbs placed 8 feet from the fixed end. c. If you were required to write a computer program to determine the stress placed on a symmetrical beam, what inputs, outputs, and algorithm would you use? 3. (Physics) Typically, most objects that radiate heat do so at many different wavelengths (see the Technical Note in Section 3.5 for a description of wavelength). The wavelength at which an object emits its maximum heat energy can be found by using Wein’s Law: ␭max = W/T ␭max is the maximum wavelength. T is the object’s temperature in °K. W is Wein’s constant (2897 microns/°K). a. Determine the units of ␭max by calculating the units resulting from the right side of the formula. b. Determine the maximum heat-radiating wavelength for the sun, assuming a tempera- ture of 6000°K. c. If you were required to write a computer program to determine the heat radiated from a planet, what inputs, outputs, and algorithm would you use? 4. (Physics) The energy, E, of a photon can be determined by using this formula: E h c = λ E is the energy of the photon. h is known as Planck’s constant and has the value 6.6256 × 10-34 Joules/sec. c is the speed of light, which is 299,792,458 m/s. ␭ is the wavelength of the light in meters. a. Determine the units of a photon’s energy, E, by calculating the units resulting from the right side of the formula. b. Determine the energy of violet light, which has a wavelength of 5.9 × 10-6 meters. c. If you were required to write a computer program to determine the energy of a photon of different light wavelengths (such as red, green, and so forth), what inputs, outputs, and algorithm would you use? 5. (Eng. Mechanics) The minimum radius, r, required of a cylindrical rod, such as that used on a bicycle pedal (see Figure 1.19), to provide enough support for the pressure exerted by the rider’s foot, yet not exceed the stress placed on the crank arm’s sprocket attachment, is determined by this formula: r d P S 3 = π r is the radius of the cylindrical rod in inches. 39 Chapter 1 Preprogramming Projects
  • 60. d is the length of the crank arm in inches. P is the weight placed on the pedal in lbs. S is the stress in lbs/in2 . a. Determine the value of r for a crank arm that’s 7 inches long, must accommodate a maximum weight of 300 lbs, and be able to sustain a stress of 10,000 lbs/in2 . b. If you were asked to write a computer program to determine the radius of the cylindrical rod for a bicycle’s crank arm, what inputs, outputs, and algorithm would your program require? 6. (Heat Transfer) The following formula is used to determine the heat transferred through a flat substance, such as a wall, with its two sides maintained at different temperatures: q k T T d =       - - 2 1 q is the heat transfer. k is the thermal conductivity of the substance in Watts/m°C. T2 is the higher temperature on one side of the substance in °C. T1 is the lower temperature on the other side of the wall in °C. d is the thickness of the substance in meters. a. Determine the units of q by calculating the units resulting from the right side of the formula. b. For a glass window with a thickness of 0.5 centimeters, a thermal conductivity of 0.77 Watts/m°C, and outside and inside temperatures of 36.6°C and 22.2°C, respectively, determine the value of q. c. If you were asked to write a computer program to determine the heat transfer through a substance, what inputs, outputs, and algorithm would your program require? d Figure 1.19 Determining the radius of a bicycle’s crank arm 40 Preliminaries
  • 61. Engineering and Scientific Disciplines Aeronautical/Aerospace Engineering Among the youngest of the engineering fields, aeronautical/aerospace engineering is concerned with all aspects of designing, producing, testing, and using vehicles or devices that fly in air (aeronautical) or space (aerospace), from hang gliders to space shuttles. Because the science and engineering principles involved are so broad, aeroengineers usually specialize in a subarea that might overlap with other engineering fields, such as mechanical, metallurgical/materials, chemical, civil, or electrical engineering. These subareas include the following: 앫 Aerodynamics: The study of flight characteristics of various structures or configurations. Typical considerations are the drag and lift associated with airplane design or the onset of turbulent flow. A knowledge of fluid dynamics is essential. Modeling and testing all forms of aircraft are part of this subarea. 앫 Structural design: Designing, producing, and testing aircraft and spacecraft to withstand the wide range of in-flight demands on these vehicles, such as underwater vessels, are in the structural engineer’s province. 앫 Propulsion systems: The design of internal combustion, jet, and liquid- and solid-fuel rocket engines and their coordination in the vehicle’s overall design. Rocket engines, especially, require innovative engineering to accommodate the extreme temperatures of storing, mixing, and burning fuels such as liquid oxygen. 앫 Instrumentation and guidance: The aerospace industry has been a leader in developing and using solid-state electronics in the form of microprocessors to monitor and adjust the operations of hundreds of aircraft and spacecraft functions. This field uses the expertise of both electrical engineers and aeroengineers. 앫 Navigation: Computing orbits within and outside the atmosphere and determin- ing the orientation of a vehicle with respect to points on Earth or in space. 41 Chapter 1 Preprogramming Projects
  • 63. Chapter 2 Problem Solving Using C++ 2.1 Introduction to C++ 2.2 Programming Style 2.3 Data Types 2.4 Arithmetic Operations 2.5 Variables and Declaration Statements 2.6 A Case Study: Radar Speed Traps 2.7 Common Programming Errors 2.8 Chapter Summary An integral part of a building’s design is its structure, and the same is true for a program. Constructing well-designed C++ programs depends on careful planning and execution, if the final design is to ensure that the completed program accomplishes its intended purpose. A central element of this planning is using modular program design, which is explained in Section 2.1. In this chapter, you also learn about different types of data and how to process them in the context of a complete C++ program. 2.1 Introduction to C++ A well-designed program is constructed by using a design philosophy similar to one for constructing a well-designed building. It doesn’t just happen; it depends on careful planning and execution, if the final design is to accomplish its intended purpose. As with buildings, an integral part of designing a program is its structure. Programs with a structure consisting of interrelated segments (called modules), arranged in a logical, easily understandable order to form an integrated and complete unit, are referred to as modular
  • 64. programs (see Figure 2.1). Modular programs are easier to develop, correct, and modify than programs constructed in some other manner. Each module is designed and developed to perform a specific task and is actually a small subprogram. A complete C++ program is constructed by combining as many modules as necessary to produce the desired result. The advantage of modular construction is that you can develop the program’s overall design before writing any modules. After finalizing requirements for each module, you can then program the modules and integrate them into the overall program as they’re completed. In C++, modules can be classes or functions. It helps to think of a function as a small machine that transforms the data it receives into a finished product. For example, Figure 2.2 illustrates a function that accepts two numbers as inputs and multiplies the two numbers to produce one output. The process of converting inputs to results is encapsulated and hidden in the function. In this regard, the function can be thought of as a single unit providing a special-purpose operation. Module 1 Module 2 Module 4 Module 3 Module 5 Module 6 Figure 2.1 A well-designed program is built by using modules Result (a x b) First number Second number Figure 2.2 A multiplying function 44 Problem Solving Using C++
  • 65. A similar analogy is suitable for a class, although it’s a more complicated unit because it contains both data and functions for manipulating the data. Unlike a function, used to encapsulate a set of operations, a class encapsulates both data and sets of operations. Each class contains all the elements required for input, output, and processing its objects and can be thought of as a small factory containing raw material (the data) and machines (the functions). In the first part of this book, however, you’re focusing on the more basic function module. Although you’ll also use capabilities provided by classes, it’s in Part Two that you learn how to construct and program your own classes. An important requirement for designing a good function is giving it a name that conveys some idea of what the function does. The names allowed for functions are also used to name other elements of the C++ language and are collectively referred to as identifiers. Identifiers can be made up of any combination of letters, digits, or underscores (_) selected according to the following rules: 1. The first character of the name must be a letter or an underscore. 2. Only letters, digits, or underscores can follow the first letter. Also, blank spaces aren’t allowed to separate words in a function name; either use the underscore to separate words, or capitalize the first letter of words after the first word. 3. A function name can’t be one of the keywords listed in Table 2.1. (A keyword is a word the language sets aside for a special purpose and can be used only in a specified manner.1) 4. The maximum number of characters in a function name is 1024.2 Table 2.1 Keywords in C++ auto delete goto public this break do if register template case double inline return typedef catch else int short union char enum long signed unsigned class extern new sizeof virtual const float overload static void continue for private struct volatile default friend protected switch while Examples of valid C++ identifiers are the following: degToRad intersect addNums slope bessel1 multTwo findMax density These are examples of invalid identifiers: 1AB3 Begins with a number, which violates rule 1. E*6 Contains a special character, which violates rule 2. while Consists of a keyword, which violates rule 3. 1 Keywords in C++ are also reserved words, which means they must be used only for their specified purpose. Attempting to use them for any other purpose generates an error message. 2 The ANSI standard requires that C++ compilers provide at least this number of characters. 45 Chapter 2 Introduction to C++
  • 66. In addition to conforming to C++’s identifier rules, a C++ function name must always be followed by parentheses. Also, a good function name should be a mnemonic (pronounced “knee-mon-ic”), which is a word designed as a memory aid. For example, the function name degToRad() is a mnemonic for a function that converts degrees to radians. The name helps identify what the function does. Function names that aren’t mnemonics should not be used because they convey no information about what the function does. Here are some examples of valid function names that aren’t mnemonics: easy() c3po() r2d2() theForce() mike() Function names can also consist of mixed uppercase and lowercase letters, as in theForce(). This convention is becoming increasingly common in C++, although it’s not necessary. Identifiers in all uppercase letters are usually reserved for symbolic constants, covered in Section 3.5. If you do mix uppercase and lowercase letters, be aware that C++ is a case-sensitive language, meaning the compiler distinguishes between uppercase and lowercase letters. Therefore, in C++, the names TOTAL, total, and TotaL are three different identifiers. The main() Function As mentioned, a distinct advantage of using functions—and, as you see in Part Two, classes— is that you can plan the program’s overall structure in advance. You can also test and verify each function’s operation separately to make sure it meets its objectives. For functions to be placed and executed in an orderly fashion, each C++ program must have one, and only one, function named main(). The main() function is referred to as a driver function because it tells other functions the sequence in which they execute (see Figure 2.3).3 Figure 2.4 shows the main() function’s structure. The first line of the function—in this case, int main()—is referred to as a function header. This line is always the first line of a function and contains three pieces of information: • What type of data, if any, is returned from the function • The name of the function • What type of data, if any, is sent to the function The keyword before the function name defines the type of value the function returns when it has finished operating. When placed before the function’s name, the keyword int (listed in Table 2.1) means the function returns an integer value. Similarly, when the parentheses following the function name are empty, no data is transmitted to the function when it runs. (Data transmitted to a function at runtime is referred to as arguments of the function.) The braces, { and }, determine the beginning and end of the function body and enclose the statements making up the function. The statements inside the braces determine what the function does, and each statement must end with a semicolon (;). You’ll be naming and writing many of your own C++ functions. In fact, the rest of Part One is primarily about the statements required to construct useful functions and how to combine functions and data into useful classes and programs. Each program, however, must have one and only one main() function. Until you learn how to pass data to a function and return data from 3 Functions executed from main() can, in turn, execute other functions. Each function, however, always returns to the function that initiated its execution. This is true even for main(), which returns control to the operating system that was in effect when main() was initiated. 46 Problem Solving Using C++
  • 67. a function (the topics of Chapter 6), the function header shown in Figure 2.4 serves for all the programs you need to write. For simple programs, the first two lines int main() { simply designate that “the program begins here,” and the last two lines return 0; } designate the end of the program. Fortunately, many useful functions and classes have already been written for you. Next, you see how to use an object created from one of these classes to create your first working C++ program. 2nd module 3rd module Last module main() You go first I’m done You go second I’m done You go third I’m done You go last I’m done . . . . . . 1st module Figure 2.3 The main() function directs all other functions int main( ) { program statements in here; return 0; } The function body Type of returned value The function name An empty argument list Figure 2.4 The structure of a main() function 47 Chapter 2 Introduction to C++
  • 68. The cout Object One of the most versatile and commonly used C++ resources is an object named cout (pronounced “see out” and derived from console output).4 It’s an output object that sends data it receives to the standard display device. For most systems, this display device is a computer screen. For example, if the data Hello there world! is sent to cout, this data is displayed on your screen. To send the data Hello there world! to the cout object, enclose the text in quotation marks ("text in here") and place the insertion symbol, <<, after the object’s name and before the message, as shown in this line: cout << "Hello there world!"; Now you see how to put all this together into a working C++ program, Program 2.1, that can be run on your computer. Program 2.1 #include <iostream> using namespace std; int main() { cout << "Hello there world!"; return 0; } The first line of the program is a preprocessor command that uses the reserved word include: #include <iostream> Preprocessor commands begin with a pound sign (#) and perform some action before the compiler translates the source program into machine code. Specifically, the #include preprocessor command causes the contents of the named file—in this case, iostream—to be inserted wherever the #include command appears in the program. The iostream file is part of the standard library that contains, among other code, two classes: istream and ostream. These two classes provide data declarations and methods for data input and output, respectively. The iostream file is called a header file because a reference to it is always placed at the top, or head, of a C++ program by using the #include command. You might be wondering what the iostream file has to do with this simple program. The answer is that the cout object is created from the ostream class. Therefore, the iostream header file must be included in all programs using cout. As shown in Program 2.1, preprocessor commands don’t end with a semicolon. 4 The cout object is formally created for the ostream class, which is described in detail in Chapter 8. 48 Problem Solving Using C++
  • 69. Following the preprocessor #include command is a statement containing the reserved word using. The following statement, for example, tells the compiler where to look to find header files in the absence of an explicit designation: using namespace std; You can think of a namespace as a section of source code the compiler accesses when it’s looking for prewritten classes or functions. Because the iostream header file is contained in a namespace named std (for the standard library), the compiler automatically uses iostream’s cout object from this namespace whenever cout is referenced. By using namespaces, you can create your own classes and functions with the same names the standard library provides and place them in differently named namespaces. You can then tell the program which class or function to use by specifying the namespace where you want the compiler to look for the class or function. In Chapter 9, you learn how to create your own namespaces. For now, you’ll use the classes and functions provided by the std namespace. The using statement is followed by the start of the program’s main() function, which begins with the function header described previously. The body of the function, enclosed in braces, consists of only two statements. The first statement in main() sends one message to the cout object: the string "Hello there world!". Because cout is an object of a prewritten class, you don’t have to create it; it’s available for use just by activating it correctly. Like all C++ objects, cout can perform only certain well-defined actions. For cout, the action is to assemble data for output display. When a string of characters is sent to cout, the object makes sure the string is displayed onscreen correctly, as shown in this output from Program 2.1: Hello there world! Point of Information What Is Syntax? A programming language’s syntax is the set of rules for formulating statements that are grammatically correct for the language. In practice, it means a C++ statement with correct syntax has the proper form specified for the compiler. If statements are in the proper form, the compiler accepts them and doesn’t generate an error message. Note, however, that a statement or program can be syntactically correct yet logi- cally incorrect. In other words, the statement or program is structured correctly but pro- duces an incorrect result. It’s similar to an English statement that’s grammatically correct but makes no sense, such as “The tree is a ragged cat.” 49 Chapter 2 Introduction to C++
  • 70. Strings in C++ are any combination of letters, numbers, and special characters enclosed in quotation marks ("string in here"). The quotation marks delimit (mark) the beginning and ending of the string and aren’t considered part of the string. Therefore, the string of characters making up the message sent to cout must be enclosed in quotation marks, as was done in Program 2.1. Now examine another program to understand cout’s versatility. Read Program 2.2 to determine what it does. Program 2.2 #include <iostream> using namespace std; int main() { cout << "Computers, computers everywhere"; cout << "n as far as I can C"; return 0; } When Program 2.2 is run, the following is displayed: Computers, computers everywhere as far as I can C You might be wondering why the n didn’t appear in the output. The characters and n, when used together, are called a newline escape sequence. They tell cout to send instructions to the display device to move to the beginning of a new line. Otherwise, the second cout statement would simply append its characters to the previous statement’s characters; it doesn’t start on a new line by itself. In C++, the backslash () character provides an “escape” from the normal interpretation of the character following it and alters its meaning—in this case, the n. If the backslash were omitted from the second cout statement in Program 2.2, the n would be printed as the letter “n” and the program would output the following: Computers, computers everywheren as far as I can C Newline escape sequences can be placed anywhere in the message sent to cout. See whether you can determine the display Program 2.3 produces. 50 Problem Solving Using C++
  • 71. Program 2.3 #include <iostream> using namespace std; int main() { cout << "Computers everywheren as far asnnI can see"; return 0; } This is the output for Program 2.3: Computers everywhere as far as I can see EXERCISES 2.1 1. (Practice) State whether the following are valid function names and if so, whether they’re mnemonic names that convey some idea of the function’s purpose. If they are invalid names, state why. power density m1234 newamp 1234 abcd total tangent absval computed b34a 34ab volts$ a2B3 while minVal sine $sine cosine speed netdistance sum return stack 2. (Practice) Assume the following functions have been written: getLength(), getWidth(), calcArea(), displayArea() a. From the functions’ names, what do you think each function might do? b. In what order do you think a main() function might execute these functions (based on their names)? 3. (Practice) Assume the following functions have been written: speed(), distance(), acceleration() From the functions’ names, what do you think each function might do? 51 Chapter 2 Introduction to C++
  • 72. 4. (Practice) Determine names for functions that do the following: a. Find the average of a set of numbers. b. Find the area of a rectangle. c. Find the minimum value in a set of numbers. d. Find the density of a steel door. e. Sort a set of numbers from lowest to highest. 5. (Program) a. Using cout, write a C++ program that displays your name on one line, your street address on a second line, and your city, state, and zip code on a third line. b. Run the program you have written for Exercise 5a. (Note: You must understand the procedures for entering and running a C++ program on the particular computer instal- lation you’re using.) 6. (Program) a. Write a C++ program to display the following output: The cosecant of an angle is equal to one over the sine of the angle. b. Compile and run the program you have written for Exercise 6a. 7. (Program) a. How many cout statements would you use to display the following output? Degrees Radians 0 0.0000 90 1.5708 180 3.1416 270 4.7124 360 6.2832 b. What’s the minimum number of cout statements that could be used to print the out- put in Exercise 7a? c. Write a complete C++ program to produce the output shown in Exercise 7a. d. Run the program you have written for Exercise 7c. 8. (Program) a. Assuming your compiler isn’t case sensitive, determine which of these pro- gram unit names are equivalent: AVERAG averag MODE BESSEL Mode Total besseL TeMp Densty TEMP denSTY MEAN total mean mode b. Redo Exercise 8a, assuming a case-sensitive compiler. Project Structuring Exercises Most projects, both programming and nonprogramming, can usually be structured into smaller subtasks or units of activity. These smaller subtasks can often be delegated to different people so that when all the tasks are finished and integrated, the project or program is completed. For Exercises 9 through 14, determine a set of subtasks that, performed together, complete the project. Be aware that each exercise has many possible solutions. The only requirement is that the set of subtasks, when performed together, complete the required task. 52 Problem Solving Using C++
  • 73. Note: The purpose of these exercises is to have you consider the different ways that complex tasks can be structured. Although there’s no one correct solution to these exercises, there are incorrect solutions and solutions that are better than others. An incorrect solution is one that doesn’t fully specify the task. One solution is better than another if it more clearly or easily identifies what must be done. N O T E 9. (Practice) You’re given the task of wiring and installing lights in your attic. Determine a set of subtasks to accomplish this task. (Hint: The first subtask is determining the place- ment of light fixtures.) 10. (Practice) You’re given the job of preparing a complete meal for five people next weekend. Determine a set of subtasks to accomplish this task. (Hint: One subtask, not necessarily the first, is buying the food.) 11. (Practice) You’re a sophomore in college and are planning to go to graduate school for a master’s degree in electrical engineering after you graduate. List a set of major objectives you must fulfill to meet this goal. (Hint: One subtask is “Determine the correct courses to take.”) 12. (Practice) You’re given the job of planting a vegetable garden. Determine a set of sub- tasks to accomplish this task. (Hint: One subtask is planning the garden’s layout.) 13. (Practice) You’re responsible for planning and arranging the family camping trip this summer. List a set of subtasks to accomplish this task. (Hint: One subtask is selecting the campsite.) 14. (Data Processing) a. A national medical testing laboratory wants a new computer system to analyze its test results. The system must be capable of processing each day’s results as well as retrieving and outputting a printed report of all results meeting certain criteria, such as all results for a particular doctor or for hospitals in a certain state. Determine three or four major program units into which this system could be separated. (Hint: One possible program unit is “Prepare Daily Results” to create each day’s reports.) b. Suppose someone enters incorrect data for a test result, and the error is discovered after the system has entered and stored the data. What program unit is needed to cor- rect this problem? Discuss why such a program unit might or might not be required by most systems. c. Assume a program unit exists that allows users to change data that has been entered and stored incorrectly. Discuss the need for including an “audit trail” that would allow reconstructing the changes later as well as when they were made and who made them. 2.2 Programming Style C++ programs start execution at the beginning of the main() function. Because a program can have only one starting point, every C++ program must contain one and only one main() function. As you have seen, all the statements making up the main() function are then included within the braces following the function name. Although the main() function must be present in every C++ program, C++ doesn’t require placing the word main, the parentheses, or the braces in any particular form. The form used in the previous section 53 Chapter 2 Programming Style
  • 74. int main() { program statements in here; return 0; } was chosen strictly for clarity and ease in reading the program but is not required. For example, the following general form of a main() function would also work: int main ( ) { first statement;second statement; third statement;fourth statement; return 0;} Notice that you can put more than one statement on a line or place a statement on more than one line. Except for strings, quotation marks, identifiers, and keywords, C++ ignores all white space. (White space refers to any combination of blank spaces, tabs, or new lines.) For example, changing the white space in Program 2.1 and making sure not to split the string Hello there world! across two lines results in the following valid program: #include <iostream> using namespace std; int main ( ){ cout << "Hello there world!"; return 0; } Although this version of main() does work, it’s an example of poor programming style because it’s difficult to read and understand. For readability, the main() function should always be written in this standard form: int main() { program statements in here; return 0; } In this standard form, the function name starts at the left margin (call this column 1) and is placed with the required parentheses on a line by itself. The opening brace of the function body follows in column 1 on the next line, directly under the first letter of the line containing the function’s name. Similarly, the closing function brace is placed by itself in column 1 (lined up with the opening brace) as the last line of the function. This structure highlights the function as a single unit. Within the function, all program statements are indented at least two spaces. Indentation is another sign of good programming practice, especially if the same indentation is used for similar groups of statements. Review Program 2.2 to see that the same indentation was used for both cout statements. 54 Problem Solving Using C++
  • 75. As you progress in your understanding and mastery of C++, you’ll develop your own indentation standards. Just keep in mind that the final form of your programs should be consistent and always aid others in reading and understanding your programs. Comments Comments are explanatory remarks made in a program. When used carefully, comments can be helpful in clarifying the overall program’s purpose, explaining what a group of statements is meant to accomplish, or explaining what one line is intended to do. C++ supports two types of comments: line and block. Both types can be placed anywhere in a program and have no effect on program execution. The compiler ignores all comments—they are there strictly for the convenience of anyone reading the program. A line comment begins with two slashes (//) and continues to the end of the line. For example, the following examples are line comments: // this is a comment // this program prints out a message // this program calculates a square root The symbols //, with no white space between them, designate the start of the line comment. The end of the line on which the comment is written designates the end of the comment. A line comment can be written on a line by itself or at the end of the line containing a program statement. Program 2.4 shows using line comments in a program. Program 2.4 // this program displays a message #include <iostream> using namespace std; int main() { cout << "Hello there world!"; // this produces the display return 0; } The first comment appears on a line by itself at the top of the program, and this location is a good one for a comment describing the program’s purpose. If more comments are required, they can be placed one per line, as with the comment after the cout statement. When a comment is too long to be contained on one line, it can be separated into two or more line comments, with each comment preceded by the // symbol. For example, the following comment generates a C++ error message because the second line doesn’t start with the // symbol: // this comment is invalid because it extends over two lines 55 Chapter 2 Programming Style
  • 76. This comment is correct, written as follows: // this comment is used to illustrate a // comment that extends across two lines Comments that span two or more lines are, however, more conveniently written as C-type block comments, which begin with the symbols /* and end with the symbols */, as in this example: /* This is a block comment that spans three lines */ In C++, a program’s structure is intended to make it readable and understandable, so extensive comments aren’t necessary. This guideline is reinforced by carefully selecting function names to convey their purpose, as discussed previously. However, if the program element’s purpose still isn’t clear from its structure, name, or context, include comments where clarification is needed. Obscure code with no comments is a sure sign of bad programming, especially when other people must maintain or read the program. Similarly, excessive comments are a sign of bad programming because not enough thought was given to making the code self- explanatory. Typically, any program you write should begin with comments including a short program description, your name, and the date the program was written or last modified. For space considerations and because all programs in this book were written by the author, these initial comments are used only for short program descriptions when they aren’t provided as part of the accompanying text. EXERCISES 2.2 1. (Debug) a. Will the following program work? #include <iostream> using namespace std; int main() {cout << "Hello there world!"; return 0;} b. Even if the program in Exercise 1a works, explain why it’s not a good program. 2. (Modify) Rewrite the following programs to conform to good programming practice and correct syntax: a. #include <iostream> int main( ){ cout << "The time has come" ; return 0;} b. #include <iostream> using namespace std; int main ( ){cout << "Newark is a cityn";cout << 56 Problem Solving Using C++
  • 77. "In New Jerseyn"; cout << "It is also a cityn" ; cout << "In Delawaren" ; return 0;} c. #include <iostream> using namespace std; int main() {cout << Reading a programn";cout << "is much easiern" ; cout << "if a standard form for main is usedn") ; cout <<"and each statement is writtenn";cout << "on a line by itselfn") ; return 0;} d. #include <iostream.h> using namespace std; int main ( ){ cout << "Every C++ program" ; cout <<"nmust have one and only one" ; cout << "main function" ; cout << "n the escape sequence of characters") ; cout << "nfor a newline can be placed anywhere" ; cout <<"n within the message passed to cout" ; return 0;} 3. (For Thought) a. When used in a message, the backslash character alters the meaning of the character immediately following it. If you want to print the backslash character, you have to tell cout to escape from the way it normally interprets the backslash. What char- acter do you think is used to alter the way a single backslash character is interpreted? b. Using your answer to Exercise 3a, write the escape sequence for printing a backslash. 4. (For Thought) a. A token of a computer language is any sequence of characters, with no intervening characters or white space, that taken as a unit has a unique meaning. Using this definition of a token, determine whether escape sequences, function names, and the keywords listed in Table 2.1 are tokens of the C++ language. b. Discuss whether adding white space to a message alters the message and whether messages can be considered tokens of C++. c. Using the definition of a token in Exercise 4a, determine whether the following state- ment is true: “Except for tokens of the language, C++ ignores all white space.” 57 Chapter 2 Programming Style
  • 78. 2.3 Data Types The objective of all programs is to process data, be it numerical, alphabetical, audio, or video. Central to this objective is classifying data into specific types. For example, calculating a rocket’s trajectory requires mathematical operations on numerical data, and alphabetizing a list of names requires comparison operations on character-based data. Additionally, some operations aren’t applicable to certain types of data. For example, it makes no sense to add names together. To prevent programmers from attempting to perform an inappropriate operation, C++ allows performing only certain operations on certain data types. The types of data permitted and the operations allowed for each type are referred to as a data type. Formally, a data type is defined as a set of values and a set of operations that can be applied to these values. For example, the set of all integer (whole) numbers constitutes a set of values, as does the set of all real numbers (numbers containing a decimal point). These two sets of numbers, however, don’t constitute a data type until a set of operations is included—in these examples, mathematical and comparison operations. The combination of a set of values plus operations becomes a true data type. C++ categorizes data types in two basic groupings: class data types and built-in data types. A class data type (referred to as a “class,” for short) is a programmer-created data type, which means the programmer defines the acceptable values and operations, using C++ code. This data type is discussed in Part Two. A built-in data type is provided as part of the C++ compiler and requires no external C++ code. Therefore, a built-in data type can be used without supplementary additions, such as the iostream header file for the cout object. Built-in data types, also referred to as primitive types, consist of the basic numerical types shown in Figure 2.5 and the operations listed in Table 2.2. As shown in this table, most operations for built-in data types are designated as symbols. For class data types, most operations are provided as functions. Table 2.2 Built-in Data Type Operations Built-in Data Type Operations Integer +, -, *, /, %, =, ==, !=, <=, >=, sizeof(), and bit operations (see Chapter 15) Floating point +, -, *, /, =, ==, !=, <=, >=, sizeof() To introduce C++’s built-in data types, literals are used. A literal is an acceptable value for a data type. The term “literal” in this context means the value identifies itself. (Another name for a literal is a literal value or constant.) For example, all numbers, such as 2, 3.6, and -8.2, are referred to as literal values because they literally display their values. Text, such as "Hello World!", is also a literal value because the text is displayed. You have been using literal values Numerical data types Floating-point types Integer types Figure 2.5 Built-in data types 58 Problem Solving Using C++
  • 79. throughout your life but have known them as numbers and words. In Section 2.5, you see some examples of non-literal values—those that don’t display themselves but are stored and accessed by using identifiers. Integer Data Types C++ provides nine built-in integer data types, as shown in Figure 2.6. The essential difference between these integer data types is the amount of storage used for each type, which affects the range of values each type is capable of representing. The three most important and common types used in most applications are int, char, and bool. The other types were provided to accommodate special situations (such as a small or large range of numbers) and have been retained for historical reasons. They enabled programmers to maximize memory usage by selecting the data type using the smallest amount of memory, consistent with an application’s requirements. When computer memories were small, compared with today’s computers, and expensive, the amount of memory used was a major concern. Although no longer a concern for most programs, these types still allow programmers to optimize memory usage when necessary, typically in special-purpose digital control systems used in home appliances and automobiles. The int Data Type The values supported by the int data type are whole numbers, mathematically known as integers. An integer value consists of digits only and can optionally be preceded by a plus (+) or minus (-) sign. Therefore, an integer value can be the number 0 or any positive or negative number without a decimal point, as shown in these examples of valid integers: 0 5 -10 +25 1000 253 -26351 +36 As these examples illustrate, integers can contain a sign. However, no commas, decimal points, or special symbols, such as the dollar sign, are allowed, as in these examples of invalid integers: $255.62 2,523 3. 6,243,892 1,492.89 +6.0 Compilers differ in their internal limits on the largest (most positive) and smallest (most negative) integer values that can be stored in each data type.5 The most common storage 5 The limits imposed by the compiler are found in the limits header file and defined as the hexadecimal constants int_max and int_min. bool char short int int long int unsigned char unsigned short int unsigned int unsigned long int Integer data types Figure 2.6 C++ integer data types 59 Chapter 2 Data Types
  • 80. allocation is 4 bytes for the int data type, which restricts the values used to represent integers from -2,147,483,648 to 2,147,483,647.6 The char Data Type The char data type is used to store single characters, including the letters of the alphabet (uppercase and lowercase), the digits 0 through 9, and special symbols, such as + $ . , - and !. A character value is any single letter, digit, or special symbol enclosed by single quotation marks, as shown in these examples: 'A' '$' 'b' '7' 'y' '!' 'M' 'q' Character values are typically stored in a computer by using ASCII or Unicode codes. The ASCII (American Standard Code for Information Interchange, pronounced “as-key”) code provides codes for the English-language character set plus codes for printer and display control, such as newline and printer paper eject codes. Each character code is contained in a single byte, which provides 256 distinct codes. Table 2.3 lists the ASCII byte codes for uppercase letters. Additionally, C++ provides for the newer Unicode code that uses 2 bytes per character and can represent 65,536 characters. This code is used for international applications because it includes character sets for other languages in addition to English. As the first 256 Unicode codes have the same numerical value as the 256 ASCII codes (the additional byte is coded with all 0s), you needn’t be concerned with which storage code to use with English-language characters. Table 2.3 The ASCII Uppercase Letter Codes Letter ASCII Code Letter ASCII Code A 01000001 N 01001111 B 01000010 O 01001110 C 01000011 P 01010000 D 01000100 Q 01010001 E 01000101 R 01010010 F 01000110 S 01010011 G 01000111 T 01010100 H 01001000 U 01010101 I 01001001 V 01010110 J 01001010 W 01010111 K 01001011 X 01011000 L 01001100 Y 01011001 M 01001101 Z 01011010 Using Table 2.3, you can determine how the characters 'B', 'A', 'R', 'T', 'E', and 'R', for example, are stored in a computer by using ASCII codes. This sequence of six characters requires 6 bytes of storage (1 byte for each letter) and is stored as illustrated in Figure 2.7. 6 The most negative number is always one higher than the most positive number. Effectively, the “lost” positive number is used for the number 0. (See the twos complement method of integer storage, described in Section 1.6.) 60 Problem Solving Using C++
  • 81. The Escape Character As you’ve seen in Section 2.1, the backslash () has a special meaning in C++ as the escape character. When a backslash is placed in front of a group of characters, it tells the compiler to escape from the way these characters are normally interpreted. The combination of a backslash and these characters is called an escape sequence. Table 2.4 lists C++’s most common escape sequences. Table 2.4 Escape Sequences Escape Sequence Character Represented Meaning ASCII Code n Newline Move to a new line 00001010 t Horizontal tab Move to the next horizontal tab setting 00001001 v Vertical tab Move to the next vertical tab setting 00001011 b Backspace Move back one space 00001000 r Carriage return Move the cursor to the start of the current line; used for overprinting 00001101 f Form feed Issue a form feed 00001100 a Alert Issue an alert (usually a bell sound) 00000111 Backslash Insert a backslash character (used to place an actual backslash character in a string) 01011100 ? Question mark Insert a question mark character 00111111 ' Single quotation Insert a single- quote character (used to place an inner single quote within a set of outer single quotes) 00100111 6 bytes of storage B A R T E R 01000010 01000001 01010010 01010100 01000101 01010010 Figure 2.7 The letters BARTER stored in a computer 61 Chapter 2 Data Types
  • 82. Table 2.4 Escape Sequences (continued) Escape Sequence Character Represented Meaning ASCII Code " Double quotation Insert a double- quote character (used to place an inner double quote within a set of outer double quotes) 00100010 nnn Octal number Consider the number nnn (n is a digit) an octal number Dependent on nnn xhhhh Hexadecimal number Consider the number hhhh (h is a digit) a hexadecimal number Dependent on hhhh 0 Null character Insert the null character, which is defined as having the value 0 00000000 Although each escape sequence in Table 2.4 is made up of two characters, the combination of these characters, with no intervening white space, causes the compiler to create the single ASCII code listed in the table. The bool Data Type In C++, the bool data type is used to represent Boolean (logical) data, so it’s restricted to one of two values: true or false. This data type is most useful when a program must examine a condition and take a prescribed course of action, based on whether the condition is true or false. For example, in a sales application, the condition being examined might be “is the total purchase for $100 or more.” Only when this condition is true is a discount applied. Because the bool data type uses an integer storage code, however, it has useful implications that most professional C++ programmers utilize. The practical uses of Boolean conditions are covered in Chapter 4, so the bool data type is discussed in more detail in that chapter. Determining Storage Size A unique feature of C++ is that you can see where and how values are stored. As an example, the C++ operator sizeof() provides the number of bytes used to store values for the data type named in the parentheses. (Review Section 1.6 if you’re unfamiliar with the concept of a byte.) This built-in operator doesn’t use an arithmetic symbol to perform its operation. Program 2.5 uses this operator to determine the amount of storage reserved for the int, char, and bool data types. 62 Problem Solving Using C++
  • 83. Program 2.5 #include <iostream> using namespace std; int main() { cout << "nData Type Bytes" << "n--------- -----" << "nint " << sizeof(int) << "nchar " << sizeof(char) << "nbool " << sizeof(bool) << 'n'; return 0; } In reviewing Program 2.5, notice that a single character value is inserted in the display by cout by enclosing it in single quotation marks, as in the escape sequence 'n' at the end of the cout statement. In the first five displayed lines, this character is included in each output string. Each time the compiler encounters the newline escape sequence, as a single character or as part of a string, it’s translated as a single character that forces the display to start at the beginning of a new line. Although quotation marks can be used for the final newline insertion, as "n", they designate a string. When only a single character is being transmitted, and to emphasize that single characters are designated by using single quotation marks, 'n' is used instead of "n". From a practical standpoint, however, both notations force a new line in the display. Point of Information The Character 'n' and the String "n" The compiler recognizes both 'n' and "n" as containing the newline character. The difference is in the data type used. Formally, 'n' is a character literal, and "n" is a string literal. From a practical standpoint, both cause the same thing to happen: A new line is forced in the output display. In encountering the character value 'n', however, the compiler translates it by using the ASCII code 00001010 (see Table 2.4). In encoun- tering the string value "n", the compiler translates it by using the correct character code but also adds an end-of-string character, which is '0'. Good programming practice requires ending the last output display with a newline escape sequence. This practice ensures that the first line of output from one program doesn’t end up on the last line displayed by the previously executed program. 63 Chapter 2 Data Types
  • 84. The output of Program 2.5 is compiler dependent, meaning each compiler reports the amount of storage it provides for the data type under consideration. When run on a computer using Microsoft’s current Visual C++ .NET compiler, for example, the following output is produced: Data Type Bytes --------- ----- int 4 char 1 bool 1 For this output, which is the typical storage almost all current C++ compilers provide, you can determine the range of values that can be stored in each data type. To do so, however, requires understanding the difference between a signed and an unsigned data type, discussed next. Signed and Unsigned Data Types A signed data type permits storing negative values in addition to 0 and positive values, so int is a signed data type. An unsigned data type provides for only non-negative values (that is, 0 and positive values). Some applications require only unsigned numerical values. For example, many date applications store dates in the numerical form yearmonthday (storing 12/25/2007 as 20071225, for example) and are concerned only with dates after 0 CE. For these applications, which never require a negative value, an unsigned data type can be used. All unsigned integer types, such as unsigned int, provide a range of positive values that, for all practical purposes, is double the range for their signed counterparts. This extra positive range is made available by using the negative range of its signed version for additional positive numbers. With an understanding of the difference between signed and unsigned data types, you can use Table 2.5 to determine the range of integer values supported by current C++ compilers. As you can see, a long int uses the same amount of storage (4 bytes) as an int. The only requirement of the ANSI C++ standard is that an int must provide at least as much storage as a short int, and a long int must provide at least as much storage as an int. On early desktop computers with a memory capacity limited to thousands of bytes, a short int typically used 1 byte of storage, an int 2 bytes, and a long int 4 bytes. This storage limited the range of int values from -32,768 to +32,767 and unsigned int values from 0 to 65,535, thus doubling the number of possible positive values, which was significant. With the current range of int values in the -2 to +2 billion range, doubling Point of Information Object-Oriented and Procedural Programs Except for the bool type, all of C++’s built-in data types are direct carryovers from the C procedural language. Not surprisingly, programs using only built-in data types can’t be object-oriented programs. Instead, as in Program 2.5, they become procedural pro- grams, those based primarily on procedures, such as main(). Only when built-in data types are bundled together to form a packet of data, which becomes an object, can an object-oriented program come into existence. 64 Problem Solving Using C++
  • 85. positive values is rarely a consideration. Additionally, a long int is unnecessary now because it is uses the same storage capacity as an int. Table 2.5 Integer Data Type Storage Name of Data Type Storage Size Range of Values char 1 256 characters bool 1 true (considered as any positive value) and false (which is a 0) short int 2 -32,768 to +32,767 unsigned short int 2 0 to 65,535 int 4 -2,147,483,648 to +2,147,483,647 unsigned int 4 0 to 4,294,967,295 long int 4 -2,147,483,648 to +2,147,483,647 unsigned long int 4 0 to 4,294,967,295 Floating-Point Types A floating-point number, more commonly known as a real number, can be the number 0 or any positive or negative number containing a decimal point, as shown in these examples: +10.625 5. -6.2 3251.92 0.0 0.33 -6.67 +2. Therefore, the numbers 5., 0.0, and +2. are classified as floating-point values, but the same numbers written without a decimal point (5, 0, +2) are integer values. As with integer values, special symbols such as the dollar sign and comma aren’t permitted in real numbers, as shown in these examples of invalid real numbers: 5,326.25 24 6,459 $10.29 7.007.645 C++ supports three floating-point data types: float, double, and long double. The difference between these data types is the amount of storage the compiler uses. Most compilers use twice the amount of storage for doubles as for floats, which allows a double to have approximately twice the precision of a float. For this reason, a float value is sometimes referred to as a single-precision number and a double value as a double-precision number. The actual storage allocation for each data type, however, depends on the compiler. The ANSI C++ standard requires only that a double have at least the same amount of precision as a float, and a long double have at least the same amount of storage as a double. Currently, most C++ compilers allocate 4 bytes for floats and 8 bytes for doubles and long doubles, which produces the range of numbers listed in Table 2.6. Table 2.6 Floating-Point Data Types Type Storage Absolute Range of Values (+ and -) float 4 bytes 1.40129846432481707x10-45 to 3.40282346638528860x1038 double and long double 8 bytes 4.94065645841246544x10-324 to 1.79769313486231570x10308 65 Chapter 2 Data Types
  • 86. In compilers using the same amount of storage for double and long double numbers, these two data types are identical. (The sizeof() operator in Program 2.5 can always be used to determine the amount of storage your compiler reserves for these data types.) A float literal is indicated by appending an f or F to the number, and a long double is created by appending an l or L to the number. In the absence of these suffixes, a floating-point number defaults to a double. For example, take a look at the following: 9.234 indicates a double literal 9.234F indicates a float literal 9.234L indicates a long double literal The only difference in these numbers is the amount of storage the computer can use for them. Appendix C describes the binary storage format used for floating-point numbers and its impact on number precision. EXERCISES 2.3 1. (Practice) Determine data types appropriate for the following data: a. The average of four grades b. The number of days in a month Point of Information What Is Precision? In numerical theory, the term precision typically refers to numerical accuracy. In this context, the statement “This computation is accurate, or precise, to the fifth decimal place” means the fifth digit after the decimal point has been rounded, and the number is accurate to within ±0.00005. In computer programming, “precision” can refer to the accuracy of a number or the amount of significant digits in the number; significant digits are defined as the number of clearly correct digits plus 1. For example, if the number 12.6874 has been rounded to the fourth decimal place, it’s correct to say that this number is precise to the fourth decimal place. In other words, all digits in the number are accurate except the fourth decimal digit, which has been rounded. Similarly, this same number has a precision of six digits, which means the first five digits are correct and the sixth digit has been rounded. Another way of saying this is that the number 12.6874 has six sig- nificant digits. The significant digits in a number need not have any relation to the number of displayed digits. For example, if the number 687.45678921 has five significant digits, it’s accurate only to the value 687.46; the last digit is assumed to be rounded. Similarly, dollar values in large financial applications are often rounded to the nearest hundred thousand dollars. In these applications, a displayed dollar value of $12,400,000, for example, isn’t accurate to the closest dollar. If this value is specified as having three significant digits, it’s accurate only to the hundred-thousand digit. 66 Problem Solving Using C++
  • 87. c. The length of the Golden Gate Bridge d. The numbers in a state lottery e. The distance from Brooklyn, N.Y. to Newark, N.J. f. The single-character prefix that specifies a component type 2. (Practice) Compile and execute Program 2.5. 3. (Modify) Modify Program 2.5 to determine the storage your compiler uses for all the C++ integer data types. 4. (Practice) Show how the name KINGSLEY is stored in a computer that uses the ASCII code by drawing a diagram similar to Figure 2.7, shown previously. 5. (Practice) Repeat Exercise 4 using the letters of your own last name. 6. (Modify) Modify Program 2.5 to determine how many bytes your compiler assigns to the float, double, and long double data types. 7. (For Thought) Because computers use different representations for storing integer, floating-point, double-precision, and character values, discuss how a program might alert the computer to the data types of various values it will be using. 8. (For Thought) Although you have concentrated on operations involving integer and floating-point numbers, C++ allows adding and subtracting characters and integers. (These operations are possible with characters because they’re integer data types and are stored by using integer codes.) Therefore, characters and integers can be mixed in arithmetic expressions. For example, if your computer uses ASCII code, the expression 'a' + 1 equals 'b' and 'z' - 1 equals 'y' is valid. Similarly, 'A' + 1 is 'B' and 'Z' - 1 is 'Y'. With this information as background, determine the character results of the fol- lowing expressions. (Assume all characters are stored by using ASCII codes.) a. 'm' - 5 b. 'm' + 5 c. 'G' + 6 d. 'G' - 6 e. 'b' - 'a' f. 'g' - 'a' + 1 g. 'G' - 'A' + 1 Note: To complete the following exercise, you need to understand basic computer storage concepts. Specifically, if you’re unfamiliar with the concepts of bytes and words, refer to Section 1.6 before doing the next exercise. N O T E 9. (Practice) Although the total number of bytes varies from computer to computer, memory sizes of 65,536 to more than several million bytes are common. In computer language, the letter K represents the number 1024, which is 2 raised to the 10th power, and M represents the number 1,048,576, which is 2 raised to the 20th power. Therefore, a memory size of 640 KB is really 640 times 1024 (655,360 bytes), and a memory size of 4 MB is really 4 times 67 Chapter 2 Data Types
  • 88. 1,048,576 (4,194,304 bytes). Using this information, calculate the actual number of bytes in the following: a. A memory containing 512 MB b. A memory consisting of 256 MB words, where each word consists of 2 bytes c. A memory consisting of 256 MB words, where each word consists of 4 bytes d. A thumb drive that specifies 2 MB e. A disk that specifies 250 MB f. A disk that specifies 8 GB (Hint: See Table 1.2.) 2.4 Arithmetic Operations The previous section presented the data values corresponding to C++’s built-in data types. This section explains the arithmetic operations that can be applied to these values. Integers and real numbers can be added, subtracted, multiplied, and divided. Although it’s usually better not to mix integers and real numbers when performing arithmetic operations, you can get predictable results when using different data types in the same arithmetic expression. Surprisingly, you can add and subtract character data and mix it with integer data to produce useful results. (For example, 'A' + 1 results in the character 'B'.) These operations are possible because characters are stored by using integer codes. The operators used for arithmetic operations are called arithmetic operators and are as follows: Operation Operator Addition + Subtraction - Multiplication * Division / Modulus division7 % These operators are also called binary operators, which means the operator requires two operands to produce a result. An operand can be a literal value or an identifier with an associated value. A simple binary arithmetic expression consists of a binary operator connecting two literal values in this form: literalValue operator literalValue Examples of simple binary arithmetic expressions are the following: 3 + 7 8 - 3 12.62 + 9.8 0.08 * 12.2 12.6 / 2 7 Don’t be concerned at this stage if you do not understand the term “modulus division.” You learn more about this operator later in “Integer Division.” 68 Problem Solving Using C++
  • 89. The spaces around arithmetic operators in these examples are inserted strictly for clarity and can be omitted without affecting the value of the expression. However, an expression in C++ must be entered in a straight-line form, as shown in these examples. For example, the C++expression equivalent to 12.6 divided by 2 must be entered as 12.6 / 2, not as the algebraic expression shown here: 12 6 2 . You can use cout to display the value of any arithmetic expression onscreen. To do this, the value must be sent to the object. For example, the following statement yields the display 21: cout << (6 + 15); Strictly speaking, the parentheses surrounding the expression 6 + 15 aren’t required to indicate that the value of the expression (that is, 21) is being displayed.8 In addition to displaying a numerical value, cout can display a string identifying the output, as was done in Section 2.1. For example, the following statement sends two pieces of data, a string and a value, to cout: cout << "The sum of 6 and 15 is " << (6 + 15); Each set of data sent to cout must be preceded by its own insertion operator, <<. In the preceding example, the first data sent for display is the string "The sum of 6 and 15 is ", and the second item sent is the value of the expression 6 + 15. This statement produces the following display: The sum of 6 and 15 is 21 The space between the word “is” and the number 21 is caused by the space in the string sent to cout. As far as cout is concerned, its input is a set of characters sent to be displayed in the order they’re received. Characters from the input are queued, one behind the other, and sent to the screen for display. Placing a space in the input makes the space part of the stream of characters that’s displayed. For example, the statement cout << "The sum of 12.2 and 15.754 is " << (12.2 + 15.754); yields the following display: The sum of 12.2 and 15.754 is 27.954 When multiple insertions are sent to cout, the code can be spread across multiple lines. Only one semicolon, however, must be used, which is placed after the last insertion and terminates the complete statement. Therefore, the preceding display is also produced by the following statement, which spans two lines: cout << "The sum of 12.2 and 15.754 is " << (12.2 + 15.754); However, when you allow a statement to span multiple lines, two rules must be followed: A string contained in quotation marks can’t be split across lines, and the terminating semicolon should appear only on the last line. You can always place multiple insertion symbols in a line. 8 The parentheses aren’t required because the + operator has a higher precedence than the << operator; therefore, the addition is performed before the insertion. 69 Chapter 2 Arithmetic Operations
  • 90. If floating-point numbers have six or fewer decimal digits, they’re displayed with enough decimal places to accommodate the fractional part of the number. If the number has more than six decimal digits, the fractional part is rounded to six decimal digits, and if the number has no decimal digits, neither a decimal point nor any decimal digits are displayed.9 Program 2.6 illustrates using cout to display the results of arithmetic expressions in the statements of a complete program. Program 2.6 #include <iostream> using namespace std; int main() { cout << "15.0 plus 2.0 equals " << (15.0 + 2.0) << endl << "15.0 minus 2.0 equals " << (15.0 - 2.0) << endl << "15.0 times 2.0 equals " << (15.0 * 2.0) << endl << "15.0 divided by 2.0 equals " << (15.0 / 2.0) << endl; return 0; } The output of Program 2.6 is the following: 15.0 plus 2.0 equals 17 15.0 minus 2.0 equals 13 15.0 times 2.0 equals 30 15.0 divided by 2.0 equals 7.5 The only new item used in Program 2.6 is the term endl, which is an example of a C++ manipulator. A manipulator is an item used to change how the output stream of characters is displayed. In particular, the endl manipulator first causes a newline character ('n') to be inserted in the display, and then forces all current insertions to be displayed immediately, instead of waiting for more data. (Section 3.2 lists the most commonly used manipulators.) Expression Types An expression is any combination of operators and operands that can be evaluated to yield a value. An expression containing only integer values as operands is called an integer expression, and the result of the expression is an integer value. Similarly, an expression containing only floating-point values (single-precision and double-precision) as operands is called a floating-point expression (also referred to as a “real expression”), and the result of the 9 None of this output is defined as part of the C++ language. Rather, it’s defined by a set of classes and routines provided with each C++ compiler. 70 Problem Solving Using C++
  • 91. expression is a floating-point value. An expression containing integer and floating-point values is called a mixed-mode expression. Although it’s usually better not to mix integer andfloating-point values in an arithmetic operation, the data type of each operation is determined by the following rules: • If both operands are integers, the result of the operation is an integer. • If one operand is a real value, the result of the operation is a double-precision value. The result of an arithmetic expression is never a single-precision (float) number. This is because during execution, a C++ program temporarily converts all single-precision numbers to double-precision numbers when an arithmetic expression is evaluated. Integer Division The division of two integer values can produce rather strange results for the unwary. For example, the expression 15/2 yields the integer result 7. Because integers can’t contain a fractional part, a value of 7.5 can’t be obtained. The fractional part resulting when two integers are divided—the remainder—is always dropped (truncated). Therefore, the value of 9/4 is 2 and 20/3 is 6. Often, however, you need to retain the remainder of an integer division. To do this, C++ provides the modulus operator (also referred to as the “remainder operator”), which has the symbol %. This operator captures the remainder when an integer is divided by an integer; using a non-integer value with the modulus operator results in a compiler error. The following examples show how the modulus operator is used: 9 % 4 is 1 (the remainder when 9 is divided by 4 is 1) 17 % 3 is 2 (the remainder when 17 is divided by 3 is 2) 15 % 4 is 3 (the remainder when 15 is divided by the 4 is 3) 14 % 2 is 0 (the remainder when 14 is divided by 2 is 0) Negation In addition to binary operators, C++ provides unary operators, which operate on a single operand. One of these unary operators uses the same symbol as binary subtraction (-). With Point of Information The endl Manipulator On many systems, the endl manipulator and the n escape sequence are processed in the same way and produce the same effect. The one exception is on systems where output is accumulated internally until enough characters collect to make it advanta- geous to display them all in one burst onscreen. In these systems, referred to as “buff- ered,” the endl manipulator forces all accumulated output to be displayed immediately, without waiting for additional characters to fill the buffer area before being printed. As a practical matter, you wouldn’t notice a difference in the final display. As a general rule, however, use the n escape sequence whenever it can be included in an existing string, and use the endl manipulator whenever a n would appear by itself or to formally signify the end of a specific group of output. 71 Chapter 2 Arithmetic Operations
  • 92. this unary operator, the minus sign in front of a single numerical value negates (reverses the sign of) the number. Table 2.7 summarizes the six arithmetic operations described so far and lists the data type for the result each operator produces, based on the data type of the operands involved. Table 2.7 Summary of Arithmetic Operators Operation Operator Symbol Type Operand(s) Result Addition + Binary Both are integers One operand is not an integer Integer Double- precision Subtraction - Binary Both are integers One operand is not an integer Integer Double- precision Multiplication * Binary Both are integers One operand is not an integer Integer Double- precision Division / Binary Both are integers One operand is not an integer Integer Double- precision Modulus % Binary Both are integers One operand is not an integer Integer Double- precision Negation - Unary Integer or double Same as operand Operator Precedence and Associativity In addition to simple expressions, such as 5 + 12 and .08 * 26.2, you can create more complex arithmetic expressions. C++, like most other programming languages, requires following certain rules when writing expressions containing more than one arithmetic operator: • Two binary operator symbols must never be placed side by side. For example, 5 * % 6 is invalid because two operators, * and %, are placed next to each other. • Parentheses can be used to form groupings, and all expressions enclosed in parentheses are evaluated first. In this way, you can use parentheses to alter the evaluation to any desired order. For example, in the expression (6 + 4) / (2 + 3), the 6 + 4 and 2 + 3 are evaluated first to yield 10 / 5. The 10 / 5 is then evaluated to yield 2. • Parentheses can be enclosed by other parentheses. For example, the expression (2 * (3 + 7) ) / 5 is valid and evaluates to 4. When parentheses are included within parentheses, expressions in the innermost parentheses are always evaluated first. The evaluation continues from innermost to outermost parentheses until all expressions in parentheses have been evaluated. The number of closing parentheses, ), must always equal the number of opening parentheses, (, so that no unpaired sets exist. 72 Problem Solving Using C++
  • 93. • Parentheses can’t be used to indicate multiplication; instead, the multiplication operator, *, must be used. For example, the expression (3 + 4) (5 + 1) is invalid. The correct expression is (3 + 4) * (5 + 1). Parentheses should specify logical groupings of operands and indicate clearly, to the compiler and programmers, the intended order of arithmetic operations. Although expres- sions in parentheses are always evaluated first, expressions containing multiple operators, whether enclosed in parentheses or not, are evaluated by the priority, or precedence, of the operators. There are three levels of precedence: 1. P1—All negations are done first. 2. P2—Multiplication, division, and modulus operations are computed next. Expres- sions containing more than one multiplication, division, or modulus operator are evaluated from left to right as each operator is encountered. For example, in the expression 35 / 7 % 3 * 4, all operations have the same priority, so the operations are performed from left to right as each operator is encountered. The division is done first, yielding the expression 5 % 3 * 4. The modulus operation, 5 % 3, is performed next, yielding a result of 2. Finally, the expression 2 * 4 is computed to yield 8. 3. P3—Addition and subtraction are computed last. Expressions containing more than one addition or subtraction are evaluated from left to right as each operator is encountered. In addition to precedence, operators have an associativity, which is the order in which operators of the same precedence are evaluated, as described in rule P2. For example, does the expression 6.0 * 6 / 4 yield 9.0, which is (6.0 * 6) / 4, or 6.0, which is 6.0 * (6 / 4)? The answer is 9.0 because C++’s operators use the same associativity as in general mathematics, which evaluates multiplication from left to right, as rule P2 indicates. Table 2.8 lists the precedence and associativity of the operators discussed in this section. As you have seen, an operator’s precedence establishes its priority in relation to all other operators. Operators at the top of Table 2.8 have a higher priority than operators at the bottom of the table. In expressions with multiple operators of different precedence, the operator with the higher precedence is used before an operator with lower precedence. For example, in the expression 6 + 4 / 2 + 3, because the division operator has a higher precedence (P2) than the addition operator, the division is done first, yielding an interme- diate result of 6 + 2 + 3. The additions are then performed, left to right, to yield a final result of 11. Table 2.8 Operator Precedence and Associativity Operator Associativity Unary - Right to left * / % Left to right + - Left to right Finally, take a look at using Table 2.8 and the precedence rules to evaluate an expression containing operators of different precedence, such as 8 + 5 * 7 % 2 * 4. Because the multiplication and modulus operators have a higher precedence than the addition operator, 73 Chapter 2 Arithmetic Operations
  • 94. these two operations are evaluated first (P2), using their left-to-right associativity, before the addition is evaluated (P3). Therefore, the complete expression is evaluated as the following: 8 + 5 * 7 % 2 * 4 = 8 + 35 % 2 * 4 = 8 + 1 * 4 = 8 + 4 = 12 EXERCISES 2.4 1. (Practice) For the following correct algebraic expressions and corresponding incorrect C++ expressions, find the errors and write corrected C++ expressions: Algebra C++ Expression a. (2)(3) + (4)(5) b. 6 18 2 + c. 4 5 12 2 3 1 . . . - d. 4.6 (3.0 + 14.9) e. (12.1 + 18.9) (15.3 - 3.8) (2)(3) + (4)(5) 6 + 18 / 2 4.5 / 12.2 - 3.1 4.6 (3.0 + 14.9) (12.1 + 18.9) (15.3 - 3.8) 2. (Practice) Determine the values of the following integer expressions: a. 3 + 4 * 6 b. 3 * 4 / 6 + 6 c. 2 * 3 / 12 * 8 / 4 d. 10 * (1 + 7 * 3) e. 50 % 20 f. 20 - 2 / 6 + 3 g. 20 - 2 / (6 + 3) h. (20 - 2) / 6 + 3 i. (20 - 2) / (6 + 3) j. (10 + 3) % 4 3. (Practice) Determine the value of the following floating-point expressions: a. 3.0 + 4.0 * 6.0 b. 3.0 * 4.0 / 6.0 + 6.0 c. 2.0 * 3.0 / 12.0 * 8.0 / 4.0 d. 10.0 * (1.0 + 7.0 * 3.0) e. 20.0 - 2.0 / 6.0 + 3.0 f. 20.0 - 2.0 / (6.0 + 3.0) g. (20.0 - 2.0) / 6.0 + 3.0 h. (20.0 - 2.0) / (6.0 + 3.0) 4. (Practice) Evaluate the following mixed-mode expressions and list the data type of the result. In evaluating the expressions, be aware of the data types of all intermediate calculations. a. 10.0 + 15 / 2 + 4.3 74 Problem Solving Using C++
  • 95. b. 10.0 + 15.0 / 2 + 4.3 c. 3.0 * 4 / 6 + 6 d. 3 * 4.0 / 6 + 6 e. 20.0 - 2 / 6 + 3 f. 10 + 17 * 3 + 4 g. 10 + 17 / 3. + 4 h. 3.0 * 4 % 6 + 6 i. 10 + 17 % 3 + 4 5. (Practice) Assume that amount stores the integer value 1, m stores the integer value 50, n stores the integer value 10, and p stores the integer value 5. Evaluate the following expressions: a. n / p + 3 b. m / p + n - 10 * amount c. m - 3 * n + 4 * amount d. amount / 5 e. 18 / p f. -p * n g. -m / 20 h. (m + n) / (p + amount) i. m + n / p + amount 6. (Practice) Repeat Exercise 5, assuming that amount stores the value 1.0, m stores the value 50.0, n stores the value 10.0, and p stores the value 5.0. 7. (Practice) Enter, compile, and run Program 2.6. 8. (Desk Check) Determine the output of the following program: #include <iostream> using namespace std; int main() // a program illustrating integer truncation { cout << "answer1 is the integer " << 9/4; cout << "nanswer2 is the integer " << 17/3; return 0; } 9. (Desk Check) Determine the output of the following program: #include <iostream> using namespace std; int main() // a program illustrating the % operator { cout << "The remainder of 9 divided by 4 is " << 9 % 4; cout << "nThe remainder of 17 divided by 3 is " << 17 % 3; 75 Chapter 2 Arithmetic Operations
  • 96. return 0; } 10. (Program) Write a C++ program that displays the results of the expressions 3.0 * 5.0, 7.1 * 8.3 - 2.2, and 3.2 / (6.1 * 5). Calculate the value of these expressions manually to verify that the displayed values are correct. 11. (Program) Write a C++ program that displays the results of the expressions 15 / 4, 15 % 4, and 5 * 3 - (6 * 4). Calculate the value of these expressions manually to verify that the displayed values are correct. 2.5 Variables and Declaration Statements All integer, floating-point, and other values used in a program are stored and retrieved from the computer’s memory. Conceptually, locations in memory are arranged like the rooms in a large hotel. Like room numbers in a hotel, each memory location has a unique address. Before high-level languages such as C++, memory locations were referenced by their addresses. For example, storing the integer values 45 and 12 in the memory locations 1652 and 2548 (see Figure 2.8) required instructions equivalent to the following: Put a 45 in location 1652 Put a 12 in location 2548 To add the two numbers just stored and save the result in another memory location, such as 3000, you need an instruction such as the following: Add the contents of location 1652 to the contents of location 2548 and store the result in location 3000 Clearly, this method of storage and retrieval is cumbersome. In high-level languages such as C++, symbolic names, called variables, are used in place of memory addresses. A variable is simply a name the programmer assigns to refer to computer storage locations. The term “variable” is used because the value stored in the memory locations assigned to the variable can change, or vary. For each name the programmer uses, the computer keeps track of the memory address corresponding to that name. In the hotel room analogy, it’s equivalent to putting a name on a room’s door and referring to the room by this name, such as calling it the Blue Room instead of Room 205. 1652 2548 12 45 Memory addresses Storage for one integer Storage for one integer Figure 2.8 Enough storage for two integers 76 Problem Solving Using C++
  • 97. In C++, the selection of variable names is the programmer’s choice, as long as the rules listed in Section 2.1 for selecting identifier names are observed. These rules are summarized in the following list: 1. The variable name must begin with a letter or underscore (_) and can contain only letters, underscores, or digits. It can’t contain blank spaces, commas, or special symbols, such as ( ) & , $ # . ! ?. 2. A variable name can’t be a keyword (see Table 2.1). 3. A variable name can’t consist of more than 1024 characters. Additionally, variable names should be mnemonics that give some indication of the variable’s purpose. For a variable used to store a value that’s the total of other values, a good name is sum or total. Variable names giving no indication of the value stored, such as r2d2, linda, and getum, shouldn’t be used. As with function names, variable names can consist of uppercase and lowercase letters. Assume the first memory location shown in Figure 2.9, which has the address 1652, is given the name num1. The memory location 2548 is given the variable name num2, and memory location 3000 is given the variable name total. Using these variable names, the operation of storing 45 in location 1652, storing 12 in location 2548, and adding the contents of these two locations is accomplished by these C++ statements: num1 = 45; num2 = 12; total = num1 + num2; Each of these statements is called an assignment statement because it tells the computer to assign (store) a value in a variable. Assignment statements always have an equal sign (=) and one variable name immediately to the left of the =. The value to the right of the equal sign is determined first; this value is then assigned to the variable to the left of the equal sign. The blank spaces in assignment statements are inserted for readability. Assignment state- ments are explained in more detail in Chapter 3, but for now, just know that you can use them to store values in variables. A variable name is useful because it frees programmers from having to think about where data is physically stored in the computer. You simply use the variable name and let the compiler worry about where in memory the data is actually stored. Before storing a value in num1 1652 2548 45 num2 total 12 45 57 Variable names Memory addresses Figure 2.9 Naming storage locations 77 Chapter 2 Variables and Declaration Statements
  • 98. a variable, however, C++ requires clearly declaring the type of data to be stored in it. You must tell the compiler, in advance, the names of variables used for characters, the names used for integers, and the names used to store other C++ data types. Declaration Statements To name a variable and specify the data type that can be stored in it, you use declaration statements, which have this general form dataType variableName; where dataType designates a valid C++ data type, and variableName is the name you select for the variable. For example, variables used to hold integer values are declared by using the keyword int to specify the data type and have this form: int variableName; Therefore, the following declaration statement declares sum as the name of a variable capable of storing an integer value: int sum; In addition, the keyword long is used to specify a long integer.10 For example, the statement long datenum; declares datenum as a variable used to store a long integer. When you’re using the long qualifier, you can also include the keyword int, so the previous declaration can also be written as follows: long int datenum; Variables used to hold single-precision values are declared by using the keyword float, and variables used to hold double-precision values are declared by using the keyword double. For example, the statement float firstnum; declares firstnum as a variable used to store a single-precision number. Similarly, the statement double secnum; declares that the variable secnum is used to store a double-precision number. Although declaration statements can be placed anywhere in a function, typically they’re grouped together and placed after the function’s opening brace. However, a variable must always be declared before using it, and like all C++ statements, declaration statements must 10 Additionally, the keywords unsigned int are used to specify an integer that can store only non-negative numbers, and the keyword short specifies a short integer. 78 Problem Solving Using C++
  • 99. end with a semicolon. A simple main() function containing declaration statements right after the opening function brace has this general form: #include <iostream> using namespace std; int main() { // declaration statements; // other statements; return 0; } Program 2.7 uses this form in declaring and using four double-precision variables, with the cout object used to display the contents of one of the variables. Point of Information Atomic Data All the variables declared so far have been used to store atomic data values. An atomic data value is considered a complete entity and can’t be decomposed into a smaller data type supported by the language. For example, although an integer can be decomposed into individual digits, C++ doesn’t have a numerical digit type. Instead, each integer is regarded as a complete value and, therefore, is considered atomic data. Because the inte- ger data type supports only atomic data values, it’s said to be an atomic data type. As you might expect, doubles, chars, and bools are atomic data types, too. 79 Chapter 2 Variables and Declaration Statements
  • 100. Program 2.7 #include <iostream> using namespace std; int main() { double grade1; // declare grade1 as a double variable double grade2; // declare grade2 as a double variable double total; // declare total as a double variable double average; // declare average as a double variable grade1 = 85.5; grade2 = 97.0; total = grade1 + grade2; average = total/2.0; // divide the total by 2.0 cout << "The average grade is " << average << endl; return 0; } The placement of the declaration statements in Program 2.7 is straightforward, although you’ll see shortly that these four declarations can be combined into a single declaration. When Program 2.7 runs, the following output is displayed: The average grade is 91.25 Notice that when a variable name is inserted in a cout statement, the value stored in the variable is placed on the output stream and displayed. Just as integer and real (single-precision, double-precision, and long double) variables must be declared before they can be used, a variable used to store a single character must also be declared. Character variables are declared by using the keyword char. For example, the following declaration specifies that ch is a character variable: char ch; Program 2.8 illustrates this declaration and the use of cout to display the value stored in a character variable. 80 Problem Solving Using C++
  • 101. Program 2.8 #include <iostream> using namespace std; int main() { char ch; // this declares a character variable ch = 'a'; // store the letter a in ch cout << "The character stored in ch is " << ch << endl; ch = 'm'; // now store the letter m in ch cout << "The character now stored in ch is "<< ch << endl; return 0; } When Program 2.8 runs, this output is produced: The character stored in ch is a The character now stored in ch is m Notice in Program 2.8 that the first letter stored in the variable ch is a and the second letter stored is m. Because a variable can be used to store only one value at a time, assigning m to the variable overwrites the a value automatically. Multiple Declarations Variables of the same data type can always be grouped together and declared by using a single declaration statement, which has this common form: dataType variableList; For example, the four separate declarations used in Program 2.7 double grade1; double grade2; double total; double average; can be replaced with this single declaration statement: double grade1, grade2, total, average; Similarly, the two character declarations char ch; char key; 81 Chapter 2 Variables and Declaration Statements
  • 102. can be replaced with this single declaration statement: char ch, key; Declaring multiple variables in a single declaration statement requires giving the data type of variables only once, separating all variable names by commas, and using only one semicolon to terminate the declaration. The space after each comma is inserted for readability and isn’t required. Declaration statements can also be used to store a value in declared variables. For example, the declaration statement int num1 = 15; both declares the variable num1 as an integer variable and sets the value of 15 in the variable. When a declaration statement is used to store a value in a variable, the variable is said to be initialized. Therefore, in this example, it’s correct to say the variable num1 has been initialized to 15. Similarly, the declaration statements double grade1 = 87.0; double grade2 = 93.5; double total; declare three double-precision variables and initialize two of them. When initializations are used, good programming practice dictates declaring each initialized variable on a line by itself. Constants, expressions using only constants (such as 87.0 + 12 - 2), and expressions using constants and previously initialized variables can be used as initializers for variables declared within a function. For example, Program 2.7 with declaration initialization becomes Program 2.7a. Program 2.7a #include <iostream> using namespace std; int main() { double grade1 = 85.5; double grade2 = 97.0; double total, average; total = grade1 + grade2; average = total/2.0; // divide the total by 2.0 cout << "The average grade is " << average << endl; return 0; } 82 Problem Solving Using C++
  • 103. Notice the blank line after the last declaration statement. Inserting a blank line after variable declarations placed at the top of a function body is a good programming practice. It improves a program’s appearance and readability. An interesting feature of C++ is that variable declarations can be intermixed and even contained in other statements; the only requirement is that a variable must be declared before its use. For example, the variable total in Program 2.7a could have been declared when it was first used with the statement double total = grade1 + grade2. In restricted situations (such as debugging, described in Section 3.7, or in a for loop, described in Section 5.4), declaring a variable at its first use can be helpful. In general, however, it’s preferable not to spread out declarations; instead, group them as concisely and clearly as possible at the top of each function. Memory Allocation The declaration statements you have seen so far have performed both software and hardware tasks. From a software perspective, declaration statements always provide a list of variables and their data types. In this software role, variable declarations also help control an otherwise common and troublesome error caused by misspelling a variable’s name in a program. For example, a variable named distance is declared and initialized by using this statement: int distance = 26; Later in the program, the variable is inadvertently misspelled in this statement: mpg = distnce / gallons; In languages that don’t require variable declarations, the program treats distnce as a new variable and assigns it an initial value of 0 or uses whatever value happens to be in the variable’s storage area. In either case, a value is calculated and assigned to mpg, and finding the error or even knowing an error occurred could be difficult. These errors are impossible in C++, however, because the compiler flags distnce as an undeclared variable. The compiler can’t, of course, detect when one declared variable is mistakenly typed in place of another declared variable. In addition to their software role, declaration statements can also perform a hardware task. Because each data type has its own storage requirements, the computer can allocate enough storage for a variable only after knowing the variable’s data type. Variable declarations provide this information, so they can be used to force the compiler to reserve enough physical memory storage for each variable. Declaration statements used for this hardware task are also called definition statements because they define or tell the compiler how much memory is needed for data storage. All the declaration statements you have encountered so far have also been definition statements. Later, you’ll see declaration statements that don’t allocate storage and are used simply to alert the program to the data types of variables created elsewhere in the program. Figures 2.10a through 2.10d illustrate the operations set in motion by definition statements. The figures show that definition statements (or declaration statements that also allocate memory) “tag” the first byte of each set of reserved bytes with a name. This name is, of course, the variable’s name, and the computer uses it to locate the starting point of a variable’s reserved memory area. After a variable has been declared in a program, typically a programmer uses it to refer to the variable’s contents (its value). The value’s memory location is generally of little concern to programmers. The compiler, however, must know where each value is stored and 83 Chapter 2 Variables and Declaration Statements
  • 104. locate each variable correctly. For this task, the compiler uses the variable name to locate the first byte of storage previously allocated to the variable. Knowing the variable’s data type then allows the compiler to store or retrieve the correct number of bytes. Tells the computer to int total; Reserve enough room for an integer number “Tag” the first byte of reserved storage with the name total Tells the computer to 4 bytes Figure 2.10a Defining the integer variable named total Tells the computer to float slope; Reserve enough room for a single-precision number “Tag” the first byte of reserved storage with the name slope Tells the computer to 4 bytes Figure 2.10b Defining the floating-point variable named slope Tells the computer to double thrust; Reserve enough room for a double-precision number “Tag” the first byte of reserved storage with the name thrust Tells the computer to 8 bytes Figure 2.10c Defining the double-precision variable named thrust 84 Problem Solving Using C++
  • 105. Displaying a Variable’s Address11 Every variable has three major items associated with it: its data type, the value stored in it, and its address. The value stored in the variable is referred to as the variable’s contents, and the address of the first memory location used for the variable constitutes its address. The number of locations actually used for the variable, as you have just seen, depends on the variable’s data type. Figure 2.11 illustrates the relationship between these three items (type, contents, and location). Programmers are usually concerned only with the value assigned to a variable (its contents) and give little attention to where the value is stored (its address). For example, take a look at Program 2.9. 11 This topic can be omitted on first reading without loss of subject continuity. Tells the computer to char key; Reserve enough room for a character “Tag” the first byte of reserved storage with the name key Tells the computer to 1 byte Figure 2.10d Defining the character variable named key Variable contents Variable address One or more bytes in memory Figure 2.11 A typical variable 85 Chapter 2 Variables and Declaration Statements
  • 106. Program 2.9 #include <iostream> using namespace std; int main() { int num; num = 22; cout << "The value stored in num is " << num << endl; return 0; } The following output is displayed when Program 2.9 is run: The value stored in num is 22 Program 2.9 merely prints the value 22, which is the contents of the variable num. You can go further, however, and ask “Where is the number 22 actually stored?” Although the answer is “in num,” it’s only half the answer. The variable name num is simply a convenient symbol for actual memory locations, as shown in Figure 2.12. To determine the address of num, you can use C++’s address operator, &, which means “the address of.” Except when used in an expression, the address operator placed in front of a variable’s name refers to the variable’s address.12 For example, &num means “the address of num.” Program 2.10 shows you an example of using the address operator. 12 When used in declaration statements that create a reference variable or reference argument (see Chapter 6), the ampersand refers to the data type preceding it. Therefore, the declaration double &num is read as “num is the address of a double” or, more commonly, “num is a reference to a double.” 22 Contents of num 4 bytes of memory Address of first byte used by num x x x x Figure 2.12 The variable num stored somewhere in memory 86 Problem Solving Using C++
  • 107. Program 2.10 #include <iostream> using namespace std; int main() { int num; num = 22; cout << "The value stored in num is " << num << endl; cout << "The address of num = " << &num << endl; return 0; } This is the output of Program 2.10: The value stored in num is 22 The address of num = 0012FED4 Figure 2.13 illustrates the additional address information provided by Program 2.10’s output. Clearly, the address output by Program 2.10 depends on the computer used to run the program. Every time Program 2.10 runs, however, it displays the address of the first memory location used to store num. As Program 2.10’s output shows, the address display is in hexadecimal notation. This display has no effect on how the program uses addresses internally; it merely gives you a means of displaying addresses that’s helpful in understanding them. As you’ll see in Chapters 6 and 12, using addresses, instead of just displaying them, is an important and powerful programming tool. EXERCISES 2.5 1. (Practice) State whether the following variable names are valid. If they are invalid, state the reason. prod_a c1234 abcd _c3 12345 newamp watts $total new$al a1b2c3d4 9ab6 sum.of average volts1 finvolt 22 Contents of num 4 bytes of memory Address of first byte used by num 0012FED4 Figure 2.13 A more complete picture of the variable num 87 Chapter 2 Variables and Declaration Statements
  • 108. 2. (Practice) State whether the following variable names are valid. If they are invalid, state the reason. Also, indicate which of the valid variable names shouldn’t be used because they convey no information about the variable. current a243 r2d2 firstnum cc_a1 harry sue c3p0 total sum maximum okay a awesome goforit 3sum for tot.a1 c$five netpower 3. (Practice) a. Write a declaration statement to declare that the variable count will be used to store an integer. b. Write a declaration statement to declare that the variable volt will be used to store a floating-point number. c. Write a declaration statement to declare that the variable power will be used to store a double-precision number. d. Write a declaration statement to declare that the variable keychar will be used to store a character. 4. (Practice) Write declaration statements for the following variables: a. num1, num2, and num3 used to store integer number b. amps1, amps2, amps3, and amps4 used to store double-precision numbers c. volts1, volts2, and volts3 used to store double-precision numbers d. codeA, codeB, codeC, codeD, and codeE used to store characters 5. (Practice) Write declaration statements for the following variables: a. firstnum and secnum used to store integer b. speed, acceleration, and distance used to store double-precision numbers c. thrust used to store a double-precision number 6. (Modify) Rewrite each of these declaration statements as three separate declarations: a. int month, day = 30, year; b. double hours, volt, power = 15.62; c. double price, amount, taxes; d. char inKey, ch, choice = 'f'; 7. (Desk Check) a. Determine what each statement causes to happen in the following program: #include <iostream> using namespace std; int main() { int num1, num2, total; num1 = 25; 88 Problem Solving Using C++
  • 109. num2 = 30; total = num1 + num2; cout << "The total of " << num1 << " and " << num2 << " is " << total << endl; return 0; } b. What output will be printed when the program in Exercise 7a runs? 8. (Practice) What are the three items associated with every variable? Note for Exercises 9 to 11: Assume that a character requires 1 byte of storage, an integer requires 4 bytes, a single-precision number requires 4 bytes, and a double-precision number requires 8 bytes. Variables are assigned storage in the order they’re declared. (Review Section 1.6 if you’re unfamiliar with the concept of a byte.) Refer to Figure 2.14 for these exercises. N O T E 9. (Practice) a. Using Figure 2.14 and assuming the variable name rate is assigned to the byte at memory address 159, determine the addresses corresponding to each variable declared in the following statements. Also, fill in the correct number of bytes with the initialization data included in the declaration statements. (Use letters for the characters, not the computer codes that would actually be stored.) float rate; char ch1 = 'M', ch2 = 'E', ch3 = 'L', ch4 = 'T'; double taxes; int num, count = 0; b. Repeat Exercise 9a, but substitute the actual byte patterns that a computer using the ASCII code would use to store characters in the variables ch1, ch2, ch3, and ch4. (Hint: Use Appendix B.) 10. (Practice) a. Using Figure 2.14 and assuming the variable named cn1 is assigned to the byte at memory address 159, determine the addresses corresponding to each variable declared in the following statements. Also, fill in the correct number of bytes with the initialization data included in the declaration statements. (Use letters for the characters, not the computer codes that would actually be stored.) Addresses 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 Figure 2.14 Memory bytes for Exercises 9 to 11 89 Chapter 2 Variables and Declaration Statements
  • 110. char cn1 = 'P', cn2 = 'E', cn3 = 'R', cn4 = 'F', cn5 = 'E'; char cn6 = 'C', cn7 = 'T', key = '', sch = ''', inc = 'A'; char inc1 = 'T'; b. Repeat Exercise 10a, but substitute the actual byte patterns a computer using the ASCII code would use to store characters in each of the declared variables. (Hint: Use Table 2.3.) 11. (Practice) Using Figure 2.14 and assuming the variable name miles is assigned to the byte at memory address 159, determine the addresses corresponding to each variable declared in the following statements: float miles; int count, num; double dist, temp; 2.6 A Case Study: Radar Speed Traps In this section, the software development procedure explained in Section 1.3 is applied to a specific programming problem. Although each problem you explore in the case studies in Part One is different, you’ll see that this software development procedure works for all of them to produce a complete program. It forms the foundation for all programs developed in Part One of this book. A highway-patrol speed detection radar emits a beam of microwaves at a frequency designated as fe. The beam is reflected off an approaching car, and the radar unit picks up and analyzes the reflected beam, fr. The reflected beam’s frequency is shifted slightly from fe to fr because of the car’s motion. The relationship between the speed of the car, v, in miles per hour (mph), and the two microwave frequencies is v f f f f mph r e r e = × ( ) +       6 685 108 . - where the emitted waves have a frequency of fe = 2 × 1010 sec-1 . Using the given formula, you’ll write a C++ program, using the software development procedure, to calculate and display the speed corresponding to a received frequency of 2.000004 × 1010 sec-1 . Step 1 Analyze the Problem For this problem, a single output is required: the speed of the car. The input items required to solve for the speed are the emitted frequency, fe, and the received frequency, fr. Step 2 Develop a Solution The algorithm for transforming the three input items into the required output item is given by the formula v = 6.685 × 108 (fr - fe) / (fr + fe). Therefore, the complete algorithm for the program solution is as follows: Assign values to fr and fe Calculate the speed using the formula v = 6.685 × 108 (fr - fe) / (fr + fe) Display the speed 90 Problem Solving Using C++
  • 111. A hand calculation, using the data fe = 2 × 1010 sec-1 and fr = 2.000004 × 1010 sec-1 , yields a speed of 66.85 mph. Step 3 Code the Solution Program 2.11 provides the necessary code. Program 2.11 #include <iostream> using namespace std; int main() { double speed, fe, fr; fe = 2e10; fr = 2.0000004e10; speed = 6.685e8 * (fr - fe) / (fr + fe); cout << "The speed is " << speed << " miles/hour " << endl; return 0; } Program 2.11 begins with an #include preprocessor command followed by a main() function. The main() function in Program 2.11 contains one declaration statement, three assignment statements, and one output statement. The assignment statements fe = 2e10; and fr = 2.0000004e10; are used to initialize the fe and fr variables. The assignment statement speed = 6.685e8 * (fr - fe) / (fr + fe); calculates a value for the variable speed. When Program 2.11 is compiled and executed, the following output is produced: The speed is 66.85 miles/hour Step 4 Test and Correct the Program The last step in the development procedure is to test the output. Because the single calculation and displayed value agree with the previous hand calculation, you have verified that the program operates correctly. Now you can use the program for different values of received frequencies. Note that if the parentheses weren’t placed correctly in the assignment statement that calculates a value for speed, the displayed value wouldn’t agree with your previous hand calculation. This would alert you to the fact that there’s an error in the program. 91 Chapter 2 A Case Study: Radar Speed Traps
  • 112. EXERCISES 2.6 1. (Modify) a. Modify Program 2.11 to calculate the speed of a car whose received radar frequency is 2.00000035 × 1010 sec-1 . b. Compile and execute the program written for Exercise 1a. 2. (Modify) a. Modify Program 2.11 to determine the frequency returned by a car traveling at 55 mph. Your program should produce the following display (replacing the underlines with the values your program calculates): The returned frequency corresponding to 55 mph is _____ b. Compile and execute the program written for Exercise 2a. Make sure to do a hand calculation so that you can verify the results your program produces. c. After verifying the results of the program written in Exercise 2a, modify the program to calculate the return frequency of a car traveling at 75 mph. 3. (Telephony) In a directly connected telephone network, all telephones are directly con- nected and don’t require a central switching station to establish calls between two telephones. The number of lines needed to maintain a directly connected network for n telephones is given by this formula: no of lines needed n n . ( ) = -1 2 For example, directly connecting four telephones requires six separate lines (see Figure 2.15). Adding a fifth telephone to this network requires an additional 4 lines, for a total of 10 lines. line 6 line 5 line 4 line 3 line 1 line 2 Telephone #3 Telephone #4 Telephone #2 Telephone #1 Figure 2.15 Directly connecting four telephones 92 Problem Solving Using C++
  • 113. a. Using the given formula, write a C++ program that determines the number of lines required for directly connecting 100 telephones. The input for this problem is the number of telephones, denoted as n in the formula, and the output is the total num- ber of lines required to directly connect the input number of telephones. b. Compile and execute the program written for Exercise 3a. 4. (Modify) Modify the program you wrote for Exercise 3 and include a new variable to represent the additional number of telephones to be connected to an existing network, and initialize this variable to 10. For this program, two outputs are required: the number of direct lines for 100 telephones and the additional number of lines needed when 10 telephones are added to the existing network. 5. (Conversion) a. Design, write, compile, and execute a C++ program to convert tempera- ture in degrees Fahrenheit to degrees Celsius. This is the equation for this conversion: Celsius = 5.0/9.0 (Fahrenheit - 32.0) Have your program convert and display the Celsius temperature corresponding to 98.6 degrees Fahrenheit. Your program should produce the following display (replacing the underlines with the correct values): For a Fahrenheit temperature of ___ degrees, the equivalent Celsius temperature is ___ degrees. b. Check the values computed by your program by hand. After verifying that your pro- gram is working correctly, modify it to convert 86.5 degrees Fahrenheit to its equiva- lent Celsius value. 6. (Electrical Eng.) a. Write, compile, and execute a C++ program to calculate the resis- tance of a series circuit consisting of twelve 56-ohm, twenty 39-ohm, thirty-two 27-ohm, and twenty-seven 15-ohm resistors. The total resistance of a series circuit is the sum of all individual resistances. Your program should produce the following display (replacing the xxxx with the actual resistance value your program calculates): The total resistance, in ohms, is xxxx b. Manually check the values computed by your program. After verifying that your pro- gram is working correctly, modify it to calculate the resistance of a series circuit con- sisting of seventeen 39-ohm resistors, nineteen 27-ohm resistors, and forty-two 15-ohm resistors. 7. (Thermodynamics) a. Design, write, compile, and execute a program that determines the work performed by a piston engine providing a force of 1000 N over a distance of 15 centimeters. The following formula is used to determine the work, W, performed: W = F d F is the force provided by the piston in Newtons. d is the distance the piston moves in meters. b. Manually check the values computed by your program. After verifying that your pro- gram is working correctly, modify it to determine the work performed by six pistons, each providing a force of 1500 N over a distance of 20 centimeters. 8. (Civil Eng.) a. Design, write, compile, and execute a program that determines the stress on a steel I-beam having a rectangular moment of inertia of 21.4 in4 , and a height of 6 inches, 93 Chapter 2 A Case Study: Radar Speed Traps
  • 114. when a load of 700 lbs is placed 8 feet from the fixed end. The stress placed on the fixed end of a symmetrical steel I-beam, as shown in Figure 2.16, can be determined by this formula: S L d c I = S is the stress in lbs/in2 . L is the weight, in lbs, of the load placed on the beam. I is the beam’s rectangular moment of inertia in units of in4 . d is the distance in inches the load is placed from the fixed end of the beam (techni- cally referred to as the “moment arm”). c is one-half the height in inches of a symmetrical beam. b. Check the values computed by your program by hand. After verifying that your pro- gram is working correctly, modify it to determine the stress when the same load is placed at the end of an 8-foot 2” x 4” wooden beam, with a rectangular moment of inertia of 10.67 in4 . 2.7 Common Programming Errors Part of learning any programming language is making the elementary mistakes commonly encountered when you begin using the language. These mistakes tend to be quite frustratingbecause each language has its own set of common programming errors waiting for the unwary. When you start programming in C++, common errors include the following. 1. Omitting the parentheses after main(). 2. Omitting or incorrectly typing the opening brace, {, that signifies the start of a function body. 3. Omitting or incorrectly typing the closing brace, }, that signifies the end of a function. 4. Misspelling the name of an object or function, such as typing cot instead of cout. 5. Forgetting to enclose a string sent to cout with quotation marks. L h d Figure 2.16 Determining the stress on a symmetrical I-beam 94 Problem Solving Using C++
  • 115. 6. Forgetting to separate data streams sent to cout with an insertion symbol, <<. 7. Omitting the semicolon at the end of each C++ statement. 8. Adding a semicolon at the end of the #include preprocessor command. 9. Forgetting the n to indicate a new line. 10. Incorrectly typing the letter O for the number 0 or vice versa. Incorrectly typing the letter l for the number 1 or vice versa. 11. Forgetting to declare all variables used in a program. The compiler detects this error, and an error message is generated for all undeclared variables. 12. Storing an inappropriate data type in a declared variable. The compiler detects this error, and the assigned value is converted to the data type of the variable it’s assigned to. 13. Using a variable in an expression before a value has been assigned to the variable. The value that happens to be in the variable when the variable is used is the value that’s used when the expression is evaluated. As such, the result of the expression is meaningless. 14. Dividing integer values incorrectly. This error is usually hidden in a larger expression and can be troublesome to detect. For example, the expression 3.425 + 2/3 + 7.9 yields the same result as the expression 3.425 + 7.9 because the integer division of 2/3 is 0. 15. Mixing data types in the same expression without clearly understanding the effect. Because C++ allows expressions with “mixed” data types, understanding the order of evaluation and the data type of all intermediate calculations is important. As a general rule, it’s better never to mix data types in an expression unless you want a specific effect. Errors 3, 5, 7, 8, and 9 in this list are the most common with beginning programmers, and even experienced programmers occasionally make error 10. A worthwhile practice is writing a program and introducing each error, one at a time, to see what error messages, if any, your compiler produces. When these error messages appear because of inadvertent mistakes, you’ll have had experience in understanding the messages and correcting the errors. A major error that all beginning programmers make is rushing to code and running a program before fully understanding its requirements and the algorithms and procedures used to produce the desired result. A symptom of this haste is the lack of a written program or even a program outline. Many problems can be caught just by checking a copy of the program (handwritten or onscreen) before it’s compiled. 2.8 Chapter Summary 1. A C++ program consists of one or more modules called functions. One of these functions must be called main(). The main() function identifies the starting point of a C++ program. 2. The simplest C++ program consists of the single function main(). 95 Chapter 2 Chapter Summary
  • 116. 3. Following the function name, the body of a function has the following general form: { All C++ statements in here; } 4. All C++ statements must be terminated by a semicolon. 5. Four types of data were introduced in this chapter: integer, floating-point, character, and Boolean. C++ recognizes each of these data types, in addition to other types you learn about in later chapters. 6. The cout object can be used to display all C++ data types. 7. When the cout object is used in a program, the preprocessor command #include <iostream> and the statement using namespace std; must be placed at the top of the program. The #include <iostream> preprocessor command does not end with a semicolon. 8. Every variable in a C++ program must be declared and the type of value it can store must be specified. Declaration statements can be placed anywhere in the function, although a variable can be used only after it’s declared. Variables can also be initialized when they are declared. Additionally, variables of the same type can be declared with a single declaration statement. Variable declaration statements have this general form: dataType variableName(s); 9. A simple C++ program containing declaration statements has this typical form: #include <iostream> using namespace std; int main() { // declaration statements; // other statements; return 0; } 10. Declaration statements always play the software role of informing the compiler of a function’s valid variable names. When a variable declaration also causes the computer to set aside memory locations for the variable, the declaration statement is called a definition statement. (All declarations used in this chapter have also been definition statements.) 11. The sizeof() operator can be used to determine the amount of storage reserved for variables. Programming Projects for Chapter 2 1. (General Math) a. Design, write, compile, and execute a C++ program that calculates and displays the perimeter of a two-dimensional triangle with sides a = 1 in, b = 1.5 in, and c = 2 in, as shown in Figure 2.17. The perimeter is given by this formula: perimeter = a + b + c 96 Problem Solving Using C++
  • 117. b. Manually check the values computed by your program. After verifying that your program is working correctly, modify it to determine the perimeter of a two- dimensional triangle with sides a = 1.62 in, b = 2.13 in, and c = 3.2 in. 2. (General Math) a. Design, write, compile, and execute a C++ program that calculates and displays the area of a two-dimensional triangle, such as the one in Figure 2.17, with a base of 1 in and a height of 1.5 in. The area is given by this formula: Area = ½ (base) × (height) b. Manually check the values computed by your program. After verifying that your program is working correctly, modify it to determine the area of a two-dimensional triangle with a base of 2 in and a height of 1.67 in. 3. (General Math) a. Design, write, compile, and execute a C++ program to calculate the volume of a sphere with a radius, r, of 3 in. The volume is given by this formula: Volume r = 4 3 3 π b. Manually check the values computed by your program. After verifying that your program is working correctly, modify it to determine the volume of a cube with a radius of 1.67 in. 4. (Physics) a. Design, write, compile, and execute a C++ program to calculate the elapsed time it takes to make a 183.67 mile trip. This is the formula for computing elapsed time: elapsed time = total distance / average speed The average speed during the trip is 58 mph. b. Manually check the values computed by your program. After verifying that your program is working correctly, modify it to determine the elapsed time it takes to make a 372-mile trip at an average speed of 67 mph. 5. (Numerical) a. Design, write, compile, and execute a C++ program to calculate the sum of the integers from 1 to 100. This is the formula for calculating this sum: sum = (n/2) (2 × a + (n - 1)d) n is the number of integers to be added. a is the first number. d is the difference between each number. a c b height base Figure 2.17 A two-dimensional triangle 97 Chapter 2 Programming Projects
  • 118. b. Manually check the values computed by your program. After verifying that your program is working correctly, modify it to determine the sum of the integers from 100 to 1000. 6. (Physics and Electrical) The energy, E, of a photon, in Joules, J, is provided by this formula: E = P × f P is 6.6256 × 10-34 Joules/sec (known as Planck’s constant). f is frequency in Hertz (Hz) of the photon. a. Given that the photon frequency of visible light is in the 3.84 × 1014 Hz to 7.69 × 1014 Hz range, design, write, compile, and execute a C++ program to calculate the energy of light with a photon frequency of 5.7 × 1014 . Verify the result produced by your program with a hand calculation. b. After verifying that your program is working correctly, use it to determine the photon energy output of a 60 Hz power line. 7. (Physics) a. The weight of an object on Earth is a measurement of the downward force on the object caused by Earth’s gravity. The formula for this force is determined by using Newton’s Second Law: F = M × Ae F is the object’s weight. M is the object’s mass. Ae is the acceleration caused by Earth’s gravity (32.2 ft/sec2 = 9.82 m/s2 ). Given this information, design, write, compile, and execute a C++ program to calculate the weight in lbf of a person having a mass of 4 lbm. Verify the result produced by your program with a hand calculation. b. After verifying that your program is working correctly, use it to determine the weight, on Earth, of a person having a mass of 3.2 lbm. 8. (Physics) a. Rewrite the program you wrote for Exercise 7 to provide the mass of a person as an output, given his or her weight as an input to the program. Use your program to determine the mass of a person who weighs 140 lbf on Earth. b. Modify the program written for Exercise 7a to also output the person’s weight on Mars and the moon. The pull of gravity on Mars is 12.54 ft/sec2 = 3.728 m/s2 , and on the moon is 5.33 ft/sec2 = 1.625 m/s2 . 9. (Civil Eng.) The maximum load that can be placed at the end of a symmetrical wooden beam, such as the rectangular beam shown in Figure 2.18, can be calculated as the following: L S I d c = × × L is the maximum weight in lbs of the load placed on the beam. S is the stress in lbs/in2 . I is the beam’s rectangular moment of inertia in units of in4 . 98 Problem Solving Using C++
  • 119. d is the distance in inches that the load is placed from the fixed end of the beam (the “moment arm”). c is one-half the height in inches of the symmetrical beam. For a 2” x 4” wooden beam, the rectangular moment of inertia is given by this formula: I base height = × = × = 3 3 12 2 4 12 10 67 . c = ½(4 in) = 2 in a. Using this information, design, write, compile, and execute a C++ program that computes the maximum load in lbs that can be placed at the end of an 8-foot 2” x 4” wooden beam so that the stress on the fixed end is 3000 lb/in2 . b. Use the program developed in Exercise 9a to determine the maximum load in lbs that can be placed at the end of a 3” x 6” wooden beam so that the stress on the fixed end is 3000 lbs/in2 . 10. (Civil Eng.) Modify the program written for Exercise 9 to determine the maximum load that can be placed at the end of an 8-foot I-beam, shown in Figure 2.19, so that the stress on the fixed end is 20,000 lbs/in2 . Use the fact that this beam’s rectangular moment of inertia is 21.4in4 and the value of c is 3 in. 11. (Mechanical Eng.) The minimum radius required for a cylindrical rod, such as one supporting a bicycle pedal (see Figure 2.20), to provide enough support for the pressure h = 4" d = 8' Figure 2.18 Calculating a symmetrical wooden beam’s maximum load 99 Chapter 2 Programming Projects
  • 120. exerted by the rider’s foot yet not exceed the stress placed on the crank arm’s sprocket attachment, is provided by this formula: r d P S 3 = × × π r is the radius of the cylindrical rod in inches. d is the length of the crank arm in inches. P is the weight placed on the pedal in lbs. S is the stress in lbs/in2 . Using this information, design, write, compile, and execute a C++ program that computes the value of r for a crank arm that is 7 inches long, accommodates a maximum weight of 300 lbs, and is able to sustain a stress of 10,000 lbs/in2 . L h d Figure 2.19 Calculating an I-beam’s maximum load d Figure 2.20 Determining the minimum radius of a bicycle’s crank arm 100 Problem Solving Using C++
  • 121. Engineering and Scientific Disciplines Thermal Science Thermal science is the field of engineering that includes both thermodynamics and heat transfer. Thermodynamics developed as a science, starting in the early 19th cen- tury, in response to the development of steam engines at that time. The intent was to understand the physical laws governing these engines in an effort to increase their efficiency. This led to analyzing and understanding the effects of temperature, pressure, and volume on steam engines and how heat moved from a hot boiler to a colder con- denser and the maximum amount of work that could be generated from this flow. It now constitutes a science that includes four basic laws, known as the 0th, 1st, 2nd, and 3rd laws of thermodynamics. Using these four laws, thermodynamics more broadly applies to large-scale systems, such as a class of engines (diesel, gas turbine, jet, rocket, and so forth) or the complete solar system. The central concept of these thermodynamic laws is energy, which is the ability to do work, and the relationship between heat, energy, and work. The fields of chemistry, chemical engineering, aerospace, mechanical engineering, biomedical engi- neering, material science, fluid mechanics, and physics make use of thermodynamic effects. Heat transfer, a field derived from the 1st and 2nd laws of thermodynamics, is technically defined as the movement of energy between substances of different temperatures. Central to heat transfer is the concept of temperature, which is a mea- surement of the motion of atoms and molecules in a substance. Temperature deter- mines the direction of heat flow between two objects placed in contact. If no heat flow occurs, the two objects have the same temperature (a consequence of the 1st law); otherwise, heat flows from the hotter object to the colder object (a consequence of the 2nd law). Heat transfer uses these three modes of transfer: 앫 Conduction is the transfer of heat through a substance caused by molecular movement in the substance. Examples are the transfer of heat through a metal rod if one side of the rod is at a higher temperature than the other, and heat loss through a heated house when the outside temperature is colder than the inside. 앫 Convection is the transfer of heat by the motion of a heated fluid, such as water or air. An example is the expansion of hot air into cooler air. 앫 Radiation is the transfer of heat away from an object emitting electromagnetic waves. An example is the electromagnetic waves emitted by the sun. Each transfer occurs over time, so heat transfer calculations are typically concerned with determining the rate of transfer initially. Given the rate, the total amount of heat transferred over a fixed interval of time can always be calculated. 101 Chapter 2 Programming Projects
  • 122. This page intentionally left blank
  • 123. Chapter 3 Assignment, Formatting, and Interactive Input 3.1 Assignment Operations 3.2 Formatting Numbers for Program Output 3.3 Using Mathematical Library Functions 3.4 Program Input Using cin 3.5 Symbolic Constants 3.6 A Case Study: Acid Rain 3.7 A Closer Look: Programming Errors 3.8 Common Programming Errors 3.9 Chapter Summary In Chapter 2, you explored how results are displayed with C++’s cout statement and how numerical data is stored and processed by using variables and assignment statements. In this chapter, you complete your introduction to C++ by learning about additional processing and input capabilities. 3.1 Assignment Operations You learned about simple assignment statements in Chapter 2. An assignment statement is the most basic C++ statement for assigning values to variables and performing computations. This statement has the following syntax: variable = expression;
  • 124. The simplest expression in C++ is a single constant. In the following assignment statements, the operand to the right of the equal sign is a constant: length = 25; width = 17.5; In these assignment statements, the value of the constant to the right of the equal sign is assigned to the variable on the left of the equal sign. Note that the equal sign in C++ doesn’t have the same meaning as an equal sign in algebra. The equal sign in an assignment statement tells the computer first to determine the value of the operand to the right of the equal sign, and then to store (or assign) that value in the locations associated with the variable to the left of the equal sign. For example, the C++ statement length = 25; is read “length is assigned the value 25.” The blank spaces in the assignment statement are inserted for readability only. Recall that a variable can be initialized when it’s declared. If an initialization isn’t done in the declaration statement, the variable should be assigned a value with an assignment statement or input operation before it’s used in any computation. Subsequent assignment statements can, of course, be used to change the value assigned to a variable. For example, assume the following statements are executed one after another, and slope wasn’t initialized when it was declared: slope = 3.7; slope = 6.28; The first assignment statement assigns the value of 3.7 to the variable named slope.1 The next assignment statement causes the computer to assign a value of 6.28 to slope. The 3.7 that was in slope is overwritten with the new value of 6.28 because a variable can store only one value at a time. Sometimes it’s useful to think of the variable to the left of the equal sign as a temporary parking spot in a huge parking lot. Just as a parking spot can be used by only one car at a time, each variable can store only one value at a time. “Parking” a new value in a variable automatically causes the program to remove any value parked there previously. In addition to being a constant, the operand to the right of the equal sign in an assignment statement can be a variable or any other valid C++ expression. An expression is any combination of constants, variables, and function calls that can be evaluated to yield a result. Therefore, the expression in an assignment statement can be used to perform calculations by using the arithmetic operators introduced in Section 2.4. The following are examples of assignment statements using expressions containing these operators: sum = 3 + 7; diff = 15 – 6; product = .05 * 14.6; tally = count + 1; newtotal = 18.3 + total; taxes = .06 * amount; totalWeight = factor * weight; average = sum / items; slope = (y2 - y1) / (x2 - x1); 1 Because it’s the first time a value is explicitly assigned to this variable, it’s often referred to as an “initialization.” This term stems from historical usage that said a variable was initialized the first time a value was assigned to it. Under this usage, it’s correct to say that “slope is initialized to 3.7.” From an implementation viewpoint, however, this statement is incorrect because the C++ compiler handles an assignment operation differently from an initialization; an initialization can happen only when a variable is created by a declaration statement. This difference is important only when using C++’s class features and is explained in detail in Section 10.1. 104 Assignment, Formatting, and Interactive Input
  • 125. As always in an assignment statement, the program first calculates the value of the expression to the right of the equal sign, and then stores this value in the variable to the left of the equal sign. For example, in the assignment statement totalWeight = factor * weight;, the arithmetic expression factor * weight is evaluated first to yield a result. This result, which is a number, is then stored in the variable totalWeight. In writing assignment expressions, you must be aware of two important considerations. Because the expression to the right of the equal sign is evaluated first, all variables used in the expression must previously have been given valid values if the result is to make sense. For example, the assignment statement totalWeight = factor * weight; causes a valid number to be stored in totalWeight only if the programmer takes care to assign valid numbers first to factor and then to weight. Therefore, the following sequence of statements tells you the values used to obtain the result that will be stored in totalWeight: factor = 1.06; weight = 155.0; totalWeight = factor * weight; Figure 3.1 illustrates the values stored in the variables factor, weight, and totalWeight. The second consideration is that because the value of an expression is stored in the variable to the left of the equal sign, only one variable can be listed in this position. For example, the assignment statement amount + 1892 = 1000 + 10 * 5; is invalid. The expression on the right evaluates to the integer 1050, which can only be stored in a variable. Because amount + 1892 isn’t a valid variable name, the compiler doesn’t know where to store the calculated value. Program 3.1 illustrates using assignment statements to calculate the volume of a cylinder. As shown in Figure 3.2, the volume of a cylinder is determined by the formula volume = ␲r 2 h, where r is the radius of the cylinder, h is the height, and ␲ is the constant 3.1416 (accurate to four decimal places). 1.06 155.0 164.30 factor weight totalWeight Figure 3.1 Values stored in variables h = 16 r = 2.5 Figure 3.2 Determining the volume of a cylinder 105 Chapter 3 Assignment Operations
  • 126. Program 3.1 // this program calculates the volume of a cylinder, // given its radius and height #include <iostream> using namespace std; int main() { double radius, height, volume; radius = 2.5; height = 16.0; volume = 3.1416 * radius * radius * height; cout << "The volume of the cylinder is " << volume << endl; return 0; } When Program 3.1 is compiled and executed, this is the output: The volume of the cylinder is 314.16 Take a look at the flow of control the computer uses in executing Program 3.1. Program execution begins with the first statement in the body of the main() function and continues sequentially, statement by statement, until the closing brace of main() is encountered. This sequential flow of control is true for all programs. The computer works on one statement at a time, executing that statement with no knowledge of what the next statement will be. This sequential execution explains why all operands used in an expression must have values assigned to them before the expression is evaluated. When the computer executes this statement in Program 3.1, volume = 3.1416 * radius * radius * height; it uses whatever value is stored in the variables radius and height at the time the assignment statement is executed.2 If no values have been specifically assigned to these variables before they’re used in the assignment statement, the computer uses whatever values happen to occupy these variables when they are referenced. (Most C++ compilers initialize all variables to zero automatically.) The computer doesn’t “look ahead” to see whether you assign values to these variables later in the program. In C++, the equal sign, =, used in assignment statements is an operator, which differs from the way most other high-level languages process this symbol. In C++ (as in C), the = symbol is called the assignment operator, and an expression using this operator, such as interest = principal * rate, is an assignment expression. Because the assignment 2 Because C++ doesn’t have an exponentiation operator, the square of the radius is obtained by the term radius * radius. Section 3.3 introduces C++’s power function pow(), which allows you to raise a number to a power. 106 Assignment, Formatting, and Interactive Input
  • 127. operator has a lower precedence than any other arithmetic operator, the value of any expression to the right of the equal sign is evaluated first, before the assignment. Like all expressions, an assignment expression has a value, which is the value assigned to the variable on the left of the assignment operator. For example, the expression a = 5 assigns a value of 5 to the variable a and results in the expression also having a value of 5. The expression’s value can always be verified by using a statement such as the following: cout << "The value of the expression is " << (a = 5); This statement displays the value of the expression, not the contents of the variable a. Although both the variable’s contents and the expression have the same value, it’s worth realizing that you’re dealing with two distinct entities. From a programming perspective, it’s the actual assignment of a value to a variable that’s important in an assignment expression; the final value of the assignment expression is of little consequence. However, the fact that assignment expressions have a value has implications that must be considered when you learn about C++’s relational operators, which are explained in the next chapter (Section 4.1). Any expression terminated by a semicolon becomes a C++ statement. The most common example is the assignment statement, which is simply an assignment expression terminated with a semicolon. For example, terminating the assignment expression a = 33 with a semicolon results in the assignment statement a = 33;, which can be used in a program on a line by itself. Because the equal sign is an operator in C++, multiple assignments are possible in the same expression or its equivalent statement. For example, in the expression a = b = c = 25, all the assignment operators have the same precedence. Because the assignment operator has a right-to-left associativity, the final evaluation proceeds in this sequence: c = 25 b = c a = b This sequence of expressions, which has the effect of assigning the number 25 to each variable, can be represented as: a = (b = (c = 25)) Appending a semicolon to the original expression results in this multiple assignment statement: a = b = c = 25; This statement assigns the value 25 to the three variables, equivalent to the following order: c = 25; b = 25; a = 25; Coercion When working with assignment statements, keep in mind the data type assigned to values on both sides of the expression because data type conversions occur across assignment operators. In other words, the value of the expression to the right of the assignment operator is converted to the data type of the variable to the left of the assignment operator. This type 107 Chapter 3 Assignment Operations
  • 128. of conversion is called a coercion because the value assigned to the variable on the left side of the assignment operator is forced into the data type of the variable to which it’s assigned. An example of a coercion occurs when an integer value is assigned to a real variable; this assignment causes the integer to be converted to a real value. Similarly, assigning a real value to an integer variable forces conversion of the real value to an integer, which always results in losing the fractional part of the number because of truncation. For example, if temp is an integer variable, the assignment temp = 25.89 causes the integer value 25 to be stored in the integer variable temp.3 A more complete example of data type conversions, which includes both mixed-mode and assignment conversion, is the evaluation of the expression a = b * d where a and b are integer variables and d is a single-precision variable. When the mixed-mode expression b * d is evaluated,4 the value of d used in the expression is converted to a double-precision number for purposes of computation. (The value stored in d remains a single-precision number.) Because one of the operands is a double-precision variable, the value of the integer variable b is converted to a double-precision number for the computation. (Again, the value stored in b remains an integer.) The resulting value of the expression b * d is a double-precision number. Finally, data type conversion across the assignment operator comes into play. Because the left side of the assignment operator is an integer variable, the double- precision value of the expression (b * d) is truncated to an integer value and stored in the variable a. Assignment Variations Although only one variable is allowed immediately to the left of the equal sign in an assignment expression, the variable to the left of the equal sign can also be used to the right. For example, the assignment expression sum = sum + 10 is valid. Clearly, as an algebraic equation, sum could never be equal to itself plus 10. In C++, however, sum = sum + 10 is not an equation—it’s an expression evaluated in two major steps: First, the value of sum 3 The correct integer portion is retained only when it’s within the range of integers the compiler allows. 4 Review the precedence and associativity rules in Section 2.4 for the evaluation of mixed-mode expressions, if necessary. Point of Information lvalues and rvalues The terms lvalue and rvalue are often used in programming technology. These terms are language independent and are used to designate the following: An lvalue can have a value assigned to it, but an rvalue can’t. In both C and C++, an lvalue can appear on both the left and right sides of an assignment operator, but an rvalue can appear only to the right of an assignment operator. All the variables you have encountered can be an lvalue or rvalue, but a number can be only an rvalue. Not all variables, however, can be lvalues and rvalues. For example, an array type, introduced in Chapter 7, can’t be an lvalue or rvalue, but elements in an array can be both. 108 Assignment, Formatting, and Interactive Input
  • 129. + 10 is calculated, and second, the computed value is stored in sum. See whether you can determine the output of Program 3.2. Program 3.2 #include <iostream> using namespace std; int main() { int sum; sum = 25; cout << "The number stored in sum is " << sum << endl; sum = sum + 10; cout << "The number now stored in sum is " << sum << endl; return 0; } In Program 3.2, the assignment statement sum = 25; tells the computer to store the number 25 in sum, as shown in Figure 3.3. The first cout statement displays the value stored in sum with the message The number stored in sum is 25. The second assignment statement, sum = sum + 10;, causes the program to retrieve the 25 stored in sum and add 10 to this number, yielding 35. The number 35 is then stored in the variable to the left of the equal sign, which is the variable sum. The 25 that was in sum is simply overwritten with the new value of 35 (see Figure 3.4). 25 sum Figure 3.3 The integer 25 is stored in sum 25 sum New value (35) is stored Old value is overwritten Figure 3.4 sum = sum + 10; causes a new value to be stored in sum 109 Chapter 3 Assignment Operations
  • 130. Assignment expressions such as sum = sum + 25, which use the same variable on both sides of the assignment operator, can be written by using the following shortcut assignment operators: += –= *= /= %= For example, the expression sum = sum + 10 can be written as sum += 10. Similarly, the expression price *= rate is equivalent to the expression price = price * rate. In using these new assignment operators, note that the variable to the left of the assignment operator is applied to the complete expression on the right. For example, the expression price *= rate + 1 is equivalent to the expression price = price * (rate + 1), not price = price * rate + 1. Accumulating Assignment expressions, such as sum += 10 or its equivalent, sum = sum + 10, are common in programming. These expressions are required in accumulating subtotals when data is entered one number at a time. For example, if you want to add the numbers 96, 70, 85, and 60 in calculator fashion, the following statements could be used: Statement Value in sum sum = 0; 0 sum = sum + 96; 96 sum = sum + 70; 166 sum = sum + 85; 251 sum = sum + 60; 311 The first statement initializes sum to 0, which removes any number stored in sum that would invalidate the final total (a “garbage value”). As each number is added, the value stored in sum is increased accordingly. After completion of the last statement, sum contains the total of all the added numbers. Program 3.3 illustrates the effect of these statements by displaying sum’s contents after each addition. 110 Assignment, Formatting, and Interactive Input
  • 131. Program 3.3 #include <iostream> using namespace std; int main() { int sum; sum = 0; cout << "The value of sum is initially set to " << sum << endl; sum = sum + 96; cout << " sum is now " << sum << endl; sum = sum + 70; cout << " sum is now " << sum << endl; sum = sum + 85; cout << " sum is now " << sum << endl; sum = sum + 60; cout << " The final sum is " << sum << endl; return 0; } Program 3.3 displays this output: The value of sum is initially set to 0 sum is now 96 sum is now 166 sum is now 251 The final sum is 311 Although Program 3.3 isn’t a practical program (because adding the numbers by hand is easier), it does illustrate the subtotaling effect of repeated use of statements having this form: variable = variable + newValue; This type of statement is called an accumulation statement. You’ll find many uses for accumulation statements when you become more familiar with the repetition statements introduced in Chapter 5. Counting The counting statement, which is an assignment statement similar to the accumulating statement, has the following form: variable = variable + fixedNumber; 111 Chapter 3 Assignment Operations
  • 132. Examples of counting statements are as follows: i = i + 1; n = n + 1; count = count + 1; j = j + 2; m = m + 2; kk = kk + 3; In these examples, the same variable is used on both sides of the equal sign. After the statement is executed, the value of the variable is increased by a fixed amount. In the first three examples, the variables i, n, and count have been increased by one. In the next two examples, the variables have been increased by two, and in the final example, the variable kk has been increased by three. For the case in which a variable is increased or decreased by only one, C++ provides two unary operators: increment and decrement operators. Using the increment operator,5 ++, the expression variable = variable + 1 can be replaced by the expression variable++ or the expression ++variable. Here are examples of the increment operator: Expression Alternative i = i + 1 i++ or ++i n = n + 1 n++ or ++n count = count + 1 count++ or ++count Program 3.4 illustrates the use of the increment operator. 5 As a historical note, the ++ in C++’s name was inspired by the increment operator symbol. It was used to indicate that C++ was the next increment to the C language. 112 Assignment, Formatting, and Interactive Input
  • 133. Program 3.4 #include <iostream> using namespace std; int main() { int count; count = 0; cout << "The initial value of count is " << count << endl; count++; cout << " count is now " << count << endl; count++; cout << " count is now " << count << endl; count++; cout << " count is now " << count << endl; count++; cout << " count is now " << count << endl; return 0; } This is the output displayed by Program 3.4: The initial value of count is 0 count is now 1 count is now 2 count is now 3 count is now 4 When the ++ operator appears before a variable, it’s called a prefix increment operator; when it appears after a variable, it’s called a postfix increment operator. The distinction between a prefix and postfix increment operator is important when the variable being incremented is used in an assignment expression. For example, k = ++n, which uses a prefix increment operator, does two things in one expression: The value of n is incremented by one, and then the new value of n is assigned to the variable k. Therefore, the statement k = ++n; is equivalent to these two statements: n = n + 1; // increment n first k = n; // assign n's value to k The assignment expression k = n++, which uses a postfix increment operator, reverses this procedure. A postfix increment operator works after the assignment is completed. Therefore,the statement k = n++; first assigns the current value of n to k, and then increments the value of n by one. This process is equivalent to these two statements: 113 Chapter 3 Assignment Operations
  • 134. k = n; // assign n's value to k n = n + 1; // and then increment n C++ also provides the decrement operator, --, in prefix and postfix variations. As you might expect, both the expressions variable-- and --variable are equivalent to the expression variable = variable - 1. Here are examples of the decrement operator: Expression Alternative i = i - 1 i-- or --i n = n - 1 n-- or --n count = count - 1 count-- or –-count When the -- operator appears before a variable, it’s called a prefix decrement operator. When this operator appears after a variable, it’s called a postfix decrement operator. For example, both the expressions n-- and --n reduce the value of n by one and are equivalent to the longer expression n = n - 1. As with the increment operators, however, the prefix and postfix decrement operators produce different results when used in assignment expressions. For example, the expression k = --n first decrements the value of n by one before assigning the value of n to k, and the expression k = n-- first assigns the current value of n to k, and then reduces the value of n by one. EXERCISES 3.1 1. (General Math) Write an assignment statement to calculate the circumference of a circle having a radius of 3.3 inches. The formula for determining the circumference, c, of a circle is c = 2␲r, where r is the radius and ␲ equals 3.1416. 2. (General Math) Write an assignment statement to calculate the area of a circle. The for- mula for determining the area, a, of a circle is a = ␲r2 , where r is the radius and ␲ = 3.1416. 3. (Conversion) Write an assignment statement to convert temperature in degrees Fahrenheit to degrees Celsius. The formula for this conversion is Celsius = 5/9 (Fahrenheit - 32). 4. (General Math) Write an assignment statement to calculate the round-trip distance, d, in feet, of a trip that’s s miles long one way. 5. (Physics) Write an assignment statement to calculate the elapsed time, in minutes, it takes to make a trip. The formula for computing elapsed time is elapsed time = total distance / average speed. Assume the distance is in miles and the average speed is in miles per hour (mph). 6. (Numerical) Write an assignment statement to calculate the nth term in an arithmetic sequence. This is the formula for calculating the value, v, of the nth term: v = a + (n - 1)d 114 Assignment, Formatting, and Interactive Input
  • 135. d is the difference between any two numbers in the sequence. a is the first number in the sequence. 7. (Civil Eng.) Write an assignment statement to calculate the linear expansion in a steel beam as a function of temperature increase. The formula for linear expansion, l, is as follows: l = l0[1 + ␣ (Tf - T0)] l0 is the length of the beam at temperature T0. ␣ is the coefficient of linear expansion. Tf is the final temperature of the beam. 8. (Physics) Coulomb’s Law states that the force, F, acting between two electrically charged spheres is given by this formula: F k q q r = 1 2 2 q1 is the charge on the first sphere. q2 is the charge on the second sphere. r is the distance between the centers of the two spheres. k is a proportionality constant. Write an assignment statement to calculate the force, F. 9. (Civil Eng.) Write an assignment statement to determine the maximum bending moment, M, of a beam, given this formula: M X W L X L = ( ) - X is the distance from the end of the beam that a weight, W, is placed. L is the length of the beam. 10. (Desk Check) Determine the output of the following program: #include <iostream> using namespace std; int main() // a program illustrating integer truncation { int num1, num2; num1 = 9/2; num2 = 17/4; cout << "the first integer displayed is " << num1 << endl; cout << "the second integer displayed is " << num2 << endl; return 0; } 115 Chapter 3 Assignment Operations
  • 136. 11. (Debug) Determine and correct the errors in the following programs. a. #include <iostream> using namespace std; int main() { width = 15 area = length * width; cout << "The area is " << area } b. #include <iostream> using namespace std; int main() { int length, width, area; area = length * width; length = 20; width = 15; cout << "The area is " << area; return 0; c. #include <iostream.h> int main() { int length = 20; width = 15, area; length * width = area; cout << "The area is " , area; return 0; } 12. (Debug) By mistake, a student reordered the statements in Program 3.3 as follows: #include <iostream> using namespace std; int main() { int sum; sum = 0; sum = sum + 96; sum = sum + 70; sum = sum + 85; sum = sum + 60; cout << "The value of sum is initially set to " << sum << endl; cout << " sum is now " << sum << endl; cout << " sum is now " << sum << endl; cout << " sum is now " << sum << endl; cout << " The final sum is " << sum << endl; return 0; } Determine the output this program produces. 116 Assignment, Formatting, and Interactive Input
  • 137. 13. (General Math) Using Program 3.1, complete the following chart by determining the volume of cylinders having these radii and heights: Radius (in) Height (in) Volume 1.62 6.23 2.86 7.52 4.26 8.95 8.52 10.86 12.29 15.35 14. (General Math) The area of an ellipse (see Figure 3.5) is given by this formula: Area = ␲ a b Using this formula, write a C++ program to calculate the area of an ellipse having a minor axis, a, of 2.5 inches and a major axis, b, of 6.4 inches. 15. (Modify) Modify Program 3.1 to calculate the weight, in pounds, of the steel cylinder whose volume was determined in that program. This is the formula for determining the weight: weight = 0.28 (␲)(r 2 )(h) r is the radius (in inches). h is the height (in inches) of the cylinder. 3.2 Formatting Numbers for Program Output Besides displaying correct results, a program should present its results attractively. Most programs are judged on the perceived ease of data entry and the style and presentation of the output. For example, displaying a monetary result as 1.897 isn’t in keeping with accepted report conventions. The display should be $1.90 or $1.89, depending on whether rounding or truncation is used. a b Figure 3.5 The minor axis, a, and the major axis, b, of an ellipse 117 Chapter 3 Formatting Numbers for Program Output
  • 138. To control the format of numbers displayed by cout, you can include field width manipulators in an output stream. Table 3.1 lists the most common stream manipulators for this purpose.6 Table 3.1 Commonly Used Stream Manipulators Manipulator Action setw(n) Set the field width to n. setprecision(n) Set the floating-point precision to n places. If the fixed manipulator is designated, n specifies the total number of displayed digits after the decimal point; otherwise, n specifies the total number of significant digits displayed (integer plus fractional digits). setfill('x') Set the default leading fill character to x. (The default leading fill character is a space, which is used to fill the beginning of an output field when the field width is larger than the value being displayed.) setiosflags (flags) Set the format flags. (See Table 3.3 for flag settings.) scientific Set the output to display real numbers in scientific notation. showbase Display the base used for numbers. A leading 0 is displayed for octal numbers and a leading 0x for hexadecimal numbers. showpoint Always display six digits total (combination of integer and fractional parts). Fill with trailing zeros, if necessary. For larger integer values, revert to scientific notation. showpos Display all positive numbers with a leading + sign. boolalpha Display Boolean values as true and false rather than 1 and 0. dec Set the output for decimal display, which is the default. endl Output a newline character and display all characters in the buffer. fixed Always show a decimal point and use a default of six digits after the decimal point. Fill with trailing zeros, if necessary. flush Display all characters in the buffer. left Left-justify all numbers. hex Set the output for hexadecimal display. oct Set the output for octal display. uppercase Display hexadecimal digits and the exponent in scientific notation in uppercase. right Right-justify all numbers (the default). noboolalpha Display Boolean values as 1 and 0 rather than true and false. noshowbase Don’t display octal numbers with a leading 0 and hexadecimal numbers with a leading 0x. 6 As noted in Chapter 2, the endl manipulator inserts a new line and then forces all current insertions to be displayed immediately, called “flushing the stream.” 118 Assignment, Formatting, and Interactive Input
  • 139. Table 3.1 Commonly Used Stream Manipulators (continued) Manipulator Action noshowpoint Don’t use a decimal point for real numbers with no fractional parts, don’t display trailing zeros in the fractional part of a number, and display a maximum of six decimal digits only. noshowpos Don’t display leading + signs (the default). nouppercase Display hexadecimal digits and the exponent in scientific notation in lowercase. For example, the statement cout << "The sum of 6 and 15 is" << setw(3) << 21; creates this printout: The sum of 6 and 15 is 21 The setw(3) field width manipulator included in the data stream sent to cout is used to set the displayed field width. The 3 in this manipulator sets the default field width for the next number in the stream to be three spaces. This field width setting causes the 21 to beprinted in a field of three spaces, which includes one blank and the number 21. As shown in this output, integers are right-justified in the specified field. Field width manipulators are useful in printing columns of numbers so that the numbers align correctly in each column. For example, Program 3.5 shows how a column of integers aligns in the absence of field width manipulators. Program 3.5 #include <iostream> using namespace std; int main() { cout << 6 << endl << 18 << endl << 124 << endl << "---n" << (6+18+124) << endl; return 0; } 119 Chapter 3 Formatting Numbers for Program Output
  • 140. The output of Program 3.5 is the following: 6 18 124 --- 148 Because no field width manipulators are used in Program 3.5, cout allocates enough space for each number as it’s received. Forcing numbers to align on the units digit requires a field width wide enough for the largest displayed number, which is three for the numbers in Program 3.5. Program 3.6 shows the use of this field width. Program 3.6 #include <iostream> #include <iomanip> using namespace std; int main() { cout << setw(3) << 6 << endl << setw(3) << 18 << endl << setw(3) << 124 << endl << "---n" << (6+18+124) << endl; return 0; } The output of Program 3.6 is as follows: 6 18 124 --- 148 The field width manipulator must be included for each occurrence of a number inserted in the data stream sent to cout; the manipulator applies only to the next insertion of data immediately following it, and the other manipulators remain in effect until they’re changed. When a manipulator requiring an argument is used, the iomanip header file must be included as part of the program. To do this, you use the preprocessor command #include <iomanip>, which is the second line in Program 3.6. 120 Assignment, Formatting, and Interactive Input
  • 141. Formatting floating-point numbers requires using three field width manipulators. The first manipulator sets the total width of the display, the second manipulator forces the display of a decimal point, and the third manipulator determines how many significant digits are displayed to the right of the decimal point. (See the “Point of Information” box in Chapter 2 for a review of significant digits.) For example, examine the following statement: cout << "|" << setw(10) << fixed << setprecision(3) << 25.67 << "|"; It causes the following printout: | 25.670| The bar symbol, |, in this example is used to delimit (mark) the beginning and end of the display field. The setw manipulator tells cout to display the number in a total field of 10. (With real numbers, the decimal point takes up one of these field locations.) The fixed manipulator forces the display of a decimal point and specifies using the setprecision manipulator to designate the number of digits displayed after the decimal point. In this case, setprecision specifies a display of three digits after the decimal point. Without the explicit designation of a decimal point (which can also be designated as setiosflags(ios::fixed), explained shortly), the setprecision manipulator speci- fies the total number of displayed digits, which includes the integer and fractional parts of the number. For all numbers (integers, single-precision, and double-precision), cout ignores the setw manipulator specification if the total specified field width is too small, and it allocates enough space for printing the integer part of the number. The fractional part of single- precision and double-precision numbers is displayed up to the precision set with the setprecision manipulator. (In the absence of setprecision, the default precision is set to six decimal places.) If the fractional part of the number to be displayed contains more digits than are called for in the setprecision manipulator, the number is rounded to the indicated number of decimal places; if the fractional part contains fewer digits than specified, the number is displayed with fewer digits. Table 3.2 shows the effect of several format manipulator combinations. For clarity, the bar symbol delimits the beginning and end of output fields. Table 3.2 Effect of Format Manipulators Manipulators Number Display Comments setw(2) 3 | 3| Number fits in the field. setw(2) 43 |43| Number fits in the field. setw(2) 143 |143| Field width is ignored. setw(2) 2.3 |2.3| Field width is ignored. setw(5) fixed setprecision(2) 2.366 | 2.37| Field width of five with two decimal digits. setw(5) fixed setprecision(2) 42.3 |42.30| Number fits in the field with the specified precision. Note that the decimal point takes up one location in the field width. setw(5) setprecision(2) 142.364 |1.4e+002| Field width is ignored, and scientific notation is used with the setprecision manipulator. 121 Chapter 3 Formatting Numbers for Program Output
  • 142. Table 3.2 Effect of Format Manipulators (continued) Manipulators Number Display Comments setw(5) fixed setprecision(2) 142.364 |142.36| Field width is ignored, but precision specification is used. The setprecision manipulator specifies the number of fractional digits. setw(5) fixed setprecision(2) 142.366 |142.37| Field width is ignored, but precision specification used. The setprecision manipulator specifies the number of fractional digits. (Note the rounding of the last decimal digit.) setw(5) fixed setprecision(2) 142 | 142| Field width is used; fixed and setprecision manipulators are irrelevant because the number is an integer that specifies the total number of significant digits (integer plus fractional digits). In addition to the setw and setprecision manipulators, a field justification manipu- lator is available. As you have seen, numbers sent to cout are normally right-justified in the display field, and strings are left-justified. To alter the default justification for a stream of data, you use the setiosflags manipulator. For example, the statement cout << "|" << setw(10) << setiosflags(ios::left) << 142 << "|"; causes the following left-justified display: |142 | Because data sent to cout can be continued across multiple lines, the previous display is also produced by this statement: cout << "|" << setw(10) << setiosflags(ios::left) << 142 << "|"; As always, the field width manipulator is in effect only for the next set of data displayed by cout. To right-justify strings in a stream, you use the setiosflags(ios::right) manipulator. The letters “ios” in the function name and the ios::right argument come from the first letters of the words “input output stream.” In addition to the left and right flags that can be used with setiosflags(), other flags can be used to affect output. Table 3.3 lists the most commonly used flags for this manipulator function. The flags in this table provide another way of setting the manipulators listed in Table 3.1. 122 Assignment, Formatting, and Interactive Input
  • 143. Table 3.3 Format Flags for Use with setiosflags() Flag Meaning ios::fixed Always show the decimal point with six digits after the decimal point. Fill with trailing zeros after the decimal point, if necessary. This flag takes precedence if it’s set with the ios::showpoint flag. ios::scientific Use exponential display in the output. ios::showpoint Always display a decimal point and six significant digits total (combination of integer and fractional parts). Fill with trailing zeros after the decimal point, if necessary. For larger integer values, revert to scientific notation unless the ios::fixed flag is set. ios::showpos Display a leading + sign when the number is positive. ios::left Left-justify the output. ios::right Right-justify the output. Because the flags in Table 3.3 are used as arguments to setiosflags() and the terms “argument” and “parameter” are synonymous, another name for a manipulator method that uses arguments is a parameterized manipulator. The following is an example of a parameter- ized manipulator method: cout << setiosflags(ios::showpoint) << setprecision(4); This statement forces all subsequent floating-point numbers sent to the output stream to be displayed with a decimal point and four decimal digits. If the number has fewer than four decimal digits, it’s padded with trailing zeros. Point of Information What Is a Flag? In current programming usage, the term flag refers to an item, such as a variable or argument, that sets a condition usually considered active or nonactive. Although the exact origin of this term in programming is unknown, it probably came from using real flags to signal a condition, such as the Stop, Go, Caution, and Winner flags commonly used at car races. In a similar manner, each flag argument for the setiosflags() manipulator function activates a specific condition. For example, the ios::dec flag sets the display format to decimal, and the ios::oct flag activates the octal display format. Because these conditions are mutually exclusive (only one can be active at a time), activating this type of flag deactivates the other flags automatically. Flags that aren’t mutually exclusive, such as ios::dec, ios::showpoint, and ios::fixed, can be set simultaneously. You can do this by using three separate setiosflag() calls or combining all arguments into one call as follows: cout << setiosflags(ios::dec | ios::fixed | ios::showpoint); 123 Chapter 3 Formatting Numbers for Program Output
  • 144. In addition to outputting integers in decimal notation, the oct and hex manipulators are used for conversions to octal and hexadecimal; Program 3.7 uses these flags. Because decimal is the default display, the dec manipulator isn’t required in the first output stream. Program 3.7 // a program that illustrates output conversions #include <iostream> #include <iomanip> using namespace std; int main() { cout << "The decimal (base 10) value of 15 is " << 15 << endl; cout << "The octal (base 8) value of 15 is " << showbase << oct << 15 <<endl; cout << "The hexadecimal (base 16) value of 15 is " << showbase << hex << 15 << endl; return 0; } The output produced by Program 3.7 is the following: The decimal (base 10) value of 15 is 15 The octal (base 8) value of 15 is 017 The hexadecimal (base 16) value of 15 is 0xf The display of integer values in one of three possible number systems (decimal, octal, and hexadecimal) doesn’t affect how the number is stored in a computer. All numbers arestored by using the computer’s internal codes. The manipulators sent to cout tell the object how to convert the internal code for output display purposes. Besides displaying integers in octal or hexadecimal form, they can also be written in a program in these forms. To designate an octal integer, the number must have a leading zero. The number 023, for example, is an octal number in C++. Hexadecimal numbers are denoted with a leading 0x. Program 3.8 shows how octal and hexadecimal integer numbers are used and produces the following output: The decimal value of 025 is 21 The decimal value of 0x37 is 55 124 Assignment, Formatting, and Interactive Input
  • 145. Program 3.8 #include <iostream> using namespace std; int main() { cout << "The decimal value of 025 is " << 025 << endl << "The decimal value of 0x37 is "<< 0x37 << endl; return 0; } Point of Information Formatting cout Stream Data Floating-point data in a cout output stream can be formatted in precise ways. For example, a common format requirement is to display monetary amounts with two digits after the decimal point, such as 123.45. You can do this with the following statement: cout << setiosflags(ios::fixed) << setiosflags(ios::showpoint) << setprecision(2); The first manipulator flag, ios::fixed, forces all floating-point numbers in the cout stream to be displayed in decimal notation. This flag also prevents using scientific notation. The next flag, ios::showpoint, tells the stream to always display a deci- mal point. Finally, the setprecision manipulator tells the stream to always display two digits after the decimal point. Instead of using manipulators, you can use the cout stream methods setf() and precision(). For example, the previous format- ting can also be accomplished with this code: cout.setf(ios::fixed); cout.setf(ios::showpoint); cout.precision(2); Note the syntax: The name of the object, cout, is separated from the method with a period. This format is the standard way of specifying a method and connecting it to a specific object. Additionally, the flags used in both the setf() method and the setiosflags() manipulator method can be combined by using the bitwise OR operator, | (explained in Section 15.2). Using this operator, the following two statements are equivalent: cout << setiosflags(ios::fixed | ios::showpoint); cout.setf(ios::fixed | ios::showpoint); The statement you select is a matter of personal preference or a predefined imposed standard. 125 Chapter 3 Formatting Numbers for Program Output
  • 146. The relationship between input, storage, and display of integers is illustrated in Figure 3.6. Finally, you can set the manipulators listed in Tables 3.1 and 3.2 by using the ostream class functions listed in Table 3.4. Table 3.4 ostream Class Functions Method Comment Example precision(n) Equivalent to setprecision() cout.precision(2) fill('x') Equivalent to setfill() cout.fill('*') setf(ios::fixed) Equivalent to cout.setf(ios::fixed) setiosflags(ios:: fixed) setf(ios:: showpoint) Equivalent to cout.setf(ios::showpoint) setiosflags(ios:: showpoint) setf(iof::left) Equivalent to left cout.setf(ios:: left) internal number code convert an octal number convert a decimal number convert a hexadecimal number convert to octal representation convert to decimal representation convert to hexadecimal representation cout << dec cout << oct cout << hex Display is octal, decimal, or hexadecimal Storage is always in binary Input is octal, decimal, or hexadecimal Integer with a leading 0 Integer with no leading 0 or 0X Integer with a leading 0X Octal display Decimal display Hexadecimal display Figure 3.6 Input, storage, and display of integers 126 Assignment, Formatting, and Interactive Input
  • 147. Table 3.4 ostream Class Functions (continued) Method Comment Example setf(ios::right) Equivalent to right cout.setf(ios:: right) setf(ios::flush) Equivalent to endl cout.setf(ios:: flush) In the Example column of Table 3.4, the name of the object, cout, is separated from the function with a period. As mentioned, this format is the standard way of calling a class function and providing it with an object to operate on. EXERCISES 3.2 1. (Desk Check) Determine the output of the following program: #include <iostream> using namespace std; int main() // a program illustrating integer truncation { cout << "answer1 is the integer " << 9/4 << "nanswer2 is the integer " << 17/3 << endl; return 0; } 2. (Desk Check) Determine the output of the following program: #include <iostream> using namespace std; int main() // a program illustrating the % operator { cout << "The remainder of 9 divided by 4 is " << 9 % 4 << "nThe remainder of 17 divided by 3 is " << 17 % 3 << endl; return 0; } 3. (Practice) Write a C++ program that displays the results of the expressions 3.0 * 5.0, 7.1 * 8.3 - 2.2, and 3.2 / (6.1 * 5). Calculate the value of these expressions manually to verify that the displayed values are correct. 4. (Practice) Write a C++ program that displays the results of the expressions 15 / 4, 15 % 4, and 5 * 3 - (6 * 4). Calculate the value of these expressions manually to verify that the display your program produces is correct. 127 Chapter 3 Formatting Numbers for Program Output
  • 148. 5. (Debug) Determine the errors in the following statements: a. cout << "n << " 15) b. cout << "setw(4)" << 33; c. cout << "setprecision(5)" << 526.768; d. "Hello World!" >> cout; e. cout << 47 << setw(6); f. cout << set(10) << 526.768 << setprecision(2); 6. (Desk Check) Determine and write out the display produced by the following statements: a. cout << "|" << 5 <<"|"; b. cout << "|" << setw(4) << 5 << "|"; c. cout << "|" << setw(4) << 56829 << "|"; d. cout << "|" << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 5.26 << "|"; e. cout << "|" << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 5.267 << "|"; f. cout << "|" << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 53.264 << "|"; g. cout << "|" << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 534.264 << "|"; h. cout << "|" << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 534. << "|"; 7. (Desk Check) Write out the display produced by the following statements: a. cout << "The number is " << setw(6) << setiosflags(ios::fixed) << setprecision(2) << 26.27 << endl; cout << "The number is " << setw(6) << setiosflags(ios::fixed) << setprecision(2) << 682.3 << endl; cout << "The number is " << setw(6) << setiosflags(ios::fixed) << setprecision(2) << 1.968 << endl; b. cout << setw(6) << setiosflags(ios::fixed) << setprecision(2) << 26.27 << endl; cout << setw(6) << setiosflags(ios::fixed) << setprecision(2) << 682.3 << endl; cout << setw(6) << setiosflags(ios::fixed) << setprecision(2) << 1.968 << endl; cout << "------n"; cout << setw(6) << setiosflags(ios::fixed) << setprecision(2) << 26.27 + 682.3 + 1.968 << endl; 128 Assignment, Formatting, and Interactive Input
  • 149. c. cout << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 26.27 << endl; cout << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 682.3 << endl; cout << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 1.968 << endl; cout << "-----n"; cout << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 26.27 + 682.3 + 1.968 << endl; d. cout << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 36.164 << endl; cout << setw(5) << setiosflags(ios::fixed) << setprecision(2) << 10.003 << endl; cout << "-----" << endl; 8. (Desk Check) The following chart lists the equivalent octal and hexadecimal representa- tions for the decimal numbers 1 through 15: Decimal: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Octal: 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 Hexadecimal: 1 2 3 4 5 6 7 8 9 a b c d e f Using this chart, determine the output of the following program: #include <iostream> #include <iomanip> using namespace std; int main() { cout << "nThe value of 14 in octal is " << oct << 14 << "nThe value of 14 in hexadecimal is " << hex << 14 << "nThe value of 0xA in decimal is " << dec << 0xA << "nThe value of 0xA in octal is " << oct << 0xA << endl; return 0; } 9. (Electrical Eng.) The combined resistance of three resistors connected in parallel, as shown in Figure 3.7, is given by this formula: Combined R R R resistance = + +       1 1 1 1 1 2 3 Using this formula, write a C++ program to calculate and display the combined resistance when the three resistors R1 = 1000, R2 = 1000, and R3 = 1000 are connected in parallel. The output should produce this display: The combined resistance is xxxx.xx ohms The xxxx.xx denotes placing the calculated value in a field width of seven columns, with two positions to the right of the decimal point. 129 Chapter 3 Formatting Numbers for Program Output
  • 150. 10. (General Math) Write a C++ program to calculate and display the value of the slope of the line connecting two points with the coordinates (3,7) and (8,12). Use the fact that the slope between two points at the coordinates (x1,y1) and (x2,y2) is slope = (y2 - y1) / (x2 - x1). Your program should produce this display: The value of the slope is xxx.xx The xxx.xx denotes placing the calculated value in a field wide enough for three places to the left of the decimal point and two places to the right of it. 11. (General Math) Write a C++ program to calculate and display the midpoint coordinates of the line connecting the two points with coordinates of (3,7) and (8,12). Use the fact that the midpoint coordinates between two points with the coordinates (x1,y1) and (x2,y2) are ((x1 + x2)/2, (y1 + y2)/2). Your program should produce this display: The x coordinate of the midpoint is xxx.xx The y coordinate of the midpoint is xxx.xx The xxx.xx denotes placing the calculated value in a field wide enough for three places to the left of the decimal point and two places to the right of it. 12. (Civil Eng.) Write a C++ program to calculate and display the maximum bending moment, M, of a beam that’s supported on both ends (see Figure 3.8). The formula is M = XW (L - X) / L, where X is the distance from the end of the beam that a weight, W, is placed, and L is the length of the beam. Your program should produce this display: The maximum bending moment is xxxx.xxxx The xxxx.xxxx denotes placing the calculated value in a field wide enough for four places to the right and left of the decimal point. For your program, assign the values 1.2, 1.3, and 11.2 to X, W, and L. R1 R2 R3 Figure 3.7 Three resistors connected in parallel W L X Figure 3.8 Calculating the maximum bending moment 130 Assignment, Formatting, and Interactive Input
  • 151. 3.3 Using Mathematical Library Functions As you have seen, assignment statements can be used to perform arithmetic computations. For example, the following assignment statement multiplies the value in current by the value in resistance and assigns the resulting value to volts: volts = resistance * current; Although addition, subtraction, multiplication, and division are accomplished easily with C++’s arithmetic operators, no operators exist for raising a number to a power, finding a number’s square root, or determining trigonometric values. To perform these calcula- tions,C++ provides standard preprogrammed functions that can be included in a program. Before using one of C++’s mathematical functions, you need to know the following: • The name of the mathematical function • What the mathematical function does • The type of data the mathematical function requires • The data type of the result the mathematical function returns • How to include the mathematical library To illustrate the use of C++’s mathematical functions, take a look at the mathematical function sqrt(), which calculates a number’s square root and uses this form: sqrt(number) The function’s name, in this case sqrt, is followed by parentheses containing the number for which the square root should be calculated. The purpose of the parentheses after the function name is to provide a funnel through which data can be passed to the function (see Figure 3.9). The items passed to the function through the parentheses are called arguments of the function and constitute its input data. For example, the following expressions are used to compute the square root of the arguments 4., 17.0, 25., 1043.29, and 6.4516: sqrt(4.) sqrt(17.0) sqrt(25.) sqrt(1043.29) sqrt(6.4516) Notice that the argument to the sqrt() function must be a real value, which is an example of C++’s function overloading capabilities. Function overloading permits using the sqrt() function sqrt (a value) Figure 3.9 Passing data to the sqrt() function 131 Chapter 3 Using Mathematical Library Functions
  • 152. same function name for arguments of different data types.7 There are actually three functions named sqrt()—defined for float, double, and long double arguments. The correct sqrt() function is called depending on the type of value passed to the function when the call is made. When one of the functions named sqrt() is called (again, the selection isautomatic, based on the passed argument), the function determines the square root of its argument and returns the result as a double. The previous expressions return these values: Expression Value Returned sqrt(4.) 2. sqrt(17.0) 4.12311 sqrt(25.) 5. sqrt(1043.29) 32.2 sqrt(6.4516) 2.54 In addition to the sqrt() function, Table 3.5 lists commonly used mathematical functions provided in C++. Accessing these functions in a program requires including the mathematical header file cmath, which contains declarations for mathematical functions. To use this header file, place the following preprocessor statement at the top of any program using a mathematical function: #include <cmath> Although some mathematical functions in Table 3.5 require more than one argument, all functions, by definition, can return at most one value. Additionally, all the functions listed are overloaded, which means the same function name can be used with integer and real arguments. Table 3.6 shows the value returned by selected functions, using sample arguments. Table 3.5 Common C++ Functions Function Name Description Returned Value abs(a) absolute value Same data type as argument pow(a1,a2) a1 raised to the a2 power Same data type as argument a1 sqrt(a) square root of a real number Double-precision sin(a) sine of a (a in radians) Double cos(a) cosine of a (a in radians) Double tan(a) tangent of a (a in radians) Double 7 If it weren’t for overloading, three separate square root functions, each with a different name, would have to be defined—one for each type of argument. 132 Assignment, Formatting, and Interactive Input
  • 153. Table 3.5 Common C++ Functions (continued) Function Name Description Returned Value log(a) natural logarithm of a Double log10(a) common log (base 10) of a Double exp(a) e raised to the a power Double Table 3.6 Selected Function Examples Example Returned Value abs(-7.362) 7.362 abs(-3) 3 pow(2.0,5.0) 32. pow(10,3) 1000 log(18.697) 2.92836 log10(18.697) 1.27177 exp(-3.2) 0.040762 Each time a mathematical function is used, it’s called into action by giving the name of the function and passing to it any data in the parentheses following the function’s name (see Figure 3.10). The arguments passed to a function need not be single constants. Expressions can also be arguments, provided the expression can be computed to yield a value of the required data type. For example, the following arguments are valid for the given functions: sqrt(4.0 + 5.3 * 4.0) abs(2.3 * 4.6) sqrt(16.0 * 2.0 - 6.7) sin(theta - phi) sqrt(x * y - z/3.2) cos(2.0 * omega) The expressions in parentheses are evaluated first to yield a specific value. Therefore, values have to be assigned to the variables theta, phi, x, y, z, and omega before their use in the preceding expressions. After the value of the argument is calculated, it’s passed to the function. Functions can also be included as part of larger expressions, as shown in this example: 4 * sqrt(4.5 * 10.0 - 9.0) - 2.0 = 4 * sqrt(36.0) - 2.0 = 4 * 6.0 - 2.0 = 24.0 - 2.0 = 22.0 function-name (data passed to the function); This passes data to the function This identifies the called function Figure 3.10 Using and passing data to a function 133 Chapter 3 Using Mathematical Library Functions
  • 154. The step-by-step evaluation of an expression such as 3.0 * sqrt(5 * 33 - 13.71) / 5 is as follows: Step Result 1. Perform multiplication in the argument. 3.0 * sqrt(165 - 13.71) / 5 2. Complete the argument calculation. 3.0 * sqrt(151.29) / 5 3. Return a function value. 3.0 * 12.3 / 5 4. Perform the multiplication. 36.9 / 5 5. Perform the division. 7.38 Program 3.9 illustrates using the sqrt() function to determine the time it takes a ball to hit the ground after it has been dropped from an 800-foot tower. This is the mathematical formula for calculating the time in seconds it takes to fall a given distance in feet: time = sqrt(2 × distance / g) where g is the gravitational constant, equal to 32.2 ft/sec2 . Program 3.9 #include <iostream> // this line can be placed second instead of first #include <cmath> // this line can be placed first instead of second using namespace std; int main() { int height; double time; height = 800; time = sqrt(2 * height / 32.2); cout << "It will take " << time << " seconds to fall " << height << " feet.n"; return 0; } Program 3.9 produces this output: It will take 7.04907 seconds to fall 800 feet. 134 Assignment, Formatting, and Interactive Input
  • 155. As used in Program 3.9, the value the sqrt() function returns is assigned to the variable time. In addition to assigning a function’s returned value to a variable, the returned value can be included in a larger expression or even used as an argument to another function. For example, the following expression is valid: sqrt( sin( abs(theta) ) ) Because parentheses are present, the computation proceeds from the inner to outer pairs of parentheses. Therefore, the absolute value of theta is computed first and used as anargument to the sin() function. The value the sin() function returns is then used as an argument to the sqrt() function. Note that the arguments of all trigonometric functions (sin(), cos(), and so forth) must be in radians. Therefore, to calculate the sine of an angle given in degrees, the angle must be converted to radians first. You can do this easily by multiplying the angle by the term (3.1416/180.). For example, to obtain the sine of 30 degrees, use the expression sin (30 * 3.1416/180.). Casts You have already seen the conversion of an operand’s data type in mixed-mode arithmetic expressions (Section 2.4) and with different operators (Section 3.1). In addition to the implicit data type conversions made automatically in mixed-mode arithmetic and assignment expres- sions, C++ provides for explicit user-specified type conversions. The operator used to force converting a value to another type is the cast operator. C++ provides compile-time and runtime cast operators. The compile-time cast is a unary operator with this syntax: dataType (expression) The dataType is the data type to which the expression in parentheses is converted. For example, the following expression int (a * b) converts the value of the expression a * b to an integer value.8 With the introduction of the latest C++ standard, runtime casts are included. In this type of cast, the requested type conversion is checked at runtime and applied if the conversion results in a valid value. Although four types of runtime casts are available, the most commonly used cast and the one corresponding to the compile-time cast has the following syntax: staticCast<data-type> (expression) For example, the runtime cast staticCast<int>(a * b) is equivalent to the compile- time cast int (a* b). 8 The C type cast syntax, in this case (int)(a * b), also works in C++. 135 Chapter 3 Using Mathematical Library Functions
  • 156. EXERCISES 3.3 1. (Practice) Write function calls to determine the following: a. The square root of 6.37 b. The square root of x - y c. The sine of 30 degrees d. The sine of 60 degrees e. The absolute value of a2 - b2 f. The value of e raised to the third power 2. (Practice) For a = 10.6, b = 13.9, and c = -3.42, determine the following values: a. int (a) b. int (b) c. int (c) d. int (a + b) e. int (a) + b + c f. int (a + b) + c g. int (a + b + c) h. float (int (a)) + b i. float (int (a + b)) j. abs(a) + abs(b) k. sqrt(abs(a - b)) 3. (Practice) Write C++ statements for the following: a. b = sin x - cos x b. b = sin2 x - cos2 x c. area = (c × b × sin a)/2 d. c a b = + 2 2 e. p m n = | | - f. sum a r r n = ( ) - - 1 1 4. (Numerical) Write, compile, and execute a C++ program that calculates and returns the fourth root of the number 81.0, which is 3. After verifying that your program works cor- rectly, use it to determine the fourth root of 1,728.896400. Your program should make use of the sqrt() function. 136 Assignment, Formatting, and Interactive Input
  • 157. 5. (General Math) Write, compile, and execute a C++ program to calculate the distance between two points with the coordinates (7, 12) and (3, 9). Use the fact that the distance between two points with the coordinates (x1, y1) and (x2, y2) is given by this formula: dis ce x y tan = + ( ) 2 2 After verifying that your program works correctly by calculating the distance between the two points manually, use your program to determine the distance between the points (-12, -15) and (22, 5). 6. (General Math) If a 20-foot ladder is placed on the side of a building at a 85-degree angle, as shown in Figure 3.11, the height at which the ladder touches the building can be calculated as height = 20 × sin 85°. Calculate this height by hand, and then write, com- pile, and execute a C++ program that determines and displays the value of the height. After verifying that your program works correctly, use it to determine the height of a 25-foot ladder placed at an angle of 85 degrees. 7. (Physics) The maximum height reached by a ball thrown with an initial velocity, v, in meters/sec, at an angle of ␪ is given by this formula: height = (.5 × v2 × sin2 ␪) / 9.8 Using this formula, write, compile, and execute a C++ program that determines and dis- plays the maximum height reached when the ball is thrown at 5 mph at an angle of 60 degrees. (Hint: Make sure to convert the initial velocity into the correct units. There are 1609 meters in a mile.) Calculate the maximum height manually, and verify the result your program produces. After verifying that your program works correctly, use it to deter- mine the height reached by a ball thrown at 7 mph at an angle of 45 degrees. 2 0 ' 85° Figure 3.11 Calculating the height of a ladder against a building 137 Chapter 3 Using Mathematical Library Functions
  • 158. 8. (Numerical) For small values of x, the value of sin(x) can be approximated by this power series: x x x x − + − + 3 5 7 3 5 7 ! ! ! .... As with the sin() function, the value of x must be in radians. Using this power series, write, compile, and execute a C++ program that approximates the sine of 180/3.1416 degrees, which equals one radian. Additionally, have your program use the sin() function to calculate the sine and display both calculated values and the absolute difference of the two results. Manually verify the approximation your program produces. After verifying that your program is working correctly, use it to approximate the value of the sine of 62.2 degrees. 9. (Conversion) The polar coordinates of a point consist of the distance, r, from a specified origin and an angle, ␪, with respect to the x-axis. The point’s x and y coordinates are related to its polar coordinates by these formulas: x = r cos ␪ y = r sin ␪ Using these formulas, write a C++ program to calculate the x and y coordinates of a point with the polar coordinates r = 10 and ␪ = 30 degrees. Verify the results your program pro- duces by calculating the results manually. After verifying that your program is working correctly, use it to convert the polar coordinates r = 12.5 and ␪ = 67.8 degrees into rectan- gular coordinates. 10. (Ecology) A model of worldwide population growth, in billions of people, since 2000 is given by this formula: Population = 6.0 e0.02[Year - 2000] Using this formula, write, compile, and execute a C++ program to estimate the worldwide population in the year 2012. Verify the result your program produces by calculating the answer manually. After verifying that your program is working correctly, use it to estimate the world’s population in the year 2019. 11. (Physics) A model to estimate the number of grams of a radioactive isotope left after t years is given by this formula: remaining material = (original material) e-0.00012t Using this formula, write, compile, and execute a C++ program to determine the amount of radioactive material remaining after 1000 years, assuming an initial amount of 100 grams. Verify the display your program produces by using a hand calculation. After verifying that your program is working correctly, use it to determine the amount of radioactive material remaining after 275 years, assuming an initial amount of 250 grams. 12. (Physics) The number of years it takes for an isotope of uranium to decay to one-half an original amount is given by this formula, where ␭, the decay constant (which is equal to the inverse of the mean lifetime), equals 0.00012: half-life = ln(2) / ␭ Using this formula, write, compile, and execute a C++ program that calculates and dis- plays the half-life of this uranium isotope. Verify the result your program produces by using a hand calculation. After verifying that your program is working correctly, use it to determine the half-life of a uranium isotope with ␭ = 0.00026. 138 Assignment, Formatting, and Interactive Input
  • 159. 3.4 Program Input Using cin Data for programs that are going to be executed only once can be included in the program. For example, if you want to multiply the numbers 30.0 and 0.05, you could use Program 3.10. Program 3.10 #include <iostream> using namespace std; int main() { double num1, num2, product; num1 = 30.0; num2 = 0.05; product = num1 * num2; cout << "30.0 times 0.05 is " << product << endl; return 0; } Program 3.10 produces this output: 30.0 times 0.05 is 1.5 Program 3.10 can be shortened, as shown in Program 3.11. Both programs, however, suffer from the same basic problem: They must be rewritten to multiply different numbers. Both programs lack the capability to enter different numbers on which to operate. Program 3.11 #include <iostream> using namespace std; int main() { cout << "30.0 times 0.05 is " << 30.0 * 0.05 << endl; return 0; } 139 Chapter 3 Program Input Using cin
  • 160. Except for the programming practice provided by writing, entering, and running the program, programs that do the same calculation only once, on the same set of numbers, clearly aren’t very useful. After all, using a calculator to multiply two numbers is simpler than entering and running Program 3.10 or 3.11. This section explains the cin statement, used to enter data in a program while it’s running. Just as a cout statement displays the value stored in a variable, cin allows users to enter a value at the keyboard (see Figure 3.12), and then the value is stored in a variable. When a statement such as cin >> num1; is encountered, the computer stops program execution and accepts data from the keyboard. When a data value is typed, cin causes the value to be stored in the variable listed after the extraction (“get from”) operator, >>. The program then continues execution with the next statement after the cin statement. To see how cin works, take a look at Program 3.12. Program 3.12 #include <iostream> using namespace std; int main() { double num1, num2, product; cout << "Please type in a number: "; cin >> num1; cout << "Please type in another number: "; cin >> num2; product = num1 * num2; cout << num1 << " times " << num2 << " is " << product << endl; return 0; } The first cout statement in Program 3.12 displays a string that tells the person at the keyboard what should be typed. When an output string is used in this manner, it’s called a prompt. In this case, the prompt tells the user to type a number. The computer then executes int main() { cin >> cout << } Screen Keyboard Figure 3.12 cin is used to enter data; cout is used to display data 140 Assignment, Formatting, and Interactive Input
  • 161. the next statement, which uses cin. The cin statement puts the computer in a temporary pause (or wait) state while the user types a value. Then the user signals cin that data entry is finished by pressing the Enter key. The entered value is stored in the variable to the right of the extraction operator (num1), and the computer is taken out of its paused state. Program execution proceeds with the next statement, which in Program 3.12 is another cout statement that displays a prompt asking the user to type another number. The next statement uses cin again to put the computer in a temporary wait state while the user types a second value (stored in the variable num2). The following sample run was made using Program 3.12: Please type in a number: 30 Please type in another number: 0.05 30 times 0.05 is 1.5 In Program 3.12, each time cin is invoked, it’s used to store one value in a variable. A cin statement, however, can be used to enter and store as many values as there are extraction operators and variables to hold the entered data. For example, the statement cin >> num1 >> num2; results in two values being read from the keyboard and assigned to the variables num1 and num2. If the data entered at the keyboard is 0.052 245.79 the variables num1 and num2 contain the values 0.052 and 245.79, respectively. Notice that there must be at least one space between numbers when they’re entered to clearly indicate where one number ends and the next begins. Inserting more than one space between numbers has no effect on cin. The same spacing also applies to entering character data; the extraction operator skips blank spaces and stores the next nonblank character in a character variable. For example, in response to the statements, char ch1, ch2, ch3; // declare three character variables cin >> ch1 >> ch2 >> ch3; // accept three characters the input a b c causes the letter a to be stored in the variable ch1, the letter b to be stored in the variable ch2, and the letter c to be stored in the variable ch3. Because a character variable can be used to store only one character, however, the following input, without spaces, can also be used: abc You can use any number of cin statements in a program, and any number of values can be entered with a single cin statement. Program 3.13 shows using a cin statement to input three numbers from the keyboard. The program then calculates and displays the average of the entered numbers. 141 Chapter 3 Program Input Using cin
  • 162. Program 3.13 #include <iostream> using namespace std; int main() { int num1, num2, num3; double average; cout << "Enter three integer numbers: "; cin >> num1 >> num2 >> num3; average = (num1 + num2 + num3) / 3.0; cout << "The average of the numbers is " << average << endl; return 0; } The following sample run was made using Program 3.13: Enter three integer numbers: 22 56 73 The average of the numbers is 50.3333 The data entered at the keyboard for this sample run consists of 22 56 73. In response to this stream of input, Program 3.13 stores the value 22 in the variable num1, the value 56 in the variable num2, and the value 73 in the variable num3 (see Figure 3.13). Because the average of three integer numbers can be a floating-point number, the variable average, used to store the average of all entered numbers, is declared as a floating-point variable (a double). Note also that parentheses are needed in the assignment statement average = (num1 + num2 + num3)/3.0;. Without the parentheses, the only value divided by 3 would be the integer in num3 (because division has a higher precedence than addition). cin >> num1 >> num2 >> num3; 22 56 73 22 56 73 num1 num2 num3 Figure 3.13 Inputting data in the variables num1, num2, and num3 142 Assignment, Formatting, and Interactive Input
  • 163. The extraction operator, >>, like the insertion operator, <<, is “clever” enough to make a few data type conversions. For example, if an integer is entered instead of a double-precision number, the integer is converted to the correct data type.9 Similarly, if a double-precision number is entered when an integer is expected, only the integer part of the number is used. For example, assume the following numbers are typed in response to the statement cin >> num1 >> num2 >> num3;, where num1 and num3 have been declared as double-precision variables and num2 is an integer variable: 56 22.879 33.923 The 56 is converted to 56.0 and stored in the variable num1. The extraction operation continues, extracting data from the input stream and expecting an integer value. As far as the << operator is concerned, the decimal point in 22.879 indicates the end of an integer and the start of a decimal number. Therefore, the number 22 is assigned to num2. Continuing to process its input stream, the next << operator takes the .879 as the next floating-point number and assigns it to num3. As far as cin is concerned, 33.923 is extra input and is ignored. If, however, you don’t enter enough data initially, the insertion operator causes the computer to pause, waiting until enough data has been entered. A First Look at User-Input Validation A well-constructed program should validate user input and ensure that a program doesn’t crash or produce nonsensical output caused by unexpected input. The term validate means checking that the entered value matches the data type of the variable it’s assigned to in a cin statement and checking that the value is within an acceptable range for the application. Programs that detect and respond effectively to unexpected user input are formally referred to as robust programs and informally as “bulletproof” programs. One of your goals as a programmer is to produce robust programs. As written, Programs 3.12 and 3.13 aren’t robust programs, and in the following discussion, you see why. The first problem with these programs becomes evident when a user enters a non- numerical value. For example, examine the following sample run using Program 3.13: Enter three integer numbers: 10 20.68 20 The average of the numbers is -2.86331e+008 This output occurs because the conversion of the second entered number results in assigning the integer value 20 to num2 and the value -858993460 to num3.10 The -858993460 value results because an invalid character, the decimal point, is assigned to a variable that expects an integer. The average of the numbers 10, 20, and -858993460 is computed correctly as -286331143.3, which is displayed in scientific notation with six significant digits as -2.86331e+008. Most users, however, would report this result as a program error. This same problem occurs when a non-integer value is entered for either of the first two inputs. (It doesn’t occur for any numerical value entered as the third input because the integer part of the last input is accepted, and the remaining input ignored.) Your first response might be “The program clearly asks you to enter integer values.” Programmers with more experience, however, understand that their responsibility is to make sure a program 9 Strictly speaking, what comes in from the keyboard isn’t any data type, such as an int or a double, but is simply a sequence of characters. The extraction operation handles the conversion from the character sequence to a defined data type. 10 Some C++ runtime systems accept the .68 as the third input and convert it to the integer value of zero. In all cases, the last value of 20 is ignored. 143 Chapter 3 Program Input Using cin
  • 164. anticipates and appropriately handles all inputs users might enter. To achieve this goal, think about what can go wrong with your program as you develop it, and then have another person or group test the program. The basic approach to handling invalid data input is called user-input validation, which means checking the entered data during or immediately after it has been entered, and then giving users a way to reenter invalid data. User-input validation is an essential part of any commercially viable program; if done correctly, it protects a program from attempting to process data that can cause computational problems. You see how to do this type of validation in Chapters 4 and 5, when you learn about C++’s selection and repetition statements. EXERCISES 3.4 1. (Practice) For the following declaration statements, write a cin statement that causes the computer to pause while the user enters the appropriate data: a. int firstnum; b. double grade; c. double secnum; d. char keyval; e. int month, years; double average; f. char ch; int num1, num2; double grade1, grade2; g. double interest, principal, capital; double price, yield; h. char ch, letter1, letter2; int num1, num2, num3; i. double temp1, temp2, temp3; double volts1, volts2; 2. (Practice) a. Write a C++ program that first displays the following prompt: Enter the temperature in degrees Celsius: Have your program accept a value entered from the keyboard and convert the tempera- ture entered to degrees Fahrenheit, using this formula: Fahrenheit = (9.0 / 5.0) × Celsius + 32.0 Your program should then display the temperature in degrees Fahrenheit with an appro- priate message. 144 Assignment, Formatting, and Interactive Input
  • 165. b. Compile and execute the program written for Exercise 2a. To verify your program, use the following test data and calculate the Fahrenheit equivalents by hand, and then use your program to see whether you get the same results: Test data set 1: 0 degrees Celsius Test data set 2: 50 degrees Celsius Test data set 3: 100 degrees Celsius When you’re sure your program is working correctly, use it to complete the following chart: Celsius Fahrenheit 45 50 55 60 65 70 3. (Practice) Write, compile, and execute a C++ program that displays the following prompt: Enter the radius of a circle: After accepting a value for the radius, your program should calculate and display the area of the circle. (Hint: Area = 3.1416 × radius2 .) For testing purposes, verify your program byusing an input radius of 3 inches. After manually determining that your program’s result is correct, use your program to complete the following chart: Radius (in) Area (sq. in) 1.0 1.5 2.0 2.5 3.0 3.5 4. (Practice) a. Write, compile, and execute a C++ program that displays the following prompts: Enter the miles driven: Enter the gallons of gas used: After each prompt is displayed, your program should use a cin statement to accept data from the keyboard for the displayed prompt. After the number for gallons of gas used has been entered, your program should calculate and display the miles per gallon (mpg). This 145 Chapter 3 Program Input Using cin
  • 166. value should be included in a message and calculated by using the formula miles per gallon = miles / gallons used. Verify your program by using the following test data: Test data set 1: miles = 276, gas = 10 gallons Test data set 2: miles = 200, gas = 15.5 gallons After finishing your verification, use your program to complete the following chart. (Make sure to convert the miles driven to kilometers driven and gallons used to liters used, and then compute the kilometers per liter.) Miles Driven Gallons Used MPG Km Driven Liters Used Km/L 250 16.00 275 18.00 312 19.54 296 17.39 b. For the program written for Exercise 4a, determine how many verification runs are required to make sure the program is working correctly, and give a reason to support your answer. 5. (Practice) a. Write, compile, and execute a C++ program that displays the following prompts: Enter a number: Enter a second number: Enter a third number: Enter a fourth number: After each prompt is displayed, your program should use a cin statement to accept a number from the keyboard for the displayed prompt. After the fourth number has been entered, your program should calculate and display the average of the numbers. The aver- age should be included in an output message. Check the average your program calculates by using the following test data: Test data set 1: 100, 100, 100, 100 Test data set 2: 100, 0, 100, 0 After finishing your verification, use your program to complete the following chart: Numbers Average 92, 98, 79, 85 86, 84, 75, 86 63, 85, 74, 82 146 Assignment, Formatting, and Interactive Input
  • 167. b. Repeat Exercise 5a, making sure you use the same variable name, number, for each number input. Also, use the variable sum for the sum of the numbers. (Hint: To do this, you can use the statement sum = sum + number after each number is accepted. Review the material on accumulating in Section 3.1.) 6. (General Math) a. Write, compile, and execute a C++ program to compute and display the value of the second-order polynomial ax2 + bx + c for any user-entered values of the coefficients a, b, and c and the variable x. Have your program display a message first to inform users what the program does, and then display suitable prompts to alert users to enter the data. (Hint: Use a prompt such as Enter the coefficient of the x-squared term:.) b. Check the result of your program written for Exercise 6a by using the following test data: Test data set 1: a = 0, b = 0, c = 22, x = 56 Test data set 2: a = 0, b = 22, c = 0, x = 2 Test data set 3: a = 22, b = 0, c = 0, x = 2 Test data set 4: a = 2, b = 4, c = 5, x = 2 After finishing your verification, use your program to complete the following chart: a b c x Polynomial Value 2.0 17.0 -12.0 1.3 3.2 2.0 15.0 2.5 3.2 2.0 15.0 -2.5 -2.0 10.0 0.0 2.0 -2.0 10.0 0.0 4.0 -2.0 10.0 0.0 5.0 -2.0 10.0 0.0 6.0 5.0 22.0 18.0 8.3 4.2 -16 -20 -5.2 7. (General Math) The roads of Kansas are laid out in a rectangular grid at exactly one-mile intervals, as shown in Figure 3.14. Pete drives his pickup x miles east and y miles north to get to his friend Joe’s farm. Both x and y are integer numbers. Using this information, write, test, and run a C++ program that prompts the user for the values of x and y, and then uses this formula to find the shortest driving distance across the fields to Joe’s farm: dis ce x y tan = + ( ) 2 2 Round the answer to the nearest integer value before it’s displayed. 8. (Numerical) Write, compile, and execute a program that calculates and displays the square root value of a user-entered real number. Verify your program by calculating the square roots of this test data: 25, 16, 0, and 2. After finishing your verification, use your program to determine the square roots of 32.25, 42, 48, 55, 63, and 79. 147 Chapter 3 Program Input Using cin
  • 168. 9. (Numerical) Write, compile, and execute a program to calculate and display the fourth root of a user-entered number. Recall from elementary algebra that you find the fourth root of a number by raising the number to the 1/4 power. (Hint: Don’t use integer division—can you see why?) Verify your program by calculating the fourth roots of this test data: 81, 16, 1, and 0. When you’re finished, use your program to determine the fourth roots of 42, 121, 256, 587, 1240, and 16,256. 10. (Electrical Eng.) For the series circuit shown in Figure 3.15, the voltage drop, V2, across resistor R2 and the power, P2, delivered to this resistor are given by the formulas V2 = I R2 and P2 = I V2, where I = E / (R1 + R2). Using these formulas, write, compile, and execute a C++ program that prompts users for values of E, R1, and R2; calculates the voltage drop and- power delivered to R2; and displays the results. Check your program by using the test data E = 10 volts, R1 = 100 ohms, and R2 = 200 ohms. After finishing your verification, use your pro- gram to complete the following chart: E (Volts) R1 (Ohms) R2 (Ohms) Voltage Drop (Volts) Power Delivered (Watts) 10 100 100 10 100 200 10 200 200 20 100 100 20 100 200 20 200 200 Distance x y Pete’s farm Joe’s farm N Figure 3.14 Illustration for Exercise 7 148 Assignment, Formatting, and Interactive Input
  • 169. 11. (Data Processing) Program 3.12 prompts users to input two numbers; the first value entered is stored in num1, and the second value is stored in num2. Using this program as a starting point, write a program that swaps the values stored in the two variables. 12. (Data Processing) Write a C++ program that prompts users to enter a number. Have your program accept the number as an integer and display the integer immediately by using a cout statement. Run your program three times. The first time, enter a valid inte- ger number; the second time, enter a double-precision number; and the third time, enter a character. Using the output display, see what number your program actually accepted from the data you entered. 13. (Data Processing) Repeat Exercise 12, but have your program declare the variable used to store the number as a double-precision variable. Run the program three times. The first time, enter an integer; the second time, enter a double-precision number; and the third time, enter a character. Using the output display, keep track of what number your program actually accepted from the data you entered. What happened, if anything, and why? 14. (For Thought) a. Why do you think successful programs contain extensive data-input validity checks? (Hint: Review Exercises 12 and 13.) b. What do you think is the difference between a data-type check and a data- reasonableness check? c. Assume that a program requests users to enter a month, day, and year. What are some checks that could be made on the data entered? 3.5 Symbolic Constants Certain constants used in a program have more general meanings that are recognized outside the program’s context. Examples of these types of constants include the number 3.1416, which is ␲ accurate to four decimal places; 32.2 ft/sec2 , which is the gravitational constant; R1 R2 I E Figure 3.15 Calculating the voltage drop 149 Chapter 3 Symbolic Constants
  • 170. and the number 2.71828, which is Euler’s number accurate to five decimal places. The following list shows other commonly used scientific and engineering constants: Avagadro’s number = 6.02214179 × 1023 /mole Boltzmann’s constant = 1.3806 × 10-23 Joules/K Planck’s constant = 6.6256 × 10-34 Joule/sec Stephan-Boltzmann’s constant = 5.6697 × 10-8 Watts/m2 K4 Universal gas constant = 8.6314472 × 107 Joules/Kmole Universal gravitational constant = 6.67428 × 10-11 N m2 /kg2 Certain other constants in a program are defined in the context of the application being programmed. For example, in a program determining the weight of different sized objects, the density of an object’s material takes on a special significance. By themselves, density numbers are quite ordinary, but in this application, they have a special meaning. Program- mers sometimes refer to these types of numbers as magic numbers. When a magic number appears repeatedly in a program, it becomes a potential source of error if it has to be changed. If just one instance of the magic number is overlooked and not changed, when the program runs the result will be incorrect, and the source of the error will be difficult to locate. To avoid the problem of having a magic number occur in many places in a program and to identify universal constants, such as ␲, clearly, C++ enables programmers to give these constants symbolic names. Then the symbolic name, instead of the magic number, can be used throughout the program. If the number ever has to be changed, the change need be made only once, where the symbolic name is equated to the actual numerical value. To equate numbers to symbolic names,you use the const declaration qualifier, which specifies that the declared identifier is read-only after it’s initialized; it can’t be changed. Examples of using this qualifier are as follows: const double PI = 3.1416; const double PLANCK = 6.6256e-34; const double DENSITY = 0.238; const int MAXNUM = 100; The first declaration statement creates a double-precision constant named PI and initializes it to 3.1416, and the second declaration statement creates a double-precision constant named PLANCK and initializes it to Planck’s constant (accurate to four decimal places). The third declaration statement creates a constant named DENSITY and initializes it to 0.238. Finally, the fourth declaration creates an integer constant named MAXNUM and initializes it with the value 100. After a const identifier is created and initialized, the value stored in it can’t be changed. For all practical purposes, the name of the constant and its value are linked for the duration of the program that declares them. Although the const identifiers have been shown in uppercase letters, lowercase letters could have been used. In C++, however, it’s common to use uppercase letters for const identifiers to identify them easily. When programmers see uppercase letters in a program, they know a symbolic name is being used, and its value can’t be changed later in the program. 150 Assignment, Formatting, and Interactive Input
  • 171. After it’s declared, a const identifier can be used in any C++ statement in place of the number it represents. For example, both these assignment statements are valid: circum = 2 * PI * radius; weight = DENSITY * volume; These statements must, of course, appear after the declarations for all their variables. Because a const declaration equates a constant value to an identifier, and the identifier can be used as a replacement for its initializing constant, these identifiers are commonly referred to as symbolic constants, named constants, or simply constants. These terms are used interchangeably in this book. Placement of Statements At this stage, you have been introduced to a variety of statement types. The general rule in C++ for statement placement is simply that a variable or symbolic constant must be declared before it can be used. Although this rule permits placing both preprocessor directives and declaration statements throughout a program, doing so results in a poor program structure. For good programming form, the following statement ordering should be used: preprocessor directives int main() { // symbolic constants // variable declarations // other executable statements return value; } As new statement types are introduced, this placement structure will be expanded to accommodate them. Note that comment statements can be intermixed anywhere within this basic structure. Program 3.14 illustrates this basic structure and uses a symbolic constant to calculate the weight of a steel cylinder. The density of the steel is 0.284 lb/in3 (= 7.738 × 103 kg/m-3 ). 151 Chapter 3 Symbolic Constants
  • 172. Program 3.14 // This program determines the weight of a steel cylinder // by multiplying the volume of the cylinder times its density. // The volume of the cylinder is given by the formula PI * pow(radius,2) * height. #include <iostream> #include <iomanip> #include <cmath> using namespace std; int main() { const double PI = 3.1416; const double DENSITY = 0.284; double radius, height, weight; cout << "Enter the radius of the cylinder (in inches): "; cin >> radius; cout << "Enter the height of the cylinder (in inches): "; cin >> height; weight = DENSITY * PI * pow(radius,2) * height; cout << setiosflags(ios:: fixed) << setiosflags(ios::showpoint) << setprecision(4) << "The cylinder weighs " << weight << " pounds" << endl; return 0; } Notice in Program 3.14 that two symbolic constants have been defined: PI and DENSITY. The following run was made to determine the weight of a cylinder with a radius of 3 inches and a height of 12 inches. Enter the radius of the cylinder (in inches): 3 Enter the height of the cylinder (in inches): 12 The cylinder weighs 96.3592 pounds The advantage of using the named constant PI in Program 3.14 is that it clearly identifies the value of 3.1416 in terms most people recognize. The advantage of using the named constant DENSITY is that the programmer can change the value of the density for another material without having to search through the program to see where DENSITY is used. If, of course, many different materials are used, DENSITY should be changed from a symbolic constant to a variable. A natural question, then, is asking what the difference is between symbolic constants and variables. 152 Assignment, Formatting, and Interactive Input
  • 173. A variable’s value can be altered anywhere in a program. By its nature, a named constant is a fixed value that must not be altered after it’s defined. Naming a constant rather than assigning the value to a variable ensures that the value in the constant can’t be altered later. Whenever a named constant appears in an instruction, it has the same effect as the constant it represents. Therefore, DENSITY in Program 3.14 is simply another way of representing the number 0.284. Because DENSITY and the number 0.284 are equivalent, the value of DENSITY can’t be subsequently changed in the program. After DENSITY has been defined as a constant, an assignment statement such as DENSITY = 0.156; is meaningless and results in an error message because DENSITY is not a variable. Because DENSITY is only a stand-in for the value 0.284, this statement is equivalent to writing the invalid expression 0.284 = 0.156. In addition to using a const statement to name constants, as in Program 3.14, you can also use this statement to equate the value of a constant expression to a symbolic name. A constant expression consists of operators and constants only. For example, the statement const double DEG_TO_RAD = 3.1416/180.0; equates the value of the constant expression 3.1416/180.0 to the symbolic name DEG_TO_RAD. The symbolic name, as always, can be used in any statement following its definition. For example, because the expression 3.1416/180.0 is required for converting degrees to radians, the symbolic name for this conversion factor can be used conveniently whenever this conversion is required. For example, in the assignment statement height = distance * sin(angle * DEG_TO_RAD); the symbolic constant DEG_TO_RAD is used to convert the value in angle to a radian measure. A previously defined named constant can also be used in a subsequent const statement. For example, the following sequence of statements is valid: const double PI = 3.1416; const double DEG_TO_RAD = PI / 180.0; Because the constant 3.1416 has been equated to the symbolic name PI, it can be used legitimately in any subsequent definition, even in another const statement. Program 3.15 uses the named constant DEG_TO_RAD to convert a user-entered angle, in degrees, to its equivalent radian measure for use by the sin() function. 153 Chapter 3 Symbolic Constants
  • 174. Program 3.15 #include <iostream> #include <iomanip> #include <cmath> using namespace std; int main() { const double PI = 3.1416; const double DEG_TO_RAD = PI/180.0; double angle; cout << "Enter the angle (in degrees): "; cin >> angle; cout << setiosflags(ios:: fixed) << setiosflags(ios::showpoint) << setprecision(4) << "The sine of the angle is " << sin(angle * DEG_TO_RAD) << endl; return 0; } The following sample run was made using Program 3.15: Enter the angle (in degrees): 30 The sine of the angle is 0.5000 Although the const qualifier has been used to construct symbolic constants, you’ll see this qualifier again in Chapter 6, where you learn it’s useful as a function argument to make sure the argument isn’t modified in the function. 154 Assignment, Formatting, and Interactive Input
  • 175. Technical Note Frequency, Period, and Wavelength A wave is a repeating pattern in time and space. Examples are sound waves, ocean waves, and light waves. Figure 3.16 shows a typical wave, which is usually described with one of these related terms: frequency, period, or wavelength. Time Amplitude T Figure 3.16 A typical wave In science and engineering fields, a wave’s frequency is denoted by the letter f, its period by the letter T, and its wavelength by the Greek letter l (lamda). The frequency of a wave is the number of repetitions of the wave occurring in one second. For example, the frequency of the musical note middle C on a piano is 261.64 repetitions per second, typically denoted as 261.64 cycles/sec. In the SI measurement system, the synonym for cycles/sec is Hertz (Hz). Therefore, 261.64 cycles/sec = 261.64 Hz, which means there are 261.64 repetitions of the wave in one second. Audio, radio, and power line waves are described in terms of their frequencies. Extremely low frequency waves, such as ocean waves, are typically described by their period, T, which is the inverse of the wave’s frequency. So mathematically, you have the following: T = 1 / f Therefore, a wave’s period is the time it takes to complete one cycle. For example, an ocean surface wave with a period of 3 sec/cycle means it takes 3 seconds to com- plete one wave cycle. What this means is that a person at a fixed location in the ocean sees a wave crest pass by every 3 seconds. The corresponding frequency of this wave is 1/T, or 1/3 cycles per second, which equals 0.33 Hz. Extremely high frequency waves, such as light and x-rays, are typically described by their wavelength. Wavelength, l, and frequency, f, are related by this formula ␭ = speed of the wave / f where the speed of the wave is the wave’s velocity in the medium through which it’s traveling. For light traveling in a vacuum, the speed of a light wave is 299,792,458 m/s ⬇ 2.998 × 108 m/s. For sound waves traveling in air, the speed of the wave is 345 m/s. continued... 155 Chapter 3 Symbolic Constants
  • 176. Technical Note Frequency, Period, and Wavelength (continued) Following is a description of waves encountered in science and engineering fields: Wave Type Frequency or Period Wavelength Ocean waves Period = 1 to 5 seconds Not used European household current 50 Hz 5.996 × 106 m American household current 60 Hz 4.996 × 106 m Radio frequencies Low frequency (LF) 3 × 104 to 3 × 105 Hz (30 to 300 kilohertz, KHz) 104 to 103 m (10 to 1 km) Medium frequency (MF) 3 × 105 to 3 × 106 Hz (.3 to 3 megahertz, MHz) 103 to 102 m (1 to .1 km) High frequency (HF) 3 × 106 to 3 × 107 Hz (3 to 30 MHz) 100 to 10 m Very high frequency (VHF) 3 × 107 to 3 × 109 Hz (30 to 300 MHz) 10 to 1 m Ultra high frequency (UHF) 3 × 109 to 3 × 1012 Hz (300 to 3000 MHz) 1 to .1 m Body heat 3 x 1011 Hz 1 × 10-3 m (1 millimeter) Infrared light 0.04 × 1015 to .3 × 1015 Hz 750 × 10-9 to 100 × 10-9 nm (750 to 100 nanometers) Red visible light 384 × 1012 to 482 × 1012 Hz 78 × 10-9 to 62 × 10-9 nm (78 to 62 nanometers) Violet visible light 659 × 1012 to 769 × 1012 Hz 45 × 10-9 to 39.8 × 10-9 nm (45 to 39 nanometers) Ultraviolet light 1 × 1015 to 1.5 × 1015 Hz 300 × 10-9 to 200 × 10-9 nm (300 to 200 nanometers) X-rays 30 × 1015 to 30 × 1018 Hz 9.9 × 10-9 to .99 × 10-9 m 156 Assignment, Formatting, and Interactive Input
  • 177. EXERCISES 3.5 1. (Practice) Modify Program 3.9 to use the named constant GRAV in place of the value 32.2 used in the program. Compile and execute your program to verify that it produces the same result shown in the text. 2. (Modify) Rewrite the following program to use the named constant FACTOR in place of the expression (5.0/9.0) used in the program: #include <iostream> using namespace std; int main() { double fahren, celsius; cout << "Enter a temperature in degrees Fahrenheit: "; cin >> fahren; celsius = (5.0/9.0) * (fahren - 32.0); cout << "The equivalent Celsius temperature is " << celsius << endl; return 0; } 3. (Modify) Rewrite the following program to use the symbolic constant PRIME in place of the value 0.04 used in the program: #include <iostream> using namespace std; int main() { float prime, amount, interest; prime = 0.04; // prime interest rate cout << <Enter the amount: "; cin >> amount; interest = prime * amount; cout << "The interest earned is" << interest << " dollars" << endl; return 0; } 4. (Modify) Rewrite the following program so that the variable volts is changed to a sym- bolic constant: #include <iostream> using namespace std; int main() { double current, resistance, volts; 墌 157 Chapter 3 Symbolic Constants
  • 178. volts = 12; cout << " Enter the resistance: "; cin >> resistance; current = volts / resistance; cout << "The current is " << current << endl; return 0; } 5. (Heat Transfer) Typically, all objects radiating heat do so at many different wavelengths. (See the Technical Note in Section 3.5 for a description of wavelength.) The wavelength at which an object emits its maximum heat energy can be found by using Wein’s Law: ␭max T = W ␭max is the maximum wavelength. T is the object’s temperature in °K. W is Wein’s constant = 2897 microns/°K. a. Using Wein’s Law, write a C++ program that accepts an object’s temperature in degrees Celsius and outputs the wavelength at which the object radiates its maximum energy. Have your program declare Wein’s constant as the symbolic constant named WEINCONSTANT. b. After verifying that your program is working, use it to determine the maximum heat- radiating wavelength for the sun, Earth, and Mars, with surface temperatures of 5727, 14, and 0.46 degrees Celsius, respectively. 3.6 A Case Study: Acid Rain The use of coal as the major source of steam power began with the Industrial Revolution. Currently, coal is one of the principal sources of electrical power generation in many industrialized countries. Since the middle of the 19th century, it has been known that the oxygen used in the burning process combines with the carbon and sulfur in coal to produce carbon dioxide and sulfur dioxide. When these gases are released into the atmosphere, sulfur dioxide combines with water and oxygen in the air to form sulfuric acid, which is transformed into separate hydronium ions and sulfates (see Figure 3.17). The hydronium ions in the atmosphere that fall to Earth as components of rain are what change the acidity levels of lakes and forests. The acid level of rain and lakes is measured on a pH scale by using this formula: pH = - log10 (concentration of hydronium ions) The concentration of hydronium ions is measured in units of moles/liter. A pH value of 7 indicates a neutral value (neither acidic nor alkaline), whereas levels below 7 indicate the presence of an acid, and levels above 7 indicate the presence of an alkaline substance. For example, sulfuric acid has a pH value of approximately 1, lye has a pH value of approximately 13, and distilled water typically has a pH value of 7. Marine life usually can’t survive in water with a pH level below 4. 158 Assignment, Formatting, and Interactive Input
  • 179. Using the formula for pH, you’ll write a C++ program, using the software development procedure described in Chapter 2, that calculates the pH level of a substance based on a user input value for the concentration of hydronium ions. Step 1 Analyze the Problem Although the problem statement provides technical information on the composition of acid rain, from a programming viewpoint, this problem is rather simple. You have only one required output (a pH level) and one input (the concentration of hydronium ions). coal smokestack sulfur and carbon dioxide + = acid rain sulfates hydronium ions sulfuric acid water and oxygen in air Figure 3.17 The formation of acid rain 159 Chapter 3 A Case Study: Acid Rain
  • 180. Step 2 Develop a Solution The algorithm for transforming the input to the required output is a straightforward use of the pH formula. The pseudocode representation of the algorithm for entering input data, processing data to produce the required output, and displaying output is as follows: Display a prompt to enter an ion concentration level. Read a value for the concentration level. Calculate a pH level, using the given formula. Display the calculated value. To make sure you understand the formula used in the algorithm, do a hand calculation. You can then use the result of this calculation to verify the result the program produces. Assuming a hydronium concentration of 0.0001 (although any value would do), the pH level is calculated as -log10 10-4 . Either by knowing that the logarithm of 10 raised to a power is the power itself or by using a log table, the value of this expression is -(-4) = 4. Step 3 Code the Solution Program 3.16 shows using the algorithm in C++. The variable names were chosen to convey the variables’ meanings in this application. Program 3.16 #include <iostream> #include <cmath> using namespace std; int main() { double hydron, pHlevel; cout << "Enter the hydronium ion concentration: "; cin >> hydron; pHlevel = -log10(hydron); cout << "The pH level is " << pHlevel << endl; return 0; } Program 3.16 begins with two #include preprocessor statements, followed by the main() function. Within main(), a declaration statement declares two floating-point variables, hydron and pHlevel. The program then displays a prompt requesting input data from the user. After the prompt is displayed, a cin statement is used to store the entered 160 Assignment, Formatting, and Interactive Input
  • 181. data in the variable hydron. Finally, a value for pHlevel is calculated, using the logarithmic library function, and displayed. As always, the program is terminated with a closing brace. Step 4 Test and Correct the Program A test run using Program 3.16 produced the following: Enter the hydronium ion concentration level: 0.0001 The pH level is 4 Because the program performs a single calculation, and the result of this test run agrees with your previous hand calculation, the calculation portion of the program has been tested completely. It can now be used to calculate the pH level of other hydronium concentrations with confidence that the results produced are accurate. EXERCISES 3.6 1. (Practice) Enter, compile, and run Program 3.16 on your computer system. 2. (General Math) The value of ␲ can be approximated by this series: 4 1 1 3 1 5 1 7 − + − +       .... Using this formula, write a program that calculates and displays the value of ␲, using 2, 3, and 4 terms of the series. 3. (General Math) The exponential function ex , where e is known as Euler’s number (and has the value 2.718281828459045 . . .) appears many times in descriptions of natural phenomena. For example, radioactive decay, population growth, and the normal (bell- shaped) curve used in statistical applications can be described by using this function. The value of ex can be approximated by using this series: 1 1 2 3 4 5 6 2 3 4 5 6 + + + + + + + x x x x x x ! ! ! ! ! ! ... Using this formula, write a program that calculates and displays the value of Euler’s num- ber, using 1, 2, 3, and 4 terms of the series. 4. (General Math) The volume of oil stored in an underground 200-foot deep cylindrical tank is determined by measuring the distance from the top of the tank to the surface of the oil. Knowing this distance and the radius of the tank, the volume of oil in the tank can be determined by using this formula: volume = ␲ radius2 (200 - distance) Using this information, write, compile, and execute a C++ program that accepts the radius and distance measurements, calculates the volume of oil in the tank, and displays the two 161 Chapter 3 A Case Study: Acid Rain
  • 182. input values and the calculated volume. Verify the results of your program by doing a hand calculation using the following test data: radius = 10 feet and distance = 12 feet. 5. (General Math) The circumference of an ellipse (review Figure 3.5) is given by this formula: Circumference = + ( ) π a b)2 Using this formula, write a C++ program to calculate the circumference of an ellipse with a minor radius, a, of 2.5 inches and a major radius, b, of 6.4 inches. (Hint: The square root can be taken by raising the quantity 2[a2 + b2 ] to the 0.5 power.) 6. (General Math) The perimeter, approximate surface area, and approximate volume of an in-ground pool are given by the following formulas: perimeter = 2(length + width) volume = length × width × average depth underground surface area = 2(length + width)average depth + length × width Using these formulas as a basis, write a C++ program that accepts the length, width, and average depth measurements, and then calculates the pool’s perimeter, volume, and underground surface area. In writing your program, make these two calculations immedi- ately after entering the input data: length × width and length + width. The results of these two calculations should be used, as needed, in the assignment statements for determining the perimeter, volume, and underground surface area without recalculating them for each equation. Verify your program’s results by doing a hand calculation, using the following test data: length = 25 feet, width = 15 feet, and average depth = 5.5 feet. After verifying that your program is working, use it to complete the following chart: Length Width Depth Perimeter Volume Underground Surface Area 25 10 5.0 25 10 5.5 25 10 6.0 25 10 6.5 30 12 5.0 30 12 5.5 30 12 6.0 30 12 6.5 7. (Heat Transfer) Radiation is the transfer of heat via electromagnetic wave propagation. Examples of heat transfer are the heat radiated from the sun, the heat radiated from Earth, and the heat given off in the evening by objects, such as cars and brick walls, warmed by the sun during the day. The heat radiated by an object can be calculated by using Stephan-Boltzmann’s Law: E = e ␴ T4 162 Assignment, Formatting, and Interactive Input
  • 183. E is the energy radiated per second per square meter of its surface. e is the emissivity of the substance (a number between 0 and 1). ␴ is Stephan-Boltzmann’s constant (5.6697 × 10-8 Watts/m2 K4 ). T is the surface temperature in degrees Kelvin (°K = °C + 273). An ideal radiator, such as the sun, has an emissivity of 1, and the heat generated from the sun, with a surface temperature of approximately 6000°K, is as follows: E = 5.6697 × 10-8 Watts/m2 K4 (6 × 103 K4 ) = 5.6697 × 10-8 Watts/m2 K4 (1296 × 1012 K4 ) = 7.3 × 107 Watts/m2 = 73,000,000 Watts/m2 Using the formula and this information, write a C++ program that accepts a planet’s tem- perature (assuming an emissivity of 1) and provides the heat generated from the planet as its output. After determining that your program is working correctly (make sure it produces the correct radiation for the sun), use it to complete the following chart (make sure to use correct units): Planet Average Surface Temperature (°Celsius) Heat Radiated (Watts/m2 ) Mercury 270 Venus 462 Earth 14 Mars -46 Jupiter -108 Saturn -139 Uranus -197 Neptune -201 8. (Heat Transfer) During the day, heat is absorbed by many objects, such as cars, roofs, and brick walls. This heat is then radiated back into the environment during the cooler evening hours. Using Stephan-Boltzmann’s Law, E = e ␴ T4 (see Exercise 7), write a C++ program that determines the amount of radiation for the objects listed in the following table. Your program should request the object’s average surface temperature and emissiv- ity, and then calculate and display the heat radiated. Complete the following chart, mak- ing three runs of the program: Substance Average Surface Temperature (°Celsius) Emissivity Heat Radiated (Watts/m2 ) Automobile 47 .3 Brick 45 .9 Commercial roof 48 .05 163 Chapter 3 A Case Study: Acid Rain
  • 184. 9. (Electrical Eng.) a. Write, compile, and execute a C++ program that calculates and dis- plays the voltage gain of a three-stage amplifier at a frequency of 1000 Hertz. The volt- age gains of the stages are as follows: Stage 1 gain: 23/[2.32 + (0.044f)2 ]1/2 Stage 2 gain: 12/[6.72 + (0.34f)2 ]1/2 Stage 3 gain: 17/[1.92 + (0.45f)2 ]1/2 f is the frequency in Hertz. The voltage gain of the amplifier is the product of the gains of each stage. b. Redo Exercise 9a, assuming the frequency will be entered when the program runs. 3.7 A Closer Look: Programming Errors The ideal in programming is to produce readable, error-free programs that work correctly and can be modified or changed with a minimum of testing. To achieve this ideal, keep in mind the different types of errors that can occur, when they’re usually detected, and how to correct them. You can detect an error at any of the following times: • Before a program is compiled • While the program is being compiled • While the program is running • After the program has been executed and the output is being examined The method for detecting errors before a program is compiled is called desk checking because you’re usually sitting at a desk with the code in front of you. It refers to the process of examining the source code for mistakes immediately after you type it. Errors detected while the program is being compiled are called compile-time errors, and errors that occur while the program is running are called runtime errors. Other names for compile-time errors are syntax errors and parse errors, terms that emphasize the type of error the compiler detects. By now, you have probably encountered numerous compile-time errors. Beginning programmers tend to be frustrated by them, but experienced programmers understand the compiler is doing a lot of valuable checking, and correcting errors the compiler does detect is usually easy. Because these errors occur while the program is being developed, not while a user is performing an important task, no one but the programmer ever knows they occurred. You fix them, and they go away. Runtime errors are more troubling because they occur while a user is running the program; in most commercial systems, the user isn’t the programmer. Many error types can cause a runtime error, such as a hardware failure. From a programming standpoint, however, most runtime errors are referred to as logic errors or faulty logic, which encompasses not analyzing what the program should do or not anticipating how users can make the program fail. For example, if a user enters data that results in an attempt to divide a number by zero, a runtime error occurs. As a programmer, the only way to protect against runtime errors is to anticipate everything a person might do to cause errors and submit your program to rigorous testing. Beginning programmers tend to blame users for an error caused by entering incorrect data, 164 Assignment, Formatting, and Interactive Input
  • 185. but professionals don’t. They understand that a runtime error is a flaw that can damage the reputation of the program and programmer. To prevent compile-time and runtime errors, it’s more fruitful to determine what causes them. As mentioned, compile-time errors are also called syntax errors: mistakes in the structure or spelling of a statement. For example, examine the following statements: cout << "There are four syntax errors heren cot " Can you find tem"; They contain the following syntax errors: 1. A closing quotation mark is missing in line 1. 2. A terminating semicolon (;) is missing in line 1. 3. The keyword cout is misspelled in line 2. 4. The insertion operator, <<, is missing in line 2. When the program is compiled, the compiler detects all these errors because they’re syntax errors that violate the basic rules of C++. If they aren’t discovered by desk checking, the compiler detects them and displays an error message.11 Sometimes the error message is clear and the error is obvious; at other times, understanding the compiler’s error message takes a little detective work. Because syntax errors are the only error type that can be detected at compile time, the terms “compile-time errors” and “syntax errors” are used interchangeably. Strictly speaking, however, compile-time refers to when the error is detected, and syntax refers to the type of error detected. The misspelling of “them” in the second statement isn’t a syntax error. Although this spelling error results in displaying an undesirable output line, it’s not a violation of C++’s syntax rules. It’s a typographical error, commonly referred to as a “typo.” The compiler doesn’t catch this type of typographical error.12 Another error the compiler doesn’t catch is a logic error, which can cause a runtime error or produce incorrect results. These errors are characterized by erroneous, unexpected, or unintentional output that’s a direct result of some flaw in the program’s logic. These errors can be detected by desk checking, by program testing, by accident when a user gets erroneous output while the program is executing, or not at all. If the error is detected while the program is executing, a runtime error can occur that generates an error message, causes premature program termination, or both. The most serious logic error is caused by not fully understanding the program’s requirements because the logic in a program reflects the logic on which it’s coded. For example, if a program’s purpose is to calculate the load-bearing strength of a steel beam and the programmer doesn’t fully understand how to make the calculation, what inputs are needed to perform the calculation, or what special conditions exist (such as how temperature affects the beam), a logic error occurs. Because the compiler doesn’t detect these errors and they often go undetected at runtime, they are always more difficult to detect than syntax errors. 11 They might not, however, be detected at the same time. Frequently, one syntax error masks another error, and the second error is detected after the first error is corrected. 12 The misspelling of a C++ keyword or a declared variable name that results in an undeclared name is caught, however, because it results in a syntax error or an undeclared variable. 165 Chapter 3 A Closer Look: Programming Errors
  • 186. If logic errors are detected, typically they’re revealed in one of two main ways. First, the program executes to completion but produces incorrect results, such as the following: • No output—This result is caused by omitting an output statement or using a sequence of statements that inadvertently bypasses an output statement. • Unappealing or misaligned output—This result is caused by an error in an output statement. • Incorrect numerical results—This result is caused by assigning incorrect values to variables in an expression, using an incorrect arithmetic expression, omitting a statement, making a round-off error, or using an improper sequence of statements. Second, a runtime error occurs. Examples of logic errors that cause this result are attempts to divide by zero or take the square root of a negative number. Plan your program testing carefully to maximize the possibility of locating errors. In addition, remember that although a single test can reveal the presence of an error, it does not verify that another error isn’t lurking somewhere else in the program. Furthermore, the fact that one test revealed no errors does not mean there are no errors. After you discover an error, however, you must locate where it occurs and fix it. In computer jargon, a program error is referred to as a bug, and the process of isolating, correcting, and verifying the correction is called debugging. Although no hard-and-fast rules exist for isolating the cause of an error, some useful techniques can be applied. The first is preventive. Often programmers introduce errors in the rush to code and run a program before understanding what’s required and how to achieve the result, as you learned in Chapter 2. Many errors can be eliminated by desk checking the program before entering or compiling it. A second useful technique is imitating the computer by executing each statement by hand as the computer would. This technique, called program tracing, involves writing down each variable, as it’s encountered in the program, and listing the value that should be stored in the variable as each input and assignment statement is encountered. Doing this sharpens your programming skills because it helps you understand what each statement in your program causes to happen. A third useful technique is including some temporary code in your program that displays the values of selected variables. If the displayed values are incorrect, you can determine what part of your program generated them and make the necessary corrections. You could also add temporary code that displays the values of all input data. This technique, called echo printing, is useful in establishing that the program is receiving and interpreting input data correctly. The most powerful technique is using a special program called a debugger. A debugger program can control the execution of a C++ program, interrupt the C++ program at any point in its execution, and display the values of all variables at the point of interruption. Finally, no discussion of debugging is complete without mentioning the main ingredient needed for isolating and correcting errors successfully: the attitude you bring to the task. After you write a program, you naturally assume it’s correct. Taking a step back to be objective about testing and finding errors in your own software is difficult. As a programmer, you must remind yourself that just because you think your program is correct doesn’t make it so. Finding errors in your own programs is a sobering experience but one that helps you become a better programmer. The process can be exciting and fun if you approach it as a detection problem, with you as the master detective. 166 Assignment, Formatting, and Interactive Input
  • 187. 3.8 Common Programming Errors When using the material in this chapter, be aware of the following possible errors: 1. Forgetting to assign or initialize values for all variables before using them in an expression. Values can be assigned by assignment statements, initialized in a declaration statement, or assigned interactively by entering values with a cin statement. 2. Using a mathematical library function without including the preprocessor statement #include <cmath> (and on a UNIX-based system, forgetting to include the -lm argument on the cc command line). 3. Using a library function without providing the correct number of arguments of the proper data type. 4. Applying the increment or decrement operator to an expression. For example, the expression (count + n)++ is incorrect. The increment and decrement operators can be applied only to variables. 5. Forgetting to use the extraction operator, >>, to separate variables in a cin statement. 6. A more unusual error occurs when increment and decrement operators are used with variables appearing more than once in the same expression. This error occurs because C++ doesn’t specify the order in which operands are accessed in an expression. For example, the value assigned to result in the following statement depends on the compiler: result = i + i++; If your compiler accesses the first operand (i) first, the preceding statement is equivalent to result = 2 * i; i++; However, if your compiler accesses the second operand (i++) first, the value of the first operand is altered before it’s used the second time, and the value 2i + 1 is assigned to result. As a general rule, don’t use the increment or decrement operator in an expression when the variable it operates on appears more than once in the expression. 7. Being unwilling to test a program in depth. Being objective about testing your own software is difficult, but as a programmer, you must remind yourself that just because you think your program is correct doesn’t make it so. 3.9 Chapter Summary 1. An expression is a sequence of one or more operands separated by operators. An operand is a constant, a variable, or another expression. A value is associated with an expression. 2. Expressions are evaluated according to the precedence and associativity of the operators used in the expression. 167 Chapter 3 Chapter Summary
  • 188. 3. The assignment operator is the = symbol. Expressions using this operator assign a value to a variable, and the expression also takes on a value. Because assignment is a C++ operation, the assignment operator can be used more than once in the same expression. 4. The increment operator, ++, adds one to a variable, and the decrement operator, --, subtracts one from a variable. Both operators can be used as prefixes or postfixes. In a prefix operation, the variable is incremented (or decremented) before its value is used. In a postfix operation, the variable is incremented (or decremented) after its value is used. 5. C++ provides library functions for calculating square root, logarithmic, and other mathematical computations. Programs using a mathematical function must include the statement #include <cmath> or have a function declaration before calling the mathematical function. 6. Every mathematical library function operates on its arguments to calculate a single value. To use a library function effectively, you must know the function name, what the function does, the number and data types of arguments the function expects, and the data type of the returned value. 7. Values passed to a function are called arguments of the function. Arguments are passed to a library function by including each argument, separated by commas, in the parentheses following the function’s name. Each function has its own requirements for the number and data types of the arguments that must be provided. 8. Functions can be included in larger expressions. 9. A cin statement is used for data input. cin accepts a stream of data from the keyboard and assigns the data to variables. This is the general form of a statement using cin: cin >> var1 >> var2 . . . >> varn; The extraction operator, >>, must be used to separate variable names in a cin statement. 10. When a cin statement is encountered, the computer temporarily suspends further execution until enough data has been entered for the number of variables in the cin statement. 11. It’s a good programming practice to display a message before a cin statement that alerts users to the type and number of data items to be entered. This message is called a prompt. It’s even a better programming practice to permit only one input variable for each cin statement. 12. Values can be equated to a single constant by using the const keyword. This keyword creates a named constant that is read-only after it’s initialized in the declaration statement. This declaration has the syntax const dataType SymbolicName = initialValue; and permits using the constant instead of the initialValue anywhere in the program after the declaration. 168 Assignment, Formatting, and Interactive Input
  • 189. Programming Projects for Chapter 3 1. (General Math) a. Write a C++ program to calculate and display the value of the slope of the line connecting two points with the coordinates (3,7) and (8,12). Use the fact that the slope between two points with the coordinates (x1,y1) and (x2,y2) is (y2 - y1) / (x2 - x1). b. How do you know the result your program produced is correct? c. After verifying the output your program produces, modify it to determine the slope of the line connecting the points (2,10) and (12,6). d. What do you think will happen if you use the points (2,3) and (2,4), which results in a division by zero? How do you think this situation can be handled? e. If your program doesn’t already do so, change its output to this: The value of the slope is xxx.xx The xxx.xx denotes placing the calculated value in a field wide enough for three places to the left of the decimal point and two places to the right of it. 2. (General Math) a. Write a C++ program to calculate and display the midpoint coordinates of the line segment connecting the two endpoints given in Exercise 1a. Use the fact that the coordinates of the midpoint between two points with the coordinates (x1,y1) and (x2,y2) are ((x1+x2)/2, (y1+y2)/2). Your program should produce the following display (replacing the underscores with values your program calculates): The x midpoint coordinate is _____ The y midpoint coordinate is _____ b. How do you know the midpoint values your program calculates are correct? c. After verifying the output your program produces, modify it to determine the midpoint coordinates of the line connecting the points (2,10) and (12,6). d. If your program doesn’t already do so, change its output to this: The x coordinate of the midpoint is xxx.xx The y coordinate of the midpoint is xxx.xx The xxx.xx denotes placing the calculated value in a field wide enough for three places to the left of the decimal point and two places to the right of it. 3. (General Math) Modify the program written for Exercise 2 so that it accepts the x and y coordinates of two points. Have your program determine and display the midpoints of the two points (use the formula given in Exercise 2). Verify your program by using the following test data: Test data set 1: Point 1 = (0,0) and Point 2 = (16,0) Test data set 2: Point 1 = (0,0) and Point 2 = (0,16) Test data set 3: Point 1 = (0,0) and Point 2 = (-16,0) Test data set 4: Point 1 = (0,0) and Point 2 = (0,-16) Test data set 5: Point 1 = (-5,-5) and Point 2 = (5,5) 169 Chapter 3 Programming Projects
  • 190. When you have finished your verification, use your program to complete the following chart: First Point Second Point Midpoint (4, 6) (16, 18) (22, 3) (8, 12) (-10, 8) (14, 4) (-12, 2) (14, 3.1) (3.1,-6) (20, 16) (3.1, -6) (-16, -18) 4. (Biology) The number of bacteria, B, in a culture that’s subject to refrigeration can be approximated by this formula: B = 300000 e-0.032t e is Euler’s number 2.71828 (rounded to five decimal places). t is the time in hours the culture has been refrigerated. Using this formula, write, compile, and execute a single C++ program that prompts the user for a value of time, calculates the number of bacteria in the culture, and displays the result. For testing purposes, check your program by using a test input of 10 hours. After verifying your program, use it to determine the number of bacteria in the culture after 12, 18, 24, 36, 48, and 72 hours. 5. (Heat Transfer) The time it takes for a spherical object to cool from an initial temperature of Tinit to a final temperature of Tfin, caused entirely by radiation, is provided by Kelvin’s cooling equation: t Nk e A T T =       2 1 1 3 3 σ fin init - t is the cooling time in years. N is the number of atoms. k is Boltzmann’s constant = 1.38 × 10-23 m2 kg/s2 K (note that 1 Joule = 1 m2 kg/s2 ). e is emissivity of the object. ␴ is Stephan-Boltzmann’s constant = 5.6703 × 10-8 Watts/m2 K4 . A is the surface area. Tfin is the final temperature. Tinit is the initial temperature. Assuming an infinitely hot initial temperature, this formula reduces to t Nk e AT = 2 3 σ fin 170 Assignment, Formatting, and Interactive Input
  • 191. Using this second formula, write a C++ program to determine the time it took Earth to cool to its current surface temperature of 300°K from its initial infinitely hot state, assuming the cooling is caused only by radiation. Use the information that the area of the Earth’s surface is 5.15 × 1014 m2 , its emissivity is 1, the number of atoms contained in the Earth is 1.1 × 1050 , and the radius of the Earth is 6.4 × 106 meters. Additionally, use the relationship that a sphere’s surface area is given by this formula: Surface area of a sphere = 4 ␲ r2 6. (Heat Transfer) The formula developed in Exercise 5 can be used to determine the cooling time, t, caused only by radiation, of each planet in the solar system. For convenience, this formula is repeated here (see Exercise 5 for a definition of each symbol): t Nk e AT = 2 3 σ fin A = surface area of a sphere = 4 ␲ r2 N = number of atoms = volume of the sphere volume of an atom Volume of a sphere = 4 3 ␲ radius3 The volume of a single atom is approximately 1 × 10-29 m3 . Using this information and the current temperatures and radii listed in the following chart, determine the time it took each planet to cool to its current temperature, caused only by radiation. Planet Current Average Surface Temperature (°Celsius) Radius (km) Cooling Time (years) Mercury 270 2439 Venus 462 6051 Earth 14 6371 Mars -46 3396 Jupiter -108 7.1492 × 104 Saturn -139 6.0268 × 104 Uranus -197 2.5559 × 104 Neptune -201 2.4764 × 104 7. (Physics) When a particular rubber ball is dropped from a given height (in meters), its impact speed (in meters/second) when it hits the ground is given by the formula speed gh = 2 where g is the acceleration caused by gravity and h is the height. The ball then rebounds to 2/3 the height from which it last fell. Using this information, write, test, and run a C++ program that calculates and displays the impact speed of the first three bounces and the 171 Chapter 3 Programming Projects
  • 192. rebound height of each bounce. Test your program by using an initial height of 2.0 meters. Run the program twice, and compare the results for dropping the ball on Earth (g = 9.81 meters/sec2 ) and on the moon (g = 1.67 meters/sec2 ). 8. (Electrical Eng.) a. The voltage gain of an amplifier is given by this formula: 275 23 0 5 2 2 +         . f n voltage gain = f is the frequency in Hz. n is the number of stages in the amplifier. Using this formula, write, compile, and execute a C++ program to determine the value of the voltage gain for a four-stage amplifier operating at a frequency of 120 Hz. Your program should produce the following display: At a frequency of xxxxx Hertz, the voltage gain is yyyyy Your program should replace xxxxx with the frequency and yyyyy with the voltage gain. b. Manually check the value your program produces. After verifying that your program is working correctly, modify it to determine the voltage gain of a 12-stage amplifier operating at a frequency of 9500 Hz. 9. (Electrical Eng.) Write, compile, and execute a C++ program that calculates and displays the value of the current flowing through an RC circuit (see Figure 3.18). The circuit consists of a battery connected in a series to a switch, a resistor, and a capacitor. When the switch is closed, the current, i, flowing through the circuit is given by this formula: i = (E/R) e-t/RC E is the voltage of the battery in volts. R is the value of the resistor in ohms. C is the value of the capacitor in farads. t is the time in seconds after the switch is closed. e is Euler’s number, which is 2.71828 (rounded to five decimal places). Using this formula, write, compile, and run a C++ program to determine the voltage across the capacitor shown in Figure 3.18 when t is 0.31 seconds. (Note: The value of RC is referred to as the system’s time constant.) The program should prompt the user to enter appropriate values and use input statements to accept the data. In constructing the prompts, use statements such as 172 Assignment, Formatting, and Interactive Input
  • 193. “Enter the voltage of the battery.” Verify your program’s operation by calculating by hand the current for the following test data: Test data set 1: Voltage = 20 volts, R = 10 ohms, RC = 0.044, t = 0.023 seconds. Test data set 2: Voltage = 35, R = 10 ohms, RC = 0.16, t = 0.067 seconds. b. Check the value computed by your program by hand. After verifying that your program is working correctly, use your program to complete the following chart: Voltage V (volts) Resistance R (ohms) RC (Time Constant) Time t (sec) Current i (amps) 35 10 0.16 0.11 35 10 0.16 0.44 35 10 0.16 0.83 15 10 0.55 0.11 15 10 0.55 0.44 15 10 0.55 0.067 6 1000 2.6 12.4 10. (Electrical Eng.) The amplification of electronic circuits is measured in units of decibels, which is calculated as 10 LOG (Po/Pi) where Po is the power of the output signal and Pi is the power of the input signal. Using this formula, write, compile, and execute a C++ program to calculate and display the decibel amplification, in which the output power is 50 times the input power. Verify your program’s result by using a hand calculation. After verifying that your program is working correctly, use it to determine the amplification of a circuit, where output power is 4.639 Watts and input power is 1 Watt. R C E Switch Figure 3.18 A series RC circuit 173 Chapter 3 Programming Projects
  • 194. 11. (Acoustics) The loudness of a sound is measured in units of decibels and is calculated as shown: 10 LOG (SL/RL) SL is the intensity of the sound being measured. RL is a reference sound-intensity level. Using this formula, write a C++ program that calculates and displays the decibel loudness of a busy street having a sound intensity of 10,000,000 RL. Verify your program’s result by using a hand calculation. After verifying that your program is working correctly, use it to determine the sound level in decibels of the following sounds: a. A whisper at sound intensity 200 RL b. A rock band playing at sound intensity 1,000,000,000,000 RL c. An airplane taking off at sound intensity 100,000,000,000,000 RL 12. (General Math) a. A balance has the following size weights: 100 lb, 50 lb, 10 lb, 5 lb, and 1 lb. The number of 100 lb and 50 lb weights required to weigh an object weighing WEIGHT pounds can be calculated by using the following C++ statements: // Determine the number of 100 lb weights w100 = int(WEIGHT/100) // Determine the number of 50 lb weights w50 = int((WEIGHT - w100 * 100)/50) Using these statements as a starting point, write a C++ program that calculates the number of each type of weight needed to weigh a 789 lb object. b. Without compiling or executing your program, manually check the effect of each statement in the program and determine what’s stored in each variable as each statement is encountered. c. After verifying that your algorithm works correctly, compile and execute your program. Verify that the results your program produces are correct. After verifying that your program is working correctly, use it to determine the weights required to weigh a 626 lb object. 174 Assignment, Formatting, and Interactive Input
  • 195. Engineering and Scientific Disciplines Electrical Engineering Electrical engineering, the largest engineering field, deals with applying the principles of electricity and electromagnetism to the manufacture of all forms of machines and devices that use electricity or produce electrical energy. In the mid-1800s, this field was concerned solely with generating electrical energy, but it has evolved into a broad field encompassing the following areas, among others: 앫 Power: This area involves generation of electrical energy in large fossil-fuel, nuclear, solar, and hydroelectric plants as well as efficient use of electrical energy by means of motors or illumination devices. Also important are transmitting and distributing electrical energy through overhead lines, microwaves, light pipes, and superconducting lines. 앫 Solid-state electronics: Through modern physics and materials science, semicon- ducting materials are developed and used to construct microcircuitry for moni- toring and controlling the operations of all kinds of devices, from video games to assembly-line robots. The improved reliability, rapidly shrinking size, and reduced power requirements of modern miniaturized electrical components have created limitless opportunities for applications. 앫 Communications: This area involves designing and constructing equipment used to transmit information via electricity or electromagnetic waves (radio, light, microwaves, and so on). This field used to include antenna characteristics and radar, but using laser for communication is the current topic. 앫 Computers and robotics: Although electronics deals with principles associated with the functions of components, computer engineers are concerned with designing the complex circuitry that interweaves components into a computer. Microprocessors, or small computers, are designed to constantly monitor and control the operations of a piece of equipment, such as a lathe or an autopilot. 175 Chapter 3 Programming Projects
  • 196. This page intentionally left blank
  • 197. Chapter 4 Selection Structures 4.1 Selection Criteria 4.2 The if-else Statement 4.3 Nested if Statements 4.4 The switch Statement 4.5 A Case Study: Solving Quadratic Equations 4.6 A Closer Look: Program Testing 4.7 Common Programming Errors 4.8 Chapter Summary The term “flow of control” refers to the order in which a program’s statements are executed. Unless directed otherwise, the normal, default flow of control for all programs is sequential. This term means statements are executed in sequence, one after another, in the order in which they’re placed in a program. In addition to sequential execution, all high-level languages provide three other control structures to alter the sequential flow of control in precisely defined ways. Here, the term “control structure” simply means a construction that specifies the order in which statements are to be executed. The three additional control structures are called selection, repetition, and invocation. As you might have guessed by its name, a selection structure is used to select statements to be performed next, and a repetition structure is used to force a repeat execution of a set of statements. Invocation is a means of invoking, or forcing, a set of statements, which have previously been combined into a separate function, to be executed at a particular point in a program. As any algorithm, no matter how complex, can be programmed by using one or more of the four standardized flow of control structures (sequential, selection, repetition, and invocation), understanding how each of these structures is constructed and operates is a primary requirement for all programmers. This chapter discusses C++’s selection control structures, and Chapters 5 and 6 cover repetition and invocation control structures.
  • 198. 4.1 Selection Criteria In solving many problems, different actions must be taken, depending on the data’s value. Examples of simple situations include calculating an area only if the measurements are positive, performing a division only if the divisor isn’t zero, printing different messages depending on the value of a grade received, and so on. The if-else statement in C++ is used to implement such a decision structure in its simplest form—choosing between two alternatives. The most commonly used pseudocode syntax of this statement is as follows: if (condition) statement executed if the condition is true; else statement executed if the condition is false; When a running program encounters the if statement, the condition is evaluated to determine its numerical value, which is then interpreted as true or false. If the condition evaluates to any positive or negative non-zero numerical value, the condition is considered a “true” condition and the statement following the if is executed. If the condition evaluates to a zero numerical value, the condition is considered a “false” condition and the statement following the else is executed. The else part of the statement is optional and can be omitted. Relational Operators The condition used in an if statement can be any valid C++ expression (including, as you’ll see, even an assignment expression). The most commonly used conditions, however, are simple relational expressions. A simple relational expression consists of a relational operator that compares two operands, as shown in Figure 4.1. Although each operand in a relational expression can be a variable or a constant, relational operators must be one of those listed in Table 4.1. These relational operators can be used with integer, float, double, or character operands but must be typed exactly as shown in Table 4.1. For example, although the following examples are all valid, age > 40 length <= 50 temp > 98.6 3 < 4 flag == done idNum == 682 day != 5 2.0 > 3.3 hours > 40 operand operand expression relational operator watts < 15.2 Figure 4.1 A simple relational expression 178 Selection Structures
  • 199. the following are invalid: length =< 50 // operator out of order 2.0 >> 3.3 // invalid operator flag = = done // spaces are not allowed Table 4.1 C++’s Relational Operators Relational Operator Meaning Example < Less than age < 30 > Greater than height > 6.2 <= Less than or equal to taxable <= 20000 >= Greater than or equal to temp >= 98.6 == Equal to grade == 100 != Not equal to number != 250 The terms relational expression and condition are frequently used as synonyms, and both terms are used interchangeably in this book. Like all C++ expressions, relational expressions are evaluated to yield a numerical result.1 In a relational expression, the value of the expression can be only the integer value 1 or 0. These values are interpreted as true and false, respectively. Conversely, a relational expression that’s true always evaluates to an integer value of 1, and a relational expression that’s false always evaluates to an integer value of 0. For example, because the relationship 3 < 4 is always true, this expression has a value of 1, and because the relationship 2.0 > 3.0 is always false, the value of the expression itself is 0. This rule can be verified by the following statements, cout << "The value of 3 < 4 is " << (3 < 4) << endl; cout << "The value of 2.0 > 3.0 is " << (2.0 > 3.0) << endl; cout << "The value of true is " << true << endl; cout << "The value of false is " << false << endl; which result in this display: The value of 3 < 4 is 1 The value of 2.0 > 3.0 is 0 The value of true is 1 The value of false is 0 The value of a relational expression such as hours > 40 depends on the value stored in the variable hours. In a C++ program, a relational expression’s value isn’t as important as the interpretation C++ places on the value when the expression is used as part of a selection statement. In these statements, which are explained in the next section, you’ll see that C++ uses a zero value to represent a false condition and any non-zero value to represent a true condition. The selection of which statement to execute next is then based on the value. In addition to numerical operands, character data can be compared by using relational operators. For these comparisons, the char values are coerced to int values automatically for the comparison. For example, in Unicode, the letter 'A' is stored by using a code with a lower numerical value than the letter 'B', the code for 'B' has a lower value than the 1 In this regard, C++ differs from other high-level languages, which yield a Boolean (true or false) result. 179 Chapter 4 Selection Criteria
  • 200. code for 'C', and so on. For character sets coded in this manner, the following conditions are evaluated as shown: Expression Value Interpretation 'A' > 'C' 0 false 'D' <= 'Z' 1 true 'E' == 'F' 0 false 'g' >= 'm' 0 false 'b' != 'c' 1 true 'a' == 'A' 0 false 'B' < 'a' 1 true 'b' > 'Z' 1 true Comparing letters is essential in alphabetizing names or using characters to select a choice in decision-making situations. Strings of characters can also be compared, and two string expressions can be compared by using relational operators or the string class’s comparison methods (discussed in Section 9.3). In the ASCII character set, a blank precedes (and is considered “less than”) all letters and numbers; the letters of the alphabet are stored in order from A to Z; and digits are stored in order from 0 to 9. In this sequence, lowercase letters come after (are considered “greater than”) uppercase letters, and letter codes come after (are “greater than”) digit codes (see Appendix B). When two strings are compared, their characters are compared one pair at a time (both first characters, then both second characters, and so on). If no differences are found, the strings are equal; if a difference is found, the string with the first lower character is considered the smaller string. Following are examples of string comparisons: Expression Value Interpretation Comment "Hello" > "Good-bye" 1 true The first H in Hello is greater than the first G in Good-bye. "SMITH" > "JONES" 1 true The first S in SMITH is greater than the first J in JONES. "123" > "1227" 1 true The third character in 123, the 3, is greater than the third character in 1227, the 2. "Behop" > "Beehive" 1 true The third character in Behop, the h, is greater than the third character in Beehive, the second e. "He" == "She" 0 false The first H in He is not equal to the first S in She. "plant" < "planet" 0 false The t in plant is greater than the e in planet. 180 Selection Structures
  • 201. Logical Operators In addition to using simple relational expressions as conditions, more complex conditions can be created by using the logical operators AND, OR, and NOT. These operators are represented by the symbols &&, ||, and !, respectively. When the AND operator, &&, is used with two simple expressions, the condition is true only if both expressions are true by themselves. Therefore, the logical condition (voltage > 48) && (milliamp < 10) is true only if voltage is greater than 48 and milliamp is less than 10. Because relational operators have a higher precedence than logical operators, the parentheses in this logical expression could have been omitted. The logical OR operator, ||, is also used with two expressions. When using the OR operator, the condition is satisfied if one or both of the two expressions are true. Therefore, the condition (voltage > 48) || (milliamp < 10) is true if voltage is greater than 48, milliamp is less than 10, or both conditions are true. Again, the parentheses surrounding the relational expressions are included to make the statement easier to read. Because relational operators have a higher precedence than logical operators, the same evaluation is made even if the parentheses are omitted. For the declarations int i, j; double a, b, complete; the following are valid conditions: a > b (i == j) || (a < b) || complete (a/b > 5) && (i <= 20) Before these conditions can be evaluated, the values of a, b, i, j, and complete must be known. Assuming a = 12.0, b = 2.0, i = 15, j = 30, and complete = 0.0, the previous expressions yield the following results: Expression Value Interpretation a > b 1 true (i == j) || (a < b) || complete 0 false (a/b > 5) && (i <= 20) 1 true The NOT operator, !, is used to change an expression to its opposite state; that is, if the expression has a non-zero value (true), the statement !expression produces a zero value (false). If an expression is false to begin with (has a zero value), !expression is true and evaluates to 1. For example, if the number 26 is stored in the variable age, the expression age > 40 has a value of 0 (false), and the expression !(age > 40) has a value of 1 (true). Because the NOT operator is used with only one expression, it’s a unary operator. 181 Chapter 4 Selection Criteria
  • 202. Relational and logical operators have a hierarchy of execution similar to arithmetic operators. Table 4.2 lists the precedence of these operators in relation to the other operators you have used. Table 4.2 Operator Precedence and Associativity Operator Associativity ! unary – ++ -- Right to left * / % Left to right + – Left to right < <= > >= Left to right == != Left to right && Left to right || Left to right = += –= *= /= Right to left The following chart illustrates using an operator’s precedence and associativity to evaluate relational expressions, assuming the following declarations: char key = 'm'; int i = 5, j = 7, k = 12; double x = 22.5; Expression Equivalent Expression Value Interpretation i + 2 == k - 1 (i + 2) == (k - 1) 0 false 3 * i - j < 22 (3 * i) - j < 22 1 true i + 2 * j > k (i + (2 * j)) > k 1 true k + 3 <= -j + 3 * i (k + 3) <= ((-j) + (3*i)) 0 false 'a' + 1 == 'b' ('a' + 1) == 'b' 1 true key - 1 > 'p' (key - 1) > 'p' 0 false key + 1 == 'n' (key + 1) == 'n' 1 true 25 >= x + 1.0 25 >= (x + 1.0) 1 true As with all expressions, parentheses can be used to alter the assigned operator priority and improve the readability of relational expressions. By evaluating the expressions in parentheses first, the following compound condition is evaluated as shown: (6 * 3 == 36 / 2) || (13 < 3 * 3 + 4) && !(6 - 2 < 5) (18 == 18) || (13 < 9 + 4) && !(4 < 5) 1 || (13 < 13) && !1 1 || 0 && 0 1 || 0 1 182 Selection Structures
  • 203. A Numerical Accuracy Problem In C++’s relational expressions, a subtle numerical accuracy problem related to single- precision and double-precision numbers can occur. Because of the way computers store these numbers, you should avoid testing for equality of single-precision and double-precision values and variables by using the relational operator ==. The reason is that many decimal numbers, such as 0.1, can’t be represented in binary with a finite number of bits, so testing for exact equality for these numbers can fail. When you want equality of noninteger values, it’s better to require that the absolute value ofthe difference between operands be less than some extremely small value. Therefore, for single-precision and double-precision operands, the general expression operandOne == operandTwo should be replaced by the condition abs(operandOne – operandTwo) < 0.000001 where the value 0.000001 can be altered to any other acceptably small value. Therefore, if the difference between the two operands is less than 0.000001 (or another user-selected amount), the two operands are considered essentially equal. For example, if x and y are single- precision variables, a condition such as x/y == 0.35 should be programmed as the following: abs(x/y - 0.35) < EPSILON EPSILON can be a constant set to any acceptably small value, such as 0.000001.2 Not requiring exact equivalence to zero ensures that slight inaccuracies in representing noninte- ger numbers in binary don’t affect evaluation of the tested condition. Because all computers have an exact binary representation of 0, comparisons for exact equality to 0 don’t have this numerical accuracy problem. EXERCISES 4.1 1. (Practice) Determine the value of the following expressions, assuming a = 5, b = 2, c = 4, d = 6, and e = 3: a. a > b b. a != b c. d % b == c % b d. a * c != d * b e. d * b == c * e 2 Using the abs() function requires including the cmath header file by placing the preprocessor command #include<cmath> before or after #include<iostream>. UNIX-based systems also require including the math library with the -lm command-line argument. 183 Chapter 4 Selection Criteria
  • 204. f. !(a * b) g. !(a % b * c) h. !(c % b * a) i. b % c * a 2. (Practice) Using parentheses, rewrite the following expressions to indicate their order of evaluation correctly. Then evaluate each expression, assuming a = 5, b = 2, and c = 4. a. a % b * c && c % b * a b. a % b * c || c % b * a c. b % c * a && a % c * b d. b % c * a || a % c * b 3. (Practice) Write relational expressions to express the following conditions (using variable names of your choosing): a. The distance is equal to 30 feet. b. The ambient temperature is 86.4 degrees. c. A speed is 55 mph. d. The current month is 12 (December). e. The letter input is K. f. A length is greater than 2 feet and less than 3 feet. g. The current day is the 15th day of the 1st month. h. The automobile’s speed is 35 mph and its acceleration is greater than 4 mph per second. i. An automobile’s speed is greater than 50 mph and it has been moving for at least 5 hours. j. The code is less than 500 characters and takes more than 2 microseconds to transmit. 4. (Practice) Determine the value of the following expressions, assuming a = 5, b = 2, c = 4, and d = 5: a. a == 5 b. b * d == c * c c. d % b * c > 5 || c % b * d < 7 4.2 The if-else Statement The if-else structure directs the computer to select between two statements based on the result of a comparison. For example, suppose you need to calculate the area of a circle, given the radius as an input value. If the input is a negative number, you want to print a message, using one cout statement, that the radius can’t be a negative value; otherwise, you calculate and print the circle’s area, using a second cout statement. The if-else structure can be 184 Selection Structures
  • 205. used in this situation to select the correct operation based on whether the radius is negative. This is the general syntax of the if-else statement: if (expression) statement1; else statement2; The expression is evaluated first. If its value is non-zero, statement1 is executed. If its value is zero, the statement after the keyword else is executed. Therefore, one of the two statements (statement1 or statement2, but not both) is always executed, depending on the expression’s value. Notice that the tested expression must be enclosed by parentheses and a semicolon is placed after each statement. For clarity, the if-else statement is typically written on four lines in this form: if (expression) no semicolon here statement1; else no semicolon here statement2; The form of the if-else statement that’s used typically depends on the length of statement1 and statement2. However, when using this four-line form, don’t put a semicolon after the parentheses or the else keyword. The semicolons are placed only at the ends of statements. Figure 4.2 shows the flowchart for the if-else statement. As a specific example of an if-else structure, take a look at constructing a C++ program for determining a circle’s area by examining the value of the radius first. The condition to be tested is whether the radius is less than 0, so the following is an appropriate if-else statement for this situation: if (radius < 0.0) cout << "A negative radius is invalid" << endl; else cout << "The area of this circle is " << 3.1416 * pow(radius,2) << endl; The relational operator < is used to represent the condition “less than.” If the value of radius is less than 0, the condition is true (has a value of 1) and the statement cout << "A negative radius is invalid"; is executed. If the condition is not true, the value of the expression is 0, and the statement after the else keyword is executed. Program 4.1 shows using this statement in a complete program. 185 Chapter 4 The if-else Statement
  • 206. Program 4.1 #include <iostream> #include <cmath> using namespace std; int main() { double radius; cout << "Please type in the radius: "; cin >> radius; if (radius < 0.0) cout << "A negative radius is invalid" << endl; else cout << "The area of this circle is " << 3.1416 * pow(radius,2) << endl; return 0; } next statement statement 1 is condition true? previous statement no yes (else part) statement 2 Figure 4.2 The if-else flowchart 186 Selection Structures
  • 207. A blank line is inserted before and after the if-else statement to highlight it in the program. This format is used throughout the book to emphasize the statement being discussed. To illustrate selection in action, Program 4.1 is run twice with different input data. These are the results: Please type in the radius: -2.5 A negative radius is invalid and Please type in the radius: 2.5 The area of this circle is 19.635 In reviewing this output, observe that the radius in the first run is less than 0, and the if part of the if-else structure executes the cout statement correctly, telling the user that a negative radius is invalid. In the second run, the radius isn’t negative, and the else part of the if-else structure is used to yield this correct area computation: 3.1416 * (2.5)2 = 19.635 Although any expression can be tested by an if-else statement, relational expressions are used most often. However, statements such as the following are valid: if (num) cout << "Bingo!"; else cout << "You lose!"; Because num is a valid expression by itself, the message Bingo! is displayed if num has any non-zero value, and the message You lose! is displayed if num has a value of zero. Compound Statements Although only a single statement is permitted in the if and else parts of the if-else statement, each single statement can be a compound statement. A compound statement is a sequence of single statements between braces, as shown in this example: { statement1; statement2; statement3; . . . last statement; } 187 Chapter 4 The if-else Statement
  • 208. Using braces to enclose a set of statements creates a single block of statements, which can be used anywhere in a C++ program in place of a single statement. The next example shows using a compound statement in the general form of an if-else statement: if (expression) { statement1; // as many statements as necessary statement2; // can be put inside the braces statement3; // each statement must end with a ; } else { statement4; statement5; . . last statement; } Program 4.2 shows using a compound statement in an actual program. Program 4.2 checks whether the value in tempType is f. If so, the compound statement corresponding to the if part of the if-else statement is executed. Any other letter in tempType results in execution of the compound statement corresponding to the else part. A sample run of Program 4.2 follows: Enter the temperature to be converted: 212 Enter an f if the temperature is in Fahrenheit or a c if the temperature is in Celsius: f The equivalent Celsius temperature is 100.00 188 Selection Structures
  • 209. Program 4.2 #include <iostream> #include <iomanip> using namespace std; // a temperature conversion program int main() { char tempType; double temp, fahren, celsius; cout << "Enter the temperature to be converted: "; cin >> temp; cout << "Enter an f if the temperature is in Fahrenheit"; cout << "n or a c if the temperature is in Celsius: "; cin >> tempType; // set output formats cout << setiosflags(ios::fixed) << setiosflags(ios::showpoint) << setprecision(2); if (tempType == 'f') { celsius = (5.0 / 9.0) * (temp - 32.0); cout << "nThe equivalent Celsius temperature is " << celsius << endl; } else { fahren = (9.0 / 5.0) * temp + 32.0; cout << "nThe equivalent Fahrenheit temperature is " << fahren << endl; } return 0; } 189 Chapter 4 The if-else Statement
  • 210. Block Scope All statements contained in a compound statement constitute a single block of code, and any variable declared in this block has meaning only between its declaration and the closing braces defining the block. For example, take a look at the following example, which consists of two blocks of code: { // start of outer block int a = 25; int b = 17; cout << "The value of a is " << a <<" and b is " << b << endl; { // start of inner block double a = 46.25; int c = 10; cout << "a is now " << a << " b is now " << b << " and c is " << c << endl; } // end of inner block cout << "a is now " << a << " and b is " << b << endl; } // end of outer block This section of code produces the following output: The value of a is 25 and b is 17 a is now 46.25 b is now 17 and c is 10 a is now 25 and b is 17 This output is produced as follows: The first block of code defines two variables named a and b, which can be used anywhere in this block after their declaration, including any block inside this outer block. In the inner block, two new variables have been declared, named a and c. The a defined in the inner block is stored in a different memory location than the a defined in the outer block. Therefore, at this stage, four different variables have been created, two with the same name. When a variable is referenced, the compiler attempts to first access a variable with the correct name that has been declared in the block containing the reference. If the referenced variable hasn’t been defined in the block, the compiler attempts to access the variable declared in the next outer block, until a valid access results. 190 Selection Structures
  • 211. Therefore, the values of the variables a and c referenced in the inner block use the values of the variables a and c declared in that block. Because no variable named b was declared in the inner block, the value of b displayed from within the inner block is obtained from the outer block. Finally, the last cout statement, which is outside the inner block, displays the value of the variable a declared in the outer block. If an attempt is made todisplay thevalue of c anywhere in the outer block, the compiler issues an error message stating that c is an undefined symbol. The area in a program where a variable can be used is formally referred to as the scope of the variable, and you delve into this subject in Chapter 6. One-Way Selection A useful modification of the if-else statement involves omitting the else part of the statement and has this shortened and often useful form: if (expression) statement; The statement following if (expression) is executed only if the expression has a non-zero value (a true condition). As before, the statement can be a compound statement. Figure 4.3 shows the flowchart for this statement. Point of Information Placement of Braces in a Compound Statement A common practice for some C++ programmers is placing the opening brace of a com- pound statement on the same line as the if and else statements. Using this conven- tion, the if statement in Program 4.2 would look like the following example. (This placement is a matter of style only—both styles are used, and both are acceptable.) if (tempType == 'f') { celsius = (5.0 / 9.0) * (temp - 32.0); cout << "nThe equivalent Celsius temperature is " << celsius << endl; } else { fahren = (9.0 / 5.0) * temp + 32.0; cout << "nThe equivalent Fahrenheit temperature is " << fahren << endl; } 191 Chapter 4 The if-else Statement
  • 212. This modified form of the if statement is called a one-way if statement. Program 4.3 uses this statement to display a message only for cars that have been driven more than 3000.0 miles. To see its one-way selection criteria in action, Program 4.3 was run twice, each time with different input data. Only the input data for the first run causes the message Car 256 is over the limit to be displayed. Please type in car number and mileage: 256 3562.8 Car 256 is over the limit. End of program output. and Please type in car number and mileage: 23 2562.3 End of program output. next statement statement is condition true? previous statement no yes Figure 4.3 A one-way if statement 192 Selection Structures
  • 213. Program 4.3 #include <iostream> using namespace std; int main() { const double LIMIT = 3000.0; int idNum; double miles; cout << "Please type in car number and mileage: "; cin >> idNum >> miles; if(miles > LIMIT) cout << " Car " << idNum << " is over the limit.n"; cout << "End of program output.n"; return 0; } Problems Associated with the if-else Statement Two of the most common problems encountered in using C++’s if-else statement are the following: • Misunderstanding the full implications of what an expression is • Using the assignment operator, =, in place of the relational operator == Recall that an expression is any combination of operands and operators that yields a result. This definition is much broader and more encompassing than is apparent at first. For example, all the following are valid C++ expressions: age + 5 age = 30 age == 40 Assuming the variables are declared correctly, each of the preceding expressions yields a result. Program 4.4 uses cout statements to display the value of these expressions when age = 18. 193 Chapter 4 The if-else Statement
  • 214. Program 4.4 #include <iostream> using namespace std; int main() { int age = 18; cout << "The value of the first expression is " << (age + 5) << endl; cout << "The value of the second expression is " << (age = 30) << endl; cout << "The value of the third expression is " << (age == 40) << endl; return 0; } The display Program 4.4 produces is as follows: The value of the first expression is 23 The value of the second expression is 30 The value of the third expression is 0 As the output of Program 4.4 shows, each expression has a value associated with it. The value of the first expression is the sum of the variable age plus 5, which is 23. The value of the second expression is 30, which is also assigned to the variable age. The value of the third expression is 0 because age is not equal to 40, and a false condition is represented in C++ with a value of 0. If the value in age had been 40, the relational expression a == 40 would be true and have a value of 1. Now assume that the relational expression age == 40 was intended to be used in this if statement, if (age == 40) cout << "Happy Birthday!"; but was mistyped as age = 40, resulting in the following: if (age = 40) cout << "Happy Birthday!"; Because the mistake results in a valid C++ expression, and any C++ expression can be tested by an if statement, the resulting if statement is valid and causes the message Happy Birthday! to be displayed regardless of what value was previously assigned to age. Can you see why? The condition tested by the if statement doesn’t compare the value in age to the number 40. It assigns the number 40 to age. That is, the expression age = 40 is not a relational expression at all; it’s an assignment expression. At the completion of the assign- ment, the expression itself has a value of 40. Because C++ treats any non-zero value as true, 194 Selection Structures
  • 215. Point of Information The Boolean Data Type Before the current ANSI/ISO C++ standard, C++ didn’t have a built-in Boolean data type with its two Boolean values, true and false. Because this data type wasn’t originally part of the language, a tested expression could not evaluate to a Boolean value. Therefore, the syntax if(Boolean expression is true) execute this statement; also wasn’t built into C or C++. Instead, both C and C++ use the more encompassing syntax, if(expression) execute this statement; where expression is any expression that evaluates to a numeric value. If the value of the tested expression is a non-zero value, it’s considered true, and only a zero value is considered false. As the ANSI/ISO C++ standard specifies, C++ has a built-in Boolean data type con- taining the values true and false. As you learned in Chapter 2, Boolean variables are declared with the bool keyword. As currently implemented, the actual values that the Boolean values true and false represent are the integer values 1 and 0, respectively. For example, examine the following program, which declares two Boolean variables: #include <iostream> using namespace std; int main() { bool t1, t2; t1 = true; t2 = false; cout <<"The value of t1 is " << t1 << "nand the value of t2 is " << t2 << endl; return 0; } This program produces the following output: The value of t1 is 1 and the value of t2 is 0 continued... 195 Chapter 4 The if-else Statement
  • 216. the cout statement is executed. Another way of looking at it is to realize that the if statement is equivalent to the following two statements: age = 40; // assign 40 to age if (age) // test the value of age cout << "Happy Birthday!"; Because a C++ compiler has no means of knowing that the expression being tested isn’t the one you want, you must be especially careful when writing conditions. EXERCISES 4.2 1. (Practice) Write appropriate if statements for the following conditions: a. If an angle is equal to 90 degrees, print the message “The angle is a right angle”; else, print the message “The angle is not a right angle.” b. If the temperature is above 100 degrees, display the message “above the boiling point of water”; else, display the message “below the boiling point of water.” c. If the number is positive, add the number to the variable positivesum; else, add the number to the variable negativesum. d. If the slope is less than 0.5, set the variable flag to zero; else, set flag to one. Point of Information The Boolean Data Type (continued) As shown by this output, the Boolean values true and false are represented by the integer values 1 and 0 and have the following relationships: !true= is false !false= is true Additionally, applying a postfix or prefix ++ operator to a variable of type bool sets the Boolean value to true. The postfix and prefix -- operators can’t be applied to Boolean variables. Boolean values can also be compared, as shown in the following code: if (t1 == t2) cout << "The values are equal" << endl; else cout << "The values are not equal" << endl; Last, assigning any non-zero value to a Boolean variable results in the variable being set to true (a value of 1), and assigning a zero value to a Boolean results in the vari- able being set to false (a value of 0). 196 Selection Structures
  • 217. e. If the difference between volts1 and volts2 is less than 0.001, set the variable approx to zero; else, calculate approx as the quantity (volts1 - volts2) / 2.0. f. If the frequency is above 60, display the message “The frequency is too high.” g. If the difference between temp1 and temp2 exceeds 2.3, calculate the variable error as (temp1 - temp2) * factor. h. If x is greater than y and z is less than 20, request that the user input a value for the variable p. i. If distance is greater than 20 and less than 35, request that the user input a value for the variable time. 2. (Practice) Write if statements corresponding to the conditions illustrated in the follow- ing flowcharts: a. sum= sum +a count= count+1 ace<25 false true b. volts=5 pwr=10 volts=16 pwr=25 c==15 false true c. factor=.7 id>22 false true d. average =sum/count count==10 false true display average 197 Chapter 4 The if-else Statement
  • 218. 3. (Practice) Write a C++ program that asks the user to input two numbers. If the first number entered is greater than the second number, the program should print the message “The first number is greater”; else, it should print the message “The first number is smaller.” Test your program by entering the numbers 5 and 8 and then using the num- bers 11 and 2. What do you think your program will display if the two numbers entered are equal? Test this case. 4. (Practice) a. A certain waveform is 0 volts for time less than 2 seconds and 3 volts for time equal to or greater than 2 seconds. (These waveforms are referred to as step functions.) Write a C++ program that accepts time in the variable named time and dis- plays the appropriate voltage, depending on the input value. b. How many runs should you make for the program written in Exercise 4a to verify that it’s operating correctly? What data should you input in each program run? 5. (Practice) An insulation test for a wire requires that the insulation withstand at least 600 volts. Write a C++ program that accepts a test voltage and displays the message “PASSED VOLTAGE TEST” or the message “FAILED VOLTAGE TEST,” as appropriate. 6. (Practice) a. Write a C++ program to compute the value of pressure in pounds per square inch (psi) of a waveform described as follows: For time, t, equal to or less than 35 seconds, the pressure is 0.46t psi, and for time greater than 35 seconds, the pressure is 0.19t + 9.45 psi. The program should request the time as input and display the pressure as output. b. How many runs should you make for the program written in Exercise 6a to verify that it’s operating correctly? What data should you input in each program run? 7. (Practice) a. Write a C++ program to display the message “PROCEED WITH TAKEOFF” or “ABORT TAKEOFF,” depending on the input. If the character g is entered in the vari- able code, the first message should be displayed; otherwise, the second message should be displayed. b. How many runs should you make for the program written in Exercise 7a to verify that it’s operating correctly? What data should you input in each program run? 8. (Fluid Mechanics) A fluid particle flowing through a pipe can flow in a smooth, constant manner, called laminar flow; in a chaotic manner, called turbulent flow; or in an interme- diate transitional stage between smooth and turbulent flow. As a practical design param- eter, the Reynolds number can be used to determine the type of flow. For a Reynolds number below 2000, the flow is laminar, and for a Reynolds number above 3000, the flow is turbulent. For a Reynolds number between 2000 and 3000, the flow is in transition from laminar to turbulent. Using this information, write and execute a C++ program that accepts a Reynolds number as user input; determines whether the flow is laminar, turbu- lent, or in transition; and displays a message indicating the type of flow based on the input Reynolds number. 9. (Electrical Eng.) A small factory generates its own power with a 20-kilowatt generator and a 50-kilowatt generator. The plant manager indicates which generator is required by typing a character code. Write a C++ program that accepts this code as input. If code s is typed, a message directing the plant foreman to use the smaller generator should be displayed; other- wise, a message directing the use of the larger generator should be displayed. 198 Selection Structures
  • 219. 4.3 Nested if Statements As you have seen, an if-else statement can contain any valid C++ simple or compound statements, including another if-else statement. Therefore, one or more if-else statements can be included in either part of an if-else statement. Including one or more if statements inside an existing if statement is called a nested if statement. For example, substituting the one-way if statement if (distance > 500) cout << "snap"; for statement1 in the following if statement if (hours < 9) statement1; else cout << "pop"; results in this nested if statement: if (hours < 9) { if (distance > 500) cout << "snap"; } else cout << "pop"; The braces around the inner one-way if statement are essential because in their absence, C++ associates an else with the closest unpaired if. Therefore, without the braces, the preceding statement is equivalent to the following: if (hours < 9) if (distance > 500) cout << "snap"; else cout << "pop"; In this example, the else is paired with the inner if, which destroys the meaning of the original if-else statement. Notice also that the indentation is irrelevant, as far as the compiler is concerned. Whether the indentation exists or not, the statement is compiled by associating the last else with the closest unpaired if, unless braces are used to alter the default pairing. The process of nesting if statements can be extended indefinitely, so the cout << "snap"; statement could be replaced by a complete if-else statement or another one-way if statement. 199 Chapter 4 Nested if Statements
  • 220. Figures 4.4a and 4.4b illustrate the general form of a nested if-else statement when a second if-else statement is nested within a) the if part of an if-else statement and b) the else part of an if-else statement. statement 1 no (else part) yes is expression-1 true? yes no (else part) is expression-2 true? statement 2 statement 3 Figure 4.4a Nested within the if part 200 Selection Structures
  • 221. The if-else Chain In general, the nesting shown in Figure 4.4a tends to be confusing and is best avoided in practice. However, a useful construction for the nesting in Figure 4.4b has this form: if (expression_1) statement1; else if (expression_2) statement2; else statement3; As with all C++ programs, because white space is ignored, this indentation isn’t required. Typically, the preceding construction is written in the following arrangement: if (expression_1) statement1; else if (expression_2) statement2; else statement3; statement 2 yes is expression-1 true? yes no (else part) no (else part) statement 3 statement 1 is expression-2 true? Figure 4.4b Nested within the else part 201 Chapter 4 Nested if Statements
  • 222. This useful form of a nested if statement is called an if-else chain. Each condition is evaluated in order, and if any condition is true, the corresponding statement is executed and the remainder of the chain is terminated. The statement associated with the final else is executed only if no previous condition is satisfied. This final else serves as a default or catch-all case that’s useful for detecting an error condition or processing a condition that’s not handled specifically by the previous conditions. The chain can be continued indefinitely by repeatedly making the last statement another if-else statement. Therefore, the general form of an if-else chain is as follows: if (expression_1) statement1; else if (expression_2) statement2; else if (expression_3) statement3; . . . else if (expression_n) statement_n; else last_statement; Each condition is evaluated in the order it appears in the statement. For the first condition that’s true, the corresponding statement is executed, and the remainder of the statements in the chain aren’t executed. Therefore, if expression_1 is true, only statement1 is executed; otherwise, expression_2 is tested. If expression_2 is true, only statement2 is executed; otherwise, expression_3 is tested, and so on. The final else and its associated statement(s) in the chain are optional, and last_statement is executed only if no previous expressions are true. To illustrate using an if-else chain, Program 4.5 displays an item’s specification status corresponding to a letter input. The following input codes are used: Specification Status Input Code Space exploration S Military grade M Commercial grade C Toy grade T 202 Selection Structures
  • 223. Program 4.5 #include <iostream> using namespace std; int main() { char code; cout << "Enter a specification code: "; cin >> code; if (code == 'S') cout << "The item is space exploration grade."; else if (code == 'M') cout << "The item is military grade."; else if (code == 'C') cout << "The item is commercial grade."; else if (code == 'T') cout << "The item is toy grade."; else cout << "An invalid code was entered."; cout << endl; return 0; } As another example of an if-else chain, take a look at determining the output of a digital converter unit by using the following input/output relationship: Input Weight Output Reading Greater than or equal to 90 lbs 1111 Less than 90 lbs but greater than or equal to 80 lbs 1110 Less than 80 lbs but greater than or equal to 70 lbs 1101 Less than 70 lbs but greater than or equal to 60 lbs 1100 Less than 60 lbs 1011 The following statements can be used to determine the correct output corresponding to the value input for the variable inlbs: if (inlbs >= 90) digout = 1111; else if (inlbs >= 80) 203 Chapter 4 Nested if Statements
  • 224. digout = 1110; else if (inlbs >= 70) digout = 1101; else if (inlbs >= 60) digout = 1100; else digout = 1011; Notice that this example makes use of the chain stopping after a true condition is found by checking for the highest input weight first. If the input value is less than 90, the if-else chain continues checking for the next highest weight, and so on, until the correct weight category is obtained. Program 4.6 uses an if-else chain to calculate and display the correct output corresponding to the weight input in the cin statement. Program 4.6 #include <iostream> using namespace std; int main() { int digout; double inlbs; cout << "Enter the input weight: "; cin >> inlbs; if (inlbs >= 90) digout = 1111; else if (inlbs >= 80) digout = 1110; else if (inlbs >= 70) digout = 1101; else if (inlbs >= 60) digout = 1100; else digout = 1011; cout << "The digital output is " << digout << endl; return 0; } 204 Selection Structures
  • 225. The following is a sample run of Program 4.6: Enter the input weight: 72.5 The digital output is 1101 As with all C++ statements, each statement in an if-else chain can be replaced by a compound statement bounded by braces. EXERCISES 4.3 1. (Practice) Modify Program 4.5 to accept both lower and uppercase letters as codes. For example, if a user enters an m or an M, the program should display the message “The item is military grade.” 2. (Practice) Write nested if statements corresponding to the conditions illustrated in the following flowcharts: a. t=s+a bin=1 is weight >35 no yes is grade=='A' yes no b. sum=0 no yes is count <5 is grade <50 fail= fail+1 yes no 205 Chapter 4 Nested if Statements
  • 226. 3. (Practice) An acute angle is less than 90 degrees, an obtuse angle is greater than 90 degrees, and a right angle is equal to 90 degrees. Using this information, write a C++ pro- gram that accepts an angle, in degrees, and displays the type of angle corresponding to the degrees entered. 4. (Data Processing) The grade level of undergraduate college students is typically deter- mined according to the following schedule: Number of Credits Completed Grade Level Less than 32 Freshman 32 to 63 Sophomore 64 to 95 Junior 96 or more Senior Using this information, write a C++ program that accepts the number of credits a student has completed, determines the student’s grade level, and displays the grade level. 5. (Data Processing) A student’s letter grade is calculated according to the following schedule: Numerical Grade Letter Grade Greater than or equal to 90 A Less than 90 but greater than or equal to 80 B Less than 80 but greater than or equal to 70 C Less than 70 but greater than or equal to 60 D Less than 60 F Using this information, write a C++ program that accepts a student’s numerical grade, converts the numerical grade to an equivalent letter grade, and displays the letter grade. 6. (Measurement) The tolerance of critical components in a system is determined accord- ing to the following schedule: Specification Status Tolerance Space exploration Less than 0.1% Military grade Greater than or equal to 0.1% and less than 1% Commercial grade Greater than or equal to 1% and less than 10% Toy grade Greater than or equal to 10% Using this information, write a C++ program that accepts a component’s tolerance reading and determines the specification that should be assigned to it. 7. (General Math) Write a C++ program that accepts a number followed by one space and then a letter. If the letter following the number is f, the program is to treat the number entered as a temperature in degrees Fahrenheit, convert the number to the equivalent degrees Celsius, and display a suitable message. If the letter following the number is c, the 206 Selection Structures
  • 227. program is to treat the number entered as a temperature in degrees Celsius, convert the number to the equivalent degrees Fahrenheit, and display a suitable message. If the letter is neither f nor c, the program is to display a message that the data entered is incorrect and terminate. Use an if-else chain in your program and make use of these conversion formulas: Celsius = (5.0 / 9.0) × (Fahrenheit - 32.0) Fahrenheit = (9.0 / 5.0) × Celsius + 32.0 8. (Debugging) Using the relationships in Program 4.6, the following program calculates the digital output: int main() { int digout; double inlbs; cout << "Enter the input weight: "; cin >> inlbs; if (inlbs >= 90) digout = 1111; if (inlbs >= 80) && (inlbs <= 90) digout = 1110; if (inlbs >= 70) && (inlbs <= 80) digout = 1101; if (inlbs >= 60) && (inlbs <= 70) digout = 1100; if (inlbs < 1000) digout = 1011; cout << "The digital output is " << digout << endl; return 0; } a. Will this program produce the same output as Program 4.6? b. Which program is better and why? 9. (Debugging) The following program was written to produce the same result as Program 4.6: int main() { int digout; double inlbs; cout << "Enter the input weight: "; cin >> inlbs; if (inlbs < 60) digout = 1011; else if (inlbs >= 60) digout = 1100; else if (inlbs >= 70) digout = 1101; else if (inlbs >= 80) digout = 1110; else if (inlbs >= 90) digout = 1111; 207 Chapter 4 Nested if Statements
  • 228. cout << "The digital output is " << digout << endl; return 0; } a. Will this program run? b. What does this program do? c. For what values of input pounds does this program calculate the correct digital output? 4.4 The switch Statement An if-else chain is used in programming applications when one set of instructions must be selected from many possible alternatives. A switch statement is an alternative to the if-else chain for situations when the condition involves comparing an integer expression with a specific value. It has this general form: switch (expression) { // start of compound statement case value_1: // terminated with a colon statement1; statement2; . . break; case value_2: // terminated with a colon statementm; statementn; . . break; . . case value_n: // terminated with a colon statementw; statementx; . . break; default: // terminated with a colon statementaa; statementbb; . . } // end of switch and compound statement The switch statement uses four new keywords: switch, case, break, and default. The following discussion explains what each of these keywords does. The switch keyword identifies the start of the switch statement. The expression in parentheses after switch is then evaluated, and this expression must evaluate to an integer result, or a compilation error results. 208 Selection Structures
  • 229. In the switch statement, the case keyword identifies values that are compared with the switch expression’s value. The case values are compared in the order in which they’re listed until a match is found, and then execution begins with the statement following the match. As illustrated in Figure 4.5, the switch expression’s value determines where execution actually begins. A switch statement can contain any number of case labels in any order. If the value of the expression doesn’t match any of the case values, however, no statement is executed unless the default keyword is encountered. (The default keyword is optional and operates the same as the last else in an if-else chain.) If the value of the expression doesn’t match any case value, program execution begins with the statement following the default keyword. After the switch statement has located an entry point, all further case value evaluations are ignored. Execution continues through the end of the compound statement unless the break keyword is encountered, which identifies the end of a case and causes an immediate exit from the switch statement. Just as the case keyword identifies possible entry points in the compound statement, the break keyword determines terminating points. Start here if expression equals value_1 Start here if expression equals value_2 Start here if expression equals value_3 Start here if expression equals value_n Start here if no previous match switch (expression) // evaluate expression { case value_1: break; case value_2: break; case value_3: break; case value_n: break; default: } // end of switch statement Figure 4.5 The expression determines an entry point for execution 209 Chapter 4 The switch Statement
  • 230. If break statements are omitted, all cases following the matching case value, including the default case, are executed. When writing a switch statement, you can use multiple case values to refer to the same set of statements; the default keyword is optional. For example, take a look at the following: switch (number) { case 1: cout << "Have a Good Morningn"; break; case 2: cout << "Have a Happy Dayn"; break; case 3: case 4: case 5: cout << "Have a Nice Eveningn"; } If the value stored in the variable number is 1, the message Have a Good Morning is displayed. Similarly, if the value of number is 2, the second message is displayed. Finally, if the value of number is 3, 4, or 5, the last message is displayed. Because the statement to be executed for the last three cases is the same, the case statements for these values can be “stacked together,” as shown in the example. Also, because there’s no default keyword, no message is printed if the value of number isn’t one of the listed case values. Although listing case values in increasing order is a good programming practice, it’s not required by the switch statement. A switch statement can have any number of case values, in any order; only the values you’re testing for must be listed. Program 4.7 uses a switch statement to select the arithmetic operation (addition, multiplication, or division) to perform on two numbers, depending on the value of the opselect variable. In the following two sample runs, the resulting display clearly identifies the case that was selected: Please type in two numbers: 12 3 Enter a select code: 1 for addition 2 for multiplication 3 for division : 2 The product of the numbers entered is 36 and Please type in two numbers: 12 3 Enter a select code: 1 for addition 2 for multiplication 3 for division : 3 The first number divided by the second is 4 210 Selection Structures
  • 231. Program 4.7 #include <iostream> using namespace std; int main() { int opselect; double fnum, snum; cout << "Please type in two numbers: "; cin >> fnum >> snum; cout << "Enter a select code: "; cout << "n 1 for addition"; cout << "n 2 for multiplication"; cout << "n 3 for division : "; cin >> opselect; switch (opselect) { case 1: cout << "The sum of the numbers entered is " << fnum+snum; break; case 2: cout << "The product of the numbers entered is " << fnum*snum; break; case 3: cout << "The first number divided by the second is " << fnum/snum; break; } // end of switch cout << endl; return 0; } In reviewing Program 4.7, notice the break statement in the last case. Although it’s not necessary, terminating the last case in a switch statement with a break is a good programming practice. It prevents a possible program error later if another case is added to the switch statement. With the addition of a new case, the break keyword between cases ensures that you won’t forget to include the break at the time of the addition. 211 Chapter 4 The switch Statement
  • 232. Because character data types are always converted to integers in an expression, a switch statement can also be used to “switch” based on the value of a character expression. For example, assuming choice is a character variable, the following switch statement is valid: switch(choice) { case 'a': case 'e': case 'i': case 'o': case 'u': cout << "The character in choice is a voweln"; break; default: cout << "The character in choice is not a voweln"; break; // this break is optional } // end of switch statement EXERCISES 4.4 1. (Practice) Rewrite the following if-else chain by using a switch statement: if (letterGrade == 'A') cout << "The numerical grade is between 90 and 100n"; else if (letterGrade == 'B') cout << "The numerical grade is between 80 and 89.9n"; else if (letterGrade == 'C') cout << "The numerical grade is between 70 and 79.9n"; else if (letterGrade == 'D') cout << "How are you going to explain this one?n"; else { cout << "Of course I had nothing to do with my grade.n"; cout << "It must have been the professor's fault.n"; } 2. (Practice) Rewrite the following if-else chain by using a switch statement: if (factor == 1) pressure = 25.0; else if (factor == 2) pressure = 36.0; else if (factor == 3) pressure = 45.0; else if (factor == 4) || (factor == 5) || (factor == 6) pressure = 49.0; 212 Selection Structures
  • 233. 3. (Data Processing) Each disk drive in a shipment is stamped with a code from 1 through 4 to indicate the manufacturer, as follows: Code Disk Drive Manufacturer 1 3M Corporation 2 Maxell Corporation 3 Sony Corporation 4 Verbatim Corporation Write a C++ program that accepts the code number as input and, based on the value entered, displays the correct disk drive manufacturer. 4. (Practice) Rewrite Program 4.5 by using a switch statement. 5. (Debugging) Explain why the if-else chain in Program 4.6 can’t be replaced with a switch statement. 6. (Debugging) Rewrite Program 4.7 by using a character variable for the select code. 4.5 A Case Study: Solving Quadratic Equations An important use of C++’s if statements is to validate data by checking for clearly invalid cases. For example, a date such as 5/33/06 contains an obviously invalid day. Similarly, the division of any number by zero in a program, such as 14/0, shouldn’t be allowed. Both examples illustrate the need for a technique called defensive programming, in which the program includes code to check for improper data before an attempt is made to process it further. The defensive programming technique of checking user input data for erroneous or unreasonable data is referred to as input data validation. A second major use of selection statements is to determine the type of calculation to be made based on the data. Both uses are shown in this case study, which illustrates a C++ program that determines the roots of a quadratic equation. A quadratic equation has the form ax2 + bx + c = 0 or can be algebraically manipulated into this form. In this equation, x is the unknown variable, and a, b, and c are known constants. Although the constants b and c can be any numbers, including 0, the value of the constant a can’t be 0. (If a is 0, the equation would become a linear equation in x.) Here are examples of quadratic equations: 5x2 + 6x + 2 = 0 x2 - 7x + 20 = 0 34x2 + 16 = 0 In the first equation, a = 5, b = 6, and c = 2; in the second equation, a = 1, b = -7, and c = 20; and in the third equation, a = 34, b = 0, and c = 16. 213 Chapter 4 A Case Study: Solving Quadratic Equations
  • 234. The real roots of a quadratic equation can be calculated by using these quadratic formulas: x b b ac a = + - - 2 4 2 and x b b ac a = - - - 2 4 2 Using these formulas, you’ll write a C++ program, following the software development procedure, to solve for the roots of a quadratic equation. Step 1 Analyze the Problem The problem requires accepting three inputs—the coefficients a, b, and c of a quadratic equation. The outputs are the roots of the equation, found by using the given formulas. Step 2 Develop a Solution A first attempt at a solution is using the user-entered values of a, b, and c to calculate a value for each root, as described by the following pseudocode: Display a program purpose message Accept user-input values for a, b, and c Calculate the two roots Display the values of the calculated roots However, this solution must be refined to account for possible input conditions. For example, if a user enters a value of 0 for both a and b, the equation is neither quadratic nor linear and has no solution (referred to as a “degenerate case”). Another possibility is that the user enters a zero for a and a non-zero value for b. In this case, the equation becomes linear with a single solution of -c/b. A third possibility is that the value of the term b2 - 4ac, which is called the discriminant, is negative. Because the square root of a negative number can’t be taken, the equation has no real roots (referred to as the “imaginary roots case”). Finally, when the discriminant is 0, both roots are the same (referred to as the “repeated roots case”). 214 Selection Structures
  • 235. Taking into account all four limiting cases, the following pseudocode shows a refined solution for determining the roots of a quadratic equation correctly: Display a program purpose message Accept user-input values for a, b, and c If a = 0 and b = 0 then display a message saying that the equation has no solution Else if a = zero then calculate the single root equal to -c/b display the single root Else { calculate the discriminant If the discriminant > 0 then solve for both roots using the given formulas display the two roots Else if the discriminant < 0 then display a message that there are no real roots Else calculate the repeated root equal to -b/(2a) display the repeated root Endif } Endif Notice that nested if-else statements are used. The outer if-else statement validates the entered coefficients and determines whether you have a valid quadratic equation. The inner if-else statement then determines whether the equation has two real roots (discriminant > 0), two imaginary roots (discriminant < 0), or repeated roots (discriminant = 0). Step 3 Code the Solution Program 4.8 lists the equivalent C++ code for the pseudocode solution. 215 Chapter 4 A Case Study: Solving Quadratic Equations
  • 236. Program 4.8 #include <iostream> #include <cmath> using namespace std; // this program solves for the roots of a quadratic equation int main() { double a, b, c, disc, root1, root2; cout << "This program calculates the roots of an"; cout << " quadratic equation of the formn"; cout << " 2n"; cout << " ax + bx + c = 0nn"; cout << "Please enter values for a, b, and c: "; cin >> a >> b >> c; if ( a == 0.0 && b == 0.0) cout << "The equation is degenerate and has no roots.n"; else if (a == 0.0) cout << "The equation has the single root x = " << -c/b << endl; else { //Start of compound statement for the outer else disc = pow(b,2.0) - 4 * a * c; // calculate discriminant if (disc > 0.0) { disc = sqrt(disc); root1 = (-b + disc) / (2 * a); root2 = (-b - disc) / (2 * a); cout << "The two real roots are " << root1 << " and " << root2 << endl; } else if (disc < 0.0) cout << "Both roots are imaginary.n"; else cout << "Both roots are equal to " << -b / (2 * a) << endl; } //end of compound statement for the outer else return 0; } 216 Selection Structures
  • 237. Step 4 Test and Correct the Program Test values should include values for a, b, and c that result in two real roots, plus limiting values for a and b that result in a linear equation (a = 0, b ⫽ 0), a degenerate equation (a = 0, b = 0), and a negative and a zero discriminant. Two test runs of Program 4.8 follow: This program calculates the roots of a quadratic equation of the form 2 ax + bx + c = 0 Please enter values for a, b, and c: 1 2 -35 The two real roots are 5 and -7 and This program calculates the roots of a quadratic equation of the form 2u ax + bx + c = 0 Please enter values for a, b, and c: 0 0 16 The equation is degenerate and has no roots. The first run solves the quadratic equation x2 + 2x - 35 = 0, which has the real roots x = 5 and x = -7. The input data for the second run results in the equation 0x2 + 0x + 16 = 0. Because it degenerates into the mathematical impossibility of 16 = 0, the program identifies it correctly as a degenerate equation. As an exercise, you could create test data for the other limiting cases the program checks for. EXERCISES 4.5 1. (Data Processing) Write, compile, and execute a C++ program that accepts a user- entered number and calculates the values of the following: user-entered number and 1 user-entered number Before calculating the square root, validate that the number is not negative, and before calculating the reciprocal, check that the number is not zero. If either condition occurs, display a message stating that the operation can’t be calculated. 2. (Data Processing) a. Write a program that accepts two real numbers and a select code from a user. If the entered select code is 1, have the program add the two previously entered num- bers and display the result; if the select code is 2, the numbers should be multiplied, and if the select code is 3, the first number should be divided by the second number. b. Determine what the program written in Exercise 2a does when the entered numbers are 3 and 0 and the select code is 3. 217 Chapter 4 A Case Study: Solving Quadratic Equations
  • 238. c. Modify the program written in Exercise 2a so that division by 0 is not allowed, and a message is displayed when this division is attempted. 3. (Data Processing) a. Write a program to display the following two prompts: Enter a month (use a 1 for Jan, etc.): Enter a day of the month: Have your program accept and store a number in the variable month in response to the first prompt and accept and store a number in the variable day in response to the second prompt. If the month entered is not between 1 and 12, print a message informing the user that an invalid month has been entered. If the day entered is not between 1 and 31, print a message informing the user that an invalid day has been entered. b. What will your program do if the user enters a number with a decimal point for the month? How can you make sure your if statements check for an integer number? c. In a non-leap year, February has 28 days; the months January, March, May, July, August, October, and December have 31 days; and all other months have 30 days. Using this information, modify the program written in Exercise 3a to display a message when an invalid day is entered for a user-entered month. For this program, ignore leap years. 4. (General Math) The quadrant in which a line drawn from the origin resides is deter- mined by the angle the line makes with the positive x-axis, as follows: Angle from the Positive X-Axis Quadrant Between 0 and 90 degrees I Between 90 and 180 degrees II Between 180 and 270 degrees III Between 270 and 360 degrees IV a. Using this information, write a C++ program that accepts the angle of the line as user input and determines and displays the correct quadrant for the input data. (Note: If the angle is exactly 0, 90, 180, or 270 degrees, the corresponding line doesn’t reside in any quadrant but lies on an axis.) b. Modify the program written for Exercise 4a to display a message that identifies an angle of 0 degrees as the positive x-axis, an angle of 90 degrees as the positive y-axis, an angle of 180 degrees as the negative x-axis, and an angle of 270 degrees as the negative y-axis. 5. (Data Processing) Years that are evenly divisible by 400 or are evenly divisible by 4 but not by 100 are leap years. For example, because 1600 is evenly divisible by 400, 1600 was a leap year. Similarly, because 1988 is evenly divisible by 4 but not by 100, it was also a leap year. Using this information, write a C++ program that accepts the year as user input, determines whether the year is a leap year, and displays a message telling the user whether the entered year is or is not a leap year. 218 Selection Structures
  • 239. 6. (Data Processing) Based on an automobile’s model year and weight, the state of New Jersey determines the weight class and registration fee by using the following schedule: Model Year Weight Weight Class Registration Fee 1970 or earlier Less than 2700 lbs 1 $16.50 2700 to 3800 lbs 2 25.50 More than 3800 lbs 3 46.50 1971 to 1979 Less than 2700 lbs 4 27.00 2700 to 3800 lbs 5 30.50 More than 3800 lbs 6 52.50 1980 or later Less than 3500 lbs 7 19.50 3500 or more lbs 8 52.50 Using this information, write a C++ program that accepts an automobile’s year and weight and determines and displays its weight class and registration fee. 7. (Data Processing) Modify Program 4.8 so that the imaginary roots are calculated and displayed when the discriminant is negative. For this case, the two roots of the equation are the following: x b b ac a i 1 2 4 2 = + - - - ( ) and x b b ac a i 2 2 4 2 = - - - - ( ) where i is the imaginary number symbol for the square root of -1. (Hint: Calculate the real and imaginary parts of each root separately.) 8. (Heat Transfer) The transfer of heat by the movement (currents) of a gas or liquid is referred to as heat convection. The heat transferred per unit area of a substance is given by this formula: q = hA(Ts - Ta) q is the heat transfer rate (Watts or Joules/sec). h is the convective heat transfer coefficient (BTU/hrft°F or Watts/m2 °C). A is the surface area (ft2 or m2 ). Ts is the surface temperature (°F or °C). Ta is the ambient (surrounding) temperature (°F or °C). 219 Chapter 4 A Case Study: Solving Quadratic Equations
  • 240. a. Write, compile, and execute a C++ program that accepts a substance’s surface area, a substance’s surface temperature, and the ambient air temperature as inputs and dis- plays the heat transfer rate through air. Users should have three choices for entering the surface area: 1. A rectangular area 2. An elliptical area 3. Other If the user selects 1, the program should ask the user to enter the surface’s length and width, and the program calculates surface area as length times width. If the user selects 2, the program should ask the user to enter the surface’s major and minor axii, and the pro- gram calculates the surface area as ␲(major axis)(minor axis). If the user selects 3 (Other), the program should ask the user to enter the surface area. The heat transfer rate should then be calculated and displayed, using the convective heat transfer coefficient of 8.7 Watts/m2 °C, which should be defined as the symbolic constant AIRCONV. b. After verifying that your program is working correctly, determine the heat transfer rate away from a chip in a computer’s console. The chip has a surface temperature of 44°C, and the ambient temperature maintained by the console’s fan is 40°C. The rect- angular chip has a length of 2 cm and a width of 2 cm. 4.6 A Closer Look: Program Testing3 In theory, a comprehensive set of test runs would reveal all possible program errors and ensure that a program works correctly for any combination of input and computed data. In practice, this level of testing requires checking all possible combinations of statement execution. Because of the time and effort required, this goal is usually impossible except for extremely simple programs. To see why this is so, take a look at Program 4.9. 3 This topic can be omitted on first reading without loss of subject continuity. 220 Selection Structures
  • 241. Program 4.9 #include <iostream> using namespace std; int main() { int num; cout << "Enter a number: "; cin >> num; if (num == 5) cout << "Bingo!n"; else cout << "Bongo!n"; return 0; } Program 4.9 has two paths that can be traversed as the program progresses from its opening brace to its closing brace. The first path, which is executed when the input number is 5, is in this sequence: cout << "Enter a number"; cin >> num; cout << "Bingo!n"; The second path, which is executed when any number except 5 is input, includes this sequence of instructions: cout << "Enter a number"; cin >> num; cout << "Bongo!n"; Testing each possible path through Program 4.9 requires two runs with a judicious selection of test input data to make sure both paths of the if statement are exercised. Adding one more if statement in the program increases the number of possible execution paths by a factor of two and requires four (that is, 22 ) runs for complete testing. Similarly, two additional if statements increase the number of paths by a factor of four and require eight (that is, 23 ) runs for complete testing, and three additional if statements produce a program that requires 16 (that is, 24 ) test runs. Now consider an application program consisting of only 10 modules, with each module containing five if statements. Assuming the modules are always called in the same sequence, there are 32 possible paths through each module (25 ) and more than 1,000,000,000,000,000 (250 , representing the number of modules multiplied by the number of if statements per module) possible paths through the complete program (all modules executed in sequence). The time needed to create test data to exercise each path and the 221 Chapter 4 A Closer Look: Program Testing
  • 242. actual computer runtime required to check each path make complete testing of this program impossible. The inability to test all combinations of statement execution sequences fully has led to the programming proverb “There is no error-free program.” Any testing should be well thought out to maximize the possibility of locating errors. At a minimum, test data should include appropriate input values, illegal input values the program should reject, and limiting values checked by selection statements in the program. 4.7 Common Programming Errors Four programming errors are common with C++’s selection statements: 1. Using the assignment operator, =, in place of the relational operator ==. This error can cause frustration because any expression can be tested by an if-else statement, so it is not immediately obvious that an error is being made. For example, the statement if (opselect = 2) cout << "Happy Birthday"; else cout << "Good Day"; always results in the message Happy Birthday being displayed, regardless of the initial value in the opselect variable. The reason is that the assignment expres- sion opselect = 2 has a value of 2, which is considered a true value in C++. The correct expression to determine the value in opselect is opselect == 2. 2. Placing a semicolon immediately after the condition, as in this example: if (condition); statement; The semicolon after (condition) is an error. It creates a null statement, which causes the statement following the semicolon to be a stand-alone statement that’s no longer part of the if statement. This stand-alone statement is always executed, regardless of the condition tested by the if statement. 3. Letting the if-else statement appear to select an incorrect choice. In this typical debugging problem, the programmer mistakenly concentrates on the tested condi- tion as the source of the problem. For example, assume the following if-else statement is part of your program: if (key == 'F') { contemp = (5.0/9.0) * (intemp - 32.0); cout << "Conversion to Celsius was done"; } else { 222 Selection Structures
  • 243. contemp = (9.0/5.0) * intemp + 32.0; cout << "Conversion to Fahrenheit was done"; } This statement always displays Conversion to Celsius was done when the vari- able key contains an F. Therefore, if this message is displayed when you believe key doesn’t contain F, you should investigate key’s value. As a general rule, whenever a selection statement doesn’t act as you think it should, test your assumptions about the values assigned to the tested variables by displaying their values. If an unantici- pated value is displayed, you have at least isolated the source of the problem to the variables rather than the structure of the if-else statement. From there, you have to determine where and how the incorrect value was produced. 4. Using nested if statements without including braces to indicate the structure. Without braces, the compiler defaults to pairing elses with the closest unpaired ifs, which sometimes destroys the selection statement’s original intent. To avoid this problem and create code that’s adaptable to change, writing all if-else statements as compound statements in this form is useful: if (expression) { // one or more statements in here } else { // one or more statements in here } No matter how many statements are added later, this form maintains the if state- ment’s original intent. 4.8 Chapter Summary 1. Relational expressions, also called conditions, are used to compare operands. If a relational expression is true, the value of the expression is the integer 1. If the relational expression is false, it has an integer value of 0. Relational expressions are created by using the following relational operators: Relational Operator Meaning Example < Less than age < 30 > Greater than height > 6.2 <= Less than or equal to taxable <= 20000 >= Greater than or equal to temp >= 98.6 == Equal to grade == 100 != Not equal to number != 250 223 Chapter 4 Chapter Summary
  • 244. 2. More complex conditions can be constructed from relational expressions by using C++’s logical operators, && (AND), || (OR), and ! (NOT). 3. An if-else statement is used to select between two alternative statements based on an expression’s value. Although relational expressions are usually used for the tested expression, any valid expression can be used. In testing an expression, if-else statements interpret a non-zero value as true and a zero value as false. The general form of an if-else statement is as follows: if (expression) statement1; else statement2; This form is a two-way selection statement. If the expression has a non-zero value, it’s considered true and statement1 is executed; otherwise, statement2 is executed. 4. An if-else statement can contain other if-else statements. In the absence of braces, each else is associated with the closest preceding unpaired if. 5. The if-else chain is a multiway selection statement with this general form: if (expression_1) statement_1; else if (expression_2) statement_2; else if (expression_3) statement_3; . . . else if (expression_m) statement_m; else statement_n; Each expression is evaluated in the order in which it appears in the chain. If an expression is true (has a non-zero value), only the statement between this expression and the next else if or else is executed, and no further expressions are tested. The final else is optional, and the statement corresponding to the final else is executed only if no previous expressions are true. 6. A compound statement consists of any number of single statements enclosed by the brace pair { and }. Compound statements are treated as a single unit and can be used anywhere a single statement is used. 7. The switch statement is a multiway selection statement with this general form: switch (expression) { // start of compound statement case value_1: // terminated with a colon statement1; statement2; . . break; case value_2: // terminated with a colon 224 Selection Structures
  • 245. statementm; statementn; . . break; . . case value_n: // terminated with a colon statementw; statementx; . . break; default: // terminated with a colon statementaa; statementbb; . . } // end of switch and compound statement For this statement, the value of an integer expression is compared with integer or character constants or constant expressions. Program execution is transferred to the first matching case and continues through the end of the switch statement, unless an optional break statement is encountered. The case values in a switch statement can appear in any order, and an optional default case can be included. The default case is executed if no other cases are matched. Programming Projects for Chapter 4 1. (Data Processing) Write C++ code sections to make the following decisions: a. Ask for two integer temperatures. If their values are equal, display the temperature; otherwise, do nothing. b. Ask for character values letter1 and letter2, representing uppercase letters of the alphabet, and display them in alphabetical order. c. Ask for three integer values, num1, num2, and num3, and display them in decreasing order. 2. (Data Processing) a. Write a program that displays the message I FEEL GREAT TODAY! or I FEEL DOWN TODAY #$*!, depending on the input. If the character u is entered in the variable code, the first message should be displayed; otherwise, the second message should be displayed. b. How many runs should you make for the program written in Exercise 2a to verify that it’s operating correctly? What data should you input in each program run? 3. (Data Processing) a. A senior engineer is paid $1700 a week, and a junior engineer, $900 a week. Write a C++ program that accepts as input an engineer’s status in the character variable status. If status equals S, the senior engineer’s salary should be displayed; otherwise, the junior engineer’s salary should be displayed. 225 Chapter 4 Programming Projects
  • 246. b. How many runs should you make for the program written in Exercise 3a to verify that it is operating correctly? What data should you input in each program run? 4. (Data Processing) a. Write a C++ program to compute and display a person’s weekly salary as determined by the following conditions: If the hours worked are less than or equal to 40, the person receives $8.00 per hour; otherwise, the person receives $320.00 plus $12.00 for each hour worked over 40 hours. The program should request the hours worked as input and display the salary as output. b. How many runs should you make for the program written in Exercise 4a to verify that it’s operating correctly? What data should you input in each program run? 5. (Structural Eng.) Three of the most commonly used beams in structural engineering are the I-beam, rectangular beam, and cylindrical beam, shown in Figures 4.6 through 4.8. In determining the stress a given weight places on a symmetrical beam, an important design parameter is the beam’s rectangular moment of inertia, I, which is typically given in units of in4 . The computation of I depends on the beam’s geometry, and for the three beam types shown, the values of I are calculated as follows: For an I-beam: I BH bh = 3 3 12 - where all measurements are in inches For a rectangular beam: I bh = 3 12 For a cylindrical beam: I r = π 4 4 Figures 4.6 through 4.8 show the variables b, h, B, H, and r. Using this information, design, write, compile, and execute a C++ program that prompts the user for the type of beam and the necessary data (based on the input), and then computes and displays the beam’s rectangular moment of inertia. H h B b ⁄2 Figure 4.6 An I-beam 226 Selection Structures
  • 247. 6. (Fluid Mechanics) A key parameter used to determine the type of fluid flow through a pipe is the Reynolds number, which is given by this formula: Re = V d v Re is the Reynolds number (a dimensionless value). V is the velocity (m/s or ft/sec). d is the diameter of the pipe (m or ft). ␯ is the kinematic viscosity of the fluid (m/s2 or ft/sec2 ). The viscosity, ␯, is a measure of the fluid’s resistance to flow and stress. Except at extremely high pressures, a liquid fluid’s kinematic viscosity is dependent on tempera- ture and independent of pressure. The following chart provides the viscosity of water at three different temperatures: Temperature (°C) Kinematic Viscosity (m/s2 ) 5 1.49 × 10-6 10 1.31 × 10-6 15 1.15 × 10-6 h b Figure 4.7 A rectangular beam r Figure 4.8 A cylindrical beam 227 Chapter 4 Programming Projects
  • 248. Using this information, write, compile, and execute a program that requests the velocity of water flowing through a pipe, the pipe’s diameter, the water’s temperature, and the water’s kinematic viscosity. Based on the input values, your program should calculate the Reynolds number. When you have verified that your program is working, use it to complete the following chart: Velocity (m/s) Pipe Diameter (mm) Temperature (°C) Reynolds Number .01 10 5 .03 10 5 .04 10 5 .01 20 10 .03 20 10 .04 20 10 .01 30 15 .03 30 15 .04 30 15 7. (Data Processing) Write a C++ program that accepts a character as input data and determines whether the character is an uppercase letter. An uppercase letter is any character that’s greater than or equal to “A” and less than or equal to “Z.” If the entered character is an uppercase letter, display the message The character just entered is an uppercase letter. If the entered letter isn’t uppercase, display the message The character just entered is not an uppercase letter. 8. (Data Processing) Repeat Exercise 7 to determine whether the character entered is a lowercase letter. A lowercase letter is any character greater than or equal to “a” and less than or equal to “z.” 9. (General Math) a. Write, run, and test a C++ program that accepts a user-input integer number and determines whether it’s even or odd. Display the entered number and the message Even or Odd. b. Modify the program written for Exercise 9a to determine whether the entered number is evenly divisible by a user-specified value, with no remainder. That is, is it evenly divisible by 3, 7, 13, or any other user-specified value? 10. (Data Processing) As a part-time student, you took two courses last term. Write, run, and test a C++ program that calculates and displays your grade point average (GPA) for the term. Your program should prompt the user to enter the grade and credit hours for each course. This information should then be displayed with the lowest grade first, and the GPA for the term should be calculated and displayed. A warning message should be printed if the GPA is less than 2.0 and a congratulatory message if the GPA is 3.5 or above. 228 Selection Structures
  • 249. 11. (Debugging) The following program displays the message Hello there! regardless of the letter input. Determine where the error is. #include <iostream.h> using namespace std; int main() { char letter; cout << "Enter a letter: "; cin >> letter; if (letter = 'm') cout << "Hello there!n"; return 0; i} 12. (Data Processing) Write, execute, and verify a C++ program that accepts three numbers as input, and then sorts the three numbers and displays them in ascending order, from lowest to highest. For example, if the input values are 7 5 1, the program should display them in the numerical order 1 5 7. 13. (Heat Transfer) The transfer of heat energy through matter, referred to as heat conduction, is always from a region of higher temperature to one of lower temperature. It occurs by transferring energy from atom to atom within a substance. With uniform temperatures on either side of equal-sized surfaces, the rate of heat flow through a substance is provided by Fourier’s law of heat conduction, which becomes the following formula: Q k T T w = ( ) 2 1 - Q is heat per unit time per unit area (Watts/m2 or BTU/hrft2 ). k is the thermal conductivity, which is a property of a substance that indicates its capability to conduct heat (Watts/m°K or BTU/hrft°F). T2 is the hotter temperature (°F or °K). T1 is the cooler temperature (°F or °K). w is the width of the substance (ft or m). a. Write, compile, and execute a C++ program that calculates and displays the heat transfer through a substance. The inputs should be the substance’s thermal conduc- tivity, its width, and temperatures on either side of it. Your program should determine which unit system is used, item by item, and then convert units as necessary so that a consistent unit system (SI or English Engineering) is used in the final determination of Q. The output should display the value of Q in both unit systems. b. Verify that your program is working by hand-calculating the heat transfer through a cement wall with a thermal conductivity of .29 Watts/m°K and a thickness of 15 cm. One side of the wall is at a constant temperature of 32°C, and the other side is -7°C. 229 Chapter 4 Programming Projects
  • 250. c. After verifying that your program is working correctly, use the following chart of thermal conductivities to determine the heat transfer rate for the following: i. A pane of glass that’s ½ cm thick and has an inside temperature of 24°C and an outside temperature of 15°C. ii. A column of air 10 cm thick that’s held between two walls, one with a temperature of 23°C and the other of 14°C. Substance Thermal Conductivity (Watts/m°K) Thermal Conductivity (BTU/hrft°F) Air .025 .0015 Cement .29 .17 Glass 1.1 .645 Soil 1.5 .88 Wood, oak .17 .096 Wood, pine .12 .065 14. (General Math) In the game of blackjack, the cards 2 through 10 are counted as their face values, regardless of suit; all face cards (jack, queen, and king) are counted as 10; and an ace is counted as a 1 or an 11, depending on the total count of all cards in a player’s hand. The ace is counted as 11 only if the resulting total value of all cards in a player’s hand doesn’t exceed 21; otherwise, it’s counted as 1. Using this information, write a C++ program that accepts three card values as inputs (a 1 corresponding to an ace, a 2 corresponding to a two, and so on), calculates the total value of the hand, and displays the value of the three cards. Engineering and Scientific Disciplines Civil Engineering The field of civil engineering is concerned primarily with large-scale structures and sys- tems used by a community. A civil engineer designs, constructs, and operates bridges, dams, tunnels, buildings, airports, roads, and other large-scale public works. Civil engi- neers are also responsible for the effects these large-scale systems have on society and the environment, so they are involved in water resources, flood control, waste disposal, and overall urban planning. The field can be subdivided into three categories: 앫 Structures: Design, construction, and operation of large-scale public works, such as dams, buildings, and roads. The properties of materials, geology, soil mechan- ics, and statics and dynamics are important elements of background training. For example, determining a building’s maximum height before it buckles under its own weight is a question involving all these subjects. 앫 Urban planning: Planning, designing, and constructing transportation systems (roads, railroads, river development, airports) and general land use. Surveying and mapmaking are necessary skills. 앫 Sanitation: Waste treatment, water supply, and sewage systems. Fluid mechanics, hydrology, pollution control, irrigation, and economics are important areas of study. 230 Selection Structures
  • 251. Chapter 5 Repetition Statements 5.1 Basic Loop Structures 5.2 while Loops 5.3 Interactive while Loops 5.4 for Loops 5.5 A Closer Look: Loop Programming Techniques 5.6 Nested Loops 5.7 do while Loops 5.8 Common Programming Errors 5.9 Chapter Summary The programs you’ve examined so far have illustrated the programming concepts involved in input, output, assignment, and selection capabilities. By this time, you should have gained enough experience to be comfortable with these concepts and the mechanics of implementing them in C++. Many problems, however, require a repetition capability, in which the same calculation or sequence of instructions is repeated, over and over, using different sets of data. Examples of this type of repetition include continual checking of user data entries until an acceptable entry, such as a valid password, is entered; counting and accumulating running totals; and constant acceptance of input data and recalculation of output values that stop only at entry of a sentinel value. This chapter explores the different methods used by programmers in constructing repeating sections of code and explains how they can be implemented in C++. More commonly, a section of code that’s repeated is referred to as a loop because after the last statement in the code is executed, the program branches, or loops, back to the first statement and starts another repetition through the code. Each repetition is also referred to as an iteration or a pass through the loop.
  • 252. 5.1 Basic Loop Structures The real power of a program is realized when the same type of operation must be made over and over. For example, in some programs the same set of instructions is repeated multiple times. Retyping the same set of instructions in a program is tedious, time consuming, and subject to error. It certainly would be convenient if you could type repeating instructions only once, and then have a method of informing the program to repeat execution of these instructions three times. This method is available by using repeating sections of code. Constructing a repeating section of code requires using four elements. The first necessary element is a repetition statement. A repetition statement both defines the boundaries of the repeating section of code and controls whether the code will be executed. In general, three different forms of repetition statements are provided in C++: • while • for • do while Each of these statements must include a condition to be evaluated, which is the second required element for constructing repeating sections of code. Valid conditions are identical to those used in selection statements. If the condition is true, the code is executed; otherwise, it’s not. The third required element is a statement that initially sets the condition. This statement must always be placed before the condition is first evaluated to ensure correct loop execution the first time the condition is evaluated. Finally, there must be a statement in the repeating section of code that allows the condition to become false. This statement is necessary to ensure that, at some point, the repetitions stop. Pretest and Posttest Loops The condition being tested can be evaluated at the beginning or end of the repeating section of code. Figure 5.1 illustrates the test occurring at the beginning of the loop. This type of loop is referred to as a pretest loop because the condition is tested before any statements in the loop are executed. If the condition is true, the executable statements in the loop are executed. If the initial value of the condition is false, the executable statements in the loop are never executed at all, and control transfers to the first statement after the loop. To avoid infinite repetitions, the condition must be updated within the loop. Pretest loops are also referred to as entrance-controlled loops. Both the while and for loop structures are examples of these loops. A loop that evaluates a condition at end of the repeating section of code, as illustrated in Figure 5.2, is referred to as a posttest or exit-controlled loop. These loops always execute the loop statements at least once before the condition is tested. Because the executable statements in the loop are executed continuously until the condition becomes false, there must always be a statement in the loop that updates the condition and permits it to become false. The do while construct is an example of a posttest loop. 232 Repetition Statements
  • 253. previous statement is the condition true? loop statements yes no next statement previous statement is the condition true? loop statements yes no next statement Figure 5.1 A pretest loop Figure 5.2 A posttest loop Fixed-Count Versus Variable-Condition Loops In addition to classifying repeating sections of code according to where the condition is tested (pretest or posttest), they are also classified by the type of condition being tested. In a fixed-count loop, the condition is used to keep track of how many repetitions have occurred. For example, you might want to produce a table of 10 numbers, including the numbers’ squares and cubes, or a fixed design, such as the following: ************************* ************************* ************************* ************************* In these cases, a fixed number of calculations are performed or a fixed number of lines are printed, at which point the repeating section of code is exited. All of C++’s repetition statements can be used to produce fixed-count loops. 233 Chapter 5 Basic Loop Structures
  • 254. In many situations, the exact number of repetitions isn’t known in advance, or the items are too numerous to count beforehand. For example, when entering a large amount of experimental data, you might not want to take the time to count the number of actual data items to be entered. In these cases, a variable-condition loop is used. In a variable-condition loop, the tested condition doesn’t depend on a count being reached, but on a variable that can change interactively with each pass through the loop. When a specified value is encountered, regardless of how many iterations have occurred, repetitions stop. All of C++’s repetition statements can be used to create variable-condition loops.1 In this chapter, you encounter examples of both fixed-count and variable-condition loops. EXERCISES 5.1 1. (For Review) List the three repetition statements provided in C++. 2. (For Review) List the four elements that must be present in a repetition statement. 3. (For Review) a. What is an entrance-controlled loop? b. Which of C++’s repetition statements produce entrance-controlled loops? 4. (For Review) a. What is an exit-controlled loop? b. Which of C++’s repetition statements produce exit-controlled loops? 5. (For Review) a. What is the difference between a pretest and posttest loop? b. If the condition being tested in a pretest loop is false, how many times are statements in the loop executed? c. If the condition being tested in a posttest loop is false, how many times are state- ments in the loop executed? 6. (For Review) What is the difference between a fixed-count and variable-condition loop? 5.2 while Loops In C++, a while loop is constructed by using a while statement in the following syntax: while (expression) statement; The expression in parentheses is the condition tested to determine whether the statement following the parentheses is executed. The expression is evaluated in exactly the same manner as one in an if-else statement; the difference is in how the expression is used. As you have seen, when the expression in an if-else statement is true (has a non-zero value), the statement following the expression is executed once. In a while statement, the 1 In loop creation, both C and C++ differ from earlier high-level languages, in which the for statement could be used only to produce fixed-count loops. C++’s for statement, as you see in Section 5.4, is virtually interchangeable with its while statement. 234 Repetition Statements
  • 255. statement following the expression is executed repeatedly as long as the expression evaluates to a non-zero value. Considering just the expression and the statement following the parentheses, the computer uses this process in evaluating a while statement: 1. Test the expression 2. If the expression has a non-zero (true) value a. execute the statement following the parentheses b. go back to Step 1 else exit the while statement and execute the next executable statement following the while statement Notice that Step 2b forces program control to be transferred back to Step 1. This transfer of control back to the start of a while statement to reevaluate the expression is what forms the program loop. The while statement literally loops back on itself to recheck the expression until it evaluates to zero (becomes false). Naturally, this rechecking means that somewhere in the loop must be a provision that permits altering the value of the tested expression. As you’ll see, this provision is indeed made. Figure 5.3 shows the looping process a while statement produces. A diamond shape is used to show the two entry and two exit points required in the decision part of the while statement. To make this looping process more tangible, consider the relational expression count <= 10 and the statement cout << count;. Using these elements, you can write the following valid while statement: while (count <= 10) cout << count; Although this statement is valid, the alert reader will realize that it creates a situation in which the cout statement is either executed forever (or until you stop the program) or not executed at all. Here’s why this happens: If count has a value less than or equal to 10 when the expression is first evaluated, the cout statement is executed. The while statement then automatically loops back on itself and retests the expression. Because you haven’t changed the value stored in count, the expression is still true, and another execution of the cout statement is made. This process continues forever, or until the program containing this statement is stopped prematurely by the user. However, if count starts with a value greater than 10, the expression is false to begin with, and the cout statement is never executed. How do you set an initial value in count to control what the while statement does the first time the expression is evaluated? The answer, of course, is to assign values to each variable in the tested expression before the while statement is encountered. For example, the following sequence of instructions is valid: count = 1; while (count <= 10) cout << count; Using this sequence of instructions ensures that count starts with a value of 1. You could assign any value to count in the assignment statement. What’s important is to assign some value. In practice, the assigned value depends on the application. You must still change the value of count so that you can finally exit the while statement. Doing this requires an expression such as count = count + 1 to increment the value of count each time the while statement is executed. The fact that a while 235 Chapter 5 while Loops
  • 256. statement provides for repetition of a single statement doesn’t prevent including an additional statement to change the value of count. All you have to do is replace the single statement with a compound statement, as in this example: count = 1; // initialize count while (count <= 10) { cout << count; count++; // increment count } Note that, for clarity, each statement in the compound statement is placed on a different line. This format is consistent with the convention adopted for compound statements in Chapter 4. Now analyze the preceding sequence of instructions. The first assignment statement sets count equal to 1. The while statement is then entered, and the expression is evaluated for the first time. Because the value of count is less than or equal to 10, the expression is true, and the compound statement is executed. The first statement in the compound statement uses the cout object to display the value of count. The next statement adds 1 to the value currently stored in count, making this value equal to 2. The while statement then loops test the expression (step 1) execute the statement after the parentheses (step 2a) loop enter the while statement (a false condition) expression evaluates to zero exit the while statement expression evaluates to a non-zero number (a true condition) go back and reevaluate the expression (step 2b) Figure 5.3 Anatomy of a while loop 236 Repetition Statements
  • 257. back to retest the expression. Because count is still less than or equal to 10, the compound statement is executed again. This process continues until the value of count reaches 11. Program 5.1 illustrates these statements in an actual program. Program 5.1 #include <iostream> using namespace std; int main() { int count; count = 1; // initialize count while (count <= 10) { cout << count << " "; count++; // increment count } return 0; } This is the output for Program 5.1: 1 2 3 4 5 6 7 8 9 10 Note that there’s nothing special about the name count used in Program 5.1. Any valid integer variable could have been used. Before you look at other examples of the while statement, two comments on Program 5.1 are in order. First, the statement count++ can be replaced with any statement that changes the value of count. A statement such as count = count + 2, for example, causes every second integer to be displayed. Second, it’s the programmer’s responsibility to ensure that count is changed in a way that leads to a normal exit from the while. For example, if you replace the expression count++ with the expression count--, the value of count never exceeds 10 and an infinite loop is created. An infinite loop is a loop that never ends; the program just keeps displaying numbers until you realize it isn’t working as you expected. Now that you have some familiarity with the while statement, see whether you can read and determine the output of Program 5.2. 237 Chapter 5 while Loops
  • 258. Program 5.2 #include <iostream> using namespace std; int main() { int i; i = 10; while (i >= 1) { cout << i << " "; i--; // subtract 1 from i } return 0; } The assignment statement in Program 5.2 initially sets the int variable i to 10. The while statement then checks to see whether the value of i is greater than or equal to 1. While the expression is true, the value of i is displayed by the cout statement, and the value of i is decremented by 1. When i finally reaches zero, the expression is false, and the program exits the while statement. Therefore, Program 5.2 produces the following display when it runs: 10 9 8 7 6 5 4 3 2 1 To illustrate the power of the while statement, consider the task of printing a table of numbers from 1 to 10 with the numbers’ squares and cubes. You can do this with a simple while statement, as shown in Program 5.3. When Program 5.3 runs, the following display is produced: NUMBER SQUARE CUBE ------ ------ ---- 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000 238 Repetition Statements
  • 259. Program 5.3 #include <iostream> #include <iomanip> using namespace std; int main() { int num; cout << "NUMBER SQUARE CUBEn" << "------ ------ ----n"; num = 1; while (num < 11) { cout << setw(3) << num << " " << setw(3) << num * num << " " << setw(4) << num * num * num << endl; num++; // increment num } return 0; } Note that the expression used in Program 5.3 is num < 11. For the integer variable num, this expression is exactly equivalent to the expression num <= 10. The choice of which to use is entirely up to you. If you want to use Program 5.3 to produce a table of 1000 numbers, all you do is change the expression in the while statement from num < 11 to num < 1001. Changing the 11 to 1001 produces a table of 1000 lines—not bad for a simple five-line while statement. 239 Chapter 5 while Loops
  • 260. All the program examples of the while statement use fixed-count loops because the tested condition is a counter that checks for a fixed number of repetitions. In a variation on the fixed-count loop, the counter is not incremented by one each time through the loop but by some other value. For example, suppose you have the task of producing a Celsius-to- Fahrenheit temperature conversion table. Fahrenheit temperatures corresponding to Celsius temperatures from 5 to 50 degrees are to be displayed in increments of 5 degrees, which can be done with this series of statements: celsius = 5; // starting Celsius value while (celsius <= 50) { fahren = (9.0/5.0) * celsius + 32.0; cout << celsius << " " << fahren; celsius = celsius + 5; } As before, the while statement consists of everything from the word while through the compound statement’s closing brace. Before the program enters the while loop, you must make sure a value is assigned to the counter being evaluated, and there’s a statement to alter the value of the counter in the loop (in increments of 5 degrees Celsius) to ensure an exit from the while loop. Program 5.4 illustrates using similar code in a complete program. This is the display produced when Program 5.4 is executed: DEGREES DEGREES CELSIUS FAHRENHEIT ------- ---------- 5 41.00 10 50.00 15 59.00 20 68.00 25 77.00 30 86.00 35 95.00 40 104.00 45 113.00 50 122.00 240 Repetition Statements
  • 261. Program 5.4 #include <iostream> #include <iomanip> using namespace std; // a program to convert Celsius to Fahrenheit int main() { const int MAX_CELSIUS = 50; const int START_VAL = 5; const int STEP_SIZE = 5; int celsius; double fahren; cout << "DEGREES DEGREESn" << "CELSIUS FAHRENHEITn" << "------- ----------n"; celsius = START_VAL; // set output formats for floating point numbers only cout << setiosflags(ios::showpoint) << setprecision(2); while (celsius <= MAX_CELSIUS) { fahren = (9.0/5.0) * celsius + 32.0; cout << setw(4) << celsius << fixed << setw(13) << fahren << endl; celsius = celsius + STEP_SIZE; } return 0; } 241 Chapter 5 while Loops
  • 262. Technical Note Fluid Mechanics The field of fluid mechanics deals with fluids at rest and in motion. Fluids include both liquids and gases and are defined as substances that conform to the shape of their holding containers. These are the primary differences between gases and liquids: 앫 Gases are expandable and contractible and always expand or contract to fill all space in the container holding them. 앫 Liquids occupy a definite volume and have a free surface if they don’t fill the container holding them. Fluid statics is the science of fluids at rest, a major subdiscipline of fluid mechanics. The most important property for fluids at rest is their weight. Fluid dynamics is the sci- ence of fluids in motion, which is the second major subdiscipline of fluid mechanics and includes aerodynamics, the study of gases in motion, and hydrodynamics, the study of liq- uids in motion. For flowing fluids, the two most important properties are density and viscosity. Density is the measure of how tightly packed the fluid is (density = mass/volume). Viscosity is the measure of a liquid’s resistance to shear stress. A fluid begins to flow when an applied force, known as a shear stress, is large enough to overcome the fluid’s weight and internal friction, assuming the fluid isn’t totally constrained in the direction of the force. The three types of fluid flow patterns through a pipe or conduit are as follows: 앫 Laminar—All fluid particles flow in smooth, straight lines parallel to the pipe’s wall. 앫 Turbulent—Fluid particle paths are irregular, but the average motion is in the direction of the flow. 앫 In transition—The fluid is between laminar and turbulent flow. Laminar flow generally occurs only when the fluid’s viscosity is very high, as in lubricating oils. Most flows, such as water flowing through pipes, are faster and turbulent. The Reynolds number provides a quick means of determining flow patterns and can be calculated by using this formula: Re = ρ µ Vd Re = the Reynolds number ρ = the fluid’s density (kg/m3 ) V = the fluid’s average speed (m/s) d = the pipe’s diameter (m) µ = the fluid’s viscosity (kg/ms) continued... 242 Repetition Statements
  • 263. EXERCISES 5.2 1. (Practice) Rewrite Program 5.1 to print the numbers 2 to 10 in increments of two. The output of your program should be the following: 2 4 6 8 10 2. (Practice) Rewrite Program 5.4 to produce a table starting at a Celsius value of -10 and ending with a Celsius value of 60, in increments of 10 degrees. 3. (Desk Checking) a. For the following program, determine the total number of items displayed as well as the first and last numbers printed: #include <iostream> using namespace std; int main() { int num = 0; while (num <= 20) { num++; cout << num << " "; } return 0; } b. Enter and run the program from Exercise 3a on a computer to verify your answers to the exercise. Technical Note Fluid Mechanics (continued) Essentially, the Reynolds number is equal to the ratio of fluid speed viscous forces A higher Reynolds number correlates with a higher fluid speed. However, when viscous forces predominate (they are retarding forces), the Reynolds number is lower, and the fluid flow is slower. In a highly viscous fluid, such as heavy oil, all the fluid’s particles tend to be kept in line, which is referred to as laminar flow. Critical Reynolds number values for determining flow type are as follows: 앫 Re < 2000: Fluid flow is laminar (least common type of water flow). 앫 2000 ⱕ Re ⱖ 3000: Fluid flow is in transition. 앫 Re > 3000: Fluid flow is turbulent (most common type of fluid flow). 243 Chapter 5 while Loops
  • 264. c. How would the output be affected if the two statements in the compound statement were reversed (that is, if the cout statement came before the num++ statement)? 4. (Conversions) Write a C++ program that converts gallons to liters. The program should display gallons from 10 to 20 in one-gallon increments and the corresponding liter equivalents. Use the relationship that 1 gallon = 3.785 liters. 5. (Conversions) Write a C++ program that converts feet to meters. The program should display feet from 3 to 30 in 3-foot increments and the corresponding meter equivalents. Use the relationship that 1 meter = 3.28 feet. 6. (Practice) An automobile travels at an average speed of 55 mph for four hours. Write a C++ program that displays the distance, in miles, the car has traveled after 1, 2, and so on hours until the end of the trip. 7. (Fluid Mechanics) The maximum laminar flow speed is the speed at which a fluid begins to change from a smooth, straight flow to turbulent flow within a pipe. It can be determined by using this formula: Maximum laminar flow speed = (2000 × pipe diameter × density)/viscosity Using this formula, write a C++ program that used a fixed-count repetition loop of four. For each pass through the loop, the program should accept a fluid’s density, its viscosity, and a pipe diameter as input, and then calculate and output the maximum laminar flow rate through the pipe. Use the results your program outputs to complete the last column in this chart: Fluid Viscosity at 40°C = 77°F (kg/ms) Density (kg/m3 ) Pipe Diameter (m) Maximum Laminar Flow Speed (m/s) Gasoline .4466 × 10-3 .7186 × 103 0.4 Medium fuel oil 2.9922 × 10-3 .8496 × 103 0.4 Medium lubricating oil 87.0736 × 10-3 .8865 × 103 0.4 Water .8975 × 10-3 .9973 × 103 0.4 8. (Numerical Analysis) a. The following is an approximate conversion formula for con- verting Fahrenheit to Celsius temperatures: Celsius = (Fahrenheit - 30) / 2 Using this formula, and starting with a Fahrenheit temperature of 0 degrees, write a C++ program that determines when the approximate equivalent Celsius temperature differs from the exact equivalent value by more than four degrees. (Hint: Use a while loop that terminates when the difference between approximate and exact Celsius equivalents exceeds 4 degrees.) 244 Repetition Statements
  • 265. b. Using the approximate Celsius conversion formula given in Exercise 8a, write a C++ program that produces a table of Fahrenheit temperatures, exact Celsius equivalent temperatures, approximate Celsius equivalent temperatures, and the difference between the exact and approximate equivalent Celsius values. The table should begin at 0 degrees Fahrenheit, use 2-degree Fahrenheit increments, and terminate when the difference between exact and approximate values is more than 4 degrees. 9. (Numerical Analysis) The value of Euler’s number, e, can be approximated by using this formula: e = + + + + + + 1 1 1 1 2 1 3 1 4 1 5 ! ! ! ! ! ... Using this formula, write a C++ program that approximates the value of e, using a while loop that terminates when the difference between two successive approximations is less than 10e-9. 10. (Numerical Analysis) The value of sin x can be approximated by using this formula: sin( ) ! ! ! ! . . . x x x x x x = + + - - 3 5 7 9 3 5 7 9 Using this formula, determine how many terms are needed to approximate the value returned by the intrinsic sin() function with an error less than 1e-6, when x = 30 degrees. (Hints: Use a while loop that terminates when the difference between the value returned by the intrinsic sin() function and the approximation is less than 1e-6. Also, note that x must first be converted to radian measure, and the alternating sign in the approximating series can be determined as (-1) × (n + 1), where n is the number of terms used in the approximation.) 5.3 Interactive while Loops Combining interactive data entry with the repetition capabilities of the while statement produces adaptable and powerful programs. To understand the concept, take a look at Program 5.5, where a while statement is used to accept and then display four user-entered numbers, one at a time. Although the program uses a simple idea, it highlights the flow of control concepts needed to produce more useful programs. The following is a sample run of Program 5.5: This program will ask you to enter 4 numbers. Enter a number: 26.2 The number entered is 26.2 Enter a number: 5 The number entered is 5 Enter a number: 103.456 The number entered is 103.456 Enter a number: 1267.89 The number entered is 1267.89 245 Chapter 5 Interactive while Loops
  • 266. Program 5.5 #include <iostream> #include <iomanip> using namespace std; int main() { const int MAXNUMS = 4; int count; double num; cout << "nThis program will ask you to enter " << MAXNUMS << " numbers.n"; count = 1; while (count <= MAXNUMS) { cout << "nEnter a number: "; cin >> num; cout << "The number entered is " << num; count++; } cout << endl; return 0; } Review the program so that you understand clearly how the output was produced. The first message displayed is caused by execution of the first cout statement. This statement is outside and before the while statement, so it’s executed once before any statement in the while loop. After the while loop is entered, the statements in the compound statement are executed while the tested condition is true. The first time through the compound statement, the message Enter a number: is displayed. The program then executes the cin statement, which forces the computer to wait for a number to be entered at the keyboard. After a number is typed and the Enter key is pressed, the cout statement displays the number. The variable count is then incremented by one. This process continues until four passes through the loop have been made and the value of count is 5. Each pass causes the message Enter a number: to be displayed, causes one cin statement to be executed, and causes the message The number entered is to be displayed. Figure 5.4 illustrates this flow of control. Instead of simply displaying the entered numbers, Program 5.5 can be modified to use the entered data. For example, you can add the numbers entered and display the total. To do this, you must be careful about how you add the numbers because the same variable, num, is used for each number entered. For this reason, the entry of a new number in Program 5.5 246 Repetition Statements
  • 267. automatically causes the previous number stored in num to be lost. Therefore, each number entered must be added to the total before another number is entered. This is the required sequence: Enter a number Add the number to the total add 1 to count loop no (condition is false) set count equal to 1 print a message print value of number accept a number using cin print the message Enter a number: is count less than or equal to 4? go back and retest count these statements are executed each time the loop is traversed yes (condition is true) end of program start stop Figure 5.4 Flow of control diagram for Program 5.5 247 Chapter 5 Interactive while Loops
  • 268. How do you add a single number to a total? A statement such as total = total + num does the job perfectly. It’s the accumulation statement introduced in Section 3.1. After each number is entered, the accumulating statement adds the number to the total, as shown in Figure 5.5. The complete flow of control for adding the numbers is illustrated in Figure 5.6. In reviewing Figure 5.6, observe that a provision has been made for initially setting the total to zero before the while loop is entered. If you cleared the total inside the while loop, it would be set to zero each time the loop was executed, and any value stored previously would be erased. total = total + num new total total the variable total new number goes in here cin num new number accept a new number the variable num add 1 to count add num to total accept a num is count < 4? no set total to zero print total yes set count to one stop start Figure 5.5 Accepting and adding Figure 5.6 Accumulation flow of a number to a total control Program 5.6 incorporates the necessary modifications to Program 5.5 to total the numbers entered. As shown, the statement total = total + num; is placed immediately after the cin statement. Putting the accumulating statement at this point in the program ensures that the entered number is “captured” immediately into the total. 248 Repetition Statements
  • 269. Program 5.6 #include <iostream> #include <iomanip> using namespace std; int main() { const int MAXNUMS = 4; int count; double num, total; cout << "nThis program will ask you to enter " << MAXNUMS << " numbers.n"; count = 1; total = 0; while (count <= MAXNUMS) { cout << "nEnter a number: "; cin >> num; total = total + num; cout << "The total is now " << setprecision(7) << total; count++; } cout << "nThe final total is " << setprecision(7) << total << endl; return 0; } To make sure you understand, review Program 5.6. The variable total was created to store the total of the numbers entered. Before entering the while statement, the value of total is set to zero to make sure any previous value in the storage location(s) assigned to the variable total is erased. Inside the while loop, the statement total = total + num; is used to add the value of the entered number to total. As each value is entered, it’s added to the existing total to create a new total. Therefore, total becomes a running subtotal of all the values entered. Only after all numbers are entered does total contain the final sum of all the numbers. After the while loop is finished, a cout statement is used to display this sum. 249 Chapter 5 Interactive while Loops
  • 270. Using the same data entered in the sample run for Program 5.5, the following sample run of Program 5.6 was made: This program will ask you to enter 4 numbers. Enter a number: 26.2 The total is now 26.2 Enter a number: 5 The total is now 31.2 Enter a number: 103.456 The total is now 134.656 Enter a number: 1267.89 The total is now 1402.546 The final total is 1402.546 Having used an accumulating assignment statement to add the numbers entered, you can go further and calculate the average of the numbers. Where do you calculate the average— inside the while loop or outside it? In the case at hand, calculating an average requires that both a final sum and the number of items in that sum be available. The average is then computed by dividing the final sum by the number of items. At this point, you must ask, “At what point in the program is the correct sum available, and at what point is the number of items available?” In reviewing Program 5.6, you can see that the correct sum needed for calculating the average is available after the while loop is finished. In fact, the whole purpose of the while loop is to ensure that the numbers are entered and added correctly to produce a correct sum. After the loop is finished, you also have a count of the number of items used in the sum. However, because of the way the while loop was constructed, the number in count (5) when the loop is finished is one more than the number of items (four) used to obtain the total. Knowing this, you simply subtract one from count before using it to determine the average. With this information as background, take a look at Program 5.7. Program 5.7 is almost identical to Program 5.6, except for the calculation of the average. The constant display of the total inside and after the while loop has also been removed. The loop in Program 5.7 is used to enter and add four numbers. Immediately after the loop is exited, the average is computed and displayed. A sample run of Program 5.7 follows: This program will ask you to enter 4 numbers. Enter a number: 26.2 Enter a number: 5 Enter a number: 103.456 Enter a number: 1267.89 The average of the numbers is 350.637 250 Repetition Statements
  • 271. Program 5.7 #include <iostream> #include <iomanip> using namespace std; int main() { const int MAXNUMS = 4; int count; double num, total, average; cout << "nThis program will ask you to enter " << MAXNUMS << " numbers.n"; count = 1; total = 0; while (count <= MAXNUMS) { cout << "Enter a number: "; cin >> num; total = total + num; count++; } count--; average = total / count; cout << "nThe average of the numbers is " << average << endl; return 0; } Sentinels All the loops created so far have been examples of fixed-count loops, in which a counter is used to control the number of loop iterations. By means of a while statement, variable-condition loops can also be constructed. For example, when entering grades, you might not want to count the number of grades that will be entered. Instead, you prefer to enter the grades continuously, and at the end, type in a special data value to signal the end of data input. In computer programming, data values used to signal the start or end of a data series are called sentinels. Sentinel values must, of course, be selected so as not to conflict with legitimate data values. For example, if you’re constructing a program to process a student’s grades, and assuming no extra credit is given that could produce a grade higher than 100, you could use any grade higher than 100 as a sentinel value. Program 5.8 illustrates this concept: Data is requested and accepted continuously until a number larger than 100 is entered. Entry 251 Chapter 5 Interactive while Loops
  • 272. of a number higher than 100 alerts the program to exit the while loop and display the sum of the numbers entered. Program 5.8 #include <iostream> using namespace std; int main() { const int HIGHGRADE = 100; double grade, total; grade = 0; total = 0; cout << "nTo stop entering grades, type in any number"; cout << "n greater than 100.nn"; while (grade <= HIGHGRADE) { total = total + grade; cout << "Enter a grade: "; cin >> grade; } cout << "nThe total of the grades is " << total << endl; return 0; } The following lines show a sample run of Program 5.8. As long as grades less than or equal to 100 are entered, the program continues to request and accept additional data. When a number less than or equal to 100 is entered, the program adds this number to the total. When a number greater than 100 is entered, the loop is exited, and the sum of the grades that were entered is displayed. To stop entering grades, type in any number greater than 100. Enter a grade: 95 Enter a grade: 100 Enter a grade: 82 Enter a grade: 101 The total of the grades is 277 252 Repetition Statements
  • 273. break and continue Statements Two useful statements in connection with repetition statements are the break and continue statements. You encountered the break statement in Section 4.4 when learning about the switch statement. This is the format of the break statement: break; A break statement, as its name implies, forces an immediate break, or exit, from the switch, while, for, and do-while statements (discussed in the next sections). For example, execution of the following while loop is terminated immediately if a number greater than 76 is entered: while(count <= 10) { cout << "Enter a number: "; cin >> num; if (num > 76) { cout << "You lose!n"; break; // break out of the loop } else cout << "Keep on trucking!n"; count++ } // break jumps to here The break statement violates structured programming principles because it provides a second, nonstandard exit from a loop. Nevertheless, the break statement is extremely useful for breaking out of loops when an unusual condition is detected. The break statement is also used to exit from a switch statement when the matching case value has been detected and processed. The continue statement is similar to the break statement but applies only to loops created with while, do-while, and for statements. This is the general format of a continue statement: continue; When continue is encountered in a loop, the next iteration of the loop begins immediately. For while loops, this means execution is transferred automatically to the top of the loop, and reevaluation of the tested expression is initiated. Although the continue statement has no direct effect on a switch statement, it can be included in a switch statement, which is contained in a loop. The effect of continue is the same: The next loop iteration begins. As a general rule, the continue statement is less useful than the break statement, but it’s convenient for skipping over data that shouldn’t be processed while remaining in a loop. 253 Chapter 5 Interactive while Loops
  • 274. For example, invalid grades are simply ignored in the following section of code, and only valid grades are added to the total:2 while (count < 30) { cout << "Enter a grade: "; cin >> grade if(grade < 0 || grade > 100) continue; total = total + grade; count++; } The Null Statement All statements must be terminated by a semicolon. A semicolon with nothing preceding it is also a valid statement, called the null statement, as shown: ; It’s a do-nothing statement used where a statement is required syntactically, but no action is called for. Typically, null statements are used with while or for statements. Program 5.10c in Section 5.4 shows an example of a for statement using a null statement. EXERCISES 5.3 1. (Practice) Rewrite Program 5.6 to compute the total of eight numbers. 2. (Practice) Rewrite Program 5.6 to display this prompt: Please type in the total number of data values to be added: In response to this prompt, the program should accept a user-entered number, and then use this number to control the number of times the while loop is executed. So if the user enters 5 in response to the prompt, the program should request the input of five numbers and display the total after five numbers have been entered. 3. (Practice) Rewrite Program 5.7 to compute the average of 10 numbers. 4. (Practice) Rewrite Program 5.7 to display the following prompt: Please type in the total number of data values to be averaged: 2 The continue statement is not essential, however, and the selection could have been written as follows: if (gradeⱖ 0 && grade ⱕ 100) { total = total + grade; count++; } 254 Repetition Statements
  • 275. In response to this prompt, the program should accept a user-entered number, and then use this number to control the number of times the while loop is executed. So if the user enters 6 in response to the prompt, the program should request an input of six num- bers and display the average of the next six numbers entered. 5. (Debugging) By mistake, a programmer puts the statement average = total / count; in the while loop immediately after the statement total = total + num; in Program 5.7. As a result, the while loop becomes the following: while (count <= MAXNUMS) { cout << "Enter a number: "; cin >> num; total = total + num; average = total / count; count++; } a. Will the program yield the correct result with this while loop? b. From a programming perspective, which while loop is better to use and why? 6. (Conversions) a. Write a C++ program to convert meters to feet. The program should request the starting meter value, the number of conversions to be made, and the increment between metric values. The display should have appropriate headings and list the meters and the corresponding feet value. If the number of iterations is greater than 10, have your pro- gram substitute a default increment of 10. Use the relationship that 1 meter = 3.281 feet. b. Run the program written in Exercise 6a on a computer. Verify that your program begins at the correct starting meter value and contains the exact number of conver- sions specified in your input data. 7. (Conversions) a. Modify the program written in Exercise 6a to request the starting meter value, the ending meter value, and the increment. Instead of the condition check- ing for a fixed count, the condition checks for the ending meter value. If the number of iterations is greater than 20, have your program substitute a default increment of (ending value - starting value) / 19. b. Run the program written in Exercise 7a on a computer. Verify that your output starts at the correct beginning value and ends at the correct ending value. 8. (Numerical Analysis) An arithmetic series is defined by the following: a + (a + d) + (a + 2d) + (a + 3d) + ... + [(a + (n - 1)d)] a is the first term. d is the “common difference.” n is the number of terms to be added. Using this information, write a C++ program that uses a while loop to display each term and determine the sum of the arithmetic series having a = 1, d = 3, and n = 100. Make sure your program displays the value it has calculated. 9. (Numerical Analysis) A geometric series is defined by the following: a + ar + ar 2 + ar 3 + ... + arn - 1 255 Chapter 5 Interactive while Loops
  • 276. a is the first term. r is the “common ratio.” n is the number of terms in the series. Using this information, write a C++ program that uses a while loop to both display each term and determine the sum of a geometric series having a = 1, r = .5, and n = 10. Make sure your program displays the value it has calculated. 10. (Misc. Application) a. The data in the following chart was collected on a recent auto- mobile trip: Mileage Gallons 22,495 Full tank 22,841 12.2 23,185 11.3 23,400 10.5 23,772 11.0 24,055 12.2 24,434 14.7 24,804 14.3 25,276 15.2 Write a C++ program that accepts a mileage and gallons value and calculates the miles per gallon (mpg) for that segment of the trip. The mpg is obtained as the difference in mileage between fill-ups divided by the number of gallons of gasoline used in the fill-up. b. Modify the program written for Exercise 10a to also compute and display the cumula- tive mpg after each fill-up. The cumulative mpg is calculated as the difference between the mileage at each fill-up and the mileage at the start of the trip divided by the sum of gallons used to that point in the trip. 5.4 for Loops In C++, a for loop is constructed by using a for statement. This statement performs the same functions as the while statement but uses a different form. In many situations, especially those using a fixed-count condition, the for statement format is easier to use than its while statement equivalent. This is the syntax of the for statement: for (initializing list; expression; altering list) statement; Although the for statement looks a little complicated, it’s really quite simple if you consider each part separately. Inside the parentheses of the for statement are three items, separated by semicolons. Each item is optional and can be described separately, but the semicolons must always be present, even if you don’t use the items. In the for statement’s most common form, the initializing list consists of a single statement used to set the starting (initial) value of a counter, the expression (also called the “condition”) 256 Repetition Statements
  • 277. contains the maximum or minimum value the counter can have and determines when the loop is finished, and the altering list provides the increment value that’s added to or subtracted from the counter each time the loop is executed. Here are two examples of simple for statements having this form: for (count = 1; count < 10; count = count + 1) cout << count; and for (i = 5; i <= 15; i = i + 2) cout << i; In the first for statement, the counter variable is named count, the initial value assigned to count is 1, the loop continues as long as the value in count is less than 10, and the value of count is incremented by 1 each time through the loop. In the next for statement, the counter variable is named i, the initial value assigned to i is 5, the loop continues as long as i’s value is less than or equal to 15, and the value of i is incremented by 2 each time through the loop. In both examples, a cout statement is used to display the value of the counter. Program 5.9 shows another example of a for loop. Program 5.9 #include <iostream> #include <iomanip> #include <cmath> using namespace std; int main() { const int MAXCOUNT = 5; int count; cout << "NUMBER SQUARE ROOTn"; cout << "------ -----------n"; cout << setiosflags(ios::showpoint); for (count = 1; count <= MAXCOUNT; count++) cout << setw(4) << count << setw(15) << sqrt(double(count)) << endl; return 0; } 257 Chapter 5 for Loops
  • 278. When Program 5.9 is executed, the following display is produced: NUMBER SQUARE ROOT ------ ----------- 1 1.00000 2 1.41421 3 1.73205 4 2.00000 5 2.23607 The first two lines of this output are produced by the two cout statements placed before the for statement. The remaining output is produced by the for loop, which begins with the for statement and is executed as follows: The initial value assigned to the counter variable count is 1. Because the value in count doesn’t exceed the final value of 5, the execution of the cout statement in the loop produces this display: 1 1.00000 Control is then transferred back to the for statement, which increments the value in count to 2, and the loop is repeated, producing this display: 2 1.41421 This process continues until the value in count exceeds the final value of 5, producing the complete output table. For comparison purposes, a while loop equivalent to the for loop in Program 5.9 is as follows: count = 1 while (count <= MAXCOUNT) { cout << setw(4) << count << setw(15) << sqrt(count) << endl; count++; } As you can see in this example, the difference between the for and while loops is the placement of the initialization, condition being tested, and incrementing items. Grouping these items in the for statement is convenient when you must construct fixed-count loops. See whether you can determine the output Program 5.10 produces. 258 Repetition Statements
  • 279. Program 5.10 #include <iostream> using namespace std; int main() { int count; for (count = 2; count <= 20; count = count + 2) cout << count << " "; return 0; } Did you figure it out? The loop starts with count initialized to 2, stops when count exceeds 20, and increments count in steps of 2. This is the output of Program 5.10: 2 4 6 8 10 12 14 16 18 20 As mentioned, the for statement doesn’t require having an initializing or altering list inside for’s parentheses; however, the two semicolons must be included in these parentheses. For example, the construction for ( ; count <= 20 ;) is valid. If the initializing list is missing, the initialization step is omitted when the for statement is executed. Therefore, the programmer must provide the required initializations before the for statement is encountered. Similarly, if the altering list is missing, any expressions needed to alter the evaluation of the tested expression must be included in the statement part of the loop. The for statement only ensures that all expressions in the initializing list are executed once, before evaluation of the tested expression, and all expressions in the altering list are executed at the end of the loop, before the tested expression is rechecked. Program 5.10 can be rewritten in any of the three ways shown in Programs 5.10a, 5.10b, and 5.10c. Program 5.10a #include <iostream> using namespace std; int main() { int count; count = 2; // initializer outside the for statement for ( ; count <= 20; count = count + 2) cout << count << " "; return 0; } 259 Chapter 5 for Loops
  • 280. Program 5.10b #include <iostream> using namespace std; int main() { int count; count = 2; // initializer outside the for loop for( ; count <= 20; ) { cout << count << " "; count = count + 2; // alteration statement } return 0; } Program 5.10c #include <iostream> using namespace std; int main() // all expressions inside for's parentheses { int count; for (count = 2; count <= 20; cout << count << " ", count = count + 2); return 0; } In Program 5.10a, count is initialized outside the for statement, and the first list inside the parentheses is left blank. In Program 5.10b, both the initializing list and the altering list are outside the parentheses. Program 5.10b also uses a compound statement in the for loop, with the expression-altering statement included in the compound statement. Finally, Program 5.10c has included all items inside the parentheses, so there’s no need for any useful statement following the parentheses. In this example, the null statement satisfies the syntactical requirement of one statement to follow for’s parentheses. Also, observe in Program 5.10c that the altering list (the last set of items in parentheses) consists of two items, and a comma has been used to separate these items. Using commas to separate items in both the initializing and altering lists is required if either of these lists contains more than one item. 260 Repetition Statements
  • 281. Last, note that Programs 5.10a, 5.10b, and 5.10c are all inferior to Program 5.10, and although you might encounter them in your programming career, you shouldn’t use them. Adding items other than loop control variables and their updating conditions in the for statement tends to make it confusing to read and can result in unwanted effects. Keeping the loop control structure “clean,” as in Program 5.10, is important and a good programming practice. Although the initializing and altering lists can be omitted from a for statement, omitting the tested expression results in an infinite loop. For example, this statement creates an infinite loop: for (count = 2; ; count = count + 1) cout << count; As with the while statement, both break and continue statements can be used in a for loop. A break forces an immediate exit from the for loop, as it does in the while loop. A continue, however, forces control to be passed to the altering list in a for statement, after which the tested expression is reevaluated. This action differs from continue’s action in a while statement, where control is passed directly to reevaluation of the tested expression. Figure 5.7 illustrates the internal workings of a for loop. As shown, when the for loop is completed, control is transferred to the first executable statement following the loop. To avoid having to illustrate every step, you can use a simplified set of flowchart symbols to describe for loops. If you use the following flowchart symbol to represent a for statement, Point of Information Where to Place the Opening Braces When the for loop contains a compound statement, professional C++ programmers use two styles of writing for loops. The style used in this book takes the following form: for (expression) { compound statement in here } An equally acceptable style places the compound statement’s opening brace on the first line. Using this style, a for loop looks like the following: for (expression) { compound statement in here } The advantage of the first style is that the braces line up under one another, making it easier to locate brace pairs. The advantage of the second style is that it makes the code more compact and saves a line, so more code can be viewed in the same display area. Both styles are used but are almost never intermixed. Select whichever style appeals to you and be consistent in its use. As always, the indentation you use in the compound state- ment (two or four spaces or a tab) should also be consistent throughout all your programs. The combination of styles you select becomes a “signature” for your programming work. 261 Chapter 5 for Loops
  • 282. you can then illustrate a complete for loop, as shown in Figure 5.8. for statement execute the altering list execute the statement after the parentheses evaluate the tested expression loop (false condition) expression’s value is non-zero (true condition) initializing statements enter the for statement expression’s value is zero exit the for statement go back and retest the condition Figure 5.7 A for loop flowchart 262 Repetition Statements
  • 283. To understand the enormous power of for loops, consider the task of printing a table of numbers from 1 to 10, including their squares and cubes, by using a for statement. This table was produced previously by using a while loop in Program 5.3. You might want to review Program 5.3 and compare it to Program 5.11 to get a better sense of the equivalence between for and while loops. Point of Information Do You Use a for or while Loop? Beginning programmers often ask which loop structure they should use—a for or while loop. It’s a good question because both loop structures are pretest loops that, in C++, can be used to construct fixed-count and variable-condition loops. In most other computer languages, including Visual Basic and Pascal, the answer is straightforward because the for statement can be used only to construct fixed-count loops. In these languages, then, for statements are used to construct fixed-count loops, and while statements are generally used only for variable-condition loops. In C++, this easy distinction doesn’t hold because both statements can be used to create both types of loops. The answer is more a matter of style. Because a for and while loop are interchangeable in C++, either loop is appropriate. Some professional programmers always use a for statement for pretest loops and almost never use a while statement; others always use a while statement and rarely use a for statement. Still a third group tends to retain the convention used in other languages—a for loop is generally used to create fixed-count loops, and a while loop is used to create variable-condition loops. In C++, it’s a matter of style, and you’ll encounter all three styles in your programming career. for (expression) { statement 1 through statement n } enter the for statement expression’s value is non-zero (true condition) (false condition) expression’s value is zero exit the for statement Figure 5.8 A simplified for loop flowchart 263 Chapter 5 for Loops
  • 284. Program 5.11 #include <iostream> #include <iomanip> using namespace std; int main() { const int MAXNUMS = 10; int num; cout << "NUMBER SQUARE CUBEn" << "------ ------ ----n"; for (num = 1; num <= MAXNUMS; num++) cout << setw(3) << num << " " << setw(3) << num * num << " " << setw(4) << num * num * num << endl; return 0; } When Program 5.11 runs, this is the display produced: NUMBER SQUARE CUBE ------ ------ ---- 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000 Simply changing the number 10 in the for statement of Program 5.11 to 1000 creates a loop that’s executed 1000 times and produces a table of numbers from 1 to 1000. As with the while statement, this small change produces an immense increase in the program’s processing and output. Notice also that the expression num++ was used in the altering list in place of the usual num = num + 1. 264 Repetition Statements
  • 285. EXERCISES 5.4 1. (Practice) Write a for statement for each of the following cases: a. Use a counter named i that has an initial value of 1, a final value of 20, and an incre- ment of 1. b. Use a counter named icount that has an initial value of 1, a final value of 20, and an increment of 2. c. Use a counter named j that has an initial value of 1, a final value of 100, and an increment of 5. d. Use a counter named icount that has an initial value of 20, a final value of 1, and an increment of -1. e. Use a counter named icount that has an initial value of 20, a final value of 1, and an increment of -2. f. Use a counter named count that has an initial value of 1.0, a final value of 16.2, and an increment of 0.2. g. Use a counter named xcnt that has an initial value of 20.0, a final value of 10.0, and an increment of -0.5. 2. (Desk Checking) Determine the number of times each for loop is executed for the for statements written for Exercise 1. 3. (Desk Checking) Determine the value in total after each of the following loops is executed: a. total = 0; for (i = 1; i <= 10; i = i + 1) total = total + 1; b. total = 1; for (count = 1; count <= 10; count = count + 1) total = total * 2; c. total = 0 for (i = 10; i <= 15; i = i + 1) total = total + i; d. total = 50 for (i = 1; i <=10; i = i + 1) total = total – i; e. total = 1 for (icnt = 1; icnt <= 8; ++icnt) total = total * icnt; f. total = 1.0 for (j = 1; j <= 5; ++j) total = total / 2.0; 265 Chapter 5 for Loops
  • 286. 4. (Desk Checking) Determine the output of the following program: #include <iostream> using namespace std; int main() { int i; for (i = 20; i >= 0; i = i – 4) cout << i << " "; return 0; } 5. (Modify) Modify Program 5.11 to produce a table of the numbers 0 through 20 in incre- ments of 2, with their squares and cubes. 6. (Modify) Modify Program 5.11 to produce a table of numbers from 10 to 1, instead of 1 to 10, as it currently does. 7. (Conversions) Write a C++ program to convert kilometers/hr to miles/hr. The program should produce a table of 10 conversions, starting at 60 km/hr and incremented by 5 km/hr. The display should have appropriate headings and list each km/hr and its equivalent miles/hr value. Use the relationship that 1 kilometer = 0.6241 miles. 8. (Practice) Write sections of C++ code to do the following: a. Display the multiples of 3 backward from 33 to 3, inclusive. b. Display the uppercase letters of the alphabet backward from Z to A. 9. (Practice) Write, run, and test a C++ program to find the value of 2n by using a for loop, where n is an integer value the user enters at the keyboard. (Hint: Initialize result = 1. Accumulate result = 2 * result.) 10. (Fluid Dynamics) Write a C++ program that uses a fixed-count loop of four. For each pass through the loop, enter a fluid’s viscosity and density from the following chart. Your program should then determine the kinematic viscosity for each fluid, using the following formula (see the Technical Note in Section 5.2 for a description of density and viscosity): Kinematic viscosity = viscosity / density Use the results output by your program to complete the last column in this chart: Fluid Viscosity at 40°C = 77°F (kg/ms) Density (kg/m3 ) Kinematic Viscosity (m2 /s) Gasoline .4466 × 10-3 .7186 × 103 Medium fuel oil 2.9922 × 10-3 .8496 × 103 Medium lubricating oil 87.0736 × 10-3 .8865 × 103 Water .8975 × 10-3 .9973 × 103 266 Repetition Statements
  • 287. 11. (Fluid Dynamics) Write a C++ program that calculates the Reynolds number for a pipe having a diameter of 0.1 meters, in which fluid flows at an average rate of .09 m/s. Your program should have a fixed-count loop of four and display both the calculated Reynolds number and the type of fluid flow—laminar, in-transition, or turbulent—for each fluid listed in the following chart, using the information provided after the chart. Use the results your program outputs to fill in the last two columns of this chart: Fluid Kinematic Viscosity (m2 /s) at 40°C Pipe Diameter (m) Avg. Fluid Speed (m/s) Reynolds Number Type of Flow Gasoline 6.215 × 10-7 0.1 .09 Medium fuel oil 3.523 × 10-6 0.1 .09 Medium lubricating oil 9.822 × 10-5 0.1 .09 Water 8.999 × 10-5 0.1 .09 The Reynolds number can be calculated by using this formula: Re = V d v Re is the Reynolds number. V is the average speed of the fluid (ft/sec or m/s). d is the pipe diameter (ft or m). ␯ is the kinematic viscosity (ft2 /sec or m2 /sec). For the determination of flow type, use these facts: Re < 2000: Fluid flow is smooth (laminar). 2000 ⱕ Re ⱖ 3000: Fluid flow is in transition. Re > 3000: Fluid flow is turbulent. 12. (Structural Eng.) The expansion of a steel bridge as it’s heated to a final Celsius tem- perature, TF, from an initial Celsius temperature, T0, can be approximated by using this formula: Increase in length = a × L × (TF - T0) a is the coefficient of expansion (which for steel is 11.7 × 10-6 ). L is the length of the bridge at temperature T0. Using this formula, write a C++ program that displays a table of expansion lengths for a steel bridge that’s 7365 meters long at 0 degrees Celsius, as the temperature increases to 40 degrees in 5-degree increments. 267 Chapter 5 for Loops
  • 288. 5.5 A Closer Look: Loop Programming Techniques This section discusses four common programming techniques associated with pretest (for and while) loops. All these techniques are common knowledge to experienced programmers. Technique 1: Interactive Input in a Loop In Section 5.2, you saw the effect of including a cin statement in a while loop. Entering data interactively in a loop is a general technique that’s equally applicable to for loops. For example, in Program 5.12, a cin statement is used to allow a user to interactively input a set of numbers. As each number is input, it’s added to a total. When the for loop is exited, the average is calculated and displayed. The for statement in Program 5.12 creates a loop that’s executed four times. The user is prompted to enter a number each time through the loop. After each number is entered, it’s added to the total immediately. Notice that total is initialized to 0 before the initializing list of the for statement is executed. The loop in Program 5.12 is executed as long as the value in count is less than 4 and is terminated when count becomes 4. (The increment to 4, in fact, is what causes the loop to end.) The output produced by Program 5.12 is essentially the same as Program 5.7. Program 5.12 #include <iostream> using namespace std; // This program calculates the average of MAXCOUNT user-entered numbers int main() { const int MAXCOUNT = 4; int count; double num, total, average; total = 0.0; for (count = 0; count < MAXCOUNT; count++) { cout << "Enter a number: "; cin >> num; total = total + num; } average = total / MAXCOUNT; cout << "The average of the data entered is " << average << endl; return 0; } 268 Repetition Statements
  • 289. Technique 2: Selection in a Loop Another common programming technique is to use a for or while loop to cycle through a set of numbers and select numbers meeting one or more criteria. For example, assume you want to find both the positive and negative sum of a set of numbers. The criterion is whether the number is positive or negative, and the logic for implementing this program is given by this pseudocode: While the loop condition is true Enter a number If the number is greater than zero add the number to the positive sum Else add the number to the negative sum Endif Endwhile Program 5.13 describes this algorithm in C++ for a fixed-count loop in which five numbers are to be entered. Program 5.13 #include <iostream> using namespace std; // This program computes the positive and negative sums of a set // of MAXNUMS user-entered numbers int main() { const int MAXNUMS = 5; int i; double usenum, positiveSum, negativeSum; positiveSum = 0; // this initialization can be done in the declaration negativeSum = 0; // this initialization can be done in the declaration for (i = 1; i <= MAXNUMS; i++) { cout << "Enter a number (positive or negative) : "; cin >> usenum; if (usenum > 0) positiveSum = positiveSum + usenum; else negativeSum = negativeSum + usenum; } 墌 269 Chapter 5 A Closer Look: Loop Programming Techniques
  • 290. cout << "The positive total is " << positiveSum << endl; cout << "The negative total is " << negativeSum << endl; return 0; } The following is a sample run of Program 5.13: Enter a number (positive or negative) : 10 Enter a number (positive or negative) : –10 Enter a number (positive or negative) : 5 Enter a number (positive or negative) : –7 Enter a number (positive or negative) : 11 The positive total is 26 The negative total is –17 Technique 3: Evaluating Functions of One Variable Loops can be constructed to give you a way to determine and display the values of a single variable mathematical function for a set of values over any specified interval. For example, you want to know the values of the following function for x between 2 and 6: y = 10x2 + 3x - 2 Assuming x has been declared as an integer variable, the following for loop can be used to calculate the required values: for (x = 2; x <= 6; x++) { y = 10 * pow(x,2.0) + 3 * x – 2; cout << setw(4) << x << setw(11) << y << endl; } In this loop, the variable x is used as both the counter variable and the unknown (independent variable) in the function. For each value of x from 2 to 6, a new value of y is calculated and displayed. This for loop is used in Program 5.14, which also prints headings for the displayed values. 270 Repetition Statements
  • 291. Program 5.14 #include <iostream> #include <iomanip> #include <cmath> using namespace std; int main() { int x, y; cout << "x value y valuen" << "------- --------n" for (x = 2; x <= 6; x++) { y = 10 * pow(x,2.0) + 3 * x – 2; cout << setw(4) << x << setw(11) << y << endl; } return 0; } The following is displayed when Program 5.14 is executed: x value y value ------- -------- 2 44 3 97 4 170 5 263 6 376 Two items are important here. First, any equation with one unknown can be evaluated by using a single for or an equivalent while loop. This method requires substituting your equation in the loop in place of the equation used in Program 5.14 and adjusting the counter values to match the solution range you want. Second, you’re not constrained to using integer values for the counter variable. For example, by specifying a non-integer increment, solutions for fractional values can be obtained. This technique is shown in Program 5.15, where the equation y = 10x2 + 3x - 2 is evaluated in the range x = 2 to x = 6 in increments of 0.5. 271 Chapter 5 A Closer Look: Loop Programming Techniques
  • 292. Program 5.15 #include <iostream> #include <iomanip> #include <cmath> using namespace std; int main() { double x, y; cout << "x value y valuen"; << "------- ---------n" cout << setiosflags(ios::fixed) << setiosflags(ios::showpoint) << setprecision(5); for (x = 2.0; x <= 6.0; x = x + 0.5) { y = 10.0 * pow(x,2.0) + 3.0 * x - 2.0; cout << setw(7) << x << setw(14) << y << endl; } return 0; } Notice that x and y have been declared as floating-point variables in Program 5.15 to allow these variables to take on fractional values. The following is the output this program produces: x value y value ------- --------- 2.00000 44.00000 2.50000 68.00000 3.00000 97.00000 3.50000 131.00000 4.00000 170.00000 4.50000 214.00000 5.00000 263.00000 5.50000 317.00000 6.00000 376.00000 272 Repetition Statements
  • 293. Technique 4: Interactive Loop Control Values used to control a loop can be set by using variables rather than constant values. For example, these four statements i = 5; j = 10; k = 1; for (count = i; count <= j; count = count + k) produce the same effect as this single statement: for (count = 5; count <= 10; count++) Similarly, these statements i = 5; j = 10; k = 1; count = i; while (count <= j) count = count + k; produce the same effect as the following while loop: count = 5; while (count <= 10) count++; The advantage of using variables in the initialization, condition, and altering expressions is that it allows you to assign values for these expressions outside the for or while statement. This method is especially useful when a cin statement is used to set the actual values. To make this technique a little more tangible, take a look at Program 5.16. 273 Chapter 5 A Closer Look: Loop Programming Techniques
  • 294. Program 5.16 #include <iostream> #include <iomanip> using namespace std; // this program displays a table of numbers with their squares and cubes, // starting from the number 1. The final number in the table is // input by the user. int main() { int num, final; cout << "Enter the final number for the table: "; cin >> final; cout << "NUMBER SQUARE CUBEn"; cout << "------ ------ ----n"; for (num = 1; num <= final; num++) cout << setw(3) << num << setw(8) << num*num << setw(7) << num*num*num << endl; return 0; } In Program 5.16, a variable is used in the for statement to control the condition (middle) expression. A cin statement has been placed before the loop to allow the user to decide what the final value should be. Notice that this arrangement permits the user to set the table’s size at runtime, instead of having the programmer set the table size at compile time. This arrangement also makes the program more general because it can be used to create a variety of tables without the need for reprogramming and recompiling. EXERCISES 5.5 1. (cin within a loop) Write and run a C++ program that accepts six Fahrenheit tempera- tures, one at a time, and converts each value entered to its Celsius equivalent before the next value is requested. Use a for loop in your program. The conversion required is Celsius = (5.0/9.0) × (Fahrenheit - 32). 274 Repetition Statements
  • 295. 2. (cin within a loop) Write and run a C++ program that accepts 10 values of gallons, one at a time, and converts each value entered to its liter equivalent before the next value is requested. Use a for loop in your program. Use the fact that 1 gallon = 3.785 liters. 3. (Interactive Loop Control) Modify the program written for Exercise 2 to initially request the number of data items to be entered and converted. 4. (Interactive Loop Control) Modify Program 5.13 so that the number of entries to be input is specified by the user when the program is executed. 5. (Selection) Modify Program 5.13 so that it displays the average of the positive and nega- tive numbers. (Hint: Be careful not to count the number 0 as a negative number.) Test your program by entering the numbers 17, -10, 19, 0, and -4. The positive average your program displays should be 18, and the negative average should be -7. 6. (Selection) a. Write a C++ program that selects and displays the maximum value of five numbers to be entered when the program is executed. (Hint: Use a for loop with both a cin and if statement inside the loop.) b. Modify the program written for Exercise 6a so that it displays both the maximum value and the position in the input set of numbers where the maximum occurs. 7. (Selection) Write a C++ program that selects and displays the first 20 integer numbers that are evenly divisible by 3. (Hint: Use the modulus operator, %.) 8. (Selection) A child’s parents promised to give the child $10 on her 12th birthday and double the gift on every subsequent birthday until the annual gift exceeded $1000. Write a C++ program to determine how old the child will be when the last amount is given and the total amount the child will have received. 9. (Mathematical Functions) Modify Program 5.15 to produce a table of y values for the following: a. y = 3x5 - 2x3 + x for x between 5 and 10 in increments of 0.2 b. y x x x x = + + + + 1 2 3 24 2 3 4 for x between 1 and 3 in increments of 0.1 c. y = 2e0.8t for t between 4 and 10 in increments of 0.2 10. (Mathematical Functions) A model of worldwide population, in billions of people, is given by this formula Population = 6.0e0.02t where t is the time in years (t = 0 represents January 2000 and t = 1 represents January 2001). Using this formula, write a C++ program that displays a yearly population table for the years January 2005 though January 2010. 11. (Mathematical Functions) The x and y coordinates, as a function of time, t, of a projec- tile fired with an initial velocity, v, at an angle of θ with respect to the ground, are given by these formulas: x = v t cos(θ ) y = v t sin(θ ) 275 Chapter 5 A Closer Look: Loop Programming Techniques
  • 296. Using these formulas, write a C++ program that displays a table of x and y values for a projectile fired with an initial velocity of 500 ft/sec at an angle of 22.8 degrees. (Hint: Remember to convert to radian measure.) The table should contain values corresponding to the time interval 0 to 10 seconds in increments of ½ seconds. 5.6 Nested Loops In many situations, using a loop within another loop, called a nested loop, is convenient. Here’s a simple example of a nested loop: for(i = 1; i <= 5; i++) // start of outer loop { cout << "ni is now " << i << endl; for(j = 1; j <= 4; j++) // start of inner loop cout << " j = " << j; // end of inner loop } // end of outer loop The first loop, controlled by the value of i, is called the outer loop. The second loop, controlled by the value of j, is called the inner loop. Notice that all statements in the inner loop are contained in the boundaries of the outer loop, and a different variable is used to control each loop. For each trip through the outer loop, the inner loop runs through its entire sequence. Therefore, each time the i counter increases by one, the inner for loop executes completely, and goes through four values (j takes on the values 1 to 4), as shown in Figure 5.9. Program 5.17 includes this type of loop in a working program. 276 Repetition Statements
  • 297. This is the output of a sample run of Program 5.17: i is now 1 j = 1 j = 2 j = 3 j = 4 i is now 2 j = 1 j = 2 j = 3 j = 4 i is now 3 j = 1 j = 2 j = 3 j = 4 i is now 4 j = 1 j = 2 j = 3 j = 4 i is now 5 j = 1 j = 2 j = 3 j = 4 inner loop inner loop inner loop i=3 i=2 i=1 j=1 j=2 j=3 j=4 j=4 j=3 j=2 j=1 j=4 j=3 j=2 j=1 Figure 5.9 For each i, j loops 277 Chapter 5 Nested Loops
  • 298. Program 5.17 #include <iostream> using namespace std; int main() { const int MAXI = 5; const int MAXJ = 4; int i, j; for(i = 1; i <= MAXI; i++) // start of outer loop <----+ { // | cout << "ni is now " << i << endl; // | // | for(j = 1; j <= MAXJ; j++) // start of inner loop | cout << " j = " << j; // end of inner loop | } // end of outer loop <-----+ cout << endl; return 0; } To understand the usefulness of a nested loop, take a look at using one to compute the average grade for each student in a class of 20 students. Each student has taken four exams during the semester. The final grade is calculated as the average of these exam grades. The pseudocode describing how to compute this average is as follows: for 20 times set the student grade total to zero for 4 times input a grade add the grade to the total endfor // end of inner for loop calculate student’s average grade print the student’s average grade endfor // end of outer for loop As described by the pseudocode, an outer loop consisting of 20 passes is used to compute the average grade for each student. The inner loop consists of four passes, and one examination grade is entered in each inner loop pass. As each grade is entered, it’s added to the total for the student, and at the end of the loop, the average is calculated and displayed. Because both the outer and inner loops are fixed-count loops of 20 and 4, respectively, for statements are used to create these loops. Program 5.18 shows the C++ code corresponding to the pseudocode. 278 Repetition Statements
  • 299. Program 5.18 #include <iostream> using namespace std; int main() { const int NUMGRADES = 4; const int NUMSTUDENTS = 20; int i, j; double grade, total, average; for (i = 1; i <= NUMSTUDENTS; i++) // start of outer loop { total = 0; // clear the total for this student for (j = 1; j <= NUMGRADES; j++) // start of inner loop { cout << "Enter an examination grade for this student: "; cin >> grade; total = total + grade; // add the grade to the total } // end of the inner for loop average = total / NUMGRADES; // calculate the average cout << "nThe average for student " << i << " is " << average << "nn"; } // end of the outer for loop return 0; } In reviewing Program 5.18, pay particular attention to the initialization of total in the outer loop, before the inner loop is entered: total is initialized 20 times, once for each student. Also, notice that the average is calculated and displayed immediately after the inner loop is finished. Because the statements that compute and display the average are also in the outer loop, 20 averages are calculated and displayed. The entry and addition of each grade in the inner loop uses techniques you have seen before and should be familiar with now. EXERCISES 5.6 1. (Misc. Application) Four experiments are performed, and each experiment has six test results. The results for each experiment are given in the following list. Write a program using a nested loop to compute and display the average of the test results for each experiment. 279 Chapter 5 Nested Loops
  • 300. 1st experiment results: 23.2 31 16.9 27 25.4 28.6 2nd experiment results: 34.8 45.2 27.9 36.8 33.4 39.4 3rd experiment results: 19.4 16.8 10.2 20.8 18.9 13.4 4th experiment results: 36.9 39 49.2 45.1 42.7 50.6 2. (Modify) a. Modify the program written for Exercise 1 so that the number of test results for each experiment is entered by the user. Write your program so that a different num- ber of test results can be entered for each experiment. b. Rewrite the program written for Exercise 2a to eliminate the inner loop. 3. (Electrical Eng.) a. An electrical manufacturer tests five generators by measuring their output voltages at three different times. Write a C++ program that uses a nested loop to enter each generator’s test results, and then computes and displays the average voltage for each generator. Assume the following generator test results: 1st generator: 122.5 122.7 123.0 2nd generator: 120.2 127.0 125.1 3rd generator: 121.7 124.9 126.0 4th generator: 122.9 123.8 126.7 5th generator: 121.5 124.7 122.6 b. Modify the program written for Exercise 3a to calculate and display the average volt- age for all the generators. (Hint: Use a second variable to store the total of all the gen- erator’s voltages.) 4. (Modify) Rewrite the program written for Exercise 3a to eliminate the inner loop. To do this, you have to input three voltages for each generator instead of entering one at a time. Each voltage must be stored in its own variable before the average is calculated. 5. (Mathematical Functions) Write a program that calculates and displays values for y when y = xz / (x - z) Your program should calculate y for values of x ranging between 1 and 5 and values of z ranging between 2 and 6. The x variable should control the outer loop and be incre- mented in steps of 1, and z should be incremented in steps of 1. Your program should also display the message Function Undefined when the x and z values are equal. 6. (Numerical Analysis) Assembly languages for some microprocessors don’t have a multi- ply operation. Although there are sophisticated algorithms for performing multiplication in these languages, a simple method multiplies by repeated addition. In this case, the algo- rithm’s efficiency can be increased by using nested loops. For example, to multiply a number by 12, first add the number three times, and then add the result four times. This calculation requires only 7 additions as opposed to 12. Using this information, write a C++ program that multiplies 33, 47, and 83 by 1001, using three loops, and then displays the result. (Hint: 1001 = 7 × 11 × 13.) 280 Repetition Statements
  • 301. 5.7 do while Loops Both while and for statements evaluate an expression at the start of the repetition loop, so they are always used to create pretest loops. Posttest loops, also referred to as exit-controlled loops, can also be constructed in C++. Figure 5.10 shows the basic structure of a posttest loop, which is referred to as a do while loop. Notice that a do while loop continues iterations through the loop while the condition is true and exits the loop when the condition is false. In C++, a posttest do while loop is created by using a do statement. As its name implies, this statement allows you to perform some statements before an expression is evaluated at the end of the loop. It has this general form in C++: do statement; while (expression); don’t forget the final semicolon, which is required here As with all C++ programs, the single statement in the do can be replaced with a compound statement. Figure 5.11 shows a flow-control diagram illustrating the operation of the do statement. As shown, all statements within the do statement are executed at least once before the expression is evaluated. Then, if the expression has a non-zero value, the statements are previous statement is the condition true? loop statements no yes next statement Figure 5.10 The do while loop structure 281 Chapter 5 do while Loops
  • 302. executed again. This process continues until the expression evaluates to zero (becomes false). For example, take a look at the following do statement: do { cout << "nEnter a price: "; cin >> price; if (abs(price – SENTINEL) < 0.0001) break; salestax = RATE * price; cout << setiosflags(ios::showpoint) << setprecision(2) << "The sales tax is $ " << salestax; } while (price != SENTINEL); Observe that the prompt and cin statement are included in the loop because the tested expression is evaluated at the end of the loop. evaluate the expression loop (false condition) expression’s value is non-zero (true condition) execute the statement after the word do enter the do statement expression’s value is zero exit the do statement go back and execute the statement Figure 5.11 The do statement’s flow of control 282 Repetition Statements
  • 303. As with all repetition statements, the do statement can always replace or be replaced by an equivalent while or for statement. The choice of which statement to use depends on the application and the programmer’s preferred style. In general, while and for statements are preferred because anyone reading the program can clearly see what’s being tested up front, at the top of the program loop. Validity Checks The do statement is particularly useful in filtering user-entered input and providing data validation checks. For example, an operator is required to enter a valid customer identifica- tion number between 1000 and 1999. A number outside this range is to be rejected, and a new request for a valid number is made. The following section of code provides the necessary data filter to verify the entry of a valid identification number: do { cout << "nEnter an identification number: "; cin >> id_num; } while (id_num < 1000 || id_num > 1999); In this code, a request for an identification number is repeated until a valid number is entered. This section of code is “bare bones,” in that it doesn’t alert the operator to the cause of the new request for data or allow premature exit from the loop if a valid identification number can’t be found. The following code is an alternative for removing the first drawback: do { cout << "nEnter an identification number: "; cin >> id_num; if (id_num < 1000 || id_num > 1999) { cout << "An invalid number was just enteredn"; cout << "Please check the ID number and reentern"; } else break; // break if a valid id_num was entered } while(1); // this expression is always true A break statement is used to exit from the loop. Because the expression the do statement is evaluating is always 1 (true), an infinite loop has been created that’s exited only when the break statement is encountered. EXERCISES 5.7 1. (Practice) a. Using a do statement, write a program to accept a grade. The program should request a grade continuously as long as an invalid grade is entered. An invalid 283 Chapter 5 do while Loops
  • 304. grade is any grade less than 0 or greater than 100. After a valid grade has been entered, your program should display the value of the grade entered. b. Modify the program written for Exercise 1a so that the user is alerted when an invalid grade has been entered. c. Modify the program written for Exercise 1b so that it allows the user to exit the pro- gram by entering the number 999. d. Modify the program written for Exercise 1b so that it automatically terminates after five invalid grades are entered. 2. (Misc. Application) a. Write a program that continuously requests a grade to be entered. If the grade is less than 0 or greater than 100, your program should print an appropriate message informing the user that an invalid grade has been entered; else, the grade should be added to a total. When a grade of 999 is entered, the program should exit the repeti- tion loop and compute and display the average of the valid grades entered. b. Run the program written in Exercise 2a on a computer and verify the program by using appropriate test data. 3. (Misc. Application) a. Write a program to reverse the digits of a positive integer number. For example, if the number 8735 is entered, the number displayed should be 5378. (Hint: Use a do statement and continuously strip off and display the number’s units digit. If the variable num initially contains the number entered, the units digit is obtained as (num % 10). After a units digit is displayed, dividing the number by 10 sets up the number for the next iteration. Therefore, (8735 % 10) is 5 and (8735 / 10) is 873. The do statement should continue as long as the remaining number is not zero. b. Run the program written in Exercise 3a on a computer and verify the program by using appropriate test data. 4. (Practice) Repeat any of the exercises in Section 5.3, using a do statement rather than a for statement. 5. (Numerical Analysis) Given a number, n, and an approximation for its square root, a closer approximation of the actual square root can be obtained by using this formula: new approximation n previous approximation = + ( / ) p previous approximation 2 Using this information, write a C++ program that prompts the user for a number and an initial guess at its square root. Using this input data, your program should calculate an approximation of the square root that’s accurate to 0.00001. (Hint: Stop the loop when the difference between the two approximations is less than 0.00001.) 6. (Numerical Analysis) Here’s a challenging problem for those who know a little calculus. The Newton-Raphson method can be used to find the roots of any equation y(x) = 0. In this method, the (i + 1)st approximation, xi+1, to a root of y(x) = 0 is given in terms of the ith approximation, xi, by the following formula, where y' denotes the derivative of y(x) with respect to x: xi+1 = xi - y(xi) / y'(xi) 284 Repetition Statements
  • 305. For example, if y(x) = 3x2 + 2x - 2, then y'(x) = 6x + 2, and the roots are found by making a reasonable guess for a first approximation x1 and iterating by using this equation: xi+1 = xi - (3xi 2 + 2xi - 2) / (6xi + 2) a. Using the Newton-Raphson method, find the two roots of the equation 3x2 + 2x - 2 = 0. (Hint: There’s one positive root and one negative root.) b. Extend the program written for Exercise 6a so that it finds the roots of any function y(x) = 0, when the function for y(x) and the derivative of y(x) are placed in the code. 5.8 Common Programming Errors When using repetition statements, beginning C++ programmers are prone to making the following seven errors: 1. The most troublesome error for new programmers is the “off by one” error, in which the loop executes one too many or one too few times than was intended. For example, the loop created by the statement for(i = 1; i < 11; i++) executes 10 times, not 11, even though the number 11 is used in the statement. An equivalent loop can be constructed by using the statement for(i = 1; i <= 10; i ++). However, if the loop is started with an initial value of i = 0, using the statement for(i = 0; i < 11; i++), the loop is traversed 11 times, as is a loop con- structed with the statement for(i = 0; i <= 10; i++). In constructing loops, you must pay particular attention to both the initial and final conditions used to control the loop to make sure the number of loop traversals isn’t off by one too many or one too few executions. The next two errors pertain to the tested expression, and you have already encountered them with the if and switch statements: 2. Inadvertently using the assignment operator, =, in place of the equality operator, ==, in the tested expression—for example, typing the assignment expression a = 5 instead of the correct relational expression a==5. Because the tested expression can be any valid C++ expression, including arithmetic and assignment expressions, the compiler doesn’t detect this error. 3. Using the equality operator, ==, when testing floating-point or double-precision operands. For example, the expression fnum == 0.01 should be replaced by a test requiring that the absolute value of fnum – 0.01 be less than an acceptable amount. The reason is that all numbers are stored in binary form. Using a finite number of bits, decimal numbers such as 0.01 have no exact binary equivalent, so tests requiring equality with these numbers can fail. (See Section 4.1 for a more complete description of this numerical accuracy problem.) The next three errors are particular to the for statement: 4. Placing a semicolon at the end of for’s parentheses, which frequently produces a do-nothing loop. For example, take a look at these statements: for(count = 0; count < 10; count++); total = total + num; 285 Chapter 5 Common Programming Errors
  • 306. The semicolon at the end of the first line of code is a null statement. It has the effect of creating a loop that’s executed 10 times with nothing done except incre- menting and testing count. This error tends to occur because C++ programmers are used to ending most lines with a semicolon. 5. Using commas are used to separate items in a for statement instead of the required semicolons, as in this example: for (count = 1, count < 10, count++) Commas must be used to separate items in the initializing and altering lists, but semicolons must be used to separate these lists from the tested expression. 6. Changing the value of the control variable used in the tested condition both inside the body of a for loop and in its altering list. For example, take a look at this for loop: for(int i=0; i<10; i++) cout << i++; In this code, the value of the variable being tested (in this case, i) is changed in two places, which is a serious logic error. 7. The final common programming error is omitting the final semicolon from the do statement. This error is usually made by programmers who have learned to omit the semicolon after the parentheses of a while statement and carry over this habit when encountering the reserved word while at the end of a do statement. 5.9 Chapter Summary 1. A section of repeating code is referred to as a loop. A loop is controlled by a repetition statement that tests a condition to determine whether the code will be executed. Each pass through the loop is referred to as a repetition or an iteration. The tested condition must always be set explicitly before its first evaluation by the repetition statement. Within the loop, there must always be a statement that permits altering the condition so that the loop, after it’s entered, can be exited. 2. There are three basic type of loops: while, for, and do while. The while and for loops are pretest or entrance-controlled loops. In this type of loop, the tested condition is evaluated at the beginning of the loop, which requires setting the tested condition explicitly before loop entry. If the condition is true, loop repetitions begin; otherwise, the loop is not entered. Iterations continue as long as the condition remains true. In C++, while and for loops are constructed by using while and for statements. The do while loop is a posttest or exit-controlled loop, in which the tested condition is evaluated at the end of the loop. This type of loop is always executed at least once. As long as the tested condition remains true, do while loops continue to execute. 3. Loops are also classified according to the type of tested condition. In a fixed-count loop, the condition is used to keep track of how many repetitions have occurred. In a variable-condition loop, the tested condition is based on a variable that can change interactively with each pass through the loop. 286 Repetition Statements
  • 307. 4. In C++, a while loop is constructed by using a while statement. This is the most commonly used form of this statement: while (expression) { statements; } The expression in parentheses is the condition that’s tested to determine whether the statement following the parentheses, which is generally a compound statement, is executed. The expression is evaluated in exactly the same manner as one in an if-else statement; the difference is how the expression is used. In a while statement, the statement following the expression is executed repeatedly as long as the expression retains a non-zero value, instead of just once, as in an if-else statement. An example of a while loop follows: count = 1; // initialize count while (count <= 10) { cout << count << " "; count++; // increment count } The first assignment statement sets count equal to 1. The while statement is then entered, and the expression is evaluated for the first time. Because the value of count is less than or equal to 10, the expression is true, and the compound statement is executed. The first statement in the compound statement uses the cout statement to display the value of count. The next statement adds 1 to the value currently stored in count, making this value equal to 2. The while statement then loops back to retest the expression. Because count is still less than or equal to 10, the compound statement is executed again. This process continues until the value of count reaches 11. Because the while statement always checks its expression at the top of the loop, any variables in the tested expression must have values assigned before the while is encountered. In addition, the while loop must contain a statement that alters the tested expression’s value. 5. In C++, a for loop is constructed by using a for statement. This statement performs the same functions as the while statement but uses a different form. In many situations, especially those using a fixed-count condition, the for statement format is easier to use than its while statement equivalent. This is the most commonly used form of the for statement: for (initializing list; expression; altering list) { statements; } 287 Chapter 5 Chapter Summary
  • 308. Inside the parentheses of the for statement are three items, separated by semicolons. Each of these items is optional, but the semicolons must be present. The initializing list is used to set any initial values before the loop is entered; generally, it’s used to initialize a counter. Statements in the initializing list are executed only once. The expression in the for statement is the condition being tested: It’s tested at the start of the loop and before each iteration. The altering list contains loop statements that aren’t within the compound statement; generally, it’s used to increment or decrement a counter each time the loop is executed. Multiple statements in both an initializing and altering list are separated by commas. Here’s an example of a for loop: for (total = 0, count = 1; count < 10; count++) { cout << "Enter a grade: "; total = total + grade; } In this for statement, the initializing list is used to initialize both total and count. The expression determines that the loop executes as long as the value in count is less than 10, and the altering list specifies that the value of count is incremented by one each time through the loop. 6. The for statement is extremely useful in creating fixed-count loops because you can include initializing statements, the tested expression, and statements affecting the tested expression in parentheses at the top of a for loop for easy inspection and modification. 7. The do statement is used to create posttest loops because it checks its expression at the end of the loop. Checking at the end of the loop ensures that the body of a do loop is executed at least once. A do loop must contain at least one statement that alters the tested expression’s value. Programming Projects for Chapter 5 1. (Probability) The probability that a telephone call will last less than t minutes can be approximated by the exponential probability function: Probability that a call lasts less than t minutes = 1 - e-t/a a is the average call length. e is Euler’s number (2.71828). For example, assuming the average call length is 2 minutes, the probability that a call will last less than 1 minute is calculated as 1 - e-1/2 = 0.3297. Using this probability equation, write a C++ program that calculates and displays a list of probabilities of a call lasting less than 1 minute to less than 10 minutes, in 1-minute increments. 2. (Probability) a. The arrival rate of customers in a busy New York bank can be estimated by using the Poisson probability function: P x e x x ( ) ! = λ λ - 288 Repetition Statements
  • 309. x is the number of customer arrivals per minute. l is the average number of arrivals per minute. e is Euler’s number (2.71828). For example, if the average number of customers entering the bank is three customers per minute, then l is equal to three. Therefore, the probability of one customer arriving in any one minute is P x e ( ) ! . = = = 1 3 1 0 149561 1 3 - and the probability of two customers arriving in any one minute is the following: P x e ( ) ! . = = = 2 3 2 0 224454 2 3 - Using the Poisson probability function, write a C++ program that calculates and displays the probability of 1 to 10 customer arrivals in any one minute when the average arrival rate is 3 customers per minute. b. The formula given in Exercise 2a is also applicable for estimating the arrival rate of planes at a busy airport. (In this situation, an arriving “customer” is an incoming plane.) Using this same formula, modify the program written in Exercise 2a to accept the average arrival rate as an input data item. Then run the modified program to determine the probability of 0 to 10 planes attempting to land at an airport in any one-minute period during peak arrival times. Assume that the average arrival rate for peak arrival times is two planes per minute. 3. (Physics) A golf ball is dropped from an airplane. The distance, d, the ball falls in t seconds is given by the formula d = ½ gt2 , where g is the acceleration caused by gravity and is equal to 32 ft/sec2 . Using this information, write and run a C++ program that displays the distance fallen in each one-second interval for 10 seconds and the total distance the golf ball falls at the end of each interval. The output should complete the following chart: Time (sec) Distance in the Current Time Interval (ft) Total Distance (ft) 0 0.0 1 16.0 . . . 10 4. (Physics) Assume the airplane in Exercise 3 is flying at a height of 50,000 feet. Modify the program written for Exercise 3 to determine how long it will take the ball to reach the ground. To increase the accuracy of your result without an undue number of calculations, decrease the time interval from 1 second to 0.1 second as the ball nears the ground. 5. (Numerical Analysis) The Fibonacci sequence is 0, 1, 1, 2, 3, 5, 8, 13, . . . ; the first two terms are 0 and 1, and each term thereafter is the sum of the two preceding terms—that is, Fib[n] = Fib[n - 1] + Fib[n - 2]. Using this information, write a C++ program that calculates the nth number in a Fibonacci sequence, where the user enters n into the program interactively. For example, if n = 6, the program should display the value 5. 289 Chapter 5 Programming Projects
  • 310. 6. (Numerical Analysis) Develop, test, and execute a C++ program that uses a while loop to determine the smallest integer power of 3 that exceeds 30,000. That is, find the smallest value of n so that 3n > 30,000. (Hint: Initialize PowerOfThree = 1, and then accumulate the expression PowerOfThree = 3 * PowerOfThree.) 7. (Numerical Analysis) A prime integer number is one that has exactly two different divisors, namely 1 and the number itself. Write, run, and test a C++ program that finds and prints all the prime numbers less than 100. (Hint: 1 is a prime number. For each number from 2 to 100, find Remainder = Number % n, where n ranges from 2 to sqrt(number). If n is greater than sqrt(number), the number is not equally divisible by n. Why? If any Remainder equals 0, the number is not a prime number.) 8. (Numerical Analysis) The quotient in long division is the number of times the divisor can be subtracted from the dividend. The remainder is what’s left over after the last subtraction. Write a C++ program that performs division by using this method. 9. (Conversion) Print the decimal, octal, and hexadecimal values of all characters between the start and stop characters entered by a user. For example, if the user enters an 'a' and a 'z', the program should print all the characters between a and z and their respective values. Make sure the second character the user enters occurs later in the alphabet than the first character. If it doesn’t, write a loop that asks the user repeatedly for a valid second character. 10. (Misc. Application) a. An old Arabian legend has it that a fabulously wealthy but unthinking king agreed to give a beggar one cent and double the amount for 64 days. Using this information, write, run, and test a C++ program that displays how much the king must pay the beggar on each day. The output of your program should appear as follows: Day Amount Owed --- ----------- 1 0.01 2 0.02 3 0.04 . . . . . . 64 . b. Modify the program you wrote for Exercise 10a to determine on which day the king will have paid the beggar a total of one million dollars. 11. (Misc. Application) According to legend, the island of Manhattan was purchased from the native Indian population in 1626 for $24. Assuming this money was invested in a Dutch bank paying 5% simple interest per year, construct a table showing how much money the native population would have at the end of each 50-year period, starting in 1626 and ending 400 years later. 290 Repetition Statements
  • 311. Engineering and Scientific Disciplines Industrial Engineering Each of the traditional engineering disciplines (civil, mechanical, electrical, chemical, and metallurgical/mining) relies on a particular area of natural science for its foundation. Indus- trial engineering, however, incorporates knowledge of the social sciences into designing improvements in human-machine systems. Industrial engineers are responsible for design- ing, installing, and evaluating machines and systems and for monitoring their interface with people to improve overall productivity. This job can also involve understanding human behavioral characteristics and their effects on the design of machines or the workplace. Industrial engineers draw heavily on knowledge in economics, business management, and finance as well as in the natural sciences. The areas of specialization for industrial engineers can be divided into four categories: 앫 Operations research: This area involves applying analytical techniques and math- ematical models to phenomena such as inventory control, simulation, decision theory, and queuing theory to optimize the total systems necessary for the production of goods. 앫 Management or administrative engineering: The increasingly complex interplay of management and production skills in modern industrial operations has resulted in a need for technically trained managers. These managers evaluate and plan corporate ventures and interact with labor, engineering departments, and subcontractors. A management engineer can also participate in a company’s financial operations, drawing on knowledge in economics, business management, and law. 앫 Manufacturing and production engineering: Before a product is produced, the complete manufacturing process must be designed and set up to optimize the economics involved and the product’s final quality. This task requires a broad knowledge of process design, plant layouts, tool design, robotics, and human- machine interactions. 앫 Information systems: This area involves using computers to gather and analyze data for decision making and planning and to improve human-machine interaction. The following list includes the most common responsibilities of industrial engineers who responded to a recent survey by the American Institute of Industrial Engineers: Facilities planning and design Cost control Methods engineering Inventory control Work systems design Energy conservation Production engineering Computerized process control Management information and Product packaging, handling, and testing control systems Tool and equipment selection Organization analysis and design Production control Work measurement Product improvement study Wage administration Preventive maintenance Quality control Safety programs Project management Training programs 291 Chapter 5 Programming Projects
  • 312. This page intentionally left blank
  • 313. Chapter 6 Modularity Using Functions 6.1 Function and Parameter Declarations 6.2 Returning a Single Value 6.3 Returning Multiple Values 6.4 A Case Study: Rectangular to Polar Coordinate Conversion 6.5 Variable Scope 6.6 Variable Storage Categories 6.7 Common Programming Errors 6.8 Chapter Summary Professional programs are designed, coded, and tested much like hardware: as a set of modules integrated to perform a completed whole. A good analogy is an automobile; one major module is the engine, another is the transmission, a third the braking system, a fourth the body, and so on. All these modules are linked together and placed under the driver’s control, which can be compared to a supervisor or main program module. The whole now operates as a complete unit, able to do useful work, such as driving to the store. During the assembly process, each module is constructed, tested, and found to be free of defects (bugs) before it’s installed in the final product. Now think of what you might do if you wanted to improve your car’s performance. You might alter the existing engine or remove it and replace it with a new engine, or you might replace the transmission. You can make each modification separately as your time and budget allow. The majority of the other modules can stay the same, but the car operates differently after your changes are made. In this analogy, each major car component can be compared to a function. For example, the driver calls on the engine when the gas pedal is pressed. The engine accepts inputs of fuel, air, and electricity to turn the driver’s request into a useful product—power—and then sends this output to the transmission for further processing. The transmission receives the engine’s output and converts it to a form the drive axle can use.
  • 314. The engine, transmission, and other modules “know” only the universe bounded by their inputs and outputs. The driver doesn’t need to know the internal operation of the modules being controlled. All that’s required is understanding what each unit does and how to use it. The driver simply “calls” on a module, such as the brakes, when that module’s output is required. Communication between modules is restricted to passing inputs to each module as it’s called on to perform its task, and each module operates in a fairly independent manner. Programmers use this same modular approach to create and maintain reliable C++ programs by using functions. As you have seen, each C++ program must contain a main() function. In addition to this required function, C++ programs can also contain any number of other functions. In this chapter, you learn how to write these functions, pass data to them, process the passed data, and return a result. 6.1 Function and Parameter Declarations In creating C++ functions, you must be concerned with the function itself and how it interacts with other functions, such as main(). Interaction with a function includes passing data to a function correctly when it’s called and returning values from a function when it ceases operation. This section describes the first part of the interface, passing data to a function and having the function receive, store, and process the transmitted data correctly. As you have already seen with mathematical functions, a function is called, or used, by giving the function’s name and passing any data to it, as arguments, in the parentheses following the function name (see Figure 6.1). The called function must be able to accept the data passed to it by the function doing the calling. Only after the called function receives the data successfully can the data be manipulated to produce a useful result. To clarify the process of sending and receiving data, take a look at Program 6.1, which calls a function named findMax(). The program, as shown, is not yet complete. After the function findMax() is written and included in Program 6.1, the completed program, consisting of the functions main() and findMax(), can be compiled and executed. function-name (data passed to function); This identifies the called function This passes data to the function Figure 6.1 Calling and passing data to a function 294 Modularity Using Functions
  • 315. Program 6.1 #include <iostream> using namespace std; void findMax(int, int); // the function declaration (prototype) int main() { int firstnum, secnum; cout << "nEnter a number: "; cin >> firstnum; cout << "Great! Please enter a second number: "; cin >> secnum; findMax(firstnum, secnum); // the function is called here return 0; } First, examine the declaration and calling of the findMax() function from main(). You then see how to write findMax() to accept data passed to it and determine the largest or maximum value of the two passed values. The function findMax() is referred to as the called function because it’s called or summoned into action by its reference in main(). The function that does the calling, in this case main(), is referred to as the calling function. The terms “called” and “calling” come from standard telephone usage, in which one party calls the other. The person initiating the call is referred to as the calling party, and the person receiving the call is referred to as the called party. The same terms describe function calls. The called function, in this case findMax(), is declared as a function that expects to receive two integer numbers and to return no value (a void) to main(). This declaration is formally referred to as a function prototype. The function is then called by the last statement in the program. Function Prototypes Before a function can be called, it must be declared to the function that will do the calling. The declaration statement for a function is referred to as a function prototype. The function prototype tells the calling function the type of value that will be formally returned, if any, and the data type and order of the values the calling function should transmit to the called function. For example, the function prototype previously used in Program 6.1 void findMax(int, int); 295 Chapter 6 Function and Parameter Declarations
  • 316. declares that the function findMax() expects two integer values to be sent to it and that this function formally returns no value (void). Function prototypes can be placed with the variable declaration statements of the calling function, above the calling function name (as in Program 6.1), or in a separate header file specified with an #include preprocessor statement. The function prototype for findMax() could have been placed before or after the statement #include <iostream>, before main(), or within main(). (The reasons for the choice of placement are explained in Section 6.3.) The general form of function prototype statements is as follows: returnDataType functionName(list of argument data types); The DataType refers to the type of value the function returns. Here are some examples of function prototypes: int fmax(int, int); double swap(int, char, char, double); void display(double, double); The function prototype for fmax() declares that this function expects to receive two integer arguments and returns an integer value. The function prototype for swap() declares that this function requires four arguments—consisting of an integer, two characters, and a double-precision argument, in that order—and returns a double-precision number. Finally, the function prototype for display() declares that this function requires two double- precision arguments and doesn’t return any value. This function might be used to display the results of a computation without returning any value to the called function. The use of function prototypes permits the compiler to error-check data types. If the function prototype doesn’t agree with data types defined when the function is written, a compiler warning occurs. The prototype also serves another task: It ensures that all arguments passed to the function are converted to the declared data type when the function is called. Calling a Function Calling a function is rather easy. The only requirements are using the name of the function and enclosing any data passed to the function in the parentheses following the function name, using the same order and type declared in the function prototype. The items enclosed in parentheses are called arguments of the called function (see Figure 6.2). If a variable is one of the arguments in a function call, the called function receives a copy of the value stored in the variable. For example, the statement findMax(firstnum, secnum); calls the findMax() function and causes the values stored in the variables firstnum and secnum to be passed to findMax(). The variable names in parentheses are arguments that provide values to the called function. After values are passed, control is transferred to the called function. findMax (firstnum, secnum); This identifies the findMax() function This causes two values to be passed to findMax() Figure 6.2 Calling and passing two values to findMax() 296 Modularity Using Functions
  • 317. As illustrated in Figure 6.3, the findMax() function does not receive the variables named firstnum and secnum and has no knowledge of these variable names.1 The function simply receives the values in these variables and must then determine where to store these values before it does anything else. Although this procedure for passing data to a function might seem surprising, it’s actually a safety procedure for ensuring that a called function doesn’t inadvertently change data stored in a variable. The function gets a copy of the data to use. It can change its copy and, of course, change any variables declared within it. However, unless specific steps to do so are taken, a function isn’t allowed to change the contents of variables declared in other functions. Next, you begin writing the findMax() function to process the values passed to it. Defining a Function A function is defined when it’s written. Each function is defined once (that is, written once) in a program and can then be used by any other function in the program that declares it suitably. Like the main() function, every C++ function consists of two parts, a function header and a function body, as illustrated in Figure 6.4. The function header’s purpose is to identify the data type of the value the function returns, provide the function with a name, and specify the number, order, and type of arguments the function expects. The function body’s purpose is to operate on the passed data and return, at most, one value directly back to the calling function. (In Section 6.3, you see how a function can be made to return multiple values indirectly.) 1 In Section 6.3, you see how C++ also permits direct access to the calling function’s variables with reference variables. findMax (firstnum, secnum); Get the value stored in secnum a value Get the value stored in firstnum a value Send the value to findMax() Send the value to findMax() the variable secnum the variable firstnum Figure 6.3 The findMax() function receives actual values 297 Chapter 6 Function and Parameter Declarations
  • 318. The function header is always the first line of a function and contains the function’s returned value type, its name, and the names and data types of its parameters. Because findMax() doesn’t formally return any value and receives two integer values, the following function header can be used: void findMax(int x, int y) no semicolon The names in parentheses in the header are called the formal parameters of the function (or parameters, for short).2 Therefore, the parameter x is used to store the first value passed to findMax(), and the parameter y is used to store the second value passed at the time of the function call. The function doesn’t know where the values come from when the call is made from main(). The first part of the call procedure the computer executes involves going to the variables firstnum and secnum and retrieving the stored values. These values are then passed to findMax() and stored in the parameters x and y (see Figure 6.5). 2 The portion of the function header containing function names and parameters is formally referred to as a “function declarator.” The items enclosed in parentheses, the parameters, are specifications for the arguments. The arguments are the values provided when the function is called. function header line { } Function header Function body constant and any other C++ statements; variable declarations; Figure 6.4 The general format of a function findMax(int x, int y) findMax(firstnum,secnum); This statement calls findMax() The value in secnum is passed The value in firstnum is passed The parameter named x The parameter named y Figure 6.5 Storing values in parameters 298 Modularity Using Functions
  • 319. The function name and all parameter names in the header—in this case, findMax, x, and y—are chosen by the programmer. Any names selected according to the rules for choosing variable names can be used. All parameters listed in the function header must be separated by commas and have their data types declared separately. Now that the function header for findMax() has been written, you can construct its body. The function has been written to select and display the larger of the two numbers passed to it. A function body begins with an opening brace, {, contains any necessary declarations and other C++ statements, and ends with a closing brace, }. This structure should be familiar because it’s the same one used in all the main() functions you’ve seen so far. This required structure shouldn’t be a surprise because main() is a function and must adhere to the rules for constructing all legitimate functions, as shown here: { symbolic constant declarations, variable declarations, and other C++ statements } Point of Information Function Definitions and Function Prototypes When you write a function, you’re formally creating a function definition. Each defini- tion begins with a function header that includes a parameter list, if any, enclosed in parentheses and ends with the closing brace that terminates the function’s body. The parentheses are required whether or not the function uses any parameters. The follow- ing is a commonly used syntax for a function definition: returnDataType functionName(parameter list) { constant declarations variable declarations other C++ statements return value } A function prototype declares a function. The syntax for a function prototype, which provides the function’s return data type, the function’s name, and the function’s parameter list, is as follows: returnDataType functionName(list of parameter data types); The prototype, along with pre- and postcondition comments (see the next Point of Information box), should give users all the programming information needed to call the function successfully. Generally, all function prototypes are placed at the top of the program, and all definitions are placed after the main() function. However, this placement can be changed. The only requirement in C++ is that a function can’t be called before it has been declared or defined. 299 Chapter 6 Function and Parameter Declarations
  • 320. In the body of the findMax() function, one variable is declared to store the maximum of the two numbers passed to it. An if-else statement is then used to find the maximum of the two numbers. Finally, a cout statement is used to display the maximum. The following shows the complete function definition for findMax(): void findMax(int x, int y) { // start of function body int maxnum; // variable declaration if (x >= y) // find the maximum number maxnum = x; else maxnum = y; cout << "nThe maximum of the two numbers is " << maxnum << endl; return; } // end of function body and end of function Notice that the parameter declarations are made in the function header, and the variable declaration is made immediately after the function body’s opening brace. This placement is in keeping with the concept that parameter values are passed to a function from outside the function, and variables are declared and assigned values from within the function body. Program 6.2 includes the findMax() function in the program code previously listed in Program 6.1. Point of Information Preconditions and Postconditions Preconditions are any set of conditions a function requires to be true if it’s to operate correctly. For example, if a function uses the symbolic constant MAXCHARS, which must have a positive value, a precondition is that MAXCHARS must be declared with a posi- tive value before the function is called. Similarly, a postcondition is a condition that will be true after the function is executed, assuming the preconditions are met. Pre- and postconditions are typically documented as user comments. For example, examine the following declaration and comments: bool leapyr(int) // Precondition: the integers must represent a year in a four-digit // form, such as 2009 // Postcondition: a value of true is returned if the year is a leap year; // otherwise, false is returned Pre- and postcondition comments should be included with function prototypes and function definitions whenever clarification is needed. 300 Modularity Using Functions
  • 321. Program 6.2 #include <iostream> using namespace std; void findMax(int, int); // the function prototype int main() { int firstnum, secnum; cout << "nEnter a number: "; cin >> firstnum; cout << "Great! Please enter a second number: "; cin >> secnum; findMax(firstnum, secnum); // the function is called here return 0; } // following is the function FindMax() void findMax(int x, int y) { // start of function body int maxnum; // variable declaration if (x >= y) // find the maximum number maxnum = x; else maxnum = y; cout << "nThe maximum of the two numbers is " << maxnum << endl; return; } // end of function body and end of function Program 6.2 can be used to select and print the maximum of any two integer numbers the user enters. A sample run of Program 6.2 follows: Enter a number: 25 Great! Please enter a second number: 5 The maximum of the two numbers is 25 301 Chapter 6 Function and Parameter Declarations
  • 322. The placement of the findMax() function after the main() function in Program 6.2 is a matter of choice. Usually, main() is listed first because it’s the driver function that gives anyone reading the program an idea of what the complete program is about before encountering the details of each function. In no case, however, can the definition of findMax() be placed inside main(). This rule applies to all C++ functions, which must be defined by themselves outside any other function. Each C++ function is a separate and independent entity with its own parameters and variables; nesting functions is never permitted. Placement of Statements C++ doesn’t impose a rigid statement-ordering structure on programmers. The general rule for placing statements in a C++ program is simply that all preprocessor directives, named constants, variables, and functions must be declared or defined before they can be used. As noted previously, although this rule permits placing both preprocessor directives and declaration statements throughout a program, doing so results in poor program structure. As a matter of good programming form, the following statement ordering should form the basic structure around which all C++ programs are constructed: preprocessor directives function prototypes int main() { // symbolic constants // variable declarations // other executable statements // return statement } // function definitions As always, comment statements can be intermixed anywhere in this basic structure. Function Stubs An alternative to completing each function required in a complete program is writing the main() function first and then adding the remaining functions as they’re developed. 302 Modularity Using Functions
  • 323. The problem with this approach, however, is the same one that occurred with Program 6.1: The program can’t be run until all the functions are included. For convenience, the code for Program 6.1 has been reproduced here: #include <iostream> using namespace std; void findMax(int, int); // the function declaration (prototype) int main() { int firstnum, secnum; cout << "nEnter a number: "; cin >> firstnum; cout << "Great! Please enter a second number: "; cin >> secnum; findMax(firstnum, secnum); // the function is called here return 0; } This program would be complete if there were a function definition for findMax(). However, you really don’t need a correct findMax() function to test and run what has been written; you just need a function that acts like it is. A “fake” findMax() that accepts the correct number and types of parameters and returns values of the proper form for the function call is all you need for initial testing. This fake function, called a stub, is the beginning of a final function and can be used as a placeholder for the final unit until the unit is completed. A stub for findMax() is as follows: void findMax(int x, int y) { cout << "In findMax()n"; cout << "The value of x is " << x << endl; cout << "The value of x is " << y << endl; } This stub function can now be compiled and linked with the previously completed code to produce an executable program. The code for the function can then be further developed with the “real” code when it’s completed, replacing the stub portion. The minimum requirement of a stub function is that it compiles and links with its calling module. In practice, it’s a good idea to have a stub display a message that it has been entered successfully and display the values of its received parameters, as in the stub for findMax(). As the function is refined, you let it do more, perhaps allowing it to return intermediate or incomplete results. This incremental, or stepwise, refinement is an important concept in efficient program development that gives you the means to run a program that doesn’t yet meet all its final requirements. Functions with Empty Parameter Lists Although useful functions having an empty parameter list are extremely limited, they can occur. (You see one such function in Exercise 11 at the end of this section.) The function 303 Chapter 6 Function and Parameter Declarations
  • 324. prototype for such a function requires writing the keyword void or nothing at all between the parentheses following the function’s name. For example, both these prototypes int display(); and int display(void); indicate that the display() function takes no parameters and returns an integer. A function with an empty parameter list is called by its name with nothing written inside the required parentheses following the function’s name. For example, the statement display(); correctly calls the display() function, whose prototype is shown in the preceding example. Point of Information Isolation Testing One of the most successful software testing methods is to embed the code being tested in an environment of working code. For example, you have two untested func- tions called in the following order, and the result the second function returns is incorrect: function 1 calls function 2 Returned value is incorrect From the information shown in this figure, one or possibly both of the functions could be operating incorrectly. The first order of business is to isolate the problem to a specific function. One powerful method of performing this code isolation is to decouple the functions. You do this by testing each function separately or by testing one function first and, only after you know it’s operating correctly, reconnecting it to the second function. Then, if an error occurs, you have isolated the error to the transfer of data between functions or the internal operation of the second function. This procedure is an example of the basic rule of testing, which states that each function should be tested only in a program in which all other functions are known to be correct. This rule means one function must first be tested by itself, using stubs if necessary for any called functions, and a second tested function should be tested by itself or with a previously tested function, and so on. This testing procedure ensures that each new function is isolated in a test bed of correct functions, with the final pro- gram built from tested function code. 304 Modularity Using Functions
  • 325. Default Arguments3 C++ provides default arguments in a function call for added flexibility. The primary use of default arguments is to extend the parameter list of existing functions without requiring any change in the calling parameter lists already used in a program. Default argument values are listed in the function prototype and transmitted automati- cally to the called function when the corresponding arguments are omitted from the function call. For example, the function prototype void example(int, int = 5, double = 6.78); provides default values for the last two arguments. If any argument is omitted when the function is actually called, the C++ compiler supplies the default values. Therefore, all the following function calls are valid: example(7, 2, 9.3) // no defaults used example(7, 2) // same as example(7, 2, 6.78) example(7) // same as example(7, 5, 6.78) Four rules must be followed when using default arguments. First, default values should be assigned in the function prototype.4 Second, if any parameter is given a default value in the function prototype, all parameters following it must also be supplied with default values. Third, if one argument is omitted in the actual function call, all arguments to its right must also be omitted. The second and third rules make it clear to the C++ compiler which arguments are being omitted and permits the compiler to supply correct default values for the missing arguments, starting with the rightmost argument and working in toward the left. Fourth, the default value used in the function prototype can be an expression consisting of both constants and previously declared variables. If this kind of expression is used, it must pass the compiler’s check for validly declared variables, even though the expression’s actual value is evaluated and assigned at runtime. Default arguments are extremely useful when extending an existing function to include more features that require additional arguments. Adding new arguments to the right of the existing arguments and giving each new argument a default value permits all existing function calls to remain as they are. In this way, the effect of the changes are conveniently isolated from existing code in the program. Reusing Function Names (Overloading)5 C++ provides the capability of using the same function name for more than one function, referred to as function overloading. The only requirement for creating more than one function with the same name is that the compiler must be able to determine which function to use based on the parameters’ data types (not the data type of the return value, if any). For example, take a look at the three following functions, all named cdabs(): void cdabs(int x) // compute and display the absolute value of an integer { if ( x < 0 ) x = -x; 墌 3 This topic can be omitted on first reading without loss of subject continuity. 4 Some compilers accept default assignments in the function definition. 5 This topic can be omitted on first reading without loss of subject continuity. 305 Chapter 6 Function and Parameter Declarations
  • 326. cout << "The absolute value of the integer is " << x << endl; } void cdabs(float x) // compute and display the absolute value of a float { if ( x < 0 ) x = -x; cout << "The absolute value of the float is " << x << endl; } void cdabs(double x) // compute and display the absolute value of a double { if ( x < 0 ) x = -x; cout << "The absolute value of the double is " << x << endl; } Which of the three functions named cdabs() is actually called depends on the argument type supplied at the time of the call. Therefore, the function call cdabs(10); causes the compiler to use the function named cdabs() that expects an integer argument, and the function call cdabs(6.28f); causes the compiler to use the function named cdabs() that uses a single-precision argument.6 Notice that overloading a function’s name simply means using the same name for more than one function. Each function that uses the name must still be written and exists as a separate entity. The use of the same function name doesn’t require code in the functions to be similar, although good programming practice dictates that functions with the same name should perform essentially the same operations. All that’s required to use the same function name is that the compiler can distinguish which function to select, based on the data types of the arguments when the function is called. However, if the only difference in the overloaded functions is the argument types, a better programming solution is to create a function template, discussed next. The use of overloaded functions, however, is extremely useful with constructor functions, explained in Section 10.2. Function Templates7 In most high-level languages, including C++’s immediate predecessor, C, each function requires its own unique name. In theory, using unique names makes sense, but in practice, it can lead to a profusion of function names, even for functions that perform essentially the same operations. For example, consider determining and displaying a number’s absolute value. If the number passed to the function can be an integer, a single-precision value, or a double-precision value, three distinct functions must be written to handle each case correctly. 6 Selection of the correct function is accomplished by a process called “name mangling.” Using this process, the function name the C++ compiler actually generates differs from the function name used in the source code. The compiler appends information to the source code function, depending on the type of data being passed, and the resulting name is said to be a “mangled” version of the source code name. 7 This topic can be omitted on first reading without loss of subject continuity. 306 Modularity Using Functions
  • 327. Certainly, you could give each function a unique name, such as abs(), fabs(), and dabs(), having the following function prototypes: void abs(int); void fabs(float); void dabs(double); Each of these functions performs essentially the same operation but on different parameter data types. A much cleaner solution is writing a general function that handles all cases, but the compiler can set parameters, variables, and even return type based on the actual function call. You can write this type of function in C++ by using function templates. A function template is a single, complete function that serves as a model for a family of functions. The function from the family that’s actually created depends on subsequent function calls. To make this concept more concrete, take a look at a function template that computes and displays the absolute value of a passed argument: template <class T> void showabs(T number) { if (number < 0) number = -number; cout << "The absolute value of the number " << " is " << number << endl; return; } For the moment, ignore the first line, template <class T>, and look at the second line, which consists of the function header void showabs(T number). Notice that this function header has the same syntax used for all function definitions, except the T where a data type is usually placed. For example, if the function header were void showabs(int number), you should recognize it as a function named showabs() that expects one integer argument to be passed to it and returns no value. Similarly, if the function header were void showabs(double number), you should recognize it as a function that expects one double-precision argument to be passed to it when the function is called. The advantage of using the T in the function template header is that it represents a general data type that’s replaced by an actual data type, such as int, float, double, and so forth, when the compiler encounters an actual function call. For example, if a function call with an integer argument is encountered, the compiler uses the function template to construct a function that expects an integer parameter. Similarly, if a call is made with a double-precision argument, the compiler constructs a function that expects a double- precision parameter. As a specific example, take a look at Program 6.3. 307 Chapter 6 Function and Parameter Declarations
  • 328. Program 6.3 #include <iostream> using namespace std; template <class T> void showabs(T number) { if (number < 0) number = -number; cout << "The absolute value of the number is " << number << endl; return; } int main() { int num1 = -4; float num2 = -4.23f; double num3 = -4.23456; showabs(num1); showabs(num2); showabs(num3); return 0; } Notice the three function calls made in the main() function; they call the function showabs() with an integer, float, and double value. Now review the function template for showabs() and look at the first line, template <class T>. This line, called a template prefix, is used to inform the compiler that the function immediately following is a template using a data type named T. In the function template, the T is used in the same manner as any other data type, such as int, float, and double. When the compiler encounters an actual function call for showabs(), the data type of the argument passed in the call is substituted for T throughout the function. In effect, the compiler creates a specific function, using the template, that expects the argument type in the call. Because Program 6.3 makes three calls to showabs(), each with a different argument data type, the compiler creates three separate showabs() functions. The compiler knows which function to use based on the arguments passed at the time of the call. This is the output displayed when Program 6.3 runs: The absolute value of the number is 4 The absolute value of the number is 4.23 The absolute value of the number is 4.23456 308 Modularity Using Functions
  • 329. The letter T used in the template prefix template <class T> is simply a placeholder for a data type that’s defined when the function is actually called. Any letter or non-keyword identifier can be used instead, so the showabs() function template could just as well have been defined as follows: template <class DTYPE> void abs(DTYPE number) { if (number < 0) number = -number; cout << "The absolute value of the number is " << number << endl; return; } In this regard, sometimes it’s simpler and clearer to read the word class in the template prefix as the words data type. With this substitution, you can read the template prefix template <class T> as “I’m defining a function template that has a data type named T.” Then, in the defined function’s header and body, the data type T (or any other letter or identifier defined in the prefix) is used in the same manner as any built-in data type, such as int, float, and double. Now suppose you want to create a function template to include both a return type and an internally declared variable. For example, take a look the following function template: template <class T> // template prefix T abs(T value) // function header line { T absnum; // variable declaration if (value < 0) absnum = -value; else absnum = value; return absnum; } In this template definition, the date type T is used to declare three items: the return type of the function, the data type of a single function parameter named value, and one variable declared in the function. Program 6.4 shows how this function template could be used in the context of a complete program. 309 Chapter 6 Function and Parameter Declarations
  • 330. Program 6.4 #include <iostream> using namespace std; template <class T> // template prefix T abs(T value) // header line { T absnum; // variable declaration if (value < 0) absnum = -value; else absnum = value; return absnum; } int main() { int num1 = -4; float num2 = -4.23f; double num3 = -4.23456; cout << "The absolute value of " << num1 << " is " << abs(num1) << endl; cout << "The absolute value of " << num2 << " is " << abs(num2) << endl; cout << "The absolute value of " << num3 << " is " << abs(num3) << endl; return 0; } In the first call to abs() made within main(), an integer value is passed as an argument. In this case, the compiler substitutes an int data type for the T data type in the function template and creates the following function: int abs(int value) // header line { int absnum; // variable declaration if (value < 0) absnum = -value; else absnum = value; return absnum; } 310 Modularity Using Functions
  • 331. Similarly, in the second and third function calls, the compiler creates two more functions: one in which the data type T is replaced by the keyword float, and one in which the data type T is replaced by the keyword double. This is the output produced by Program 6.4: The absolute value of -4 is 4 The absolute value of -4.23 is 4.23 The absolute value of -4.23456 is 4.23456 The value of using a function template is that one function definition has been used to create three different functions, each of which uses the same logic and operations but operates on different data types. Finally, although both Programs 6.3 and 6.4 define a function template using a single placeholder data type, function templates with more than one data type can be defined. For example, the template prefix template <class DTYPE1, class DTYPE2, class DTYPE3> can be used to create a function template requiring three different data types. As before, in the function template’s header and body, the data types DTYPE1, DTYPE2, and DTYPE3 are used in the same manner as any built-in data type, such as int, float, and double. Also, as noted previously, the names DTYPE1, DTYPE2, and DTYPE3 can be any non-keyword identifier. Conventionally, the letter T followed by zero or more digits is used, such as T, T1, T2, T3, and so forth. EXERCISES 6.1 1. (Practice) For the following function headers, determine the number, type, and order (sequence) of the values that must be passed to the function: a. void factorial(int n) b. void volts(int res, double induct, double cap) c. void power(int type, double induct, double cap) d. void flag(char type, double current, double time) e. void total(double amount, double rate) f. void roi(int a, int b, char c, char d, double e, double f) g. void getVal(int item, int iter, char decflag, char delim) 2. (Practice) a. Write a function named check() that has three parameters. The first parameter should accept an integer number, and the second and third parameters should accept a double-precision number. The function body should just display the values of data passed to the function when it’s called. (Note: When tracing errors in functions, hav- ing the function display values it has been passed is helpful. Quite often, the error isn’t in what the function body does with data, but in the data received and stored.) 311 Chapter 6 Function and Parameter Declarations
  • 332. b. Include the function written in Exercise 2a in a working program. Make sure your function is called from main(). Test the function by passing various data to it. 3. (Practice) a. Write a function named findAbs() that accepts a double-precision num- ber passed to it, computes its absolute value, and displays the absolute value. A number’s absolute value is the number itself if the number is positive and the negative of the num- ber if the number is negative. b. Include the function written in Exercise 3a in a working program. Make sure your function is called from main(). Test the function by passing various data to it. 4. (Practice) a. Write a function called mult() that accepts two floating-point numbers as parameters, multiplies these two numbers, and displays the result. b. Include the function written in Exercise 4a in a working program. Make sure your function is called from main(). Test the function by passing various data to it. 5. (Practice) a. Write a function named sqrIt() that computes the square of the value passed to it and displays the result. The function should be capable of squaring numbers with decimal points. b. Include the function written in Exercise 5a in a working program. Make sure your function is called from main(). Test the function by passing various data to it. 6. (Practice) a. Write a function named powfun() that raises an integer number passed to it to a positive integer power and displays the result. The positive integer should be the second value passed to the function. Declare the variable used to store the result as a long-integer data type to ensure enough storage for the result. b. Include the function written in Exercise 6a in a working program. Make sure your function is called from main(). Test the function by passing various data to it. 7. (Numerical) a. Write a C++ program that computes and displays the fractional part of any user-entered number. For example, if the number 256.879 is entered, the number 0.879 should be displayed. (Hint: Use an int cast.) b. Enter, compile, and execute the program written for Exercise 7a. 8. (Numerical) a. Write a C++ program that accepts an integer argument and determines whether the passed integer is even or odd. (Hint: Use the % operator.) b. Enter, compile, and execute the program written for Exercise 8a. 9. (Practice) a. Write a function that produces a table of the numbers from 1 to 10, their squares, and their cubes. The function should produce the same display as Program 5.11. b. Include the function written in Exercise 9a in a working program. Make sure your function is called from main(). Test the function by passing various data to it. 10. (Modify) a. Modify the function written for Exercise 9a to accept the starting value of the table, the number of values to be displayed, and the increment between values. If the incre- ment isn’t sent explicitly, the function should use a default value of 1. Name your function selTab(). A call to selTab(6,5,2); should produce a table of five lines, the first line starting with the number 6 and each succeeding number increasing by 2. b. Include the function written in Exercise 10a in a working program. Make sure your function is called from main(). Test the function by passing various data to it. 312 Modularity Using Functions
  • 333. 11. (Numerical) A useful function using no parameters can be constructed to return a value for ␲ that’s accurate to the maximum number of decimal places your computer allows. This value is obtained by taking the arcsine of 1.0, which is ␲ / 2, and multiplying the result by 2. In C++, the required expression is 2.0 * asin(1.0); the asin() func- tion is provided in the standard C++ mathematics library. (Remember to include cmath in your preprocessor directives.) Using this expression, write a C++ function named pi() that calculates and displays the value of ␲. (In the next section, you see how to return this value to the calling function.) 12. (Practice) a. Write a function template named display() that displays the value of the single argument passed to it when the function is called. b. Include the function template created in Exercise 12a in a complete C++ program that calls the function three times: once with a character argument, once with an integer argument, and once with a double-precision argument. 13. (Numerical) a. Write a function template named whole() that returns the integer value of any argument passed to it when the function is called. b. Include the function template created in Exercise 13a in a complete C++ program that calls the function three times: once with a character argument, once with an integer argument, and once with a double-precision argument. 14. (Numerical) a. Write a function template named maximum() that returns the maxi- mum value of three arguments passed to the function when it’s called. Assume that all three arguments are the same data type. b. Include the function template created for Exercise 14a in a complete C++ program that calls the function with three integers and then with three double-precision numbers. 15. (Numerical) a. Write a function template named square() that computes and returns the square of the single argument passed to the function when it’s called. b. Include the function template created for Exercise 15a in a complete C++ program. 6.2 Returning a Single Value Using the method of passing data to a function explained in the previous section, the called function receives only copies of the values contained in arguments at the time of the call. (Review Figure 6.3 if it’s unclear to you.) When a value is passed to a called function in this manner, the passed argument is referred to as a passed by value and is a distinct advantage of C++.8 Because the called function doesn’t have direct access to the variables used as arguments by the calling function, it can’t inadvertently alter the value stored in one of these variables. The function receiving the passed by value arguments can process the values sent to it in any fashion and return one, and only one, “legitimate” value directly to the calling function (see Figure 6.6). In this section, you see how this value is returned to the calling function. As you 8 This argument is also referred to as a “call by value.” These terms, however, don’t refer to the function call as a whole, but to how the calling function passes values to the called function. 313 Chapter 6 Returning a Single Value
  • 334. might expect, given C++’s flexibility, there’s a way of returning more than a single value, but that’s the topic of the next section. As with calling a function, returning a value directly requires handling the interface between the called and calling functions correctly. From its side of the return transaction, the called function must provide the following items: • The data type of the returned value • The actual value being returned A function returning a value must specify, in its header, the data type of the value to be returned. Recall that the function header includes both the function name and a parameter list. For example, the findMax() function written previously determines the maximum value of two numbers passed to it. For convenience, the findMax() code is listed again: void findMax(int x, int y) { // start of function body int maxnum; // variable declaration if (x >= y) // find the maximum number maxnum = x; else maxnum = y; cout << "nThe maximum of the two numbers is " << maxnum << endl; return; } // end of function body and end of function In this function header, x and y are the names chosen for the function’s parameters: void findMax(int x, int y) If findMax() is to return a value, its function header must be amended to include the data type of the value being returned. For example, if an integer value is to be returned, this is the correct function header: int findMax(int x, int y) A function can receive many values Only one value can be directly returned Figure 6.6 A function directly returns at most one value 314 Modularity Using Functions
  • 335. Similarly, if the function is to receive two single-precision parameters and return a single-precision value, this is the correct function header: float findMax(float x, float y) If the function is to receive two double-precision parameters and return a double- precision value, the function header would be the following:9 double findMax(double x, double y) Now see how to modify the findMax() function to return the maximum value of the two numbers passed to it. To do this, you must first determine the data type of the value to be returned and include this data type in the function header. Because the maximum value determined by findMax() is stored in the integer variable maxnum, the function should return this variable’s value. Returning an integer value from findMax() requires the following function declaration: int findMax(int x, int y) Observe that it’s the same as the original function header for findMax(), with the keyword int substituted for the keyword void. Having declared the data type that findMax() will return, all that remains is including a statement in the function to cause the return of the correct value. To return a value, a function must use a return statement, which has this form:10 return expression; When the return statement is encountered, the expression is evaluated first. The value of the expression is then automatically converted to the data type declared in the function header before being sent back to the calling function. After the value is returned, program control reverts to the calling function. Therefore, to return the value stored in maxnum, all you need to do is include the statement return maxnum; before the closing brace of the findMax() function. The complete function code is as follows: int findMax(int x, int y) // function header { // start of function body int maxnum; // variable declaration if (x >= y) maxnum = x; else maxnum = y; return maxnum; // return statement } These should be the same data type 9 The return data type is related to the parameter data types only as much as the returned value is typically determined by the parameter values. In this case, because the function is used to return the maximum value of its parameters, it would make little sense to return a data type that doesn’t match the function’s parameter data types. 10 Many programmers place the expression in parentheses, as in return (expression);. Although either form (with or without parentheses) can be used, choose one and stay with it for consistency. 315 Chapter 6 Returning a Single Value
  • 336. In this new code for the findMax() function, note that the data type of the expression in the return statement matches the data type in the function header. It’s up to the programmer to ensure this match for every function returning a value. Failure to match the return value with the function’s declared data type exactly might not result in an error when your program is compiled, but it could lead to undesired results because the return value is always converted to the data type declared in the function declaration. Usually, this is a problem only when the fractional part of a returned floating-point or double-precision number is truncated because the function was declared to return an integer value. Having taken care of the sending side of the return transaction, you must now prepare the calling function to receive the value sent by the called function. On the calling (receiving) side, the calling function must • Be alerted to the type of value to expect back from the called function • Use the returned value correctly Alerting the calling function to the type of return value to expect is taken care of by the function prototype. For example, including the function prototype int findMax(int, int); before the main() function is enough to alert main() that findMax() is a function that returns an integer value. To actually use a returned value, you must provide a variable to store the value or use the value in an expression. To store the returned value in a variable, you use a standard assignment statement. For example, the following assignment statement can be used to store the value returned by findMax() in the variable max: max = findMax(firstnum, secnum); This assignment statement does two things. First, the right side of the assignment statement calls findMax(), and then the result returned by findMax() is stored in the variable max. Because the value returned by findMax() is an integer, the variable max should also be declared as an integer variable in the calling function’s variable declarations. The value a function returns need not be stored in a variable, but it can be used wherever an expression is valid. For example, the expression 2 * findMax(firstnum, secnum) multiplies the value returned by findMax() by 2, and the following statement displays the returned value: cout << findMax(firstnum, secnum); Program 6.5 illustrates including prototype and assignment statements for main() to declare, call, and store a returned value from findMax() correctly. As before, and in keeping with the convention of placing the main() function first, the findMax() function is placed after main(). 316 Modularity Using Functions
  • 337. Program 6.5 #include <iostream> using namespace std; int findMax(int, int); // the function prototype int main() { int firstnum, secnum, max; cout << "nEnter a number: "; cin >> firstnum; cout << "Great! Please enter a second number: "; cin >> secnum; max = findMax(firstnum, secnum); // the function is called here cout << "nThe maximum of the two numbers is " << max << endl; return 0; } int findMax(int x, int y) { // start of function body int maxnum; // variable declaration if (x >= y) // find the maximum number maxnum = x; else maxnum = y; return maxnum; // return statement } In reviewing Program 6.5, note the four items introduced in this section. First, the function prototype for findMax() is a statement ending with a semicolon, as all declaration statements do; it alerts main() and any subsequent functions using findMax() to the data type that findMax() returns. Second, an assignment statement is used in main() to store the returned value from the findMax() call in the variable max. In Program 6.5, max is declared correctly as an integer in main()’s variable declarations so that it matches the returned value’s data type. The third and fourth items concern coding the findMax() function: The first line of findMax() declares that the function returns an integer value, and the expression in the return statement evaluates to a matching data type. Therefore, findMax() is internally 317 Chapter 6 Returning a Single Value
  • 338. consistent in sending an integer value back to main(), and main() has been alerted to receive and use the returned integer. In writing your own functions, always keep these four items in mind. For another example, see whether you can identify these four items in Program 6.6. Program 6.6 #include <iostream> using namespace std; double tempvert(double); // function prototype int main() { const int CONVERTS = 4; // number of conversions to be made int count; double fahren; for(count = 1; count <= CONVERTS; count++) { cout << "nEnter a Fahrenheit temperature: "; cin >> fahren; cout << "The Celsius equivalent is " << tempvert(fahren) << endl; } return 0; } // convert fahrenheit to celsius double tempvert(double inTemp) { return (5.0/9.0) * (inTemp - 32.0); } In reviewing Program 6.6, first analyze the tempvert() function. The function’s definition begins with the function header and ends with the closing brace after the return statement. The function is declared as a double, meaning the expression in the function’s return statement must evaluate to a double-precision number, which it does. Because a function header is not a statement but the start of the code defining the function, it doesn’t end with a semicolon. On the receiving side, main() has a prototype for the tempvert() function that agrees with tempvert()’s function definition. No variable is declared in main() to store the 318 Modularity Using Functions
  • 339. returned value from tempvert() because the returned value is passed immediately to cout for display. Finally, one purpose of declarations, as you learned in Chapter 2, is to alert the computer to the amount of internal storage reserved for data. The prototype for tempvert() performs this task and alerts the compiler to the type of storage needed for the returned value. Because main() is always the first function in a program, you must include function prototypes for all functions called by main() and any subsequent functions. Inline Functions11 Calling a function places a certain amount of overhead on a computer. This overhead consists of the following steps: 1. Placing argument values in a reserved memory region (called the stack) that the function has access to 2. Passing control to the function 3. Providing a reserved memory location for any returned value (again, using the stack for this purpose) 4. Returning to the correct point in the calling program Paying this overhead is justified when a function is called many times because it can reduce a program’s size substantially. Instead of the same code being repeated each time it’s needed, the code is written once, as a function, and called whenever it’s needed. For small functions that aren’t called many times, however, the overhead of passing and returning values might not be warranted. It would still be convenient to group repeating lines of code together under a common function name and have the compiler place this code in the program wherever the function is called. Inline functions provide this capability. Telling the C++ compiler that a function is inline causes a copy of the function code to be placed in the program at the point the function is called. For example, because the tempvert() function in Program 6.6 is fairly short, it’s an ideal candidate to be an inline function. To make it, or any other function, an inline one simply requires placing the reserved keyword inline before the function name and defining the function before any calls are made to it. Program 6.7 makes tempvert() an inline function. Observe in Program 6.7 that the inline function is placed ahead of any calls to it. This placement is a requirement of all inline functions, so a function prototype isn’t needed before subsequent calling functions. Because the function is now inline, its code is expanded into the program wherever it’s called. 11 This section is optional and can be omitted on first reading without loss of subject continuity. 319 Chapter 6 Returning a Single Value
  • 340. Program 6.7 #include <iostream> using namespace std; inline double tempvert(double inTemp) // an inline function { return (5.0/9.0) * (inTemp - 32.0); } int main() { const CONVERTS = 4; // number of conversions to be made int count; double fahren; for(count = 1; count <= CONVERTS; count++) { cout << "nEnter a Fahrenheit temperature: "; cin >> fahren; cout << "The Celsius equivalent is " << tempvert(fahren) << endl; } return 0; } The advantage of using an inline function is an increase in execution speed. Because the inline function is expanded and included in every expression or statement calling it, no execution time is lost because of the call and return overhead a non-inline function requires. The disadvantage is the increase in program size when an inline function is called repeatedly. Each time an inline function is referenced, the complete function code is reproduced and stored as an integral part of the program. A non-inline function, however, is stored in memory only once. No matter how many times the function is called, the same code is used. Therefore, inline functions should be used only for small functions that aren’t called extensively in a program. 320 Modularity Using Functions
  • 341. EXERCISES 6.2 1. (Modify) Rewrite Program 6.5 so that the findMax() function accepts two double- precision arguments and returns a double-precision value to main(). Make sure to modify main() to pass two double-precision values to findMax() and to accept and store the double-precision value returned by findMax(). 2. (Practice) For the following function headers, determine the number, type, and order (sequence) of values that should be passed to the function when it’s called and the data type of the value the function returns: a. int factorial(int n) b. double volts(int res, double induct, double cap) c. double power(int type, double induct, double cap) d. char flag(char type, float current, float time) e. int total(float amount, float rate) f. float roi(int a, int b, char c, char d, float e, float f) g. void getVal(int item, int iter, char decflag, char delim) 3. (Practice) Write function headers for the following: a. A function named check() that has three parameters. The first parameter should accept an integer number, and the second and third parameters should accept a double-precision number. The function returns no value. b. A function named findAbs() that accepts a double-precision number passed to it and returns its absolute value. c. A function named mult() that accepts two floating-point numbers as parameters, multiplies these two numbers, and returns the result. d. A function named sqrIt() that computes and returns the square of the integer value passed to it. e. A function named powfun() that raises an integer number passed to it to a positive integer (as an argument) power and returns the result as an integer. f. A function that produces a table of the numbers from 1 to 10, their squares, and their cubes. No arguments are to be passed to the function, and the function returns no value. 4. (General Math) a. Write a function named rightTriangle() that accepts the lengths of two sides of a right triangle as the arguments a and b. The subroutine should determine and return the hypotenuse, c, of the triangle. (Hint: Use Pythagoras’ theorem, c2 = a2 + b2 .) b. Include the function written for Exercise 4a in a working program. The main() function should call rightTriangle() correctly and display the value the function returns. 5. (General Math) a. Write a C++ function named findAbs() that accepts a double- precision number passed to it, computes its absolute value, and returns the absolute value to the calling function. A number’s absolute value is the number itself if the number is positive and the negative of the number if the number is negative. 321 Chapter 6 Returning a Single Value
  • 342. b. Include the function written in Exercise 5a in a working program. Make sure your function is called from main() and returns a value to main() correctly. Have main() use a cout statement to display the returned value. Test the function by passing various data to it. 6. (General Math) a. The volume, V, of a cylinder is given by the formula V = ␲r2 L where r is the cylinder’s radius and L is its length. Using this formula, write a C++ func- tion named cylvol() that accepts a cylinder’s radius and length and returns its volume. b. Include the function written in Exercise 6a in a working program. Make sure your function is called from main() and returns a value to main() correctly. Have main() use a cout statement to display the returned value. Test the function by passing various data to it. 7. (General Math) a. The side surface area, S, of a cylinder is given by the formula S = 2␲rl where r is the cylinder’s radius, and l is the length of the cylinder. Using this formula, write a C++ function named surfarea() that accepts a cylinder’s radius and length and returns its side surface area. b. Include the function written in Exercise 7a in a working program. Make sure your function is called from main() and returns a value to main() correctly. Have main() use a cout statement to display the returned value. Test the function by passing various data to it. 8. (Numerical) A second-degree polynomial in x is given by the expression ax2 + bx + c, where a, b, and c are known numbers and a is not equal to 0. Write a C++ function named polyTwo(a,b,c,x) that computes and returns the value of a second-degree polynomial for any passed values of a, b, c, and x. 9. (Structural Eng.) a. The maximum allowable deflection of a beam depends on its function. For a floor, the typical maximum allowable deflection, in inches, is Dmax = L / 240, and for a roof beam, Dmax = L / 180, where L is the length of the beam in inches. Using these formulas, write and test a function named maxDeflect() that accepts the length of a beam, in feet, and the type of beam (floor or roof) as a character code and returns the maximum allowable deflection. b. Include the function written in Exercise 9a in a working program. Make sure your function is called from main() and returns a value to main() correctly. Have main() use a cout statement to display the returned value. Test the function by passing various data to it. 10. (Structural Eng.) a. The load, Pcr, in units of kips, applied to a column that causes the column to buckle is referred to as the critical buckling load. This load can be determined by using this formula: Pcr = ␲2 E A / (L / r)2 322 Modularity Using Functions
  • 343. E is the modulus of elasticity of the column’s material. A is the cross-sectional area. L is the length of the column. r is the column’s radius of gyration. Using this formula, write a C++ function named cLoad() that accepts values of E, A, L, and r and returns the critical buckling load. b. Include the function written in Exercise 10a in a working program. Make sure your function is called from main() and returns a value to main() correctly. Have main() use a cout statement to display the returned value. Test the function by passing various data to it. 11. (Numerical) a. The following is an extremely useful programming algorithm for round- ing a real number to n decimal places: Step 1: Multiply the number by 10n Step 2: Add 0.5 Step 3: Delete the fractional part of the result Step 4: Divide by 10n For example, using this algorithm to round the number 78.374625 to three decimal places yields: Step 1: 78.374625 × 103 = 78374.625 Step 2: 78374.625 + 0.5 = 78375.125 Step 3: Retaining the integer part = 78375 Step 4: 78375 divided by 103 = 78.375 Using this algorithm, write a C++ function that accepts a user-entered value and returns the result rounded to two decimal places. b. Enter, compile, and execute the program written for Exercise 11a. 12. (Numerical) a. Write a C++ function named whole() that returns the integer part of any number passed to the function. (Hint: Assign the passed argument to an integer variable.) b. Include the function written in Exercise 12a in a working program. Make sure your function is called from main() and returns a value to main() correctly. Have main() use a cout statement to display the returned value. Test the function by passing various data to it. 13. (Numerical) a. Write a C++ function named fracpart() that returns the fractional part of any number passed to it. For example, if the number 256.879 is passed to fracpart(), the number 0.879 should be returned. Have fracpart() call the whole() function you wrote in Exercise 12. The number returned can then be determined as the number passed to fracpart() less the returned value when the same argument is passed to whole(). The completed program should consist of main() followed by fracpart() followed by whole(). b. Include the function written in Exercise 13a in a working program. Make sure your function is called from main() and returns a value to main() correctly. Have main() use a cout statement to display the returned value. Test the function by passing various data to it. 323 Chapter 6 Returning a Single Value
  • 344. 14. (Numerical) Years that are evenly divisible by 400 or are evenly divisible by 4 but not by 100 are leap years. For example, because 1600 is evenly divisible by 400, 1600 was a leap year. Similarly, because 1988 is evenly divisible by 4 but not by 100, it was also a leap year. Using this information, write a C++ function that accepts the year as user input and returns a 1 if the passed year is a leap year or a 0 if it isn’t. 6.3 Returning Multiple Values In a typical function invocation, the called function receives values from its calling function, stores and manipulates the passed values, and directly returns at most one value. When data is passed in this manner, it’s referred to as a pass by value. Calling a function and passing arguments by value is a distinct advantage of C++. It allows functions to be written as independent entities that can use any variable or parameter name without concern that other functions might be using the same name. It also alleviates any concern that altering a parameter or variable in one function could inadvertently alter a parameter or variable’s value in another function. In this approach, parameters can be considered initialized variables, or variables assigned values when the function is executed. At no time, however, does the called function have direct access to any variable defined in the calling function, even if the variable is used as an argument in the function call. At times, however, you need to modify this approach by giving a called function direct access to its calling function’s variables. This approach allows one function—the called function—to use and change the value of variables that have been defined in the calling function. Doing this requires passing the variable’s address to the called function. After the called function has the variable’s address, it “knows where the variable lives,” so to speak, and can access and change the value stored there. Passing addresses is referred to as a function pass by reference12 because the called function can reference, or access, the variable whose address has been passed. C++ provides two types of address parameters: references and pointers. This section describes the method that uses reference parameters. Passing and Using Reference Parameters As always, when exchanging data between two functions, you must be concerned with both the sending and receiving sides. From the sending side, calling a function and passing an address as an argument that’s accepted as a reference parameter is the same as calling a function and passing a value; the called function is summoned into action by giving its name and a list of arguments. For example, the statement newval(firstnum, secnum); calls the function named newval() and passes two arguments to it. Whether a value or an address is actually passed depends on the parameter types declared for newval(). Now take a look at writing the newval() function and prototype so that it receives the addresses rather than the values of the variables firstnum and secnum, which are assumed to be double-precision variables. 12 It’s also referred to as a “call by reference,” and again, both terms refer only to the argument whose address has been passed. 324 Modularity Using Functions
  • 345. One of the first requirements in writing newval() is to declare two reference parameters for accepting passed addresses. In C++, a reference parameter is declared with this syntax: dataType& referenceName For example, the reference declaration double& num1; declares that num1 is a reference parameter used to store the address of a double. Similarly, int& secnum; declares that secnum is a reference to an integer, and char& key; declares that key is a reference to a character. Recall from Section 2.4 that the ampersand, &, in C++ means “the address of.” Additionally, when & is used in a declaration, it refers to “the address of” the preceding data type. Using this information, declarations such as double& num1 and int& secnum are sometimes more clearly understood if they are read backward. Reading the declaration double& num1 in this manner yields the information “num1 is the address of a double-precision value.” Because you need to accept two addresses in the parameter list for newval(), the declarations double& num1 and double& num2 can be used. Including these declarations in the parameter list for newval(), and assuming the function returns no value (void), the function header for newval() becomes the following: void newval(double& num1, double& num2) For this function header, the following is an appropriate function prototype: void newval(double&, double&); This prototype and function header are included in Program 6.8, which uses a newval() function body that displays and alters the values stored in these reference variables from within the called function. In calling the newval() function in Program 6.8, you need to understand the connection between the arguments, firstnum and secnum, used in the function call and the parameters, xnum and ynum, used in the function header. Both refer to the same data items. The significance is that the values in the arguments (firstnum and secnum) can now be altered from within newval() by using the parameter names (xnum and ynum). Therefore, the parameters xnum and ynum don’t store copies of the values in firstnum and secnum; instead, they access the locations in memory set aside for these two arguments. 325 Chapter 6 Returning Multiple Values
  • 346. Program 6.8 #include <iostream> using namespace std; void newval(double&, double&); // prototype with two reference parameters int main() { double firstnum, secnum; cout << "Enter two numbers: "; cin >> firstnum >> secnum; cout << "nThe value in firstnum is: " << firstnum << endl; cout << "The value in secnum is: " << secnum << "nn"; newval(firstnum, secnum); // call the function cout << "The value in firstnum is now: " << firstnum << endl; cout << "The value in secnum is now: " << secnum << endl; return 0; } void newval(double& xnum, double& ynum) { cout << "The value in xnum is: " << xnum << endl; cout << "The value in ynum is: " << ynum << "nn"; xnum = 89.5; ynum = 99.5; return; } The equivalence of argument names in Program 6.8, which is the essence of a pass by reference, is illustrated in Figure 6.7. As shown in this figure, the argument names and their matching parameter names are simply different names referring to the same memory storage areas. In main(), these memory locations are referenced by the argument names firstnum and secnum, and in newval(), the same locations are referenced by the parameter names xnum and ynum. 326 Modularity Using Functions
  • 347. The following is a sample run of Program 6.8: Enter two numbers: 22.5 33.0 The value in firstnum is: 22.5 The value in secnum is: 33 The value in xnum is: 22.5 The value in ynum is: 33 The value in firstnum is now: 89.5 The value in secnum is now: 99.5 In reviewing this output, notice that the values initially displayed for the parameters xnum and ynum are the same as those displayed for the arguments firstnum and secnum. Because xnum and ynum are reference parameters, however, newval() now has direct access to the arguments firstnum and secnum. Therefore, any change to xnum in newval() alters the value of firstnum in main(), and any change to ynum changes secnum’s value. As the final displayed values show, the assignment of values to xnum and ynum in newval() is reflected in main() as the altering of firstnum’s and secnum’s values. The equivalence between actual calling arguments and function parameters shown in Program 6.8 provides the basis for returning multiple values from within a function. For example, say you want to write a function that’s required to accept three values, compute these values’ sum and product, and return these computed results to the calling routine. By firstnum xnum One value is stored secnum ynum In main() the values are referenced as In newval() the same values are referenced as One value is stored Figure 6.7 The equivalence of arguments and parameters in Program 6.8 327 Chapter 6 Returning Multiple Values
  • 348. naming the function calc() and providing five parameters (three for input data and two references for returned values), the following function can be used: void calc(double num1, double num2, double num3, double& total, double& product) { total = num1 + num2 + num3; product = num1 * num2 * num3; return; } This function has five parameters named num1, num2, num3, total, and product. Only the last two are declared as references, so the first three arguments are passed by value and the last two arguments are passed by reference. In this function, only the last two parameters are altered. The value of the fourth parameter, total, is calculated as the sum of the first three parameters, and the last parameter, product, is computed as the product of the parameters num1, num2, and num3. Program 6.9 includes this function in a complete program. Program 6.9 #include <iostream> using namespace std; void calc(double, double, double, double&, double&); // prototype int main() { double firstnum, secnum, thirdnum, sum, product; cout << "Enter three numbers: "; cin >> firstnum >> secnum >> thirdnum; calc(firstnum, secnum, thirdnum, sum, product); // function call cout << "nThe sum of the numbers is: " << sum << endl; cout << "The product of the numbers is: " << product << endl; return 0; } void calc(double num1, double num2, double num3, double& total, double& product) { total = num1 + num2 + num3; product = num1 * num2 * num3; return; } 328 Modularity Using Functions
  • 349. In main(), the function calc() is called with the five arguments firstnum, secnum, thirdnum, sum, and product. As required, these arguments agree in number and data type with the parameters declared by calc(). Of the five arguments passed, only firstnum, secnum, and thirdnum have been assigned values when the call to calc() is made. The remaining two arguments haven’t been initialized and are used to receive values back from calc(). Depending on the compiler used, these arguments initially contain zeros or “garbage” values. Figure 6.8 shows the relationship between actual and parameter names and the values they contain after the return from calc(). After calc() is called, it uses its first three parameters to calculate values for total and product and then returns control to main(). Because of the order of its actual calling arguments, main() knows the values calculated by calc() as sum and product, which are then displayed. Following is a sample run of Program 6.9: Enter three numbers: 2.5 6.0 10.0 The sum of the entered numbers is: 18.5 The product of the entered numbers is: 150 As a final example of the usefulness of passing references to a called function, take a look at constructing a function named swap() that exchanges the values of two of main()’s double-precision variables. This type of function is useful when sorting a list of numbers. Because the value of more than one variable is affected, swap() can’t be written as a pass by value function that returns a single value. The exchange of main()’s variables by swap() can be accomplished only by giving swap() access to main()’s variables. One way of doing this is using reference parameters. You have already seen how to pass references to two variables in Program 6.8. Now you see how to construct a function to exchange the values in the passed reference parameters. num2 num3 num1 10.0 6.0 2.5 A value is passed main() calc() Argument names used in main() Parameter names used in calc() 10.0 thirdnum 6.0 secnum 2.5 firstnum total 18.5 sum product 150.0 product Figure 6.8 The relationship between argument and parameter names 329 Chapter 6 Returning Multiple Values
  • 350. Exchanging values in two variables is accomplished by using the three-step exchange algorithm: 1. Save the first parameter’s value in a temporary location (see Figure 6.9a). 2. Store the second parameter’s value in the first variable (see Figure 6.9b). 3. Store the temporary value in the second parameter (see Figure 6.9c). Following is the swap() function written according to these specifications: void swap(double& num1, double& num2) { double temp; temp = num1; // save num1's value num1 = num2; // store num2's value in num1 num2 = temp; // change num2's value return; } Notice that the use of references in swap()’s function header gives swap() access to equivalent arguments in the calling function. Therefore, any changes to the two reference parameters in swap() change the values in the calling function’s arguments automatically. Program 6.10 contains swap() in a complete program. num1 temp num2 Figure 6.9a Save the first value num1 temp num2 Figure 6.9b Replace the first value with the second value num2 num1 temp Figure 6.9c Change the second value 330 Modularity Using Functions
  • 351. Program 6.10 #include <iostream> using namespace std; void swap(double&, double&); // function receives two references int main() { double firstnum = 20.5, secnum = 6.25; cout << "The value stored in firstnum is: " << firstnum << endl; cout << "The value stored in secnum is: "<< secnum << "nn"; swap(firstnum, secnum); // call the function with references cout << "The value stored in firstnum is now: " << firstnum << endl; cout << "The value stored in secnum is now: " << secnum << endl; return 0; } void swap(double& num1, double& num2) { double temp; temp = num1; // save num1's value num1 = num2; // store num2's value in num1 num2 = temp; // change num2's value return; } The following is a sample run of Program 6.10: The value stored in firstnum is: 20.5 The value stored in secnum is: 6.25 The value stored in firstnum is now: 6.25 The value stored in secnum is now: 20.5 As shown by Program 6.10’s output, the values stored in main()’s variables have been modified from within swap(), which was made possible by using reference parameters. If a pass by value had been used instead, the exchange in swap() would affect only swap()’s 331 Chapter 6 Returning Multiple Values
  • 352. parameters and accomplish nothing with main()’s variables. A function such as swap() can be written only by using a reference or some other means that provides access to main()’s variables. (This other means is with pointers, the topic of Chapter 12.) In using reference parameters, two cautions need to be mentioned. First, reference parameters must be variables (that is, they can’t be used to change constants). For example, calling swap() with two literals, as in the call swap(20.5, 6.5), passes two constants to the function. Although swap() can execute, it doesn’t change the values of these constants.13 Second, a function call gives no indication that the called function will be using reference parameters. The default in C++ is to make passes by value rather than passes by reference, specifically to limit a called function’s ability to alter variables in the calling function. This calling procedure should be adhered to whenever possible, which means reference param- eters should be used only in restricted situations that require multiple return values, as in the swap() function in Program 6.10. The calc() function included in Program 6.9, although useful for illustration purposes, could also be written as two separate functions, each returning a single value. EXERCISES 6.3 1. (Practice) Write parameter declarations for the following: a. A parameter named slope that will be a reference to a double-precision value b. A parameter named energy that will be a reference to a double-precision number c. A parameter named minutes that will be a reference to an integer number d. A parameter named key that will be a reference to a character e. A parameter named yield that will be a reference to a double-precision number 2. (Practice) Three integer arguments are to be used in a call to a function named time(). Write a suitable function header for time(), assuming that time() accepts these variables as the reference parameters sec, min, and hours and returns no value to its calling function. 3. (Modify) Rewrite the findMax() function in Program 6.5 so that the variable max, declared in main(), is used to store the maximum value of the two passed numbers. The value of max should be set from within findMax(). (Hint: A reference to max has to be accepted by findMax().) 4. (Practice) Write a function named change() that has an integer parameter and six inte- ger reference parameters named hundreds, fifties, twenties, tens, fives, and ones. The function is to consider the passed integer value as a dollar amount and con- vert the value into the fewest number of equivalent bills. Using the reference parameters, the function should alter the arguments in the calling function. 5. (Practice) Write a function named time() that has an integer parameter named seconds and three integer reference parameters named hours, mins, and secs. The 13 Most compilers catch this error. 332 Modularity Using Functions
  • 353. function is to convert the passed number of seconds into an equivalent number of hours, minutes, and seconds. Using the reference parameters, the function should alter the argu- ments in the calling function. 6. (Practice) Write a function named yearCalc() that has an integer parameter represent- ing the total number of days from the date 1/1/2000 and reference parameters named year, month, and day. The function is to calculate the current year, month, and day given the number of days passed to it. Using the reference parameters, the function should alter the arguments in the calling function. For this problem, assume each year has 365 days, and each month has 30 days. 7. (Desk Check) The following program uses the same argument and parameter names in both the calling and called functions. Determine whether doing so causes any problem for the compiler. #include <iostream> using namespace std; void time(int&, int&); // function prototype int main() { int min, hour; cout << "Enter two numbers :"; cin >> min >> hour; time(min, hour); return 0; } void time(int& min, int& hour) // accept two references { int sec; sec = (hour * 60 + min) * 60; cout << "The total number of seconds is " << sec << endl; return; 6.4 A Case Study: Rectangular to Polar Coordinate Conversion Preparing a well-designed computer program is much like preparing a well-designed term paper, in that both should start with an outline. This outline can be written down or, for very small programs, simply kept in mind as the program is being developed. As with a term-paper outline that lists the main topics, a computer program’s initial outline lists the primary tasks the program is to accomplish. In written form, a computer program’s initial outline is typically a pseudocode description or a first-level structure diagram. (Both were described in Section 1.3.) This initial outline 333 Chapter 6 A Case Study: Rectangular to Polar Coordinate Conversion
  • 354. begins the process of defining a more complicated problem as a set of smaller, more manageable tasks. Each of these tasks can be further subdivided or refined into even smaller tasks, if required. After the tasks are well defined, the actual work of coding can begin, starting with any task, in any order. If there are more tasks than one programmer can handle, they can be distributed among as many programmers as necessary. This workload distribution is equivalent to having many people work on a large research project, with each person responsible for a topic or project component. A general outline applicable to many engineering and scientific tasks is the following algorithm: Get the inputs to the problem Calculate the desired result Report the results of the calculation These three tasks are the primary responsibilities of every program, and this algorithm is referred to as the problem-solver algorithm. Figure 6.10 shows a first-level structure diagram of this algorithm. Each task in the problem-solver algorithm can be worked on independently as a function—a sort of “mini” C++ program that’s easier to complete than a whole program. Each function task can be refined and coded in any order, although completing the input section first usually makes testing and development easier. Next, you apply this development procedure to the programming problem of converting rectangular coordinates to their polar equivalents. Step 1 Problem Definition A program is to be written to convert a point’s rectangular (x,y) coordinates into polar form. That is, given an x and y position on a Cartesian coordinate system, shown in Figure 6.11, you must calculate the distance from the origin, r, and the angle from the x-axis, θ , specified by the point. The values of r and θ are referred to as the point’s polar coordinates. When the x and y coordinates of a point are known, the equivalent r and θ coordinates can be calculated by using these formulas: r x y = + 2 2 θ = ≠ tan ( / ) -1 0 y x x You begin developing your program with an outline of what the program is to accomplish. You can construct an initial pseudocode description by applying the problem-solver algorithm Problem- solver algorithm Get inputs Calculate result Display result Figure 6.10 The problem-solver algorithm 334 Modularity Using Functions
  • 355. to the specifics of the program. The required inputs are x and y coordinates, the calculation is to convert the input values to their polar coordinate form, and the display is the calculated polar coordinates. The initial pseudocode description is as follows: Get the x and y coordinate values Calculate the polar (r and θ ) coordinate values Display the polar coordinate values Figure 6.12 shows the equivalent first- or top-level structure diagram for this algorithm. As this program is rather simple and each task described by the algorithm is well defined, you can begin coding each task. To show that any task can be coded independently of any other task, you start by coding the function that calculates polar coordinates, although you could start with any function. As an added feature, this function will return the angle θ in degrees rather than the radian measure the atan() function returns. Because this function must receive two inputs, the x and y coordinates, and return two outputs, the r and θ coordinates, you provide four parameters: two for the inputs and two for the outputs. Using the parameter names x, y, r, and (x,y) x-axis y-axis r Figure 6.11 The correspondence between polar (distance and angle) and Cartesian (x and y) coordinates Rectangular to polar coordinate conversion Input x and y coordinates Calculate r and Display r and θ θ Figure 6.12 A top-level structure diagram 335 Chapter 6 A Case Study: Rectangular to Polar Coordinate Conversion
  • 356. theta and the function name polar(), the following code performs the required calculation of polar coordinates: void polar(double x, double y, double& r, double& theta) { const double TODEGREES = 180.0/3.141593; r = sqrt(x * x + y * y); theta = atan(y/x) * TODEGREES; return; } The polar() function is straightforward. The function header declares that the function returns no value, and each of its parameters is declared as a floating-point data type. The first two parameters are used to accept x and y values, and the last two parameters, which are reference parameters, are used to pass the converted distance and angle values back to the calling function. In the function body, a constant named TODEGREES is defined as the factor 180.0 / 3.142593. The next two assignment statements use the parameters x and y to assign values to the r and theta parameters. The TODEGREES named constant is used to convert the radian value returned from the atan() function into degrees. As written, the polar() function can be compiled to check for any compile-time errors. To understand how the return values are passed, it’s helpful to think of the reference parameters r and theta as containers (or variables) through which values can be passed in either direction. This situation is shown in Figure 6.13, which illustrates the fundamental characteristics of reference parameters: They simply make it possible for both called functions and calling functions to access the same storage area with different names. As shown in Figure 6.13, the calling function can access the values assigned to r and theta in polar() with the argument names distance and angle or any other programmer-selected argument names. Step 2 Testing the Function After polar() is written, it can be tested independently of any other function. For this testing, you write a dedicated driver function that calls only polar(), as shown in Program 6.11. r main() polar() main() polar() 5.0 distance theta 53.1301 angle Figure 6.13 Parameter values when polar() is called 336 Modularity Using Functions
  • 357. Program 6.11 #include <iostream> #include <cmath> using namespace std; void polar(double, double, double&, double&); // function prototype int main() { double distance, angle; polar(3.0, 4.0, distance, angle); cout << "r = " << distance << endl; cout << "angle = " << angle << endl; return 0; } void polar(double x, double y, double& r, double& theta) { const double TODEGREES = 180.0/3.141593; r = sqrt(x * x + y * y); theta = atan(y/x) * TODEGREES; return; } Notice that in main(), the literals 3.0 and 4.0 are passed to polar(). The function accepts these inputs as the parameters x and y and uses these parameters in calculating values for the parameters r and theta. In main(), these last two parameters are known as distance and angle, and their values are displayed immediately after the call to polar() is made. This is the output produced when Program 6.11 runs: r = 5 angle = 53.1301 These results are the same as those you would get from a hand calculation. As the function performs only two calculations, and the results displayed by the test program agree with those from a hand calculation, the function has been completely tested. It still remains to be group tested with the other two functions required for the complete program to make sure correct argument values are exchanged between each function. 337 Chapter 6 A Case Study: Rectangular to Polar Coordinate Conversion
  • 358. Step 3 Completing the Program The structure diagram for the complete program (shown previously in Figure 6.12) also requires writing functions for accepting two rectangular coordinates and displaying the calculated polar coordinates. The following function, getrec(), can be used to accept the input data: void getrec(double& x, double& y) { cout << "Rectangular to Polar Coordinate" << " Conversion Programn" << endl; cout << "Enter the x coordinate: "; cin >> x; cout << "Enter the y coordinate: "; cin >> y; return; } In this function, the reference parameters x and y are used to return the values entered in response to the two cin prompts. As with the polar() function, this function can be tested by using a small dedicated driver program. Program 6.12 shows the function with its driver program. Notice that the dedicated driver program, also referred to as a “front-end driver,” has been used to call getrec() and display the values this function returns. The following output produced by Program 6.12 verifies the correct operation of the getrec() function: Rectangular to Polar Coordinate Conversion Program Enter the x coordinate: 3 Enter the y coordinate: 4 The entered value for x is 3 The entered value for y is 4 338 Modularity Using Functions
  • 359. Program 6.12 #include <iostream> using namespace std; void getrec(double&, double&); // function prototype int main() { double xcoord, ycoord; getrec(xcoord, ycoord); cout << "The entered value for x is " << xcoord << endl; cout << "The entered value for y is " << ycoord << endl; return 0; } void getrec(double& x, double& y) { cout << "Rectangular to Polar Coordinate" << " Conversion Programn" << endl; cout << "Enter the x coordinate: "; cin >> x; cout << "Enter the y coordinate: "; cin >> y; return; } The function for displaying polar coordinates is constructed in a similar manner. Program 6.13 contains both the function, named showit(), and a front-end driver for testing the function. Notice that the parameter names used in the function header for showit() need not be the same as those used in any other function. showit() is constructed to simply display the values in its two parameters, which in this case have been named radius and angle. The following output of Program 6.13 verifies that showit() displays the values passed to it correctly: The polar coordinates are: Distance from origin: 5 Angle (in degrees) from x-axis: 53.1301 339 Chapter 6 A Case Study: Rectangular to Polar Coordinate Conversion
  • 360. Program 6.13 #include <iostream> using namespace std; void showit(double, double); // function prototype int main() { showit(5.0, 53.1301); return 0; } void showit(double radius, double angle) { cout << "nThe polar coordinates are: " << endl; cout << " Distance from origin: " << radius << endl; cout << " Angle (in degrees) from x-axis: " << angle << endl; return; } It now remains to create one main() program that calls each of the developed functions in the correct order. This is done in Program 6.14, which also includes the functions getrec(), polar(), and showit(). Program 6.14 // This program converts rectangular coordinates to polar coordinates // Functions used: getrec() - obtain the rectangular coordinates // : polar() - calculate the polar coordinates // : showit() - display the polar coordinates #include <iostream> #include <cmath> using namespace std; void getrec(double&, double&); // function prototype void polar(double, double, double&, double&); // function prototype void showit(double, double); // function prototype 墌 340 Modularity Using Functions
  • 361. int main() { double x, y, distance, angle; getrec(x, y); polar(x, y, distance, angle); showit(distance, angle); return 0; } void getrec(double& x, double& y) { cout << "Rectangular to Polar Coordinate" << " Conversion Programn" << endl; cout << "Enter the x coordinate: "; cin >> x; cout << "Enter the y coordinate: "; cin >> y; return; } void polar(double x, double y, double& r, double& theta) { const double TODEGREES = 180.0/3.141593; r = sqrt(x * x + y * y); theta = atan(y/x) * TODEGREES; return; } void showit(double radius, double angle) { cout << "nThe polar coordinates are: " << endl; cout << " Distance from origin: " << radius << endl; cout << " Angle (in degrees) from x-axis: " << angle << endl; return; } 341 Chapter 6 A Case Study: Rectangular to Polar Coordinate Conversion
  • 362. The following output was produced from one run of Program 6.14: Rectangular to Polar Coordinate Conversion Program Enter the x coordinate: 3 Enter the y coordinate: 4 The polar coordinates are: Distance from origin: 5 Angle (in degrees) from x-axis: 53.1301 Before leaving Program 6.14, note that an alternative to writing driver programs for each function during program development is writing a main() program first and adding the functions later as they’re developed. To do this, you use stubs for each function (see Section 6.1) and then replace each stub, one at a time, with the completed function. EXERCISES 6.4 1. (Practice) The volume, v, and side surface area, s, of a cylinder are given by the formulas v= ␲r2 l s = 2␲rl where r is the cylinder’s radius, and l is its length. Using these formulas, write and test a function named cylinder() that accepts a cylinder’s radius and length and returns its volume and side surface area. 2. (Practice) Write a C++ program that accepts the rectangular coordinates of two points (x1, y1) and (x2, y2), calculates the distance of each point from the origin, and calculates the distance between the two points. The distance, d, between two points is given by this formula: d x x y y = ( ) + ( ) 2 1 2 2 1 2 - - 3. (Fluid Mechanics) Fluid flowing in a pipe flows in a smooth pattern, known as laminar flow, or a turbulent pattern, known as turbulent flow. The velocity, V, that produces each type of flow in the pipe can be determined by using these formulas: Vlaminar = (2100 µ) / (r d) Vturbulent = (4000 µ) / (r d) Vlaminar is the velocity of the fluid, in ft/sec, that produces a definite laminar flow. Vturbulent is the velocity of the fluid, in ft/sec, that produces a definite turbulent flow. µ is the fluid’s viscosity in lbf-sec/ft2 . ρ is the fluid’s density in slug/ft3 . d is the pipe’s inside diameter in feet. 342 Modularity Using Functions
  • 363. Using these formulas, write and test a C++ function named flow() that returns both the laminar flow velocity, Vlaminar , and the turbulent flow velocity, Vturbulent , using reference parameters. The function should calculate these velocities for water, which has a viscosity, µ, of 1.9 × 105 lbf-sec/ft2 and a density, r , of 1.94 slug/ft3 . The pipe diameter should be passed by value to the flow() function. 4. (Fluid Mechanics) The viscosity and density of three common fluids are listed in the following chart: Fluid Viscosity (lbf-sec/ft2 ) Density (slug/ft3 ) Ethyl alcohol 2.29 × 105 1.527 Methyl alcohol 1.17 × 105 1.531 Propyl alcohol 4.01 × 105 1.556 Using this data, write and test a C++ function named viscDen() that returns the viscos- ity and density of the selected fluid by using reference parameters. The type of fluid should be input to the function as a character that’s passed by value. 5. (Numerical) Many algorithms have been developed for generating pseudorandom numbers. Some use a counting scheme, such as counting bits beginning at an arbitrary location in a changing memory. Another scheme, which creates pseudorandom numbers by performing a calculation, is the power residue method. The power residue method begins with an odd n-digit integer, referred to as the “seed” number. The seed is multiplied by the value (10n/2 - 3). Using the lowest n digits of the result (the “residue”) produces a new seed. Continuing this procedure produces a series of random numbers, with each new number used as the seed for the next number. If the original seed has four or more digits (n equal to or greater than 4) and is not divisible by 2 or 5, this procedure yields 5 × 10(n-2) random numbers before a sequence of numbers repeats itself. For example, starting with a six-digit seed (n = 6), such as 654321, a series of 5 × 104 = 50,000 random numbers can be generated. As an algorithm, the steps in generating pseudorandom numbers with a power residue method consist of the following: Step 1: Have a user enter a six-digit integer seed that isn’t divisible by 2 or 5—this means the number should be an odd number not ending in 5. Step 2: Multiply the seed number by 997, which is 103 - 3. Step 3: Extract the lower six digits of the result produced by Step 2. Use this random number as the next seed. Step 4: Repeat Steps 2 and 3 for as many random numbers as needed. 343 Chapter 6 A Case Study: Rectangular to Polar Coordinate Conversion
  • 364. Therefore, if the user-entered seed number is 654321 (Step 1), the first random number generated is calculated as follows: Step 2: 654321 × 997 = 652358037 Step 3: Extract the lower six digits of the number obtained in Step 2, using a standard programming “trick” that involves the following: Step 3a: Divide the number by 106 = 1000000 (for example, 652358037 / 1000000 = 652.358037). Step 3b: Take the integer part of the result of Step 3a (for example, the integer part of 652.358037 = 652). Step 3c: Multiply the previous result by 106 (for example, 652 × 106 = 652000000). Step 3d: Subtract this result from the original number (for example, 652358037 - 652000000 = 358037). The integer part of a floating-point number can be determined by assigning the floating- point number to an integer variable or using a C++ cast (see Section 3.3). In this proce- dure, you’ll use the cast mechanism. The algorithm for producing a random number can be accomplished with the following code: i = int(997.0 * x / 1.e6); // take the integer part x = 997.0 * x - i * 1.e6; Using this information, do the following: a. Create a function named randnum() that accepts a floating-point “seed” as a param- eter and returns a floating-point random number between 0 and 1.e6. b. Incorporate the randnum() function created in Exercise 5a into a working C++ pro- gram that produces 10 random numbers between 0 and 1.e6. c. Test the randomness of the randnum() function created in Exercise 5a by using the method described in Exercise 9. Try some even seed values and odd seed values end- ing in 5 to determine whether they affect the randomness of the numbers. 6. (Mathematical) Write a C++ function that determines in which quadrant a line drawn from the origin resides. The determination of the quadrant is made by using the angle the line makes with the positive x-axis, as follows: Angle from the Positive X-Axis Quadrant Between 0 and 90 degrees 1 Between 90 and 180 degrees 2 Between 180 and 270 degrees 3 Between 270 and 360 degrees 4 344 Modularity Using Functions
  • 365. Note: If the angle is exactly 0, 90, 180, or 270 degrees, the corresponding line doesn’t reside in any quadrant; it lies on an axis. For this case, your function should return a 0. N O T E 7. (Simulation) Write a program to simulate the roll of two dice. If the total of the two dice is 7 or 11, you win; otherwise, you lose. Embellish this program as much as you like, with betting, different odds, different combinations for win or lose, stopping play when you have no money left or reach the house limit, displaying the dice, and so forth. (Hint: Cal- culate the dots showing on each die with the expression dots = int(6.0 * random number + 1), where the random number is between 0 and 1.) 8. (Desk Check) The following program uses the same variable names in both the calling and called functions. Determine whether doing so causes any problem for the compiler. #include <iostream.h> int time(int, int); // function prototype int main() { int min, hour, sec; cout << "Enter two numbers: "; cin >> min, hour; sec = time(min, hour); cout << "The total number of seconds is " << sec << endl; return 0; } int time(int min, int hour) { int sec; sec = (hour * 60 + min) * 60; return sec; } 9. (Numerical) Write a program that tests the effectiveness of the rand() library function. Start by initializing 10 counters to 0. Then generate a large number of pseudorandom integers between 0 and 9. Each time a 0 occurs, increment the variable you have designated as the zero counter; when a 1 occurs, increment the counter variable that’s keeping count of the 1s that occur; and so on. Finally, display the number of 0s, 1s, 2s, and so on that occurred and the percentage of the time they occurred. 345 Chapter 6 A Case Study: Rectangular to Polar Coordinate Conversion
  • 366. 6.5 Variable Scope Now that you have begun to write programs containing more than one function, you can look more closely at the variables declared in each function and their relationship to variables in other functions. By their nature, C++ functions are constructed to be independent modules. As you have seen, values are passed to a function by using the function’s parameter list, and a value is returned from a function by using a return statement. Seen in this light, a function can be thought of as a closed box, with slots at the top to receive values and a single slot at the bottom to return a value (see Figure 6.14). The metaphor of a closed box is useful because it emphasizes that what goes on inside the function, including all variable declarations in the function body, is hidden from the view of all other functions. Because the variables created in a function are conventionally available only to the function, they are said to be local to the function, or local variables. This term refers to the scope of an identifier; scope is the section of the program where the identifier, such as a variable, is valid or “known.” This section of the program is also referred to as where the variable is “visible.” A variable can have a local scope or a global scope. A variable with a local scope is simply one with storage locations set aside for it by a declaration statement in a function body. Local variables are meaningful only when used in expressions or statements inside the function that declared them. This means the same variable name can be declared and used in more than one function. For each function that declares the variable, a separate and distinct variable is created. All the variables you have used until now have been local variables, a result of placing declaration statements inside functions and using them as definition statements that cause the computer to reserve storage for the declared variable. As you’ll see in the next section, declaration statements can be placed outside functions and also need not act as definitions that reserve new storage areas for the declared variable. A variable with global scope, more commonly termed a global variable, has storage created for it by a declaration statement located outside any function. These variables can be used by all functions that are placed after the global variable declaration. Program 6.15 shows using a global variable, and the same variable name has been used on purpose inside both functions in the program. Values passed to the function ... ... A single value directly returned by the function Figure 6.14 A function can be considered a closed box 346 Modularity Using Functions
  • 367. Program 6.15 #include <iostream> using namespace std; int firstnum; // create a global variable named firstnum void valfun(); // function prototype (declaration) int main() { int secnum; // create a local variable named secnum firstnum = 10; // store a value in the global variable secnum = 20; // store a value in the local variable cout << "From main(): firstnum = " << firstnum << endl; cout << "From main(): secnum = " << secnum << endl; valfun(); // call the function valfun cout << "nFrom main() again: firstnum = " << firstnum << endl; cout << "From main() again: secnum = " << secnum << endl; return 0; } void valfun() // no values are passed to this function { int secnum; // create a second local variable named secnum secnum = 30; // affects only this local variable's value cout << "nFrom valfun(): firstnum = " << firstnum << endl; cout << "From valfun(): secnum = " << secnum << endl; firstnum = 40; // changes firstnum for both functions return; } 347 Chapter 6 Variable Scope
  • 368. The variable firstnum in Program 6.15 is a global variable because its storage is created by a definition statement located outside a function. Because both main() and valfun() follow the definition of firstnum, both functions can use this global variable with no further declaration needed. Program 6.15 also contains two separate local variables, both named secnum. Storage for the secnum variable named in main() is created by the definition statement in main(). A different storage area for the secnum variable in valfun() is created by the definition statement in the valfun() function. Figure 6.15 shows the three distinct storage areas reserved by the three definition statements in Program 6.15. Each variable named secnum is local to the function in which its storage is created, and each variable can be used only from within its corresponding function. Therefore, when secnum is used in main(), the storage area main() reserves for its secnum variable is accessed, and when secnum is used in valfun(), the storage area valfun() reserves for its secnum variable is accessed. The following output is produced when Program 6.15 runs: From main(): firstnum = 10 From main(): secnum = 20 From valfun(): firstnum = 10 From valfun(): secnum = 30 From main() again: firstnum = 40 From main() again: secnum = 20 firstnum main() secnum storage for one integer valfun() secnum storage for one integer Figure 6.15 The three storage areas reserved by Program 6.15 348 Modularity Using Functions
  • 369. Now analyze this output to see how local and global variables work. Because firstnum is a global variable, both main() and valfun() can use and change its value. Initially, both functions print the value of 10 that main() stored in firstnum. Before returning, valfun() changes the value of firstnum to 40, which is the value displayed when the firstnum is next displayed from within main(). Because each function “knows” only its own local variables, main() can send only the value of its secnum to cout, and valfun() can send only the value of its secnum to cout. Therefore, whenever secnum is obtained from main(), the value of 20 is displayed, and whenever secnum is obtained from valfun(), the value 30 is displayed. C++ doesn’t confuse the two secnum variables because only one function can execute at a time. While a function is executing, only variables and parameters that are “in scope” for that function (global and local) can be accessed. The scope of a variable in no way influences or restricts its data type. Just as a local variable can be a character, an integer, a Boolean, a double, or any other data type that’s been introduced, global variables can be all these data types, as illustrated in Figure 6.16. A variable’s scope is determined by the placement of the definition statement that reserves storage for it and optionally by a declaration statement that makes it visible, whereas a variable’s data type is determined by using a keyword (char, int, bool, double, and so on) before the variable’s name in a declaration statement. Scope Resolution Operator When a local variable has the same name as a global variable, all references to the variable name made within the local variable’s scope refer to the local variable. This situation is illustrated in Program 6.16, where the variable name number is defined as both a global and local variable. When Program 6.16 is run, the following output is displayed: The value of number is 26.4 char int bool double local char int bool double global Scope Data type Figure 6.16 Relating the scope and type of a variable 349 Chapter 6 Variable Scope
  • 370. Program 6.16 #include <iostream> using namespace std; double number = 42.8; // a global variable named number int main() { double number = 26.4; // a local variable named number cout << "The value of number is " << number << endl; return 0; } As shown by the program’s output, the local variable name takes precedence over the global variable. In these cases, you can still access the global variable by using C++’s scope resolution operator, which has the symbol ::. This operator must be placed immediately before the variable name, as in ::number. When used in this manner, the :: tells the compiler to use the global variable. As an example, the scope resolution operator is used in Program 6.16a. Program 6.16a #include <iostream> using namespace std; double number = 42.5; // a global variable named number int main() { double number = 26.4; // a local variable named number cout << "The value of number is " << ::number << endl; return 0; } 350 Modularity Using Functions
  • 371. This is the output produced by Program 6.16a: The value of number is 42.5 As indicated by this output, the scope resolution operator causes the global, rather than the local, variable to be accessed. Misuse of Globals Global variables allow programmers to “jump around” the normal safeguards provided by functions. Instead of passing variables to a function, it’s possible to make all variables global. Do not do this. By indiscriminately making all variables global, you destroy the safeguards C++ provides to make functions independent and insulated from each other, including carefully designating the type of arguments a function needs, the variables used in the function, and the value returned. Using only global variables can be especially disastrous in large programs with many user-created functions. Because all variables in a function must be declared, creating functions that use global variables requires remembering to write the appropriate global declarations at the top of each program using the function—they no longer come along with the function. More devastating, however, is trying to track down an error in a large program with global variables. Because a global variable can be accessed and changed by any function following the global declaration, locating the origin of an erroneous value is a time-consuming and frustrating task. Global definitions, however, are sometimes useful in creating variables and constants that must be shared between many functions. Instead of passing the same variable to each function, defining the variable once as global is easier. Doing so also alerts anyone reading the program that many functions use the variable. Most large programs almost always make use of a few global variables or constants. Smaller programs containing a few functions, however, should almost never contain global variables. The misuse of globals doesn’t apply to function prototypes, which typically are global. All the function prototypes you have used have been of global scope, which declares the prototype to all subsequent functions. Placing a function prototype in a function makes the prototype a local declaration, which makes it available only to the function it’s declared within. EXERCISES 6.5 1. (Practice) a. For the following section of code, determine the data type and scope of all declared variables on a separate sheet of paper, using the column headings shown in the following chart. (The entries for the first variable have been filled in.) Variable Name Data Type Scope volts int global to main(), roi(), and step() 351 Chapter 6 Variable Scope
  • 372. #include <iostream> using namespace std; int volts; long int resistance; double current; int main() { int power; double factor, time; . . return 0; } double roi(int mat1, int mat2) { int count; double weight; . . return weight; } int step(double first, double last) { int hours; double fracpart; . . return 10*hours; } b. Draw boxes around the appropriate section of the preceding code to enclose each vari- able’s scope. c. Determine the data type of parameters that the roi() and step() functions expect and the data type of the value these functions return. 2. (Practice) a. For the following section of code, determine the data type and scope of all declared variables on a separate sheet of paper, using the column headings shown in the following chart. (The entries for the first variable have been filled in.) Variable Name Data Type Scope key char global to main(), func1(), and func2() #include <iostream> using namespace std; char key; long int number; 墌 352 Modularity Using Functions
  • 373. int main() { int a,b,c; double x,y; . . return 0; } double secnum; int func1(int num1, int num2) { int o,p; float q; . . return p; } double func2(double first, double last) { int a,b,c,o,p; double r; double s,t,x; . . return s * t; } b. Draw a box around the appropriate section of the preceding code to enclose the scope of the variables key, secnum, y, and r. c. Determine the data type of the arguments that the func1() and func2() functions expect and the data type of the value these functions return. 3. (Practice) The term “scope” can also apply to a function’s parameters. What do you think is the scope of all function parameters? 4. (Practice) Define the scope of the parameter p2 and the variables a, b, c, d, m, n, p, d, q, and r in the following program structure: #include <iostream> using namespace std; int a, b; double One(float); void Two(void); int main() { int c, d; double e, f; . . return 0; } 墌 353 Chapter 6 Variable Scope
  • 374. double One(double p2) { char m, n; . . } void Two(void) { int p, d; double q, r; . . } 5. (Desk Check) Determine the values displayed by each cout statement in the following program: #include <iostream> using namespace std; int firstnum = 10; // declare and initialize a global variable void display(); // function prototype int main() { int firstnum = 20; // declare and initialize a local variable cout << "nThe value of firstnum is " << firstnum << endl; display(); return 0; } void display(void) { cout << "The value of firstnum is now " << firstnum << endl; return; } 6.6 Variable Storage Categories The scope of a variable defines the location in a program where that variable can be used. If you draw a box around the section of program code where each variable is valid, the space inside the box would represent the variable’s scope. From this viewpoint, a variable’s scope can be thought of as the space in the program where the variable is valid. In addition to the space dimension represented by scope, variables have a time dimension that refers to the length of time storage locations are reserved for a variable. This time dimension is referred to as the variable’s lifetime. For example, all variable storage 354 Modularity Using Functions
  • 375. locations are released back to the computer when a program is finished running. However, while a program is still executing, interim variable storage locations are reserved and subsequently released back to the computer. Where and how long a variable’s storage locations are kept before they’re released can be determined by the variable’s storage category. Besides having a data type and scope, every variable has a storage category. The four available storage categories are auto, static, extern, and register. If one of these category names is used, it must be placed before the variable’s data type in a declaration statement. The following are examples of declaration statements that include a storage category designation: auto int num; // auto storage category and int data type static int miles; // static storage category and int data type register int dist; // register storage category and int data type extern int volts; // extern storage category and int data type auto float coupon; // auto storage category and float data type static double yrs; // static storage category and double data type extern float yld; // extern storage category and float data type auto char inKey; // auto storage category and char variable type To understand what a variable’s storage category means, next you examine local variables (created inside a function) and then global variables (created outside a function). Local Variable Storage Categories Local variables can be members only of the auto, static, or register storage categories. If no category description is included in the declaration statement, the variable is assigned to the auto category automatically, so auto is the default category C++ uses. All the local variables you have used have been auto variables because the storage category designation was omitted. The term auto is short for “automatic.” Storage for automatic local variables is reserved or created automatically each time a function declaring automatic variables is called. As long as the function hasn’t returned control to its calling function, all automatic variables local to the function are “alive”—meaning storage for the variables is available. When the function returns control to its calling function, its local automatic variables “die”—meaning storage for the variables is released back to the computer. This process repeats each time a function is called. For example, in Program 6.17, the testauto() function is called three times from main(). This is the output produced by Program 6.17: The value of the automatic variable num is 0 The value of the automatic variable num is 0 The value of the automatic variable num is 0 355 Chapter 6 Variable Storage Categories
  • 376. Program 6.17 #include <iostream> using namespace std; void testauto(); // function prototype int main() { int count; // count is a local auto variable for(count = 1; count <= 3; count++) testauto(); return 0; } void testauto() { int num = 0; // num is a local auto variable // initialized to 0 cout << "The value of the automatic variable num is " << num << endl; num++; return; } Each time testauto() is called, the automatic variable num is created and initialized to 0. When the function returns control to main(), the variable num is destroyed along with any value stored in num. Therefore, the effect of incrementing num in testauto(), before the function’s return statement, is lost when control is returned to main(). For most applications, the use of automatic variables works just fine. In some cases, however, you want a function to remember values between function calls, which is the purpose of the static storage category. A local variable declared as static causes the program to keep the variable and its latest value even when the function that declared it has finished executing. The following are examples of static variable declarations: static int rate; static double resistance; static char inKey; 356 Modularity Using Functions
  • 377. A local static variable isn’t created and destroyed each time the function declaring it is called. After they’re created, local static variables remain in existence for the program’s lifetime. This means the last value stored in the variable when the function finishes executing is available to the function the next time it’s called. Because local static variables retain their values, they aren’t initialized in a declaration statement in the same way as automatic variables. To understand why, consider the automatic declaration int num = 0;, which causes the automatic variable num to be created and set to 0 each time the declaration is encountered. This procedure is called a runtime initialization because initialization occurs each time the declaration statement is encountered. This type of initialization would be disastrous for a static variable because resetting the variable’s value to 0 each time the function is called destroys the very value you’re trying to save. Initialization of static variables (both local and global) is done only once, when the program is first compiled. At compile time, the variable is created and any initialization value is placed in it.14 Thereafter, the value in the variable is kept without further initialization. To see how this process works, examine Program 6.18. Program 6.18 #include <iostream> using namespace std; void teststat(); // function prototypeint main() { int count; // count is a local auto variable for(count = 1; count <= 3; count++) teststat(); return 0; } void teststat() { static int num = 0; // num is a local static variable cout << "The value of the static variable num is now " << num << endl; num++; return; } 14 Some compilers initialize static local variables the first time the definition statement is executed rather than when the program is compiled. 357 Chapter 6 Variable Storage Categories
  • 378. This is the output produced by Program 6.18: The value of the static variable num is now 0 The value of the static variable num is now 1 The value of the static variable num is now 2 As this output shows, the static variable num is set to 0 only once. The teststat() function then increments this variable just before returning control to main(). The value num has when leaving the teststat() function is retained and displayed when the function is next called. Unlike automatic variables that can be initialized by constants or expressions using both constants and previously initialized variables, static variables can be initialized only by using constants or constant expressions, such as 3.2 + 8.0. Also, unlike automatic variables, all static variables are set to 0 when no explicit initialization is given. Therefore, the specific initialization of num to 0 in Program 6.17 isn’t required. The remaining storage category available to local variables, register, isn’t used as extensively as auto or static variables. The following are examples of register variable declarations: register int time; register double diffren; register float coupon; The register variables have the same time duration as auto variables; that is, a local register variable is created when the function declaring it is entered and is destroyed when the function finishes running. The only difference between register and auto variables is where storage for the variable is located. Storage for all variables (local and global), except register variables, is reserved in the computer’s memory. Most computers also have a few high-speed storage areas, called registers, located in the CPU that can also be used for variable storage. Because registers are located in the CPU, they can be accessed faster than the normal memory storage areas located in the computer’s memory unit. Also, computer instructions referencing registers typically require less space than instructions referencing memory locations because there are fewer registers than memory locations that can be accessed. When the compiler substitutes a register’s location for a variable during program compilation, the instruction needs less space than address memory having millions of locations. Besides decreasing a compiled C++ program’s size, using register variables can increase the program’s execution speed if your computer supports this data type. Application programs intended to be executed on different types of computers shouldn’t use registers, however. Generally, the compiler foils attempts to do so by switching variables declared with the register storage category to the auto storage category automatically. The only restriction in using the register storage category is that a register variable’s address can’t be taken by using the address operator, &. This concept is easier to understand when you realize that registers don’t have standard memory addresses. Global Variable Storage Categories Global variables are created by definition statements external to a function. By their nature, these externally defined variables don’t come and go with the calling of a function. After a global variable is created, it exists until the program in which it’s declared has finished executing. Therefore, global variables can’t be declared as auto or register variables that 358 Modularity Using Functions
  • 379. are created and destroyed as the program is running. Global variables can be declared with the static or extern storage category (but not both). The following are examples of declaration statements including these two category descriptions: extern int sum; extern double volts; static double current; The static and extern storage categories affect only the scope, not the lifetime, of global variables. As with static local variables, all global variables are initialized to 0 at compile time. The purpose of the extern storage category is to extend a global variable’s scope beyond its normal boundaries. To understand this concept, first note that all the programs written so far have been contained in one file. Therefore, when you have saved or retrieved programs, you have needed to give the computer only a single name for your program. C++ doesn’t require doing this, however. Large programs typically consist of many functions stored in multiple files. For example, Figure 6.17 shows the three functions main(), func1(), and func2() stored in one file and the two functions func3() and func4() stored in a second file. int volts; double current; static double power; . . . int main() { func1(); func2(); func3(); func4(); } int func1() { . . . } int func2() { . . . } file1 file2 double factor; int func3() { . . . } int func4() . . . } Figure 6.17 A program can extend beyond one file 359 Chapter 6 Variable Storage Categories
  • 380. For the files shown in Figure 6.17, the global variables volts, current, and power declared in file1 can be used only by the functions main(), func1(), and func2() in this file. The single global variable, factor, declared in file2 can be used only by the functions func3() and func4() in file2. Although the variable volts has been created in file1, you might want to use it in file2. To do this, you place the declaration statement extern int volts; in file2, as shown in Figure 6.18. Putting this statement at the top of file2 extends the scope of volts into file2 so that it can be used by both func3() and func4(). The extern designation simply declares a global variable that’s defined in another file. So placing the statement extern double current; in func4() extends the scope of this global variable, created in file1, into func4(). Additionally, the scope of the global variable factor, created in file2, is extended into func1() and func2() by the declaration statement extern double factor; placed before func1(). Notice that factor is not available to main(). A declaration statement containing the word extern is different from other declaration statements, in that it doesn’t cause a new variable to be created by reserving new storage for the variable. An extern declaration statement simply informs the computer that a global int volts; double current; static double power; . . . int main() { func1(); func2(); func3(); func4(); } extern double factor; int func1() { . . . } int func2() { . . . } file1 file2 double factor; extern int volts; int func3() { . . . } int func4() { extern double current; . . . } Figure 6.18 Extending the scope of global variables 360 Modularity Using Functions
  • 381. variable already exists and can now be used. The actual storage for the variable must be created somewhere else in the program by using one, and only one, global declaration statement in which the word extern hasn’t been used. The global variable can, of course, be initialized in its original declaration. Initialization in an extern declaration statement is not allowed, however, and causes a compilation error. The existence of the extern storage category is the reason for carefully distinguishing between the creation and declaration of a variable. Declaration statements containing the word extern don’t create new storage areas; they only extend the scope of existing global variables. The last global storage category, static, is used to prevent extending a global variable into a second file. Global static variables are declared in the same way as local static variables, except the declaration statement is placed outside any function. The scope of a global static variable can’t be extended beyond the file in which it’s declared. This rule provides a degree of privacy for global static variables. Because they are “known” and can be used only in the file where they’re declared, other files can’t access or change their values. Therefore, global static variables can’t subsequently be extended to a second file by using an extern declaration statement. Trying to do so results in a compilation error. EXERCISES 6.6 1. (Practice) a. List the storage categories available to local variables. b. List the storage categories available to global variables. 2. (Practice) Describe the difference between a local auto variable and a local static variable. 3. (Practice) What is the difference between the following functions? void init1() { static int yrs = 1; 墌 Point of Information Storage Categories Variables of type auto and register are always local variables. Only non-static global variables can be declared by using the extern keyword. Doing so extends the variable’s scope into another file or function. Making a global variable static makes the variable private to the file in which it’s declared. Therefore, static variables can’t use the extern keyword. Except for static variables, all variables are initialized each time they come into scope; static variables are initialized only once, when they’re defined. 361 Chapter 6 Variable Storage Categories
  • 382. cout << "The value of yrs is " << yrs << endl; yrs = yrs + 2; return; } void init2() { static int yrs; yrs = 1; cout << "The value of yrs is " << yrs << endl; yrs = yrs + 2; return; } 4. (Practice) a. Describe the difference between a global static variable and a global extern variable. b. If a variable is declared with an extern storage category, what other declaration statement must be present somewhere in the program? 5. (Practice) The declaration statement static double resistance; can be used to create a local or global static variable. What determines the scope of the variable resistance? 6. (Practice) For the function and variable declarations shown in Figure 6.19, place an extern declaration to accomplish each of the following: a. Extend the scope of the global variable choice into file2. b. Extend the scope of the global variable flag into the average() function only. c. Extend the scope of the global variable date into average() and variance(). d. Extend the scope of the global variable date into roi() only. e. Extend the scope of the global variable factor into roi() only. f. Extend the scope of the global variable bondtype into file1. g. Extend the scope of the global variable resistance into both watts() and thrust(). 6.7 Common Programming Errors The following programming errors are common when constructing and using functions: 1. An extremely common error related to functions is passing incorrect data types. The values passed to a function must correspond to the data types of parameters declared for the function. One way to verify that correct values have been received is to 362 Modularity Using Functions
  • 383. display all passed values in the function body before any calculations are made. After this verification has taken place, you can dispense with the display.15 2. Another common error can occur when the same variable is declared locally in both the calling and called functions. Even though the variable name is the same, a change to one local variable does not alter the value in the other local variable. 3. A related error is one that can occur when a local variable has the same name as a global variable. Inside the function declaring it, the use of the variable’s name affects only the local variable’s contents unless the scope resolution operator, ::, is used. 4. Another common error is omitting the called function’s prototype before or within the calling function. The called function must be alerted to the type of value to be returned, and the function prototype provides this information. The prototype can be omitted if the called function is placed in a program before its calling function. Although omitting the prototype and return type for functions returning an integer is permitted, doing so is poor documenting practice. The actual value a function returns can be verified by displaying it both before and after it’s returned. 5. The last two common errors are terminating a function header with a semicolon and forgetting to include the data type of a function’s parameters in the function header. 15 In practice, a good debugger program should be used. char choice; int flag; long date, time; int main() { . . . } double factor; double watts() { . . . } double thrust() { . . . } file1 file2 char bondtype; double resistance; double roi() { . . . } double average() { . . . } double variance { . . . } Figure 6.19 Files for Exercise 6 363 Chapter 6 Common Programming Errors
  • 384. 6.8 Chapter Summary 1. A function is called by giving its name and passing any data to it in the parentheses following the name. If a variable is one of the arguments in a function call, the called function receives a copy of the variable’s value. 2. The common form of a user-written function is as follows: returnDataType functionName(parameter list) { // declarations and other C++ statements; // return expression; } The first line of the function is called the function header. The opening and closing braces of the function and all statements between these braces constitute the function body. The returned data type is, by default, an integer when no returned data type is specified. The parameter list is a comma-separated list of parameter declarations. 3. A function’s return type is the data type of the value the function returns. If no type is declared, the function is assumed to return an integer value. If the function doesn’t return a value, it should be declared as a void type. 4. Functions can return at most a single data type value to their calling functions. This value is the value of the expression in the return statement. 5. Arguments passed to a function, when it’s called, must conform to the parameters specified by the function header in terms of order, number of arguments, and specified data type. 6. Using reference parameters, a variable’s address is passed to a function. If a called function is passed an address, it has the capability to access the calling function’s variable. Using passed addresses permits a called function to return multiple values. 7. Functions can be declared to all calling functions by means of a function prototype. The prototype provides a declaration for a function that specifies the data type the function returns, the function’s name, and the data types of the arguments the function expects. As with all declarations, a function prototype is terminated with a semicolon and can be included in local variable declarations or as a global declaration. This is the most common form of a function prototype: dataType functionName(parameter data type list); If the called function is placed above the calling function in the program, no further declaration is required because the function’s definition serves as a global declaration to all subsequent functions. 8. Every variable in a program has a scope, which determines where in the program the variable can be used. A variable’s scope is local or global and is determined by where the variable’s definition statement is placed. A local variable is defined in a function and can be used only in its defining function or block. A global variable is defined outside a function and can be used in any function following the variable’s definition. All global variables that aren’t specifically initialized by the user are initialized to 0 by the compiler, and global variables not declared as static can be shared between files by using the keyword extern. 364 Modularity Using Functions
  • 385. 9. Every variable also has a storage category, which determines how long the value in the variable is retained, also known as the variable’s lifetime. auto variables are local variables that exist only while their defining function is executing; register variables are similar to auto variables but are stored in a computer’s registers rather than in memory; and static variables can be global or local and retain their values while the program is running. All static variables are set to 0 when they’re defined if the user doesn’t initialize them explicitly. Programming Projects for Chapter 6 1. (Practice) The volume, V, of a right circular cylinder is given by the formula V = ␲ r2 h where r is the cylinder’s radius and h is the cylinder’s height. Write a function that accepts two double-precision arguments—a cylinder’s radius and height—and returns the cylinder’s volume. 2. (Practice) a. Write a function that calculates the area, a, of a circle when its circumfer- ence, c, is given. This function should call a second function that returns the radius, r, of the circle, given c. The relevant formulas are r = c/2␲ and a = ␲r2 . b. Write a C++ program that accepts the value of the circumference from the user, calculates the radius and area, and displays the calculated values. Your program should use the functions written for Exercise 2a. 3. (Practice) Write a function named pass() that returns a reject or accept code depending on whether the mean tolerance of a group of parts is less than or greater than 1.0%. If the average is less than 1.0%, the function should return an A for accept; otherwise, it should return an R for reject. 4. (Practice) A function is defined by the following code: double FractionToDecimal(double numerator, double denominator) { return (numerator/denominator); } a. Write the shortest front-end driver you can to test this function and check the passing of parameters. b. Complete the FractionToDecimal() function so that it correctly calculates and returns the decimal value of values passed to it when it’s called. 5. (Data Processing) a. The time in hours, minutes, and seconds is to be passed to a function named totsec(). Write totsec() to accept these values, determine the total number of seconds in the passed data, and display the calculated value. b. Include the totsec() function written for Exercise 5a in a working program. The main() function should correctly call totsec() and display the value the function returns. Use the following test data to verify your program’s operation: hours = 10, minutes = 36, and seconds = 54. Make sure to do a hand calculation to verify the result your program displays. 365 Chapter 6 Programming Projects
  • 386. 6. (Data Processing) a. Write a function named daycount() that accepts a month, day, and year as its input arguments; calculates an integer representing the total number of days from the turn of the century to the date that’s passed; and returns the calculated integer to the calling function. For this problem, assume each year has 365 days and each month has 30 days. Test your function by verifying that the date 1/1/00 returns a day count of 1. b. Include the daycount() function written for Exercise 6a in a working program. The main() function should correctly call daycount() and display the integer returned by the function. 7. (Data Processing) a. A clever and simple method of preparing to sort dates into ascending (increasing) or descending (decreasing) order is to convert a date in the form month/day/year into an integer number with the formula date = year × 10000 + month × 100 + day. For example, using this formula, the date 12/6/1988 converts to the integer 19881206, and the date 2/28/2010 converts to the integer 20100228. Sorting the resulting integer numbers puts dates into the correct order automatically. Using this formula, write a function named convertdays() that accepts a month, day, and year; converts the passed data into a single date integer; and returns the integer to the calling function. b. Include the convertdays() function written for Exercise 7a in a working program. The main() function should call convertdays() correctly and display the integer the function returns. 8. (Data Processing) Write a program that reads a key pressed on the keyboard and displays its code on the screen. Use the program to determine the code for the Enter key. Then write a function named ReadOneChar() that reads a character and ignores any succeeding characters until the Enter key is pressed. The entered character should be returned by ReadOneChar(). 9. (Conversion) a. Write and test a C++ function named MakeMilesKmTable() to display a table of miles converted to kilometers. The arguments to the function should be the starting and stopping values of miles and the increment. The output should be a table of miles and their equivalent kilometer values. Use the relationship that 1 mile = 1.61 kilometers. b. Modify the function written for Exercise 9a so that two columns are printed. For example, if the starting value is 1 mile, the ending value is 20 miles, and the increment is 1, the display should look like the following: Miles = Kilometers Miles = Kilometers 1 1.61 11 17.70 2 3.22 12 19.31 . . . . . . . . 10 16.09 20 32.18 (Hint: Find split = (start + stop)/2. Let a loop execute from miles = start to split, and calculate and print across one line the values of miles and kilometers for both miles and (miles - start + split + 1).) 366 Modularity Using Functions
  • 387. 10. (Conversion) Your company will soon open a new office in France. So that it can do business there, your manager has asked you to prepare a comprehensive package that performs the following American-to-metric conversions on demand: Measure American Metric Formula distance inch foot yard mile centimeter meter meter kilometer 2.54 cm/in 0.305 m/ft 0.9144 m/yd 1.6109 km/mi temperature Fahrenheit Celsius C = (5/9)(F - 32) weight pound ounce kilogram gram 0.454 kg/lb 28.35 gm/oz currency dollar franc entered by the user, about 5 francs/$ capacity quart teaspoon liter milliliter 0.946 liter/qt 4.9 ml/tsp math degree degree radian grad rad = (␲/180)(degree) grad = (200/180)(degree) 11. (Numerical) Heron’s formula for the area, A, of a triangle with sides of length a, b, and c is A s s a s b s c = ( )( )( )     - - - where s a b c = + + ( ) 2 Write, test, and execute a function that accepts the values of a, b, and c as parameters from a calling function, and then calculates the values of s and [s(s - a)(s - b)(s - c)]. If this quantity is positive, the function calculates A. If the quantity is negative, a, b, and c do not form a triangle, and the function should set A = -1. The value of A should be returned by the function. 12. (Numerical) A formula to raise a real number, a, to the real power, b, is given by the formula a e b b a = × ( )     ln where a must be positive and b must be positive or 0. Using this formula, write a function named power() that accepts a and b as real values and returns ab . 13. (Numerical) A fraction-handling program contains this menu: A. Add two fractions B. Convert a fraction to decimal C. Multiply two fractions Q. Quit a. Write C++ code for the program with stub functions for the choices. 367 Chapter 6 Programming Projects
  • 388. b. Insert the FractionToDecimal() function from Exercise 4b into the code with commands to pass and display the parameters. c. Complete the program by replacing the stub functions with functions that perform appropriate operations. 14. (Numerical) A value that’s sometimes useful is the greatest common divisor of two integers, n1 and n2. Euclid discovered an efficient method to do this more than 2000 years ago. For this exercise, however, a stub is enough. Write the integer function stub gcd(n1, n2). Simply have it return a value that suggests it received its arguments correctly. (Hint: N1 + N2 is a good choice of return values. Why isn’t N1 / N2 a good choice?) 15. (Numerical) a. Euclid’s method for finding the greatest common divisor (GCD) of two positive integers consists of the following steps: Step 1: Divide the larger number by the smaller and retain the remainder. Step 2: Divide the smaller number by the remainder, again retaining the remainder. Step 3: Continue dividing the previous remainder by the current remainder until the remainder is zero, at which point the last non-zero remainder is the GCD. For example, if the two positive integers are 84 and 49, you have the following: Step 1: 84/49 yields a remainder of 35. Step 2: 49/35 yields a remainder of 14. Step 3: 35/14 yields a remainder of 7. Step 3: 14/7 yields a remainder of 0. Therefore, the last non-zero remainder, which is 7, is the GCD of 84 and 49. Using Euclid’s algorithm, replace the stub function written for Exercise 14 with an actual function that determines and returns the GCD of its two integer arguments. 16. (Data Processing) a. Write a function named date() that accepts a long integer of the form yyyymmdd, such as 19980412; determines the corresponding month, day, and year; and returns these three values to the calling function. For example, if date is called by using the statement date(20110412, &month, &day, &year) the number 4 should be returned in month, the number 12 in day, and the number 2011 in year. b. Include the date() function written for Exercise 16a in a working program. The main() function should call date() and display the three values returned by the function. 368 Modularity Using Functions
  • 389. 17. (Numerical) The determinant of the 2 by 2 matrix a a a a 11 12 21 22 is defined as the scalar value a11a22 - a21a12. Similarly, the determinant of a 3 by 3 matrix, defined as a a a a a a a a a 11 12 13 21 22 23 31 32 33 is determined as a a a a a a a a a a a a 11 22 23 32 33 21 12 13 32 33 31 12 - + a a a a 13 22 23 a. Using this information, write and test two functions named det2() and det3(). The det2() function should accept the four coefficients of a 2 by 2 matrix and return its determinant. The det3() function should accept the nine coefficients of a 3 by 3 matrix and return its determinant by calling det2() to calculate the required 2 by 2 determinants. b. Write and run a C++ program that accepts the nine coefficients of a 3 by 3 matrix in one function, passes these coefficients to det3(), and uses a third function to display the calculated determinant. 369 Chapter 6 Programming Projects
  • 390. Engineering and Scientific Disciplines Chemical Engineering Chemical engineering is the application of the knowledge or techniques of science, par- ticularly chemistry, to industry. Chemical engineers are responsible for designing and operating large-scale manufacturing plants for materials that undergo chemical changes in their production. These materials include all the new and improved products that have so profoundly affected society, such as petrochemicals, rubbers and polymers, new metal alloys, industrial and fine chemicals, foods, paints, detergents, cements, pesti- cides, industrial gases, and medicines. Chemical engineers also play an important role in pollution abatement and man- agement of existing energy resources. Because the field of chemical engineering has become so broad, classifying the activities of chemical engineers is difficult. They can be subdivided roughly into large-scale production systems (chemical processing) and smaller scale (molecular) systems. Chemical Processing Chemical processing concerns all aspects of designing and operating large chemical- processing plants. It includes the following areas: 앫 Petrochemicals: Distilling and refining fuels, such as gasoline, synthetic natural gas, and coal liquefaction and gasification, and producing an infinite variety of petroleum products, from cosmetics to pharmaceuticals. 앫 Synthetic materials: The process of polymerization, joining simple molecules into large complex molecules, is responsible for many modern materials, such as nylon, synthetic rubbers, polystyrene, and a wide variety of plastics and synthetic fibers. 앫 Food and biochemical engineering: The manufacture of packaged food, improve- ment of food additives, sterilization, and use of industrial bacteria, fungi, and yeasts in processes such as fermentation. 앫 Unit operations: Analyzing the transport of heat or fluid, such as pumping chemicals through a pipeline or transferring heat between substances. This area also includes the effect of heat transfer on chemical reactions, such as oxidation, chlorination, and so on. 앫 Cryogenic engineering: The design of plants operating at temperatures near absolute zero. 앫 Electrochemical engineering: Using electricity to alter chemical reactions, such as electroplating, or designing batteries and energy cells. 앫 Pollution control: Monitoring and reducing the harmful effects of chemical processing on the environment. Topics of concern are wastewater control, air pollution abatement, and the economics of pollution control. continued... 370 Modularity Using Functions
  • 391. Engineering and Scientific Disciplines Molecular Systems This field involves applying laboratory techniques to large-scale processes and includes the following areas: 앫 Biochemical engineering: Application of enzymes, bacteria, and so on to improve large-scale chemical processes. 앫 Polymer synthesis: Molecular basis for polymer properties and the chemical synthesis of new polymers adapted for large-scale production. 앫 Research and development in all areas of chemical processing. Preparation for a career in chemical engineering requires a thorough background in physics, chemistry, and mathematics and a knowledge of thermodynamics and physical, analytic, and organic chemistry. Although extensively trained in chemistry, chemical engineers differ from chemists, in that their main concern is adapting laboratory tech- niques to large-scale manufacturing plants. 371 Chapter 6 Programming Projects
  • 392. This page intentionally left blank
  • 393. Chapter 7 Arrays 7.1 One-Dimensional Arrays 7.2 Array Initialization 7.3 Declaring and Processing Two- Dimensional Arrays 7.4 Arrays as Arguments 7.5 A Case Study: Statistical Analysis 7.6 The Standard Template Library (STL) 7.7 A Closer Look: Searching and Sorting 7.8 Common Programming Errors 7.9 Chapter Summary All the variables you have used so far have a common characteristic: Each variable can be used to store only a single value at a time. For example, although the variables key, count, and grade declared in the statements char key; int count; double grade; are of different data types, each variable can store only one value of the declared data type. These types of variables are called atomic variables (also referred to as scalar variables), which means their values can’t be further subdivided or separated into a legitimate data type.
  • 394. Often you have a set of values, all the same data type, that form a logical group. For example, the following lists show three groups of items: 1) a list of five double-precision temperatures, 2) a list of four character codes, and 3) a list of six integer voltages: Temperatures Codes Voltages 95.75 Z 98 83.0 C 87 97.625 K 92 72.5 L 79 86.25 85 72 A simple list containing items of the same data type is called a one-dimensional array. This chapter describes how one-dimensional arrays are declared, initialized, stored in a computer, and used. You also explore the use of one-dimensional arrays with sample programs and see the procedures for declaring and using multidimensional arrays. 7.1 One-Dimensional Arrays A one-dimensional array, also referred to as a single-dimensional array, is a list of related values, all having the same data type, that’s stored with a single group name.1 In C++, as in other computer languages, the group name is referred to as the array name. For example, consider this list of temperatures: 95.75 83.0 97.625 72.5 86.25 All the temperatures in the list are double-precision numbers and must be declared as such. However, each item in the list doesn’t have to be declared separately. The items in the list can be declared as a single unit and stored under a common variable name called the array name. For example, temp is used as the name for this list, and the declaration statement double temp[5]; specifies that temp is to store five double-precision values. Notice that this declaration statement gives the array (or list) name, the data type of items in the array, and the number of items in the array. It’s a specific example of the general syntax of an array declaration statement: dataType arrayName[number-of-items] 1 Lists can be implemented in a variety of ways. An array is simply one list implementation in which all list elements are of the same type, and each element is stored consecutively in a set of contiguous memory locations. 374 Arrays
  • 395. Good programming practice requires defining number-of-items in the array as a constant before declaring the array. So in practice, the previous array declaration for temp would be declared with two statements, as in these examples: const int NUMELS = 5; // define a constant for the number of items double temp[NUMELS]; // declare the array The following are other examples of array declarations using this two-line syntax: const int NUMELS = 6; int volts[NUMELS]; const int ARRAYSIZE = 4; char code[ARRAYSIZE]; const int SIZE = 100; double amount[SIZE]; In these declaration statements, each array is allocated enough memory to hold the number of data items specified in the declaration statement. For example, the array named volts has storage reserved for six integers, the array named code has storage reserved for four characters, and the array named amount has storage reserved for 100 double-precision numbers. The constant identifiers, NUMELS, ARRAYSIZE, and SIZE, are programmer- selected names. Figure 7.1 illustrates the storage reserved for the volts and code arrays. Each item in an array is called an element or a component of the array. The elements in the arrays shown in Figure 7.1 are stored sequentially, with the first element stored in the first reserved location, the second element stored in the second reserved location, and so on until the last element is stored in the last reserved location. This contiguous storage allocation is a key feature of arrays because it provides a simple mechanism for locating any element in the list easily. Because elements in the array are stored sequentially, any single element can be accessed by giving the array’s name and the element’s position. This position is called the element’s Enough storage for six integers an integer an integer an integer an integer an integer an integer volts array a character a character a character a character code array Enough storage for four characters Figure 7.1 The volts and code arrays in memory 375 Chapter 7 One-Dimensional Arrays
  • 396. index or subscript value. (The two terms are synonymous.) For a one-dimensional array, the first element has an index of 0, the second element has an index of 1, and so on. In C++, the array name and element index are combined by listing the index in brackets after the array name. For example, the declaration double temp[5]; creates five elements, with the following correspondences: temp[0] refers to the first temperature stored in the temp array temp[1] refers to the second temperature stored in the temp array temp[2] refers to the third temperature stored in the temp array temp[3] refers to the fourth temperature stored in the temp array temp[4] refers to the fifth temperature stored in the temp array Figure 7.2 illustrates the temp array in memory with the correct designation for each array element. Each element is referred to as an indexed variable or a subscripted variable because both a variable name (the array name, in this case) and an index or a subscript value must be used to reference the element. Remember that the index or subscript value gives the element’s position in the array. The subscripted variable, temp[0], is read as “temp sub zero” or “temp zero.” This is a shortened way of saying “the temp array subscripted by zero.” Similarly, temp[1] is read as “temp sub one” or “temp one,” temp[2] as “temp sub two” or “temp two,” and so on. Although referencing the first element with an index of 0 might seem unusual, doing so increases the computer’s speed when it accesses array elements. Internally, unseen by the programmer, the computer uses the index as an offset from the array’s starting position. As illustrated in Figure 7.3, the index tells the computer how many elements to skip, starting from the beginning of the array, to get to the desired element. Subscripted variables can be used anywhere that scalar (atomic) variables are valid. Here are examples of using the elements of the temp array: temp[0] = 95.75; temp[1] = temp[0] - 11.0; temp[2] = 5.0 * temp[0]; temp[3] = 79.0; temp[4] = (temp[1] + temp[2] - 3.1) / 2.2; sum = temp[0] + temp[1] + temp[2] + temp[3] + temp[4]; The subscript in brackets need not be an integer constant; any expression that evaluates to an integer can be used as a subscript.2 In each case, of course, the value of the expression 2 Some compilers permit floating-point variables as subscripts; in these cases, the floating-point value is truncated to an integer value. temp[0] temp[1] temp[2] temp[3] temp[4] temp array element 0 element 1 element 2 element 3 element 4 Figure 7.2 Identifying array elements 376 Arrays
  • 397. must be within the valid subscript range defined when the array is declared. For example, assuming i and j are int variables, the following subscripted variables are valid: temp[i] temp[2*i] temp[j-i] An important advantage of using integer expressions as subscripts is that it allows sequencing through an array by using a loop. This makes statements such as the following unnecessary: sum = temp[0] + temp[1] + temp[2] + temp[3] + temp[4]; The subscript values in this statement can be replaced by a for loop counter to access each element in the array sequentially. For example, the code sum = 0; // initialize the sum to zero for (i = 0; i < 5; i++) sum = sum + temp[i]; // add in a value retrieves each array element sequentially and adds the element to sum. The variable i is used as both the counter in the for loop and a subscript. As i increases by one each time through the loop, the next element in the array is referenced. The procedure for adding array elements in the for loop is similar to the accumulation procedure you have used before. The advantage of using a for loop to sequence through an array becomes apparent when working with larger arrays. For example, if the temp array contains 100 values rather than just 5, simply changing the number 5 to 100 in the for statement is enough to sequence through the 100 elements and add each temperature to the sum. As another example of using a for loop to sequence through an array, say you want to locate the maximum value in an array of 1000 elements named volts. The procedure to locate the maximum value is to assume initially that the first element in the array is the largest number. Then, as you sequence through the array, the maximum is compared to each Start here The array name temp identifies the starting location of the array Skip over three elements to get to the starting location of element 3 temp[0] temp[1] temp[2] temp[3] temp[4] element 3 Figure 7.3 Accessing an array element—element 3 377 Chapter 7 One-Dimensional Arrays
  • 398. element. When an element with a higher value is located, that element becomes the new maximum. The following code does the job: const int NUMELS = 1000; maximum = volts[0]; // set the maximum to element 0 for (i = 1; i < NUMELS; i++) // cycle through the rest of the array if (volts[i] > maximum) // compare each element to the maximum maximum = volts[i]; // capture the new high value In this code, the for statement consists of one if statement. The search for a new maximum value starts with element 1 of the array and continues through the last element. Each element is compared to the current maximum, and when a higher value is encountered, it becomes the new maximum. Input and Output of Array Values An array element can be assigned a value interactively by using a cin statement, as shown in these examples of data entry statements: cin >> temp[0]; cin >> temp[1] >> temp[2] >> temp[3]; cin >> temp[4] >> volts[6]; In the first statement, a single value is read and stored in the variable temp[0]. The second statement causes three values to be read and stored in the variables temp[1], temp[2], and temp[3]. Finally, the last cin statement is used to read values into the variables temp[4] and volts[6]. Alternatively, a for loop can be used to cycle through the array for interactive data input. For example, the following code prompts the user for five temperatures: const int NUMELS = 5; for(i = 0; i < NUMELS; i++) { cout << "Enter a temperature: "; cin >> temp[i]; } Point of Information Aggregate Data Types In contrast to atomic types, such as integer and floating-point data, there are aggregate types. An aggregate type, also referred to as both a structured type and a data struc- ture, is any type whose values can be decomposed and are related by some defined structure. Additionally, operations must be available for retrieving and updating values in the data structure. One-dimensional arrays are examples of a structured type. In a one-dimensional array, such as an array of integers, the array is composed of integer values, with the integers related by their position in the list. Indexed variables provide the means of accessing and modifying values in the array. 378 Arrays
  • 399. The first temperature entered is stored in temp[0], the second temperature entered is stored in temp[1], and so on until five temperatures have been entered. One caution about storing data in an array: C++ doesn’t check the value of the index being used (called a bounds check). If an array has been declared as consisting of 10 elements, for example, and you use an index of 12, which is outside the bounds of the array, C++ doesn’t notify you of the error when the program is compiled. The program attempts to access element 12 by skipping over the appropriate number of bytes from the start of the array. Usually, this attempt results in a program crash, but not always. If the referenced location contains a value of the correct data type, the new value simply overwrites the value in the referenced memory locations. This leads to more errors, which are troublesome to locate when the variable legitimately assigned to the storage location is used at a different point in the program. During output, an array element can be displayed by using a cout statement, or complete sections of the array can be displayed by including a cout statement in a for loop. Examples of both methods are shown: cout << volts[6]; and cout << "The value of element " << i << " is " << temp[i]; and const int NUMELS = 20; for (k = 5; k < NUMELS; k++) cout << k << " " << amount[k] << endl; The first statement displays the value of the subscripted variable volts[6]. The second statement displays the values of subscript i and of temp[i]. Before this statement can be executed, i must have an assigned value. Finally, the last example includes a cout statement in a for loop that displays both the value of the index and the value of elements 5 to 20. Program 7.1 illustrates these input and output techniques, using an array named temp that’s defined to store five integer numbers. The program includes two for loops. The first for loop is used to cycle through each array element and allows the user to input array values. After five values have been entered, the second for loop is used to display the stored values. Program 7.1 #include <iostream> using namespace std; int main() { const int MAXTEMPS = 5; int i, temp[MAXTEMPS]; 墌 379 Chapter 7 One-Dimensional Arrays
  • 400. A sample run of Program 7.1 follows: Enter a temperature: 85 Enter a temperature: 90 Enter a temperature: 78 Enter a temperature: 75 Enter a temperature: 92 temperature 0 is 85 temperature 1 is 90 temperature 2 is 78 temperature 3 is 75 temperature 4 is 92 In reviewing the output of Program 7.1, pay attention to the difference between the index value displayed and the numerical value stored in the corresponding array element. The index value refers to the element’s location in the array, and the subscripted variable refers to the value stored in the designated location. In addition to simply displaying the values stored in each array element, the elements can also be processed by referencing the desired element. For example, in Program 7.2, the value of each element is accumulated in a total, which is displayed after all array elements have been displayed. for (i = 0; i < MAXTEMPS; i++) // Enter the temperatures { cout << "Enter a temperature: "; cin >> temp[i]; } cout << endl; for (i = 0; i < MAXTEMPS; i++) // Print the temperatures cout << "temperature " << i << " is " << temp[i] << endl; return 0; } 380 Arrays
  • 401. A sample run of Program 7.2 follows: Enter a temperature: 85 Enter a temperature: 90 Enter a temperature: 78 Enter a temperature: 75 Enter a temperature: 92 The total of the temperatures 85 90 78 75 92 is 420 Notice that in Program 7.2, unlike Program 7.1, only the values stored in each array element, not the index numbers, are displayed. Although the second for loop is used to accumulate the total of each element, the accumulation could also have been accomplished Program 7.2 #include <iostream> using namespace std; int main() { const int MAXTEMPS = 5; int i, temp[MAXTEMPS], total = 0; for (i = 0; i < MAXTEMPS; i++) // Enter the temperatures { cout << "Enter a temperature: "; cin >> temp[i]; } cout << "nThe total of the temperatures"; for (i = 0; i < MAXTEMPS; i++) // Display and total the temperatures { cout << " " << temp[i]; total = total + temp[i]; } cout << " is " << total << endl; return 0; } 381 Chapter 7 One-Dimensional Arrays
  • 402. in the first for loop by placing the statement total = total + temp[i]; after the cin statement used to enter a value. Also, the cout statement used to display the total is placed outside the second for loop so that the total is displayed only once, after all values have been added to the total. If this cout statement were placed inside the for loop, five totals would be displayed, with only the last displayed total containing the sum of all array values. EXERCISES 7.1 1. (Practice) Write array declarations for the following: a. A list of 100 double-precision voltages b. A list of 50 double-precision temperatures c. A list of 30 characters, each representing a code d. A list of 100 integer years e. A list of 32 double-precision velocities f. A list of 1000 double-precision distances g. A list of 6 integer code numbers 2. (Practice) Write correct notation for the first, third, and seventh elements of the follow- ing arrays: a. int grades[20] b. double volts[10] c. double amps[16] d. int dist[15] e. double velocity[25] f. double time[100] 3. (Practice) a. Write input statements using cin that can be used to enter values in the first, third, and seventh elements of each array declared in Exercise 2. b. Write a for loop that can be used to enter values for each array declared in Exercise 2. 4. (Practice) a. Write output statements using cout that can be used to display values from the first, third, and seventh elements of each array declared in Exercise 2. b. Write a for loop that can be used to display values for the complete array declared in Exercise 2. 5. (Desk Check) List the elements displayed by the following sections of code: a. for (m = 1; m <= 5; m++) cout << a[m] << " "; b. for (k = 1; k <= 5; k = k + 2) cout << a[k] << " "; 382 Arrays
  • 403. c. for (j = 3; j <= 10; j++) cout << b[j] << " "; d. for (k = 3; k <= 12; k = k + 3) cout << b[k] << " "; e. for (i = 2; i < 11; i = i + 2) cout << c[i] << " "; 6. (Practice) a. Write a program to input the following values in an array named volts: 11.95, 16.32, 12.15, 8.22, 15.98, 26.22, 13.54, 6.45, and 17.59. After the data has been entered, have your program display the values. b. Repeat Exercise 6a, but after the data has been entered, have your program display it in the following form: 11.95 16.32 12.15 8.22 15.98 26.22 13.54 6.45 17.59 7. (Practice) Write a program to input eight integer numbers in an array named temp. As each number is input, add the numbers to a total. After all numbers are input, display the numbers and their average. 8. (Data Processing) a. Write a program to input 10 integer numbers in an array named fmax and determine the maximum value entered. Your program should contain only one loop, and the maximum should be determined as array element values are being input. (Hint: Set the maximum equal to the first array element, which should be input before the loop used to input the remaining array values.) b. Repeat Exercise 8a, keeping track of both the maximum element in the array and the index number for the maximum. After displaying the numbers, print these two mes- sages (replacing the underlines with the correct values): The maximum value is: ___ This is element number ___ in the list of numbers c. Repeat Exercise 8b, but have your program locate the minimum of the data entered. 9. (Data Processing) a. Write a program to input the following integer numbers in an array named grades: 89, 95, 72, 83, 99, 54, 86, 75, 92, 73, 79, 75, 82, and 73. As each number is input, add the numbers to a total. After all numbers are input and the total is obtained, calculate the average of the numbers, and use the average to determine the deviation of each value from the average. Store each deviation in an array named deviation. Each deviation is obtained as the element value less the average of all the data. Have your program display each deviation with its corresponding element from the grades array. b. Calculate the variance of the data used in Exercise 9a. The variance is obtained by squaring each deviation and dividing the sum of the squared deviations by the num- ber of deviations. 10. (Electrical Eng.) Write a program that specifies three one-dimensional arrays named cur- rent, resistance, and volts. Each array should be capable of holding 10 elements. 383 Chapter 7 One-Dimensional Arrays
  • 404. Using a for loop, input values for the current and resistance arrays. The entries in the volts array should be the product of the corresponding values in the current and resistance arrays (so volts[i] = current [i] * resistance[i]). After all the data has been entered, display the following output, with the appropriate value under each column heading: Current Resistance Volts 7.2 Array Initialization Array elements can be initialized in their declaration statements in the same manner as scalar variables, except the initializing elements must be included in braces, as shown in these examples: int temp[5] = {98, 87, 92, 79, 85}; char codes[6] = {'s', 'a', 'm', 'p', 'l', 'e'}; double slopes[7] = {11.96, 6.43, 2.58, .86, 5.89, 7.56, 8.22}; Initializers are applied in the order they are written, with the first value used to initialize element 0, the second value used to initialize element 1, and so on, until all values have been used. For example, in the declaration int temp[5] = {98, 87, 92, 79, 85}; temp[0] is initialized to 98, temp[1] is initialized to 87, temp[2] is initialized to 92, temp[3] is initialized to 79, and temp[4] is initialized to 85. Because white space is ignored in C++, initializations can be continued across multiple lines. For example, the following declaration uses four lines to initialize all the array elements: int gallons[20] = {19, 16, 14, 19, 20, 18, // initializing values 12, 10, 22, 15, 18, 17, // can extend across 16, 14, 23, 19, 15, 18, // multiple lines 21, 5}; If the number of initializers is less than the declared number of elements listed in square brackets, the initializers are applied starting with array element 0. Therefore, in the declaration double length[7] = {7.8, 6.4, 4.9, 11.2}; only length[0], length[1], length[2], and length[3] are initialized with the listed values. The other array elements are initialized to 0. Unfortunately, there’s no method of indicating repetition of an initialization value or of initializing later array elements without first specifying values for earlier elements. A unique feature of initializers is that the array size can be omitted when initializing values are included in the declaration statement. For example, the following declaration reserves enough storage room for five elements: int gallons[] = {16, 12, 10, 14, 11}; 384 Arrays
  • 405. Similarly, the following two declarations are equivalent: char codes[6] = {'s', 'a', 'm', 'p', 'l', 'e'}; char codes[] = {'s', 'a', 'm', 'p', 'l', 'e'}; Both these declarations set aside six character locations for an array named codes. An interesting and useful simplification can also be used when initializing character arrays. For example, the following declaration uses the string "sample" to initialize the codes array: char codes[] = "sample"; // no braces or commas Recall that a string is any sequence of characters enclosed in quotation marks. The preceding declaration creates an array named codes with seven elements and fills the array with the seven characters shown in Figure 7.4. The first six characters, as expected, consist of the letters s, a, m, p, l, and e. The last character, the escape sequence 0, is called the null character. The null character is appended automatically to all strings used to initialize a character array. It’s what distinguishes a C-string from a string class string. This character has an internal storage code numerically equal to zero. (The storage code for the 0 character has a numerical value of decimal 48, so the computer can’t confuse the two.) The null character is used as a sentinel to mark the end of a string. After values have been assigned to array elements, through initialization in the declara- tion statement or with interactive input, array elements can be processed as described in the previous section. For example, Program 7.3 shows the initialization of array elements in the array declaration statement, and then uses a for loop to locate the maximum value stored in the array. The following output is produced by Program 7.3: The maximum value is 27 codes[0] codes[1] codes[2] codes[3] codes[4] codes[5] codes[6] s a m p l e 0 Figure 7.4 Initializing a character array with a string adds a terminating 0 character 385 Chapter 7 Array Initialization
  • 406. EXERCISES 7.2 1. (Practice) Write array declarations, including initializers, for the following: a. A list of 10 integer voltages: 89, 75, 82, 93, 78, 95, 81, 88, 77, and 82. b. A list of five double-precision slopes: 11.62, 13.98, 18.45, 12.68, and 14.76. c. A list of 100 double-precision distances; the first six distances are 6.29, 6.95, 7.25, 7.35, 7.40, and 7.42. d. A list of 64 double-precision temperatures; the first 10 temperatures are 78.2, 69.6, 68.5, 83.9, 55.4, 67.0, 49.8, 58.3, 62.5, and 71.6. e. A list of 15 character codes; the first seven codes are f, j, m, q, t, w, and z. 2. (Data Processing) Write an array declaration statement that stores the following values in an array named volts: 16.24, 18.98, 23.75, 16.29, 19.54, 14.22, 11.13, and 15.39. Include these statements in a program that displays the values in the array. 3. (Data Processing) Write a program that uses an array declaration statement to initialize the following numbers in an array named slopes: 17.24, 25.63, 5.94, 33.92, 3.71, 32.84, 35.93, 18.24, and 6.92. Your program should locate and display the maximum and mini- mum values in the array. Program 7.3 #include <iostream> using namespace std; int main() { const int MAXELS = 5; int i, max, nums[MAXELS] = {2, 18, 1, 27, 16}; max = nums[0]; for (i = 1; i < MAXELS; i++) if (max < nums[i]) max = nums[i]; cout << "The maximum value is " << max << endl; return 0; } 386 Arrays
  • 407. 4. (Electrical Eng.) Write a program that stores the following resistance values in an array named resistance: 16, 27, 39, 56, and 81. Your program should also create two arrays named current and power, each capable of storing five double-precision numbers. Using a for loop and a cin statement, have your program accept five user-input numbers in the current array when the program is run. Your program should store the product of the values of the squares of the current array and the resistance array in the power array. For example, use power[1] = resistance[1] * pow(current[1],2). Your program should then display the following output (fill in the chart): Resistance Current Power 16 27 39 56 81 Total: 5. (Practice) a. Write a declaration to store the string "This is a test" in an array named strtest. Include the declaration in a program to display the message, using the following loop: for (i = 0; i < NUMDISPLAY; i++) cout << strtest[i]; NUMDISPLAY is a named constant for the number 14. b. Modify the for statement in Exercise 5a to display only the array characters t, e, s, and t. c. Include the array declaration written in Exercise 5a in a program that uses a cout state- ment to display characters in the array. For example, the statement cout << strtest; causes the string stored in the strtest array to be displayed. Using this statement requires having the end-of-string marker, 0, as the last character in the array. d. Repeat Exercise 5a, using a while loop. (Hint: Stop the loop when the 0 escape sequence is detected. The expression while (strtest[i] != '0') can be used.) 387 Chapter 7 Array Initialization
  • 408. 7.3 Declaring and Processing Two-Dimensional Arrays A two-dimensional array, sometimes referred to as a table, consists of both rows and columns of elements. For example, the following array of numbers is called a two-dimensional array of integers: 8 16 9 52 3 15 27 6 14 25 2 10 This array consists of three rows and four columns. To reserve storage for this array, both the number of rows and the number of columns must be included in the array’s declaration. Calling the array val, the following is the correct specification for this two-dimensional array: int val[3][4]; Similarly, the declarations double volts[10][5]; char code[6][26]; specify that the array volts consists of 10 rows and 5 columns of floating-point numbers, and the array code consists of 6 rows and 26 columns, with each element capable of holding one character. To locate each element in a two-dimensional array, you use its position in the array. As shown in Figure 7.5, the term val[1][3] uniquely identifies the element in row 1, column 3. As with one-dimensional array variables, two-dimensional array variables can be used anywhere that scalar variables are valid, as shown in these examples using elements of the val array: watts = val[2][3]; val[0][0] = 62; newnum = 4 * (val[1][0] - 5); sumRow0 = val[0][0] + val[0][1] + val[0][2] + val[0][3]; The last statement causes the values of the four elements in row 0 to be added and the sum to be stored in the scalar variable sumRow0. Row 0 Row 1 Row 2 8 3 14 Col. 0 16 15 25 Col. 1 9 27 2 Col. 2 52 6 10 Col. 3 val[1][3] Row position Column position Figure 7.5 Each array element is identified by its row and column position 388 Arrays
  • 409. As with one-dimensional arrays, two-dimensional arrays can be initialized in their declaration statements by listing the initial values inside braces and separating them with commas. Additionally, braces can be used to separate rows. For example, the declaration int val[3][4] = { {8,16,9,52}, {3,15,27,6}, {14,25,2,10} }; declares val as an array of integers with three rows and four columns, with the initial values given in the declaration. The first set of internal braces contains values for row 0 of the array, the second set of internal braces contains values for row 1, and the third set of braces contains values for row 2. Although the commas in the initialization braces are always required, the inner braces can be omitted. Without them, the initialization for val can be written as follows: int val[3][4] = {8,16,9,52, 3,15,27,6, 14,25,2,10}; Separating initial values into rows in the declaration statement isn’t necessary because the compiler assigns values beginning with the [0][0] element and proceeds row by row to fill in the remaining values. Therefore, the initialization int val[3][4] = {8,16,9,52,3,15,27,6,14,25,2,10}; is equally valid but doesn’t clearly indicate to another programmer where one row ends and another begins. As shown in Figure 7.6, a two-dimensional array is initialized in row order. The elements of row 0 are initialized, then the elements of row 1 are initialized, and so on, until the initializations are completed. This row ordering is the same ordering used to store two- dimensional arrays. That is, array element [0][0] is stored first, followed by element [0][1], then element [0][2], and so on. Following row 1’s elements are row 2’s elements, and so on for all rows in the array. Initialization starts with this element val[0][0]=8 val[0][1]=16 val[0][2]=9 val[0][3]=52 val[1][0]=3 val[1][1]=15 val[1][3]=6 val[1][2]=27 val[2][0]=14 val[2][1]=25 val[2][2]=2 val[2][3]=10 Figure 7.6 Storage and initialization of the val array 389 Chapter 7 Declaring and Processing Two- Dimensional Arrays
  • 410. As with one-dimensional arrays, two-dimensional arrays can be displayed with element notation or by using loops (while or for). Program 7.4, which displays all elements of a 3-by-4 two-dimensional array, shows these two techniques. Notice that constants are used to define the array’s rows and columns. This is the display produced by Program 7.4: Display of val array by explicit element 8 16 9 52 3 15 27 6 14 25 2 10 Program 7.4 #include <iostream> #include <iomanip> using namespace std; int main() { const int NUMROWS = 3; const int NUMCOLS = 4; int i, j; int val[NUMROWS][NUMCOLS] = {8,16,9,52,3,15,27,6,14,25,2,10}; cout << "nDisplay of val array by explicit element" << endl << setw(4) << val[0][0] << setw(4) << val[0][1] << setw(4) << val[0][2] << setw(4) << val[0][3] << endl << setw(4) << val[1][0] << setw(4) << val[1][1] << setw(4) << val[1][2] << setw(4) << val[1][3] << endl << setw(4) << val[2][0] << setw(4) << val[2][1] << setw(4) << val[2][2] << setw(4) << val[2][3]; cout << "nnDisplay of val array using a nested for loop"; for (i = 0; i < NUMROWS; i++) { cout << endl; // print a new line for each row for (j = 0; j < NUMCOLS; j++) cout << setw(4) << val[i][j]; } cout << endl; return 0; } 390 Arrays
  • 411. Display of val array using a nested for loop 8 16 9 52 3 15 27 6 14 25 2 10 The first display of the val array produced by Program 7.4 is constructed by designating each array element. The second display of array element values, which is identical to the first, is produced by using a nested for loop. Nested loops are especially useful when dealing with two-dimensional arrays because they allow the programmer to designate and cycle through each element easily. In Program 7.4, the variable i controls the outer loop, and the variable j controls the inner loop. Each pass through the outer loop corresponds to a single row, with the inner loop supplying the column elements. After a complete row is printed, a new line is started for the next row. The result is a display of the array in a row-by-row fashion. After two-dimensional array elements have been assigned, array processing can begin. Typically, for loops are used to process two-dimensional arrays because, as noted previously, they allow the programmer to designate and cycle through each array element easily. For example, the nested for loop in Program 7.5 is used to multiply each element in the val array by the scalar number 10 and display the resulting value. Program 7.5 #include <iostream> #include <iomanip> using namespace std; int main() { const int NUMROWS = 3; const int NUMCOLS = 4; int i, j; int val[NUMROWS][NUMCOLS] = {8,16,9,52, 3,15,27,6, 14,25,2,10}; // multiply each element by 10 and display it cout << "nDisplay of multiplied elements"; for (i = 0; i < NUMROWS; i++) { cout << endl; // start each row on a new line for (j = 0; j < NUMCOLS; j++) { val[i][j] = val[i][j] * 10; cout << setw(5) << val[i][j]; } // end of inner loop } // end of outer loop cout << endl; return 0; } 391 Chapter 7 Declaring and Processing Two- Dimensional Arrays
  • 412. Following is the output produced by Program 7.5: Display of multiplied elements 80 160 90 520 30 150 270 60 140 250 20 100 Larger Dimensional Arrays Although arrays with more than two dimensions aren’t commonly used, C++ does allow declaring any number of dimensions by listing the maximum size of all dimensions for the array. For example, the declaration int response [4][10][6]; declares a three-dimensional array.The first element in the array is designated as response[0][0][0] and the last element as response[3][9][5]. As shown in Figure 7.7, you can think of a three-dimensional array as a book of data tables. Using this analogy, think of the first index as the location of the desired row in a table, the second index value as the desired column, and the third index value, often called the “rank,” as the page number of the selected table. Similarly, arrays of any dimension can be declared. Conceptually, a four-dimensional array can be represented as a shelf of books, with the fourth dimension used to declare a selected book on the shelf, and a five-dimensional array can be viewed as a bookcase filled with books, with the fifth dimension referring to a selected shelf in the bookcase. Using the same analogy, a six-dimensional array can be thought of as a single row of bookcases, with the sixth dimension referring to the desired bookcase in the row; a seven-dimensional array can be thought of as multiple rows of bookcases, with the seventh dimension referring to the desired row, and so on. Alternatively, arrays of three, four, five, six, and so on dimensional arrays can be viewed as mathematical n-tuples of order three, four, five, six, and so forth. Row index Column index Page number index (rank) Figure 7.7 Representation of a three-dimensional array 392 Arrays
  • 413. EXERCISES 7.3 1. (Practice) Write specification statements for the following: a. An array of integers with 6 rows and 10 columns b. An array of integers with 2 rows and 5 columns c. An array of characters with 7 rows and 12 columns d. An array of characters with 15 rows and 7 columns e. An array of double-precision numbers with 10 rows and 25 columns f. An array of double-precision numbers with 16 rows and 8 columns 2. (Desk Check) Determine the output produced by the following program: #include <iostream> using namespace std; int main() { int i, j, val[3][4] = {8,16,9,52,3,15,27,6,14,25,2,10}; for (i = 0; i < 3; ++i) for (j = 0; j < 4; ++j) cout << " " << val[i][j]; return 0; } 3. (Practice) a. Write a C++ program that adds the values of all elements in the val array used in Exercise 2 and displays the total. b. Modify the program written for Exercise 3a to display the total of each row separately. 4. (Practice) Write a C++ program that adds equivalent elements of the two-dimensional arrays named first and second. Both arrays should have two rows and three columns. For example, element [1][2] of the resulting array should be the sum of first[1][2] and second[1][2]. The first and second arrays should be initialized as follows: first second 16 18 23 24 52 77 54 91 11 16 19 59 5. (Data Processing) a. Write a C++ program that finds and displays the maximum value in a two-dimensional array of integers. The array should be declared as a 4-by-5 array of integers and initialized with the data 16, 22, 99, 4, 18, -258, 4, 101, 5, 98, 105, 6, 15, 2, 45, 33, 88, 72, 16, and 3. b. Modify the program written in Exercise 5a so that it also displays the maximum val- ue’s row and column subscript numbers. 393 Chapter 7 Declaring and Processing Two- Dimensional Arrays
  • 414. 6. (Data Processing) Write a C++ program that selects the values in a 4-by-5 array of posi- tive integers in increasing order and stores the selected values in the one-dimensional array named sort. Use the data statement in Exercise 5a to initialize the two- dimensional array. 7. (Electrical Eng.) a. An engineer has constructed a two-dimensional array of real num- bers with three rows and five columns. This array currently contains test voltages of an amplifier. Write a C++ program that interactively inputs 15 array values, and then deter- mines the total number of voltages in these ranges: less than 60, greater than or equal to 60 and less than 70, greater than or equal to 70 and less than 80, greater than or equal to 80 and less than 90, and greater than or equal to 90. b. Entering 15 voltages each time the program written for Exercise 7a runs is cumbersome. What method could be used for initializing the array during the testing phase? c. How might the program you wrote for Exercise 7a be modified to include the case of no voltage being present? That is, what voltage could be used to indicate an invalid voltage, and how would your program have to be modified to exclude counting such a voltage? 7.4 Arrays as Arguments Array elements are passed to a called function in the same manner as scalar variables; they are simply included as subscripted variables when the function call is made. For example, the following function call passes the values of the elements volts[2] and volts[6] to the function findMin(): findMin(volts[2], volts[6]); Passing a complete array of values to a function is, in many respects, easier than passing each element. The called function receives access to the actual array rather than a copy of values in the array. For example, if volts is an array, the function call findMax(volts); makes the complete volts array available to the findMax() function. This function call is different from passing a single variable to a function. Recall that when a single scalar argument is passed to a function (see Section 6.1), the called function receives only a copy of the passed value, which is stored in one of the function’s parameters. If arrays were passed in this manner, a copy of the complete array would have to be created. For large arrays, making copies for each function call would waste computer storage and frustrate the effort to return multiple-element changes made by the called program. (Remember that a function returns at most one direct value.) To avoid these problems, the called function is given direct access to the original array.3 In this way, any changes the called function makes are made directly to the array. For the following specific examples of function calls, the arrays nums, keys, volts, and current are declared as shown: int nums[5]; // an array of five integers char keys[256]; // an array of 256 characters double volts[500], current[500]; // two arrays of 500 doubles 3 The called function has access to the original array because the array’s starting address is actually passed as an argument. The formal parameter receiving this address argument is a pointer. Chapter 12 explains the intimate relationship between array names and pointers. 394 Arrays
  • 415. For these arrays, the following function calls can be made; note that in each case, the called function receives direct access to the named array: findMax(nums); findCh(keys); calcTot(nums, volts, current); On the receiving side, the called function must be alerted that an array is being made available. For example, the following are suitable function headers for the previous functions: int findMax(int vals[5]) char findCh(char in_keys[256]) void calcTot(int arr1[5], double arr2[500], double arr3[500]) In each function header, the programmer chooses the names in the parameter list. However, the parameter names used by the functions still refer to the original array created outside the function, as Program 7.6 makes clear. Program 7.6 #include <iostream> using namespace std; const int MAXELS = 5; int findMax(int [MAXELS]); // function prototype int main() { int nums[MAXELS] = {2, 18, 1, 27, 16}; cout << "The maximum value is " << findMax(nums) << endl; return 0; } // find the maximum value int findMax(int vals[MAXELS]) { int i, max = vals[0]; for (i = 1; i < MAXELS; i++) if (max < vals[i]) max = vals[i]; return max; } 395 Chapter 7 Arrays as Arguments
  • 416. Notice that the function prototype for findMax() declares that findMax returns an integer and expects an array of five integers as an actual argument. It’s also important to know that only one array is created in Program 7.6. In main(), this array is known as nums, and in findMax(), the array is known as vals. As illustrated in Figure 7.8, both names refer to the same array, so vals[3] is the same element as nums[3]. The parameter declaration in the findMax() header actually contains extra information not required by the function. All that findMax() must know is that the parameter vals references an array of integers. Because the array has been created in main() and no additional storage space is needed in findMax(), the declaration for vals can omit the array size. Therefore, the following is an alternative function header: int findMax(int vals[]) This form of the function header makes more sense when you realize that only one item is actually passed to findMax() when the function is called: the starting address of the num array, as shown in Figure 7.9. Because only the starting address of vals is passed to findMax(), the number of elements in the array need not be included in the declaration for vals.4 In fact, generally 4 An important consequence of passing the starting address is that findMax() has direct access to the passed array. This access means any change to an element of the vals array is a change to the nums array. This result is much different from the situation with scalar variables, where the called function doesn’t receive direct access to the passed variable. int main() { int nums[5]; . . . findMax(nums) ; returns 0; } int findMax(int vals[5]) . . . } In main(): nums[1] nums[2] nums[3] nums[4] In findMax(): vals[1] vals[2] vals[3] vals[4] This creates the array These reference the same array nums[0] vals[0] Figure 7.8 Only one array is created 396 Arrays
  • 417. it’s advisable to omit the array size from the function header. For example, the more general form of findMax() can be used to find the maximum value of an integer array of arbitrary size: int findMax(int vals[], int numels) //find the maximum value { int i, max = vals[0]; for (i = 1; i < numels; i++) if (max < vals[i]) max = vals[i]; return max; } The more general form of findMax() declares that the function returns an integer value. The function expects the starting address of an integer array and the number of elements in the array as arguments. Then, using the number of elements as the boundary for its search, the function’s for loop causes each array element to be examined in sequential order to locate the maximum value. Program 7.7 shows using findMax() in a complete program. Starting address of nums array is &nums[0]. This is passed to the function nums[0] nums[1] nums[2] nums[3] nums[4] findMax(nums); Figure 7.9 The array’s starting address is passed Program 7.7 #include <iostream> using namespace std; int findMax(int [], int); // function prototype int main() { 墌 397 Chapter 7 Arrays as Arguments
  • 418. The following is the output displayed by Programs 7.6 and 7.7: The maximum value is 27 Passing two-dimensional arrays to a function is identical to passing one-dimensional arrays. The called function receives access to the entire array. For example, if val is a two-dimensional array, the function call display(val); makes the complete val array available to the function display(). Consequently, any changes display() makes are made directly to the val array. As further examples, if the following two-dimensional arrays named test, factors, and thrusts are declared as int test[7][9]; float factors[26][10]; double thrusts[256][52]; then the following function calls are valid: findMax(test); obtain(factors); average(thrusts); On the receiving side, the called function must be alerted that a two-dimensional array is being made available. For example, assuming the previous functions return an integer, the following are suitable function headers: int findMax(int nums[7][9]) int obtain(float values[26][10]) int average(double vals[256][52]) const int MAXELS = 5; int nums[MAXELS] = {2, 18, 1, 27, 16}; cout << "The maximum value is " << findMax(nums, MAXELS) << endl; return 0; } // find the maximum value int findMax(int vals[], int numels) { int i, max = vals[0]; for (i = 1; i < numels; i++) if (max < vals[i]) max = vals[i]; return max; } 398 Arrays
  • 419. The parameter names chosen are used inside the function body. However, the parameter names still refer to the original array created outside the function. Program 7.8 shows passing a two-dimensional array to a function that displays the array’s values. Only one array is created in Program 7.8. This array is known as val in main() and as nums in display(). Therefore, val[0][2] refers to the same element as nums[0][2]. Notice the use of the nested for loop in Program 7.8 for cycling through each array element. The variable rownum controls the outer loop, and the variable colnum controls the inner loop. For each pass through the outer loop, which corresponds to a single row, the innerloop makes one pass through the column elements. After a complete row is printed, a Program 7.8 #include <iostream> #include <iomanip> using namespace std; const int ROWS = 3; const int COLS = 4; void display(int [ROWS][COLS]); // function prototype int main() { int val[ROWS][COLS] = {8,16,9,52, 3,15,27,6, 14,25,2,10}; display(val); return 0; } void display(int nums[ROWS][COLS]) { int rownum, colnum; for (rownum = 0; rownum < ROWS; rownum++) { for(colnum = 0; colnum < COLS; colnum++) cout << setw(4) <<nums[rownum][colnum]; cout << endl; } return; } 399 Chapter 7 Arrays as Arguments
  • 420. new line is started for the next row. The result is a display of the array in a row-by-row fashion: 8 16 9 52 3 15 27 6 14 25 2 10 The parameter declaration for nums in display() contains extra information not required by the function. The declaration for nums can omit the row size of the array, so the following is an alternative function prototype: display(int nums[][4]); The reason the column size must be included but the row size is optional becomes obvious when you see how array elements are stored in memory. Starting with element val[0][0], each succeeding element is stored consecutively, row by row, as val[0][0], val[0][1], val[0][2], val[0][3], val[1][0], val[1][1], and so on, as illustrated in Figure 7.10. As with all array accesses, a single element of the val array is obtained by adding an offset to the array’s starting location. For example, element val[1][3] of the val array in Figure 7.10 is located at an offset of 28 bytes from the start of the array. Internally, the compiler uses the row index, column index, and column size to determine this offset, using the following calculation (assuming 4 bytes for an int): The column size is necessary in the offset calculation so that the compiler can determine the number of positions to skip over to get to the correct row. val[1][3] Column 0 Column 1 Column 2 Column3 Row 0 Row 1 Row 2 Figure 7.10 Storage of the val array No. of bytes in a complete row Offset = [(3 4)+ [1 (4 4)] = 28 bytes Bytes per integer Column size Row index Column index × × × 400 Arrays
  • 421. Internal Array Element Location Algorithm5 Internally, each element in an array is obtained by adding an offset to the starting address of the array. Therefore, the memory address of each array element is calculated internally as follows: Address of element i = starting array address + the offset For one-dimensional arrays, the offset to the element with index i is calculated as follows: Offset = i * the size of an element For two-dimensional arrays, the same address calculation is made, except that the offset is determined as Offset = column index value * the size of an element + row index value * number of bytes in a complete row where the number of bytes in a complete row is calculated as follows: number of bytes in a complete row = maximum column specification * the size of an element For example, as illustrated in Figure 7.11, for a one-dimensional array of integers in which each integer is stored with 4 bytes, the offset to the element with an index value of 5 is 5 * 4 = 20. Using the address operator, &, you can check this address algorithm, as shown in Program 7.9. 5 This topic is optional and can be omitted without loss of subject continuity. An integer An integer An integer An integer An integer An integer Index = 0 Index = 1 Index = 2 Index = 3 Index = 4 Index = 5 Starting address of the array 4 bytes 4 bytes 4 bytes 4 bytes 4 bytes Offset to Element 5 = 20 bytes Address of Element 5 Figure 7.11 The offset to the element with an index value of 5 401 Chapter 7 Arrays as Arguments
  • 422. Here is a sample output produced by Program 7.9: The starting address of the arr array is: 1244796 The storage size of each array element is: 4 The address of element number 5 is: 1244816 The starting address of the array, displayed using the notation arr, is: 1244796 Notice that the addresses have been displayed in decimal form, and element 5 is 20 bytes beyond the array’s starting address. Also, the array’s starting address is the same as the address of element 0, which is coded as &arr[0]. Alternatively, as shown by the displayed line, the starting array address can also be obtained as arr, which is the array name, because an array name is a pointer constant, which is an address. (Chapter 12 explains the close association of array names and pointers.) Program 7.9 #include <iostream> using namespace std; int main() { const int NUMELS = 20; int arr[NUMELS]; cout << "The starting address of the arr array is: " << int (&arr[0]) << endl; cout << "The storage size of each array element is: " << sizeof(int) << endl; cout << "The address of element number 5 is: " << int (&arr[5]) << endl; cout << "The starting address of the array, " << "ndisplayed using the notation arr, is: " << int (arr) << endl; return 0; } 402 Arrays
  • 423. EXERCISES 7.4 1. (Practice) The following declaration was used to create the volts array: int volts[500]; Write two different function headers for a function named sortArray() that accepts the volts array as a parameter named inArray. 2. (Practice) The following declaration was used to create the factors array: double factors[256]; Write two different function headers for a function named findKey() that accepts the factors array as a parameter named select. 3. (Practice) The following declaration was used to create the power array: double power[256]; Write two different function headers for a function named prime() that accepts the power array as an argument named watts. 4. (Modify) a. Modify the findMax() function in Program 7.6 to locate the minimum value of the passed array. b. Include the function written in Exercise 4a in a complete program and run the program. 5. (Practice) Write a program that has a declaration in main() to store the following num- bers in an array named temps: 6.5, 7.2, 7.5, 8.3, 8.6, 9.4, 9.6, 9.8, and 10.0. There should be a function call to show() that accepts the temps array as a parameter named temps and then displays the numbers in the array. 6. (Electrical Eng.) Write a program that declares three one-dimensional arrays named volts, current, and resistance. Each array should be declared in main() and be capable of holding 10 double-precision numbers. The numbers to store in current are 10.62, 14.89, 13.21, 16.55, 18.62, 9.47, 6.58, 18.32, 12.15, and 3.98. The numbers to store in resistance are 4, 8.5, 6, 7.35, 9, 15.3, 3, 5.4, 2.9, and 4.8. Your program should pass these three arrays to a function named calc_volts(), which should calculate elements in the volts array as the product of the corresponding elements in the current and resistance arrays (for example, volts[1] = current[1] * resistance[1]). After calc_volts() has passed values to the volts array, the values in the array should be displayed from within main(). 7. (Statistics) Write a program that includes two functions named calcavg() and variance(). The calcavg() function should calculate and return the average of val- ues stored in an array named testvals. The array should be declared in main() and include the values 89, 95, 72, 83, 99, 54, 86, 75, 92, 73, 79, 75, 82, and 73. The variance() function should calculate and return the variance of the data. The variance is obtained by subtracting the average from each value in testvals, squaring the values 403 Chapter 7 Arrays as Arguments
  • 424. obtained, adding them, and dividing by the number of elements in testvals. The val- ues returned from calcavg() and variance() should be displayed by using cout statements in main(). 7.5 A Case Study: Statistical Analysis Arrays are extremely useful in applications that require multiple passes through the same set of data elements. This section uses one such application that’s a statistical data analysis requiring two passes through the data. The first pass is used to input the list and determine the average of the data. The second pass uses the average to determine a standard deviation. This application illustrates one-dimensional array processing and helps you understand passing an array to a function. Step 1 Analyze the Problem The statement of the problem indicates that two output values are required: an average and a standard deviation. The input item defined in the problem statement is a list of integer numbers. Because the problem statement doesn’t specify the list size, and to make the application’s functions as general as possible, both functions will be designed to handle any size list passed to them. This design also requires passing the exact number of elements in the array to each function at the time of the function call. This capability means each function must be capable of receiving at least two input items as parameters: an array of arbitrary size and an integer number corresponding to the number of elements in the passed array. Step 2 Develop a Solution The I/O specifications determined from the problem analysis imply that the each function’s parameter list must be capable of receiving at least two items: one parameter to accommodate the integer array and the second parameter to accept an integer. The first function returns the average of the numbers in the passed array, and the second function returns the standard deviation. These items are determined as follows: Calculate the average by adding the grades and dividing by the number of grades that was added. Determine the standard deviation by: Subtracting the average from each grade. (This results in a set of new numbers, each of which is called a deviation.) Squaring each deviation found in the previous step. Adding the squared deviations and dividing the sum by the number of deviations. The square root of the number found in the previous step is the standard deviation. The standard deviation can be calculated only after the average has been computed. Therefore, in addition to requiring the array of integers and the number of values in the array, the standard deviation function also requires that the average be passed to it. Specifying the algorithm in detail, before any coding is done, ensures that all necessary inputs and requirements are discovered early in the program development process. 404 Arrays
  • 425. To make sure you understand the required processing, do a hand calculation, assuming the average and standard deviation of the following 10 grades are to be determined: 98, 82, 67, 54, 78, 83, 95, 76, 68, and 63. Here’s the average of these grades: Average = (98 + 82 + 67 + 54 + 78 + 83 + 95 + 76 + 68 + 63)/10 = 76.4 The standard deviation is calculated by first determining the sum of the squared deviations, and then dividing the resulting sum by 10 and taking its square root, as shown: - - = + ( . ) ( 98 76 4 82 76 2 . . ) 4 2 - - + + ( . ) ( . ) 67 76 4 54 76 4 2 2 - + + ( . ) ( 78 76 4 8 2 3 3 76 4 2 - . ) - - + + ( . ) ( . ) 95 76 4 76 76 4 2 2 - + ( . ) 68 76 3 2 2 2 63 76 4 1730 400700 + = ( . ) . - = = = = 1730 4007 10 173 04007 13 154470 . / . . Sum of squared deviations Standard deviation Having specified the algorithm for both functions, you’re now in a position to code them. Step 3 Code the Solution When writing functions, concentrating on the function header first is helpful. You can then write the function body to process the input parameters correctly to produce the desired results. Naming the averaging function findAvg() and selecting the parameter names nums for the passed array and numel for the number of elements, the function header becomes the following: double findAvg(int nums[], int numel) This function header begins the definition of the averaging function and allows the function to accept an array of integer values and an integer number. As shown by the hand calculation, the average of a set of integer numbers can be a floating-point number; therefore, the function is defined as returning a floating-point value. The function body calculates the average as described by the algorithm developed earlier. The completed findAvg() function is as follows: double findAvg(int nums[], int numel) { int i; double sumnums = 0.0; for (i = 0; i < numel; i++) // calculate the sum of the grades sumnums = sumnums + nums[i]; return (sumnums / numel); // calculate and return the average } The function body contains a for loop to sum the numbers. Notice also that the termination value of the loop counter in the for loop is numel, the number of integers in the array passed to the function through the parameter list. Using this parameter gives the 405 Chapter 7 A Case Study: Statistical Analysis
  • 426. function its generality and allows it to be used for input arrays of any size. For example, calling the function with the statement findAvg(values,10) tells the function that numel is 10 and the values array consists of 10 values, whereas the statement findAvg(values,1000) tells findAvg() that numel is 1000 and the values array consists of 1000 numbers. In both calls, the actual argument named values corresponds to the parameter named nums in the findAvg() function. Using similar reasoning as for the averaging function, the function header for the standard deviation function, named stdDev(), is as follows: double stdDev(int nums[], int numel, double av) This header begins the definition of the stdDev() function. It defines the function as returning a double-precision value and accepting an array of integers, an integer value, and a double-precision value as inputs to the function. The body of the stdDev() function must calculate the standard deviation as described in the algorithm. This is the complete standard deviation function: double stdDev(int nums[], int numel, double av) { int i; double sumdevs = 0.0; for (i = 0; i < numel; i++) sumdevs = sumdevs + pow((nums[i] - av),2.0); return(sqrt(sumdevs/numel)); } Step 4 Test and Correct the Program Testing a program’s function requires writing a main() function to call the function you’re testing and display the returned results. Program 7.10 uses a main() function to set up a grade array with the data previously used in the hand calculation and to call the findAvg() and stdDev() functions. 406 Arrays
  • 427. Program 7.10 #include <iostream> #include <iomanip> #include <cmath> using namespace std; double findAvg(int [], int); // function prototype double stdDev(int [], int, double); // function prototype int main() { const int NUMELS = 10; int values[NUMELS] = {98, 82, 67, 54, 78, 83, 95, 76, 68, 63}; double average, sDev; average = findAvg(values, NUMELS); // call the function sDev = stdDev(values, NUMELS, average); // call the function cout << "The average of the numbers is " << setw(5) << setiosflags(ios::showpoint) << setprecision(2) << average << endl; cout << "The standard deviation of the numbers is " << setw(5) << setiosflags(ios::showpoint) << setprecision(2) << sDev << endl; return 0; } double findAvg(int nums[], int numel) { int i; double sumnums = 0.0; for (i = 0; i < numel; i++) // calculate the sum of the grades sumnums = sumnums + nums[i]; return (sumnums / numel); // calculate and return the average } 墌 407 Chapter 7 A Case Study: Statistical Analysis
  • 428. A test run of Program 7.10 produced the following display: The average of the numbers is 76.40 The standard deviation of the numbers is 13.15 Although this result agrees with the previous hand calculation, testing isn’t complete without verifying the calculation at the boundary points. For this program, the test consists of checking the calculation with all the same values, such as all 0s and all 100s. Another simple test is to use five 0s and five 100s. You can try these tests on your own as an exercise. EXERCISES 7.5 1. (Practice) Enter and run Program 7.10 on your computer. 2. (Practice) Run Program 7.10 to determine the average and standard deviation of the fol- lowing list of 15 grades: 68, 72, 78, 69, 85, 98, 95, 75, 77, 82, 84, 91, 89, 65, and 74. 3. (List Maintenance) A common programming problem is maintaining a list in numerical or alphabetical order. For example, inventory part numbers are typically kept in numerical order, but telephone lists are kept in alphabetical order. For this exercise, write a function that inserts a three-digit part number in a list of part numbers. The list is maintained in increasing numerical order, and duplicate part numbers aren’t allowed. Allocate a maximum list size of 100 values, and use a sentinel value of 9999 to indicate the end of the list. For example, if the current list contains nine part numbers, the 10th position in the list contains the sentinel value. Figure 7.12 shows double stdDev(int nums[], int numel, double av) { int i; double sumdevs = 0.0; for (i = 0; i < numel; i++) sumdevs = sumdevs + pow((nums[i] - av),2); return(sqrt(sumdevs/numel)); } 408 Arrays
  • 429. the insertion process for an original list of nine part numbers, using the following process- ing algorithm: Determine where in the list the new part number should be placed This is done by comparing the new part number to each value in the current list until a match is found, a part number larger than the new part number is located, or the end of the list is encountered If the new part number matches an existing part number, display a message that the part number exists Else To make room for the new element in the array, move each element down one position. This is done by starting from the sentinel value and coping each item to the next position down until the desired position in the list is vacated. Insert the new part number in the vacated position Endif 4. (List Maintenance) a. Write a complete C++ program that can be used to update an ordered list of numbers. Use the list of numbers shown in Figure 7.12 to test that your program is working correctly. b. Test the program you wrote for Exercise 4a, using a new part number of 86 with the list of numbers shown in Figure 7.12. This test should place this new part number at the beginning of the existing list. c. Test the program you wrote for Exercise 4a, using a part number of 200 with the list of numbers shown in Figure 7.12. This test should place this new part number at the end of the existing list. 5. (List Maintenance) a. Determine an algorithm for deleting an entry from an ordered list of numbers. b. Write a function named delete(), which uses the algorithm determined in Exercise 5a, to delete a part number from the list shown in Figure 7.12. The new part number of 142 is to be inserted here (a) Original list (b) Elements copied to make room for the new part number (c) The updated list 185 192 9999 109 122 136 144 157 162 178 185 192 9999 109 122 136 144 157 162 178 144 185 192 9999 109 122 136 144 157 162 178 142 Figure 7.12 Updating an ordered list of part numbers 409 Chapter 7 A Case Study: Statistical Analysis
  • 430. 6. (List Maintenance) The following letters are stored in an alphabet array: B, J, K, M, S, and Z. Write and test a function named adlet(), which accepts the alphabet array and a new letter as arguments, and then inserts the new letter in the correct alphabetical order in the alphabet array. 7. (File Creation) Write a C++ program that creates an array containing the integer num- bers 60, 40, 80, 90, 120, 150, 130, 160, 170, and 200. Your program should then write the data in the array to a text file. (Alternatively, you can create the file with a text editor.) 8. (File Update) a. Develop, write, and execute a C++ program that reads in the list of 10 integer numbers from the data file created in Exercise 7. b. Modify the program you wrote for Exercise 8a so that the program does the following: 앫 Deletes the first number input from the file 앫 Accepts a new integer value that will be placed at the end of the list of numbers 앫 Computes and displays the average of all numbers (not including the deleted value) 앫 Overwrites the old file with the new list of numbers 7.6 The Standard Template Library (STL)6 Many programming applications require expanding and contracting lists as list items are added and removed. Although expanding and contracting an array can be accomplished by creating, copying, and deleting arrays, this solution is costly in terms of initial programming, maintenance, and testing time. To meet the need of providing a tested and generic set of data structures that can be modified, expanded, and contracted, C++ includes a useful set of classes in its Standard Template Library (STL). Additionally, the functions included in the STL provide useful ways of sorting and searching lists of data. For example, you might need to arrange experimental results in increasing (ascending) or decreasing (descending) order for a statistical analysis. Perhaps an array of names, as string data, must be sorted in alphabetical order, or an array of part names needs to be searched to find a particular part. Each STL class is coded as a template (see Section 6.1) that permits constructing a generic data structure, referred to as a container. The terms list and collection are synonyms for a container, and both these terms refer to a set of data items that form a natural unit or group. Using this definition, an array can also be considered a container, but not in the technical sense that it’s created by using the STL; rather, it’s provided as a built-in data type. Figure 7.13 shows the container types in the STL. This section discusses the vector container class, along with the most commonly used algorithms for this class and the arguments, known as iterators, these algorithms require. A vector is similar to an array, in that it stores elements that can be accessed by using an integer index starting at 0. However, a vector is different from an array, in that a vector expands automatically as needed and is provided by several extremely useful class functions7 for 6 This topic can be omitted on first reading without loss of subject continuity. 7 In general computer terminology, functions defined in a class (discussed in Part Two) are referred to as “methods.” In C++, the terms “class functions” and “class methods” are used interchangeably. 410 Arrays
  • 431. operating on the vector. Table 7.1 lists these vector class functions, with shading to identify the functions used in the demonstration program. Table 7.1 Summary of Vector Class Functions and Operations Class Functions and Operations Description vector<DataType> name Creates an empty vector with compiler-dependent initial size vector<DataType> name(source) Creates a copy of the source vector vector<DataType> name(n) Creates a vector of size n vector<DataType> name (n, elem) Creates a vector of size n with each element initialized as elem vector<DataType> name(src.beg, src.end) Creates a vector initialized with elements from a source container beginning at src.beg and ending at src.end ~vector(DataType>() Destroys the vector and all elements it contains name[index] Returns the element at the designated index, with no bounds checking name.at(index) Returns the element at the specified index argument, with bounds checking on the index value name.front() Returns the first element in the vector name.back() Returns the last element in the vector dest = src Assigns all elements of src vector to dest vector name.assign(n, elem) Assigns n copies of elem name.assign (src.begin, src.end) Assigns the elements of the src container (need not be between the range src.begin and src. end) to the name vector STL container types vector deque list set multiset map multimap Figure 7.13 The collection of STL container types 411 Chapter 7 The Standard Template Library (STL)
  • 432. Table 7.1 Summary of Vector Class Functions and Operations (continued) Class Functions and Operations Description insert(pos, elem) Inserts elem at position pos name.insert (pos, n, elem) Inserts n copies of elem starting at position pos name.insert(pos, src.begin, src.end) Inserts elements from src.begin to src.end, starting at position pos name.push_back(elem) Appends elem at the end of the vector name.erase(pos) Removes the element at the specified position pos name.erase(begin, end) Removes elements within the specified range name.resize(value) Resizes the vector to a larger size, with new elements created by using the default constructor name.resize(value, elem) Resizes the vector to a larger size, with new elements created as elem name.clear() Removes all elements from the vector name.swap(nameB) Swaps the elements of nameA and nameB vectors; can be performed by using the swap algorithm nameA == nameB Returns a Boolean true if nameA elements equal nameB elements; otherwise, returns false nameA != nameB Returns a Boolean false if nameA elements equal nameB elements; otherwise, returns true; same as !(nameA == nameB) nameA < nameB Returns a Boolean true if nameA is less than nameB; otherwise, returns false nameA > nameB Returns a Boolean true if nameA is greater than nameB; otherwise, returns false; same as nameB < nameA nameA <= nameB Returns a Boolean true if nameA is less than or equal to nameB nameA >= nameB Returns a Boolean true if nameA is greater than or equal to nameB name.size() Returns the size of the vector name.empty() Returns a Boolean true if the vector is empty; otherwise, returns false name.max_size() Returns the maximum possible elements as an integer name.capacity() Returns the maximum possible elements as an integer without relocating the vector In addition to the vector class functions listed in Table 7.1, vectors have access to the complete set of generic STL functions, referred to in the STL as algorithms. Table 7.2 summarizes the most commonly used STL algorithms. 412 Arrays
  • 433. Table 7.2 Commonly Used STL Algorithms Algorithm Name Description accumulate Returns the sum of the numbers in a specified range binary_search Returns a Boolean value of true if the specified value exists within the specified range; otherwise, returns false. Can be used only on a sorted set of values. copy Copies elements from a source range to a destination range copy_backward Copies elements from a source range to a destination range in a reverse direction count Returns the number of elements in a specified range that match a specified value equal Compares the elements in one range of elements, element by element, to the elements in a second range fill Assigns every element in a specified range to a specified value find Returns the position of an element’s first occurrence in a specified range having a specified value if the value exists. Performs a linear search, starting with the first element in a specified range, and proceeds one element at a time until the complete range has been searched or the specified element has been found. max_element Returns the maximum value of elements in the specified range min_element Returns the minimum value of elements in the specified range random_shuffle Randomly shuffles element values in a specified range remove Removes a specified value in a specified range without changing the order of the remaining elements replace Replaces each element in a specified range having a specified value with a newly specified value reverse Reverses elements in a specified range search Finds the first occurrence of a specified value or sequence of values within a specified range sort Sorts elements in a specified range into ascending order swap Exchanges element values between two objects unique Removes duplicate adjacent elements in a specified range 413 Chapter 7 The Standard Template Library (STL)
  • 434. Notice that there’s both a swap algorithm (Table 7.2) and a swap() vector function (Table 7.1). Because a function is targeted to work specifically with its container type and generally executes faster when a container class provides a function with the same name as an algorithm, you should use the class functions. Finally, the STL provides additional items referred to as iterators, used to specify which elements in a container are to be operated on when an algorithm is called. Two of the most useful iterators are returned by the STL iterator functions begin() and end(). These general-purpose functions return the positions of the first and last elements in a container. To better understand using an STL container class, in this section you see how to use the vector container class to create a vector for holding a list of part numbers. As you’ll see, a vector is similar to a C++ array, except it can automatically expand as needed. Program 7.11 constructs a vector and initializes it with integers stored in an integer array. After it’s initialized, various vector functions and STL algorithms are used to operate on the vector. Specifically, one function is used to change an existing value, a second is used to insert a value into the vector, and a third is used to add a value to the end of the list. After each function and algorithm are applied, a cout statement is used to display the results. In reviewing Program 7.11, notice these four header files that precede the using namespace std; statement: • The <iostream> header is required to create and use cout. • The <string> header is required for constructing strings. • The <vector> header is required to create one or more vector objects. • The <algorithm> header is required for the sort algorithm that’s applied after vector elements have been added and replaced. Point of Information When to Use an Array or a Vector An array is the data structure of first choice when you have a list of primitive data types or objects that don’t have to be expanded or contracted. A vector is the data structure of first choice when you have a list of primitive data types or objects that can be grouped as an array but must be expanded or contracted. Whenever possible, use STL’s algorithms to operate on arrays and vectors. STL classes and algorithms provide verified and reliable code that can shorten program development time. 414 Arrays
  • 435. Program 7.11 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; int main() { const int NUMELS = 4; int n[] ={136, 122, 109, 146}; int i; // create a vector of strings using the n[] array vector<int> partnums(n, n + NUMELS); cout << "nThe vector initially has a size of " << int(partnums.size()) << ",n and contains the elements:n"; for (i = 0; i < int(partnums.size()); i++) cout << partnums[i] << " "; // modify the element at position 4 (i.e. index = 3) in the vector partnums[3] = 144; cout << "nnAfter replacing the fourth element, the vector has a size of " << int(partnums.size()) << ",n and contains the elements:n"; for (i = 0; i < int(partnums.size()); i++) cout << partnums[i] << " "; // insert an element into the vector at position 2 (i.e. index = 1) partnums.insert(partnums.begin()+1, 142); cout << "nnAfter inserting an element into the second position," << "n the vector has a size of " << int(partnums.size()) << "," << " and contains the elements:n"; for (i = 0; i < int(partnums.size()); i++) cout << partnums[i] << " "; // add an element to the end of the vector partnums.push_back(157); 墌 415 Chapter 7 The Standard Template Library (STL)
  • 436. The following statement in Program 7.11 is used to create and initialize the vector named partnums: vector<int> partnums(n, n + NUMELS); The vector partnums is declared as a vector of type int and initialized with elements from the n array, starting with the first array element (element n[0]) and ending with the last array element, located at position n + NUMELS. Therefore, the vector size is large enough for four integer values and has been initialized with the integers 136, 122, 109, and 146. The next set of statements in Program 7.11 displays the initial values in the vector by using standard subscripted vector notation that’s identical to the notation for accessing array elements. Displaying vector values in this manner, however, requires knowing how many elements each vector contains. As you insert and remove elements, you would like the vector to track the first and last elements’ locations. This capability is provided automatically by the two STL iterator functions mentioned previously: begin() and end(). The next major set of statements consists of the following: // modify the element at position 4 (i.e. index = 3) in the vector partnums[3] = 144; // insert an element into the vector at position 2 (i.e. index = 1) partnums.insert(partnums.begin()+1, 142); These statements are used to modify an existing vector value and insert a new value into the vector. Specifically, the partnums[3] notation uses standard indexing, and the insert() function uses an iterator argument, which is constructed as an offset by using the begin() or cout << "nnAfter adding an element to the end of the list," << "n the vector has a size of " << int(partnums.size()) << "," << " and contains the elements:n"; for (i = 0; i < int(partnums.size()); i++) cout << partnums[i] << " "; // sort the vector sort(partnums.begin(), partnums.end()); cout << "nnAfter sorting, the vector's elements are:n"; for (i = 0; i < int(partnums.size()); i++) cout << partnums[i] << " "; cout << endl; return 0; } 416 Arrays
  • 437. end() function. Additionally, you have to specify the value to be inserted at the designated position. Therefore, partnums[3] specifies changing the fourth element in the vector. (Vectors, like arrays, begin at index position 0.) The insert() function is used to insert the integer value 142 in the vector’s second position. Because the begin() function returns a value corresponding to the start of the vector, adding 1 to it designates the vector’s second position.8 At this position, the new value is inserted. All subsequent values are moved up by one position in the vector, and the vector expands automatically to accept the inserted value. At this point in the program, the vector partnums now contains the following elements: 136 142 122 109 144 This arrangement of values was obtained by replacing the original value 146 with 144 and inserting the 142 into the second position, which moves all subsequent elements up automatically by one position and increases the total vector size to five integers. Next, the statement partnums.push_back(157); is used to append the integer 157 to the end of the vector, which results in the following elements: 136 142 122 109 144 157 Finally, the last section of code in Program 7.11 uses the sort() algorithm to sort elements in the vector. After the algorithm is applied, the vector’s values are displayed again. Following is the complete output Program 7.11 produces: The vector initially has a size of 4, and contains the elements: 136 122 109 146 After replacing the fourth element, the vector has a size of 4, and contains the elements: 136 122 109 144 After inserting an element into the second position, the vector has a size of 5, and contains the elements: 136 142 122 109 144 After adding an element to the end of the list, the vector has a size of 6, and contains the elements: 136 142 122 109 144 157 After sorting, the vector's elements are: 109 122 136 142 144 157 8 More precisely, begin() requires an iterator argument, not an integer index argument. The begin() and end() functions return iterators, to which offsets can be applied. In this behavior, they are similar to pointers (covered in Chapter 12). 417 Chapter 7 The Standard Template Library (STL)
  • 438. EXERCISES 7.6 1. (For Review) Define the terms “container” and “Standard Template Library.” 2. (For Review) What include statements should be included with programs using the Standard Template Library? 3. (Practice) Enter and execute Program 7.11. 4. (Modify) Modify Program 7.11 so that the user inputs the initial set of numbers when the program executes. Have the program request the number of initial numbers to be entered. 5. (Modify) Modify Program 7.11 to use and display the results reported by the vector class’s capacity() and max_size() functions. 6. (Modify) Modify Program 7.11 to use the random_shuffle algorithm. 7. (Modify) Modify Program 7.11 to use the binary_search and find algorithms. Have your program request the number to be found. 8. (Modify) Using Program 7.11 as a starting point, create an equivalent program that uses a vector of strings. Initialize the vector by using the array string names[] = {"Donavan", "Michaels", "Smith", "Jones"};. 9. (Practice) Use the max_element and min_element algorithms to determine the maxi- mum and minimum values in the vector created for Exercise 8. (Hint: Use the expression max_element(vectorName.begin(), vectorName.end()) to determine the maxi- mum value stored in the vector. Then use the same arguments for the min_element algorithm.) 7.7 A Closer Look: Searching and Sorting9 Most programmers encounter the need to both sort and search a list of data items at some time in their programming careers. For example, you might have to sort a list of names in alphabetical order and search this list to find a particular name. Similarly, you might have to arrange a list of dates in ascending order and search this list to locate a certain date. This section introduces the fundamentals of sorting and searching lists. Note that sorting a list before searching it isn’t necessary, although much faster searches are possible if the list is in sorted order, as you’ll see. Search Algorithms A common requirement of many programs is searching a list for a certain element. For example, in a list of names and telephone numbers, you might search for a specific name so 9 This topic can be omitted on first reading without loss of subject continuity. 418 Arrays
  • 439. that the corresponding telephone number can be printed, or you might need to search the list simply to determine whether a name is there. The two most common methods of performing these searches are the linear and binary search algorithms. Linear Search In a linear search, also known as a sequential search, each item in the list is examined in the order in which it occurs until the desired item is found or the end of the list is reached. This search method is analogous to looking at every name in the phone directory, beginning with Aardvark, Aaron, until you find the one you want or until you reach Zzxgy, Zora. Obviously, it’s not the most efficient way to search a long alphabetized list. However, a linear search has these advantages: • The algorithm is simple. • The list need not be in any particular order. In a linear search, the search begins at the first item in the list and continues sequentially, item by item, through the list. The pseudocode for a function performing a linear search is as follows: For all items in the list Compare the item with the desired item If the item is found Return the index value of the current item Endif EndFor Return -1 if the item is not found Notice that the function’s return value indicates whether the item was found. If the return value is -1, the item isn’t in the list; otherwise, the return value in the for loop provides the index of where the item is located in the list. The linearSearch() function illustrates this procedure as a C++ function: // this function returns the location of key in the list // a -1 is returned if the value is not found int linearSearch(int list[], int size, int key) { int i; for (i = 0; i < size; i++) { if (list[i] == key) return i; } return -1; } In reviewing linearSearch(), notice that the for loop is simply used to access each element in the list, from first element to last, until a match with the desired item is found. If the item is located, the index value of the current item is returned, which causes the loop to terminate; otherwise, the search continues until the end of the list is encountered. To test this function, a main() driver function has been written to call linearSearch() and display the results it returns. Program 7.12 shows the complete test program. 419 Chapter 7 A Closer Look: Searching and Sorting
  • 440. Program 7.12 #include <iostream> using namespace std; int linearSearch(int [], int, int); //function prototype int main() { const int NUMEL = 10; int nums[NUMEL] = {5,10,22,32,45,67,73,98,99,101}; int item, location; cout << "Enter the item you are searching for: "; cin >> item; location = linearSearch(nums, NUMEL, item); if (location > -1) cout << "The item was found at index location " << location << endl; else cout << "The item was not found in the listn"; return 0; } // this function returns the location of key in the list // a -1 is returned if the value is not found int linearSearch(int list[], int size, int key) { int i; for (i = 0; i < size; i++) { if (list[i] == key) return i; } return -1; } 420 Arrays
  • 441. Sample runs of Program 7.12 follow: Enter the item you are searching for: 101 The item was found at index location 9 and Enter the item you are searching for: 65 The item was not found in the list As noted previously, an advantage of linear searches is that the list doesn’t have to be in sorted order to perform the search. Another advantage is that if the desired item is toward the front of the list, only a small number of comparisons are made. The worst case, of course, occurs when the desired item is at the end of the list. On average, however, and assuming the item is equally likely to be anywhere in the list, the number of required comparisons is n/2, where n is the list’s size. Therefore, for a 10-element list, the average number of comparisons needed for a linear search is 5, and for a 10,000-element list, the average number of comparisons needed is 5000. As you see next, this number can be reduced significantly by using a binary search algorithm. Binary Search In a binary search, the list must be in sorted order. Starting with an ordered list, the desired item is first compared to the element in the middle of the list. (For lists with an even number of elements, either of the two middle elements can be used.) There are three possibilities after the comparison is made: The desired item might be equal to the middle element, it might be greater than the middle element, or it might be less than the middle element. In the first case, the search has been successful, and no further searches are required. In the second case, because the desired item is greater than the middle element, it must be in the second half of the list, if it’s found at all. This means the first part of the list, consisting of all elements from the first to the midpoint, can be discarded from any further search. In the third case, because the desired item is less than the middle element, it must be in the first part of the list, if it’s found at all. For this case, the second half of the list, containing all elements from the midpoint to the last element, can be discarded from any further search. The algorithm for this search strategy is shown in Figure 7.14 and defined by the following pseudocode: Set the lower index to 0 Set the upper index to one less than the size of the list Begin with the first item in the list While the lower index is less than or equal to the upper index Set the midpoint index to the integer average of the lower and upper index values Compare the desired item to the midpoint element If the desired item equals the midpoint element Return the index value of the current item Else If the desired item is greater than the midpoint element Set the lower index value to the midpoint value plus 1 Else If the desired item is less than the midpoint element Set the upper index value to the midpoint value less 1 Endif EndWhile Return -1 if the item is not found 421 Chapter 7 A Closer Look: Searching and Sorting
  • 442. In both the pseudocode and Figure 7.14’s flowchart, a while loop is used to control the search. The initial list is defined by setting the left index value to 0 and the right index value to one less than the number of elements in the list. The midpoint element is then taken as the integerized average of the left and right values. Set left index to midpoint +1 Item >midpoint element? Item =midpoint element? Calculate midpoint index value While left index <= right index Set right index to list size -1 Set left index to zero No Return -1 Return index value Set right index to midpoint -1 No No Yes Yes Start Input item Yes Figure 7.14 The binary search algorithm 422 Arrays
  • 443. After the comparison to the midpoint element is made, the search is subsequently restricted by moving the left index to one integer value above the midpoint or by moving the right index one integer value below the midpoint. This process is continued until the desired element is found or the left and right index values become equal. The binarySearch() function presents the C++ version of this algorithm: // this function returns the location of key in the list // a -1 is returned if the value is not found int binarySearch(int list[], int size, int key) { int left, right, midpt; left = 0; right = size -1; while (left <= right) { midpt = (int) ((left + right) / 2); if (key == list[midpt]) { return midpt; } else if (key > list[midpt]) left = midpt + 1; else right = midpt - 1; } return -1; } For purposes of testing this function, Program 7.13 is used. A sample run of Program 7.13 yielded the following: Enter the item you are searching for: 101 The item was found at index location 9 Program 7.13 #include <iostream> using namespace std; int binarySearch(int [], int, int); //function prototype int main() { const int NUMEL = 10; 墌 423 Chapter 7 A Closer Look: Searching and Sorting
  • 444. int nums[NUMEL] = {5,10,22,32,45,67,73,98,99,101}; int item, location; cout << "Enter the item you are searching for: "; cin >> item; location = binarySearch(nums, NUMEL, item); if (location > -1) cout << "The item was found at index location " << location << endl; else cout << "The item was not found in the arrayn"; return 0; } // this function returns the location of key in the list // a -1 is returned if the value is not found int binarySearch(int list[], int size, int key) { int left, right, midpt; left = 0; right = size -1; while (left <= right) { midpt = (int) ((left + right) / 2); if (key == list[midpt]) { return midpt; } else if (key > list[midpt]) left = midpt + 1; else right = midpt - 1; } return -1; } 424 Arrays
  • 445. The value of using a binary search algorithm is that the number of elements that must be searched is cut in half each time through the while loop. So the first time through the loop, n elements must be searched; the second time through the loop, n/2 of the elements has been eliminated and only n/2 remain. The third time through the loop, another half of the remaining elements has been eliminated, and so on. In general, after p passes through the loop, the number of values remaining to be searched is n/(2p ). In the worst case, the search can continue until less than or equal to one element remains to be searched. Mathematically, this procedure can be expressed as n/(2p ) ⱕ 1. Alternatively, it can be rephrased as p is the smallest integer so that 2p > n. For example, for a 1000-element array, n is 1000 and the maximum number of passes, p, required for a binary search is 10. Table 7.3 compares the number of loop passes needed for a linear and binary search for different list sizes. Table 7.3 A Comparison of while Loop Passes for Linear and Binary Searches Array size 10 50 500 5000 50,000 500,000 5,000,000 50,000,000 Average linear search passes 5 25 250 2500 25,000 250,000 2,500,000 25,000,000 Maximum linear search passes 10 50 500 5000 50,000 500,000 5,000,000 50,000,000 Maximum binary search passes 4 6 9 13 16 19 23 26 As shown, the maximum number of loop passes for a 50-item list is almost 10 times more for a linear search than for binary search, and even more spectacular for larger lists. As a rule of thumb, 50 elements are usually taken as the switch-over point: For lists smaller than 50 elements, linear searches are acceptable; for larger lists, a binary search algorithm should be used. Big O Notation On average, over a large number of linear searches with n items in a list, you would expect to examine half (n/2) of the items before locating the desired item. In a binary search, the maximum number of passes, p, occurs when n/(2)p = 1. This relationship can be manipulated algebraically to 2p = n, which yields p = log2n, which approximately equals 3.33 log10n. For example, finding a particular name in an alphabetical directory with n = 1000 names requires an average of 500 (=n/2) comparisons using a linear search. With a binary search, only about 10 (⬇ 3.33 * log101000) comparisons are required. A common way to express the number of comparisons required in any search algorithm using a list of n items is to give the order of magnitude of the number of comparisons required, on average, to locate a desired item. Therefore, the linear search is said to be of order n and the binary search of order log2n. Notationally, they’re expressed as O(n) and O(log2n), where the O is read as “the order of.” 425 Chapter 7 A Closer Look: Searching and Sorting
  • 446. Sort Algorithms Two major categories of sorting techniques, called internal and external sorts, are available for sorting data. Internal sorts are used when the data list isn’t too large and the complete list can be stored in the computer’s memory, usually in an array. External sorts are used for much larger data sets that are stored in external disk or tape files and can’t be accommodated in the computer’s memory as a complete unit. Next, you learn about two internal sort algorithms that can be used when sorting lists with fewer than approximately 50 elements. For larger lists, more sophisticated sorting algorithms are typically used. Selection Sort One of the simplest sorting techniques is the selection sort, in which the smallest value is selected from the complete list of data and exchanged with the first element in the list. After this first selection and exchange, the next smallest element in the revised list is selected and exchanged with the second element in the list. Because the smallest element is already in the first position in the list, this second pass needs to consider only the second through last elements. For a list consisting of n elements, this process is repeated n - 1 times, with each pass through the list requiring one less comparison than the previous pass. For example, take a look at the list of numbers shown in Figure 7.15. The first pass through the initial list results in the number 32 being selected and exchanged with the first element in the list. The second pass, made on the reordered list, results in the number 155 being selected from the second through fifth elements. This value is then exchanged with the second element in the list. The third pass selects the number 307 from the third through fifth elements in the list and exchanges this value with the third element. Finally, the fourth and last pass through the list selects the remaining minimum value and exchanges it with the fourth list element. Although each pass in this example resulted in an exchange, no exchange would have been made in a pass if the smallest value were already in the correct location. Initial list Pass 1 Pass 2 Pass 3 Pass 4 690 32 32 32 32 307 307 155 144 144 32 690 690 307 307 155 155 307 690 426 426 426 426 426 690 Figure 7.15 A sample selection sort 426 Arrays
  • 447. In pseudocode, the selection sort is described as follows: Set exchange count to zero (not required, but done to keep track of the exchanges) For each element in the list, from the first to the next to last Find the smallest element from the current element being referenced to the last element by: Setting the minimum value equal to the current element Saving (storing) the index of the current element For each element in the list, from the current element + 1 to the last element in the list If element[inner loop index] < minimum value Set the minimum value = element[inner loop index] Save the index value corresponding to the newfound minimum value Endif EndFor Swap the current value with the new minimum value Increment the exchange count EndFor Return the exchange count The selection Sort() function incorporates this procedure into a C++ function: int selectionSort(int num[], int numel) { int i, j, min, minidx, temp, moves = 0; for ( i = 0; i < (numel - 1); i++) { min = num[i]; // assume minimum is the first array element minidx = i; // index of minimum element for(j = i + 1; j < numel; j++) { if (num[j] < min) // if you've located a lower value { // capture it min = num[j]; minidx = j; } } if (min < num[i]) // check whether you have a new minimum { // and if you do, swap values temp = num[i]; num[i] = min; num[minidx] = temp; moves++; } } return moves; } 427 Chapter 7 A Closer Look: Searching and Sorting
  • 448. The selectionSort() function expects two arguments: the list to be sorted and the number of elements in the list. As the pseudocode specifies, a nested set of for loops performs the sort. The outer for loop causes one less pass through the list than the total number of items in the list. For each pass, the variable min is initially assigned the value num[i], where i is the outer for loop’s counter variable. Because i begins at 0 and ends at one less than numel, each element in the list, except the last, is successively designated as the current element. The inner loop cycles through the elements below the current element and is used to select the next smallest value. Therefore, this loop begins at the index value i + 1 and continues through the end of the list. When a new minimum is found, its value and position in the list are stored in the variables min and minidx. At completion of the inner loop, an exchange is made only if a value less than that in the current position is found. Program 7.14 was constructed to test selectionSort(). This program implements a selection sort for the same list of 10 numbers used to test the search algorithms. For later comparison to other sorting algorithms, the number of actual moves the program makes to get data into sorted order is counted and displayed. The output Program 7.14 produces is as follows: The sorted list, in ascending order, is: 5 10 22 32 45 67 73 98 99 101 8 moves were made to sort this list Clearly, the number of moves displayed depends on the initial order of values in the list. An advantage of the selection sort is that the maximum number of moves that must be made is n - 1, where n is the number of items in the list. Further, each move is a final move that results in an element residing in its final location in the sorted list. A disadvantage of the selection sort is that n(n - 1)/2 comparisons are always required, regardless of the initial arrangement of data. This number of comparisons is obtained as follows: The last pass always requires one comparison, the next-to-last pass requires two comparisons, and so on, to the first pass, which requires n - 1 comparisons. Therefore, the total number of comparisons is the following: 1 + 2 + 3 + . . . + n - 1 = n(n - 1)/2 = n2 /2 - n/2 For large values of n, the n2 term dominates, and the order of the selection sort is O(n2 ). 428 Arrays
  • 449. Program 7.14 #include <iostream> using namespace std; int selectionSort(int [], int); int main() { const int NUMEL = 10; int nums[NUMEL] = {22,5,67,98,45,32,101,99,73,10}; int i, moves; moves = selectionSort(nums, NUMEL); cout << "The sorted list, in ascending order, is:n"; for (i = 0; i < NUMEL; i++) cout << " " <<nums[i]; cout << endl << moves << " moves were made to sort this listn"; return 0; } int selectionSort(int num[], int numel) { int i, j, min, minidx, temp, moves = 0; for ( i = 0; i < (numel - 1); i++) { min = num[i]; // assume minimum is the first array element minidx = i; // index of minimum element for(j = i + 1; j < numel; j++) { if (num[j] < min) // if you've located a lower value { // capture it min = num[j]; minidx = j; } } if (min < num[i]) // check whether you have a new minimum { // and if you do, swap values 墌 429 Chapter 7 A Closer Look: Searching and Sorting
  • 450. Exchange (Bubble) Sort In an exchange sort, adjacent elements of the list are exchanged with one another so that the list becomes sorted. One example of this sequence of exchanges is the bubble sort, in which successive values in the list are compared, beginning with the first two elements. If the list is to be sorted in ascending (from smallest to largest) order, the smaller value of the two being compared is always placed before the larger value. For lists sorted in descending (from largest to smallest) order, the smaller of the two values being compared is always placed after the larger value. For example, a list of values is to be sorted in ascending order. If the first element in the list is larger than the second, the two elements are exchanged. Then the second and third elements are compared. Again, if the second element is larger than the third, these two elements are exchanged. This process continues until the last two elements have been compared and exchanged, if necessary. If no exchanges were made during this initial pass through the data, the data is in the correct order and the process is finished; otherwise, a second pass is made through the data, starting from the first element and stopping at the next-to-last element. The reason for stopping at the next-to-last element on the second pass is that the first pass always results in the most positive value “sinking” to the bottom of the list. To see a specific example, examine the list of numbers in Figure 7.16. The first comparison results in exchanging the first two element values, 690 and 307. The next comparison, between elements two and three in the revised list, results in exchanging values between the second and third elements, 690 and 32. This comparison and possible switching of adjacent values is continued until the last two elements have been compared and possibly exchanged. This process completes the first pass through the data and results in the largest number moving to the bottom of the list. As the largest value sinks to the bottom of the list, the smaller elements slowly rise, or “bubble,” to the top of the list. This bubbling effect of the smaller elements is what gives rise to the name “bubble sort” for this sorting algorithm. temp = num[i]; num[i] = min; num[minidx] = temp; moves++; } } return moves; } 690 307 307 307 307 307 690 32 32 32 32 32 690 155 155 155 155 155 690 426 426 426 426 426 690 Figure 7.16 The first pass of an exchange sort 430 Arrays
  • 451. Because the first pass through the list ensures that the largest value always moves to the bottom of the list, the second pass stops at the next-to-last element. This process continues with each pass stopping at one higher element than the previous pass, until n - 1 passes through the list have been completed or no exchanges are necessary in any single pass. In both cases, the resulting list is in sorted order. The pseudocode describing this sort is as follows: Set exchange count to zero (not required, but done to keep track of the exchanges) For the first element in the list to one less than the last element (i index) For the second element in the list to the last element (j index) If num[j] < num[j - 1] { Swap num[j] with num[j - 1] Increment exchange count } EndFor EndFor Return exchange count This sort algorithm is coded in C++ as the bubbleSort() function, which is included in Program 7.15 for testing purposes. This program tests bubbleSort() with the same list of 10 numbers used in Program 7.14 to test selectionSort(). For comparison to the earlier selection sort, the number of adjacent moves (exchanges) bubbleSort() makes is also counted and displayed. Program 7.15 #include <iostream> using namespace std; int bubbleSort(int [], int); // function prototype int main() { const int NUMEL = 10; int nums[NUMEL] = {22,5,67,98,45,32,101,99,73,10}; int i, moves; moves = bubbleSort(nums, NUMEL); cout << "The sorted list, in ascending order, is:n"; for (i = 0; i < NUMEL; ++i) cout << " " <<nums[i]; cout << endl << moves << " moves were made to sort this listn"; return 0; } 墌 431 Chapter 7 A Closer Look: Searching and Sorting
  • 452. Here’s the output produced by Program 7.15: The sorted list, in ascending order, is: 5 10 22 32 45 67 73 98 99 101 18 moves were made to sort this list As with the selection sort, the number of comparisons in a bubble sort is O(n2 ), and the number of required moves depends on the initial order of values in the list. In the worst case, when the data is in reverse sorted order, the selection sort performs better than the bubble sort. Both sorts require n(n - 1)/2 comparisons, but the selection sort needs only n - 1 moves, and the bubble sort needs n(n - 1)/2 moves. The additional moves the bubble sort requires result from the intermediate exchanges between adjacent elements to “settle” each element into its final position. In this regard, the selection sort is superior because no intermediate moves are necessary. For random data, such as that used in Programs 7.14 and 7.15, the selection sort generally performs equal to or better than the bubble sort. 7.8 Common Programming Errors Four common errors are associated with using arrays: 1. Forgetting to declare the array. This error results in a compiler error message such as “invalid indirection” each time a subscripted variable is encountered in a program. int bubbleSort(int num[], int numel) { int i, j, temp, moves = 0; for ( i = 0; i < (numel - 1); i++) { for(j = 1; j < numel; j++) { if (num[j] < num[j-1]) { temp = num[j]; num[j] = num[j-1]; num[j-1] = temp; moves++; } } } return moves; } 432 Arrays
  • 453. Chapter 12 explains the exact meaning of this error message when establishing the relationship between arrays and pointers. 2. Using a subscript that references a nonexistent array element, such as declaring the array as size 20 and using a subscript value of 25. Most C++ compilers don’t detect this error. However, it results in a runtime error that causes a program crash or results in a value with no relation to the intended element being accessed from memory. In either case, this error is usually difficult to locate. The only solution is to make sure, by specific programming statements or by careful coding, that each subscript references a valid array element. 3. Not using a large enough counter value in a for loop counter to cycle through all the array elements. This error usually occurs when an array is initially specified as size n and there’s a for loop in the program of the form for(i = 0; i < n; i++). The array size is then expanded, but the programmer forgets to change the interior for loop parameters. Declaring an array’s size with a named constant and consis- tently using the named constant throughout the function in place of the variable n eliminates this problem. 4. Forgetting to initialize the array. Although many compilers set all elements of integer and real value arrays to 0 automatically, and all elements of character arrays to blanks, it’s up to the programmer to make sure each array is initialized correctly before processing of array elements begins. 7.9 Chapter Summary 1. A one-dimensional array is a data structure that can be used to store a list of values of the same data type. These arrays must be declared by giving the data type of values stored in the array and the array size. For example, the declaration int num[100]; creates an array of 100 integers. A preferable approach is first using a named constant to set the array size, and then using this constant in the array definition, as shown in these examples: const int MAXSIZE = 100; and int num[MAXSIZE]; 2. Array elements are stored in contiguous locations in memory and referenced by using the array name and a subscript (or index), such as num[22]. Any non-negative integer value expression can be used as a subscript, and the subscript 0 always refers to the first element in an array. 3. A two-dimensional array is declared by listing a row and a column size with the data type and array name. For example, the following declaration creates a two-dimensional array consisting of five rows and seven columns of integer values: int mat[5][7]; 4. Arrays can be initialized when they are declared. For two-dimensional arrays, you list the initial values, row by row, inside braces and separate them with commas. For example, the declaration 433 Chapter 7 Chapter Summary
  • 454. int vals[3][2] = { {1, 2}, {3, 4}, {5, 6} }; produces the following three-row-by-two-column array: 1 2 3 4 5 6 As C++ uses the convention that initialization proceeds in row order, the inner braces can be omitted. Therefore, the following statement is an equivalent initialization: int vals[3][2] = { 1, 2, 3, 4, 5, 6}; 5. Arrays are passed to a function by passing the array name as an argument. The value actually passed is the address of the first array storage location. Therefore, the called function receives direct access to the original array, not a copy of the array elements. A formal argument must be declared in the called function to receive the passed array name. The declaration of the formal argument can omit the array’s row size. Programming Projects for Chapter 7 1. (Statistics) a. Write a C++ program that reads a list of double-precision grades from the keyboard into an array named grade. The grades are to be counted as they’re read, and entry is to be terminated when a negative value has been entered. After all grades have been input, your program should find and display the sum and average of the grades. The grades should then be listed with an asterisk (*) placed in front of each grade that’s below the average. b. Extend the program written for Exercise 1a to display each grade and its letter equivalent, using the following scale: Between 90 and 100 = A. Greater than or equal to 80 and less than 90 = B. Greater than or equal to 70 and less than 80 = C. Greater than or equal to 60 and less than 70 = D. Less than 60 = F. 2. (Practice) Define an array named peopleTypes that can store a maximum of 50 integer values entered at the keyboard. Enter a series of 1s, 2s, 3s, and 4s into the array to represent people at a local school function; 1 represents an infant, 2 represents a child, 3 represents a teenager, and 4 represents an adult. No other integer value should be accepted as valid input, and data entry should stop when a negative value is entered. Your program should count the number of each 1, 2, 3, and 4 in the array and display a list of how many infants, children, teenagers, and adults were at the school function. 3. (Numerical) Given a one-dimensional array of integer numbers, write and test a function that prints the array elements in reverse order. 4. (Numerical) Write and test a function that returns the position of the largest and smallest values in an array of double-precision numbers. 434 Arrays
  • 455. 5. (Sorting) Read a set of numerical grades from the keyboard into an array. The maximum number of grades to be entered is 50, and data entry should be terminated when a negative number is entered. Have your program sort and print the grades in descending order. 6. (Numerical) a. Define an array with a maximum of 20 integer values, and fill the array with numbers input from the keyboard or assigned by the program. Then write a function named split() that reads the array and places all zeros or positive numbers in an array named positive and all negative numbers in an array named negative. Finally, have your program call a function that displays the values in both the positive and negative arrays. b. Extend the program written for Exercise 6a to sort the positive and negative arrays into ascending order before they are displayed. 7. (Numerical) Using the srand() and rand() C++ library functions, fill an array of 1000 floating-point numbers with random numbers that have been scaled to the range 1 to 100. Then determine and display the number of random numbers having values between 1 and 50 and the number having values greater than 50. What do you expect the output counts to be? 8. (Statistical) In many statistical analysis programs, data values considerably outside the range of the majority of values are simply dropped from consideration. Using this information, write a C++ program that accepts up to 10 floating-point values from a user and determines and displays the average and standard deviation of the input values. All values more than four standard deviations away from the computed average are to be displayed and dropped from any further calculation, and a new average and standard deviation should be computed and displayed. 9. (Data Processing) Your professor has asked you to write a C++ program that determines grades at the end of the semester. For each student, identified by an integer number between 1 and 60, four exam grades must be kept, and two final grade averages must be computed. The first grade average is simply the average of all four grades. The second grade average is computed by weighting the four grades as follows: The first grade gets a weight of 0.2, the second grade gets a weight of 0.3, the third grade gets a weight of 0.3, and the fourth grade gets a weight of 0.2. That is, the final grade is computed as follows: 0.2 * grade1 + 0.3 * grade2 + 0.3 * grade3 + 0.2 * grade4 Using this information, construct a 60-by-7 two-dimensional array, in which the first column is used for the student number, the next four columns for the grades, and the last two columns for the computed final grades. The program’s output should be a display of the data in the completed array. For testing purposes, the professor has provided the following data: Student Grade 1 Grade 2 Grade 3 Grade 4 1 100 100 100 100 2 100 0 100 0 3 82 94 73 86 4 64 74 84 94 5 94 84 74 64 435 Chapter 7 Programming Projects
  • 456. 10. (Modify) Modify the program written for Exercise 9 by adding an eighth column to the array. The grade in the eighth column should be calculated by computing the average of the top three grades only. 11. (Data Processing) a. Create a two-dimensional list of integer part numbers and quantities of each part in stock, and write a function that displays data in the array in decreasing quantity order. No more than 100 different parts are being kept track of. Test your program with the following data: Part No. Quantity 1001 62 949 85 1050 33 867 125 346 59 1025 105 b. Modify the function written in Exercise 11a to display the data in part number order. 12. (Data Processing) The answers to a true-false test are as follows: T T F F T. Given a two-dimensional answer array, in which each row corresponds to the answers provided on one test, write a function that accepts the two-dimensional array and number of tests as parameters and returns a one-dimensional array containing the grades for each test. (Each question is worth 5 points so that the maximum possible grade is 25.) Test your function with the following data: Test 1: T F T T T Test 2: T T T T T Test 3: T T F F T Test 4: F T F F F Test 5: F F F F F Test 6: T T F T F 13. (Modify) Modify the function you wrote for Exercise 12 so that each test is stored in column order rather than row order. 14. (Data Processing) A three-dimensional weather array for the months July and August 2008 has planes labeled by the month numbers 7 and 8. In each plane, there are rows numbered 1 through 31, representing the days, and two columns labeled H and L, representing the day’s high and low temperatures. Use this information to write a C++ program that assigns the high and low temperatures for each element of the arrays. Then allow the user to request the following: • Any day’s high and low temperatures • Average high and low temperatures for a given month 436 Arrays
  • 457. • Month and day with the highest temperature • Month and day with the lowest temperature 15. (Computational) A magic square is a square of numbers with N rows and N columns, in which each integer value from 1 to (N * N) appears exactly once, and the sum of each column, each row, and each diagonal is the same value. For example, Figure 7.17 shows a magic square in which N = 3, and the sum of the rows, columns, and diagonal is 15. Write a program that constructs and displays a magic square for any given odd number N. This is the algorithm: Insert the value 1 in the middle of the first row (element [0][N%2]). After a value, x, has been placed, move up one row and to the right one column. Place the next number, x + 1, there, unless: (1) You move off the top (row = -1) in any column. Then move to the bottom row and place the next number, x + 1, in the bottom row of that column. (2) You move off the right end (column = N) of a row. Then place the next number, x + 1, in the first column of that row. (3) You move to a position that is already filled or out of the upper-right corner. Then place the next number, x + 1, immediately below x. Stop when you have placed as many elements as there are in the array. 16. (Computational) Among other applications, Pascal’s triangle (see Figure 7.18) provides a means of determining the number of possible combinations of n things taken r at a time. For example, the number of possible combinations of five people (n = 5) taken two at a time (r = 2) is 10. Each row of the triangle begins and ends with 1. Every other element in a row is the sum of the element directly above it with the element to the left of the one above it. That is, element[n][r] = element[n-1][r] + element[n-1][r-1] Using this information, write and test a C++ program to create the first 11 rows of a two-dimensional array representing Pascal’s triangle. For any given value of n less than 11 and r less than or equal to n, the program should display the correct element. Use your program to determine in how many ways a committee of 8 can be selected from a group of 10 people. 8 1 6 0 1 2 3 5 7 4 0 1 2 9 2 Column Row Figure 7.17 A magic square 437 Chapter 7 Programming Projects
  • 458. 1 1 1 1 1 1 0 1 2 3 4 5 1 1 4 10 3 1 5 4 1 5 0 1 2 3 4 5 n 1 3 6 10 2 r Figure 7.18 Pascal’s triangle Engineering and Scientific Disciplines Mechanical Engineering Generally speaking, mechanical engineers are concerned with machines or systems that produce or apply energy. The range of technological activities considered part of mechanical engineering is probably broader than in any other engineering field. The field can be roughly subdivided into four categories: 앫 Power: Designing power-generating machines and systems, such as boiler-turbine engines for generating electricity, solar power, heating systems, and heat exchanges. 앫 Design: Innovative design of machine parts or components, from the most intricate and small to the gigantic. For example, mechanical engineers work alongside electrical engineers to design automatic control systems, such as robots. 앫 Automotive: Designing and testing transportation vehicles and the machines used to manufacture them. 앫 Heating, ventilation, air conditioning, and refrigeration: Designing systems to control the environment, both indoors and outside, and to control pollution. Mechanical engineers usually have a thorough background in subjects such as ther- modynamics, heat transfer, statics and dynamics, and fluid mechanics. 438 Arrays
  • 459. Chapter 8 I/O Streams and Data Files 8.1 I/O File Stream Objects and Methods 8.2 Reading and Writing Character-Based Files 8.3 Random File Access 8.4 File Streams as Function Arguments 8.5 A Case Study: Pollen Count File Update 8.6 A Closer Look: The iostream Class Library 8.7 Common Programming Errors 8.8 Chapter Summary The data for the programs you have used so far has been assigned internally in the programs or entered by the user during program execution. As such, data used in these programs is stored in the computer’s main memory and ceases to exist after the program using it has finished executing. This type of data entry is fine for small amounts of data. However, imagine a company having to pay someone to type in the names and addresses of hundreds or thousands of customers every month when bills are prepared and sent. As you learn in this chapter, storing large amounts of data outside a program on a convenient storage medium is more sensible. Data stored together under a common name on a storage medium other than the computer’s main memory is called a data file. Typically, data files are stored on disks, USB drives, or CD/DVDs. Besides providing permanent storage for data, data files can be shared between programs, so the data one program outputs can be input in another program. In this chapter, you learn how data files are created and maintained in C++.
  • 460. 8.1 I/O File Stream Objects and Methods To store and retrieve data outside a C++ program, you need two things: • A file • A file stream object You learn about these important topics in this section. Files A file is a collection of data stored together under a common name, usually on a disk, magnetic tape, USB drive, or CD/DVD. For example, the C++ programs you store on disk are examples of files. The stored data in a program file is the code that becomes input data to the C++ compiler. In the context of data processing, however, a C++ program isn’t usually considered data, and the term “file” or “data file” typically refers only to external files containing the data used in a C++ program. A file is physically stored on an external medium, such as a disk. Each file has a unique filename, referred to as the file’s external name. The external name is how the operating system (OS) knows the file. When you review the contents of a directory or folder (for example, in Windows Explorer), you see files listed by their external names. Each computer OS has its own specification for the maximum number of characters permitted for an external filename. Table 8.1 lists these specifications for commonly used OSs. Table 8.1 Maximum Allowable Filename Characters OS Maximum Filename Length DOS 8 characters plus an optional period and 3-character extension Windows 98, 2000, XP, Vista 255 characters UNIX Early versions Current versions 14 characters 255 characters To make sure examples in this book are compatible with all the OSs listed in Table 8.1, the more restrictive DOS specification has been adhered to generally (but not always). If you’re using one of the other OSs, however, you can take advantage of the increased length specification to create descriptive filenames, but avoid using extremely long filenames because they take more time to type and can result in typing errors. A manageable length for a filename is usually 12 to 14 characters, with a maximum of 25 characters. Using the DOS convention, all the following are valid data filenames: prices.dat records info.txt exper1.dat scores.dat math.mem Choose filenames that indicate the type of data in the file and the application for which it’s used. Typically, the first eight characters describe the data, and an extension (the characters after the decimal point) describes the application used to create the file. For example, the Excel program adds the .xls or .xlsx extension automatically to all spreadsheet files, Microsoft Word and WordPerfect use the extensions .doc (or .docx) and 440 I/O Streams and Data Files
  • 461. .wpx (x refers to the version number), and C++ compilers require a program file with the extension .cpp. When creating your own filenames, you should adhere to this practice. For example, using the DOS convention, the name exper1.dat is suitable for describing a file of data corresponding to experiment number 1. Two basic types of files exist: text files, also known as character-based files, and binary-based files. Both file types store data by using a binary code; the difference is in what the codes represent. Briefly, text files store each character, such as a letter, digit, dollar sign, decimal point, and so on, by using a character code (typically ASCII or Unicode). With a character code, a word processing program or text editor can display the files so that a person can read them. Binary-based files use the same code the C++ compiler uses for primitive data types. This means numbers appear in their true binary form, and strings retain their ASCII or Unicode form. The advantage of binary-based files is compactness; storing numbers with their binary code usually takes less space than with character values. In general, programmers use text files more often because the file’s data can be displayed by word processing programs and simple text editors. The default file type in C++ is always a text file and is the file type discussed in this chapter. File Stream Objects A file stream is a one-way transmission path used to connect a file stored on a physical device, such as a disk or CD, to a program. Each file stream has its own mode that determines the direction of data on the transmission path—that is, whether the path moves data from a file to a program or from a program to a file. A file stream that receives or reads data from a file to a program is an input file stream. A file stream that sends or writes data to a file is an output file stream. The direction, or mode, is defined in relation to the program, not the file; data going into a program is considered input data, and data sent out from a program is considered output data. Figure 8.1 illustrates the data flow from and to a file, using input and output file streams. For each file your program uses, regardless of the file’s type (text or binary), a distinct file stream object must be created. If you want your program to read from and write to a file, both input and output file stream objects are required. Input file stream objects are declared to be Point of Information Functions and Methods C++ programmers can make full use of the many functions C++ classes provide with- out knowing the internal details of how the function is constructed or even how to construct a class. Functions provided as part of a class are formally referred to as class methods (or methods, for short). Therefore, a method can be referred to as a func- tion, although the term “method” provides more information in telling you the func- tion is available as part of a class. Part Two (Chapters 10 and 11) explains classes and their construction in detail. As you’ll see, a class is constructed from C++ code that includes both data and functions (although the functions are more accurately referred to as methods). An object is simply a specific item constructed from a class. For example, a specific car is an object, which is a specific item from the class of all cars, or the book you’re reading now is an object, which is a specific item from the class of all third editions of the book C++ For Engineers and Scientists. 441 Chapter 8 I/O File Stream Objects and Methods
  • 462. of type ifstream, and output file stream objects are declared to be of type ofstream. For example, the following declaration statement declares an input file stream object named inFile to be an object of the ifstream class: ifstream inFile; Similarly, the following declaration statement declares an output file stream object named outFile to be an object of the ofstream class: ofstream outFile; In a C++ program, a file stream is accessed by its stream object name: one name for reading the file and one name for writing to the file. Object names, such as inFile and outFile, can be any programmer-selected name that conforms to C++’s identifier rules. File Stream Methods Each file stream object has access to the methods defined for its ifstream or ofstream class. These methods include connecting a stream object name to an external filename (called opening a file), determining whether a successful connection has been made, closing a connection (called closing a file), getting the next data item into the program from an input stream, putting a new data item from the program onto an output stream, and detecting when the end of a file has been reached. Opening a file connects a file stream object to a specific external filename by using a file stream’s open() method, which accomplishes two purposes. First, opening a file establishes the physical connecting link between a program and a file. Because details of this link are handled by the computer’s OS and are not visible to the program, normally the programmer doesn’t need to consider them. From a coding perspective, the second purpose of opening a file is more relevant. Besides establishing the actual physical connection between a program and a data file, opening a file connects the file’s external name to the stream object name that the program uses internally. The method that performs this task, open(), is provided by the ifstream and ofstream classes. Disk Input file stream #include <fstream> int main() { return 0; } Program Output file stream File Figure 8.1 Input and output file streams 442 I/O Streams and Data Files
  • 463. In using the open() method to connect the file’s external name to its internal object stream name, only one argument is required: the external filename. For example, the following statement connects the external file named prices.dat to the internal file stream object named inFile: inFile.open("prices.dat"); This statement assumes, of course, that inFile has been declared as an ifstream or ofstream object. If a file has been opened with the preceding statement, the program accesses the file by using the internal object name inFile, and the computer saves the file under the external name prices.dat. The external filename argument passed to open() is a string enclosed in double quotation marks. Calling the open() method requires standard object notation, in which the method name, in this case open(), is preceded by an object name (inFile, in this example) followed by a period. When an existing file is connecting to an input file stream, the file’s data is made available for input, starting at the first data item in the file. Similarly, a file connected to an output file stream creates a new file, said to be in output mode, and makes the file available for output. If a file exists with the same name as a file opened in output mode, the old file is erased (overwritten) and all its data is lost. When opening a file for input or output, good programming practice requires checking that the connection has been established before attempting to use the file. You can do this with the fail() method, which returns a true value if the file was opened unsuccessfully (that is, it’s true the open failed) or a false value if the open succeeded. Typically, the fail() method is used in code similar to the following, which attempts to open a file named Point of Information Input and Output Streams A stream is a one-way transmission path between a source and a destination. In data transmission, a stream of bytes is sent down this transmission path, similar to a stream of water providing a one-way path for water to travel from a source to a destination. Stream objects are created from stream classes. You have already used two stream objects extensively: the input stream object named cin and the output stream object named cout. The cin object, created from the istream stream class, provides a transmission path from keyboard to program. The cout object, created from the ostream stream class, provides a transmission path from program to screen. The istream and ostream stream classes are parent classes to the iostream class. When the iostream header file is included in a program with the #include <iostream> directive, the cin and cout stream objects are declared automatically and opened by the C++ compiler. File stream objects provide the same capabilities as the cin and cout objects, except they connect a program to a file rather than the keyboard or screen. File stream objects must be declared explicitly as objects of the ifstream class (for input) or objects of the ofstream class (for output). The ifstream and ofstream classes are made available by including the fstream header file with the directive #include <fstream>. The fstream class is derived from the ifstream and ofstream classes. 443 Chapter 8 I/O File Stream Objects and Methods
  • 464. prices.dat for input, checks that a valid connection was made, and reports an error message if the file wasn’t opened for input successfully: ifstream inFile; // any object name can be used here inFile.open("prices.dat"); // open the file // check that the connection was successfully opened if (inFile.fail()) { cout << "nThe file was not successfully opened" << "n Please check that the file currently exists." << endl; exit(1); } If the fail() method returns a true, indicating the open failed, this code displays an error message. In addition, the exit() function, which is a request to the OS to end program execution immediately, is called. The cstdlib header function must be included in any program using exit(), and exit()’s single-integer argument is passed directly to the OS for any further program action or user inspection. Throughout the remainder of the book, this type of error checking is included whenever a file is opened. (Section 9.2 shows how to use exception handling for the same type of error checking.) In addition to the fail() method, C++ provides three other methods, listed in Table 8.2, for detecting a file’s status. Table 8.2 File Status Methods Prototype Description fail() Returns a Boolean true if the file hasn’t been opened successfully; otherwise, returns a Boolean false value. eof() Returns a Boolean true if a read has been attempted past the end-of-file; otherwise, returns a Boolean false value. The value becomes true only when the first character after the last valid file character is read. good() Returns a Boolean true value while the file is available for program use. Returns a Boolean false value if a read has been attempted past the end-of-file. The value becomes false only when the first character after the last valid file character is read. bad() Returns a Boolean true value if a read has been attempted past the end-of-file; otherwise, returns a false. The value becomes true only when the first character after the last valid file character is read. Program 8.1 shows the statements required to open a file for input, including an error-checking routine to ensure that the open was successful. A file opened for input is said to be in read mode or input mode. (These two terms are synonymous.) 444 I/O Streams and Data Files
  • 465. A sample run of Program 8.1 produces the following output: The file has been successfully opened for reading. A different check is required for output files (files that are written to) because if a file exists with the same name as the file to be opened in output mode, the existing file is erased and all its data is lost. To avoid this situation, the file is first opened in input mode to see whether it exists. If it does, the user is given the choice of permitting it to be overwritten when it’s opened later in output mode. The code to accomplish this check is shaded in Program 8.2. Program 8.1 #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() using namespace std; int main() { ifstream inFile; inFile.open("prices.dat"); // open the file with the // external name prices.dat if (inFile.fail()) // check for a successful open { cout << "nThe file was not successfully opened" << "n Please check that the file currently exists." << endl; exit(1); } cout << "nThe file has been successfully opened for reading." << endl; // statements to read data from the file would be placed here return 0; } 445 Chapter 8 I/O File Stream Objects and Methods
  • 466. Program 8.2 #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() using namespace std; int main() { ifstream inFile; ofstream outFile; inFile.open("prices.dat"); // attempt to open the file for input char response; if (!inFile.fail()) // if it doesn't fail, the file exists { cout << "A file by the name prices.dat exists.n" << "Do you want to continue and overwrite itn" << " with the new data (y or n): "; cin >> response; if (tolower(response) == 'n') { cout << "The existing file will not be overwritten." << endl; exit(1); //terminate program execution } } outFile.open("prices.dat"); // now open the file for writing if (inFile.fail()) // check for a successful open { cout << "nThe file was not successfully opened" << endl; exit(1); } cout << "The file has been successfully opened for output." << endl; // statements to write to the file would be placed here return 0; } 446 I/O Streams and Data Files
  • 467. The following two runs were made with Program 8.2: A file by the name prices.dat exists. Do you want to continue and overwrite it with the new data (y or n): n The existing file will not be overwritten. and A file by the name prices.dat exists. Do you want to continue and overwrite it with the new data (y or n): y The file has been successfully opened for output. Although Programs 8.1 and 8.2 can be used to open an existing file for reading and writing, both programs lack statements to perform a read or write and close the file. These topics are discussed shortly. Before moving on, however, it’s possible to combine the declaration of an ifstream or ofstream object and its associated open statement into one statement. For example, examine the following two statements in Program 8.1: ifstream inFile; inFile.open("prices.dat"); They can be combined into a single statement: ifstream inFile("prices.dat"); Embedded and Interactive Filenames Programs 8.1 and 8.2 have two problems: • The external filename is embedded in the program code. • There’s no provision for a user to enter the filename while the program is running. As both programs are written, if the filename is to change, a programmer must modify the external filename in the call to open() and recompile the program. Both these problems can be avoided by assigning the filename to a string variable. A string variable, as used in this book, is a variable that can hold a string value, which is any sequence of zero or more characters enclosed in quotation marks, such as "Hello World" and "". Remember that the quotation marks delimit the beginning and end of a string but aren’t stored as part of the string. In declaring and initializing a string variable for use in an open() method, the string is considered a C-string. (See the Point of Information “Using C-Strings as Filenames” for precautions when using a C-string.) A safer alternative, and one used throughout this book, is to use a string class object and convert it to a C-string by using the c_str() method. 447 Chapter 8 I/O File Stream Objects and Methods
  • 468. After a string variable is declared to store a filename, it can be used in one of two ways. First, as shown in Program 8.3a, it can be placed at the top of a program to clearly identify a file’s external name, instead of embedding it in an open() method call. Point of Information Using C-Strings as Filenames If you use a C-string (which is simply a one-dimensional array of characters) to store an external filename, you must specify the C-string’s maximum length in brackets immedi- ately after it’s declared. For example, examine the following declaration: char filename[21] = "prices.dat"; The number in brackets (21) is one more than the maximum number of characters that can be assigned to the variable filename because the compiler adds an end-of- string character to terminate the string. Therefore, the string value "prices.dat", which consists of 10 characters, is actually stored as 11 characters. In this example, the maximum value that can be assigned to the string variable filename is a string value consisting of 20 characters. Program 8.3a #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() #include <string> using namespace std; int main() { string filename = "prices.dat"; // place the filename up front ifstream inFile; inFile.open(filename.c_str()); // open the file if (inFile.fail()) // check for successful open { cout << "nThe file named " << filename << " was not successfully opened" << "n Please check that the file currently exists." << endl; exit(1); } cout << "nThe file has been successfully opened for reading.n"; return 0; } 448 I/O Streams and Data Files
  • 469. In Program 8.3a, the string object is declared and initialized with the name filename. This name is placed at the top of main() for easy file identification. When a string object is used, as opposed to a string literal, the variable name isn’t enclosed in quotation marks in the open() method call. In the open() call, the value of the string object, which is a C-string, is provided by the expression filename.c_str(). Finally, in the fail() method, the file’s external name is displayed by inserting the string object’s name in the cout output stream. External names of files are identified in this manner in this book. Another useful role string objects play is to permit users to enter the filename as the program is executing. For example, the code string filename; cout << "Please enter the name of the file you wish to open: "; cin >> filename; allows a user to enter a file’s external name at runtime. The only restriction in this code is that the user must not enclose the entered string value in quotation marks, and the entered string value can’t contain any blanks. The reason no blanks can be included is that when cin is used, the compiler terminates the string when it encounters a blank. Program 8.3b uses this code in the context of a complete program. Program 8.3b #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() #include <string> using namespace std; int main() { string filename; ifstream inFile; cout << "Please enter the name of the file you wish to open: "; cin >> filename; inFile.open(filename.c_str()); // open the file if (inFile.fail()) // check for successful open { cout << "nThe file named " << filename << " was not successfully opened" << "n Please check that the file currently exists." << endl; exit(1); } cout << "nThe file has been successfully opened for reading.n"; return 0; } 449 Chapter 8 I/O File Stream Objects and Methods
  • 470. Point of Information Using fstream Objects In using ifstream and ofstream objects, the input or output mode is indicated by the object. Therefore, ifstream objects must be used for input, and ofstream objects must be used for output. Another means of creating file streams is to use fstream objects that can be used for input or output, but this method requires an explicit mode designation. An fstream object is declared by using the following syntax: fstream objectName; When using the fstream class’s open() method, two arguments are required: a file’s external name and a mode indicator. Here are the permissible mode indicators: Indicator Description ios::in Open a text file in input mode ios::out Open a text file in output mode ios::app Open a text file in append mode ios::ate Go to the end of the opened file ios::binary Open a binary file in input mode (default is text file) ios::trunc Delete file contents if it exists ios::nocreate If file doesn’t exist, open fails ios::noreplace If file exists, open for output fails As with ofstream objects, an fstream object in output mode creates a new file and makes the file available for writing. If a file exists with the same name as a file opened for output, the old file is erased. For example, the following statement declares file1 as an object of type fstream: fstream file1; The following statement attempts to open the text file prices.dat for output: file1.open("prices.dat",ios::out); After this file has been opened, the program accesses the file by using the internal object name file1, and the computer saves the file under the external name prices.dat. An fstream file object opened in append mode means an existing file is avail- able for data to be added to the end of the file. If the file opened for appending doesn’t exist, a new file with the designated name is created and made available to receive output from the program. For example, the following statement declares file1 to be of type fstream and attempts to open a text file named prices.dat and make it available for data to be added to the end of the file: file1.open("prices.dat",ios::app); continued... 450 I/O Streams and Data Files
  • 471. The following is a sample output of Program 8.3b: Please enter the name of the file you wish to open: foobar The file named foobar was not successfully opened Please check that the file currently exists. Closing a File A file is closed by using the close() method. This method breaks the connection between the file’s external name and the file stream object, which can be used for another file. Examine the following statement, which closes the inFile stream’s connection to its current file: inFile.close(); As indicated, the close() method takes no argument. Because all computers have a limit on the maximum number of files that can be open at one time, closing files that are no longer needed makes good sense. Any open files existing at the end of normal program execution are closed automatically by the OS. EXERCISES 8.1 1. (Practice) Write declaration and open statements that link the following external filenames to their corresponding internal object names. All files are text-based. Point of Information Using fstream Objects (continued) Finally, an fstream object opened in input mode means an existing external file has been connected and its data is available as input. For example, the following state- ment declares file1 to be of type fstream and attempts to open a text file named prices.dat for input: file1.open("prices.dat",ios::in); The mode indicators can be combined by the bitwise OR operator, | (see Section 15.2). For example, the following statement opens the file1 stream, which can be an fstream or ifstream, as an input binary stream: file1.open("prices.dat", ios::in | ios::binary) If the mode indicator is omitted as the second argument for an ifstream object, the stream is opened as a text input file by default; if the mode indicator is omitted for an ofstream object, the stream is opened as a text output file by default. 451 Chapter 8 I/O File Stream Objects and Methods
  • 472. External Filename Internal Object Name Mode coba.mem memo output book.let letter output coupons.bnd coups append yield.bnd yield append prices.dat priFile input rates.dat rates input 2. (Practice) a. Write a set of two statements that declares the following objects as ifstream objects, and then opens them as text input files: inData.txt, prices.txt, coupons.dat, and exper.dat. b. Rewrite the two statements for Exercise 2a, using a single statement. 3. (Practice) a. Write a set of two statements that declares the following objects as ofstream objects, and then opens them as text output files: outDate.txt, rates.txt, distance.txt, and file2.txt. b. Rewrite the two statements for Exercise 3a, using a single statement. 4. (Practice) Enter and execute Program 8.1 on your computer. 5. (Practice) Enter and execute Program 8.2 on your computer. 6. (Practice) a. Enter and execute Program 8.3a on your computer. b. Add a close() method to Program 8.3a, and then execute the program. 7. (Practice) a. Enter and execute Program 8.3b on your computer. b. Add a close() method to Program 8.3b, and then execute the program. 8. (Practice) Using the reference manuals provided with your computer’s OS, determine the following: a. The maximum number of characters the computer can use to name a file for storage b. The maximum number of data files that can be open at the same time 9. (Practice) Would it be appropriate to call a saved C++ program a file? Why or why not? 10. (Practice) a. Write declaration and open statements to link the following external file- names to their corresponding internal object names. Use only ifstream and ofstream objects. External Name Internal Object Name Mode coba.mem memo binary and output coupons.bnd coups binary and append prices.dat priFile binary and input b. Redo Exercise 10a, using only fstream objects. c. Write close statements for each file opened in Exercise 10a. 452 I/O Streams and Data Files
  • 473. Point of Information Checking for a Successful Connection You must check that the open() method established a connection between a file stream and an external file successfully because the open() call is a request to the OS that can fail for various reasons. Chief among these reasons is a request to open an existing file for reading that the OS can’t locate or a request to open a file for output in a nonexistent folder. If the OS can’t satisfy the open request, you need to know about it and terminate your program. Failure to do so can result in abnormal program behavior or a program crash. There are two styles of coding for checking the return value. The most common method for checking that a fail didn’t occur when attempting to use a file for input is the one coded in Program 8.1. It’s used to distinguish the open() request from the check made via the fail() call and is repeated here for convenience: inFile.open("prices.dat"); // request to open the file if (inFile.fail()) // check for a failed connection { cout << "nThe file was not successfully opened" << "n Please check that the file currently exists." << endl; exit(1); } Similarly, the check made in Program 8.2 is typically included when a file is being opened in output mode. Alternatively, you might encounter programs that use fstream objects in place of ifstream and ofstream objects (see the previous Point of Information box). When using fstream’s open() method, two arguments are required: a file’s external name and an explicit mode indication. Using an fstream object, the open request and check for an input file typically appear as follows: fstream inFile; inFile.open("external name", ios::in); if (inFile.fail()) { cout << "nThe file was not successfully opened" << "n Please check that the file currently exists." << endl; exit(1); } Many times, the conditional expression inFile.fail() is replaced by the equivalent expression !inFile. Although ifstream and ofstream objects are always used in this book, be prepared to encounter styles that use fstream objects. 453 Chapter 8 I/O File Stream Objects and Methods
  • 474. 8.2 Reading and Writing Character-Based Files Reading or writing character-based files involves almost the identical operations for reading input from the keyboard and writing data to the screen. For writing to a file, the cout object is replaced by the ofstream object name declared in the program. For example, if outFile is declared as an object of type ofstream, the following output statements are valid: outFile << 'a'; outFile << "Hello World!"; outFile << descrip << ' ' << price; The filename in each of these statements, in place of cout, directs the output stream to a specific file instead of to the standard display device (the screen). Program 8.4 shows using the insertion operator, <<, to write a list of descriptions and prices to a file. Program 8.4 #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() #include <string> #include <iomanip> // needed for formatting using namespace std; int main() { string filename = "prices.dat"; // put the filename up front ofstream outFile; outfile.open(filename.c_str()); if (outFile.fail()) { cout << "The file was not successfully opened" << endl; exit(1); } // set the output file stream formats outFile << setiosflags(ios::fixed) << setiosflags(ios::showpoint) << setprecision(2); 墌 454 I/O Streams and Data Files
  • 475. When Program 8.4 runs, the, prices.dat file is created and saved by the computer as a text file. It’s a sequential file consisting of the following data: Mats 39.95 Bulbs 3.22 Fuses 1.08 The actual storage of characters in the file depends on the character codes the computer uses. Although only 30 characters appear to be stored in the file—corresponding to the descriptions, blanks, and prices written to the file—the file contains 36 characters. The extra characters consist of the newline escape sequence at the end of each line created by the endl manipulator, which is created as a carriage return character (cr) and linefeed (lf). Assuming characters are stored with the ASCII code, the prices.dat file is physically stored as shown in Figure 8.2. For convenience, the character corresponding to each hexadecimal code is listed below the code. A code of 20 represents the blank character. Additionally, C and C++ append the low-value hexadecimal byte 0x00 as the end-of-file (EOF) sentinel when the file is closed. This EOF sentinel is never counted as part of the file. // send data to the file outFile << "Mats " << 39.95 << endl << "Bulbs " << 3.22 << endl << "Fuses " << 1.08 << endl; outFile.close(); cout << "The file " << filename << " has been successfully written." << endl; return 0; } 4D M 61 a 74 t 73 s 20 33 3 39 9 2E . 39 9 35 5 0D cr 0A 1f 42 B 75 u 6C l 62 b 73 s 20 33 3 2E . 32 2 32 2 0D cr 0A 1f 46 F 75 u 73 s 65 e 73 s 20 31 1 2E . 30 0 38 8 0D cr 0A 1f Figure 8.2 The prices.dat file as stored by the computer 455 Chapter 8 Reading and Writing Character- Based Files
  • 476. Reading from a Text File Reading data from a character-based file is almost identical to reading data from a standard keyboard, except the cin object is replaced by the ifstream object declared in the program. For example, if inFile is declared as an object of type ifstream that’s opened for input, the following statement reads the next two items in the file and stores them in the variables descrip and price: inFile >> descrip >> price; The file stream name in this statement, in place of cin, directs the input to come from the file stream rather than the standard input device stream. Table 8.3 lists other methods that can be used for stream input. These methods must be preceded by a stream object name. All these methods, except getline(), are defined in the iostream class. The getline() method is defined in the string class. Point of Information Formatting Text File Output Stream Data Output file streams can be formatted in the same manner as the cout standard output stream. For example, if an output stream named fileOut has been declared, the fol- lowing statement formats all data inserted in the fileOut stream in the same way these parameterized manipulators work for the cout stream: fileOut << setiosflags(ios::fixed) << setiosflags(ios::showpoint) << setprecision(2); The first manipulator parameter, ios::fixed, causes the stream to output all num- bers as though they were floating-point values. The next parameter, ios::showpoint, tells the stream to provide a decimal point. Therefore, a value such as 1.0 appears as 1.0, not 1. Finally, the setprecision() manipulator tells the stream to display two decimal values after the decimal point. Therefore, the number 1.0, for example, appears as 1.00. Instead of using manipulators, you can use the stream methods setf() and precision(). For example, the previous formatting can be accomplished with the following code: fileOut.setf(ios::fixed); fileOut.setf(ios::showpoint); fileOut.precision(2); Which style you select is a matter of preference. In both cases, the formats need be specified only once and remain in effect for every number subsequently inserted in the file stream. 456 I/O Streams and Data Files
  • 477. Table 8.3 Stream Input Class Methods Method Name Description get() Returns the next character extracted from the input stream as an int. get(charVar) Overloaded version of get() that extracts the next character from the input stream and assigns it to the specified character variable, charVar. getline(fileObject, strObj, termChar) Extracts characters from the specified input stream, fileObject, until the terminating character, termChar, is encountered. Assigns the characters to the specified string class object, strObj. peek() Returns the next character in the input stream without extracting it from the stream. ignore(int n) Skips over the next n characters. If n is omitted, the default is to skip over the next single character. Program 8.5 shows how the prices.dat file created in Program 8.4 can be read. This program illustrates one way of detecting the EOF marker by using the good() method (see Table 8.2). Because this method returns a Boolean true value before the EOF marker has been read or passed over, it can be used to verify that the data read is valid file data. Only after the EOF marker has been read or passed over does this method return a Boolean false. Therefore, the notation while(inFile.good()) used in Program 8.5 ensures that the data is read from the file before the EOF has been read. Point of Information The put() Method All output streams have access to the fstream class’s put() method, which permits character-by-character output to a stream. This method works in the same manner as the character insertion operator, <<. The syntax of this method call is the following: ofstreamName.put(characterExpression); The characterExpression can be a character variable or literal value. For example, the following code can be used to output an 'a' to the standard output stream: cin.put('a'); In a similar manner, if outFile is an ofstream object file that has been opened, the following code outputs the character value in the character variable named keycode to this output: char keycode; . . outFile.put(keycode); 457 Chapter 8 Reading and Writing Character- Based Files
  • 478. Program 8.5 produces the following display: Mats 39.95 Bulbs 3.22 Fuses 1.08 Program 8.5 #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() #include <string> using namespace std; int main() { string filename = "prices.dat"; // put the filename up front string descrip; double price; ifstream inFile; inFile.open(filename.c_str()); if (inFile.fail()) // check for successful open { cout << "nThe file was not successfully opened" << "n Please check that the file currently exists." << endl; exit(1); } // read and display the file's contents inFile >> descrip >> price; while (inFile.good()) // check next character { cout << descrip << ' ' << price << endl; inFile >> descrip >> price; } inFile.close(); return 0; } 458 I/O Streams and Data Files
  • 479. Point of Information A Way to Identify a File’s Name and Location During program development, test files are usually placed in the same directory as the program. Therefore, a method call such as inFile.open("exper.dat") causes no problems to the OS. In production systems, however, it’s not uncommon for data files to reside in one directory and program files to reside in another. For this reason, includ- ing the full pathname of any file that’s opened is always a good idea. For example, if the exper.dat file resides in the C:testfiles directory, the open() call should include the full pathname: inFile.open("C:test filesexper.dat"). Then, no matter where the program is run from, the OS knows where to locate the file. Note the use of double backslashes, which is required. Another important convention is to list all filenames at the top of a program instead of embedding the names deep in the code. You can do this easily by using string variables to store each filename. For example, if the statement string filename = "c:testfilesexper.dat"; is placed at the top of a program file, the declaration statement clearly lists both the name of the file and its location. Then, if some other file is to be tested, all that’s required is a simple one-line change at the top of the program. Using a string variable for the file’s name is also useful for the fail() method check. For example, take a look at the following code: string filename; ifstream infile; inFile.open(filename.c_str()); if (inFile.fail()) { cout << "n The file named " << filename << was not successfully opened" <<n Please check that this file currently exists."; exit(1); } In this code, the name of the file that failed to open is displayed in the error mes- sage without the name being embedded as a string value. 459 Chapter 8 Reading and Writing Character- Based Files
  • 480. Examine the expression inFile.good() used in the while statement. This expres- sion is true as long as the EOF marker hasn’t been read. Therefore, as long as the item read is good, the loop continues to read the file. Within the loop, the items just read are displayed, and then a new string and a double-precision number are input to the program. When the EOF has been detected, the expression returns a Boolean value of false and the loop terminates. This termination ensures that data is read and displayed up to, but not including, the EOF marker. A replacement for the statement while(inFile.good()) is while(!inFile. eof()), which is read as "while the end of file has not been reached." This replacement works because the eof() method returns a true only after the EOF marker has been read or passed over. In effect, the relational expression checks that the EOF hasn’t been read—hence, the use of the NOT operator, !. Another means of detecting the EOF is to use the fact that the extraction operation, >>, returns a Boolean value of true if data is extracted from a stream; otherwise, it returns a Boolean false value. Using this return value, the following code can be used in Program 8.5 to read the file: // read and display the file's contents while (inFile >> descrip >> price) // check next character cout << descrip << ' ' << price << endl; Although this code seems a bit cryptic at first glance, it makes perfect sense when you understand that the expression being tested extracts data from the file and returns a Boolean value to indicate whether the extraction was successful. Finally, in the previous while statement or in Program 8.5, the expression inFile >> descrip >> price can be replaced by a getline() method (see Table 8.3). For file input, this method has the following syntax: getline(fileObject, strObj, terminatingChar) fileObject is the name of the ifstream file, strObj is a string class object, and terminatingChar is an optional character constant or variable specifying the terminating character. If this optional third argument is omitted, the default terminating character is the newline ('n') character. Program 8.6 shows using getline() in the context of a complete program. Program 8.6 is a line-by-line text-copying program, which reads a line of text from the file and then displays it on the screen. The output of Program 8.6 is the following: Mats 39.95 Bulbs 3.22 Fuses 1.08 If obtaining the description and price as separate variables were necessary, either Program 8.5 should be used, or the string returned by getline() in Program 8.6 must be processed further to extract the separate data items. (See Section 8.6 for parsing procedures.) 460 I/O Streams and Data Files
  • 481. Standard Device Files The file stream objects you have seen so far have been logical file objects. A logical file object is a stream that connects a file of logically related data, such as a data file, to a program. In addition to logical file objects, C++ supports physical file objects. A physical file object is a stream that connects to a hardware device, such as a keyboard, screen, or printer. The actual physical device assigned to your program for data entry is formally called the standard input file. Usually, it’s the keyboard. When a cin object method call is encountered in a C++ program, it’s a request to the OS to go to this standard input file for the expected input. Similarly, when a cout object method call is encountered, the output is automatically displayed or “written to” a device that has been assigned as the standard output file. For most systems, it’s a computer screen, although it can also be a printer. Program 8.6 #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() #include <string> using namespace std; int main() { string filename = "prices.dat"; // put the filename up front string line; ifstream inFile; inFile.open(filename.c_str()); if (inFile.fail()) // check for successful open { cout << "nThe file was not successfully opened" << "n Please check that the file currently exists." << endl; exit(1); } // read and display the file's contents while (getline(inFile,line)) cout << line << endl; inFile.close(); return 0; } 461 Chapter 8 Reading and Writing Character- Based Files
  • 482. When a program is executed, the standard input stream cin is connected to the standard input device. Similarly, the standard output stream cout is connected to the standard output device. These two object streams are available for programmer use, as are the standard error stream, cerr, and the standard log stream, clog. Both these streams connect to the screen. Other Devices The keyboard, display, error, and log streams are connected automatically to the stream objects cin, cout, cerr, and clog when the iostream header file is included in a program. Other devices can be used for input or output if the name assigned by the system is known. For example, most IBM or IBM-compatible PCs assign the name prn to the printer connected to the computer. For these computers, a statement such as outFile.open("prn") connects the Point of Information The get() and putback() Methods All input streams have access to the fstream class’s get() method, used for character-by-character input from an input stream. This method works similarly to char- acter extraction, using the >> operator, with two important differences: If a newline character, 'n', or a blank character, ' ', is encountered, these characters are read in the same manner as any other alphanumeric character. The syntax of this method call is the following: istreamName.get(characterVariable); For example, the following code can be used to read the next character from the standard input stream and store the character in the variable ch: char ch; cin.get(ch); Similarly, if inFile is an ifstream object that has been opened to a file, the following code reads the next character in the stream and assigns it to the character variable keycode: char keycode; inFile.get(keycode); In addition to the get() method, all input streams have a putback() method for putting the last character read from an input stream back on the stream. This method has the following syntax (with characterExpression representing any character variable or character value): ifstreamName.putback(characterExpression); The putback() method provides output capability to an input stream. The put- back character need not be the last character read; it can be any character. All putback characters, however, have no effect on the data file. They affect only the open input stream. Therefore, the data file characters remain unchanged, although the characters subsequently read from the input stream can change. 462 I/O Streams and Data Files
  • 483. printer to the ofstream object named outFile. A subsequent statement, such as outFile << "Hello World!";, would cause the string Hello World! to be output directly to the printer. As the name of an actual file, prn must be enclosed in quotation marks in the open() method call. EXERCISES 8.2 1. (Practice and Modify) a. Enter and execute Program 8.5. b. Modify Program 8.5 to use the expression !inFile.eof() in place of the expression inFile.good(), and execute the program to see whether it operates correctly. 2. (Practice and Modify) a. Enter and execute Program 8.6. b. Modify Program 8.6 by replacing cout with cerr, and verify that the output for the standard error stream is the screen. c. Modify Program 8.6 by replacing cout with clog, and verify that the output for the standard log stream is the screen. 3. (Practice and Modify) a. Write a C++ program that accepts lines of text from the key- board and writes each line to a file named text.dat until an empty line is entered. An empty line is a line with no text that’s created by pressing the Enter (or Return) key. b. Modify Program 8.6 to read and display the data stored in the text.dat file created in Exercise 3a. 4. (Practice) Determine the OS command or procedure your computer provides to display the contents of a saved file. 5. (Data Processing) a. Create a text file named employee.dat containing the following data: Anthony A 10031 7.82 12/18/2008 Burrows W 10067 9.14 06/9/2006 Fain B 10083 8.79 05/18/2007 Janney P 10095 10.57 09/28/2008 Smith G 10105 8.50 12/20/2007 b. Write a C++ program to read the employee.dat file created in Exercise 5a and pro- duce a duplicate copy of the file named employee.bak. c. Modify the program written in Exercise 5b to accept the names of the original and duplicate files as user input. d. The program written for Exercise 5c always copies data from an original file to a duplicate file. What’s a better method of accepting the original and duplicate filenames, other than prompting the user for them each time the program runs? 463 Chapter 8 Reading and Writing Character- Based Files
  • 484. 6. (Data Processing) a. Write a C++ program that opens a file and displays its contents with line numbers. That is, the program should print the number 1 before displaying the first line, print the number 2 before displaying the second line, and so on for each line in the file. b. Modify the program written in Exercise 6a to list the file’s contents on the printer assigned to your computer. 7. (Data Processing) a. Create a text file containing the following data (without the headings): Name Social Security Number Hourly Rate Hours Worked B Caldwell 555-88-2222 7.32 37 D Memcheck 555-77-4444 8.32 40 R Potter 555-77-6666 6.54 40 W Rosen 555-99-8888 9.80 35 b. Write a C++ program that reads the data file created in Exercise 7a and computes and displays a payroll schedule. The output should list the Social Security number, name, and gross pay for each person, calculating gross pay as Hourly Rate × Hours Worked. 8. (Data Processing) a. Create a text file containing the following data (without the headings): Car Number Miles Driven Gallons of Gas Used 54 250 19 62 525 38 71 123 6 85 1322 86 97 235 14 b. Write a C++ program that reads the data in the file created in Exercise 8a and displays the car number, miles driven, gallons of gas used, and miles per gallon (mpg) for each car. The output should contain the total miles driven, total gallons of gas used, and average mpg for all cars. These totals should be displayed at the end of the output report. 9. (Data Processing) a. Create a text file with the following data (without the headings): Part Number Initial Amount Quantity Sold Minimum Amount QA310 95 47 50 CM145 320 162 200 MS514 34 20 25 EN212 163 150 160 464 I/O Streams and Data Files
  • 485. b. Write a C++ program to create an inventory report based on the data in the file cre- ated in Exercise 9a. The display should consist of the part number, current balance, and the amount needed to bring the inventory to the minimum level. The current balance is the initial amount minus the quantity sold. 8.3 Random File Access The term file access refers to the process of retrieving data from a file. There are two types of file access: sequential access and random access. To understand file access types, first you need to understand how data is organized in a file. The term file organization refers to the way data is stored in a file. The files you have used, and will continue to use, have a sequential organization, meaning characters in the file are stored in a sequential manner. In addition, each open file has been read in a sequential manner, meaning characters are accessed one after another, which is called sequential access. Although characters are stored sequentially, they don’t have to be accessed the same way. In fact, you can skip over characters and read a sequentially organized file in a nonsequential manner. In random access, any character in the opened file can be read without having to sequentially read all characters stored ahead of it first. To provide random access to files, each ifstream object creates a file position marker automatically. This marker is a long integer representing an offset from the beginning of the file and keeps track of where the next character is to be read from or written to. Table 8.4 lists the methods used to access and change the file position marker. The suffixes g and p in these method names denote get and put; get refers to an input (get from) file, and put refers to an output (put to) file. Table 8.4 File Position Marker Methods Name Description seekg(offset, mode) For input files, move to the offset position indicated by the mode. seekp(offset, mode) For output files, move to the offset position indicated by the mode. tellg(void) For input files, return the current value of the file position marker. tellp(void) For output files, return the current value of the file position marker. The seek() methods allow the programmer to move to any position in the file. To understand these methods, you must understand how data is referenced in the file by using the file position marker. Each character in a data file is located by its position in the file. The first character in the file is located at position 0, the next character at position 1, and so forth. A character’s position is referred to as its offset from the start of the file. Therefore, the first character has a 0 offset, the second character has an offset of 1, and so on, for each character in the file. The seek() methods require two arguments: the offset, as a long integer, in the file and where the offset is to be calculated from, determined by the mode. The three alternatives for the mode are ios::beg, ios::cur, and ios::end, which denote the beginning of the file, 465 Chapter 8 Random File Access
  • 486. current position, and end of the file. Therefore, the mode ios::beg means the offset is the true offset from the start of the file. The mode ios::cur means the offset is relative to the current position in the file, and the mode ios::end means the offset is relative to the end of the file. A positive offset means move forward in the file, and a negative offset means move backward. Examples of seek() method calls are shown in the following code. In these examples, inFile has been opened as an input file and outFile as an output file. The offset passed to seekg() and seekp() must be a long integer, hence the uppercase L appended to each number in the method calls. inFile.seekg(4L,ios::beg); // go to the fifth character in the input file outFile.seekp(4L,ios::beg); // go to the fifth character in the output file inFile.seekg(4L,ios::cur); // move ahead five characters in the input file outFile.seekp(4L,ios::cur); // move ahead five characters in the output file inFile.seekg(-4L,ios::cur); // move back five characters in the input file outFile.seekp(-4L,ios::cur); // move back five characters in the output file inFile.seekg(0L,ios::beg); // go to start of the input file outfile.seekp(0L,ios::beg); // go to start of the output file inFile.seekg(0L,ios::end); // go to end of the input file outFile.seekp(0L,ios::end); // go to end of the output file inFile.seekg(-10L,ios::end); // go to 10 characters before the input file's end outFile.seekp(-10L,ios::end); // go to 10 characters before the output file's end As opposed to seek() methods that move the file position marker, the tell() methods return the file position marker’s offset value. For example, if 10 characters have been read from an input file named inFile, the method call returns the long integer 10: inFile.tellg(); This means the next character to be read is offset 10 byte positions from the start of the file and is the 11th character in the file. Program 8.7 shows using seekg() and tellg() to read a file in reverse order, from last character to first. As each character is read, it’s also displayed. Assume the test.dat file contains the following characters: The grade was 92.5 The output of Program 8.7 is the following: 5 : . : 2 : 9 : : s : a : w : : e : d : a : r : g : : e : h : T : 466 I/O Streams and Data Files
  • 487. Program 8.7 #include <iostream> #include <fstream> #include <string> #include <cstdlib> using namespace std; int main() { string filename = "test.dat"; char ch; long offset, last; ifstream inFile(filename.c_str()); if (inFile.fail()) // check for successful open { cout << "nThe file was not successfully opened" << "n Please check that the file currently exists" << endl; exit(1); } inFile.seekg(0L,ios::end); // move to the end of the file last = inFile.tellg(); // save the offset of the last character for(offset = 1L; offset <= last; offset++) { inFile.seekg(-offset, ios::end); ch = inFile.get(); cout << ch << " : "; } inFile.close(); cout << endl; return 0; } 467 Chapter 8 Random File Access
  • 488. Program 8.7 initially goes to the last character in the file. The offset of this character, the EOF character, is saved in the variable last. Because tellg() returns a long integer, last has been declared as a long integer. Starting from the end of the file, seekg() is used to position the next character to be read, referenced from the end of the file. As each character is read, the character is displayed, and the offset is adjusted to access the next character. The first offset used is -1, which represents the character immediately preceding the EOF marker. EXERCISES 8.3 1. (Practice) a. Create a file named test.dat containing the data in the test.dat file used in Program 8.7. (You can use a text editor or copy the test.dat file from this book’s Web site.) b. Enter and execute Program 8.7 on your computer. 2. (Modify) Rewrite Program 8.7 so that the origin for the seekg() method used in the for loop is the start of the file rather than the end. 3. (Modify) Modify Program 8.7 to display an error message if seekg() attempts to refer- ence a position beyond the end of the file. 4. (Practice) Write a program that reads and displays every second character in a file named test.dat. 5. (Practice) Using the seek() and tell() methods, write a function named fileChars() that returns the total number of characters in a file. 6. (Practice) a. Write a function named readBytes() that reads and displays n characters starting from any position in a file. The function should accept three arguments: a file object name, the offset of the first character to be read, and the number of characters to be read. (Note: The prototype for readBytes() should be void readBytes(fstream&, long, int).) b. Modify the readBytes() function written in Exercise 6a to store the characters read into a string or an array. The function should accept the storage address as a fourth argument. 8.4 File Streams as Function Arguments A file stream object can be used as a function argument. The only requirement is that the function’s formal parameter be a reference (see Section 6.3) to the appropriate stream, either ifstream& or ofstream&. For example, in Program 8.8, an ofstream object named outFile is opened in main(), and this stream object is passed to the inOut() function. The function prototype and header for inOut() declare the formal parameter as a reference to an ostream object type. The inOut() function is then used to write five lines of user-entered text to the file. 468 I/O Streams and Data Files
  • 489. Program 8.8 #include <iostream> #include <fstream> #include <cstdlib> #include <string> using namespace std; int main() { string fname = "list.dat"; // here is the file you are working with void inOut(ofstream&); // function prototype ofstream outFile; outFile.open(fname.c_str()); if (outFile.fail()) // check for a successful open { cout << "nThe output file " << fname << " was not successfully opened" << endl; exit(1); } inOut(outFile); // call the function return 0; } void inOut(ofstream& fileOut) { const int NUMLINES = 5; // number of lines of text string line; int count; cout << "Please enter five lines of text:" << endl; for (count = 0; count < NUMLINES; count++) { getline(cin,line); fileOut << line << endl; } cout << "nThe file has been successfully written." << endl; return; } 469 Chapter 8 File Streams as Function Arguments
  • 490. In main(), the file is an ofstream object named outFile. This object is passed to the inOut() function and accepted as the formal parameter fileOut, which is declared to be a reference to an ofstream object type. The inOut() function then uses its reference parameter outFile as an output file stream name in the same manner that main() would use the fileOut stream object. Program 8.8 uses the getline() method introduced in Section 8.2 (see Table 8.3). Program 8.9 expands on Program 8.8 by adding a getOpen() function to perform the open. Like inOut(), getOpen() accepts a reference argument to an ofstream object. After the getOpen() function finishes executing, this reference is passed to inOut(), as in Program 8.8. Although you might be tempted to write getOpen() to return a reference to an ofstream, it won’t work because it results in an attempt to assign a returned reference to an existing one. Program 8.9 #include <iostream> #include <fstream> #include <cstdlib> #include <string> using namespace std; int getOpen(ofstream&); // function prototype - pass a reference to an fstream void inOut(ofstream&); // function prototype - pass a reference to an fstream int main() { ofstream outFile; // filename is an fstream object getOpen(outFile); // open the file inOut(outFile); // write to it return 0; } 墌 470 I/O Streams and Data Files
  • 491. Program 8.9 allows the user to enter a filename from the standard input device and then opens the ofstream connection to the external file. If an existing data file’s name is entered, the file is destroyed when it’s opened for output. A useful trick for preventing this mishap is to open the entered file by using an input file stream. If the file exists, the fail() method indicates a successful open (that is, the open doesn’t fail), which indicates the file is available for input. This technique can be used to alert the user that a file with the entered name exists in the system and to request confirmation that data in the file can be destroyed and the file opened for output. Before the file is reopened for output, the input file stream should be closed. Implementing this trick is left for you to try in Exercise 4. int getOpen(ofstream& fileOut) { string name; cout << "nEnter a file name: "; getline(cin,name); fileOut.open(name.c_str()); // open the file if (fileOut.fail()) // check for successful open { cout << "Cannot open the file" << endl; exit(1); } else return 1; } void inOut(ofstream& fileOut) { const int NUMLINES = 5; // number of lines int count; string line; cout << "Please enter five lines of text:" << endl; for (count = 0; count < NUMLINES; ++count) { getline(cin,line); fileOut << line << endl; } cout << "nThe file has been successfully written."; return; } 471 Chapter 8 File Streams as Function Arguments
  • 492. EXERCISES 8.4 1. (Practice) A function named pFile() is to receive a filename as a reference to an ifstream object. What declarations are required to pass a filename to pFile()? 2. (Practice) Write a function named fcheck() that checks whether a file exists. The function should accept an ifstream object as a formal reference parameter. If the file exists, the function should return a value of 1; otherwise, the function should return a value of 0. 3. (Practice) A data file consisting of a group of lines has been created. Write a function named printLine() that reads and displays any line of the file. For example, the func- tion called printLine(fstream& fName,5); should display the fifth line of the passed object stream. 4. (Modify) Rewrite the getOpen() function used in Program 8.9 to incorporate the file- checking procedures described in this section. Specifically, if the entered filename exists, an appropriate message should be displayed. The user should be presented with the option of entering a new filename or allowing the program to overwrite the existing file. Use the function written for Exercise 2 in your program. 8.5 A Case Study: Pollen Count File Update After a data file has been created, application programs are typically written to read and update the file with current data. In this case study, a file is used as a database for storing the 10 most recent pollen counts, which are used in the summer as allergy “irritability” measures. As a new reading is obtained, it’s added to the file, and the oldest stored reading is deleted. Step 1 Analyze the Problem Pollen count readings, which are taken from August through September in the northeastern United States, measure the number of ragweed pollen grains in the air. Pollen counts in the range of 10 to 200 grains per cubic meter of air are normal during this time of year. Typically, pollen counts above 10 begin affecting a small percentage of hay fever sufferers, counts in the range of 30 to 40 noticeably bother approximately 30% of hay fever sufferers, and counts between 40 and 50 adversely affect more than 60% of all hay fever sufferers. A program is to be written that updates a file containing the 10 most recent pollen counts. As a new count is obtained, it’s added to the end of the file, and the oldest count is deleted from the file.1 Additionally, the average of the new file’s data is calculated and displayed. The existing file, named pollen.in, contains the data shown in Figure 8.3. The input data for this problem consist of a file of 10 integer numbers and a user-input value of the most recent integer value pollen count. There are two required outputs: • A file of the 10 most recent integer values • The average of the data in the updated file 1 This type of data storage is formally referred to as a first-in/first-out (FIFO) list, also called a “queue.” If the list is maintained in last-in/first-out order (LIFO), it’s called a “stack.” 472 I/O Streams and Data Files
  • 493. Step 2 Develop a Solution The algorithm for solving this problem is straightforward and is described by the following pseudocode: main() function Display a message indicating what the program does. Call the Input stream function. Call the Output stream function. Call the Update function. Display the new 10-week average. Input stream function Request the name of the input data file. Open an input file stream and validate a successful connection. Output stream function Request the name of the output data file. Open an output file stream and validate a successful connection. Update function Request a new pollen count reading. Read the oldest pollen count from the input data file. For the remaining input file pollen counts: Read an input value. Add the value to a total. Write the input value to the output file stream. Endfor Write the new pollen count to the output file stream. Add the new pollen count to the total. Calculate the average as total / (number of pollen counts). Return the new 10-week average. Close all files. In reviewing this algorithm, notice that the oldest pollen count is read but never used in any computation. The remaining pollen counts are read, “captured” in a total, and written to the output data file. The last pollen count is then added to the total and also written to the output data file. Finally, the average of the most recent pollen counts is computed and displayed, and all file streams are closed. 30 60 40 80 90 120 150 130 160 170 Oldest pollen count (to be deleted) Last pollen count Figure 8.3 Data currently in the pollen.in file 473 Chapter 8 A Case Study: Pollen Count File Update
  • 494. Step 3 Code the Solution Program 8.10 presents a C++ representation of the selected design; the algorithm has been coded as the pollenUpdate() function. Program 8.10 #include <iostream> #include <fstream> #include <cstdlib> #include <string> using namespace std; void openInput(ifstream&); // pass a reference to an ifstream void openOutput(ofstream&); // pass a reference to an ofstream double pollenUpdate(ifstream&, ofstream&); // pass two references int main() { ifstream inFile; // inFile is an istream object ofstream outFile; // outFile is an ofstream object double average; // display a user message cout << "nnThis program reads the old pollen count file, " << "creates a current pollen" << "n count file, and calculates and displays " << "the latest 10-week average."; openInput(inFile); openOutput(outFile); average = pollenUpdate(inFile, outFile); cout << "nThe new 10-week average is: " << average << endl; return 0; } 墌 474 I/O Streams and Data Files
  • 495. // this function gets an external filename and opens the file for input void openInput(ifstream& fname) { string filename; cout << "nnEnter the input pollen count filename: "; cin >> filename; fname.open(filename.c_str()); if (fname.fail()) // check for a successful open { cout << "nFailed to open the file named " << filename << "for input" << "n Please check that this file exists" << endl; exit(1); } return; } // this function gets an external filename and opens the file for output void openOutput(ofstream& fname) { string filename; cout << "Enter the output pollen count filename: "; cin >> filename; fname.open(filename.c_str()); if (fname.fail()) // check for a successful open { cout << "nFailed to open the file named " << filename << "for output" << endl; exit(1); } return; } 墌 475 Chapter 8 A Case Study: Pollen Count File Update
  • 496. // the following function reads the pollen file, // writes a new file, // and returns the new weekly average double pollenUpdate(ifstream& inFile, ofstream& outFile) { const int POLNUMS = 10; // maximum number of pollen counts int i, polreading; int oldreading, newcount; double sum = 0; double average; // get the latest pollen count cout << "Enter the latest pollen count reading: "; cin >> newcount; // read the oldest pollen count inFile >> oldreading; // read, sum, and write out the rest of the pollen counts for(i = 0; i < POLNUMS; i++) { inFile >> polreading; sum += polreading; outFile << polreading << endl; } // write out the latest reading outFile << newcount << endl; // compute and display the new average average = (sum + newcount) / double(POLNUMS); inFile.close(); outFile.close(); cout << "nThe output file has been written.n"; return average; } 476 I/O Streams and Data Files
  • 497. Step 4 Test and Correct the Program Testing Program 8.10 requires providing both valid and invalid input data for the program. Invalid data consists of a nonexistent input data filename and a data file containing fewer than 10 items. Valid data consists of a file containing 10 integers. A sample run of Program 8.10 follows with a valid input file: This program reads the old pollen count file, creates a current pollen count file, and calculates and displays the latest 10-week average. Enter the input pollen count filename: pollen.in Enter the output pollen count filename: pollen.out Enter the latest pollen count reading: 200 The output file has been written. The new 10-week average is: 120 The updated file Program 8.10 creates is shown in Figure 8.4. In reviewing this file’s contents, notice that the most current reading has been added to the end of the file, and other pollen readings from the original file shown in Figure 8.3 have been moved up one position in the new file. Also, notice that the output of the sample run calculates the new 10-week average correctly. EXERCISES 8.5 1. (Practice) Write a C++ program to create the pollen.in file shown in Figure 8.3. 2. (Practice) Using the file created in Exercise 1 or the pollen.in file provided on this book’s Web site, enter and run Program 8.10 on your computer. 60 40 80 90 120 150 130 160 170 200 Oldest pollen count Most recent reading Figure 8.4 The updated pollen.in file 477 Chapter 8 A Case Study: Pollen Count File Update
  • 498. 3. (Conversion) a. A file named polar.dat contains the polar coordinates needed in a graphics program. Currently, this file contains the following data: Distance (Inches) Angle (Degrees) 2.0 45.0 6.0 30.0 10.0 45.0 4.0 60.0 12.0 55.0 8.0 15.0 Write a C++ program to create this file on your computer. b. Using the polar.dat file created in Exercise 3a, write a C++ program that accepts distance and angle data from the user and adds the data to the end of the file. c. Using the polar.dat file created in Exercise 3a, write a C++ program that reads this file and creates a second file named xycord.dat. The entries in the new file should contain the rectangular coordinates corresponding to the polar coordinates in the polar.dat file. Polar coordinates are converted to rectangular coordinates by using these formulas: x = r (cos θ ) y = r (sin θ ) The r is the distance coordinate and θ is the radian equivalent of the angle coordi- nate in the polar.dat file. 4. (Data Processing) a. Write a C++ program to create a data file containing the following information: Student ID Number Student Name Course Code Course Credits Course Grade 2333021 BOKOW, R. NS201 3 A 2333021 BOKOW, R. MG342 3 A 2333021 BOKOW, R. FA302 1 A 2574063 FALLIN, D. MK106 3 C 2574063 FALLIN, D. MA208 3 B 2574063 FALLIN, D. CM201 3 C 2574063 FALLIN, D. CP101 2 B 2663628 KINGSLEY, M. QA140 3 A 2663628 KINGSLEY, M. CM245 3 B 2663628 KINGSLEY, M. EQ521 3 A 2663628 KINGSLEY, M. MK341 3 A 2663628 KINGSLEY, M. CP101 2 B 478 I/O Streams and Data Files
  • 499. b. Using the file created in Exercise 4a, write a C++ program that creates student grade reports. The grade report for each student should contain the student’s name and ID number, a list of courses taken, the credits and grade for each course, and a semester grade point average (GPA). For example, this is the grade report for the first student: Student Name: BOKOW, R. Student ID Number: 2333021 Course Code Course Credits Course Grade NS201 3 A MG342 3 A FA302 1 A Total Semester Course Credits Completed: 7 Semester GPA: 4.0 The semester GPA is computed in two steps. First, each course grade is assigned a numerical value (A = 4, B = 3, C = 2, D = 1, F = 0), and the sum of each course’s grade value times the credits for each course is computed. This sum is then divided by the total number of credits taken during the semester. 5. (File Update) a. Write a C++ program to create a data file containing the following information: Student ID Number Student Name Course Credits Course GPA 2333021 BOKOW, R. 48 4.0 2574063 FALLIN, D. 12 1.8 2663628 KINGSLEY, M. 36 3.5 b. Write a C++ program to update the file created in Exercise 5a with the data from the file created in Exercise 4a. 8.6 A Closer Look: The iostream Class Library2 As you have seen, the classes in the iostream class library access files by using entities called streams. For most systems, the data bytes transferred on a stream represent ASCII characters or binary numbers. The mechanism for reading a byte stream from a file or writing a byte stream to a file is hidden when using a high-level language, such as C++. Nevertheless, understanding this mechanism is useful so that you can place the services provided by the iostream class library in context. File Stream Transfer Mechanism Figure 8.5 illustrates the mechanism for transferring data between a program and a file. As shown, this transfer involves an intermediate file buffer contained in the computer’s memory. 2 This topic can be omitted on first reading without loss of subject continuity. 479 Chapter 8 A Closer Look: The iostream Class Library
  • 500. Each opened file is assigned its own file buffer, which is a storage area used by the data transferred between the program and the file. The program either writes a set of data bytes to the file buffer or reads a set of data bytes from the file buffer by using a stream object. The data transfer between the device storing the data file (usually a disk or CD/DVD) and the file buffer is handled by special OS programs. These programs, called device drivers, aren’t stand-alone programs; they’re an integral part of the OS. A device driver is a section of OS code that accesses a hardware device, such as a disk, and handles the data transfer between the device and the computer’s memory. Because the computer’s internal data transfer rate is generally much faster than any device connected to it, the device driver must correctly synchronize the data transfer speed between the computer and the device sending or receiving data. Typically, a disk device driver transfers data between the disk and file buffer only in fixed sizes, such as 1024 bytes at a time. Therefore, the file buffer is a convenient means of permitting a device driver to transfer data in blocks of one size, and the program can access them by using a different size (typically, as separate characters or as a fixed number of characters per line). Components of the iostream Class Library The iostream class library consists of two primary base classes: streambuf and ios. The streambuf class provides the file buffer, illustrated in Figure 8.5, and general routines for transferring binary data. The ios class contains a pointer to the file buffers provided by the streambuf class and general routines for transferring text data. From these two base classes, several other classes are derived and included in the iostream class library. Figure 8.6 is an inheritance diagram for the ios family of classes as it relates to the ifstream, ofstream, and fstream classes. Figure 8.7 is an inheritance diagram for the streambuf family of classes. In these diagrams, the arrows point from a derived class to a base class. Table 8.5 lists the correspondence between the classes shown in Figures 8.6 and 8.7, including the header files defining these classes. Disk, tape, or CD/DVD Computer memory Transfer handled by a device driver Transfer handled by iostream library Program Buffer File Figure 8.5 The data transfer mechanism 480 I/O Streams and Data Files
  • 501. Table 8.5 Correspondence Between Classes in Figures 8.6 and 8.7 ios Class streambuf Class Header File istream ostream iostream streambuf iostream or fstream ifstream ofstream fstream filebuf fstream Therefore, the ifstream, ofstream, and fstream classes you have used for file access use a buffer provided by the filebuf class and defined in the fstream header file. Similarly, the cin, cout, cerr, and clog iostream objects use a buffer provided by the streambuf class and defined in the iostream header file. frstream iostream fstream istream ostream ios ifstream ofstream Figure 8.6 The base class ios and its derived classes streambuf filebuf strstreambuf Figure 8.7 The base class streambuf and its derived classes 481 Chapter 8 A Closer Look: The iostream Class Library
  • 502. In-Memory Formatting In addition to the classes shown in Figure 8.7, a class named strstream is derived from the ios class. This class uses the strstreambuf class shown in Figure 8.7, requires the strstream header file, and provides capabilities for writing and reading strings to and from in-memory defined streams. As an output stream, these streams are typically used to “assemble” a string from smaller pieces until a complete line of characters is ready to be written to cout or to a file. Attaching a strstream object to a buffer for this purpose is similar to attaching an fstream object to an output file. For example, the statement strstream inmem(buf, 72, ios::out); attaches a strstream object to an existing buffer of 72 bytes in output mode. Program 8.11 shows how this statement is used in the context of a complete program. Program 8.11 #include <iostream> #include <strstream> #include <iomanip> using namespace std; int main() { const int MAXCHARS = 81; // one more than the maximum characters in a line int units = 10; double price = 36.85; char buf[MAXCHARS]; strstream inmem(buf, MAXCHARS, ios::out); // open an in-memory stream // write to the buffer through the stream inmem << "No. of units = " << setw(3) << units << " Price per unit = $" << setw(6) << setprecision(2) << fixed << price << '0'; cout << '|' << buf << '|'; cout << endl; return 0; } 482 I/O Streams and Data Files
  • 503. Program 8.11 produces the following output: |No. of units = 10 Price per unit = $ 36.85| This output illustrates that the character buffer has been filled in correctly by insertions to the inmem stream. (Note that the end-of-string NULL, '0', which is the last insertion to the stream, is required to close off the C-string correctly.) After the character array has been filled, it’s written to a file as a single string. In a similar manner, a strstream object can be opened in input mode. This stream would be used as a working storage area, or buffer, for storing a complete line of text from a file or standard input. After the buffer has been filled, the extraction operator would be used to “disassemble” the string into component parts and convert each data item into its designated data type. Doing this permits inputting data from a file on a line-by-line basis before assigning data items to their respective variables. 8.7 Common Programming Errors The common programming errors with files are as follows: 1. Forgetting to open a file before attempting to read from it or write to it. 2. Using a file’s external name in place of the internal file stream object name when accessing the file. The only stream method that uses the data file’s external name is the open() method. As always, all stream methods discussed in this chapter must be preceded by a stream object name followed by a period (the dot operator). 3. Opening a file for output without first checking that a file with the same name already exists. If it does and you didn’t check for a preexisting filename, the file is overwritten. 4. Not understanding that the end of a file is detected only after the EOF marker has been read or passed over. 5. Attempting to detect the end of a file by using character variables for the EOF marker. Any variable used to accept the EOF must be declared as an integer variable. For example, if ch is declared as a character variable, the following expression produces an infinite loop:3 while ( (ch = in.file.peek()) != EOF ) This problem occurs because a character variable can never take on an EOF code. EOF is an integer value (usually -1) with no character representation, which ensures that the EOF code can’t be confused with a legitimate character encountered as normal data in the file. To terminate the loop created by the preceding expression, the variable ch must be declared as an integer variable. 6. Using an integer argument with the seekg() and seekp() functions. This offset must be a long integer constant or variable. Any other value passed to these functions can have unpredictable results. 3 This infinite loop doesn’t occur on UNIX systems, where characters are stored as signed integers. 483 Chapter 8 Common Programming Errors
  • 504. 8.8 Chapter Summary 1. A data file is any collection of data stored together in an external storage medium under a common name. 2. A data file is connected to a file stream by using fstream’s open() method. This method connects a file’s external name with an internal object name. After the file is opened, all subsequent accesses to the file require the internal object name. 3. A file can be opened in input or output mode. An opened output file stream creates a new data file or erases the data in an existing opened file. An opened input file stream makes an existing file’s data available for input. An error condition results if the file doesn’t exist and can be detected by using the fail() method. 4. All file streams must be declared as objects of the ifstream or ofstream class. Therefore, a declaration similar to either of the following must be included with the declaration to open the file: ifstream inFile; ofstream outfile; The stream object names inFile and outfile can be replaced with any user-selected object name. 5. In addition to any files opened in a function, the standard stream objects cin, cout, and cerr are declared and opened automatically when a program runs. cin is an input file stream object used for data entry (usually from the keyboard), cout is an output file stream object used for data display (usually on screen), and cerr is an output file stream object used for displaying system error messages (usually on screen). 6. Data files can be accessed randomly by using the seekg(), seekp(), tellg(), and tellp() methods. The g versions of these methods are used to alter and query the file position marker for input file streams, and the p versions do the same for output file streams. 7. Table 8.6 lists class-supplied methods for file manipulation. The getline() method is defined in the string class, and all other methods are defined in the fstream class. Table 8.6 File Manipulation Methods Method Name Description get() Extract the next character from the input stream and return it as an int. get(chrVar) Extract the next character from the input stream and assign it to chrVar. getline(fileObject, strObj, termChar) Extract the next string of characters from the input file stream object and assign them to strObj until the specified terminating character is detected. If omitted, the default terminating character is a newline. 484 I/O Streams and Data Files
  • 505. Table 8.6 File Manipulation Methods (continued) Method Name Description getline(C-stringVar,int n,'n') Extract and return characters from the input stream until n-1 characters are read or a newline is encountered (terminates the input with a '0'). peek() Return the next character in the input stream without extracting it from the stream. put(chrExp) Put the character specified by chrExp on the output stream. putback(chrExp) Push the character specified by chrExp back onto the input stream. Does not alter the data in the file. ignore(int n) Skip over the next n characters; if n is omitted, the default is to skip over the next single character. eof() Returns a Boolean true value if a read has been attempted past the end of file; otherwise, it returns a Boolean false value. The value becomes true only when the first character after the last valid file character is read. good() Returns a Boolean true value while the file is available for program use. Returns a Boolean false value if a read has been attempted past the end of file. The value becomes false only when the first character after the last valid file character is read. bad() Returns a Boolean true value if a read has been attempted past the end of file; otherwise, it returns a false. The value becomes true only when the first character after the last valid file character is read. fail() Returns a Boolean true if the file hasn’t been opened successfully; otherwise, it returns a Boolean false value. 485 Chapter 8 Chapter Summary
  • 506. Programming Projects for Chapter 8 1. (Data Processing) a. Create a text file containing the following data (without the headings): Name Rate Hours Callaway, G. 6.00 40 Hanson, P. 5.00 48 Lasard, D. 6.50 35 Stillman, W. 8.00 50 b. Write a C++ program that uses the information in the file created in Exercise 1a to produce the following pay report for each employee: Name Pay Rate Hours Regular Pay Overtime Pay Gross Pay Compute regular pay as any hours worked up to and including 40 hours multiplied by the pay rate. Compute overtime pay as any hours worked above 40 hours times a pay rate of 1.5 multiplied by the regular rate. The gross pay is the sum of regular and overtime pay. At the end of the report, the program should display the totals of the regular, overtime, and gross pay columns. 2. (Data Processing) a. Store the following data in a file: 5 96 87 78 93 21 4 92 82 85 87 6 72 69 85 75 81 73 b. Write a C++ program to calculate and display the average of each group of numbers in the file created in Exercise 2a. The data is arranged in the file so that each group of numbers is preceded by the number of data items in the group. Therefore, the first number in the file, 5, indicates that the next five numbers should be grouped together. The number 4 indicates that the following four numbers are a group, and the 6 indicates that the last six numbers are a group. (Hint: Use a nested loop. The outer loop should terminate when the end of file has been encountered.) 3. (Data Processing) Write a C++ program that allows the user to enter the following information from the keyboard for each student in a class (up to 20 students): Name Exam 1 Grade Exam 2 Grade Homework Grade Final Exam Grade For each student, your program should first calculate a final grade, using this formula: Final Grade = 0.20 × Exam 1 + 0.20 × Exam 2 + 0.35 × Homework + 0.25 × Final Exam Then assign a letter grade on the basis of 90–100 = A, 80–89 = B, 70–79 = C, 60–69 = D, and less than 60 = F. All the information, including the final grade and the letter grade, should then be displayed and written to a file. 4. (Data Processing) Write a C++ program that permits users to enter the following information about your small company’s 10 employees, sorts the information in ascending ID number, and then writes the sorted information to a file: ID No. Sex(M/F) Hourly Wage Years with the Company 5. (Data Processing) Write a C++ program that reads the file created in Exercise 4, changes the hourly wage or years for each employee, and creates a new updated file. 486 I/O Streams and Data Files
  • 507. 6. (Data Processing) Write a C++ program that reads the file created in Exercise 4 one record at a time, asks for the number of hours each employee worked each month, and calculates and displays each employee’s total pay for the month. 7. (Data Processing) a. You have collected information about cities in your state. You decide to store each city’s name, population, and mayor in a file. Write a C++ program to accept the data for a number of cities from the keyboard and store the data in a file in the order in which they’re entered. b. Read the file created in Exercise 7a, sort the data alphabetically by city name, and display the data. 8. (Data Processing) A bank’s customer records are to be stored in a file and read into a set of arrays so that a customer’s record can be accessed randomly by account number. Create the file by entering five customer records, with each record consisting of an integer account number (starting with account number 1000), a first name (maximum of 10 characters), a last name (maximum of 15 characters), and a double-precision number for the account balance. After the file is created, write a C++ program that requests a user-input account number and displays the corresponding name and account balance from the file. 9. (Inventory) Create an ASCII file with the following data or use the shipped.txt file provided on this book’s Web site. The headings are not part of the file but indicate what the data represents. Shipped Date Tracking Number Part Number First Name Last Name Company 04/12/97 D50625 74444 James Lehoff Rotech 04/12/97 D60752 75255 Janet Lezar Rotech 04/12/97 D40295 74477 Bill McHenry Rotech 04/12/97 D23745 74470 Diane Kaiser Rotech 04/12/97 D50892 75155 Helen Richardson NapTime The format of each line in the file is identical, with fixed-length fields defined as follows: Field Position Field Name Starting Col. No. Ending Col. No. Field Length 1 Shipped Date 1 8 8 2 Tracking Number 12 17 6 3 Part Number 22 26 5 4 First Name 31 35 5 5 Last Name 39 48 10 6 Company 51 64 14 Using this data file, write a C++ program that reads the file and produces a report listing the shipped date, part number, first name, last name, and company name. 487 Chapter 8 Programming Projects
  • 508. Engineering and Scientific Disciplines Environmental Science and Technology Two of the newest areas of science and engineering are the related fields of environ- mental science and technology. Environmental science began as an extension of ecol- ogy, a biological field that gained prominence in the 1960s. Ecology studies the interrelationships between specific biological organisms and their environment. In the 1970s, the study of the larger interplay among physical, chemical, and bio- logical components of the environment, both locally and globally, began and became the field known as environmental science. This field now includes study of the follow- ing areas, among others: 앫 Climate change 앫 Ozone depletion 앫 Weather pattern changes 앫 Water quality 앫 Air pollution 앫 Noise pollution 앫 Conservation of natural resources 앫 Disposal of toxic substances The impact of human activities on these environmental areas is a chief concern of environmental science. Typically, many different scientific and engineering experts are needed to work as a team in analyzing and solving environmental issues. Applying engineering and scientific expertise to solving environmental problems falls within the purview of environmental technology. This field is concerned with pre- serving the natural environment and its resources by providing solutions in areas such as water purification, human waste management, renewable energy, and recycling, among others. 488 I/O Streams and Data Files
  • 509. Chapter 9 Completing the Basics 9.1 Exception Handling 9.2 Exceptions and File Checking 9.3 The string Class 9.4 Character Manipulation Functions 9.5 Input Data Validation 9.6 A Closer Look: Namespaces and Creating a Personal Library 9.7 Common Programming Errors 9.8 Chapter Summary The current ANSI/ISO C++ standard introduces two new features that weren’t part of the original C++ specification: exception handling and the string class. This chapter covers both these new features. Exception handling is a means of error detection and processing, which has gained increasing acceptance in programming technology. It permits detecting an error at the point in the code where the error has occurred and provides a means of processing the error and returning control to the line that generated the error. Although error detection and code correction are possible by using if statements and functions, exception handling gives you another useful programming tool targeted at error detection and processing. With the new ANSI/ISO C++ standard, the string class is now part of the standard C++ library. This class provides an expanded set of class functions, including easy insertion and removal of characters from a string, automatic string expansion when a string’s original capacity is exceeded, string contraction when characters are removed from a string, and range checking to detect invalid character positions. In addition to discussing these two new C++ features, this chapter shows how exception handling, when applied to strings, is a useful means of validating user input.
  • 510. 9.1 Exception Handling The traditional C++ approach to error handling uses a function to return a specific value to indicate specific operations. Typically, a return value of 0 or 1 is used to indicate successful completion of the function’s task, whereas a negative value indicates an error condition. For example, with a function used to divide two numbers, a return value of -1 could indicate that the denominator is zero, and the division can’t be performed. When multiple error conditions can occur, different return values can be used to indicate specific errors. Although this approach is still available and often used, a number of problems can occur. First, the programmer must check the return value to detect whether an error did occur. Next, the error-handling code that checks the return value frequently becomes intermixed with normal processing code, so sometimes it’s difficult to determine which part of the code is handling errors. Finally, returning an error condition from a function means the condition must be the same data type as a valid returned value; hence, the error code must be a specified value that can be identified as an error alert. This means the error code is embedded as one of the possible nonerror values the function might require and is available only at the point where the function returns a value. In addition, a function returning a Boolean value has no additional values for reporting an error condition. None of these problems are insurmountable, and many times this approach is simple and effective. However, the latest C++ compilers have added a technique designed for error detection and handling referred to as exception handling. With this technique, when an error occurs while a function is executing, an exception is created. An exception is a value, a variable, or an object containing information about the error at the point the error occurs. This exception is immediately passed, at the point it was generated, to code called the exception handler, which is designed to deal with the exception. The process of generating and passing the exception is referred to as throwing an exception. The exception is thrown from within the function while it’s still executing, which permits handling the error and then returning control back to the function so that it can complete its assigned task. In general, two fundamental types of errors can cause C++ exceptions: those resulting from a program’s inability to obtain a required resource and those resulting from flawed data. Examples of the first error type are attempts to obtain a system resource, such as locating and finding a file for input. These errors are the result of external resources over which the programmer has no control. The second type of error can occur when a program prompts the user to enter an integer, and the user enters a string, such as e234, that can’t be converted to a numerical value. Another example is the attempt to divide two numbers when the denominator has a 0 value, a condition referred to as a “division by zero error.” These errors can always be checked and handled in a manner that doesn’t result in a program crash. Before seeing how to use exception handling, review Table 9.1 to familiarize yourself with the terminology used with processing exceptions. Table 9.1 Exception-Handling Terminology Terminology Description Exception A value, a variable, or an object that identifies a specific error that has occurred while a program is executing Throw an exception Send the exception to a section of code that processes the detected error 490 Completing the Basics
  • 511. Table 9.1 Exception-Handling Terminology (continued) Terminology Description Catch or handle an exception Receive a thrown exception and process it Catch clause The section of code that processes the error Exception handler The code that throws and catches an exception The general syntax of the code required to throw and catch an exception is the following: try { // one or more statements, // at least one of which should // be capable of throwing an exception } catch(exceptionDataType parameterName) { // one or more statements } This example uses two new keywords: try and catch. The try keyword identifies the start of an exception-handling block of code. At least one of the statements inside the braces defining this block of code should be capable of throwing an exception. As an example, examine the try block in the following section of code: try { cout << "Enter the numerator (whole numbers only): "; cin >> numerator; cout << "Enter the denominator (whole numbers only):"; cin >> denominator; result = numerator/denominator; } The try block contains five statements, three of which might result in an error you want to catch. In particular, a professionally written program would make sure valid integers are entered in response to both prompts and the second entered value is not a zero. For this example, you just check that the second value entered isn’t zero. From the standpoint of the try block, only the value of the second number matters. The try block is altered to say “Try all the statements within me to see whether an exception, which in this case is a zero second value, occurs.” To check that the second value isn’t zero, you add a throw statement in the try block, as follows: try { cout << "Enter the numerator: (whole number only): "; cin >> numerator; cout << "Enter the denominator: (whole number only): "; cin >> denominator; if (denominator == 0) throw denominator; else result = numerator/denominator; } 491 Chapter 9 Exception Handling
  • 512. In this try block, the thrown item is an integer value. A string literal, a variable, or an object could have been used, but only one of these items can be thrown by any single throw statement. The first four statements in the try block don’t have to be included in the code; however, doing so keeps all the relevant statements together. Keeping related statements together makes it easier to add throw statements in the same try block to ensure that both input values are integer values. A try block must be followed by one or more catch blocks, which serve as exception handlers for any exceptions thrown by statements in the try block. Here’s a catch block that handles the thrown exception, which is an integer: catch(int e) { cout << "A denominator value of " << e << " is invalid." << endl; exit (1); } The exception handling this catch block provides is an output statement that identifies the caught exception and then terminates program execution. Notice the parentheses following the catch keyword. Inside the parentheses are the data type of the exception that’s thrown and a parameter name used to receive the exception. This parameter, which is a programmer-selected identifier but conventionally uses the letter e for exception, is used to hold the exception value generated when an exception is thrown. Multiple catch blocks can be used as long as each block catches a unique data type. The only requirement is providing at least one catch block for each try block. The more exceptions that can be caught with the same try block, the better. Program 9.1 provides a complete program that includes a try block and a catch block to detect a division by zero error. Following are two sample runs of Program 9.1. Note that the second output indicates that an attempt to divide by a zero denominator has been detected successfully before the operation is performed. Enter the numerator (whole number only): 12 Enter the denominator(whole number only): 3 12/3 = 4 and Enter the numerator (whole number only): 12 Enter the denominator(whole number only): 0 A denominator value of 0 is invalid. 492 Completing the Basics
  • 513. Instead of terminating program execution when a zero denominator is detected, a more robust program can give the user the opportunity to reenter a non-zero value. To do this, the try block is included in a while statement, and then the catch block returns program control to the while statement after informing the user that a zero value has been entered. Program 9.2 accomplishes this task. Program 9.1 #include <iostream> using namespace std; int main() { int numerator, denominator; try { cout << "Enter the numerator (whole number only): "; cin >> numerator; cout << "Enter the denominator(whole number only): "; cin >> denominator; if (denominator == 0) throw denominator; // an integer value is thrown else cout << numerator <<'/' << denominator << " = " << double(numerator)/ double(denominator) << endl; } catch(int e) { cout << "A denominator value of " << e << " is invalid." << endl; exit (1); } return 0; } 493 Chapter 9 Exception Handling
  • 514. In reviewing this code, notice that it’s the continue statement in the catch block that returns control to the top of the while statement. (See Section 5.3 for a review of the continue statement.) Following is a sample run of Program 9.2: Enter a numerator (whole number only): 12 Enter a denominator (whole number only): 0 A denominator value of 0 is invalid. Please reenter the denominator (whole number only): 5 12/5 = 2.4 Program 9.2 #include <iostream> using namespace std; int main() { int numerator, denominator; bool needDenominator = true; cout << "Enter a numerator (whole number only): "; cin >> numerator; cout << "Enter a denominator (whole number only): "; while(needDenominator) { cin >> denominator; try { if (denominator == 0) throw denominator; // an integer value is thrown } catch(int e) { cout << "A denominator value of " << e << " is invalid." << endl; cout << "Please reenter the denominator (whole number only): "; continue; // this sends control back to the while statement } cout << numerator <<'/' << denominator << " = " << double(numerator)/ double(denominator) << endl; needDenominator = false; } return 0; } 494 Completing the Basics
  • 515. One caution should be mentioned when throwing string literals as opposed to numeric values. When a string literal is thrown, it’s a C-string, not a string class object, that is thrown. This means the catch statement must declare the received argument as a C-string (which is a character array) rather than a string. As an example, take a look at using the following statement instead of throwing the value of the denominator variable in Programs 9.1 and 9.2: throw "***Invalid input - A denominator value of zero is not permitted***"; Here’s a correct catch statement for the preceding throw statement: catch(char e[]) An attempt to declare the exception as a string class variable results in a compiler error. EXERCISES 9.1 1. (Practice) Define the following terms: a. exception b. try block c. catch block d. exception handler e. throw an exception f. catch an exception 2. (Practice) Enter and execute Program 9.1. 3. (Practice) Replace the following statement in Program 9.1 cout << numerator <<'/' << denominator << " = " << double (numerator)/ double (denominator) << endl; with the statement cout << numerator <<'/' << denominator << " = " << numerator/denominator << endl; and execute the modified program. Enter the values 12 and 5, and explain why the result is incorrect from the user’s viewpoint. 4. (Modify) Modify Program 9.1 so that it throws and catches the message ***Invalid input -A denominator value of zero is not permitted***. (Hint: Review the caution at the end of this section.) 5. (Practice) Enter and execute Program 9.2. 6. (Modify) Modify Program 9.2 so that it continues to divide two numbers until the user enters the character q (as a numerator or denominator) to terminate program execution. 495 Chapter 9 Exception Handling
  • 516. 7. (Validation) Include the exception-handling code provided in this section in Program 9.1 to ensure that the user enters a valid integer value for both the numerator and denominator. 9.2 Exceptions and File Checking Error detection and processing with exception handling is used extensively in C++ programs that use one or more files. For example, if a user deletes or renames a file by using an OS command, this action causes a C++ program to fail when an open() method call attempts to open the file with its original name. Exception handling is typically used when opening a data file to ensure that the file opens successfully before attempting any processing of data in the file. Recall from Section 9.1 that the code for general exception handling looks like this: try { // one or more statements, // at least one of which should // throw an exception } catch(exceptionDataType parameterName) { // one or more statements } In this code, the try block statements are executed. If no error occurs, the catch block statements are omitted, and processing continues with the statement following the catch block. However, if any statement in the try block throws an exception, the catch block with the exception data type matching the exception is executed. If no catch block is defined for a try block, a compiler error occurs. If no catch block exists that catches a thrown data type, a program crash occurs if the exception is thrown. Most times, the catch block displays an error message and terminates processing with a call to the exit() function. Program 9.3 shows the statements required to open a file in read mode and includes exception handling. Program 9.3 #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() #include <string> using namespace std; 墌 496 Completing the Basics
  • 517. This is the exception message Program 9.3 displays when the prices.dat file isn’t found: The file prices.dat was not successfully opened. Please check that the file currently exists. int main() { string filename = "prices.dat"; // put the filename up front string descrip; double price; ifstream inFile; try // this block tries to open the file, read it, // and display the file's data { inFile.open(filename.c_str()); if (inFile.fail()) throw filename; // this is the exception being checked // read and display the file's contents inFile >> descrip >> price; while (inFile.good()) // check next character { cout << descrip << ' ' << price << endl; inFile >> descrip >> price; } inFile.close(); return 0; } catch (string e) { cout << "nThe file "<< e << " was not successfully opened." << "n Please check that the file currently exists." << endl; exit(1); } } 497 Chapter 9 Exceptions and File Checking
  • 518. Although the exception-handling code in Program 9.3 can be used to check for a successful file open for input and output, a more rigorous check is usually required for an output file because a file opened for output is almost guaranteed to be found. If it exists, the file will be found; if it doesn’t exist, the operating system creates it (unless append mode is specified and the file exists, or the operating system can’t find the indicated folder). Knowing that the file has been found and opened, however, isn’t enough for output purposes when an existing output file must not be overwritten. In these cases, the file can be opened for input, and, if the file is found, a further check can be made to ensure that the user explicitly approves overwriting it. The shaded code in Program 9.4 shows how to make this check. Point of Information Checking That a File Was Opened Successfully Using exception handling, the most common method for checking that the operating system located the designated file is the one coded in Program 9.3. The key coding points are repeated here for convenience: try // this block tries to open the file, read it, // and display the file's data { // open the file, throwing an exception if the open fails // perform all required file processing // close the file } catch (string e) { cout << "nThe file "<< e << " was not successfully opened." << "n Please check that the file currently exists." << endl; exit(1); } Program 9.4 #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() #include <string> #include <iomanip> // needed for formatting using namespace std; int main() { char response; string filename = "prices.dat"; // put the filename up front ifstream inFile; ofstream outfile; 墌 498 Completing the Basics
  • 519. try // open a basic input stream simply to check whether the file exists { inFile.open(filename.c_str()); if (inFile.fail()) throw 1; // this means the file doesn't exist // only get here if the file is found; // otherwise, the catch block takes control cout << "A file by the name " << filename << " currently exists.n" << "Do you want to overwrite it with the new data (y or n): "; cin >> response; if (tolower(response) == 'n') { inFile.close(); cout << "The existing file has not been overwritten." << endl; exit(1); } } catch(int e) {}; // a do-nothing block that permits // processing to continue try { // open the file in write mode and continue with file writes outfile.open(filename.c_str()); if (outfile.fail()) throw filename; // set the output file stream formats outfile << setiosflags(ios::fixed) << setiosflags(ios::showpoint) << setprecision(2); // write the data to the file outfile << "Mats " << 39.95 << endl << "Bulbs " << 3.22 << endl << "Fuses " << 1.08 << endl; outfile.close(); cout << "The file " << filename << " has been successfully written." << endl; return 0; } catch(string e) { cout << "The file " << filename << " was not opened for output and has not been written." << endl; } } 499 Chapter 9 Exceptions and File Checking
  • 520. In Program 9.4, the try blocks are separate. Because a catch block is affiliated with the closest previous try block, there’s no ambiguity about unmatched try and catch blocks. Opening Multiple Files To understand how to apply exception handling to opening two files at the same time, assume you want to read data from a character-based file named info.txt, one character at a time, and write this data to a file named info.bak. Essentially, this application is a file-copying program that reads data from one file in a character-by-character manner and writes the data to a second file. Figure 9.1 shows the characters stored in the input file. Figure 9.2 illustrates the structure of the streams needed to produce the file copy. In this figure, an input stream object referenced by the variable inFile reads data from the info.txt file, and an output stream object referenced by the variable outfile writes data to the info.bak file. Now examine Program 9.5, which creates the info.bak file as a duplicate of the info.txt file, using the procedure shown in Figure 9.2. Now is the time for all good people to come to the aid of their party. Please call (555) 888-6666 for further information. Figure 9.1 The data stored in the info.txt file Computer Program Read Write Disk OS interface info.txt info.bak OS interface Figure 9.2 The file copy stream structure Program 9.5 #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() #include <string> using namespace std; 墌 500 Completing the Basics
  • 521. int main() { string fileOne = "info.txt"; // put the filename up front string fileTwo = "info.bak"; char ch; ifstream inFile; ofstream outfile; try //this block tries to open the input file { // open a basic input stream inFile.open(fileOne.c_str()); if (inFile.fail()) throw fileOne; } // end of outer try block catch (string in) // catch for outer try block { cout << "The input file " << in << " was not successfully opened." << endl << " No backup was made." << endl; exit(1); } try // this block tries to open the output file and { // perform all file processing outfile.open(fileTwo.c_str()); if (outfile.fail())throw fileTwo; while ((ch = inFile.get())!= EOF) outfile.put(ch); inFile.close(); outfile.close(); } catch (string out) // catch for inner try block { cout << "The backup file " << out << " was not successfully opened." << endl; exit(1); } cout << "A successful backup of " << fileOne << " named " << fileTwo << " was successfully made." << endl; return 0; } 501 Chapter 9 Exceptions and File Checking
  • 522. For simplicity, Program 9.5 attempts to open the input and output files in separate and unnested try blocks. More generally, the second file is opened in a nested inner try block, so the attempt to open this second file wouldn’t be made if opening the first file threw an exception. (The Point of Information box explains how to nest try blocks.) In reviewing Program 9.5, pay particular attention to this statement: while((ch = inFile.get())!= EOF) This statement reads a value from the input stream continuously until the EOF value is detected. As long as the returned value doesn’t equal the EOF value, the value is written to the output object stream. The parentheses surrounding the expression (ch = inFile. get()) are necessary to make sure a value is read and assigned to the variable ch before the retrieved value is compared to the EOF value. Without parentheses, the complete expression would be ch = inFile.get()!= EOF. Given the precedence of operations, the relational expression inFile.get()!= EOF would be executed first. Because it’s a relational expression, its result is a Boolean true or false value based on the data the get() method retrieves. Attempting to assign this Boolean result to the character variable ch is an invalid conversion across an assignment operator. Point of Information Nesting try Blocks When more than one file stream is involved, opening each file stream in its own try block permits isolating and identifying exactly which file caused an exception, if one occurs. The try blocks can be nested. For example, Program 9.5 has been rewritten with nested try blocks. Notice that the catch block for the inner try block must be nested in the same block scope as the try block: #include <iostream> #include <fstream> #include <cstdlib> // needed for exit() #include <string> using namespace std; int main() { string fileOne = "info.txt"; // put the filename up front string fileTwo = "info.bak"; char ch; ifstream inFile; ofstream outfile; try //this block tries to open the input file { // open a basic input stream inFile.open(fileOne.c_str()); if (inFile.fail()) throw fileOne; try // this block tries to open the output file and continued... 502 Completing the Basics
  • 523. EXERCISES 9.2 1. (For Review) List two conditions that cause a fail condition when a file is opened for input. 2. (For Review) List two conditions that cause a fail condition when a file is opened for output. 3. (For Review) If a file that exists is opened for output in write mode, what happens to the data currently in the file? Point of Information Nesting try Blocks (continued) { // perform all file processing // open a basic output stream outfile.open(fileTwo.c_str()); if (outfile.fail())throw fileTwo; while ((ch = inFile.get()) != EOF) outfile.put(ch); inFile.close(); outfile.close(); } // end of inner try block catch (string out) // catch for inner try block { cout << "The backup file " << out << " was not successfully opened." << endl; exit(1); } } // end of outer try block catch (string in) // catch for outer try block { cout << "The input file " << in << " was not successfully opened." << endl << " No backup was made." << endl; exit(1); } cout << "A successful backup of " << fileOne << " named " << fileTwo << "was successfully made." << endl; return 0; } The important point to notice is nesting the try blocks. If the two try blocks aren’t nested and the input stream declaration, ifstream inFile;, is placed in the first block, it can’t be used in the second try block without producing a compiler error. The reason is that all variables declared in a block of code (defined by an open- ing and closing brace pair) are local to the block in which they’re declared. 503 Chapter 9 Exceptions and File Checking
  • 524. 4. (Modify) Modify Program 9.3 to use an identifier of your choice, in place of the letter e, for the catch block’s exception parameter name. 5. (Practice) Enter and execute Program 9.4. 6. (Debug) Determine why the two try blocks in Program 9.4, which are not nested, cause no problems in compilation or execution. (Hint: Place the declaration for the filename in the first try block and compile the program.) 7. (Debug) a. If the nested try blocks in the Point of Information on nested try blocks are separated into unnested blocks, the program won’t compile. Determine why this is so. b. What additional changes have to be made to the program in Exercise 7a that would allow it to be written with unnested blocks? (Hint: See Exercise 6.) 9.3 The string Class The programs in this book have used the istream class’s cout object extensively, but you haven’t investigated this class in detail or learned how the cout object is created. However, an advantage of object-oriented program design is that you can use thoroughly tested classes without knowing how the class is constructed. In this section, you use another class provided by C++’s standard library: the string class. However, you’re going to create objects from the class before using them instead of using an existing object, such as cout. A class is a user-created data type. Like built-in data types, a class defines a valid set of data values and a set of operations that can be used on them. The difference between a user-created class and a built-in data type is how the class is constructed. A built-in data type is provided as an integral part of the compiler, and a class is constructed by a programmer using C++ code. Other than that and the terminology, the two data types are used in much the same manner. The key difference in terminology is that storage areas for built-in data types are referred to as variables, whereas storage areas declared for a class are referred to as objects. The values the string class permits are referred to as string literals. A string literal is any sequence of characters enclosed in quotation marks. A string literal is also referred to as a string value, a string constant, and, more conventionally, a string. Examples of strings are "This is a string", "Hello World!", and "xyz 123 *!#@&". The quotation marks indicate the beginning and ending points of the string and are never stored with the string. Figure 9.3 shows the programming representation of the string Hello when it’s created as an object of the string class. By convention, the first character in a string is always designated as position 0. This position value is also referred to as both the character’s index value and its offset value. H e l 3 l 4 2 1 0 Position: o Figure 9.3 The storage of a string as a sequence of characters 504 Completing the Basics
  • 525. string Class Functions The string class provides a number of functions for declaring, creating, and initializing a string. In earlier versions of C++, the process of creating a new object is referred to as instantiating an object, which in this case becomes instantiating a string object, or creating a string, for short. Table 9.2 lists the functions the string class provides for creating and initializing a string object. In class terminology, functions are formally referred to as methods, and the methods that perform the tasks of creating and initializing are called constructor methods, or constructors, for short. Table 9.2 string Class Constructors (Require the Header File string) Constructor Description Examples string objectName = value Creates and initializes a string object to a value that can be a string literal, a previously declared string object, or an expression containing string literals and string objects string str1 = "Good Morning"; string str2 = str1; string str3 = str1 + str2; string objectName(stringValue) Produces the same initialization as the preceding item string str1("Hot"); string str1(str1 + "Dog"); string objectName(str, n) Creates and initializes a string object with a substring of string object str, starting at index position n of str string str1(str2, 5) If str2 contains the string Good Morning, then str1 becomes the string Morning string objectName(str, n, p) Creates and initializes a string object with a substring of string object str, starting at index position n of str and containing p characters string str1(str2, 5,2) If str2 contains the string Good Morning, then str1 becomes the string Mo string objectName(n, char) Creates and initializes a string object with n copies of char string str1(5,'*') This makes str1 = "*****" 505 Chapter 9 The string Class
  • 526. Table 9.2 string Class Constructors (Require the Header File string) (continued) Constructor Description Examples string objectName Creates and initializes a string object to represent an empty character sequence (same as string objectName = "";, so the length of the string is 0) string message; Program 9.6 shows examples of each constructor the string class provides. Program 9.6 #include <iostream> #include <string> using namespace std; int main() { string str1; // an empty string string str2("Good Morning"); string str3 = "Hot Dog"; string str4(str3); string str5(str4, 4); string str6 = "linear"; string str7(str6, 3, 3); cout << "str1 is: " << str1 << endl; cout << "str2 is: " << str2 << endl; cout << "str3 is: " << str3 << endl; cout << "str4 is: " << str4 << endl; cout << "str5 is: " << str5 << endl; cout << "str6 is: " << str6 << endl; cout << "str7 is: " << str7 << endl; return 0; } 506 Completing the Basics
  • 527. Here is the output created by Program 9.6: str1 is: str2 is: Good Morning str3 is: Hot Dog str4 is: Hot Dog str5 is: Dog str6 is: linear str7 is: ear Although this output is straightforward, str1 is an empty string consisting of no characters; because the first character in a string is designated as position 0, not 1, the character position of the D in the string Hot Dog is position 4, which is shown in Figure 9.4. String Input and Output In addition to a string being initialized with the constructors listed in Table 9.2, strings can be input from the keyboard and displayed on screen. Table 9.3 lists the basic functions and objects for input and output of string values. Table 9.3 string Class Input and Output C++ Object or Function Description cout General-purpose screen output object cin General-purpose keyboard input object that stops reading string input when white space is encountered getline(cin, strObj) General-purpose keyboard input function that inputs all characters entered, stores them in the string strObj, and stops accepting characters when it receives a newline character (n) In addition to the standard cout and cin objects you have been using throughout the book, the string class provides the getline() function for string input. For example, the expression getline(cin, message) accepts and stores characters typed at the terminal continuously until the Enter key is pressed. Pressing the Enter key generates a newline character, 'n', which getline() interprets as the end-of-line entry. All the characters encountered by getline(), except the newline character, are stored in the string message, as illustrated in Figure 9.5. Program 9.7 shows using the getline() function and cout statement to input and output a string that’s entered at the user’s terminal. Although cout is used in Program 9.7 for string output, cin generally can’t be used in place of getline() for string input because cin reads a set of characters up to a blank space or a newline character. Therefore, attempting to enter the characters This is a string by using the statement cin >> message; results in only the H o t 2 1 0 5 6 4 D o g 3 Character position: Figure 9.4 The character positions of the string Hot Dog 507 Chapter 9 The string Class
  • 528. word This being assigned to message. Because a blank terminates a cin extraction operation, cin’s usefulness for entering string data is restricted; therefore, getline() is used. The following is a sample run of Program 9.7: Enter a string: This is a test input of a string of characters. The string just entered is: This is a test input of a string of characters. In its most general form, the getline() function has the syntax getline(cin, strObj, terminatingChar) where strObj is a string variable name and terminatingChar is an optional character constant, or variable, specifying the terminating character. For example, the expression getline(cin, message, '!') accepts all characters entered at the keyboard, including a newline character, until an exclamation point is entered. The exclamation point isn’t stored as part of the string. getline() characters n characters Figure 9.5 Inputting a string with getline() Program 9.7 #include <iostream> #include <string> using namespace std; int main() { string message; // declare a string object cout << "Enter a string:n"; getline(cin, message); cout << "The string just entered is:n" << message << endl; return 0; } 508 Completing the Basics
  • 529. If the optional third argument, terminatingChar, is omitted when getline() is called, the default terminating character is the newline ('n') character. Therefore, the statement getline(cin,message,'n'); can be used in place of the statement getline(cin, message);. Both these statements stop reading characters when the Enter key is pressed. In all the programs used from this point forward, input is terminated by pressing the Enter key, which generates a newline character. For this reason, the optional third argument passed to getline(), which is the terminating character, is omitted. Caution: The Phantom Newline Character Seemingly strange results can happen when the cin input stream object and getline() function are used together to accept data or when cin is used by itself to accept characters. To see how this result can occur, take a look at Program 9.8, which uses cin to accept an integer entered at the keyboard. The integer is then stored in the variable value, and a getline() function call follows. When Program 9.8 runs, the number entered in response to the prompt Enter a number: is stored in the variable value. At this point, everything seems to be working fine. Notice, however, that in entering a number, you enter the number and press the Enter key. On almost all computer systems, this entered data is stored in a temporary holding area called a buffer immediately after the characters are entered, as shown in Figure 9.6. Program 9.8 #include <iostream> #include <string> using namespace std; int main() { int value; string message; cout << "Enter a number: "; cin >> value; cout << "The number entered is:n" << value << endl; cout << "Enter text:n"; getline(cin, message); cout << "The text entered is:n" << message << endl; cout << int(message.length()); return 0; } 509 Chapter 9 The string Class
  • 530. The cin input stream in Program 9.8 first accepts the number entered but leaves the 'n' in the buffer. The next input statement, which is a call to getline(), picks up thecode for the Enter key as the next character and terminates any further input. Following is a sample run of Program 9.8: Enter a number: 26 The number entered is 26 Enter text: The text entered is In this output, no text is accepted in response to the prompt Enter text:. No text occurs because, after the program accepts the number 26, the code for the Enter key, which is a newline escape sequence, remains in the buffer and is picked up and interpreted by the getline() function as the end of its input. This result occurs whether an integer (as in Point of Information The string and char Data Types A string can consist of zero, one, or more characters. When the string has no charac- ters, it’s said to be an empty string with a length of zero. A string with a single charac- ter, such as "a", is a string of length one and is stored differently from a char data type, such as 'a'. However, for many practical purposes, a string of length one and a char respond in the same manner; for example, both cout >> "n" and cout >> 'n' produce a new line on the screen. It’s important to understand that they are different data types; for example, both these declarations string s1 = 'a'; // INVALID INITIALIZATION char key = "n"; // INVALID INITIALIZATION produce a compiler error because they attempt to initialize one data type with literal values of another type. 2 6 n Each character is sent to a buffer as it’s typed Buffer (temporary storage) Keyboard Figure 9.6 Typed characters are first stored in a buffer 510 Completing the Basics
  • 531. Program 9.8), a string, or any other input is accepted by cin and then followed by a getline() function call. There are three solutions to this “phantom” Enter key problem: • Don’t mix cin with getline() inputs in the same program. • Follow the cin input with the call to cin.ignore(). • Accept the Enter key in a character variable and then ignore it. The preferred solution is the first one. All solutions, however, center on the fact that the Enter key is a legitimate character input and must be recognized as such. You encounter this problem again when you learn about accepting char data types in Section 9.4. String Processing Strings can be manipulated by using string class functions or the character-at-a-time functions described in Section 9.4. Table 9.4 lists the most commonly used string class functions plus the standard arithmetic and comparison operators that can also be used with strings. Table 9.4 The string Class Processing Functions (Require the Header File string) Function/Operation Description Example int length() Returns the length of the string string.length() int size() Same as the preceding item string.size() at(int index) Returns the character at the specified index and throws an exception if the index is nonexistent string.at(4) int compare(str) Compares the given string to str; returns a negative value if the given string is less than str, a 0 if they are equal, and a positive value if the given string is greater than str string1.compare(string2) c_str() Returns the string as a null- terminated C-string string1.c_str() bool empty Returns true if the string is empty; otherwise, returns false string1.empty() 511 Chapter 9 The string Class
  • 532. Table 9.4 The string Class Processing Functions (Require the Header File string) (continued) Function/Operation Description Example erase(ind,n) Removes n characters from the string, starting at index ind string1.erase(2,3) erase(ind) Removes all characters from the string, starting from index ind until the end of the string, and the length of the remaining string becomes ind string1.erase(4) int find(str) Returns the index of the first occurrence of str in the complete string string1.find("the") int find(str, ind) Returns the index of the first occurrence of str in the complete string, with the search beginning at index ind string1.find("the",5) int find_first_of(str, ind) Returns the index of the first occurrence of any character in str in the complete string, with the search starting at index ind string1.find_first_of("lt",6) int find_first_not_of(str, ind) Returns the index of the first occurrence of any character not in str in the complete string, with the search starting at index ind string1.find_first_not_of("lt",6) 512 Completing the Basics
  • 533. Table 9.4 The string Class Processing Functions (Require the Header File string) (continued) Function/Operation Description Example void insert(ind, str) Inserts the string str into the complete string, starting at index ind string.insert(4, "there") void replace(ind, n, str) Removes n characters in the string object, starting at index position ind, and inserts the string str at index position ind string1.replace(2,4,"okay") string substr(ind,n) Returns a string consisting of n characters extracted from the string, starting at index ind; if n is greater than the remaining number of characters, the rest of the string is used string2 = string1.substr(0,10) void swap(str) Swaps characters in str with those in the first string string1.swap(string2) [ind] Returns the character at index x, without checking whether ind is a valid index string1[5] = Assignment (also converts a C-string to a string) string1 = string + Concatenates two strings string1 + string2 513 Chapter 9 The string Class
  • 534. Table 9.4 The string Class Processing Functions (Require the Header File string) (continued) Function/Operation Description Example += Concatenation and assignment string2 += string1 == != < <= > >= Relational operators Return true if the relation is satisfied; otherwise, return false string1 == string2 string1 <= string2 string1 > string2 The most commonly used function in Table 9.4 is length(). It returns the number of characters in the string, which is referred to as the string’s length. For example, the value returned by the function call "Hello World!".length() is 12. As always, the quotation marks surrounding a string value aren’t considered part of the string. Similarly, if the string referenced by string1 contains the value "Have a good day.", the value returned by the call string1.length() is 16. Two string expressions can be compared for equality by using the standard relational operators. Each character in a string is stored in binary with the ASCII or Unicode code. Although these codes are different, they have some characteristics in common. In both, a blank precedes (is less than) all letters and numbers; letters of the alphabet are stored in order from A to Z; and digits are stored in order from 0 to 9. In addition, digits come before (are less than) uppercase characters, which are followed by lowercase characters. Therefore, uppercase characters are mathematically less than lowercase characters. When two strings are compared, their characters are compared a pair at a time (both first characters, then both second characters, and so on). If no differences are found, the strings are equal; if a difference is found, the string with the first lower character is considered the smaller string, as shown in these examples: • "Hello" is greater than "Good Bye" because the first H in Hello is greater than the first G in Good Bye. • "Hello" is less than "hello" because the first H in Hello is less than the first h in hello. • "SMITH" is greater than "JONES" because the first S in SMITH is greater than the first J in JONES. • "123" is greater than "1227" because the third character in 123, the 3, is greater than the third character in 1227, the 2. • "Behop" is greater than "Beehive" because the third character in Behop, the h, is greater than the third character in Beehive, the e. Program 9.9 uses length() and several relational expressions in the context of a complete program. 514 Completing the Basics
  • 535. Following is a sample output produced by Program 9.9: string1 is the string: Hello The number of characters in string1 is 5 string2 is the string: Hello there The number of characters in string2 is 11 Hello is less than Hello there 墌 Program 9.9 #include <iostream> #include <string> using namespace std; int main() { string string1 = "Hello"; string string2 = "Hello there"; cout << "string1 is the string: " << string1 << endl; cout << "The number of characters in string1 is " << int(string1.length()) << endl << endl; cout << "string2 is the string: " << string2 << endl; cout << "The number of characters in string2 is " << int(string2.length()) << endl << endl; if (string1 < string2) cout << string1 << " is less than " << string2 << endl << endl; else if (string1 == string2) cout << string1 << " is equal to " << string2 << endl << endl; else cout << string1 << " is greater than " << string2 << endl << endl; string1 = string1 + " there world!"; cout << "After concatenation, string1 contains the characters: " << string1 << endl; cout << "The length of this string is " << int(string1.length()) << endl; return 0; } 515 Chapter 9 The string Class
  • 536. After concatenation, string1 contains the characters: Hello there world! The length of this string is 18 When reviewing this program’s output, refer to Figure 9.7, which shows how the characters in string1 and string2 are stored in memory. The length of each string refers to the total number of characters in the string, and the first character in each string is located at index position 0. Therefore, the length of a string is always one more than the index number of the last character’s position in the string. Although you use the concatenation operator and length() function most often, at times you’ll find the other string functions in Table 9.4 useful. One of the most useful is the at() function, which enables you to retrieve separate characters in a string. Program 9.10 uses this function to select one character at a time from the string, starting at string position 0 and ending at the index of the last character in the string. This last index value is always one less than the number of characters (that is, the string’s length) in the string. The expression str.at(i) in the switch statement retrieves the character at position i in the string. This character is then compared to five different character values. The switch statement uses the fact that selected cases “drop through” in the absence of break statements. Therefore, all selected cases result in an increment to vowelCount. Program 9.10 displays the following output: The string: Counting the number of vowels has 9 vowels. Location of a string string2 string1 Character part of a string object Character part of a string object Location of a string H e l l o H e l l o t h e r e Figure 9.7 The initial strings used in Program 9.9 516 Completing the Basics
  • 537. As an example of inserting and replacing characters in a string with the functions listed in Table 9.4, assume you start with a string created by the following statement: string str = "This cannot be"; Figure 9.8 illustrates how this string is stored in the buffer created for it. As indicated, the length of the string is 14 characters. Now assume the following statement is executed: str.insert(4," I know"); Program 9.10 #include <iostream> #include <string> using namespace std; int main() { string str = "Counting the number of vowels"; int i, numChars; int vowelCount = 0; cout << "The string: " << str << endl; numChars = int(str.length()); for (i = 0; i < numChars; i++) { switch(str.at(i)) // here is where a character is retrieved { case 'a': case 'e': case 'i': case 'o': case 'u': vowelCount++; } } cout << "has " << vowelCount << " vowels." << endl; return 0; } 517 Chapter 9 The string Class
  • 538. This statement inserts the designated seven characters in " I know", beginning with a blank, in the existing string starting at index position 4. Figure 9.9 shows the string after the insertion. If the statement str.replace(12, 6, "to"); is executed next, the existing characters in index positions 12 through 17 are deleted, and the two characters contained in to are inserted starting at index position 12. Figure 9.10 shows the net effect of this replacement. The number of replacement characters (in this case, two) can be fewer than, equal to, or greater than the number of characters being replaced, which in this case is six. Finally, if you append the string "correct" to the string shown in Figure 9.10 by using the concatenation operator, +, you get the string shown in Figure 9.11. Program 9.11 uses these statements in a complete program. Character position: T h i 2 1 0 5 6 4 3 s 8 7 11 12 10 9 13 c a n n o b e t Length = 14 Figure 9.8 Initial storage of a string object Character position: T h i 2 1 0 5 6 4 3 s 8 7 11 12 10 9 13 I k n o w Length = 21 15 14 18 19 17 16 20 a n c n o t b e Figure 9.9 The string after the insertion Character position: T h i 2 1 0 5 6 4 3 s 8 7 11 12 10 9 13 I k n o w Length = 17 15 14 16 o t b e Figure 9.10 The string after the replacement Character position: T h i 2 1 0 5 6 4 3 s 8 7 11 12 10 9 13 I k n o w Length = 25 15 14 18 19 17 16 20 o t b e c o r 22 23 21 24 e c t r Figure 9.11 The string after the append 518 Completing the Basics
  • 539. The following output produced by Program 9.11 matches the strings shown in Figures 9.8 to 9.11: The original string is: This cannot be and has 14 characters. The string, after insertion, is: This I know cannot be and has 21 characters. The string, after replacement, is: This I know to be and has 17 characters. The string, after appending, is: This I know to be correct and has 25 characters. Program 9.11 #include <iostream> #include <string> using namespace std; int main() { string str = "This cannot be"; cout << "The original string is: " << str << endl << " and has " << int(str.length()) << " characters." << endl; // insert characters str.insert(4," I know"); cout << "The string, after insertion, is: " << str << endl << " and has " << int(str.length()) << " characters." << endl; // replace characters str.replace(12, 6, "to"); cout << "The string, after replacement, is: " << str << endl << " and has " << int(str.length()) << " characters." << endl; // append characters str = str + " correct"; cout << "The string, after appending, is: " << str << endl << " and has " << int(str.length()) << " characters." << endl; return 0; } 519 Chapter 9 The string Class
  • 540. Of the remaining string functions listed in Table 9.4, the most commonly used are those that locate specific characters in a string and create substrings. Program 9.12 shows how some of these other functions are used. Program 9.12 #include <iostream> #include <string> using namespace std; int main() { string string1 = "LINEAR PROGRAMMING THEORY"; string s1, s2, s3; int j, k; cout << "The original string is " << string1 << endl; j = int(string1.find('I')); cout << " The first position of an 'I' is " << j << endl; k = int(string1.find('I', (j+1))); cout << " The next position of an 'I' is " << k << endl; j = int(string1.find("THEORY")); cout << " The first location of "THEORY" is " << j << endl; k = int(string1.find("ING")); cout << " The first index of "ING" is " << k << endl; // now extract three substrings s1 = string1.substr(2,5); s2 = string1.substr(19,3); s3 = string1.substr(6,8); cout << "The substrings extracted are:" << endl << " " << s1 + s2 + s3 << endl; return 0; } 520 Completing the Basics
  • 541. Here is the output produced by Program 9.12: The original string is LINEAR PROGRAMMING THEORY The first position of an 'I' is 1 The next position of an 'I' is 15 The first location of "THEORY" is 19 The first index of "ING" is 15 The substrings extracted are: NEAR THE PROGRAM The main point shown in Program 9.12 is that characters and sequences of characters can be located and extracted from a string. EXERCISES 9.3 1. (Practice) Enter and execute Program 9.7. 2. (Practice) Determine the value of text.at(0), text.at(3), and text.at(10), assuming for each one that text is each of the following strings: a. Now is the time b. Rocky raccoon welcomes you c. Happy Holidays d. The good ship 3. (Practice) Enter and execute Program 9.10. 4. (Modify) Modify Program 9.10 to count and display the numbers of each vowel contained in the string. 5. (Modify) Modify Program 9.10 to display the number of vowels in a user-entered string. 6. (Program) Using the at() function, write a C++ program that reads in a string by using getline() and then displays the string in reverse order. (Hint: After the string has been entered and saved, retrieve and display characters, starting from the end of the string.) 7. (Program) Write a C++ program that accepts both a string and a single character from the user. The program should determine how many times the character is contained in the string. (Hint: Search the string by using the find(str, ind) function. This func- tion should be used in a loop that starts the index value at 0 and then changes the index value to one past the index of where the char was last found.) 8. (Practice) Enter and execute Program 9.11. 9. (Practice) Enter and execute Program 9.12. 521 Chapter 9 The string Class
  • 542. 9.4 Character Manipulation Functions In addition to the string functions provided by the string class, the C++ language provides several useful character class functions, listed in Table 9.5. The function declaration (prototype) for each function is contained in the header file string or cctype, which must be included in any program using these functions. Table 9.5 Character Library Functions (Require the Header File string or cctype) Function Prototype Description Example int isalpha(charExp) Returns a true (non-zero integer) if charExp evaluates to a letter; otherwise, it returns a false (zero integer) isalpha('a') int isalnum(charExp) Returns a true (non-zero integer) if charExp evaluates to a letter or a digit; otherwise, it returns a false (zero integer) char key; cin >> key; isalnum(key); int isupper(charExp) Returns a true (non-zero integer) if charExp evaluates to an uppercase letter; otherwise, it returns a false (zero integer) isupper('a') int islower(charExp) Returns a true (non-zero integer) if charExp evaluates to a lowercase letter; otherwise, it returns a false (zero integer) islower('a') int isdigit(charExp) Returns a true (non-zero integer) if charExp evaluates to a digit (0 through 9); otherwise, it returns a false (zero integer) isdigit('a') int isascii(charExp) Returns a true (non-zero integer) if charExp evaluates to an ASCII character; otherwise, returns a false (zero integer) isascii('a') int isspace(charExp) Returns a true (non-zero integer) if charExp evaluates to a space; otherwise, returns a false (zero integer) isspace(' ') int isprint(charExp) Returns a true (non-zero integer) if charExp evaluates to a printable character; otherwise, returns a false (zero integer) isprint('a') int isctrl(charExp) Returns a true (non-zero integer) if charExp evaluates to a control character; otherwise, it returns a false (zero integer) isctrl('a') 522 Completing the Basics
  • 543. Table 9.5 Character Library Functions (Require the Header File string or cctype) (continued) Function Prototype Description Example int ispunct(charExp) Returns a true (non-zero integer) if charExp evaluates to a punctuation character; otherwise, returns a false (zero integer) ispunct('!') int isgraph(charExp) Returns a true (non-zero integer) if charExp evaluates to a printable character other than white space; otherwise, returns a false (zero integer) isgraph(' ') int toupper(charExp) Returns the uppercase equivalent if charExp evaluates to an lowercase character; otherwise, it returns the character code without modification toupper('a') int tolower(charExp) Returns the lowercase equivalent if charExp evaluates to an uppercase character; otherwise, it returns the character code without modification tolower('A') Because all the istype() functions listed in Table 9.5 return a non-zero integer (a Boolean true value) when the character meets the condition and a zero integer (a Boolean false value) when the condition is not met, these functions are typically used in an if statement. For example, the following code segment assumes ch is a character variable: if(isdigit(ch)) cout << "The character just entered is a digit" << endl; else if(ispunct(ch)) cout << "The character just entered is a punctuation mark" << endl; In this example, if ch contains a digit character, the first cout statement is executed; if the character is a letter, the second cout statement is executed. In both cases, however, the character to be checked is included as an argument to the function. Program 9.13 illustrates this type of code in a program that counts the number of letters, digits, and other characters in a string. The characters to be checked are obtained by using the string class’s at() function. In Program 9.13, this function is used in a for loop that cycles through the string from the first character to the last. The output produced by Program 9.13 is the following: The original string is: This -123/ is 567 A ?<6245> Test! This string contains 33 characters, which consist of 11 letters 10 digits 12 other characters. As indicated by this output, each of the 33 characters in the string has been categorized correctly as a letter, a digit, or other character. 523 Chapter 9 Character Manipulation Functions
  • 544. Program 9.13 #include <iostream> #include <string> #include <cctype> using namespace std; int main() { string str = "This -123/ is 567 A ?<6245> Test!"; char nextChar; int i; int numLetters = 0, numDigits = 0, numOthers = 0; cout << "The original string is: " << str << "nThis string contains " << int(str.length()) << " characters," << " which consist of" << endl; // check each character in the string for (i = 0; i < int(str.length()); i++) { nextChar = str.at(i); // get a character if (isalpha(nextChar)) numLetters++; else if (isdigit(nextChar)) numDigits++; else numOthers++; } cout << " " << numLetters << " letters" << endl; cout << " " << numDigits << " digits" << endl; cout << " " << numOthers << " other characters." << endl; cin.ignore(); return 0; } 524 Completing the Basics
  • 545. Typically, as in Program 9.13, the functions in Table 9.5 are used in a character-by- character manner on each character in a string. You see this again in Program 9.14, where each lowercase string character is converted to its uppercase equivalent by using the toupper() function. This function converts only lowercase letters, leaving all other characters unaffected. In Program 9.14, pay particular attention to the statement for (i = 0; i < int(str.length()); i++) used to cycle through each character in the string. Typically, this cycling through the string, a character at a time, is how each element in a string is accessed, using the length() function to determine when the end of the string has been reached. (Review Program 9.13 to see that it’s used in the same way.) The only real difference is that in Program 9.14, each element is accessed by using the subscript notation str[i]; in Program 9.13, the at() function is used. Although these two notations are interchangeable—and which one you use is a matter of choice—for consistency, the two notations shouldn’t be mixed in the same program. A sample run of Program 9.14 produced the following output: Type in any sequence of characters: this is a test of 12345. The characters just entered, in uppercase, are: THIS IS A TEST OF 12345. Program 9.14 #include <iostream> #include <string> using namespace std; int main() { int i; string str; cout << "Type in any sequence of characters: "; getline(cin,str); // cycle through all elements of the string for (i = 0; i < int(str.length()); i++) str[i] = toupper(str[i]); cout << "The characters just entered, in uppercase, are: " << str << endl; cin.ignore(); return 0; } 525 Chapter 9 Character Manipulation Functions
  • 546. Character I/O Although you have used cin and getline() to accept data entered from the keyboard in a more or less “cookbook” manner, you need to understand what data is being sent to the program and how the program must react to process the data. At a fundamental level, all input (as well as output) is done on a character-by-character basis, as illustrated in Figure 9.12. As Figure 9.12 shows, the entry of every piece of data, whether it’s a string or a number, consists of typing characters. For example, entry of the string Hello consists of pressing and releasing the five character keys H, e, l, l, o, and the Enter key. Similarly, output of the number 26.95 consists of displaying the five characters 2, 6, ., 9, and 5. Although programmers typically don’t think of data in this manner, programs are restricted to this character-by-character I/O, and all of C++’s higher-level I/O functions and stream objects are based on lower-level character I/O functions. These more elemental character functions, which can be used by a programmer, are listed in Table 9.6. H e l l o Assemble into a string Is it 'n'? get() int Replace with getline() Stream of data 'H' 'e' 'l' 'l' 'o' <Enter> No Stop reading Yes value Figure 9.12 Accepting keyboard-entered characters 526 Completing the Basics
  • 547. Table 9.6 Basic Character I/O Functions (Require the Header File cctype) Function Description Example cout.put(charExp) Places the character value of charExp on the output stream. cout.put('A'); cin.get(charVar) Extracts the next character from the input stream and assigns it to the variable charVar. cin.get(key); cin.peek(charVar) Assigns the next character from the input stream to the variable charVar without extracting the character from the stream. cin.peek(nextKey); cin.putback(charExp) Pushes a character value of charExp back onto the input stream. cin.putback(cKey); Point of Information Why the char Data Type Uses Integer Values In C++, a character is stored as an integer value, which is sometimes confusing to beginning programmers. The reason is that, in addition to standard English letters and characters, a program needs to store special characters that have no printable equivalents. One is the end-of-file (EOF) sentinel that all computer systems use to desig- nate the end of a data file. The EOF sentinel can be transmitted from the keyboard. For example, on UNIX-based systems, it’s generated by holding down the Ctrl key and pressing the D key; on Windows-based systems, it’s generated by holding down Ctrl and pressing Z. On both systems, the EOF sentinel is stored as the integer number -1, which has no equivalent character value. (You can check this by displaying the integer value of each entered character [see Program 9.15] and typing Ctrl+D or Ctrl+Z, depending on the system you’re using.) By using a 16-bit integer value, more than 64,000 different characters can be represented. This number of characters provides enough storage for multiple character sets, including Arabic, Chinese, Hebrew, Japanese, and Russian, and almost all known language symbols. Therefore, storing a character as an integer value has a practical value. An important consequence of using integer codes for string characters is that char- acters can be compared easily for alphabetical ordering. For example, as long as each subsequent letter in an alphabet has a higher value than its preceding letter, the com- parison of character values is reduced to the comparison of numeric values. Storing characters in sequential numerical order ensures that adding one to a letter produces the next letter in the alphabet. 527 Chapter 9 Character Manipulation Functions
  • 548. Table 9.6 Basic Character I/O Functions (Require the Header File cctype) (continued) Function Description Example cin.ignore(n, char) Ignores a maximum of the next n input characters, up to and including the detection of char. If no arguments are specified, ignores the next single character on the input stream. cin.ignore(80,'n'); cin.ignore(); The get() function reads the next character in the input stream and assigns it to the function’s character variable. For example, examine this statement: cin.get(nextChar); It causes the next character entered at the keyboard to be stored in the character variable nextChar. This function is useful for inputting and checking characters before they are assigned to a complete string or C++ data type. The character output function corresponding to get() is put(). This function expects a single-character argument and displays the character passed to it on the screen. For example, the statement cout.put('A') causes the letter A to be displayed on the screen. Of the last three functions listed in Table 9.6, the cin.ignore() function is the most useful. This function permits skipping over input until a designated character, such as 'n', is encountered. For example, the statement cin.ignore(80, 'n') skips up to a maximum of the next 80 characters or stops skipping if the newline character is encountered. This statement can be useful in skipping all further input on a line, up to a maximum of 80 characters, or until the end of the current line is encountered. Input would begin with the next line. The peek() function returns the next character on the stream but doesn’t remove it from the stream’s buffer (see Table 9.6). For example, the expression cin.peek(nextChar) returns the next character input on the keyboard but leaves it in the buffer. This action is sometimes useful for peeking ahead and seeing what the next character is but leaving it in place for the next input. Finally, the putback() function places a character back on the stream so that it’s the next character read. The argument passed to putback() can be any character expression that evaluates to a legitimate character value; it doesn’t have to be the last input character. The Phantom Newline Character Revisited As you saw in Section 9.3, sometimes you get seemingly strange results when a cin input stream is followed by a getline() function call. This same result can occur when characters are inputted by using the get() character function. To see how it can occur, take a look at Program 9.15, which uses the get() function to accept the next character entered at the keyboard and stores the character in the variable fkey. 528 Completing the Basics
  • 549. When Program 9.15 runs, the character entered in response to the prompt Type in a character: is stored in the character variable fkey, and the decimal code for the character is displayed by explicitly casting the character into an integer to force its display as an integer value. The following sample run illustrates this technique: Type in a character: m The key just accepted is 109 At this point, everything seems to be working, although you might be wondering why the decimal value of m is displayed instead of the character. In typing m, two keys are usually pressed, the m key and the Enter key. As in the previous section, these two characters are stored in a buffer after they’re pressed (refer back to Figure 9.12). The first key pressed, m in this case, is taken from the buffer and stored in fkey, but the code for the Enter key is still in the buffer. Therefore, a subsequent call to get() for a character input picks up the code for the Enter key as the next character automatically. For example, take a look at Program 9.16. Point of Information A Notational Inconsistency All the character class functions listed in Table 9.6 use the standard object-oriented notation of preceding the function’s name with an object name, as in cin.get(). However, the string class getline() function uses the notation getline(cin, strVar). In this notation, the object (cin) appears as an argument, which is how procedural-based functions pass variables. For consistency, you would expect getline() to be called as cin.getline(). Unfortunately, this notation was already in use for a getline() function created for C-style strings (which are simply one- dimensional arrays of characters, as discussed in Section 7.2), so a notational inconsis- tency was created. Program 9.15 #include <iostream> using namespace std; int main() { char fkey; cout << "Type in a character: "; cin.get(fkey); cout << "The key just accepted is " << int(fkey) << endl; return 0; } 529 Chapter 9 Character Manipulation Functions
  • 550. The following is a sample run of Program 9.16: Type in a character: m The key just accepted is 109 Type in another character: The key just accepted is 10 After entering the letter m in response to the first prompt, the Enter key is also pressed. From a character standpoint, this input represents the entry of two distinct characters. The first character is m, which is coded and stored as the integer 109. The second character also gets stored in the buffer with the numerical code for the Enter key. The second call to get() picks up this code immediately, without waiting for another key to be pressed. The last cout stream displays the code for this key. The reason for displaying the numerical code rather than the character is that the Enter key has no printable character associated with it that can be displayed. Remember that every key has a numerical code, including Enter, the spacebar, Esc, and Ctrl. These keys generally have no effect when entering numbers because the input functions ignore them as leading or trailing input with numerical data. These keys also don’t affect the entry of a single character requested as the first user data to be inputted, as in Program 9.15. Only when a character is requested after the user has already input other data, as in Program 9.16, does the usually invisible Enter key become noticeable. In Section 9.1, you learned some ways to prevent the Enter key from being accepted as a legitimate character input when the getline() function is used. You can use the following ways when the get() function is used in a program: • Follow the cin.get() input with the call cin.ignore(). • Accept the Enter key in a character variable, and then don’t use it again. Program 9.16 #include <iostream> using namespace std; int main() { char fkey, skey; cout << "Type in a character: "; cin.get(fkey); cout << "The key just accepted is " << int(fkey) << endl; cout << "Type in another character: "; cin.get(skey); cout << "The key just accepted is " << int(skey) << endl; return 0; } 530 Completing the Basics
  • 551. Program 9.17 applies the first solution to Program 9.16. Ignoring the Enter key after the first character is read and displayed clears the buffer of the Enter key and gets it ready to store the next valid input character as its first character. In Program 9.17, observe that when the user types the letter m and presses the Enter key, the m is assigned to fkey and the code for the Enter key is ignored. The next call to get() stores the code for the next key pressed in the variable skey. From the user’s standpoint, the Enter key has no effect, except to signal the end of each character input. The following is a sample run of Program 9.17: Type in a character: m The key just accepted is 109 Type in another character: b The key just accepted is 98 A Second Look at User-Input Validation As mentioned in the first look at user-input validation (in Section 3.4), programs that respond effectively to unexpected user input are formally referred to as robust programs and informally as “bulletproof” programs. Code that validates user input and ensures that a program doesn’t produce unintended results caused by unexpected input is a sign of a well-constructed, robust program. One of your jobs as a programmer is to produce robust Program 9.17 #include <iostream> using namespace std; int main() { char fkey, skey; cout << "Type in a character: "; cin.get(fkey); cout << "The key just accepted is " << int(fkey) << endl; cin.ignore(); cout << "Type in another character: "; cin.get(skey); cout << "The key just accepted is " << int(skey) << endl; cin.ignore(); return 0; } 531 Chapter 9 Character Manipulation Functions
  • 552. programs. To see how unintended results can occur, examine the following two code examples. First, assume your program contains the following statements: cout << "Enter an integer: "; cin >> value; By mistake, a user enters the characters e4. In earlier versions of C++, this input would cause the program to terminate unexpectedly, or crash. Although a crash can still occur with the current ANSI/ISO standard, it doesn’t in this case. Instead, a meaningless integer value is assigned to the variable value. This assignment, of course, invalidates any results obtained by using this variable. As a second example, take a look at the following code, which causes an infinite loop if the user enters a non-numeric value. (The program can be halted by holding down Ctrl and pressing C.) double value; do { cout << "Enter a number (enter 0 to exit): "; cin >> value; cout << "The square root of this number is: " << sqrt(value) << endl; }while (value !=0); The basic technique for handling invalid data input and preventing seemingly innocuous code, as in these two examples, from producing unintended results is referred to as user-input validation. This term means validating the entered data during or after data entry and giving the user a way of reentering data, if it’s invalid. User-input validation is an essential part of any commercially viable program, and if done correctly, it protects a program from attempting to process data types that can cause a program to crash, create infinite loops, or produce more invalid results. The central element in user-input validation is checking each entered character to verify that it qualifies as a legitimate character for the expected data type. For example, if an integer is required, the only acceptable characters are a leading plus (+) or minus (-) sign and the digits 0 through 9. These characters can be checked as they’re being typed, which means the get() function is used to input a character at a time, or after all the characters can be accepted in a string, and then each string character is checked for validity. After all the entered characters have been validated, the entered string can be converted into the correct data type. Two basic techniques can be used to verify the validity of entered characters. Section 9.5 explains one of these techniques: character-by-character checking. A second technique, which encompasses a broader scope of data-processing tasks using exception handling, is discussed at the end of Section 9.5. EXERCISES 9.4 1. (Practice) Enter and execute Program 9.13. 2. (Practice) Enter and execute Program 9.14. 532 Completing the Basics
  • 553. 3. (Practice) Write a C++ program that counts the number of words in a string. A word is encountered whenever a transition from a blank space to a nonblank character is encountered. The string contains only words separated by blank spaces. 4. (Practice) Generate 10 random numbers in the range 0 to 129. If the number represents a printable character, print the character with an appropriate message that indicates the following: The character is a lowercase letter. The character is an uppercase letter. The character is a digit. The character is a space. If the character is none of these, display its value in integer format. 5. (Practice) a. Write a function named length() that determines and returns the length of a string without using the string class length() function. b. Write a simple main() function to test the length() function written for Exercise 5a. 6. (Practice) a. Write a function named countlets() that returns the number of letters in a string passed as an argument. Digits, spaces, punctuation, tabs, and newline charac- ters should not be included in the returned count. b. Include the countlets() function written for Exercise 6a in an executable C++ pro- gram, and use the program to test the function. 7. (Practice) Write a program that accepts a string from the console and displays the hexa- decimal equivalent of each character in the string. 8. (Practice) Write a C++ program that accepts a string from the console and displays the string one word per line. 9. (Debug) In response to the following code, suppose a user enters the data 12e4: cout << "Enter an integer: "; cin >> value; What value will be stored in the integer variable value? 9.5 Input Data Validation One of the major uses of strings in programs is for user-input validation. Validating user input is essential: Even though a program prompts the user to enter a specific type of data, such as an integer, the prompt doesn’t ensure that the user will comply. What a user enters is, in fact, totally out of the programmer’s control. What is in your control is how you deal with the entered data. It certainly does no good to tell a frustrated user that “The program clearly tells you to enter an integer, and you entered a date.” Successful programs anticipate invalid data and prevent it from being accepted and processed. Typically, this is accomplished by first validating that data is of the correct type. If it is, the data is accepted; otherwise, the user is requested to reenter the data, with an explanation of why the entered data was invalid. 533 Chapter 9 Input Data Validation
  • 554. A common method of validating numerical input data is accepting all numbers as strings. Each character in the string can then be checked to make sure it complies with the requested data type. After this check is made and data is verified to be the correct type, the string is converted to an integer or double-precision value by using the conversion functions listed in Table 9.7. (For data accepted with string class objects, the c_str() function must be applied to the string before the conversion function is called.) As an example, consider inputting an integer number. To be valid, the data entered must adhere to the following conditions: • The data must contain at least one character. • If the first character is a + or - sign, the data must contain at least one digit. • Only digits from 0 to 9 are acceptable following the first character. Table 9.7 C-String Conversion Functions Function Description Example int atoi(stringExp) Converts stringExp to an integer. Conversion stops at the first non-integer character. atoi("1234") double atof(stringExp) Converts stringExp to a double-precision number. Conversion stops at the first character that can’t be interpreted as a double. atof("12.34") char[] itoa(integerExp) Converts integerExp to a character array. The space allocated for the returned characters must be large enough for the converted value. itoa(1234) The following function, isvalidInt(), can be used to check that an entered string complies with these conditions. This function returns the Boolean value of true if the conditions are satisfied; otherwise, it returns a Boolean false value. bool isvalidInt(string str) { int start = 0; int i; bool valid = true; // assume a valid bool sign = false; // assume no sign // check for an empty string if (int(str.length()) == 0) valid = false; // check for a leading sign if (str.at(0) == '-'|| str.at(0) == '+') { sign = true; start = 1; // start checking for digits after the sign } 墌 534 Completing the Basics
  • 555. // check that there is at least one character after the sign if (sign && int(str.length()) == 1) valid = false; // now check the string, which you know // has at least one non-sign character i = start; while(valid && i < int(str.length())) { if(!isdigit(str.at(i))) valid = false; //found a non-digit character i++; // move to next character } return valid; } In the code for the isvalidInt() function, pay attention to the conditions being checked. They are commented in the code and consist of the following: • The string is not empty. • A valid sign (+ or -) is present. • If a sign is present, at least one digit follows it. • All the remaining characters in the string are digits. Only if all these conditions are met does the function return a Boolean true value. After this value is returned, the string can be converted into an integer safely with the assurance that no unexpected value will result to hamper further data processing. Program 9.18 uses this function in the context of a complete program. Program 9.18 #include <iostream> #include <string> using namespace std; int main() { bool isvalidInt(string); // function prototype (declaration) string value; int number; cout << "Enter an integer: "; getline(cin, value); 墌 535 Chapter 9 Input Data Validation
  • 556. if (!isvalidInt(value)) cout << "The number you entered is not a valid integer."; else { number = atoi(value.c_str()); cout << "The integer you entered is " << number; } return 0; } bool isvalidInt(string str) { int start = 0; int i; bool valid = true; // assume a valid bool sign = false; // assume no sign // check for an empty string if (int(str.length()) == 0) valid = false; // check for a leading sign if (str.at(0) == '-'|| str.at(0) == '+') { sign = true; start = 1; // start checking for digits after the sign } // check that there is at least one character after the sign if (sign && int(str.length()) == 1) valid = false; // now check the string, which you know // has at least one non-sign character i = start; while(valid && i < int(str.length())) { if(!isdigit(str.at(i))) valid = false; //found a non-digit character i++; // move to next character } return valid; } 536 Completing the Basics
  • 557. Two sample runs of Program 9.18 produced the following output: Enter an integer: 12e45 The number you entered is not a valid integer. and Enter an integer: -12345 The integer you entered is -12345 As shown by this output, the program successfully determines that an invalid character was entered in the first run. A second line of defense is to provide error-processing code in the context of exception- handling code. This type of code is typically used to permit the user to correct a problem, such as invalid data entry, by reentering a new value. The means of providing this code in C++ is referred to as exception handling. Using exception handling, you can construct a complete means of ensuring that the user enters an integer number in response to a request for an integer value. The technique involves extending the isvalidInt() function in Program 9.18 to ensure that not only is an invalid integer value detected, but also the program gives the user the option of reentering values until a valid integer is entered. This technique can be applied easily to ensure the entry of a valid double-precision number, which is the other numerical data type often requested as user-entered data. Using the isvalidInt() function from Program 9.18, a more comprehensive function named getanInt() is developed that uses exception processing to accept user input continuously until a string corresponding to a valid integer is detected. After a valid string is entered, the getanInt() function converts the string to an integer and returns the integer value. This technique ensures that the program requesting an integer actually receives aninteger and prevents any unwarranted effects, such as a program crash caused by an invalid data type being entered. The algorithm used to perform this task is as follows: Set a Boolean variable named notanint to true while (notanint is true) try Accept a string value If the string value does not correspond to an integer, throw an exception catch the exception Display the error message "Invalid integer - Please reenter: " Send control back to the while statement Set notanint to false (causes the loop to terminate) End while Return the integer corresponding to the entered string The code corresponding to this algorithm is shaded in Program 9.19. 537 Chapter 9 Input Data Validation
  • 558. Program 9.19 #include <iostream> #include <string> using namespace std; int main() { int getanInt(); // function declaration (prototype) int value; cout << "Enter an integer value: "; value = getanInt(); cout << "The integer entered is: " << value << endl; return 0; } int getanInt() { bool isvalidInt(string); // function declaration (prototype) bool notanint = true; string svalue; while (notanint) { try { cin >> svalue; // accept a string input if (!isvalidInt(svalue)) throw svalue; } catch (string e) { cout << "Invalid integer - Please reenter: "; continue; // send control to the while statement } notanint = false; } return atoi(svalue.c_str()); // convert to an integer } 墌 538 Completing the Basics
  • 559. Following is a sample output produced by Program 9.19: Enter an integer value: abc Invalid integer - Please reenter: 12. Invalid integer - Please reenter: 12e Invalid integer - Please reenter: 120 The integer entered is: 120 As this output shows, the getanInt() function works correctly. It requests input continuously until a valid integer is entered. bool isvalidInt(string str) { int start = 0; int i; bool valid = true; // assume a valid bool sign = false; // assume no sign // check for an empty string if (int(str.length()) == 0) valid = false; // check for a leading sign if (str.at(0) == '-'|| str.at(0) == '+') { sign = true; start = 1; // start checking for digits after the sign } // check that there is at least one character after the sign if (sign && int(str.length()) == 1) valid = false; // now check the string, which you know // has at least one non-sign character i = start; while(valid && i < int(str.length())) { if(!isdigit(str.at(i))) valid = false; // found a non-digit character i++; // move to next character } return valid; } 539 Chapter 9 Input Data Validation
  • 560. EXERCISES 9.5 1. (Practice) Write a C++ program that prompts the user to type in an integer. Have your program use cin to accept the number as an integer and use cout to display the value your program actually accepted from the data entered. Run your program four times. The first time you run the program, enter a valid integer number; the second time, enter a double-precision number; the third time, enter a character; and the fourth time, enter the value 12e34. 2. (Modify) Modify the program you wrote for Exercise 1, but have your program use a double-precision variable. Run the program four times: First, enter an integer; second, enter a decimal number; third, enter a decimal number with an f as the last character entered; and fourth, enter a character. Using the output display, keep track of what num- ber your program actually accepted from the data you entered. What happened, if any- thing, and why? 3. (For Thought) a. Why do you think successful application programs contain extensive data input validity checks? (Hint: Review Exercises 1 and 2.) b. What do you think is the difference between a data-type check and a data- reasonableness check? c. A program requests that the user enter a month, day, and year. What are some reason- ableness checks that could be made on the data entered? 4. (Practice) a. Enter and execute Program 9.18. b. Run Program 9.18 four times, using the data referred to in Exercise 1 for each run. 5. (Modify) Modify Program 9.18 to display any invalid characters that were entered. 6. (Modify) Modify Program 9.18 to request an integer continuously until a valid number is entered. 7. (Modify) Modify Program 9.18 to remove all leading and trailing spaces from the entered string before it’s checked for validity. 8. (Useful Utility) Write a function that checks each digit as it’s entered, instead of check- ing the completed string, as in Program 9.18. 9. (Practice) Enter and execute Program 9.19. 10. (Modify) Modify the isvalidInt() function used in Program 9.19 to remove all lead- ing and trailing blank spaces from its string argument before determining whether the string corresponds to a valid integer. 11. (Modify) Modify the isvalidInt() function used in Program 9.19 to accept a string that ends in a decimal point. For example, the input 12. should be accepted and con- verted to the integer number 12. 540 Completing the Basics
  • 561. 9.6 A Closer Look: Namespaces and Creating a Personal Library Until the introduction of PCs in the early 1980s, with their extensive use of integrated circuits and microprocessors, computer speed and available memory were severely restricted. For example, the most advanced computers had speeds measured in milliseconds; current computers have speeds measured in nanoseconds and higher. Similarly, the memory capacity of early desktop computers consisted of 4000 bytes of internal memory, but today’s computer memories are in the 512 MB range and higher. With these early hardware restrictions, programmers had to use every possible trick to save memory space and make programs run more efficiently. Almost every program was hand-crafted and included what was called “clever code” to minimize runtime and maximize use of memory storage. Unfortunately, this individualized code became a liability. New programmers had to spend considerable time to understand existing code; even the original programmer had trouble figuring out code written only months before. This complexity in code made modifications time consuming and costly and precluded cost-effective reuse of existing code for new installations. The inability to reuse code efficiently, combined with expanded hardware capabilities, prompted the discovery of more efficient programming. This discovery began with structured programming concepts incorporated into procedural languages, such as Pascal, and led to the object-oriented techniques that form the basis of C++. An early criticism of C++, however, was that it didn’t have a comprehensive library of classes, but with the current ANSI/ISO standard, an extensive C++ library is available. No matter how many useful classes and functions the standard library provides, however, each major type of programming application, such as engineering, scientific, and financial, has its own specialized requirements. For example, the ctime header file in C++ provides good date and time functions. However, for specialized needs, such as scheduling problems, these functions must be expanded to include finding the number of working days between two dates, taking into account weekends and holidays, among other tasks. These functions could be provided as part of a more complete Date class or as non-class functions. To meet these specialized needs, programmers create and share their own libraries of classes and functions with other programmers working on the same or similar projects. After the classes and functions have been tested, they can be incorporated into any program without further coding time. At this stage in your programming career, you can begin building your own library of specialized functions and classes. Section 9.5 described how to do this with the input validation functions, isvalidInt() and getanInt(), which are reproduced here for convenience: bool isvalidInt(string str) { int start = 0; int i; bool valid = true; // assume a valid bool sign = false; // assume no sign // check for an empty string if (int(str.length()) == 0) valid = false; 墌 541 Chapter 9 A Closer Look: Namespaces and Creating a Personal Library
  • 562. // check for a leading sign if (str.at(0) == '-'|| str.at(0) == '+') { sign = true; start = 1; // start checking for digits after the sign } // check that there is at least one character after the sign if (sign && int(str.length()) == 1) valid = false; // now check the string, which you know // has at least one non-sign character i = start; while(valid && i < int(str.length())) { if(!isdigit(str.at(i))) valid = false; // found a // non-digit character i++; // move to next character } return valid; } int getanInt() { bool isvalidInt(string); // function declaration (prototype) bool notanint = true; string svalue; while (notanint) { try { cin >> svalue; // accept a string input if (!isvalidInt(svalue)) throw svalue; } catch (string e) { cout << "Invalid integer - Please reenter: "; continue; // send control to the while statement } notanint = false; } return atoi(svalue.c_str()); // convert to an integer } The first step in creating a library is to encapsulate all the specialized functions and classes into one or more namespaces and then store the complete code (with or without using a namespace) into one or more files. For example, you can create one namespace, dataChecks, and save it in the file named dataChecks.cpp. Note that the namespace’s filename need not be the same as the namespace name used in the code. The syntax for creating a namespace is the following: namespace name { // functions and/or classes in here } // end of namespace 542 Completing the Basics
  • 563. The following code includes the two functions isvalidInt() and getanInt() in the namespace dataChecks, adds the appropriate include files, and uses a declaration statement needed by the new namespace. The syntax required to create the namespace has been shaded: #include <iostream> #include <string> using namespace std; namespace dataChecks { bool isvalidInt(string str) { int start = 0; int i; bool valid = true; // assume a valid bool sign = false; // assume no sign // check for an empty string if (int(str.length()) == 0) valid = false; // check for a leading sign if (str.at(0) == '-'|| str.at(0) == '+') { sign = true; start = 1; // start checking for digits after the sign } // check that there is at least one character after the sign if (sign && int(str.length()) == 1) valid = false; // now check the string, which you know // has at least one non-sign character i = start; while(valid && i < int(str.length())) { if(!isdigit(str.at(i))) valid = false; // found a // non-digit character i++; // move to next character } return valid; } int getanInt() { bool isvalidInt(string); // function declaration (prototype) bool notanint = true; string svalue; while (notanint) { try { cin >> svalue; // accept a string input if (!isvalidInt(svalue)) throw svalue; } 墌 543 Chapter 9 A Closer Look: Namespaces and Creating a Personal Library
  • 564. catch (string e) { cout << "Invalid integer - Please reenter: "; continue; // send control to the while statement } notanint = false; } return atoi(svalue.c_str()); // convert to an integer } } // end of dataChecks namespace After the namespace has been created and stored in a file, it can be included in another file by supplying a preprocessor directive to inform the compiler where the namespace is found and by including a using directive that tells the compiler which namespace in the file to use. For the dataChecks namespace, which is stored in a file named dataChecks. cpp, the following statements perform these tasks: #include <c:mylibrarydataChecks.cpp> using namespace dataChecks; The first statement provides the full pathname for the source code file. Notice that two backslashes are used to separate items in pathnames. The double backslashes are required when providing a relative or full pathname. The only time backslashes aren’t required is when the library code is in the same directory as the program being executed. As indicated, the dataChecks source file is saved in the mylibrary folder. The second statement tells the compiler to use the dataChecks namespace in the designated file. Program 9.20 includes these two statements in an executable program. The only requirement for the include statement in Program 9.20 is that the filename and location must correspond to an existing file with the same name in the designated path; Program 9.20 #include <c:mylibrarydataChecks.cpp> using namespace dataChecks; int main() { int value; cout << "Enter an integer value: "; value = getanInt(); cout << "The integer entered is: " << value << endl; return 0; } 544 Completing the Basics
  • 565. otherwise, a compiler error occurs. If you want to name the source code file with a file extension, any extension can be used as long as these rules are followed: • The filename under which the code is stored includes the extension. • The same filename, including extension, is used in the include statement. Therefore, if the filename used to store the functions is dataLib.cpp, the include statement in Program 9.20 would be the following: #include <c:mylibrarydataLib.cpp> Additionally, a namespace isn’t required in the file. Using a namespace permits you to isolate the data-checking functions in one area and add more namespaces to the file as needed. Designating a namespace in the using statement tells the compiler to include only the code in the specified namespace rather than all code in the file. In Program 9.20, if the data-checking functions weren’t enclosed in a namespace, the using statement for the dataChecks namespace would have to be omitted. Including the previously written and tested data-checking functions in Program 9.20 as a separate file enables you to focus on the program code using these functions instead of being concerned with function code that’s already been written and tested. In Program 9.20, the main() function exercises the data-checking functions and produces the same output as Program 9.19. In creating the dataChecks namespace, you have included source code for the two functions. Including this code isn’t required, and a compiled version of the source code can be saved instead. Finally, additions to a namespace defined in one file can be made in another file by using the same namespace name in the new file and including a using statement for the first file’s namespace. EXERCISES 9.6 1. (Practice) Enter and compile Program 9.20. (Hint: The namespace file dataChecks and the program file are available with the source code provided on this book’s Web site.) 2. (For Thought) Why would a programmer supply a namespace file in its compiled form rather than as source code? 3. (For Thought) a. What is an advantage of namespaces? b. What is a possible disadvantage of namespaces? 4. (For Thought) What types of classes and functions would you include in a personal library? Why? 5. (Useful Utility) a. Write a C++ function named whole() that returns the integer part of any number passed to the function. (Hint: Assign the passed argument to an integer variable.) b. Include the function written in Exercise 5a in a working program. Make sure your function is called from main() and correctly returns a value to main(). Have main() use a cout statement to display the returned value. Test the function by passing various data to it. 545 Chapter 9 A Closer Look: Namespaces and Creating a Personal Library
  • 566. c. When you’re confident that the whole() function written for Exercise 5a works cor- rectly, save it in a namespace and a personal library of your choice. 6. (Useful Utility) a. Write a C++ function named fracpart() that returns the fractional part of any number passed to the function. For example, if the number 256.879 is passed to fracpart(), the number .879 should be returned. Have the fracpart() function call the whole() function you wrote in Exercise 5a. The number returned can then be determined as the number passed to fracpart() less the returned value when the same argument is passed to whole(). b. Include the function written in Exercise 6a in a working program. Make sure the function is called from main() and correctly returns a value to main(). Have main() use a cout statement to display the returned value. Test the function by passing various data to it. c. When you’re confident the fracpart() function written for Exercise 6a works cor- rectly, save it in the same namespace and personal library selected for Exercise 5c. 9.7 Common Programming Errors Here are the common errors associated with defining and processing strings: 1. Forgetting to include the string header file when using string class objects. 2. Forgetting that the newline character, 'n', is a valid data input character. 3. Forgetting to convert a string class object by using the c_str() function when converting string class objects to numerical data types. 9.8 Chapter Summary 1. A string literal is any sequence of characters enclosed in quotation marks. It’s referred to as a string value, a string constant, and, more conventionally, a string. 2. A string can be constructed as an object of the string class. 3. The string class is commonly used for constructing strings for input and output purposes, such as for prompts and displayed messages. Because of its capabilities, this class is used when strings need to be compared or searched or specific characters in a string need to be examined or extracted as a substring. It’s also used in more advanced situations when characters in a string need to be replaced, inserted, or deleted regularly. 4. Strings can be manipulated by using the functions of the class they’re objects of or by using the general-purpose string and character functions. 5. The cin object, by itself, tends to be of limited usefulness for string input because it terminates input when a blank is encountered. 6. For string class data input, use the getline() function. 7. The cout object can be used to display string class strings. 546 Completing the Basics
  • 567. Programming Projects for Chapter 9 1. (Practice) Enter the data for the info.txt file in Figure 9.1 or download it from this book’s Web site. Then enter and execute Program 9.5 and verify that the backup file was written. 2. (Modify) Modify Program 9.5 to use a getline() function in place of the get() method currently in the program. 3. (Useful Utility) a. Write a C++ function that accepts a string and two character values. The function should return the string with each occurrence of the first character replaced by the second character. b. Test the function written for Exercise 3a by writing a program that accepts a string from the user, calls the function written for Exercise 3a to replace all occurrences of the letter e with the letter x from the user-entered string, and then displays the changed string. 4. (Useful Utility) Modify the function written for Exercise 3a to search for the first occurrence of a user-entered sequence of characters, and then replace this sequence, when it’s found in the string, with a second user-entered sequence. For example, if the entered string is Figure 4-4 illustrates the output of Program 4-2 and the user enters that 4- is to be replaced by 3-, the resulting string is Figure 3-4 illustrates the output of Program 4-2. (Only the first occurrence of the searched for sequence has been changed.) 5. (Useful Utility) Modify the program written for Exercise 4 to replace all occurrences of the designated sequence of characters with the new sequence of characters. For example, if the entered string is Figure 4-4 illustrates the output of Program 4-2 and the user enters that 4- is to be replaced by 3-, the resulting string is Figure 3-4 illustrates the output of Program 3-2. 6. (Data Processing) a. Write a C++ program that stops reading a line of text when a period is entered and displays the sentence with correct spacing and capitalization. For this program, correct spacing means only one space between words, and all letters should be lowercase, except the first letter. For example, if the user enters the text i am going to Go TO THe moVies., the displayed sentence should be I am going to go to the movies. b. Determine what characters, if any, aren’t displayed correctly by the program you created for Exercise 6a. 7. (Data Processing) Write a C++ program that accepts a name as first name followed by last name, and then displays the name as last name, first name. For example, if the user enters Gary Bronson, the output should be Bronson, Gary. 8. (Data Processing) Modify the program written for Exercise 7 to include an array of five names. 547 Chapter 9 Programming Projects
  • 568. 9. (Useful Utility) a. Write a C++ function named isvalidReal() that checks for a valid double-precision number. This kind of number can have an optional + or - sign, at most one decimal point (which can be the first character), and at least one digit between 0 and 9. The function should return a Boolean value of true if the entered number is a real number; otherwise, it should return a Boolean value of