A Guide To C++ Programming
A Guide To C++ Programming
A Guide To C++ Programming
C++
The data files used in this text can be downloaded from lpdatafiles.com
Also available for downloading are data and library files, instructions for compilers, and separate chapters that describe different operating systems.
Copyright 1997 by
First Edition
(softcover) (hardcover)
All rights reserved. No part of this work covered by the copyright may be reproduced or used in any form or by any means graphic, electronic, or mechanical, including photocopying, recording, taping, or information storage and retrieval systems without the written permission of the publisher, with the exception of programs, which may be entered, stored, and executed in a computer system, but not reprinted for publication or resold in any other form.
All orders including educational, Canadian, foreign, FPO, and APO may be placed by contacting:
Lawrenceville Press, Inc. P.O. Box 704 Pennington, NJ 08534-0704 (609) 737-1148 (609) 737-8564 fax
The text is written and published by Lawrenceville Press, Inc. and is in no way connected with Borland, Inc. or the Microsoft Corporation. Borland screen captures are copyrighted by and reprinted with permission of Borland International, Inc., 1995. All rights reserved. Microsoft is a registered trademark of the Microsoft Corporation. Screen shots reprinted by permission from Microsoft Corporation.
Preface
e have strived to make this the clearest, most comprehensible C++ text available. Our primary objective in this text is to present material in clear language with easy to follow examples. To meet this objective, we and our reviewers have thoroughly classroom tested the text. We believe that students must be instructed in what constitutes good programming style so that their programs are easy to understand, modify, and debug. Good programming techniques are presented throughout the text. As programming teachers, we have reviewed most of the currently available C++ texts and have found them too often lacking the clarity required to explain difficult concepts. Also, we have discovered that the teacher support material provided with these texts is both limited and inadequate. This text and its comprehensive Teachers Resource Package are our answer to the problem. It is our belief that learning to program offers the student an invaluable opportunity to develop problem-solving skills. The process of defining a problem, breaking it down into a series of smaller problems and finally writing a computer program to solve it is an exercise in learning to think logically. In addition, the student is made aware of the capabilities and limitations of the computer and soon realizes that the programmerthe human elementis more important than the machine. A Guide to Programming in C++ is written for a one or two-term course. No previous programming experience is required or assumed. It is the goal of this text to provide the best possible introduction for students learning C++, whether they will continue on to more advanced computer science courses or end their computer education with this introductory course.
Topic Organization
Chapter One presents a brief history of computing and introduces the student to computer and programming terminology. In Chapter Two students learn what an object-oriented language is and are introduced to C++ programming structure. From the beginning the importance of employing good programming style is emphasized. Chapter Three presents variable assignment, data types, and string types. The first Case Study is presented where students are taught the process of specification, design, coding, and debugging and testing. Chapter Four introduces the if statement, the looping statements do-while and for, and Boolean variables. The Case Study that ends the chapter produces a guessing game program.
Preface
Pref 1
The emphasis of Chapter Five is on the user-defined function. Concepts presented include using default parameters, passing values, and using pre and post conditions. Students are shown how to build a library and how to use top-down design in constructing large programs. In the Case Study a program to play a game of 21 is created. Chapter Six presents classes and objects including the concept of instantiation and member functions. Students are taught how to solve the towers of Hanoi puzzle. In the Case Study, data storing a college database is displayed. Mathematical functions, rounding values, recursion, and enumerated types are discussed in Chapter Seven. In the Case Study a program is written to perform numerical integration for several mathematical functions. Using arrays including storing values, searching, and manipulating a string object is explained in Chapter Eight. Both two and three dimensional arrays are presented. A vote analysis program is written in the Case Study. Chapter Nine explains how a stream processes characters. The fstream library is used. Students are taught how to read numeric and character data and how to pass and return stream objects as parameters. Random access files are also presented. Chapter Ten explains how to create classes. Topics such as defining member functions, building utility classes, and using special member functions are presented. The fundamental concepts of object-oriented programming and object-oriented design are discussed. The Case Study improves upon the AccountClass developed in the chapter. Chapter Eleven explains event-driven programming. Students create GUI-based programs using libraries included with this text. Sorting a list using a selective sort or a merge sort as well as measuring the efficiency of a sorting algorithm are discussed in Chapter Twelve. Searching a list using a binary search or a depth-first search is also discussed. Chapter Thirteen introduced advanced data structures including stacks, queues, and linked lists. Dynamic memory and binary search trees are also explained.
Pref 2
Many demonstration programs are included, complete with sample runs, so that students are shown both proper programming techniques and the output actually produced by their computer. Each C++ statement is given a clear definition, shown in a single program line and then demonstrated in a program body. Beginning in Chapter Three, most chapters end by stating a problem and then developing the appropriate algorithm. The process of specification, design, coding, and debugging and testing is clearly outlined for producing the problems solution. Numerous reviews are presented throughout each chapter which provide immediate reinforcement to newly learned concepts. Solutions to the reviews are given in the Teachers Resource Package. A summary appears at the end of each chapter. These summaries offer the student a review of the important concepts presented in the chapter. Newly introduced terms are defined at the end of each chapter. A review of new symbols, keywords, and libraries is presented at the chapters end. Each chapter includes a large set of exercises of varying difficulty, making them appropriate for students with a range of abilities. Many of the exercises contain a demonstration run to help make clear what output is expected from the students program. Exercises based on previous work are marked with a symbol. Advanced exercises are indicated as such, and require a carefully thought-out algorithm and stepwise refinement as part of its solution, similar in form to that used in solving the Case Study. Answers to the exercises are included on diskette. Considerable care has been taken to make the many illustrations in this text meaningful so that they serve to increase the students understanding of topics being discussed. In addition to the standard index an index of the major programs in the text is included. Separate appendices for Turbo C++ and Microsoft Visual C++ are included to cover the unique features of each software package.
Reviews
Illustrations
Preface
Pref 3
In addition to the material in the lessons, other features are included for each chapter: Tests - A comprehensive test for each chapter as well as a midterm and final examination. Each test consists of multiple choice questions and problems that are solved on the computer by writing a C++ program. A full set of answers and a grading key are also included. Answers - Complete answers for the reviews and exercises presented in the text. A master diskette, included with the Package contains the following files: Program files - All major programs including all programs in the program index, the Case Studies, and the Lawrenceville Press libraries are included on the diskette. Tests - The tests are also provided in text files so that they can be edited. Answer files - Answers to the reviews, exercises, and tests. Student diskettes containing many of the example programs, Case Studies, and the Lawrenceville Press libraries can be easily made by following the directions included in the Teachers Resource Package. Student diskettes are also available in packs of 10. As an added feature, the Package is contained in a 3-ring binder. This not only enables pages to be removed for duplication, but also allows you to keep your own notes in the Package.
to Programming In C++ (Lawrenceville Press, June 1997) by the College Board, Educational Testing Service, or the AP Computer Science Development Committee.
Acknowledgments
The authors are especially grateful to the following instructors and their students who classroom tested this text as it was being written. Their comments and suggestions have been invaluable: Neil Ascione, Madison, NJ Betty Badgett, Abington, PA Bob Britten, Victoria, BC Canada Fran Bucci, Pennellville, NY Gerald Chung, Sherwood Park, AB Canada David Coad, Campbell River, BC Canada Judith Conway, Bear, DE M.G. Corcoran, Suffield, CT Mike Dubin, Euclid, OH Gary Farbman, Pine Bush, NY Jim Fraser, Hebron, NE William Freitas, Claremont, CA Kyle Gillett, Denver, CO Bev Hall, Farmington, CT Robert Hare, Ardmore, OK Edwin Hensley, Round Rock, TX Nan Hert, Boca Raton, FL Nancy Hudanich, Cape May, NJ John Junell, Sequim, WA Roger Kiel, Annandale, NJ Deborah Klipp, Linwodd, NJ Helen Koch, Calgary, AB Canada Kathleen Larson, Kingston, NY Carol Martin, Marietta, GA Sue Michaels, New Milford, NJ Dan Minsart, Chico, CA Meezie Pierce, West Palm Beach, FL Dennis Pieretti, Toms River, NJ Joel Tomski, Des Plaines, IL Evelyn Torres-Rangel, San Gabriel, CA Conrad Trapp, New Ulm, MN Joel Wagnor, Englewood, NJ John Wieja, Wassenaar, Netherlands A special thanks is due Helen Koch, Calgary, AB Canada. She has provided many helpful comments and suggestions from her review of the text. We also wish to thank her students. We thank Courier Book Companies, Inc. who supervised the printing of this text. The success of this and all of our texts is due to the efforts of Heidi Crane, Vice President of Marketing at Lawrenceville Press. Joseph Dupree and Robin Van Ness run our Customer Relations Department and handle
Preface
Pref 5
the many thousands of orders we receive in a friendly and efficient manner. Rich Guarascio and Michael Porter are responsible for the excellent service Lawrenceville Press offers in shipping orders. Vickie Grassman, a member of the Lawrenceville Press staff, edited Chapters One and Eleven, authored both appendices, and reviewed much of the text. Marie Gann, a student at Florida Atlantic University, reviewed the text and tested much of the code. Jeff Dytko, a student at the University of Dayton, is responsible for the table of contents and comprehensive index. We appreciate their efficiency and thoroughness. The graphics in this text were produced by Elaine Malfas, director of computer graphics at Lawrenceville Press, and John Gandour. Elaine also produced the cover. Her artistic ability and professionalism are greatly appreciated. A note of appreciation is due our colleague Nanette Hert. She helped test this text in her class and has offered valuable suggestions on ways in which it could be improved. Finally, we would like to thank our students, for whom and with whom this text was written. Their candid evaluation of each lesson and their refusal to accept anything less than perfect clarity in explanation have been the driving forces behind the creation of A Guide to Programming in C++. Mr. Corica wishes to express his appreciation for the support and sacrifices made by his family, Maryanne, Matthew, and Daniel during the writing of this text. He also promises to return the dining room to its originally intended use.
Pref 6
Table of Contents
Chapter One - An Introduction to Computers
1.1 What is a Computer? ...................................................................................... 1-1 The History of Computers 1.2 Ancient Counting Machines .......................................................................... 1-2 1.3 Arabic Numerals ............................................................................................. 1-2 1.4 The Pascaline .................................................................................................... 1-3 1.5 The Stepped Reckoner .................................................................................... 1-3 1.6 The Punched Card .......................................................................................... 1-4 1.7 Babbages Difference and Analytical Engines ............................................ 1-4 1.8 The Electronic Tabulating Machine .............................................................. 1-5 1.9 The Mark I ........................................................................................................ 1-6 1.10 ENIAC: The First Electronic Computer ....................................................... 1-7 1.11 The Stored Program Computer .................................................................... 1-8 1.12 The Transistor .................................................................................................. 1-9 1.13 Integrated Circuits .......................................................................................... 1-9 1.14 Mainframes .................................................................................................... 1-10 The Modern Computer 1.15 The Microprocessor and the Microcomputer ........................................... 1-11 1.16 The Personal Computer ............................................................................... 1-11 1.17 Computer Architecture ................................................................................ 1-12 1.18 Auxiliary Memory ........................................................................................ 1-14 1.19 Number Systems ........................................................................................... 1-15 1.20 Storing Data in Memory .............................................................................. 1-16 1.21 Operating Systems ........................................................................................ 1-17 1.22 Programming Languages ............................................................................ 1-18 Computer Issues 1.23 The Ethical Responsibilities of the Programmer ...................................... 1-19 1.24 The Social and Ethical Consequences of Computers .............................. 1-20 1.25 The Right to Privacy ..................................................................................... 1-21 1.26 Protecting Computer Software and Data .................................................. 1-22 1.27 Computer Organizations ............................................................................. 1-23 Chapter Summary ......................................................................................... 1-23 Vocabulary ...................................................................................................... 1-24
Table of Contents
T1
The bool Library ............................................................................................ 4-18 The break Statement ..................................................................................... 4-19 Generating Random Numbers .................................................................... 4-19 The conio Library .......................................................................................... 4-20 Case Study ...................................................................................................... 4-22 Chapter Summary ......................................................................................... 4-24 Vocabulary ...................................................................................................... 4-26 C++ .................................................................................................................. 4-27 Exercises .......................................................................................................... 4-28
Table of Contents
T3
Table of Contents
T5
13.11 Binary Search Trees ..................................................................................... 13-16 13.12 Implementing Binary Search Trees .......................................................... 13-17 13.13 Beyond this Book ........................................................................................ 13-21 Chapter Summary ....................................................................................... 13-21 Vocabulary .................................................................................................... 13-22 C++ ................................................................................................................ 13-23 Exercises ........................................................................................................ 13-24
Table of Contents
T7
1
Objectives
After completing this chapter you will be able to: 1. Discuss the history of computers. 2. Understand how the microcomputer works. 3. Understand the binary number system. 4. Understand how data is stored in memory. 5. Understand the ethical responsibilities of the programmer.
1
I
n this chapter you will learn about computers, their history, and how they process and store data. Important issues relating to computers is also discussed. There are three reasons for learning how to use a computer. The first and most important is to develop problem-solving skills. This is done by learning how to analyze a problem carefully, develop a step-by-step solution, and then use the computer as a tool to produce a solution. A second reason for learning about computers is to become acquainted with their capabilities and limitations. Because you are a part of a computerized society, learning to use a computer is probably the best way to become familiar with one. Finally, using a computer can be fun. The intellectual challenge of controlling the operations of a computer is not only rewarding but also an invaluable skill. The techniques learned in this class can be used both at home and on the job.
An Introduction to Computers
11
12
The Pascaline was a mechanical calculating device invented by Blaise Pascal in 1642
The Pascaline he invented was a complicated set of gears which could only be used to perform addition and not for multiplication or division. Unfortunately, due to manufacturing problems, Pascal never got the device to work properly.
The Stepped Reckoner was another early attempt at creating a mechanical calculating device
An Introduction to Computers
13
Jacquards loom was the first device to make use of punched cards to store information
The weaving industry would seem to have little in common with the computer industry, but the idea that information could be stored by punching holes on a card was to be of great use in the later development of the computer.
14
Joseph Jacquard. During processing, the Analytical Engine was to store information in a memory unit that would allow it to make decisions and then carry out instructions based on those decisions. For example, for comparing two numbers it could be programmed to determine which was larger and then follow different sets of instructions. The Analytical Engine was no more successful than its predecessors, but its design was to serve as a model for the modern computer.
Babbages Analytical Engine was a calculating machine that used punched cards to store information
Babbages chief collaborator on the Analytical Engine was Ada, Countess of Lovelace, the daughter of Lord Byron. Interested in mathematics, Lady Lovelace was a sponsor of the Engine and one of the first people to realize its power and significance. She also tested the device and wrote of its achievements in order to gain support for it. Because of her involvement she is often called the first programmer. Babbage had hoped that the Analytical Engine would be able to think. Lady Lovelace, however, said that the Engine could never originate anything, meaning that she did not believe that a machine, no matter how powerful, could think. To this day her statement about computing machines remains true.
An Introduction to Computers
15
piece of information (male, female, age, etc.). The cards were then inserted into the machine and metal pins used to open and close electrical circuits. If a circuit was closed, a counter was increased by one.
Herman Holleriths tabulating machine, invented for the Census of 1880, used electricity instead of gears to perform calculations
Holleriths machine was immensely successful. The general count of the population, then 63 million, took only six weeks to calculate, while full statistical analysis took seven years. This may not sound like much of an improvement over the nine years of the previous census, but Holleriths machine enabled the Census Bureau to make a far more detailed and useful study of the population than had previously been possible. Based on the success of his invention, Hollerith and some friends formed a company that sold his invention all over the world. The company eventually became known as International Business Machines (IBM).
16
It also had over 750,000 parts, many of them moving mechanical parts which made the Mark I not only huge but unreliable.
Because it could make decisions, ENIAC was the first true computer
ENIAC had two major weaknesses. First, it was difficult to change its instructions to have the computer solve different problems. It had originally been designed to compute artillery trajectory tables, but when it needed to work on another problem it could take up to three days of wire
An Introduction to Computers
17
pulling, replugging, and switch-flipping to change instructions. Second, the ENIAC was unreliable because the tubes it contained were constantly burning out. Today, much of the credit for the original design of the electronic computer is given to John Atanasoff, a math and physics professor at Iowa State University. Between 1939 and 1942, Atanasoff, working with graduate student Clifford Berry, developed a working digital computer on the campus at Iowa State. Unfortunately, their patent application was not handled properly, and it was not until almost 50 years later that Atanasoff received full credit for his invention, the Atanasoff Berry Computer (ABC). In 1990, he was awarded the Presidential Medal of Technology for his pioneering work, and some of his early devices were exhibited at the Smithsonian.
The next computer to employ von Neumanns concepts was the UNIVersal Automatic Computer, or UNIVAC, built by Mauchly and Eckert. The first one was sold to the U.S. Census Bureau in 1951. Computers continued to use many vacuum tubes which made them large and expensive. UNIVAC weighed 35 tons. These computers were so expensive to purchase and run that only the largest corporations and the U.S. government could afford them. Their ability to perform up to 1,000 calculations per second, however, made them popular.
18
One transistor replaced many tubes, making computers smaller, less expensive, and more reliable
These new computers also saw a change in the way data was stored. Punched cards were replaced by magnetic tape and high speed reel-toreel tape machines. Using magnetic tape gave computers the ability to read (access) and write (store) data quickly and reliably.
An Introduction to Computers
19
1
A typical integrated circuit chip (approximately half an inch wide and 1.5 inches long)
One of the most important benefits of using integrated circuits is to decrease the cost and size of computers. The IBM System 360 was one of the first computers to use integrated circuits and was so popular with businesses that IBM had difficulty keeping up with the demand. Computers had come down in size and price to such a point that smaller organizations such as universities and hospitals could now afford them.
1.14 Mainframes
Mainframe computers are large computer systems that cost many hundreds of thousands, if not millions, of dollars. Mainframes can carry out many different tasks at the same time. They are used by large corporations, banks, government agencies, and universities. Mainframes can calculate a large payroll, keep the records for a bank, handle the reservations for an airline, or store student information for a universitytasks that require the storage and processing of huge amounts of information.
1 10
An Introduction to Computers
1 11
A microcomputer combines a keyboard, monitor, disk drives, and a mouse in a desktop-sized package
The base unit of a microcomputer contains the CPU and data storage devices such as a diskette drive, a CD-ROM drive, and a hard disk which is a disk drive completely contained inside the base unit. The keyboard, mouse, and disk drives are used to input data, and the monitor is used to view input and output. A microcomputer also has software which are programs that tell a computer what to do. Many businesses and schools have networked their microcomputers. In a network, microcomputers are connected so that data can be transmitted between them. Because a network can include a large number of computers, it can perform many of the functions of a mainframe. As network technology progresses, the distinction between a mainframe computer and networked microcomputers is rapidly becoming blurred.
1 12
1
memory
This diagram illustrates the direction in which data flows between a computers subsystems:
There are different types of memory in a computer system. Read Only Memory, or ROM, contains the most basic operating instructions for the computer. It is a permanent part of the computer and cannot be changed. The instructions in ROM enable the computer to complete simple jobs such as placing a character on the screen or checking the keyboard to see if any keys have been pressed. Three additional memory components are Random Access Memory (RAM), registers, and auxiliary memory. RAM, also called main memory, is where data and instructions are stored temporarily. Data stored in RAM can be changed or erased. When the computer is first turned on, this part of memory is empty and, when turned off, any data it stores is lost. Registers are temporary memory locations within the CPU that are involved in the execution of every instruction. The information stored in registers can be retrieved at very high speeds. Because RAM and register storage is temporary, computers use auxiliary memory storage for long term storage of programs and data. Auxiliary memory devices are discussed later. The computers memory components work together by first accessing a program and necessary data stored in the auxiliary memory and then copying it into RAM. Data is copied into a register when instructions are performed. The results are copied back to RAM and eventually stored for later use in auxiliary memory. During this process, data can be received from input devices and results sent to output devices.
CPU
The Central Processing Unit, or CPU directs all the activities of the computer, and all information flows through the CPU. Because one of the tasks of the CPU is to control the order in which tasks are completed, it is often referred to as the brain of the computer. However, this comparison with the human brain has an important flaw. The CPU only executes tasks according to the instructions it has been given; it cannot think for itself. It can only follow instructions that it gets from ROM or from a program in RAM.
A CPU chip many times more powerful than the Mark I measures about 2 inches by 2 inches An Introduction to Computers
1 13
ALU
The Arithmetic Logic Unit, or ALU, is the part of the CPU where the intelligence of the computer is located. It can perform only two operations: adding numbers and comparing numbers. How does the computer subtract, multiply, or divide numbers if the ALU can only add and compare numbers? The ALU does this by turning problems like multiplication and division into addition problems. This would seem to be a very inefficient way of doing things, but it works because the ALU is so fast. For example, to solve the problem 5 ! 2, the computer adds five twos, 2 + 2 + 2 + 2 + 2, to calculate the answer, 10. The ALU is so fast that the time needed to carry out a single addition of this type is measured in nanoseconds (billionths of a second). The other job of the ALU is to compare numbers and then determine whether a number is greater than, less than, or equal to another number. This ability is the basis of the computers decision-making power.
diskette
CD-ROM
hard disk
1 14
base 10
Our most familiar number system is the decimal, or base 10, system. It uses ten digits: 0 through 9. Each place represents a power of ten, with the first place to the left of the decimal point representing 100, the next place representing 101, the next 102, and so on (remember that any number raised to the zero power is 1). In the decimal number 485, the 4 represents 4!102, the 8 represents 8!101 and the 5 represents 5!100. The number 485 represents the sum: 4!100 + 8!10 + 5!1 (400 + 80 + 5) as shown below: Decimal Number 485 Base 10 Equivalent 4!102 + 8!101 + 5!100 = 400 + 80 + 5
base 2
The binary, or base 2, system works identically except that each place represents a power of two instead of a power of ten. For example, the binary number 101 represents the sum 1!22 + 0!21 + 1!20 or 5 in base ten. Some decimal numbers and their binary equivalents are shown below: Decimal Number 0 1 2 3 4 Binary Number 00 01 10 11 100 Base 2 Equivalent = 0!21 + 0!20 = 0!21 + 1!20 = 1!21 + 0!20 = 1!21 + 1!20 = 1!22 + 0!21 + 0!20 = 0!2 + 0!1 = 0!2 + 1!1 = 1!2 + 0!1 = 1!2 + 1!1 = 1!4 + 0!2 + 0!1 =0+0 =0+1 =2+0 =2+1 =4+0+0
base 16
The hexadecimal, or base 16, system is based on 16 digits: 0 through 9, and the letters A through F representing 10 through 15 respectively. Each place represents a power of sixteen. For example, the hexadecimal number 1F represents the sum 1!161 + 15!160. Some decimal numbers and their hexadecimal equivalents are shown below: Decimal Number 0 10 15 20 25 30 Hexadecimal Number 0 A F 14 19 1E Base 16 Equivalent = 0!160 = 10!160 = 15!160 = 1!161 + 4!160 = 1!161 + 9!160 = 1!161 + 14!160 = 0!1 = 10!1 = 15!1 = 1!16 + 4!1 = 1!16 + 9!1 = 1!16 + 14!1 =0 = 10 = 15 = 16 + 4 = 16 + 9 = 16 + 14
For clarity, a non-base 10 number should have the base subscripted after the number. For example, to tell the difference between 100 in base 10 and 100 in base 2 (representing 4), the base 2 number should be written as 1002.
An Introduction to Computers
1 15
ASCII code
The computer uses binary digits to express not only numbers, but all information, including letters of the alphabet. Because of this, a special code had to be established to translate numbers, letters and characters into binary digits. This code has been standardized for computers as the American Standard Code for Information Interchange, or ASCII. In this code, each letter of the alphabet, both uppercase and lowercase, and each symbol, digit, and special control function used by the computer is represented by a number. The name JIM, for example, is represented by the ASCII numbers 74, 73, 77. In turn, these numbers are then stored by the computer in binary code: Letter J I M ASCII 74 73 77 Binary Code 01001010 01001001 01001101
Each ASCII code is translated into one byte (8-bits) and stored in memory. Note how eight 0s and 1s are used to represent each letter in JIM in binary code. ASCII codes 0 through 31 are reserved for use by the computer. Code 32 is the space character. Codes 33 through 126 are symbols, numbers, and letters. Codes above 126 are either unused, or may differ from system to system.
memory address
Data stored in memory is referred to by an address. An address is a unique binary representation of its location in memory. Therefore, data can be stored, accessed, and retrieved from memory by its address. For data to be addressable in memory, it must usually be at least one byte. For example, to store JIM in memory each character can be stored in binary code in a separate location in memory designated by its address:
1 16
1
integers real numbers
Because JIM is a character string, it will probably be stored in adjacent addresses. Bits grouped in units of 8 to 64 bits or more are called words. Data stored in a word is also located by an address. The size of a word depends on the computer system. The binary representation of an integer number is usually stored in one word of memory. Because an integer is stored in one word, the size of the word determines the range of integers that can be stored. An overflow error occurs when the number of bits that represent the integer is greater than the size of the word. Real numbers, also called floating point numbers, are numbers that contain decimal points. The binary representation of a real number is also stored in one word of memory. The binary number 111.10 is equivalent to the real decimal number 7.5 and is stored in memory as the binary number 0.11110!23. In this form, the bits that represent the mantissa (fractional part) are stored in one section of a word and the exponent, in this example 3 (112), is stored in another section of the word:
roundoff error
The overflow problem discussed for integers can also occur in real numbers if the part of the word storing the exponent is not large enough. A roundoff error occurs when there are not enough bits to hold the mantissa.
An Introduction to Computers
1 17
1 18
Computer Issues
Although computers cannot think, they do have some advantages over the human brain. For example, suppose you were given a list of ten numbers (input) and were asked to first, remember them (memory), second, calculate their average (process), and third, write down the average (output). In so doing, you would perform the same four tasks as a computer. Now suppose you were given 100 or 1,000 numbers and asked to calculate the average. Chances are you would get confused and tired performing all the calculations. The computer would have none of these problems. It would accurately remember all of the data and be able to quickly calculate the answers. The computer, therefore, has three important advantages over the human brain: 1. Reliable memory, with the ability to store and recall large amounts of data over long periods of time. 2. Speed, which enables it to process data quickly. 3. The ability to work 24 hours a day without rest. Remember that as reliable and fast as a computer is, it is only as smart as the instructions it is given by a program.
An Introduction to Computers
1 19
would be capable of doing the job as well as a computer. Computers are also routinely used to monitor seriously ill patients. Since computers are able to work 24 hours a day without becoming distracted or falling asleep, they probably perform such tasks better than most humans.
An Introduction to Computers
1 21
Contaminated disks are one way that viruses are spread from computer to computer
1 22
Most people are becoming aware that the willful destruction of computer data is no different than any other vandalization of property. Since the damage is done electronically the result is often not as obvious as destroying physical property, but the consequences are much the same. It is estimated that computer crimes cost the nation billions of dollars each year.
Chapter Summary
Humans have searched for a machine to calculate and record data for thousands of years. The earliest of these devices were mechanical, requiring gears, wheels and levers, and were often unreliable. The advent of electricity brought about machines which used vacuum tubes, and were capable of performing thousands of calculations a minute. The unreliability of the vacuum tube lead to the development of the transistor and integrated circuit. Von Neumanns concept of the central processing unit allowed computers to solve many different problems by simply typing new instructions at a keyboard. Computers became much smaller when vacuum tubes were replaced with transistors in the 1960s. A further reduction in size and cost came with the development of integrated circuits, also called chips. Mainframes are large, expensive computers that can carry out many tasks at the same time. However, with the invention of the microprocessor, todays microcomputers rival the performance of older mainframes. All computers have the same architecture: (1) input devices (keyboard, mouse) to accept data from the user, (2) memory for storing commands and data, (3) a central processing unit for controlling the operations of the computer, and (4) output devices (monitor, printer) for the user to view the processed information. In general, a computer is a machine which accepts information, processes it according to some specific instructions in the form of software, and then returns new information as output. Todays microcomputer makes use of a CPU on a chip, the microprocessor, which controls the actions of the computer. A computer has different types of memory that include ROM, RAM, registers, and auxiliary memory. ROM contains the most basic operating instructions for the computer and are permanent. RAM and resigters are both temporary memory. The CPU contains a special device called the Arithmetic Logic Unit (ALU) which performs any math or comparison operations. Auxiliary memory devices such as diskettes, CD-ROMs, and hard disks are used for long term storage of data and programs.
An Introduction to Computers
1 23
Because the electrical circuits on a chip have one of two states, OFF or ON, the binary number system is used to represent the two state: 0 for OFF and 1 for ON. In the base 2 number system, each place represents a power of two. The base 16 number system uses 16 digits with each place representing a power of 16. The computer uses binary digits grouped into bytes to express all information. The ASCII code translates numbers and letters into a one byte binary code. The location of data stored in memory is referred to by an address. Integers and real numbers are stored in one word in memory. Because the number of bits in a word is limited, an overflow error occurs when the number of bits that represent an integer is greater than the size of the word. A roundoff error occurs when the bits that represent the mantissa of a real number is greater than the section of the word that stores the mantissa. A computer needs an operating system such as Windows 95 to run. An operating system is automatically booted when the computer is turned on. High-level programming languages were developed so programmers could write English-like instructions that the computer could translate. The C language was designed by Bell Laboratories in 1978 and was extended into C++ in the early 1980s. A source program is compiled into an object program. As computers are increasingly used to make decisions in situations which can impact human life, it becomes the responsibility of programmers to do their best to insure the reliability of the software they have developed. We must continue to be cautious not to replace human beings with computers in areas where judgement is crucial. Historians refer to the present time as the information age due to the computers ability to store and manipulate large amounts of data. As the use of computers increases they will profoundly affect society. Therefore, it is important to analyze the social and ethical implications of computers. A problem created by computers is their potential for invading our right to privacy. Laws have been passed to protect us from the misuse of data stored in computers. Because computer software is easy to copy, illegal copies are often made, denying software manufacturers of rightful compensation. Another problem has been the willful destruction of computer files by erasing data or planting a virus into programs that spread when programs are copied. The ACM and ANSI are computer organizations that help promote standards and guidelines relating to issues in the computer industry.
Vocabulary
Abacus Ancient counting device which uses beads on a frame. Address Unique binary representation of the location of data in memory. ALU Arithmetic Logic Unit, the part of the CPU that handles math operations. 1 24
Applications software Commercially produced programs written to perform specific tasks such as word processing. ASCII American Standard Code for Information Interchange, the code used for representing characters in the computer. Auxiliary memory Devices that store data so that it can be reused. Binary system Base 2 number system used by computers. Uses only two digits. Bit Binary Digit, a single 0 or 1 in a binary number. Byte A group of 8 bits. Chips Tiny integrated circuits etched into blocks of silicon. CPU Central Processing Unit, the device which electronically controls the functions of the computer. COBOL A high-level computer language. Compiling Translating a source program into machine language. Computer An electronic machine that accepts data, processes it according to specific instructions, and provides the results as new information. Data Information either entered into or produced by the computer. Debug To remove errors from a computer program. Decimal system Base 10 number system used by computers. Uses only ten digits. Document Also called a file. File Collection of data stored on a disk in a form the computer can read. Floating point numbers Numbers that contain decimal points. FORTRAN A high-level computer language. GUI (Graphical User Interface) An operating system that uses pictures to communicate. Hardware Physical devices which make up the computer and its peripherals. Hexadecimal system Number system used by computers. Uses sixteen digits (base 16). Input Data used by the computer. K, kilobyte Measurement of computer memory capacity. 1024 bytes. Keyboard Device resembling a typewriter used for inputting data into a computer. Machine language Computer program written in binary code, just 0s and 1s. Mantissa The fractional part of a real or floating point number. MB, megabyte bytes. Measurement of computer memory capacity. 1,048,576
An Introduction to Computers
1 25
Memory Electronic storage used by the computer. Memory address Binary representation of the location of data in memory. Microprocessor CPU on a single chip. Monitor Television-like device used to display computer output. Multitasking More than one application running at a time. Nanosecond Billionth of a second. Object program The machine language created by compiling source code. Operating system Software that allows the user to communicate with the computer. Output Data produced by a computer program. Pascal A high-level computer language. Program Series of instructions written in a special language directing the computer to perform certain tasks. PC Personal Computer, a small computer employing a microprocessor. RAM Random Access Memory. Memory that temporarily stores data and instructions. Real numbers Numbers that contain decimal points (also called floating point numbers). ROM Read Only Memory. Memory that permanently stores data and instructions, and contains the most basic operating instructions for the computer. Roundoff error Occurs when there are not enough bits to hold the mantissa of a number. Software Computer programs. Source code A program written in a high-level language. Window The area on the screen that contains an open program or file. Words Bits grouped in units of 8 to 64 bits.
1 26
2
Objectives
After completing this chapter you will be able to: 1. Understand what an object-oriented language is. 2. Read a short program containing the cout and return statements. 3. Understand a C++ program structure including comments and main(). 4. Run a program and understand compiling and linking. 5. Understand syntax errors and warnings. 6. Use cout to display a string. 7. Display special characters. 8. Understand good programming style guidelines.
2
ur lives are increasingly interwoven with computers. Computers run our televisions, microwave ovens, and cars; they deliver our electronic mail; they bring us entertainment; they are revolutionizing our society. All of these applications of computing, and more, require programs. In this text you will learn how to write programs using the object-oriented language called C++.
Introducing C++
21
cout
In C++ input/output devices are called streams. cout (pronounced see out) is the console output stream, and the send to operator << (also called the insertion operator) is used to send data into the stream. In the first statement, the words following the << operator are enclosed in quotation marks to form a string. When executed, this statement sends the string Hello, world! to the console output device (the computer screen.) It is important to know that all C++ symbols are case-sensitive, meaning that cout is correct but cOut, COUT, and Cout, are not. This is a common source of confusion in C++ programming.
return
n (0) which causes the program to terminate, eturn The next statement is retur and the value 0 to be sent back to the computer system. The value 0 indicates to the system that the program terminated without error.
22
The two program statements end with a semicolon ( ; ). Semicolons are required in C++ to indicate the end of a statement.
comments
Comments are used to explain and clarify the contents of a program for a human reader. The computer ignores them. The symbols /* and */ indicate the beginning and end of a comment, respectively. These symbols are best used with multi-line comments. Comments can also be indicated by the symbols //. All characters on a line after the // symbols are considered to be a comment and are ignored. For example:
return return(0); // second statement
//
For style purposes, it is best to use the // symbols for a comment that follows a statement. Following the opening comment is the line
#include <iostream.h>
library
which tells the compiler that the iostream library is needed. A library is a collection of program code that can be included in a program to perform a variety of tasks. The iostream library is used to perform input/output (I/O) stream tasks. For example, cout is in the iostream library. Nearly all of the programs in this text require this library, and therefore include this line. The next line
int main()
main()
is the header of the main() function. A function is a set of statements that accomplish a task. A function header includes the return type of the function and the function name. As indicated in the main() header, main() n (0) as explained in Section 2.3. eturn returns an integer (int) through retur The body of the program is enclosed in curly braces; the { and } symbols indicate the beginning and the end of the program statements.
{}
Introducing C++
23
compiling
A compiler is a program that translates C++ code into machine language. Machine language is a low-level language consisting of only 1s and 0s, and is the native language of a computer. A C++ program typed by a programmer is called the source code; and the compiled, resulting sequence created by a compiler is called the object code. During compilation, the compiler checks the syntax of a program and reports errors. Before the object code can be executed, it must be linked to other pieces of code that interact with the computer system. The object code must also be linked to any libraries (e.g., iostream.h) used by the program. The compiled and linked program is called an executable file because it is ready to be run on the computer. Finally, the program in linked object form is executed by the system. When a program is run, its output is displayed in a window.
linking
running
warning message
In some cases, the compiler generates a warning message rather than an error. A warning message indicates that a statement in the program is legal, but suspicious. If a warning is generated, it is important to determine the source and fix the problem before running the program. Experienced programmers may choose to ignore certain warnings, but for beginning programmers it is important to consider warnings no different than errors.
24
Review 1
Enter the Hello world program, and run it.
Review 2
Write a program that displays your name. Use the Hello world program as a guide.
Review 3
Open the Hello world program. Type various errors into the program and create a chart indicating the first error message given for each error. For example: Error Misspelling iostream.h Sample Error message
"Unable to open include file IOSTREEM.H"
When run, the program produces the output: -Calculate the area of a circleRadius = 10 Area = 314 The first cout statement
cout << "-Calculate the area of a circle-" << endl;
performs two actions. The first is to display the string -Calculate the area of a circle- on the screen, and the second is to move output to the next line (i.e., it ends the line). If output is not moved to the next line, the next string sent to the screen will be displayed after the first so that both messages are on a single line. Note that while strings are enclosed in quotation marks, endl is not. If it were, it would be interpreted as a string, and displayed on the screen.
Introducing C++
25
endl
is included. This statement does not display any characters, but it does move output to the next line.
displaying numbers
meric values should not be enclosed in quotation marks. Each item requires the << operator to its left. After the last item, a semicolon indicates the end of the statement.
calculations
programming style
a calculation is performed and the result sent to cout so that it is displayed on the screen. Note that the asterisk, *, is used to indicate multiplication. The symbols +, -, and / are used to indicate addition, subtraction, and division, respectively. The use of parentheses when performing a calculation in a cout statement is good programming style.
Review 4
Write a C++ statement that can be used in the Circle Area program to display the circumference ("#r) of the circle.
Review 5
Modify Review 2 to display your name and address separated by blank lines.
which displays: You say "Good-bye, " and I say "Hello" The double quotation marks that follow the backslashes are displayed rather than interpreted as ending the string. The backslash is often called an escape character and the combination of symbols an escape sequence. The idea is that it escapes from the normal interpretation of characters in a string.
escape sequence
26
Another special character is the end of line character. This is indicated by \n and can replace the use of endl. For example
cout << "This falls on a single line.\n"; cout << "This goes on the next line.";
displays: This falls on a single line. This goes on the next line. Other escape sequences include: Symbol
\n \" \' \a \\ \t
Effect Go to next line Double-quotation mark Single-quotation mark Alert (make a beep sound) Single backslash Tab (move eight spaces)
" *\n"; " |\\\n"; " ___|_\\_\n"; "~~~~~~~\\_____/~~~~~~~\n"; "~~~~~~~~~~~~~~~~~~~~~\n"; "\a\tThe \"Yankee Clipper\"";
When run, the program produces the output: * |\ ___|_\_ ~~~~~~~\_____/~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ The "Yankee Clipper"
Review 6
Write a program that displays a house. Do not use endl. When run, the program output should be similar to: /\ / \ / \ | -- | |_||_|
Introducing C++
27
Review 7
Write a program that displays the following text: "I think, therefore I am." Rene Descartes
will work exactly the same as the Circle Area program originally presented. The difference is that the human reader has more difficulty understanding, modifying, and debugging code that looks like this. The quality of a programmers work depends as much upon how the code is designed as upon the output generated. Therefore, throughout the text, good programming style will be discussed. In general, some good programming style guidelines are: Use one statement per line. Use an equal number of spaces to indent each line of the body of a program. Include a comment describing each program and giving the authors name and date. The description should include the purpose of the program and any key features used. Use /* and */ to enclose these comments. Blank lines should be used to set off sections of code. Place comments within the body of the code to clarify the code for a reader. However, these comments should not repeat what is obvious from the code. Generally it is best to use // for these comments. 28
Chapter Summary
Programs can be written in different languages, such as Pascal or BASIC. C++ is a popular programming language used for object-oriented programming. Object-oriented programs are programs constructed using classes. A class is code in a file separate from the main program. There are many benefits of learning how to program. It gives you a sense of what computers can and cannot do. It also develops problemsolving skills, and helps you appreciate the task of software development. Finally, learning to program is fun. Every C++ program has a certain structure. Comments are included to help the human reader understand the program but are ignored by the compiler. Multi-line comments are set off by the symbols /* and */. Single line comments begin with the // symbol. Any characters on a line after the // symbol are considered comments. The iostream library is included in a program to perform input/output stream tasks and should be included in nearly all programs. Every program contains a main() function which is a set of statements that accomplish a task. A statement is a line of code in the program body that tells the computer what to do. Each statement is terminated by a semicolon. One or more statements enclosed in the { and } symbols indicate the body of the program. All C++ symbols are case-sensitive. Input/output devices are called streams. cout is the console output stream used in conjunction with the << operator to send information to the screen. cout can output strings and the results of calculations. It is good programming style to enclose any calculations in a cout statement in parentheses.
endl is used to move output onto the next line. Escape sequences are used to output special characters.
A compiler converts C++ code to machine language called object code. Object code is linked with other code to make an executable program that can be run on the computer. A compiler cannot compile a program that contains errors. During compilation, the compiler detects syntax errors, statements that violate C++ rules. In some cases, the compiler generates a warning message which indicates that a statement is legal, but suspicious. All errors and warnings should be fixed before running the program. C++ is a freeform language with statements separated by semicolons. Code should, however, be laid out so as to make it easy to understand by a human reader.
Introducing C++
29
Vocabulary
Body The part of a program that contains the statement(s) enclosed in the { and } symbols. C++ Object-oriented programming language. Comment Information placed in a program to explain and clarify the contents of a program for a human reader. Comments are enclosed by /* and */ or follow // and are ignored by the compiler. Compiler A program that converts source code, usually written in a language like C++, into object code, a machine language version. End-of-line A special escape sequence, \n, that when placed inside a string causes the compiler to end the line of output. Escape character A special character, such as the backslash (\), that is used to escape from the normal interpretation of characters in a string. Escape sequence The combination of an escape character and symbols, such as \n. Executable File The compiled and linked version of a program ready to run on the computer. Free form A programming language, like C++, where spaces and blank lines generally have no effect on the programs operation. Function A set of statements that accomplish a task. Function Header Appears as the first line of a function, and includes the return type and function name. Library A collection of program code that can be used by the program it is included in to perform a variety of tasks. Link To combine several pieces of compiled code into a single compiled program. Machine language The low-level, native language of a computer that consists of only 1s and 0s. Object A separate piece of a program. Object code The machine language code produced by compilation. Object-Oriented A programming language, like C++, in which programs are constructed in separate pieces. Program A sequence of instructions that tells the computer how to accomplish a particular task. Source code The program code written in a language like C++. Statement A line of code in the program body that tells the computer what to do. Stream An input/output device, such as cout. String Characters and/or symbols enclosed in quotation marks.
2 10
2
C++
Syntax error An error caused by a statement in the program that violates the rules of C++. Warning message A message given by the compiler because a statement in the program is legal, but suspicious.
#include Used to link a library into a program. /* */ A pair of symbols used to enclose single and multi-line comments. // Symbols used to indicate that the rest of the current line contains only
a comment.
" " Used to enclose a string. \ Escape character used to indicate a special character in a string. \a Escape sequence indicating a beep sound. \n Escape sequence indicating the end of line character. \" Escape sequence indicating a double-quotation mark. \t Escape sequence indicating a tab character. \' Escape sequence indicating a single-quotation mark. \\ Escape sequence indicating a backslash. ; Symbol used to end a statement. { } Symbols used to indicate the beginning and the end of a set of program statements. cout The console output stream. Use to send program output to the screen. << The send to operator used to send information into a stream. endl Inserted in an output stream (cout) to move output to the next line.
Introducing C++
2 11
Exercises
Exercise 1
There are five errors in the following C++ program. What are they?
/*Circle Area program Calculates the area of a circle using the formula A=pi * r * r A Student, 7/13/97 // #include <iostream.c> int main() { cout << "-Calculate the area of a circle-" << endl cout >> endl; cout << Radius = << 10 << endl; cout << "Area = " << (3.14*10*10) << endl; return return(0); }
Exercise 2
There are five errors in the following C++ program. What are they?
/*Circle Area program Calculates the area of a circle using the formula A=pi * r * r A Student, 7/13/97 */ #include <iostream.h> {/* cout << "-Calculate the area of a circle-" << 'endl"; cout << endl; Cout << "Radius = " << 10 << endl; cout << "Area = " << (3.14*10*10) << endl; return return(0); */}
Exercise 3
Modify the Circle Area program from Section 2.8 to calculate and display the area of a circle with radius 10 with the output formatted so that the radius and area appear on the same line, clearly spaced. The program output should be similar to: The area of a circle of radius 10 is 314
2 12
Exercise 4
Write a program that displays your name, class, and school address. The program output should be similar to:
Exercise 5
Write a program that calculates and displays the area and perimeter of a rectangle with length 5 and width 3.
Exercise 6
Write a program that calculates and displays the number of kilometers per liter a car gets if it travels 712.5 kilometers on a 70.3 liter tank of gas.
Exercise 7
Write a program that calculates and displays the average jump length of a long-jumper whose jumps were 3.3m, 3.5m, 4.0m, and 3.0m.
Exercise 8
This program illustrates how C++ handles calculations. Notice how C++ displays results with decimals only if at least one of the numbers in the calculation contains decimals.
Exercise 9
Write a program that calculates and displays the average class size of a programming course if the classes have 14, 16, 13, and 19 students. Note: In order to display a result that contains decimals, it is necessary for at least one of the numbers in the calculation to contain decimals. Thus, you might divide by 4.0 rather than 4 in your calculation.
Introducing C++
2 13
Exercise 10
On average, the power of available computer technology increases by a factor of four every three years. Suppose that a computer can process one task per second in 1980. Write a program that displays how many tasks per second a computer can process in the next two decades. Have the calculations performed in the program. The program output should look similar to: 1980 1983 1986 1989 1992 1995 1998 2001 1 4 16 64 256 1024 4096 16384
Exercise 11
Write a program that uses cout to display a block of asterisks. The program output should be similar to: ******** * * * * ********
Exercise 12
Write a program that displays a happy face. The program output should be similar to: ***** * * * o * * * - * o *
2 14
Exercise 13
Write a program that displays a grouchy face. The program output should be similar to: ***** * * * * * * * o | + * O * ***** "grouchy" \ / o * * * * *
Exercise 14
The Chemistry department has 4 computers, the Physics department has 8, the English department has 2, and the Math lab has 12. Write a program that produces the following output. Have the computer perform the calculation in the last line. Format the output using the appropriate escape sequences. Chemistry Physics English Math lab Grand Total 4 8 2 12 26
Introducing C++
2 15
2 16
3
Objectives
After completing this chapter you will be able to: 1. Assign values to a variable. 2. Obtain a value from the user with cin. 3. Use named constants. 4. Choose appropriate identifiers. 5. Use data types. 6. Understand promotion, integer division, type casting, modulus division, and operator precedence. 7. Use the String type. 8. Use the ignore() function. 9. Format output using width(), setf(), and precision(). 10. Choose wisely how to define a variable.
3
T
he Circle Area program of Chapter Two showed how a calculation could be performed and its result displayed. This program was limited because it performed the calculation for a specific number, 10, written into the program. To have the program perform the calculation using a different value it would have to be modified by replacing the value 10 with the new value in three places, recompiled, and run again. To remove this limitation, variables are used to represent values within a program.
defines a variable named Radius which stores data of type double. A double is a numeric value possibly containing a decimal portion. Other data types will be described later in this chapter.
assignment
Once defined, a variable must be given a value. One way to do this is through assignment. For example, in the following assignment statement the variable Radius is assigned the value 12.3:
Radius = 12.3;
The equal sign (=) represents assignment, and the effect is to store the value 12.3 in the memory location referred to by the name Radius. The following program demonstrates how a variable can be used:
/*Program to illustrate variables */ #include <iostream.h> int main() { double Radius; Radius = 10; cout << "Radius = " << Radius << endl; cout << endl; Radius = 12.3; cout << "Radius = " << Radius << endl; return return(0); }
31
When run, the program displays: Radius = 10 Radius = 12.3 The programs assignment statements are used to change what is stored in the variable Radius so that different values are displayed by the different cout statements. There can be only one value stored in Radius at any given time. Therefore, when the value 12.3 is assigned to Radius, the value 10 is no longer available. The following illustrates this: First, the variable is defined:
double Radius; ? Radius
In this statement the compiler tells the computer to set aside space in memory that is identified by the variable name Radius. Until the variable is assigned a value, the value associated with Radius is unknown. When the first assignment statement is executed, the value 10 is placed in the memory location identified by the name Radius:
Radius = 10; 10 Radius
The first cout statement displays this value of 10. When the second assignment statement is executed, the value 10 is replaced with the value 12.3:
Radius = 12.3; 12.3 Radius
assignment statement Variable assignment statements must be written so that the identifier (variable name) is on the left side of the equal sign and the value is on the structure right. An expression may also be used on the right side of an assignment statement. For example, in the statement
Area = 3.14*10*10;
the expression on the right is evaluated and the result stored as the value of the variable Area. Two common errors are to reverse this:
3.14*10*10 = Area; // Error!
32
Review 1
What would be the output of the following program?
#include <iostream.h> int main() { double Number; Number = 12; Number = 15; cout << (Number*Number) << endl; return return(0); }
Review 2
Modify the Circle Area program from Chapter Two so that a variable named Radius is defined and assigned the value 10, and this variable is used rather than the number 10 throughout the rest of the program.
causes the program to wait for the user to type a value and press Enter and then assigns that value to the variable Radius. cin is the console input stream, part of the iostream library. The get from operator >> (also called the extraction operator) is used to get data from the input stream and feed it to the variable. A cin statement makes the Circle Area program more useful:
/*Circle Area program */ #include <iostream.h> int main() { cout << "-Calculate the area of a circle-" << endl; cout << endl; double Radius; cout << "Enter radius: "; cin >> Radius; // Get Radius value from user cout << "Radius = " << Radius << endl; cout << "Area = " << (3.14*Radius*Radius) << endl; return return(0); }
33
The program output when the user types 10 is as follows. The user input in the program output has been underlined to distinguish it from the program output: -Calculate the area of a circleEnter radius: 10 Radius = 10 Area = 314 Two points should be made about the modified Circle Area program. First, the variable is declared after the heading, but just before the user is prompted for a value. It is generally considered good programming style to declare variables close to the section of code where they are first used so that the program is easier to understand. Second, the statement
cout << "Enter radius: ";
programming style
does not end with an endl to cause output to move to the next line. As a result, the user can enter the value right next to the prompt.
From this point forward in the execution of the program, the identifier PI represents the value 3.14. When this statement is included in the Circle Area program, the last cout statement can be modified to include the constant:
cout << "Area = " << (PI*Radius*Radius) << endl;
This formula should be easily understandable to any reader who has seen the mathematical version, A = #r2. Representing a value that does not change during program execution as a named constant makes the code easier for a reader to understand. Code that includes named constants is also easier to modify because the value of the constant need only be changed in one place. A common error when defining constants is to leave out the type. When this happens, the constant is made the default type of int. A second error is to include a program statement which tries to change the value of a constant. For example, the following statement generates a compiler error:
const double PI = 3.14; PI = 22/7; // This will generate an error
34
keywords
There are several identifiers that C++ reserves for use as keywords. A keyword has special meaning to the compiler, and therefore cannot be a user-defined variable or constant. For example, double is a keyword. In this text keywords are emphasized by formatting them in a different font, just as the word double is formatted. Refer to Appendix C for a complete list of C++ keywords. As a matter of good programming style, one final rule is that variables and constants should be named so that they are quickly and clearly understandable to the reader. This is important for other readers of your program, for you as you try to get your program working correctly, and for you as you later modify and improve your program.
programming style
Review 3
Write a program that asks the user for the length and width of a rectangle, and then displays the value of the area of the rectangle.
Review 4
Modify the Circle Area program to use a constant for #, ask the user for the radius, and to display the area and circumference (2#r) of the circle.
Review 5
List five legal and five illegal variable names illustrating the rules for identifiers in C++. Indicate why each illegal name is incorrect.
35
double
The double type is used to store positive or negative real numbers. This type is often referred to as floating point, meaning that it can represent values with numbers after the decimal point. When very large or very small numbers are stored and displayed, the computer will use scientific notation. For example
double j; j = 123456789.0; cout << j << endl;
displays the number 123456789 as: 1.23457e+08 which represents the number 1.23457 ! 108. Note that a double value is rounded to six significant figures when displayed. The remaining digits are stored internally, and will be used in calculations.
The int and long types are used to store positive and negative integers. The only difference between int and long is the range of values that may be represented. While for many purposes, int variables are sufficient, it is often necessary to use long variables for values that may exceed 32,767 (the limit for an int). If a value with a decimal portion is assigned to an integer variable, the value is truncated (the decimal portion is not stored). For example
int i; i = 12.9; cout << i << endl;
displays: 12 While int and long variables may seem limited, they are the perfect choice for counting whole number quantities. Many programs throughout this text will use integer variables and constants.
char
The char type stores a single character. Characters include the letters of the alphabet, digits, symbols like $, %, and spaces, and in general any character that can be typed or displayed. For example:
char ch; ch = 'A'; cout << ch << endl;
displays: A A char variable assignment requires using single-quotation marks. In this case, A is assigned to variable ch. If double-quotation marks are used, an error message is generated.
36
It is important to understand that the char value '4' is not the same as the int value 4. For example, trying to do arithmetic with char values in a statement like:
cout << ('4' + '5') << endl;
compiles without error but displays the number 105! This is because the characters are interpreted as binary numbers before being added.
This style of variable definitions can lead to simpler, easier-to-read code. A variable definition can also include assignment. For example:
double x = 6; char ch1 = 'A', ch2 = 'B'; int y = 2*x;
The first statement defines x as a double variable and assigns it a value of 6. The next statement creates two character variables and assigns them the values A and B. The last statement defines an integer variable and assigns it the result of an expression, in this case 12. It is sometimes tempting to think that an initial assignment establishes a relationship that is maintained throughout the program. This is not true. For example
int x = 12; int y = 2*x; x = 4; cout << y << endl;
Review 6
Write variable definitions to represent the number of votes received by an election candidate, the percentage of votes won by the candidate, the initials of the candidate, and a constant for the year of the election. Be sure to use meaningful identifier names.
Review 7
Write a program illustrating the difference between a constant and a variable definition that includes an assignment. Your program should compile correctly if the variable is defined without the word const, and generate a compiler error if it is included.
37
promotion
integer division
type casting
displays the value 6, not the expected 6.25. Integer division truncates the decimal portion of the quotient to result in an integer. When real division is preferred, type casting must be done to explicitly convert the type of one of the values into a real number. In the above example, if we cast the 25 into a double, the statement
cout << ( double double(25)/4);
displays 6.25 because C++ promotes the 25 to a double and then real number division is performed. Note that casting was done by indicating the desired type and enclosing the value to convert in parentheses.
modulus division
Another built-in arithmetic operator is modulus division, %. Modulus division returns the remainder resulting from division. For example
cout << (25%4);
Modulus division is often useful in examining the digits of a number, finding the number of minutes left over after hours have been accounted for, and other integer-related tasks. The modulus division operator may only be used with int or long values; an attempt to use a double value with the % operator will generate a compiler error message.
38
operator precedence
An expression is evaluated using a specific order of operations, or operator precedence. Multiplication and division (including modulus division) are performed first, followed by addition and subtraction. Two operators of the same precedence are evaluated in order from left to right. Operator precedence can be changed by including parentheses in an expression. The operations within parentheses are evaluated first. It is also good programming style to include parentheses when there is any ambiguity or question at all so a reader will not have any doubts about what is intended.
Review 8
For each of the following expressions, indicate the value that will be calculated by the computer. If the expression is not legal, state why.
20+3 20.0+6.5 3.37.3 2*4 23.0/5 23/5 20%3 20.0%5.0 "20" + "2" "3.14" * "10" * "10"
Review 9
What does the following statement display when x is 1998? When x is 1776? When x is 38?
cout << ((x/10)%10);
If your libraries are not stored in this folder, the #include statement in your programs will need the appropriate path.
39
The following program demonstrates the String type and string input and output. Note the #include statement that allows String variables to be used. Also note that String must begin with a capital letter:
/*String type demo program */ #include <iostream.h> #include <lvp\string.h> int main() { String Name; cout << "Enter your name: "; cin >> Name; cout << "Welcome, " << Name; cout << "! Nice to meet you!" << endl; return return(0); } String variables can be defined and used with cin and cout just like C++
built-in data types. One of the great strengths of C++ is the ability to extend the language in this way. The program output looks like: Enter your name: Spike Welcome, Spike! Nice to meet you! When used with a string, cin takes input only up to the first blank. For example, if the user types a name with a space, only the first part is taken: Enter your name: Mary Anne Welcome, Mary! Nice to meet you!
getline()
For this reason, the string library includes the getline() function to handle full line input. If we replace the cin statement in the program above with
getline(cin, Name);
the output looks similar to: Enter your name: Mary Anne Welcome, Mary Anne! Nice to meet you! The getline() syntax requires the first item in parentheses to be the name of the input stream, and the second item to be the name of the string variable which will hold the value typed.
String variables can be assigned values just like other variables, as in:
Name = "Fedor";
Note that double-quotation marks are required, not single-quotation marks as with char variable assignments. It is also important to recognize that arithmetic cannot be performed with strings, even if the string contains a number. For example, given the legal definition
String Number = "123";
3 10
does compile, but produces the unexpected output: 123123 When two strings are added they are concatenated, or joined to form one string.
Review 10
Write a program that asks the user for a first and last name, and then displays the name as shown below (including the comma): Enter your first name: Isabella Enter your last name: Allende Your name is Allende, Isabella
the getline() function will appear to be skipped, and Name will be an empty string. This happens because the cin >> x statement reads a number and leaves the end-of-line character (the Enter key pressed by the user) in the stream. The getline() statement then reads this character and assumes that it has reached the end of a line, so it stores nothing in Name and program execution proceeds to the next statement. Replacing the getline() statement with cin >> Name avoids this problem, but does not allow for multiple word entries.
3 11
A better approach to this problem is to use the ignore() function which skips over characters until a specified character is encountered. For example, the statement
cin.ignore(100, '\n');
will skip up to 100 characters stopping only after it encounters and skips the end-of-line character, which is represented as \n. The syntax of the ignore() function requires the maximum number of characters to skip and the character we want to end skipping on. For example, the code:
int x; String Name; cin >> x; cin.ignore(100, '\n'); getline(cin, Name);
correctly handles both the input of a number followed by the input of a string. As a general rule, use the ignore() function prior to a getline() function.
which display the word Hello on the right of a 20-character field and the word Goodbye on the right of a 10-character field. The numbers displayed in the first line of the output show how the words line up: 12345678901234567890 Hello Goodbye The syntax of the formatting statements use dot notation: cout is followed by a period then the width() function name with the field size. The width() function is useful for lining up numbers, as in the statements
cout.width(10); cout << 123 << endl; cout.width(10); cout << 12 << endl; cout.width(10); cout << 12345 << endl;
which display 123 12 12345 A cout.width() statement is required for each item of output.
3 12
setf()
By default, output is right aligned in a field. This is useful for columns of numbers, but names and other words are usually left aligned. To change output alignment in a field the setf() function must be used. For example, the statement
cout.setf(ios::left);
left aligns field output until the next setf(). ios::left is a constant provided by the iostream library. As an example of setf(), consider the statements
cout.setf(ios::left); // Needed only once cout << "123456789012345678901234567890" << endl; cout.width(20); cout << "Hello"; cout.width(10); cout << "Goodbye" << endl;
which display 123456789012345678901234567890 Hello Goodbye Each word is left aligned in a field of the specified width, padded with blanks to fill out the width on the right. The setf() function is used with the constant ios::fixed to specify that numeric output is to be displayed with a fixed number of decimals. This is useful for formatting double output. In addition to setf(), precision() is used to specify the number of decimals, as in the statements:
cout.setf(ios::fixed); cout.precision(3); // Use fixed number of decimals in output // Set the number of decimals to 3
precision()
Like setf(), precision() remains in effect until the next use of precision(). As an example of fixed output, the statements
cout.setf(ios::fixed); cout.precision(3); cout.width(10); cout cout.width(10); cout cout.width(10); cout // Needed only once // Needed only once << 123.2 << endl; << 12.34567 << endl; << 9123.0 << endl;
display formatted double output: 123.200 12.346 9123.000 Note that values are rounded and zeroes are added to give the correct number of decimal places to each number in the list. Thus, the value 12.34567 is output as 12.346 rather than 12.345.
3 13
Review 11
Write a program that uses the width() function to display the following output: LVPress LVPress LVPress LVPress LVPress LVPress LVPress
Review 12
Write a program that displays a cast listing formatted as follows: Julie Andrews Richard Burton Robert Goulet Guinevere King Arthur Lancelot
Review 13
Write a program that uses the setf() and precision() functions to display the value of # (3.1415926) to various numbers of decimal places. Use a constant for #. The program output should look similar to: 3.1 3.14 3.142 3.1416 3.14159 3.141593
3.11 Choosing wisely: int vs. long vs. double; const vs. variable
It should be clear from what has been discussed that a program may be written in a variety of ways and still work correctly. In addition to the choices for program style, identifier names, and comments, the programmer may need to choose whether to define a variable as an int, a long, or a double, and as a const or not. In choosing between an int or long and a double, the most important issue is what quantity is being represented. If the quantity can only have integer values (negative and positive whole numbers, and zero) then it should be represented as an integer (int or long). This way both the compiler and a human reader will immediately understand the possible values of the variable. To use a double in this case would be misleading. If the quantity can have values with decimals, of course, it is an easy decision: a double must be used.
3 14
It is relatively easy to choose between an int and a long. Clearly a long must be used whenever there is any chance that the variable will have to represent numbers larger than 32,767 or lower than 32,767. Although it may seem easier to simply use longs for all integer quantities, int variables require less storage space, and can perhaps improve readability by indicating that only small values will be stored. The decision concerning the use of const is particularly interesting. A const is used to prevent errors later. If the program contains code to change the value of the const value, a compilation error will be generated. This is desirable since the intention is to create an unchangeable value. Another benefit to using a const is that a reader will immediately understand that the value is not to be changed, and this will give insight into how the identifier is being used. If a program is easy for a reader to understand, it is easier to debug, easier to get working correctly, and easier to modify. Since most of the cost of producing software lies in debugging and modifying the code, it is crucial that it be clear and well written.
Case Study
This and all following chapters end with a Case Study. Each Case Study illustrates the sequence of steps and the thinking that goes into the construction of a substantial programming project. Learning to program is much more than simply learning the commands of a particular language. It is learning how to combine these commands to produce robust, clear, working code. It is learning a process for creating software. The steps in the creation of software are generally given as specification, design, coding, and debugging and testing. In this first Case Study each of these steps will be explained.
specification
The first step in any programming project is defining what the program is to accomplish. This is called the specification of the program, or the spec, because it specifies what the program is to do. The specification for this Case Study is: Prompt the user for the names of the candidates and the number of votes for each candidate for an election. Display a table that shows the number of votes for each candidate, the percentage of votes (to two decimal places) for each candidate, and the total number of votes cast. For the programmer, the specification is law. If there are ambiguities in the spec, the correct response is to return to the author of the spec and ask for clarification.
3 15
design
The design of a program tells how the program will be constructed. For this Case Study, the design looks like: The program will first prompt the user to enter the candidate names and then store them in string variables. Next the number of votes will be entered by the user and stored in long variables. The total and the percentages will then be calculated and also stored in variables (a long and two doubles). The table is then displayed using these variables. The table will look similar to: Candidate Votes Grassman 1276 Lee 952 TOTAL: 2228 Percent 57.27 42.73
The writer of the specification only indicated that the table should be easy to read, and this presentation seems to satisfy this.
coding
The program is written, or coded, based upon the design. In this Case Study, the design can be broken down into three parts. The first part obtains the input:
String Candidate1, Candidate2; cout << "Enter name of first candidate: "; cin >> Candidate1; cout << "Enter name of second candidate: "; cin >> Candidate2; long Votes1, Votes2; cout << "Enter votes for " << Candidate1 << ": "; cin >> Votes1; cout << "Enter votes for " << Candidate2 << ": "; cin >> Votes2; cout << endl;
The last line of this program segment places a blank line in the output between the entering of the data and the display of the table. The second part of the program calculates the total and percentages:
long VotesTotal = Votes1 + Votes2; double Percent1 = 100 * double (Votes1)/VotesTotal; double Percent2 = 100 * double (Votes2)/VotesTotal;
Each of these variables is defined and given an initial value in the same statement. This programming style can be an aid to the reader because there is no need to look back to see how a variable was defined. Note the need to typecast the long variables in the calculation of the double values for the percentages. Typecasting the first long value in the divisions (Votes1 and Votes2) is sufficient to generate real division.
3 16
The last part of the program displays the table. To make the table layout easy to change later, a named constant is used for the field width of the columns. The format of the fields must also be established:
const int ColWidth = 10; cout.setf(ios::fixed); cout.precision(2); // Width of columns in table
The first line of the table displays the headings. The first column, containing the names, should be left aligned:
cout.setf(ios::left); cout.width(ColWidth); cout << "Candidate";
The next two columns, containing the vote counts and the percentages, are right aligned:
cout.setf(ios::right); cout.width(ColWidth); cout << "Votes"; cout.width(ColWidth); cout << "Percent" << endl;
The next row of the table displays data aligned under the column headings:
cout.setf(ios::left); cout.width(ColWidth); cout << Candidate1; cout.setf(ios::right); cout.width(ColWidth); cout << Votes1; cout.width(ColWidth); cout << Percent1 << endl;
The second and last rows of data will be coded similarly. The complete Case Study program is shown below:
/*Vote Analysis program. Names and votes for two candidates are entered and the percentages and votes are displayed in a table */ #include <iostream.h> #include <lvp/string.h> int main() { cout << "--Vote Analysis Program--" << endl << endl; String Candidate1, Candidate2; cout << "Enter name of first candidate: "; cin >> Candidate1; cout << "Enter name of second candidate: "; cin >> Candidate2; long Votes1, Votes2; cout << "Enter votes for " << Candidate1 << ": "; cin >> Votes1; cout << "Enter votes for " << Candidate2 << ": "; cin >> Votes2; cout << endl; long VotesTotal = Votes1 + Votes2; double Percent1 = 100 * double (Votes1)/VotesTotal; double Percent2 = 100 * double (Votes2)/VotesTotal;
3 17
// Output column headings cout.setf(ios::left); cout.width(ColWidth); cout << "Candidate"; cout.setf(ios::right); cout.width(ColWidth); cout << "Votes"; cout.width(ColWidth); cout << "Percent" << endl; // Output election results cout.setf(ios::left); cout.width(ColWidth); cout << Candidate1; cout.setf(ios::right); cout.width(ColWidth); cout << Votes1; cout.width(ColWidth); cout << Percent1 << endl; cout.setf(ios::left); cout.width(ColWidth); cout << Candidate2; cout.setf(ios::right); cout.width(ColWidth); cout << Votes2; cout.width(ColWidth); cout << Percent2 << endl; cout.width(ColWidth); cout << "TOTAL: "; cout.width(ColWidth); cout << VotesTotal << endl; return return(0); }
Running the Case Study produces output similar to: --Vote Analysis Program-Enter Enter Enter Enter name of first candidate: Grassman name of second candidate: Lee votes for Grassman: 1276 votes for Lee: 952 Percent 57.27 42.73
Debugging is the process of getting a program to work correctly. Testing is the process of selecting data to test different possibilities and reveal bugs. Good test cases for this program include equal numbers of votes, and very lopsided numbers including the case where one candidate gets zero votes. In testing the program it fails when both candidates have zero votes. The statements:
double Percent1 = 100 * double (Votes1)/VotesTotal; double Percent2 = 100 * double (Votes2)/VotesTotal;
3 18
generate a run-time error if both votes are zero because division by zero is an error. Since this is unlikely to occur, the Case Study will not be changed as the result of this test.
Review 14
Experiment with the Case Study program. What happens when the user enters zero for one of the vote values? What happens when the user enters a character instead of a number?
Review 15
Modify the Case Study program to handle three candidates.
Review 16
Modify the Case Study program to make the table look different. Change the first column of names so that it has a width of 10, while the other two columns have widths of only 6. Change the heading Percent to Pct to make this possible.
Chapter Summary
Variables are used to represent values within a program. A variable definition consists of a type and identifier. Data is stored in variables through the use of assignment statements (using =) and user input (using cin >>). A variable may also be assigned a value when it is declared. Built-in C++ types include double, char, int, and long. A String type is accessible by including the string library supplied with this text. Identifiers must start with a letter and contain only letters, digits, and the underscore character. Uppercase and lowercase letters are considered different, so that the variable Dog and the variable dog would be considered different variables. Keywords are identifiers reserved by C++ and cannot be used as user-defined variables or constants. Variables may be defined anywhere in a program before they are first used. Identifiers that hold unchanging values are defined as constants in a const definition. Arithmetic operations can be performed on numeric data types. An asterisk (*) is used to indicate multiplication, while a slash (/) is used to indicate division. The modulus division operator, %, returns the remainder of integer division. Integer division is performed when both the divisor and dividend are integers. The decimal portion of the quotient in integer division is truncated to result in an integer. To perform real division, one of the integer values can be typecast into a double by placing it in parentheses after the word double. When types are mixed in an expression, the values with the narrower range are promoted to the type of the value with the wider range before performing the calculation. The string library function getline() is used to properly read strings that may contain spaces. The ignore() function should be used after each numeric input whenever reading numeric and string values from the user.
3 19
Output is formatted with cout functions. These include width(), setf(), and precision(). The programmer is faced with many choices in designing and writing code. In this chapter the decisions between int, long, and double types, and between const and variable definitions were explored. Steps in creating a program include specification, design, coding, debugging, and testing. These steps are used in the Case Study program.
Vocabulary
Assignment A statement which gives a value to a variable or constant. The equal sign (=) is used for this in C++. Coding The process of turning a program design into code. Concatenation The process by which two strings are joined to form one string. Constant An identifier given a value which cannot be changed during the execution of a program. Debugging The process of fixing errors in a program in order to get it to work properly. Design The description of how a program will satisfy its specification. Dot Notation The syntax required when using a function from a library, as in the statement: cin.ignore(80, '\n') Floating Point Another name for a double. Identifier The name used for a variable or constant. Integer Division The division performed when the / operator is used. The decimal portion of the quotient is truncated to result in an integer. Keyword A word that has special meaning to the compiler, and therefore cannot be a user-defined variable or constant. Modulus Division The operator, %, which returns the remainder of the division of two integers. Operator Precedence The order in which arithmetic operations are performed in an expression. Promotion The process by which a value with a narrower range is converted a value with a wider range. Scientific Notation Used by the computer to display very large or very small numbers. Specification A description of what a program is to accomplish. String A sequence of characters. Testing The process of running a program with various sets of data in order to reveal problems.
3 20
3
C++
Type The kind of data stored in a variable or constant. For example, int,
long, double, String.
Type Casting To explicitly convert the type of one value into another type. Variable A named memory location which stores and represents a value in a program.
The modulus operator returns the remainder of the division of two integers.
>> The get from operator that gets data from the input stream and feeds
it into a variable. string.h A library that implements the String type so that string variables can be defined and string input and output be performed.
String Type limited to values containing sequences of characters. This type is available by including the string library. char Type limited to values that are single characters. cin The console input stream object. const
Specifies that an identifier is to represent a value that cannot be changed during the execution of a program. a decimal portion. getline() String function that obtains an entire line of input from the user and places it in a single String variable.
double Type limited to values that are real numbers possibly containing
ignore() cin function that skips over characters until a specified character is encountered.
int Type limited to values which are integer values in the range 32,767.
setf(ios::fixed) Specifies field formatting to display fixed numbers. setf(ios::left) Specifies field formatting to display output left aligned. setf(ios::right) Specifies field formatting to display output right aligned.
long
Type limited to values which are integer values in the range 2,147,483,647.
precision() cout function which specifies the number of digits to display in a fixed field format. setf() cout function which specifies a fixed field format. width() cout function which specifies the field width for the next item of output.
3 21
Exercises
Exercise 1
The height of an object dropped from a starting height of 100 meters is given by the equation h=1004.9*t2 where t is the time in seconds. Write a program that asks the user for a time less than 20 seconds and displays the height of the object at that time using this formula. The program output should look similar to: Enter the time: 2 The object is at 80.4 meters.
Exercise 2
Enter the temperature in Fahrenheit: 212 The temperature in Celsius is 100.0 degrees.
Write a program to convert Fahrenheit to Celsius using the formula C=5/9(F32). Test the program with values 212, 32, 98.6, and 40. The program output should look similar to:
Exercise 3
A labor and rent cost of $1.20 per pizza, regardless of size. The cost of materials that varies by the size of the pie according to the formula $0.05*diameter*diameter.
Write a program that allows the user to enter a diameter, and then display the cost of making a pie of that size. The program output should look similar to: Enter the size of the pizza: 10 The cost is $6.20
Exercise 4
The distance to school is 32 kilometers. Write a program that asks the user for an average speed in kilometers per hour, and then displays the time in minutes required for the trip at this speed. The program output should look similar to: Enter the average speed: 88 The trip to school will take 21.8 minutes.
3 22
Exercise 5
Einsteins famous formula, E=MC2 gives the amount of energy released by the complete conversion of matter of mass M into energy E. If M represents the mass in kilograms and C represents the speed of light in meters per second (3.0 x 108 m/s), then the result is in the energy unit Joules. It takes 360000 Joules to light a 100 watt light bulb for an hour. Write a program that calculates the energy and the number of light bulbs that could be powered by a given mass of matter. The program output should look similar to: Enter the mass in kg: 0.01 This mass could produce 9e+14 Joules of energy. It could power 2.5e+09 100-watt light bulbs for an hour.
Exercise 6
Write a program that allows the user to enter two integers, and then displays the results of integer (/) and modulus (%) division in either order. Program output should look similar to:
Exercise 7
Gym classes are to form volleyball teams of 7 each. Write a program that asks for the number of players, and then gives the number of teams and the number of players left over. The program output should look similar to: Enter the number of players: 37 There will be 5 teams with 2 left over.
Exercise 8
Write a program that allows the user to enter a time in minutes and then displays the time in hours:minutes format. The program output should look similar to:
Be sure to consider times where the number of minutes left over is fewer than 10. For example, 184 minutes should display 3:04. (Hint: use the modulus operator.)
3 23
Exercise 9
Write a program that displays the coins necessary to make the change entered by the user. The change can be made up of quarters, dimes, nickels, and pennies. Assume that the amount of change is less than $1.00, and use the minimum number of coins. The program output should look similar to: Enter the amount of change in cents: 68 Change: Quarters: 2 Dimes: 1 Nickels: 1 Pennies: 3
Exercise 10
a) Write a program that accepts a two-digit number and displays the digits each on a single line. The program output should look similar to: Enter a two-digit number: 27 The first digit is 2 The second digit is 7 b) Modify the program to work for a three-digit number. c) Modify the program to report the sum of the digits of a three-digit number: Enter a three-digit number: 274 The first digit is 2 The second digit is 7 The third digit is 4 The sum of the digits is 13
Exercise 11
Daurs Flowers ships flowers in pots around the world, and orders are placed via the Internet. a) Write a program that asks the user for the number of flower pots to be shipped, and then displays the number of boxes required. A big box can hold four pots, and a small box only one. Have the program calculate the smallest number of boxes required. The program output should look similar to: Enter the number of flower pots to ship: 25 We will ship: 6 big box(s) 1 small box(s) b) Modify the program to allow for a very big box that can hold nine pots. The program output should look similar to: Enter the number of flower pots to ship: 25 We will ship: 2 very big box(s) 1 big box(s) 3 small box(s) 3 24
Exercise 12
Write a program that calculates the number of hours of your life that you have spent sleeping. Assume that you sleep 8 hours each night. To simplify the problem, assume that there are always 30 days in each month, and 365 days in each year. The program output should look similar to: Enter your birthdate (using numbers for months): Month: 9 Day: 27 Year: 1984 Enter todays date (using numbers for months): Month: 10 Day: 26 Year: 2002 You have been alive for 6599 days. You have slept 52792 hours.
Exercise 13
A fast food restaurant charges $1.49 for burgers, $0.89 for fries, and $0.99 for sodas. a) Write a program that allows an employee to enter an order (the number of burgers, fries, and sodas), and then display a total, the tax (at 6%), and the final cost. The program output should look similar to: Enter the number of burgers: 3 Enter the number of fries: 2 Enter the number of sodas: 5 The total before tax is: $11.20 The tax is $0.67 The grand total is $11.87 b) Modify the program to allow the employee to enter the amount tendered, and then display the change. Program output should look similar to: ... Enter amount tendered: 20 The change is: $8.13
Exercise 14
Write a program to help you analyze the time taken for your C++ projects. The program should ask for the time spent designing, coding, debugging, and testing, and then display a table showing the percentage of time taken for each part.
Exercise 15
Write a program that examines the spending patterns of a user. It should ask the user for the amount spent in the last month on food, clothing, entertainment, and rent, and then display a table showing the percentage of expenditures for each category.
3 25
Exercise 16
The results of a primary election between two candidates in three states are: New York New Jersey Connecticut Awbrey 314159 89008 213451 Berlin 271860 121032 231034
Write a program that asks the user to enter the candidate names and election results, and then displays a summary table similar to the following: Candidate Awbrey Berlin TOTAL VOTES: Votes 616618 623926 1240544 Percent 49.71 50.29
3 26
4
Objectives
After completing this chapter you will be able to: 1. Allow a program to make decisions using the if statement. 2. Add an else clause to the if statement. 3. Write compound statements. 4. Use nested if statements. 5. Use an else-if ladder to decide among three or more actions. 6. Use logical operators in Boolean expressions. 7. Use do-while loops. 8. Develop an algorithm to solve a problem. 9. Use while loops. 10. Use the debugger to detect errors in logic. 11. Count or sum values. 12. Use for loops. 13. Use a Boolean variable. 14. Use the break statement to terminate the current block of code. 15. Generate random numbers. 16. Use the conio library.
4
n this chapter you will learn the C++ statements that control the flow of a program. Controlling the flow of a program allows one message to be displayed during one run of the program and a different message to be displayed during a different run. Another example of controlling program flow is when certain statements are executed a number of times.
When this if statement is executed, the flow of the program depends upon the value of Temp. If the value of Temp is less than 5, then the cout statement is executed and the program continues on to the next statement of the program. If the value of Temp is not less than 5 (i.e., it is greater than or equal to 5), then the cout statement is not executed and the program continues on to the next statement of the program. The if statement takes the form:
if (condition) statement;
The condition of the if statement is a Boolean expression. A Boolean expression is an expression that evaluates to either true or false. Boolean expressions are often formed using relational operators. In the if statement above, the less than relational operator (<) was used. There are five other relational operators in addition to the < operator: Operator == < <= > >= != Meaning equal to less than less than or equal to greater than greater than or equal to not equal to
41
A Boolean expression can involve comparisons of many different types including numbers, strings, characters, and expressions formed from these, as in the following examples:
ch <= 'Z' Grade == 12 FruitName == "Banana" Radius != 0 2*pi*Radius >= Area
The statement of an if can be a single C++ statement as in the if statement on the previous page, or a compound statement as explained later. The following program illustrates the use of a simple if statement.
/*Temperature program */ #include <iostream.h> int main() { double Temp; cout << "Enter today's temperature (Celsius): "; cin >> Temp; if (Temp < 5) cout << "Wear a coat today" << endl; cout << "Have a great day!" << endl; return(0); return }
The users input will affect the program flow. When run, this programs output may look similar to: Enter today's temperature (Celsius): -11 Wear a coat today. Have a great day! Or the program output may look similar to: Enter today's temperature (Celsius): 26 Have a great day!
4.2 if Pitfalls
Legal C++ if statements can fail to work as expected if some simple rules are not followed. First, never make equality comparisons (== or !=) with values that may have fractional parts. For example, the code
if (480 == 4.8*100) cout << "These are equal";
roundoff error
does not output the message as expected due to computer roundoff error. In this case, when 4.8 is multiplied by 100, the result is not 480 but instead 479.999999999. Since this is not equal to 480, the if condition evaluates to false. Roundoff error occurs because some doubles cannot be exactly represented in binary notation by the computer. Comparisons involving inequalities (< or >) work as expected.
42
4
= versus ==
Second, it is important to compare values of only the same type. For example, comparing the character 2 to the number 3
'2' > 3
is a true Boolean expression because 2 is represented internally by the value 50. There are also two common errors made with an if statement. First, the assignment operator (=) is often used when the equality relational operator (==) is intended. When this is done, an assignment rather than a comparison is made. For example, can you predict the output of the code below?
int x = 0; if (x = 1) cout << "x is now ONE" << endl; cout << "The value of x is now " << x << endl;
Because of the inadvertent use of = instead of == in the if condition, the program displays: x is now ONE The value of x is now 1 When an assignment is made in the condition of an if statement, the compiler generates a warning. When an illegal assignment is made in the condition of an if statement, the compiler gives an error message. For example, the code
if (1= x) cout << "x is now ONE" << endl;
has a 1 on the left side of the unintended assignment statement causing the compiler to generate an error message about Lvalue. Lvalue refers to a value that can be used on the left side of an assignment statement. In this case, a 1 is on the left side rather than a variable, so the error is generated.
misplaced semicolon
Another common error is to place a semicolon after the if condition, as in the statements:
if (Score == 1); // Semicolon incorrectly included! cout << "You got a hole in one!" << endl;
A semicolon indicates the if statement is complete. Therefore, when Score is equal to one the program does nothing and then goes on to the cout statement. When Score is not equal to one the program still goes on to the cout statement. The misplaced semicolon causes the message to be displayed regardless of the value of Score.
Review 1
Write a statement that could be added to the end of the Chapter Three Case Study program that will display It was a tie! if the votes entered for each candidate are the same.
43
Review 2
Modify the Circle Area program from Chapter Three to display an error message if the value entered for Radius is negative. In either case, the program may calculate and output an attempt at an answer for the area.
The statement in the else clause can be a single C++ statement or a compound statement as explained in the next section. For example, in the if statement
if (Temp < 5) cout << "Wear a coat today." << endl; else cout << "Don't wear a coat today." << endl;
only the first message is displayed when the value of Temp is less than 5, and only the second message is displayed when the value of Temp is not less than 5.
programming style
The indentation used in the if statement is good programming style and has no effect on the execution of the statement. When reading the code, the indentation makes it easier to follow the logic of the statement. This is especially important as if statements become large and complex.
programming style
A compound statement may contain as many statements as desired. The curly braces do not slow down program execution and can be included even when there is only one statement to be executed. Always using compound statements can make the look of an if statement more consistent, and eliminate the dangling else problem explained later.
44
Review 3
The following code compiles without error but contains a bug. Find the bug and predict the output of the corrected code when Score is 1 and when Score is 2:
if (Score == 1) cout << "You got a hole in one!" << endl; else else; cout << "You didn't get a hole in one!" << endl;
Review 4
Write a statement that could be put at the end of the Chapter Three Case Study program to display the name of the winner. In the event of a tie, either name can be displayed.
Advanced
Modify the statement above to display the winners name or It was a tie! as appropriate.
Review 5
Modify the Circle Area program to display an error message when the value entered for Radius is negative. If Radius is a positive value or zero, only the resulting area in a message should be displayed. The error message should look similar to: Radius entered was -3.4 Negative radii are illegal
45
dangling else
A logic error associated with nested if statements is known as the dangling else problem. For example, consider the following statement:
if (Temp < 13) if (Temp < 2) cout << "Cool"; else cout << "Hot"; // Which "if" does this belong to?
The indentation suggests that when the first if condition is false the message Hot is displayed because the else is executed. However, the else is really associated with the second if statement. This is made clear by simply changing the indentation:
if (Temp < 13) if (Temp < 2) cout << "Cool"; else cout << "Hot";
In this statement, when Temp>=13 nothing is printed! To achieve the logic suggested with the first indentation, a compound statement is used:
if (Temp < 13) { if (Temp < 2) cout << "Cool"; } else cout << "Hot";
After execution of any of the cout statements, execution of the ladder is elsecomplete and program flow proceeds to the next statement after the else if ladder.
if ladder is important. When if The logic used in developing an else else-if conditions are testing a range of numbers as in the example above, care must be taken to ensure that the conditions are ordered correctly. If Temp<41 were the first if condition, the message Hot would be displayed for every Temp value less than 41, rather than just those values from 13 to 41. Also note that the final else clause does not contain an if statement. If the program reaches this clause, it is only because all the other if conditions were false, so a default message is displayed.
46
The sequential if code tests basically the same conditions in several different places. This means that there is opportunity for inconsistency, and makes it harder to change the code correctly.
Review 6
In mathematics, the quantity b24ac is called the discriminant. Write a program that asks the user for values of a, b, and c, and displays No roots if the discriminant is negative, One root if the discriminant is zero, and Two roots if the discriminant is positive. The program output may look similar to: Enter the Enter the Enter the a=1, b=2, value for a: 1 value for b: 2 value for c: 1 c=1: One root
Review 7
Predict the output of the following code:
int Age = 2; if (Age > 5) if (Age >= 18) cout << "Adult"; else cout << "Child";
47
Review 8
Write a program that asks the user for the number of strokes on one hole of a par 5 golf game and then displays an appropriate message according to the following table: 1 2 3 4 5 6 7 8 9 or over Hole in one! Double-Eagle Eagle Birdie Par Bogey Double-Bogey Triple-Bogey Disaster
(true) || (true) evaluates to true (true) || (false) evaluates to true (false) || (true) evaluates to true (false) || (false) evaluates to false
displays the message if the temperature is less than 5 or the wind is greater than 24 or both. As another example, the statement
if ((Temp < 5) && (Wind > 24)) cout << "Wear a coat today." << endl;
displays the message only if both the temperature is less than 5 and the wind is greater than 24. The parentheses around each Boolean expression are optional but should be included for clarity. A hard-to-detect error in a Boolean expression is inadvertently using the symbols & or | which have meanings in C++ that differ from that of && and ||. If the symbols & or | are used, the program may compile and may even give the correct output for many runs. However, in a later run wrong output may be given.
A third logical operator is not which is represented by the symbol !. An expression containing ! is evaluated according to the following rules: !(true) evaluates to false !(false) evaluates to true
48
displays the message if it is not true that the temperature is less than 5. Note that the exclamation point is placed inside the parentheses that form the if condition, but outside the parentheses of the Boolean expression. It is important that the expression after the exclamation point be parenthesized so that there is not an attempt to not the value of Temp rather than the whole condition.
Review 9
Identify the logic errors in the following code that is intended to display a single appropriate message for any value of Height:
if (Height < 150) cout << "Short" << endl; if ((Height > 150) && (Height < 175)) cout << "Medium" << endl; if (Height > 175) cout << "Tall" << endl; if ladder. Rewrite the code using an else else-if
Review 10
Given the following variable definitions
int Age = 2, Height = 81, Weight = 13;
give the value, true or false, for each of the following expressions:
(Height > Weight) && (Weight != 10) (Age != 2) || (Height > 60) !(Weight == 15) (Age*Weight > Height) !((Age == 2) || (Age == 3))
Review 11
Write a program that asks the user for the length, width, and height of a package, and displays Reject if any dimension is greater than 10 cm, and Accept if all the dimensions are less than or equal to 10 cm.
49
where statement is one or more C++ statements that form the body of the loop. The condition is a Boolean expression used to determine if the loop while loop is executed at least once because the do-w is to be repeated. The do condition is not evaluated until after the first iteration of the loop. If the condition is true statement is executed again and then the condition reevaluated. This looping process is repeated until the condition is evaluated and found to be false. The following program demonstrates looping:
/*Circle Area program with a do-while loop */ #include <iostream.h> int main() { char Answer; // Whether the user wants another circle cout << "Circle Area Calculator" << endl; do { // Perform calculation const double PI = 3.14159; double Radius; cout << "Enter the radius: "; cin >> Radius; cout << "Area is " << (PI * Radius * Radius) << endl; // Ask if another calculation is desired cout << "Do another circle (Y/N)?"; cin >> Answer; } while (Answer == 'Y'); cout << "Thanks for using the Circle Calculator" << endl; return return(0); }
The users input will affect the program flow. When run, the programs output may look similar to: Circle Area Calculator Enter the radius: 10 Area is 314.159 Do another circle (Y/N)? Y Enter the radius: 2 Area is 12.5664 Do another circle (Y/N)? N Thanks for using the Circle Calculator
4 10
programming style
The constant PI and the variable Radius are declared within the loop body which means they are accessible by statements in the loop only. The variable Answer is accessed by the while condition outside the loop and therefore must be declared outside the loop body. Declaring Answer in the loop body will lead to an Undefined symbol compilation error.
Review 12
The Circle Area program in Section 4.9 only repeats the calculation if the user enters an uppercase Y. Modify the while condition so that the loop is executed when the user enters either Y or y.
Review 13
Write a simple password program. Have the user repeatedly enter a password until the secret word happiness is entered. The program output may look similar to: Enter the password: money Enter the password: success Enter the password: happiness Youve got it! Modify the program by adding an if statement that outputs a message for all incorrect tries: Enter the password: money Sorry, try again! Enter the password: success Sorry, try again! Enter the password: happiness Youve got it!
4.10 Algorithms
Programs with more complex specifications require a method of design called an algorithm. An algorithm is a series of steps that tell how to solve a problem. An algorithm created using both human terms and C++ while do-while code is called pseudocode. For example, the pseudocode for the do loop in the previous section might be: do Get Radius value from user Calculate the area of a circle using the Radius value Ask user if another calculation is desired while (Answer == Yes) Creating an algorithm forces a programmer to think through a program before actually coding it. This is helpful in two ways. First, an algorithm can be done away from the computer which usually helps a programmer focus on the overall structure of a program instead of focusing on just one statement at a time. Second, errors in logic are usually reduced.
logic error
A logic error is caused by statements that are syntactically correct but produce undesired or unexpected results. One logic error already discussed is the dangling else associated with nested ifs. Some logic errors associated with looping structures are discussed in Section 4.12.
4 11
Unlike syntax errors, logic errors must be found by the programmer rather than the compiler. These errors can be found only by thorough testing of the program, and by careful reading of the code. Good programming style that includes careful documentation and indentation and descriptive identifiers can be helpful when looking for logic errors.
where statement is one or more C++ statements that form the body of the loop. The condition is a Boolean expression used to determine if the loop is to be executed. If the condition is true statement is executed and then the condition reevaluated. This looping process is repeated until the condition is evaluated and found to be false. For example, consider the problem of asking the user for a value that falls within a certain range. If the entered value is outside the desired range, the user needs to enter a new value. This process will need to be repeated until an appropriate value is entered. However, if the user enters an appropriate value the first time then an error message need never be displayed. The pseudocode for this problem might be: Ask for a positive value While (Value < 0) Display an error message Ask for a positive value This pseudocode converted into C++ looks like:
cout << "Enter a positive number: "; cin >> Number; while (Number < 0) { cout << "Number must be positive" << endl; cout << "Please re-enter: "; cin >> Number; }
The users input will affect the program flow. When run, the programs output may look similar to: Enter a positive number: -10 Number must be positive Please re-enter: 2
4 12
misplaced semicolon
A number of logic errors can lead to an infinite loop. For instance, the following loop is infinite if Number is initially negative. Can you see why?
while (Number < 0); { cout << "Please enter a positive number:"; cin >> Number; }
The semicolon after the while condition causes the statement to check the condition, do nothing, then check the condition again, do nothing, then check, and so on. This continues on indefinitely since the user is never given the chance to re-enter a value. To the user, the program appears to come to a complete halt. A program in Windows that has gone into an infinite loop can usually be interrupted by pressing the key combination Ctrl+Alt+Sys Rq.
Inadvertently leaving out the curly braces that enclose the loop body will also cause an infinite loop. For example:
while (Number < 0) cout << "Please enter a positive number:"; cin >> Number;
The indentation suggests that two statements make up the loop body. However, since the curly braces are missing, only the first statement is in the loop. In this case, the condition is checked and the first cout statement executed, and then the condition checked again, and so on. Since the cin statement is never executed, there is no opportunity for a positive number to be entered, and the loop goes on forever. No warning is given by the compiler for this error.
Review 14
Write a program that uses the code in Section 4.11 to verify that it correctly handles negative entries. Then modify the code to accept entries between 1 and 10, inclusive. (Hint: Change the condition.) Be sure to change the messages displayed to the user.
4 13
Review 15
Modify the Circle Area program to include a while loop so that many circle areas can be computed. Let a radius of zero indicate the end of input. The program output should look similar to: Enter radius (0 to quit): 10 Area is 314 Enter radius (0 to quit): 2 Area is 12.56 Enter radius (0 to quit): 0 Have a good day! Use the following pseudocode: Ask for a radius while (radius is not zero) Calculate and display the area Ask for another radius Display good-bye message
Review 16
Write the pseudocode for a program that asks the user for an integer value between Low and High inclusive. The program should continue prompting the user until a value in this range is entered. Write the program using the pseudocode.
The pseudocode for this program could be: Get a value while (value is not zero) Count the value Sum the value Get another value Display the average by dividing the sum by the count A while loop can be used to get multiple values from the user. But what about counting and summing?
4 14
counting
A program that counts the number of values entered by the user is actually counting the number of loop iterations. To count loop iterations, a statement similar to the following is included in the loop body:
NumberOfValues=NumberOfValues+1;
In this assignment statement, the expression on the right is evaluated first, and then the result stored as the value of the variable on the left. Therefore, each time this statement is executed, one is added to the current value of NumberOfValues and then assigned to NumberOfValues as its new value.
initialized
Counting variables are used often in programs and are referred to as counters. When using counters, it is important that they first be initialized. A variable is initialized in an assignment statement to give the variable a starting value. In most cases, a counter should be initialized to 0. A similar assignment statement is used to sum the values entered by a user, as in the statement:
SumOfValues=SumOfValues+Value;
summing
The expression on the right is evaluated first, and then the result stored as the value of the variable on the left. As with a counter variable, the summing variable should be initialized to zero before adding values to it. The pseudocode converted into C++ looks like:
/*Calculate Average program */ #include <iostream.h> int main() { int Value; // Value entered by user int NumberOfValues = 0; // Number of values entered so far int SumOfValues = 0; // Sum of values entered so far const int Sentinel = 0; // Indicates end of values to be entered cout << "--Calculate Average Program--" << endl; cout << "Enter a value (" << Sentinel << " to quit): "; cin >> Value; while (Value != Sentinel) { NumberOfValues = NumberOfValues + 1; SumOfValues = SumOfValues + Value; cout << "Enter a value (" << Sentinel << " to quit): "; cin >> Value; } double cout << "Average is " << (double double(SumOfValues)/NumberOfValues) << endl; return return(0); }
sentinel
Notice that the code uses a constant called Sentinel. This constant holds a special value to act as a flag, or sentinel, signifying the end of the loop. A program can also get the sentinel value from the user. This approach provides a clear and easy-to-change method for ending a loop.
4 15
4.15 ++ and +=
There are shortcuts for both counting and summing in C++. Placing the symbol ++ directly after a variable name indicates one should be added to the variable. For example
NumberOfValues++;
increment operator
The ++ symbol is called the increment operator and its meaning was behind the decision to call this language C++. The idea was that this objectoriented extension to the C language was one better than C. For adding a value to a sum, the symbol += is used. For example
SumOfValues+=Value;
The += symbol is a special form of the assignment operator (=) and indicates the value after the operator is to be added to the value of the variable on the left of the operator.
Review 17
Modify the program in Section 4.14 so that it also calculates and displays the percentage of values entered that are below 70 (Hint: Use an if statement and another counting variable.) The program output may look similar to: Enter a Enter a Enter a Enter a Enter a Average Percent value (0 to quit): value (0 to quit): value (0 to quit): value (0 to quit): value (0 to quit): is 73.5 below 70: 25.0% 70 80 60 84 0
Review 18
Write a program that uses a while loop and a counter to display the numbers 1 through 12 each on a line.
Review 19
Modify Review 18 so that it also calculates and displays the sum of the numbers 1 through 12.
4 16
The initialization is performed only once when the for loop is first executed. The condition is a Boolean expression evaluated before each iteration of the loop body (statement). statement may be a single statement or a compound statement executed only when condition is true. The increment is performed after each iteration of the loop body, and usually advances a counter. Any of these parameters may be left out, leaving the semicolons as markers. The following for loop displays the numbers 1 through 10:
for (int int i=1; i<=10; i++) cout << i << endl;
Note that the counter i was declared as well as initialized in the for loop. However, a variable can be declared in a block of code only once. Therefore, if i is to be used again within the same block of code, its declaration (int i;) must appear outside the for loop. In the following example, the initialization parameter is left out of the for statement because Number has already been initialized:
// Prints a table of numbers and their squares int Number; cout << "Enter number to start from: "; cin >> Number; for ( ; Number<=10; Number++) cout << Number << " " << Number*Number << endl;
The variable names will change depending upon the program. However, this format makes it clear what the starting and ending values are. The previous code can be modified to include this standard:
// Prints a table of numbers and their squares const int Finish = 10; int Start; cout << "Enter number to start from: "; cin >> Start; int Number=Start; Number<=Finish; Number++) for (int cout << Number << " " << Number*Number << endl;
programming style
While it is possible to modify the value of the loop control variable from within a for loop or to terminate the loop prematurely, this is generally considered poor programming style. Good programming style dictates that changes to the loop control variable will be in the increment only and the loop will end only when the condition is false.
4 17
4.17 -- and -=
decrement operator
A for loop is often decremented. The symbol -- is called the decrement operator, and is used to indicate one should be subtracted from a variable. For example
Total--;
The = symbol is a special form of the assignment operator (=) and indicates the value after the operator is to be subtracted from the value of the variable on the left of the operator.
Review 20
Write a for loop that displays the numbers from 2 to 20 by twos, i.e., 2, 4, 6, 8, 10, etc. (Hint: Use Number+=2 as the increment.)
Review 21
Write a for loop that displays the numbers from 20 to 0, i.e., 20, 19, 18, 17, etc.
Review 22
Write a for loop that computes the sum of the odd numbers from 1 to a maximum value entered by the user.
4 18
The Boolean constant true is used to create a while condition that is always eak statement is executed. break true. Therefore, the loop iterates until the br
eak, the while loop from the Calculate Average program could Using br break be rewritten as: while (true) { cout << "Enter a value (" << Sentinel << "to quit): "; cin >> Value; if (Value==Sentinel) break break; // Terminate the loop NumberOfValues++; SumOfValues+=Value; }
Notice the code for entry of values is not repeated as in the original code.
programming style
It is important to avoid the indiscriminate use of break statements. Do eak to avoid thinking more deeply about a problem, but inbreak not use br stead to simplify your code when appropriate. A good rule of thumb is eak statement in a loop, and it is break that there should be no more than one br eak statement in for loops. break probably better not to use the br
displays 10 integers in the range 0 to 99. However, when using only the random() function the same 10 random numbers are generated each time the program is executed! This is intentional. Often it is easier to debug a program when the behavior does not change from run to run. Once a program is debugged, the randomize() function, also in the random library, should be included to generate random numbers from run to run:
randomize(); int i=1; i<=10; i++) for (int cout << random(100) << endl;
4 19
It is important to call randomize() only once. If it is called many times (for example, calling it from within the loop) then the program may generate the same number over and over again. To generate a random integer between 1 and some maximum value, the following expression may be used
1 + random(MaxRandom)
To generate a random floating point number between 0 and 1 (not including 1), the following expression can be used:
double double(random(10000))/10000
tween zero and 1. The lowest value will be 0, and the highest will be 9999/ 10000 or 0.9999.
Function
The program window is cleared with the clrscr() and clreol() functions. The clrscr() function can perform relatively slowly. When speed is important, only a portion of the screen should be cleared or rewritten if possible. The clreol() function is most commonly used in conjunction with the gotoxy() function to replace a message or a number on part of the screen with another message or number. The getch() and getche() functions are used to get a single keystroke from the user. They do not require the user to press the Enter key, and are commonly used to implement simple menus, as in the statements:
char Choice; cout << "A. Circle" << endl; cout << "B. Square" << endl; cout << "Press your choice: "; Choice = getche();
4 20
4
kbhit()
The only difference between getche() and getch() is that getche() echoes the key pressed to the screen while getch() does not. In the previous statements, getche() is used in an assignment statement because it returns the value of the key pressed by the user. This value is then stored in Choice. The getch() and getche() functions can also be used to pause a program, as in the statements:
cout << "Press a key to continue" << endl; getch(); // Pause until user presses a key
The kbhit() function is often used as the condition of a loop. For example, the following loop increments a counter until a key is pressed:
int Number = 1; cout << "Press any key to stop" << endl; while (!kbhit()) { cout << Number << endl; Number++; } getch(); // Read in the keystroke pressed
The getch() statement is included to read in the keystroke so that it is not left for the next read operation later in the program.
gotoxy()
The gotoxy() function is used to move the cursor to any position in the program output window. For example, the statement
gotoxy(3, 6);
moves the cursor to the third column from the left and the sixth row from the top of the output window. The upper-left corner of the window is the first column and the first row. The following Doodle program illustrates many of the conio functions. In the first section, the user can draw with asterisks by pressing the I/ J/K/M keys. In the second section, the program erases the drawing by putting random asterisks and blanks in the window:
/*Doodle program */ #include <iostream.h> #include <conio.h> #include <random.h> int main() { randomize(); cout << "Doodler! Press I/J/K/M to move, Q to quit" << endl; char KeyPressed; // Key pressed by user int x=40; int y=10; // Establish initial position of cursor do { // Plot a "point" gotoxy(x, y); cout << '*'; gotoxy(x, y); // Move blinking cursor under current spot KeyPressed = getch(); // Get a key, not echoing to the screen if (KeyPressed == 'I' || KeyPressed == 'i') y--; else if (KeyPressed == 'M' || KeyPressed == 'm') y++;
4 21
else if (KeyPressed == 'J' || KeyPressed == 'j') x--; else if (KeyPressed == 'K' || KeyPressed == 'k') x++; else if (KeyPressed == 'Q' || KeyPressed == 'q') ; // Do nothing else cout << "\a"; // Beep for bad keystroke } while ((KeyPressed != 'Q') && (KeyPressed != 'q')); gotoxy(1, 1); // Clear and display new title clreol(); cout << "Random stars! Press any key to stop." << endl; while (!kbhit()) { gotoxy(1+random(60), 2+random(20)); cout << "* "; // A star and a blank to draw AND erase } return (0); }
No page in a book could do this program justice! We suggest you run the program yourself to see how it behaves.
Review 23
Modify the Doodle program so that when the spacebar is pressed the drawing character is changed to a single blank rather than an asterisk and a blank. This would allow the user to erase by overwriting with blanks. Pressing the asterisk key should return the drawing character to an asterisk.
Review 24
Write a program that displays a counter in the middle of the window. The counter should count down from 1000 to 0, and at 0 should generate a series of beeps. Write the program so that the user can press any key during the counting to stop the counting and end the program without the beeps.
Review 25
Write a program that displays five rolls of two dice where each die is a number between 1 and 6, and shows the total. When run, program output may look similar to: 2 1 6 4 5 4 1 6 3 2 = = = = = 6 2 12 7 7
Case Study
In this Case Study a guessing game program will be created.
specification
Prompt the user to guess a random number generated by the computer. The program should report whether the guess is too high, too low, or correct. The user may guess as many times as desired, or may give up by entering a zero. At the end, the program displays the number of guesses taken.
4 22
design
Program design includes code design and data design. Code design is the process of determining the algorithms and program structure to be used to satisfy the specification. Data design is the process of deciding upon the variables and constants and their types based on the code design. A loop is needed to allow for multiple guesses. Since the number of guesses that will be taken is unknown, a while loop rather than a for (counting) loop should be used. Since there will be at least one guess entered, while loop will used. The program pseudocode looks like: do-w the do Generate the random number do { Get a guess If (Guess != Sentinel to give up) Report if number is too high, too low, or correct Add one to the number of guesses } while ((Guess != Sentinel to give up) and (Guess is not correct)) Report number of guesses
code design
data design
Variables are needed for the random number (Secret), the users guess (Guess), and a counter for the number of guesses (NumGuesses). Constants are needed for the two unchanging values: The maximum random number (MaxValue), and the sentinel to be used to give up (GiveUpValue). Translating the pseudocode to C++ gives the final code:
/*Guessing Game program */ #include <iostream.h> #include <random.h> int main() { // Generate secret number const int MaxValue = 100; randomize(); int Secret = 1+random(MaxValue); // Have user guess secret number const int GiveUpValue = 0; int NumGuesses = 0; int Guess; cout << "--Guessing Game!--\n"; do { cout << "Enter guess (" << GiveUpValue << " to give up):"; cin >> Guess; if (Guess != GiveUpValue) { if (Guess == Secret) cout << "Youve got it!\n"; else if (Guess < Secret) cout << "Too low! Try again!\n"; else cout << "Too high! Try again!\n"; NumGuesses++; } } while ((Guess != GiveUpValue) && (Guess != Secret)); if (Guess == GiveUpValue) cout << "You gave up after " << NumGuesses << " guesses.\n"; else cout << "It took you " << NumGuesses << " guesses.\n"; return return(0); }
coding
4 23
Program output will depend on user input. When run, the Case Study output may look similar to: --Guessing Game!-Enter guess (0 to give up):50 Too high! Try again! Enter guess (0 to give up):25 Too low! Try again! Enter guess (0 to give up):37 Youve got it! It took you 3 guesses. In another run, program output may look similar to: --Guessing Game!-Enter guess (0 to give up):50 Too low! Try again! Enter guess (0 to give up):75 Too high! Try again! Enter guess (0 to give up):0 You gave up after 2 guesses Logic errors are more likely in if statements and loops. Therefore, it is necessary to carefully create the pseudocode and work through each condition. For test cases, high, low, and correct guesses were made. It was also necessary to give up in one run in order to test that code.
Review 26
Modify the Case Study program so that it asks the user for the maximum random number to be generated (rather than using a constant).
Review 27
Modify the Case Study program so that the user has the option of playing the game repeatedly.
Review 28
Modify the Case Study program so that it prevents the user from entering numbers outside the range 0..MaxValue. If such a number is entered, the program should display an error message and then allow the user to enter that guess again.
Chapter Summary
Controlling program flow includes controlling which statements are executed and how many times statements are executed. This chapter covered the if statement and three looping statements for controlling program flow. Each of these statements evaluates a condition to determine program flow. The condition is a Boolean expression which evaluates to either true or false. A Boolean expression is formed using relational operators, and may also contain logical operators. The symbols && and || represent logical and and or. The symbol ! is used in a condition to represent logical not. When the condition portion of the if statement and
4 24
the tree looping statements is true, program flow branches to statement which can be a single C++ statement or a group of statements enclosed by curly braces called a compound statement. The if statement may include an else clause that executes when condition is false. Nested if statements are used to control program flow in one of three if else-if or more ways. A standard way of formatting nested ifs is called an else if ladder is the preferred programming style where posladder. The else else-if sible because it is less error-prone and because of its clarity to the reader.
while loop allows statements to be repeated as often as desired. do-w The do while executes the statements of the loop body and then checks do-while The do the while condition. If condition is true, the loop body is executed again and then condition checked again. This process is repeated until condition is evaluated and found to be false.
Compilers usually contain tools for debugging a program. The step feature is used for stepping through each line of code as a program executes. A watch window may be set up to watch the values of variables as a program executes. An algorithm is a series of steps that tell how to solve a problem. When creating a program, algorithms are often written as pseudocode which is a mix of English and C++. The while loop checks its condition before the first execution of the loop body. Therefore, this loop may not execute its loop body at all.
eak break Flags, or sentinels, are used to signify that a loop should end. The br statement can be used inside a loop body to terminate the current block of code and move the flow of control to the next statement after the block.
A third loop, the for loop is generally used to execute a loop body a fixed number of times. Loops are often used for counting and summing values. The expression foo++ is a shorthand for foo=foo+1 which adds one to the value of foo. The expression Sum+=foo is a shorthand for Sum=Sum+foo which adds the value of foo to the current value of Sum. Counters and summing variables must be initialized to get the expected results. The expression foo-- is a shorthand for foo=foo1 which subtracts one from the value of foo. The expression Sum=foo is a shorthand for Sum=Sumfoo which subtracts the value of foo from the current value of Sum. A Boolean variable can have one of only two values: true or false. The bool library is used to implement the bool type. The bool constants, true and false, are useful for controlling loops when used in conjunction with the break statement. Random numbers are generated using the random() and randomize() functions in the random library. The conio library provides a number of functions for controlling a programs output in its window.
4 25
Vocabulary
Algorithm A series of steps that tell how to solve a problem. Boolean Expression An expression that contains a relational operator and evaluates to either true or false. A Boolean expression may also contain logical operators. Boolean Variable A variable of type bool that can store only true or false. Code Design The process of determining the algorithm and program structure to be used to satisfy the specification. Compound Statement A group of statements surrounded by curly braces. Counter A variable used to count the number of loop iterations. Data Design The process of deciding upon the variables and constants and their types based on the code design. Dangling else A logic error that occurs in a nested if statement when an else clause is associated with the inside if instead of with the outside if as intended. Decrement Operator The symbols -- used to indicate one will be subtracted from a variable. Flag Also called a sentinel. Increment Operator The symbols ++ used to indicate one will be added to a variable. Infinite Loop A loop which iterates forever because of a logic error. Initialization An assignment statement that gives a variable a starting value. Counters are often initialized. Iteration The repetition of the execution of one or more statements in a program. Logical Operators Operators used in a complex if condition (&&, ||, !). Logic Error An error caused by statements that are syntactically correct but produce an undesired or unexpected result. Looping Also called iteration. Lvalue An expression which can be used on the left-hand side of an assignment statement, usually a variable. Nested if An if statement inside another if statement. Pseudocode code. An algorithm created using both English terms and C++
Relational Operators Operators used in an expression to make comparisons (==, <, <=, >, >=, !=) Sentinel A value used to indicate the end of a sequence of values. Roundoff Error Associated with floating point numbers because they cannot be exactly represented in binary notation by the computer.
4 26
C++
! The C++ symbol for the logical not operator. && The C++ symbol for the logical and operator. || The C++ symbol for the logical or operator. -- Decrement operator for subtracting one from a variable. ++ Increment operator used for adding one to a variable. = Special assignment operator for subtracting a value from a variable. += Special assignment operator used for adding a value to a variable. bool Type limited to values of true and false.
bool.h A library that implements the bool type so that Boolean variables can be defined. Also includes constants true and false.
br eak Statement to terminate the current block of code and move the flow break
of control to the next statement after the block. clreol() Function in the conio library for clearing the a line in the program window from the current cursor position. clrscr() Function in the conio library for clearing the program window. conio.h The console input/output library which includes functions for controlling a programs output in a window.
do while Looping statement which performs its body one or more times. do-w else if Ladder Nested ifs formatted a standard way for multiple decision else-if
branching. getch() Function in the conio library that reads a key pressed, but does not display that key. getche() Function in the conio library that reads a key pressed, and displays that key. gotoxy() Function in the conio library that moves the cursor in the program window to a designated position.
if
Executes a statement or a compound statement when its condition is true, and alternately executes a different statement or a compound statement when its condition is false. kbhit() Function in the conio.h library that returns true if a key has been pressed (but not read) and false otherwise.
times. random.h The library that includes the random() and randomize() functions. random() Function in the random library for generating a random number. randomize() Function in the random library for generating random numbers from run to run.
while Looping statement which performs its body zero or more times.
4 27
Exercises
Exercise 1
Write a program to assist in computer repair. The user is asked if the ailing computer beeps on startup, and if the hard drive spins. If it beeps and the drive spins, have the program display Contact tech support. If it beeps and the drive doesnt spin, have the program display Check drive contacts. If it doesnt beep, and the hard drive doesnt spin, have the program display Bring computer to repair center. Finally, if it doesnt beep, but the hard drive spins, have the program display Check the speaker contacts.
Exercise 2
Geels Overnight Delivery service accepts no package heavier than 27 kilograms, or larger than 0.1 cubic meters. Write a program that asks the input for the weight of a package and its dimensions, and displays an appropriate message if the package does not meet the requirements (e.g., too large, too heavy, or both). The program output should look similar to: Enter weight of package in kilograms: 28 Enter length of package in meters: 1 Enter width of package in meters: .5 Enter height of package in meters: .5 Rejected: Too heavy and too large
Exercise 3
0 up to but not including 4 dozen 4 up to but not including 6 dozen 6 up to but not including 11 dozen 11 or more dozen Extra eggs are priced at 1/12 the per $0.50 per dozen $0.45 per dozen $0.40 per dozen $0.35 per dozen dozen price.
Ernestos Eggs has different wholesale prices for their eggs, based upon the number sold:
a) Write a program that asks the user for the number of eggs, and then calculates the bill. The program output should look similar to: Enter number of eggs: 126 Your cost is $0.40 per dozen or 0.033 per egg. Your bill comes to $4.20 b) A computer is not always available, so Mr. Ernesto would like a chart showing the price for any number of eggs up to 120. Write a program that displays a chart similar to: 1 2 3 ... 48 ... 4 28 0.04 0.08 0.12 1.80
Exercise 4
Clarks Cafe pays its employees time and a half for every hour worked over 40 hours. a) Write a program to calculate gross weekly wages (before taxes) given the hours worked and the hourly rate. The program output should look similar to: Enter hours worked: 45 Enter hourly rate: 10.00 Gross wages = $ 475.00 b) Mr. Clark employs students who are exempt from taxes and others who are not. Modify the program so that if an employee is not exempt, 18% will be deducted from gross wages, otherwise NO TAXES DEDUCTED will be displayed. Two program runs are shown below: Enter hours worked: 45 Enter hourly rate: 10.00 Exempt (Y/N)? Y Gross wages = $475.00 NO TAXES DEDUCTED Enter hours worked: 20 Enter hourly rate: 4.00 Exempt (Y/N)? N Gross wages = $80.00 Wages after taxes = $65.60
Exercise 5
The Bored Auto Company has done it again. Some models of their cars may be difficult to drive because their wheels are not exactly round. Cars with model numbers 119, 179, 189 through 195, 221, and 780 have been found to have this defect. Write a program that allows customers to enter the model number of their car to find out whether or not it is defective. The program should terminate when a zero is entered as a model number. The program output should look similar to: Enter your model number (0 for done): 127 Your car is OK. Enter your model number (0 for done): 221 Your car is defective. Please have it fixed. Enter your model number (0 for done): 0 Program complete.
4 29
Exercise 6
You deposit $2500.00 in a new super Certificate of Deposit (CD) at your bank. Write a program to calculate how many years it will take for your CD to be worth $5000.00 or more, if it pays 7.5% interest compounded annually.
Exercise 7
Write a program that takes a non-negative long as input and displays each of the digits on a separate line. The program output should look similar to:
Exercise 8
Enter an integer: 145 Sum of digits is 10 Enter an integer: 8888 Sum of digits is 32
Write a program that displays the sum of the digits of any non-negative integer. Two program runs are shown below:
Exercise 9
Enter an integer: 145 Sum of the cubes of the digits is 190 Enter an integer: 8888 Sum of the cubes of the digits is 2048
a) Write a program that displays the sum of the cubes of the digits of any non-negative integer. Two program runs are shown below:
b) Modify the program to determine what integers of two, three, or four digits are equal to the sum of the cubes of their digits.
Exercise 10
An interesting problem in number theory is sometimes called the necklace problem. This problem begins with two single-digit numbers. The next number is obtained by adding the first two numbers together and saving only the ones-digit. This process is repeated until the necklace closes by returning to the original two numbers. For example, if the starting numbers are 1 and 8, twelve steps are required to close the necklace: 18976392134718 4 30
Write a program that asks the user for two starting numbers, and then displays the sequence and the number of steps taken. The program output should look similar to: Enter first number: 1 Enter second number: 8 1 8 9 7 6 3 9 2 1 3 4 7 1 8 Your numbers required 12 steps.
Exercise 11
a) Write a program that asks the user for a non-negative integer and then displays a message indicating if it is prime or not. A prime number is an integer that has no factors other than one and itself. Two program runs are shown below: Enter an integer: 51 Not prime Enter an integer: 53 Prime b) Modify the program to display the number of primes found between two numbers entered by the user. Enter starting number: 50 Enter ending number: 59 Number of primes in range: 2
Exercise 12
Write a program that displays the prime factors of an integer entered by the user. If a number is a prime factor more than once, it should be printed more than once. The program output should look similar to: Enter a number: 140 Prime factors: 2,2,5,7 Use the following algorithm: Initialize a counter at 2 So long as the counter is less than or equal to the number if the counter divides the number evenly display the counter divide the number by the counter to get a new number else add one to the counter
4 31
Exercise 13
Write a program that asks the user for two non-negative integers and then prints the greatest common divisor (GCD) of the two numbers. The GCD is the largest integer that divides into both numbers evenly. Two program runs are shown below: Enter an integer: 12 Enter an integer: 18 The GCD is 6 Enter an integer: 102 Enter an integer: 68 The GCD is 34
Exercise 14
Amys Garden Emporium uses mailing labels for shipping boxes. Write a program to display a mailing label for each box to be shipped. The program output should look similar to: How many boxes? AMYS GARDEN SUNTAN, IOWA BOX NUMBER 1 2 EMPORIUM 12345 OF 2
Exercise 15
Write a program that displays the sum of all of the integers between two input numbers, inclusive. The program output should look similar to: Enter starting number: 25 Enter ending number: 47 The sum of integers from 25 to 47 is 828
Exercise 16
a) Write a program that reads in letter grades for a class of 20 students and displays the number of students who passed (D or better) and the number who failed (E or F). The program output should look similar to: Enter a grade: C Enter a grade: A ... 16 students passed 4 students failed
4 32
b) Modify the program to work for a class of any size. Use Z as the value of the sentinel, making sure not to count the Z as a grade. Program output should display the percentage of students passing and failing using formatted output: Enter a grade: C Enter a grade: E Enter a grade: A ... Enter a grade: Z 12 students passed: 80.00% 3 students failed: 20.00%
Exercise 17
Write a program that asks the user for starting and ending values and then display a formatted table of squares and cubes. Write the program so that it is easy to change the column widths. The program output should look similar to: Enter starting value: 5 Enter ending value: 12 X 5 6 12 X SQUARED 25 36 ... 144 X CUBED 125 216 1728
Exercise 18
a) Write a program that calculates the average and total for a known number of test grades. The program should first read in the number of grades and then the grades. The program output should look similar to: How many grades? 12 Enter a grade: 95 ... Enter a grade: 69 The total is 1020 The average is 85.00
4 33
b) Modify the program to include error checking so that it will give an error message and not accept test grades outside the range 0 100. The program output should look similar to: How many grades? 3 Enter a grade: 82 Enter a grade: -12 -12 is not an acceptable grade Enter a grade: 75 Enter a grade: 93 The total is 250 The average is 83.33 c) Modify the program to accept any number of grades terminated with a sentinel, 1. The program output should look similar to: Enter a grade: 82 Enter a grade: 75 Enter a grade: -1 The total is 157 The average is 78.5
Exercise 19
The factorial of a positive number is the product of all positive integers less than or equal to the number. For example, 5 factorial (written 5!) is equal to 5*4*3*2*1, or 120. a) Write a program that reads a positive integer and displays its factorial. The program output should look similar to: Enter an integer: 5 5! = 120 b) 0! is defined as 1, but all negative factorials are considered to be undefined. Modify the factorial program to ask the user for an integer until a positive integer or 0 is entered. The program output should look similar to: Enter an integer: -5 -5! is undefined. Enter an integer: 0 0! = 1
4 34
Exercise 20
The interest rate on a 5-year variable rate Certificate of Deposit (CD) is changed every year. Write a program to calculate the yearly interest and final value of the CD, given the initial investment and the five interest rates. Interest is compounded annually. The program output should look similar to: Enter initial investment: 3000.00 Enter interest rate for year 1 (decimal): 0.10 You earned $300.00 interest. Enter interest rate for year 2 (decimal): 0.05 You earned $165.00 interest. ... Enter interest rate for year 5 (decimal): 0.11 You earned $1548.07 interest. Your CD is worth $4548.07
Exercise 21
Modify Review 22 to display the sum of the odd numbers from 1 to maximum values 1 through 50. The program output should look similar to: 1 2 3 4 5 6 ... 48 49 50 1 1 4 4 9 9 576 625 625
Exercise 22
The election results for two candidates in six wards are: Ward 1 2 3 4 5 6 Kubak 528 313 1003 519 713 2103 Kelly 210 721 822 518 921 1922
4 35
Write a program that asks the user to enter the given election results, and then display the total votes and percentages for each candidate and the number of wards won by each candidate. The program output should look similar to: Ward 1 Enter Enter Ward 2 Enter Enter ... Name Kubak Kelly Kubak: 528 Kelly: 210 Kubak: 313 Kelly: 721
Wards won 4 2
Exercise 23
An interesting (yet unsolved) question in mathematics concerns hailstone numbers. This series is produced by taking an initial integer, and if the number is even, dividing it by 2. If the initial number is odd, multiply it by 3 and add 1. This process is then repeated. For example, an initial number of 10 produces: 10, 5, 16, 8, 4, 2, 1, 4, 2, 1, 4, 2, 1, An initial value of 23 produces: 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1, Notice that both numbers eventually reach the cycle 4, 2, 1, 4, 2, 1, . Write two programs that answer the following questions for initial values of 1 to 200: a) Do all numbers from 1 to 200 eventually reach this cycle? b) What is the maximum number of iterations taken to reach the cycle and which starting number produces this maximum?
Exercise 24
Chaos theory is a subfield of mathematics which relies heavily on the computer. A simple chaos experiment is: Take any real number X between 0 and 1 as a starting value. Generate a new number using the logistic equation: X = 2*X*(1X); Display this new X, and repeat the process. Perform this cycle 50 times. a) Write a program that asks the user for a starting value and then performs this process. Try to determine what happens for different starting values. b) Modify the program so that the 2 in the equation can be replaced with a value specified by the user in the range 2 to 4, but the starting value of X is always 0.5. See if you can find interesting behavior. 4 36
Exercise 25
Write a program that plays a guessing game where the computer tries to guess a number picked by the user. The program asks the user to think of a secret number and then asks the user a sequence of guesses. After each guess, the user must report whether it is too high or too low or correct. The program should count the guesses. (Hint: Maintain HighestPossible and LowestPossible variables, and always guess midway between the two. This is called a binary search.) The program output should look similar to: Think of a number between 1 and Is the number 50 (Correct, Low, Is the number 25 (Correct, Low, Is the number 13 (Correct, Low, Is the number 19 (Correct, Low, Number of guesses: 4 100 and then press any key. High)? h High)? h High)? l High)? c
Exercise 26
Write a program that acts as a simple slot machine. The user starts with 100 tokens and with each pull of the handle loses 1 token. The computer spins three wheels each consisting of the numbers 1, 2, and 3. If all three numbers are 1, the user gets 4 tokens; if all three are 2, the user gets 8 tokens; if all are 3, the user gets 12 tokens. Program output should look similar to: You have 100 tokens. Pull? Y [1] [3] [2] You lost. You have 99 tokens. Pull? Y [2] [2] [2] You won 8 tokens! You have 106 tokens. Pull? N Thanks for playing!
Exercise 27
Modify the Doodle program in Section 4.21 so that when the C key is pressed the drawing character is changed to the next key pressed. Thus, if the user pressed C and then $, the program will use $ characters instead of * characters when drawing.
Exercise 28
Modify the Doodle program in Section 4.21 so that it uses the numeric keypad keys to move and includes diagonal moves.
4 37
Exercise 29
Write a program that uses gotoxy() to display an x formed from asterisks on the screen. Let the user specify the size of the x as an odd number between 1 and 15. The program output should look similar to: What size x would you like (an odd number)? 5 * * * * * * * * *
Exercise 30
In the random walk problem, a person is placed at the center of a 7 meter long bridge. Each step, the person moves 1 meter either forward or backward at random. a) Write a program to determine how many steps the person will walk before taking a step off the bridge. Have the program average 50 trials, and report the average and greatest number of steps. (Hint: Use random(2), with 0 meaning to go forward and 1 meaning to go backward.) b) Modify the program to display the position of the person at each stage of a run: step step step step step step 1:| * 2:| * 3:| * 4:| * 5:| * 6:| * ... | | | | | |
Exercise 31
A simple form of animation is done by drawing characters, then erasing them by redrawing them with blanks, and then drawing them in a new location. The pseudocode might be: Set location to starting spot Draw black character at location While not done do Draw white character at location Change location Draw black character at (new) location The line Change location may mean adding one to the location, or changing the location according to a command key pressed. a) Write a program that animates an asterisk moving across the screen from left to right. b) Modify the program so that the user can specify the direction with L meaning left to right and T meaning top to bottom.
4 38
c) Modify the program so that the character is formed of several characters, e.g., o o ' \_/
Exercise 32
Modify the Case Study so that it prevents the user from entering a foolish guess (i.e., one lower than a number previously reported to be too low, or higher than a number previously reported to be too high). (Hint: Maintain HighestPossible and LowestPossible variables, updating one of them after each guess.)
The exercise section of this and most succeeding chapters will end with one or more advanced exercises. These exercises provide the specification; your task is to produce design, coding, debugging, and testing steps just as those used in the Case Study problem.
Advanced Exercise 33
Write a program to simulate a simplified version of the game 21. A deck of cards numbered 1 to 10 is used and any number can be repeated. The computer starts by asking you (the user) how many cards you want. It then deals you the cards, which are randomly picked, and deals itself three randomly picked cards. If both scores are over 21, or if both are equal but under 21, the game is declared a draw. Otherwise, the winner is the one with the highest score equal to or less than 21. If one score is over 21, but the other is 21 or less, the player with 21 or less is declared the winner. Write your program so that the game can be played as often as desired with the winner of each game winning one point. At the end of the games, display the total winnings for you and the computer and the number of draws. The program output should look similar to: How many cards do you want? 3 You: 8 5 1 Computer: 8 3 3 I have 14 and you have 14 so we draw. Would you like to play again? (Y/N)? Y How many cards do you want? 2 You: 7 2 Computer: 8 7 4 I have 19 and you have 9 so I win. Would you like to play again? (Y/N)? Y How many cards do you want? 3 You: 8 7 4 Computer: 2 1 7 I have 10 and you have 19 so you win. Would you like to play again (Y/N)? N Computer wins = 1 Your wins = 1 Draws = 1
4 39
4 40
5
Objectives
After completing this chapter you will be able to: 1. Write user-defined functions. 2. Use parameters to pass values to a function. 3. Write overloaded functions. 4. Use default parameters. 5. Use the return statement to return a value from a function. 6. Use reference parameters in a function. 7. Develop methodologies for building functions. 8. Use preconditions and postconditions to document functions. 9. Build a library containing code to perform related tasks. 10. Use top-down design in constructing large programs. 11. Understand function prototypes.
5
A
s the complexity of your programs increases, you may wonder how large programs containing hundreds of thousands of lines of code are ever written. Software applications such as these are often written by a team of from tens to hundreds of programmers. But how can so many individuals work together effectively? A complex programming task is broken down into small, independent parts that can work together in a clearly defined way. In C++, these small, independent parts are called functions. Understanding and using functions is central to becoming a C++ programmer.
void
A user-defined function has the same format as a main() function. The function above does not return a value, therefore it begins with the keyn statement. A cometurn word void instead of int and does not contain a retur ment describing the function is included as good programming style.
Functions
51
function defintion
A function definition is the actual code of a function. To execute a function it is called by main() or another function using its name and parentheses. In this way, user-defined functions extend the C++ language. The program below includes the DaysToHours() function and a similar function HoursToDays():
/*Time Conversion program. Illustrates user-defined functions. */ #include <iostream.h> //-------------------------------------------------------------------------------void DaysToHours() /*Converts days to hours */ { int Days, Hours; cout << "Enter the number of days: "; cin >> Days; Hours = Days*24; cout << "The number of hours in " << Days << " days is: " << Hours; } //-------------------------------------------------------------------------------void HoursToDays() /* Converts hours to days */ { int Hours, Days; cout << "Enter the number of hours: "; cin >> Hours; Days = Hours/24; cout << "The number of days in " << Hours << " hours is: " << Days; } //-------------------------------------------------------------------------------int main() { char Choice; cout << "1 Days to Hours" << endl; cout << "2 Hours to Days" << endl; cout << "Enter your choice: "; cin >> Choice; if (Choice == '1') DaysToHours(); // function call else HoursToDays(); // function call return return(0); }
When run, the program output may look similar to: 1 Days to Hours 2 Hours to Days Enter your choice: 1 Enter the number of days: 3 The number of hours in 3 days is: 72
52
A function definition must appear before the function can be called. For this reason, the order of function definitions must be considered if one function calls another. This is also why the main() function appears last in the program. To summarize, the structure of a program becomes: #include <libraries> function definitions main() function
Review 1
Modify the Time Conversion program to include an Introduction() function that gives instructions to the user on the use of the program. Have the main() function call Introduction() before asking for the users choice.
Review 2
Modify the Time Conversion program to include a third function HoursToMinutes().
In this case, 3 and 5 are the function parameters. These parameters are used to position the cursor in the third row of the fifth column in the program output window. A function uses parameters when they have been specified in the function definition. For example, a user-defined function DrawBar() displays a bar of asterisks across the screen. The length of the bar is determined with a parameter:
void DrawBar(int int Length) /*Displays a bar of asterisks of length Length. Length assumed >= 0 */ { const char Mark = '*'; for (int int i=0; i<Length; i++) cout << Mark; cout << endl; }
The function heading includes the type and name of the parameter, in this case, Length. Length can then be used in the function like a variable. The initial value of Length is determined by the argument given in the function call. For example, the statements
DrawBar(30); int i = 5; DrawBar(i);
Functions
53
In the function heading, int Length is the formal parameter, also called the formal argument. It defines the type of the value required in the function call. The value 30 in the function call is the actual parameter, also called the actual argument. It is the value being passed to the function in a call. Note that the actual parameter can also be the value stored in a variable.
multiple parameters
When specifying more than one parameter in a function definition, the parameters are separated by a comma. For example, a modified DrawBar() requires both the character to display as well as a length:
void DrawBar(int int Length, char Mark) /*Displays a bar of length Length using the character Mark. Length assumed >= 0 */ { for (int int i=0; i<Length; i++) cout << Mark; cout << endl; }
parameter order
The order of the parameters is significant. In a function, the first actual parameter corresponds to the first formal parameter, and the second actual parameter to the second formal parameter, as illustrated below:
programming style
As many parameters as desired can be placed in a function header. However, well-designed functions usually have only a few parameters.
Review 3
Write a main() function that uses four calls to DrawBar() to create a triangle: * ** *** ****
Review 4
Write a function SpanishNum() that displays the spanish equivalent of its int parameter that is in the range 1 to 5: 1 2 3 4 5 uno dos tres cuatro cinco
Write a program where main() uses a for loop to display a table similar to the one above.
54
When run, the program displays: **************************************** $$$$$$$$$$ **************************************** The DrawBar(40) calls invoke the first function, while the DrawBar(10,'$') call invokes the second. The compiler makes this decision based upon the types, order, and number of the actual arguments in a call.
Functions
55
When run, the program displays: **************************************** $$$$$$$$$$ **************************************** In the function header, Mark is declared with a default value. If only a single argument is given in the call, then the default value (an asterisk) is used. If both arguments are given in the call, the default value is overridden. Note how the function definition with the default parameter can take the place of both the previous DrawBar() functions. When using default parameters: All nondefault parameters must come first, followed by any parameters that have defaults. There is often ambiguity introduced when using default parameters and overloading on the same function. It is generally best to use one or the other, but not both for any given function.
56
Review 5
Write a function GiveHint() that has two int arguments, Secret and Guess, and displays one of the following messages as appropriate: Too high! Try again! Too low! Try again! You've got it!
Review 6
Write a function DrawBox() that has an int and a char argument, and displays a square using the char argument. DrawBox() should make calls to DrawBar() to perform its work. For example, the call DrawBox(4,'%') should display: %%%% %%%% %%%% %%%%
Review 7
Write a function DrawBox() that is based on the function in Review 6. This DrawBox() should include three parameters, two of which are int arguments giving the height and width of a rectangle to be drawn. The function header should be:
void DrawBox(int int Height, int Width, char Mark) /*Draws a rectangle of size Height and Width using the character Mark. Height, Width assumed >= 0 */
Write a program where main() makes calls to this DrawBox() and the one in Review 6 to illustrate how overloading allows these two functions to coexist.
Review 8
Write a function DrawBox() that is based on the function in Review 7. This DrawBox() should include two int arguments giving the height and width of a rectangle to be drawn and a third default parameter for Mark. To test this DrawBox(), write a program where main() makes a call that uses the default parameter and a call that doesnt.
The function definition begins with double indicating the type of value it will return to the calling function. The value returned by the function is n statement. A return statement can return a single value only. eturn in a retur
Functions
57
Functions can return any type of value, including built-in types (int, double, char) and those implemented in a library (String, bool). The void type is used to indicate that a function does not return any value at all, as was the case with the previous user-defined functions in this chapter. Functions defined using void do not include a return statement. Calculations can be performed within the return statement. For example, CubeOf() could be rewritten as:
double CubeOf(double double x) /*Returns the cube of x */ { return return(x*x*x); }
Functions that return a value can be used in calculations, assignments, or streams. For example, the statement
for (Row=1; Row<=4; Row++) cout << Row << " " << CubeOf(Row) << endl;
displays: 1 2 3 4 1 8 27 64
programming style
In the statement above, the value returned by CubeOf() is passed to cout to be displayed, and these values form the second column above. Note that the actual parameter is the variable Row, while the formal parameter is x. Throughout a program, descriptive variable names should be used without regard to matching parameter names in function definitions. Understanding the return statement permits better understanding of the main() function used in every C++ program:
int main() { // statements return return(0); }
The int in the main() header indicates that this function returns an integer. As discussed in Chapter Two, the value returned by main() is used to indicate if the function terminated without error. A 0 indicates no error.
Review 9
Write a function PowerOf() that calculates and returns the value of xn. (Hint: A for loop can be used to calculate the power.) Use the function header:
double PowerOf(double double x, int n) /*Returns x to the nth power. n assumed >= 0 */
58
Review 10
Write a program that uses PowerOf() in Review 9 to display a table of the first ten powers of 2. The program output should look similar to: 2 to 2 to 2 to 2 to ... 2 to the the the the 1 2 3 4 is is is is 2 4 8 16
the 10 is 1024
produces the undesired output: Before Swap(): a=3 and b=5 After Swap(): a=3 and b=5
reference parameters
Reference parameters, or call-by-reference parameters, pass values both in to and out of a function. The variables representing actual parameters are automatically and immediately altered by a function call with reference parameters, as demonstrated in the following program:
Functions
59
/*Reference Parameters program */ #include <iostream.h> //-------------------------------------------------------------------------------void Swap(int int &x, int &y) /*Exchanges the values of x and y */ { int Temp; Temp = x; x = y; y = Temp; } //-------------------------------------------------------------------------------int main() { int a = 3, b = 5; cout << "Before Swap(): a= " << a << " and b= " << b << endl; Swap(a, b); cout << "After Swap(): a= " << a << " and b= " << b; return (0); }
produces the output: Before Swap(): a=3 and b=5 After Swap(): a=5 and b=3
&
Note that x and y are preceded by an ampersand (&) in the Swap() header to indicate that they are reference parameters. When reference parameters are used, the values of the actual parameters are passed to the formal parameters, and then may be altered by the function and passed back to the actual parameters, as illustrated below:
Reference parameters are used when a function needs to return more than one value. As demonstrated by the Swap() function, two values were passed into a function (a and b) and two values were passed out (new a and b). As another example, a function BreakUp() converts a total number of seconds to hours, minutes, and seconds that are returned in three parameters:
void BreakUp(int int TotalSeconds, int &Hours, int &Minutes, int &Seconds) /*Returns the Hours, Minutes, and Seconds in TotalSeconds. TotalSeconds assumed >= 0 */ { Hours = TotalSeconds/3600; int Left = TotalSeconds%3600; Minutes = Left/60; Seconds = Left%60; }
The first parameter, TotalSeconds, is a value parameter (no ampersand) that sends information in to the function. Hours, Minutes, and Seconds are preceded by an ampersand to indicate that they are reference parameters to be modified by the function. For example, the code
5 10
int h, m, s, TotalSecs = 5000; BreakUp(TotalSecs, h, m, s); cout << "Hours: " << h << endl; cout << "Minutes: " << m << endl; cout << "Seconds: " << s << endl;
displays: Hours: 1 Minutes: 23 Seconds: 20 Unlike Swap(), the three reference parameters were not given initial values because the purpose of BreakUp() is to pass these three values back. It is important that the actual parameter corresponding to a reference parameter be a variable. If a constant is used instead, the compiler generates a warning, and any changes made within the function cannot be reflected in the calling function because there is no variable in the call to be changed.
Review 11
Write a function DaysToHrsMins() that takes an int as its first parameter and returns the corresponding Hours and Mins as its second and third parameters. The function should not communicate directly with the user, but should only use the parameters to pass information in and out. Write a program that uses DaysToHrsMins() to display a table similar to: 1 day(s) is 24 hours or 1440 minutes 2 day(s) is 48 hours or 2880 minutes ... 10 days(s) is 240 hours or 14400 minutes
Review 12
Write a function FindLoHi() that takes two int values and returns the lesser of the two as its third parameter and the greater of the two as its fourth parameter. Use the function header:
void FindLoHi(int int x, int y, int &Lo, int &Hi)
Overload this function by writing another function that does the same task using double as the type for all its arguments. Write a program that illustrates the use of these functions.
Review 13
Write a function SetLoHi() that reorders the values of its two int parameters into low-high order. If x is less than y when the function is called, it should do nothing. Use the function header:
void SetLoHi(int int &x, int &y)
Functions
5 11
specification design
The first step in creating a function is determining what the function is to accomplish. This is called its specification. A function is designed according to its specification. The design includes determining what information the function needs from the caller, and what information the function should return. The following table can be used as a guide: If the function must return... no information one item of information more than one item of information then... use a void function use a return statement use reference parameters
If reference parameters are to be used in a function, consider whether it is possible and logical for a parameter to provide both input and output from the function. A function should be designed with the following in mind: A function should perform a single, well-defined task. The functions name and parameter names should be descriptive of the task being performed by the function so that it is understandable to someone reading only the function and not the rest of the program. A function should be short; a long function implies that the code should be further decomposed into other functions as described below. Another part of designing a function is determining whether a function should be written as two or more different functions. For example, rather than a single function:
void BreakUp(int int TotalSeconds, int &Hours, int &Minutes, int &Seconds) /*Returns the Hours, Minutes, and Seconds in TotalSeconds. TotalSeconds assumed >= 0 */
It might be preferable to have three functions, each returning just one piece of information:
int SecondsFrom(int int TotalSeconds) /*Returns the number of seconds left when converting TotalSeconds to H/M/S form. TotalSeconds assumed >= 0 */ int MinutesFrom(int int TotalSeconds) /*Returns the number of minutes when converting TotalSeconds to H/M/S form. TotalSeconds assumed >= 0 */ int HoursFrom(int int TotalSeconds) /*Returns the number of hours when converting TotalSeconds to H/M/S form. TotalSeconds assumed >= 0 */
5 12
5
coding debugging and testing
These functions offer the advantage of calculating only the desired quantity rather than all three quantities. The disadvantage is that there are more names to remember and some redundant calculations performed within the functions. There is no best choicethe programmer has to consider the options for the particular application being written. The third step in creating a function is coding. This includes carefully commenting a function as discussed in the next section. Code can also be made clearer by separating functions with a delimiter. For example:
//---------------------------------------------------------------------
The last step in creating a function is debugging and testing. The best method for debugging is to write just enough code to test each function in isolation during the development process. A common error is to write an entire program containing many functions and only test when the program is completely coded. This makes it much harder to find the source of bugs, and greatly increases the chance that bugs will go undetected through the testing process.
The initial requirements of a function are called the preconditions. Up to this point, we have been referring to these comments as assumptions. If the preconditions are met when a function is called, a correctly written function will satisfy a postcondition. A function may not have a precondition, as in a function that can act on any data values. However, a function with no postcondition implies that it accomplishes nothing! Good guidelines for writing preconditions and postconditions are: The precondition is a statement that must be true at the beginning of a function for the function to work properly. The postcondition is a statement that must be true at the end of the execution of a function if the function has worked properly. Preconditions and postconditions should not state facts that the compiler has already verified or refer to variables or other information outside the function. The postcondition should not tell how the function accomplished its task.
Functions
5 13
Note that the precondition does not state that n is an integer since the compiler checks for this. The goal in function documentation is to create a function header which fully describes the actions of the function. When reading a program segment that includes a function call, the programmer should only need to read the header of the function called to understand what is happening. As our programs become more and more complex, this will become increasingly important. In addition, the use of preconditions and postconditions are an effective tool in debugging. Often it is possible to place code at the beginning of a function to verify that the precondition has been met. Code can also often be placed at the end of the function to verify that the postcondition has been met. If a functions precondition is not satisfied, the problem must be in the calling function. If the precondition is satisfied but the postcondition is not, then the problem must lie within the function.
Review 14
Write a function DisplayWithDecimals() that displays a double value with a given number of decimals. Use the header:
void DisplayWithDecimals(double double Num, int NumDecimals) /*Displays Num to NumDecimals places Post: Num displayed to NumDecimals places */
Review 15
Write a function FindDigits() that has a parameter for a three-digit number and three other parameters for returning the three individual digits of the three-digit number.
Review 16
Complete the functions SecondsFrom(), MinutesFrom(), and HoursFrom() by writing the code for the bodies of the functions. Write a program that uses each of these functions. (The main() can be similar to the code in Section 5.7.)
5 14
combines the code from the iostream library with the current program. A library usually contains code to perform related tasks. For example, the iostream libr ary contains code related to the input/output stream. In this section a utility library will be written that might be useful in a variety of programs. The utility library will contain the user-defined functions Pause() and GetInt() described below.
Pause()
A common need is to pause program execution until the user presses a key. This can be accomplished with the following two lines of code:
cout << "Press a key to continue" << endl; getch(); // Wait for user to hit a key
The getch() function is defined in the conio library. Therefore, the conio library will need to be included in the utility library.
GetInt()
A program commonly prompts the user for an integer in a specific range. A function that returns an integer in the desired range from the user while providing appropriate error messages would have the following header:
int GetInt(int int Lo, int Hi) /*Obtains and returns an integer from the user in the range Lo..Hi. Pre: Lo < Hi Post: An integer between Lo and Hi inclusive returned */
The body of this function uses a loop to check the user entry, and displays an error message if the entry is out of range. Once the user enters a correct value, the loop terminates and the value is returned:
int Entry; cin >> Entry; while ((Entry < Lo) || (Entry > Hi)) { cout << "Value must be between " << Lo << " and " << Hi << endl; cout << "Please re-enter: "; cin >> Entry; } return return(Entry);
Functions
5 15
To create the utility library the desired functions are coded in a file by themselves, along with the necessary include statements:
/*Utility Library void Pause() int GetInt(int int Lo, int Hi) #include <iostream.h> #include <conio.h> //-------------------------------------------------------------------------------void Pause() /*Displays a message and waits for the user to hit a key Post: Key pressed */ { cout << "Press a key to continue" << endl; getch(); // Pause for user to hit a key } //-------------------------------------------------------------------------------int GetInt(int int Lo, int Hi) /*Obtains and returns an integer from the user in the range Lo..Hi. Pre: Lo < Hi Post: An integer between Lo and Hi inclusive returned */ { int Entry; cin >> Entry; while ((Entry < Lo) || (Entry > Hi)) { cout << "Value must be between " << Lo << " and " << Hi << endl; cout << "Please re-enter: "; cin >> Entry; } return return(Entry); }
*/
This file may be saved with any name. However, by convention, it should be saved with a .h extension. Since this is a utility library, the file is saved as utility.h in the same folder with our other C++ program files. The utility library can be included in a program with the statement:
#include "utility.h"
Note that, rather than angle brackets, < and >, double-quotation marks are used. When a library is included with angle brackets, the compiler looks for the file in the include directory. When double-quotation marks are used, it looks in the current directory.
5 16
When run, the program output may look similar to: Welcome to the translator program! Choose to see the Spanish translation 0 End program 1 Hello 2 Good-bye 3 Tomorrow Enter your choice: 3 Manana Press a key to continue Choose to see the Spanish translation 0 End program 1 Hello 2 Good-bye 3 Tomorrow Enter your choice: 6 Value must be between 0 and 3 Please re-enter: 0 Gracias! Press a key to continue Thanks for using the translator!
Functions
5 17
The program uses Pause() and GetInt() almost as if they were built into C++. The utility library has, in a sense, extended the language. Note that the program includes the iostream library. The utility library also included iostream. Libraries are constructed so that duplication is detected and the library is linked in only oncethere is no cost in terms of efficiency. This feature will be discussed later in the text.
Review 17
Add to the utility library a function Signature() that displays a declaration of authorship: This program was written by Liam Carr.
Review 18
The random() function in random.h is sometimes inconvenient to use since it only generates values between 0 and one less than its integer argument. Add to the utility library a function RandomInRange() that takes integer parameters Lo and Hi and returns a random number in the range Lo..Hi. Write a program that illustrates its use.
/*Time Conversion program with prototypes */ #include <iostream.h> //-------------------------------------------------------------------------------void DaysToHours(); /* Converts days to hours */ void HoursToDays(); /* Converts hours to days */ //-------------------------------------------------------------------------------int main() { char Choice; cout << "1 Days to Hours" << endl; cout << "2 Hours to Days" << endl; cout << "Enter your choice: "; cin >> Choice; if (Choice == '1') DaysToHours(); else HoursToDays(); return return(0); } //-------------------------------------------------------------------------------void DaysToHours() /* Converts days to hours */ { int Days, Hours; cout << "Enter the number of days: "; cin >> Days; Hours = Days*24; cout << "The number of hours in " << Days << " days is: " << Hours; } //-------------------------------------------------------------------------------void HoursToDays() /* Converts hours to days */ { int Hours, Days; cout << "Enter the number of hours: "; cin >> Hours; Days = Hours/24; cout << "The number of days in " << Hours << " hours is: " << Days; }
This program will perform identically to the version at the beginning of this chapter. The advantage is that main() (the top in top-down design) is near the top of the program, making it easy to see what functions it calls. The disadvantage is that the prototypes make the program longer and must be updated each time a function changes, introducing the possibility of inconsistency.
Functions
5 19
Case Study
In this Case Study a game of 21 program will be created. Note that this game is the Advanced Exercise at the end of Chapter Four.
specification
The program asks the user how many cards are wanted. It then deals cards to the user which are random numbers from 1 to 10. The program then deals itself three cards. If both scores are over 21, or if both are equal but less than or equal to 21, the game is declared a draw. Otherwise, the winner is the one with the highest score equal to or less than 21. If one score is over 21, but the other is 21 or less, the player with 21 or less is declared the winner. The program allows the game to be played as often as desired. At the end of the games the program displays the total wins, losses, and draws. A sample run illustrates the game: How many cards do you want? 3 You: 8 5 1 = 14 Computer: 8 3 3 = 14 A draw! Would you like to play again? (Y/N)? Y How many cards do you want? 2 You: 7 2 = 9 Computer: 8 7 4 = 19 Computer wins! Would you like to play again? (Y/N)? Y How many cards do you want? 3 You: 8 7 4 = 19 Computer: 2 1 7 = 10 You win! Would you like to play again (Y/N)? N Your wins = 1 Computer wins = 1 Draws = 1
designlevel 1
The method for constructing this program will be top-down design. Through this approach, the main() function is written first. The major tasks to be accomplished are to play a game, maintain the wins, losses, and draws, determine if another game is to be played, and report the wins, losses, and draws. The pseudocode for main() is: Initialize counters do Play a game Update counters as needed Ask the user for another game while (the user wants to play again) Display the final results
5 20
5
codinglevel 1
To complete the design for main(), the pseudocode is used to determine the data design. Counters are needed for the wins, losses, and draws. A variable is needed to hold the result of a game. Another variable is needed to hold the result of prompting the user to play another game. At the first level of a top-down design, there are no details for accomplishing the major tasks. These details are addressed in the next level of refinement. The top-down design approach to programming dictates that main() be translated into code before continuing on to the next level of refinement. This will help resolve any ambiguities in the logic, and clearly identify the tasks remaining to be accomplished. The main() code is based on its pseudocode and data design:
int main() { int Wins = 0, Losses = 0, Draws = 0; char Answer; do { int Result; // 0=draw 1=user win 2=computer win Result = PlayGame(); UpdateCount(Result, Wins, Losses, Draws); Answer = AskRepeat(); } while ((Answer != 'N') && (Answer != 'n')); Report(Wins, Losses, Draws); return return(0); }
The main() function cannot be compiled because the functions that handle the major tasks of playing the game, maintaining the counters, and reporting are not yet written. However, we can make a compilable level 1 version of the program by adding stub functions which are functions with carefully written headers and empty bodies:
/* Game of 21 program */ #include <iostream.h> //-------------------------------------------------------------------------------int PlayGame() /*Plays one game of 21 and returns an indication of the winner Post: One game has been played, and a code returned indicating the winner: 0=Draw 1=user Won 2=Computer Won */ { } //-------------------------------------------------------------------------------void UpdateCount(int int Result, int &Wins, int &Losses, int &Draws) /*Increments one of the counters as determined by Result Pre: Result is either 0, 1, or 2 Post: Either Wins, Losses, or Draws has been incremented based upon whether Result is 1, 2, or 0 respectively */ { } //-------------------------------------------------------------------------------char AskRepeat() /*Asks the user if another game is desired and returns response Post: User has been asked and has responded with Y, y, N, or n. The response is returned. */ { }
Functions
5 21
//-------------------------------------------------------------------------------int Wins, int Losses, int Draws) void Report(int /*Reports the current results Pre: Wins, Losses, Draws represent the current results Post: The current results have been displayed */ { } //-------------------------------------------------------------------------------int main() { int Wins = 0, Losses = 0, Draws = 0; char Answer; do { int Result; // 0=draw 1=user win 2=computer win Result = PlayGame(); UpdateCount(Result, Wins, Losses, Draws); Answer = AskRepeat(); } while ((Answer != 'N') && (Answer != 'n')); Report(Wins, Losses, Draws); return return(0); }
This code will compile without error to produce a level 1 version of the program that can be refined. However, the stub functions generate a warnings indicating that parameters and variables are not used and values are not returned. At this point, the Case Study may be illustrated as:
Review 19
Without looking ahead, write a body for the function Report().
Review 20
Without looking ahead, write a body for the function AskRepeat().
Review 21
Without looking ahead, write a body for the function UpdateCount().
Review 22
Write a function Introduction() that gives the rules, etc. for the game of 21.
5 22
designlevel 2
In the next level of design, the functions called by main() are refined. The UpdateCount(), AskRepeat(), and Report() functions are straightforward in their design. The PlayGame() function is more complex. Using the top-down design approach, PlayGame() and the functions it calls will be designed and coded at this level. The pseudocode for PlayGame() is: Play user hand Play computer hand Determine winner Report result of the game The data design for PlayGame() is a variable to hold the score of the human hand, a variable to hold the score of the computer hand, and a variable to hold the winner.
PlayGame() designlevel 1
PlayGame() codinglevel 1
In the next level of the PlayGame() design, the functions called by PlayGame() designlevel 2 PlayGame() are refined. The DealUser() pseudocode is: Ask the user the number of cards For (CardCount=0, CardCount<NumCards, CardCount++) Get a card Add the card to the score Return the score The DealComputer() pseudocode is: For (CardCount=0, CardCount<3, CardCount++) Get a card Add the card to the score Return the score The FindWinner() pseudocode is: An else-if ladder comparing UserSum and Computer Sum Return a 0 for a draw, a 1 for a User win, and a 2 for a computer win The DealUser(), DealComputer(), and FindWinner() functions will be PlayGame() codinglevel 2 coded in the next level of coding for the program.
Functions
5 23
codinglevel 2
5 24
//-------------------------------------------------------------------------------int UserSum, int ComputerSum) int FindWinner(int /*Determines winner and returns code indicating winner. Post: Winner determined according to rules in the specification and code returned indicating the winner: 0=Draw 1=User Won 2=Computer Won */ { const int Limit = 21; if ((UserSum==ComputerSum) || ((UserSum>Limit) && (ComputerSum>Limit))) return return(0); else if ((ComputerSum>Limit) || ((UserSum>ComputerSum) && (UserSum<=Limit))) return return(1); else return return(2); } //-------------------------------------------------------------------------------void ReportResult(int int Result) /*Reports the result of the game Pre: Result is either 0, 1, or 2 Post: Result has been displayed. */ { if (Result == 0) cout << "A draw! \n"; else if (Result == 1) cout << "You win! \n"; else cout << "Computer wins! \n"; } //-------------------------------------------------------------------------------int PlayGame() /*Plays one game of 21 and returns an indication of the winner Post: One game has been played, and a code returned indicating the winner: 0=Draw 1=User Won 2=Computer Won */ { int UserSum = DealUser(); int ComputerSum = DealComputer(); int Winner = FindWinner(UserSum, ComputerSum); ReportResult(Winner); return return(Winner); } //-------------------------------------------------------------------------------void UpdateCount(int int Result, int &Wins, int &Losses, int &Draws) /*Increments one of the counters as determined by Result Pre: Result is either 0, 1, or 2 Post: Either Wins, Losses, or Draws has been incremented based upon whether Result is 1, 2, or 0 respectively */ { if (Result==0) Draws++; else if (Result==1) Wins++; else Losses++; }
Functions
5 25
//-------------------------------------------------------------------------------char AskRepeat() /*Asks the user if another game is desired and returns response Pre: none Post: User has been asked and has responded with Y, y, N, or n. The response is returned. */ { char Answer; cout << "Would you like to play again? (Y/N)? "; cin >> Answer; while ((Answer != 'Y') && (Answer != 'y') && (Answer != 'N') && (Answer != 'n')) { cout << "Answer Y or N please: "; cin >> Answer; } return return(Answer); } //-------------------------------------------------------------------------------void Report(int int Wins, int Losses, int Draws) /*Reports the current results Pre: Wins, Losses, Draws represent the current results Post: The current results have been displayed */ { cout << "Your wins = " << Wins << endl; cout << "Computer wins = " << Losses << endl; cout << "Draws = " << Draws << endl; } //-------------------------------------------------------------------------------int main() { randomize(); int Wins = 0, Losses = 0, Draws = 0; char Answer; do { int Result; // 0=draw 1=user win 2=computer win Result = PlayGame(); UpdateCount(Result, Wins, Losses, Draws); Answer = AskRepeat(); } while ((Answer != 'N') && (Answer != 'n')); Report(Wins, Losses, Draws); return return(0); }
Note that the utility library was included so that GetInt() could be used to obtain the number of cards desired by the user.
In developing such a large program, it is necessary to test subparts of the program in isolation. For example, to test the logic used in writing FindWinner(), main() was replaced with the following code:
while (true) { cout << "Enter User total: " << endl; cin >> UserSum; cout << "Enter Computer total: " << endl; cin >> ComputerSum; cout << "Result: " << FindWinner(UserSum, ComputerSum) << endl; }
5 26
This allowed any combination of sums to be entered to make sure that the program consistently gave the correct results. The test data included: User 21 15 23 23 15 21 10 10 18 24 Computer 21 15 25 23 10 18 24 15 21 10 Expected Result 0 0 0 0 1 1 1 2 2 2
It is best to try to include in the test data each possible way the program could execute, and also include edge cases. An edge case occurs when the data is right on the edge between two behaviors. In this case, the value 21 lies on the edge between a successful score and a score that is too high to win. In order to verify that <= was used when < is needed, the edge cases must be tested carefully. It can be difficult to read through a lengthy program such as this one. The best way to learn about a large program is to attempt to revise it, as in the Reviews below. When doing them, take careful note of what portions of the code need to be changed, and what portions do not. Note how the program organization makes it easier to make modifications.
Review 23
The cards dealt are unrealistic in that it is just as likely to draw a 1 as a 10 where in actuality 10s, Jacks, Queens, and Kings all count as ten-point cards. Modify the Case Study so that cards are drawn from 1 to 13, with cards 1 to 10 counting as their value, and cards 11 through 13 counting as ten points.
Review 24
Modify the Case Study so that the user is initially dealt two cards, and then is asked one-by-one for any additional cards. For example: You: 3 7 Another? Y 6 Another? N Total: 16
Review 25
Modify the Case Study so that the computer, rather than always taking three cards, takes cards one-by-one until the total reaches 16 or higher.
Functions
5 27
Chapter Summary
A function performs a single, well-defined task. User-defined functions can be written to extend the C++ language. A function is executed by calling it from main() or another function. The function call includes the function name and parentheses with any required parameters. A funcn statement. tion can return a single value through the retur eturn A function definition is the actual code of the function, and includes a header. The header begins with a keyword indicating what type of value the function returns. void indicates a function returns nothing. The header also contains a descriptive function name and any parameters required by the function. A functions parameters, also called arguments, can be value parameters, default parameters, or reference parameters. Value parameters can only pass values into a function. The variables representing value parameters are not changed by a function. Default parameters use a value assigned to a parameter in the function header when that parameter is not specified in a function call. Reference parameters pass values into and out of a function. Reference parameters are indicated with a preceding & in the function header. The variables representing reference parameters can be changed by a function. Function overloading is defining more than one function by the same name. Function overloading is allowed because the compiler evaluates the types, order, and number of parameters in a function call as well as the function name. The same method used to construct good programs should be used to construct functions. This method is specification, design, coding, and debugging and testing. The initial requirements of a function are called the preconditions. A correctly written function will satisfy a postcondition. A functions documentation should include a header with the precondition and postcondition as well as a description of the functions purpose. A library can be created by writing functions and saving them in a file traditionally named with a .h extension. This file can then be included in any program. User-defined libraries are enclosed with quotation marks in an include statement. One common method used in the construction of a large program is top-down design, also called step-wise refinement. In the top-down approach main() is constructed first and then the major tasks are refined. Refinement of tasks is done in levels with each level being coded and tested before continuing to the next level. One method of coding that emphasizes top-down design is using function prototypes. A function prototype is a statement that consists of the function header terminated by a semicolon. Function prototypes are included at the beginning of a program and allow main() to be defined before the bodies of the other functions.
5 28
Vocabulary
Actual Argument See Actual Parameter. Actual Parameter The variable or value being passed to a function through a function call. Argument See parameter. Call Including a function name and its parameters to execute the function. For example, DrawBar(2). Call-By-Reference Parameter See Reference Parameter. Call-By-Value Parameter See Value Parameter. Default Parameter A formal parameter with a default value that is used if the actual parameter is not specified in a function call. Edge Case A case in which program data is on the edge between two behaviors. Formal Argument See Formal Parameter. Formal Parameter The parameter type and name in the function header. Function C++ code written in a specific format to perform a single, welldefined task. Function Definition The actual code of the function. Function Overloading name. Defining more than one function by the same
Function Prototype A statement at the top of a program consisting of the function header terminated by a semicolon. Parameter Values included in a function call that are passed to the function. Precondition A statement that must be true at the beginning of a function for the function to work properly. Postcondition A statement that must be true at the end of the execution of a function if the function has worked properly. Reference Parameter A parameter that can receive as well as pass a value to a function. Top-Down Design A method for constructing a large program where the main() is written first and then the subtasks refined. Step-Wise Refinement See Top-Down Design. Stub Function A function header with no body that is used to create a compilable level 1 of a program. User-Defined Function A function written by the user. Value Parameter A parameter that passes only its value to a function.
Functions
5 29
C++
void
Used at the beginning of a function definition to indicate that a function returns nothing. Statement used to return a value from a function to the calling function.
& Used to indicate a reference parameter.
retur n eturn
5 30
Exercises
Exercise 1
/\ / \ /____\ | | |____| ** ********** Write a program that calls functions Roof(), Base(), and Walk() to display:
Exercise 2
a) Write a function Triangle() that takes a parameter and displays a right triangle with that many lines. Use the DrawBar() function as a basis. For example, the function call Triangle(4) displays: * ** *** **** b) Write a program using Triangle() to draw triangles of sizes 1, 3, 5, and 7, each separated by a blank line.
Exercise 3
Write a function IsoTriangle() that takes a size parameter and displays an isosceles triangle with that many lines. Use the DrawBar() function as a basis. (Hint: Use another function Spaces() to display the leading spaces before the start of the asterisks on each line.) For example, the function call IsoTriangle(4) displays: * *** ***** *******
Functions
5 31
Exercise 4
Write a function DisplayWithCommas() that displays any long up to 10 digits using commas. For example, 1234567 should be displayed as 1,234,567. Be sure your function correctly handles negative numbers as well.
Exercise 5
void DisplayFormatted (int int n, int Width) /*Displays the value of n left-aligned in a field of size Width. Post: Value displayed left-aligned in a field of size Width */
Write a program illustrating its use. b) Overload the DisplayFormatted() function to work for double values. In this case, include a width parameter and also a decimals parameter giving the number of decimals to display. c) Write a program illustrating both DisplayFormatted() functions. d) Add these functions to the utility library.
Exercise 6
A prime number is an integer that has no factors other than one and itself. For example, 2, 3, 5, and 7 are prime while 9, 10, and 15 are not. a) Write a function IsPrime() that accepts a long greater than 1 as a parameter and returns a bool. The function should return true if and only if the integer is prime. (Hint: An integer can be tested for primeness by repeatedly dividing it by integers smaller than itself but larger than 1, and checking whether the remainder is zero. Use the modulus operator, %.) b) Write a program that uses IsPrime() to display all the prime numbers between 2 and 100.
Exercise 7
Write a function GetChar(), modeled on GetInt(), that obtains a character from the user that falls within the two character arguments given. Use the header:
char GetChar(char char Lo, char Hi)
For example, the following code will return A, B, C, D, E, or F and assign it to Grade:
Grade = GetChar('A', 'F');
5 32
Exercise 8
a) Write a function BreakUp() that takes an integer in the range 0999 as a parameter and returns each of the digits in three integer reference parameters. b) Write a function Build() that takes three integer parameters and returns a value which consists of the number represented by the three digits. c) Write a program illustrating BreakUp() and Build() using the specification: Every number from 0 to 999 is first broken up and then rebuilt and the result compared to the original value. An error message should be displayed if the original and rebuilt numbers do not match.
Exercise 9
Programs such as racing programs must manipulate times in minutes and seconds. a) Write two utility functions, ReadTime() and DisplayTime(), that handle reading and writing of times. Test the functions with the code:
{ int Min, Sec; cout << "Enter a time: "; ReadTime(Min, Sec); cout << "Your time was: "; DisplayTime(Min, Sec); }
The program output may look similar to: Enter a time: Enter minutes: 65 Enter seconds: 32 Your time was 1:05:32 Note that the time was displayed in hours, minutes and seconds and that a zero was inserted when needed to display the proper number of minutes. b) Write a function AddTime() that takes two times in four parameters and returns their sum as a third pair of reference parameters. Test the function using the code:
{ int Min1, Sec1, Min2, Sec2, MinTot, SecTot; cout << "Enter first time: "; ReadTime(Min1, Sec1); cout << "Enter second time: "; ReadTime(Min2, Sec2); cout << "Your total time was: "; AddTime(Min1, Sec1, Min2, Sec2, MinTot, SecTot); DisplayTime(MinTot, SecTot); }
Functions
5 33
When run, the program output may look similar to: Enter a time: Enter minutes: 12 Enter seconds: 32 Enter another time: Enter minutes: 21 Enter seconds: 43 Your total time was: 0:34:15
Exercise 10
It is useful to have a program to manipulate fractions. a) Write a function Reduce() that takes the integer numerator and denominator of a fraction and reduces the fraction, changing the numerator and denominator as necessary. A fraction may be reduced by finding the largest common factor and dividing both the numerator and denominator by this factor. The function can be tested using the code:
{ int Num, Denom; cout << "Enter the numerator: "; cin >> Num; cout << "Enter the denominator: "; cin >> Denom; Reduce(Num, Denom); cout << "The reduced fraction is "<< Num << "/" << Denom << endl; }
When run, the program output may look similar to: Enter the numerator: 12 Enter the denominator: 16 The reduced fraction is 3/4 b) Write a program that adds two fractions, reporting the result in reduced form. Use functions ReadFraction(), DisplayFraction(), and AddFraction(). ReadFraction() and AddFraction() should return their fractions in reduced form using Reduce().
Exercise 11
Using a top-down design approach, write a program that displays one month of a calendar using the specification: The user enters the number of days in the month and the day of the week on which the month starts (1=Monday, etc.). The output for a 30 day month that starts on a Wednesday should be:
5 34
Sun Mon Tue Wed Thu Fri Sat ********************************************************* * * * * 1* 2* 3* 4* * * * * * * * * * * * * * * * * ********************************************************* * 5* 6* 7* 8* 9* 10* 11* * * * * * * * * * * * * * * * * ********************************************************* * 12* 13* 14* 15* 16* 17* 18* * * * * * * * * * * * * * * * * ********************************************************* * 19* 20* 21* 22* 23* 24* 25* * * * * * * * * * * * * * * * * ********************************************************* * 26* 27* 28* 29* 30* * * * * * * * * * * * * * * * * * * ********************************************************* a) Write a compilable level 1 version of the program. Be sure to document and write headers for the level 2 functions. b) Complete the program and debug and test it. Note: You should judge your program by how little redundant code it contains, and how easy it is to modify column widths and heights.
Exercise 12
The game of Nim is played as follows: The game starts with a random number of stones between 15 and 30. Two players alternate turns and on each turn may take either 1, 2, or 3 stones from the pile. The player forced to take the last stone loses. The computer version of Nim may be played as follows: The specification: The computer generates the random number of stones, and the user is allowed to go first. On each user turn, the program displays the current number of stones and asks for the number to be removed. On each computer turn, the program displays the number of stones and the number taken (a random number from 1 to 3.) When the last stone is drawn, the program displays the winner. Code should be included to prevent the user or the computer from trying to take an illegal amount of stones. In particular, neither should be allowed to take three stones when there are only 1 or 2 left. The program output may look similar to that shown on the next page:
Functions
5 35
There are 16 stones. How many would you like? 3 There are 13 stones. The computer takes 3. There are 10 stones. How many would you like? 4 Value must be between 1 and 3 How many would you like? 3 There are 7 stones. The computer takes 2. There are 5 stones. How many would you like? 3 There are 2 stones. The computer takes 1. There is 1 stone. How many would you like? 3 Value must be between 1 and 1 How many would you like? 1 The computer wins! a) Write a compilable level 1 version of the program. Be sure to comment and write headers for the level 2 functions. b) Complete the program and debug and test it. c) Advanced: Try to make the computer play smart rather than random. See if you can come up with a strategy that will allow the computer to win as often as the user.
Exercise 13
The game of Mastermind is played as follows: One player (the code maker) chooses a secret arrangement of colored pegs and the other player (the code breaker) tries to guess it. The code breaker puts forth an arrangement of colored pegs, and the code maker reports two numbers: 1. The number of pegs that are the correct color and in the correct position 2. The number of pegs that are the correct color regardless of whether they are in the correct position. a) Write a program that plays the part of the code maker in this game. The code will consist of an arrangement of 3 pegs each with a color from 1 to 5. The program output may look similar to: Guess 1: First peg: 3 Second peg: 4 Third peg: 2 You have 1 correct peg(s) and Guess 2: First peg: 3 Second peg: 4 Third peg: 5 You have 1 correct peg(s) and Guess 3: First peg: 3 Second peg: 5 Third peg: 4 You have 3 correct peg(s) and You have broken the code in 3 5 36
2 correct color(s)
3 correct color(s)
Note: For simplicity, do not allow either the guess or the code to contain duplicates. You should write a function that checks for duplicate pegs and use it to prevent duplicates. b) Write a compilable level 1 version of the program. Be sure to comment and write headers for the level 2 functions. c) Write the next level functions, and so on until the program is complete. d) Debug and test the program.
Exercise 14
a) Write a program that uses functions to solve the Random Walk problem from Chapter Four Exercise 30. Include a function that displays the bridge and the person. b) Modify the Random Walk program to display a table of bridge length vs. average time taken to step off of it. Use 50 trials for each bridge length, and try odd lengths from 5 to 21 meters long. The program output may look similar to: Length 5 7 9 ... 21 Average Time 5.6 7.2 8.0 ... 37.5
In generating this table, do not display the picture of the bridge. c) Advanced: See if you can determine what the relationship is between the length of the bridge and the time taken to fall off it.
Exercise 15
Write a program that plays a dice game with the user. The specification: The user begins with a score of 1000. The user is asked how many points to risk and then the computer rolls two dice. If an even total is rolled, the user loses the points at stake. If an odd total is rolled, the user receives double the points at stake. The program output may look similar to: You have 1000 points. Points to risk: 100 Roll is 3 and 5 You lose. Play again? Y You have 900 points. Points to risk: 200 Roll is 1 and 2 You win. Play again? N Final score: 1300
Functions
5 37
Exercise 16
Write a program which plays the game of Hi-Lo with the user. The specification: The user begins with a score of 1000. The user is asked the number of points to risk and to choose High or Low. The computer then chooses a random number between 1 and 13. If the number is between 1 and 6 inclusive, it is considered Low. If it is between 8 and 13 inclusive, it is considered High. The number 7 is considered neither High nor Low, and the user loses the points at risk. If the user guesses correctly, the user receives double the points. If the user guesses incorrectly, the user loses the points at risk. The program output may look similar to: You have 1000 points. How many points to risk: 100 Predict (1=High, 0=Low): 1 Number is 3 You lose. Play again? Y You have 900 points. How many points to risk: 200 Predict (1=High, 0=Low): 1 Number is 11 You win. Play again? N Final amount: 1300
Exercise 17
Chapter Four Exercise 31 described a simple form of animation. This sort of work can be simplified by using a function that draws the figure at a specific location. Modify the program using a function with the following header:
void SmileyFace(int int x, int y, bool Black) /*Draws a simple smiley face with upper-left corner at position x, y on the screen. If Black is true, the face is drawn with black characters. If Black is false, the face is drawn with blanks, effectively erasing the face. Pre: x and y are valid screen coordinates Post: Face is drawn with either black characters or blanks
*/
Exercise 18
Write a program that runs a random horse race. The specification: There are three horses. During each round, a random number from 1 to 100 is generated for each horse. The horse advances one square if the random number is greater than 50. Show the track this way: 1|--------H------| 2|-------H-------| 3|---------H-----| Write a function ShowHorse() that takes a horse number (1 to 3) and a position on the track, and shows the current position of the horse. Have the program run until one of the horses reaches the finish line.
5 38
Advanced Exercise 19
Computers have been widely used to test students on their ability to solve arithmetic problems. Write a program that will test a student on addition, subtraction, or multiplication using random integers between 1 and 100. The student begins by choosing the type of problem and is then asked 10 problems with 3 chances to answer each correctly. If after 3 chances the answer is still incorrect, the correct answer is displayed. A score is calculated by awarding 10 points for a correct answer on the first try, 5 points on the second try, 2 points on the third try, and 0 points if all three attempts are wrong. The program output may look similar to: Enter 1. 2. 3. the number for the problem type desired. Addition Subtraction Multiplication
Enter choice: 1 25 + 73 = 79 WRONG Try again. 25 + 73 = 98 CORRECT 12 + 94 = 106 CORRECT 15 + 6 = 19 WRONG Try again. 15 + 6 = 18 WRONG Try again. 15 + 6 = 20 You have missed 3 times. The answer is 21. 36 + 49 = 85 CORRECT ... 17 + 65 = 82 CORRECT Your score = 70
Functions
5 39
5 40
6
Objectives
After completing this chapter you will be able to: 1. Understand classes and objects including the concepts instantiation and member function. 2. Use classes in programs. 3. Use String class member functions. 4. Use the ios class. 5. Understand constructors. 6. Pass an object as a parameter. 7. Use the PegClass class. 8. Write a program to solve the towers of Hanoi puzzle. 9. Use the TopListClass class.
6
key skill in object-oriented programming is learning how to use classes that have been written by someone else. In this chapter you will learn how to use classes and objects in the construction of programs. The String class, two utility classes, and the cout and cin objects will be used. In Chapter Ten you will learn how to create classes.
defines a variable of type double with the identifier Radius. Just as user-defined functions extend the C++ language so do userdefined types. A user-defined type is called a class. A class is used to create an object. Objects are declared with the name of the class followed by an identifier. For example, the statement
CircleClass B;
instantiation
declares an object of class CircleClass with the identifier B. Declaring an object is often called instantiation. In this case, B is an instance of CircleClass. Several instances of CircleClass can be created at once:
CircleClass LeftCircle, MiddleCircle, RightCircle;
A variable has just one value associated with it. However, an object has all the properties of its class associated with it. Properties of a class include member functions.
member function
A member function is a function belonging to a class. It is also sometimes called a method of the class. A member function is called by giving the objects identifier, a period, and then the function name and any needed arguments. For example, CircleClass has member functions SetRadius() and Area() that can be used in statements similar to
double Radius; cout << "Enter radius:"; cin >> Radius; B.SetRadius(Radius); cout << "Area is " << B.Area() << endl;
61
programming style
Classes can be given a descriptive name that ends with the word Class as good programming style. This naming procedure makes it easy to know when an identifier is associated with a class. CircleClass, like PegClass and TopListClass, was written for demonstration purposes. CircleClass has member functions SetRadius(), Area(), and Circumference(). The following program demonstrates classes:
/* Classes Demonstration Program */ #include <iostream.h> #include <lvp\circle.h> int main() { cout << "-Calculate the area of a circle-" << endl; cout << endl; CircleClass B; double Radius; cout << "Enter radius: "; cin >> Radius; B.SetRadius(Radius); cout << "Area = " << B.Area() << endl; cout << "Circumference = " << B.Circumference() << endl; return return(0); }
When run, the program displays: -Calculate the area of a circleEnter radius: 10 Area = 314.159 Circumference = 62.8318
62
creates two instances of the String class. The author of the String class has written the class so that its objects can be displayed on the screen, assigned values that are read from the user, used in assignment statements, and passed as arguments to functions.
length()
The String class has a member function length() that returns the length of the string stored by a string object. For example, the statements
String FirstName = "Samuel"; cout << FirstName.length() << endl;
substr()
Another string member function is substr() that returns part of the string stored by a String object. The part returned is specified with one argument that gives the starting position and another argument that gives the number of characters to return. Positions in a String object are counted from the left, starting with zero: Characters: Position: S 0 a 1 m 2 u 3 e 4 l 5
of FirstName consisting of characters in positions 3, 4, and 5. The precondition of substr() is that a substring be a valid part of the String object.
find()
A third string member function is find() that takes a String argument and returns the position of the first occurrence of this string in an object. For example, the statements
String FirstName = "Samuel"; cout << FirstName.find("mu") << endl;
display 2
63
indicating that the string mu was found starting in position 2 of FirstName. If the string is not found, then find() returns a special constant value, npos. For example, the statements
String FirstName = "Samuel"; if (FirstName.find("pi")==npos) cout << "Not found." << endl;
display Not found. The find() function is overloaded so that it can also be called with a character argument. For example, the statements
String FirstName = "Samuel"; cout << FirstName.find('e') << endl;
A member function c_str() returns a C-style (not C++) string. This function is sometimes needed when using strings with functions from other libraries. For example, a useful function in the stdlib library is atoi(). This function converts a string to an int. Similarly, the atof() function in stdlib converts a string to a double. Both of these functions require a C-string parameter. atoi() is used in the code below:
String s; cout << "Enter an integer: "; cin >> s; cout << s << " doubled is " << (2*atoi(s.c_str()));
A class can include operator member functions that redefine, or overload, the built-in C++ operators. The String class contains many of these functions. For example, the addition operator (+) is overloaded to return a string consisting of concatenated String objects, as in the statements
String Part1 = "wood", Part2 = "chuck", Whole; Whole = Part1 + Part2; cout << Whole << endl;
+=
Similarly, the special assignment operator, +=, concatenates one string onto the end of another. For example, the statements
String FirstName = "Samuel", LastName = "Clemens", Whole = ""; Whole+=FirstName; Whole+=" "; Whole+=LastName; cout << Whole << endl;
Review 1
Write a function WriteFirstLast() that takes a String argument containing a name in last-commafirst format (e.g., Twain, Mark) and displays it in first-last format (e.g., Mark Twain). Use the find() function to identify the position of the comma, and the substr() function to display the parts. Assume there is a space after the comma.
Review 2
Write a function ConvertToFirstLast() that returns (not displays) a first-last formatted string corresponding to a last-comma-first string sent as an argument. See Review 1 for the definition of first-last and last-comma-first formats.
which will output the string Hello, world! to the console (the cout object.)
There are also constant data members defined in the ios class. To use these constants, they must begin with a prefix ios:: to indicate the source of the constant. For example, ios::fixed is a constant used as an argument to the setf() member function. Others include ios::left and ios::right.
6.5 Constructors
A class automatically executes a constructor member function whenever an object of that class is instantiated. Constructors make sure that objects of the class are properly initialized. A constructor member function can be given values through parameters. An argument to the constructor may give an initial value to the object, or specify its size, or some other aspect of the object. This allows variations on the object instantiated. For example, a String object may be instantiated with the declaration
String FirstName("Samuel");
which creates an object FirstName with the value Samuel. Constructors, like any function, can be overloaded. Commonly, classes have a number of different constructors. In the statement above, a String class object was created by passing an argument to the constructor. This was possible because the class contains a constructor with no arguments and a constructor with a String argument.
65
const parameter
As with any const value, the compiler will prevent the value of Word from being changed within the function. Any attempt to change the value should generate a compiler error. However, because this is a recent feature of C++, some compilers generate a warning rather than an error.
Functions
void AddRing(int int Size); /*Adds a ring of Size to peg. Post: Ring of size Size added to peg int RemoveRing(); /*Removes a top ring on peg and returns its size. Pre: Peg is not empty Post: Top ring on peg removed and its size returned int TopRing(); /*Returns size of top ring (or 0 if none) Pre: Peg is not empty Post: Size of top ring on peg returned */ int RingsOnPeg(); /*Returns number of rings on peg Post: Number of rings on peg returned */
*/
*/
66
void ShowAll(); /*Shows all declared and configured pegs Post: All declared and configured pegs are displayed */
To instantiate P and Q, parameters must be included to display the pegs. At the first call to Pause(), three rings have been added to the pegs and the following displayed. Note how only one call to ShowAll() displays all the PegClass objects: | | | | | | | | XXXXX|XXXXX XXXX|XXXX XXXX|XXXX XXX|XXX XXX|XXX XX|XX -------------------------------Press a key to continue The first ring, of size 3, ends up on the bottom. At the second call to ShowAll(), two rings have been removed: | | | | | | | | | | | XXX|XXX XXX|XXX XX|XX --------------------------------
67
Review 3
Assume the following code is in the main() function of a program that includes the pegclass library. Sketch the status of the pegs at the end of the program and indicate the output generated by the last statement:
PegClass P(7), Q(5); for (int int i=1; i<=5; i++) { P.AddRing(i); Q.AddRing(3); } P.RemoveRing(); cout << P.TopRing() << " " << Q.TopRing() << endl;
Review 4
What effect would the following statement have as the last statement in the program above?
P.AddRing(Q.RemoveRing());
Review 5
Write a function TotalRings() that takes three pegs as arguments and returns the total number of rings on the three pegs. Write a program that uses PegClass to create three pegs of height 8 and tests the TotalRings() function by placing a number of rings on the various pegs and then calling the function. Note that pegs cannot be passed as value parameters.
68
/*Towers of Hanoi program. Demonstrates the solution to a three-ring puzzle */ #include <lvp\pegclass.h> #include "utility.h" //-------------------------------------------------------------------------------void MoveRing(PegClass &FromPeg, PegClass &ToPeg) /*Moves a ring from the FromPeg to the ToPeg Pre: FromPeg is not empty Post: A ring has been moved */ { int Size = FromPeg.RemoveRing(); ToPeg.AddRing(Size); } //-------------------------------------------------------------------------------int main() { PegClass Left(7), Middle(7), Right(7); const int NumRings = 3; // Fill Left ring with NumRings, starting with biggest int Ring=NumRings; Ring>=1; Ring--) for (int Left.AddRing(Ring); MoveRing(Left, Middle); Pause(); Left.ShowAll(); MoveRing(Left, Right); Pause(); Left.ShowAll(); MoveRing(Middle, Right); Pause(); Left.ShowAll(); MoveRing(Left, Middle); Pause(); Left.ShowAll(); MoveRing(Right, Left); Pause(); Left.ShowAll(); MoveRing(Right, Middle); Pause(); Left.ShowAll(); MoveRing(Left, Middle); Pause(); Left.ShowAll(); return return(0); }
The MoveRing() function changes the status of the two pegs passed to it by moving a ring off or on. Therefore, the peg objects are reference parameters. Since the code demonstrates the moves, a static diagram would poorly illustrate the output. If possible, run the program and view the output.
Review 6
Write a function FillPeg() that takes a peg P and an integer N as arguments. It should add N rings to the peg, from size N down to 1. Show how this could be used in the program above. Reviews 7 through 9 develop a version of the Towers of Hanoi program that allows the user to solve the puzzle.
Review 7
Write a function GetUserMove() that asks the user for a source peg and a destination peg (L, M, or R) and returns the input as two reference parameters.
Review 8
Write a function MakeUserMove() that takes two characters representing the user move and the three pegs as arguments and moves the ring as desired by the user.
69
Review 9
Modify main() in the Towers of Hanoi program to use the functions in Reviews 7 and 8 to allow the user to play until Middle.RingsOnPeg() == NumRings.
Functions
void AddItem(long long Score, String Name); /*Adds a score and name to the list if Score ranks in the list, otherwise does nothing. Post: A score and name have been inserted if score is greater than any of the current scores */ int Rank); String GetName(int /*Determines the Name in Rank position in the list. Rank of 1 is the highest score. Pre: Rank is in range 1 to maximum number of items in list. Post: Name in Rank position returned */ long GetScore(int int Rank); /*Determines the Score in Rank position in the list. Rank of 1 is the highest score. Pre: Rank is in range 1 to maximum number of items in list. Post: Score in Rank position returned */ void Clear(); /*Clears TopListClass object back to empty items. Post: List contains only scores of 0 and names of Empty */ int GetListSize(); /*Determines the number of items that can be stored in the list Post: The number of items that can be stored in the list returned */ void Display (ostream os); /* Displays list to output stream Post: Names and Scores displayed */
6 10
int main() { TopListClass DemoList("samplist.dat"); DemoList.Display(cout); // Display current scores to console String Name; const String Sentinel = "END"; long Score; while (true) { cout << "Enter your name (" << Sentinel << " to end): "; getline(cin, Name); if (Name == Sentinel) break break; cout << "Enter your score: "; cin >> Score; cin.ignore(80, '\n'); DemoList.AddItem(Score, Name); DemoList.Display(cout); } return return(0); }
6 11
Empty 0 Empty 0 Empty 0 Empty 0 Empty 0 Enter your name (END to end): Vickie Enter your score: 910 Tristan 1200 Vickie 910 Marie 825 Empty 0 Empty 0 Empty 0 Empty 0 Empty 0 Empty 0 Empty 0 Enter your name (END to end): END
The program stores the list on disk using the file name given. This way the list is maintained from one run to the next. Note how a class can make file manipulation transparent: code to open the disk file, load information from the file, and store it, is executed almost invisibly. The DemoList is displayed by simply inserting it into the cout stream. This generates legible, but poorly formatted output. A better approach would be to use the GetName() and GetScore() member functions to obtain the information and then display it formatted. This task is presented as Review 10.
Review 10
Write a function PrintFormatted() that takes TopListClass P as its argument and displays a neatly formatted table from rank 1 to the highest rank stored. Use GetName(), GetScore(), and GetListSize() member functions, and cout.width() in the function.
Review 11
Write a function with the following header:
bool NewPersonalBest(String Name, long Score, const TopListClass &TL) /*Returns true if and only if Score is higher than any other score in TL associated with Name, and Name appears in TL somewhere. Post: true returned if Name's score is higher than a previous score by Name */
The idea is that the player has previously made the list, but now has a new score that is higher than any previous score achieved.
Review 12
Modify the TopListClass demonstration program to use a list of only five items. Write a main() that tries to insert more than five items to verify that TopListClass objects restrict the list to the top five scores.
6 12
Review 13
Run the TopListClass demonstration program and then open the data file produced (e.g., samplist.dat) to see how the list is stored. What would the file look like if the only items inserted were a score of 3141 for Euclid and a score or 2718 for Euler? Does it matter in which order the scores were inserted?
Case Study
In this Case Study, data from a college database will be displayed.
specification
Use the information in a database of colleges to produce a list of the five colleges with the highest enrollments and display the average enrollment of all the colleges in the database. The CollegeClass class, implemented in the college library, provides access to a database of over 400 colleges. The CollegeClass documentation follows: CollegeClass (college.h) Constructor
CollegeClass(); /*Opens a database file on disk making the first item the current item. Post: First item of database is current item */
Functions
bool GetNext(); /*Move to next item in database (next college); returns false if fails Post: Next item in database is current item or false returned */ bool CurrentIsValid(); /*Returns true if current item is valid (i.e. not past end of database) Post: true returned if current item is valid void Reset(); /*Moves back to the start of the database Post: First item of database is current item */ // These functions obtain information from the current item String GetName(); String GetTown(); String GetState(); String GetPubOrPri(); // Public or Private long GetEnrollment(); long GetTuition(); long GetRoomAndBoard();
*/
Operators << Inserts the data from the current item into the output stream
design
The specification requires a list of the top five colleges by enrollment. This is a natural task for a TopListClass object. To output a formatted list a user-defined function WriteTopColleges() is required. The specification also requires the average enrollment of all the colleges in the database. The algorithm for this is count the colleges, sum their enrollments, and then divide the total enrollments by the total number of colleges.
6 13
Using the CollegeClass class, the TopListClass class, and the algorithm for the average enrollments, the Case Study pseudocode becomes: while CurrentIsValid() Add college to count of colleges Add enrollment of college to sum of enrollments Insert college in toplist GetNext() Display average enrollment Display list of top 5 colleges by enrollment
coding
6 14
When run, the program displays: Average enrollment over 452 colleges: 10454 Ohio State University 38958 Indiana University - Bloomington 35551 Texas A&M University 33479 Arizona State University 31906 Pennsylvania State University Park 31732 It is impressive to see how just forty lines of code (including documentation) can, with the judicious use of classes, solve a complex task.
Review 14
Modify the Case Study so that the average enrollment and top five schools by enrollment are displayed for just the state specified by the user.
Review 15
Modify the Case Study so that it displays a list of the top five colleges by tuition cost and another list of the top five by enrollment. Use the WriteTopColleges() function for both lists.
Review 16
Predict what would happen if the statement EnrollmentList.Clear() were removed from the main function and the program executed several times. Then test your prediction by actually removing the line and running the program.
Chapter Summary
Classes are user-defined types that extend the C++ programming language. A class is used to create an object. When an object is created it is said to be instantiated. Objects can be used like other variables. When an object is used as a parameter, it is usually best to pass it as a const parameter which is a reference parameter that is not allowed to change. Classes contain member functions that define the properties of an object of that class. Operator member functions overload the built-in C++ operators. A constructor member function is automatically called when an object is instantiated. Constructors can have parameters that specify the aspects of an object, and a constructor can be overloaded. Classes can also contain member constants. The String class contains a length() member function that returns the number of characters in the calling String object. The substr() function, also in the String class, returns a part of the String object. The find() function returns the position of a character or string in the calling String object. The c_str() function returns a C-style string, and is useful when using functions atoi() and atof() from stdlib which require C-style parameters. The String class also overloads the + and += operators. The ios class is in the iostream library. cin and cout are predeclared objects. The ios class also defines the << and >> operators, and contains several constants.
6 15
The PegClass class has a constructor that requires parameters. When a class has a constructor that requires parameters, the parameters must be given to instantiate the object. The PegClass class is useful for solving the Towers of Hanoi puzzle. The TopListClass class is useful for storing data in a file. A game program often uses this approach for storing top scores. This class was also useful for maintaining a list of items that met certain requirements, as in the Case Study which printed the top five colleges by enrollment.
Vocabulary
Class A user-defined type. Constant Data Member A constant belonging to a class. Constructor A member function that is automatically called when an object is instantiated. Instance An identifier associated with a class. Instantiate Declare an object. Member Function A function that belongs to a class. Method Sometimes used to refer to a member function. Operator Member Function A member function that overloads a C++ built-in operator. Object An instance of a class.
C++
+ Overloaded operator in the string class that concatenates strings. += Overloaded operator in the string class that concatenates strings.
atof() A stdlib library function that returns a double from a C-style string. atoi() A stdlib library function that returns an int from a C-style string. c_str() A String member function that returns a C-style string. CollegeClass A class in the college library that is used to view the information in a college database.
const
Keyword used to define an object as a parameter that cannot be changed. find() A String member function that returns the position of a character or string in the calling String object. ios A class in the iostream library that is used for input/output. length() A String member function that returns the number of characters of the calling String object. PegClass A class in the pegclass library that is used for creating and displaying pegs.
6 16
substr() A String member function that returns a substring of the calling String object. TopListClass A class in the toplist library that is used to create a file of data items.
6 17
Exercises
Exercise 1
Vote YES! then ote YES! V then te YES! Vo and so on. a) Write a function RotateOne() that takes a string parameter and returns it with one character moved from the left to the right as illustrated above. (Hint: Be sure the message includes a space at the end so the words do not run together in the scroll.) b) Write a program that displays 10 sequences of a message. c) Write a program that asks the user for a message and then uses gotoxy() to display it as a scrolling message at the top of the screen. You may need to include a delay loop to slow down the scrolling process. A simple one is:
for (long long i=1; i<=2000000; i++);
A Scrolling message display shows a message with characters entering from the right. For example, if the message is Vote YES!, the display first shows
This loop does nothing for 2,000,000 iterations which causes a brief pause in the program.
Exercise 2
Write a function Reverse() that returns a string containing the reverse of its string parameter, e.g. Testing returns gnitseT.
Exercise 3
a) When an integer expression with a value between 65 and 90 is cast into a char the char(65); displays an A. Write a result is an uppercase letter. For example, cout << char function RanWord() that returns a word formed of random letters, of the length given as a parameter. Use the function header:
int NumLetters) String RanWord(int /*Returns a word of length NumLetters formed of random letters Pre: NumLetters >= 1, randomize() has been called Post: Random word of length NumLetters returned */
b) Write a program to display 5 six-letter words. c) Modify RanWord() so that it always returns words with at least one vowel. Have the function do this by repeatedly generating words until a word with a vowel (A, E, I, O, U) is generated.
6 18
Exercise 4
Write a function IsPalin() that returns true if and only if its string parameter is a palindrome. A palindrome is any word that is spelled the same backwards and forwards, for example DAD.
Exercise 5
Reading of numeric values from the user is error-prone. If the user mis-types by entering a letter the program may behave unpredictably. Use the atoi() and atof() functions to create more robust functions GetInt() and GetDouble() which read a string, and convert it to the numeric value to be returned. Test these functions, and then add them to the Utility library.
Exercise 6
It is often necessary to ask a user for a character input, and then to check it against a list of valid entries. This is cumbersome when a condition contains many choices, as in the code:
char Choice; cout << "Enter your choice (A, B, or C): "; cin >> Choice; while ((Choice != 'A') && (Choice != 'B') && (Choice != 'C')) { cout << "Choose from among A, B, and C" << endl; cin >> Choice; }
*/
GetChoice() should display error messages until the user enters a valid character, and allow the code above to be rewritten as:
cout << "Enter your choice (A, B, or C): "; char Choice = GetChoice("ABC");
Exercise 7
In many applications it is necessary to take a string containing a command and divide it into pieces for further processing. Usually those pieces are separated by blanks. For example, the string Pick up 2 sticks would be divided into 4 pieces: Pick, up, 2, and sticks. a) Write a function ExtractFirstWord() using the following header:
void ExtractFirstWord(String &Sentence, String &Word) /*Removes the first word from Sentence and returns it in Word. Pre: Words in Sentence are separated by blanks Post: First word of Sentence returned with blanks before and after word discarded. Sentence returned with first word and spaces before and after the word removed. Sentence and Word returned as empty strings if Sentence contained no words. */
6 19
Exercise 8
It counts and reports the number of moves taken by the user. It allows the user to give up by entering a peg of Q. It provides an option to specify the number of rings at the start (3 or 4).
Exercise 9
Modify the Towers of Hanoi program developed in Reviews 7 through 9 so that it counts the number of moves taken by the user and maintains a top scorer list. Note that since TopListClass ranks the highest score as best, and in this case the lowest score is to be considered the best, some creative programming is required. Store the number of moves by subtracting from 1000 first. That is, a score of 12 moves is stored as 988 (100012). When printing the list of top scores, reconvert the scores by subtracting from 1000 (1000988).
Exercise 10
One variation of the game of Nim, described in Chapter Five Exercise 12, is played with four pegs. Initially, the pegs contain 1, 2, 3, and 4 rings (all rings are the same size). On each turn, a player may take 1, 2, or 3 rings from a single peg. The player who takes the last ring loses. Write a program that uses the pegclass library to allow two players to play Nim. Be sure the program allows only legal moves. A typical screen may look similar to: | | | | | | | XXX|XXX | | XXX|XXX XXX|XXX | XXX|XXX XXX|XXX XXX|XXX XXX|XXX XXX|XXX XXX|XXX XXX|XXX ------------------------------------ ------------Player 1: Choose a peg: 3 Choose the number to take: 2
Exercise 11
Modify a game program from a previous Exercise to include a top scores list. 6 20
Exercise 12
Use the TopListClass class in a program that tracks results of a gymnastics competition. Names of up to 20 competitors and their numerical scores are entered, and at the end of the competition, a full list of all competitors and their scores is displayed. Finally the names of the Gold, Silver, and Bronze winners are displayed. Note: Gymnastics scores are usually given to one decimal place (1.0 to 10.0), but a TopListClass object only stores integer values. Multiply the scores by 10 before storing them, and divide by ten before displaying them.
Exercise 13
Modify Exercise 12 to include several different events: Balance Beam, Floor Exercises, and Uneven Bars. Provide the user with a menu of options: A. B. C. D. E. F. Enter Balance Beam result Enter Floor Exercises result Enter Uneven Bars result Display all current standings Display all medal winners Quit
Exercise 14
Modify the Case Study so that the average and top enrollment lists are generated for public schools, private schools, and both. Have the program also provide a count of the number in each category.
Exercise 15
Modify the Case Study so that it gives the average and top five colleges based upon the total cost combining tuition and room and board.
Exercise 16
Write a program that displays the names of the lowest tuition and highest tuition colleges in the college database. Refer to the CollegeClass class used in the Case Study. You do not need to use TopListClass for this program.
Exercise 17
Write a program that uses the CollegeClass class from the Case Study to allow the user to search for information on a given college. Have the program require the user to enter just the first few letters of the college name, and then display the information on all colleges that match these letters. (Note that the names of some colleges are stored in the form: Foobar, University of)
6 21
Exercise 18
a) The college database used in the Case Study stores many college names in the form: Foobar, University of. Write a function that converts names in this form to University of Foobar. The function should return college names that do not originally contain commas as unchanged. b) Modify the Case Study to include the function from part (a).
Advanced Exercise 19
Use the CollegeClass class from the Case Study to write a Find-a-College program that asks the user a number of questions, and then displays the names of all colleges that match the responses. For example: A. Public B. Private C. Either Enter choice: B A. Large (above 2000) B. Small (below 2000) C. Either Enter choice: C Enter maximum tuition: 12000
Colleges fitting your criteria are: American University of Puerto Rico Baldwin-Wallace College ...
6 22
7
Objectives
After completing this chapter you will be able to: 1. Use the mathematical (trigonometric, logarithmic, exponential) functions contained in the math library. 2. Avoid problems created by roundoff error. 3. Round a double value to the nearest integer. 4. Write recursive functions. 5. Use the ASCII code. 6. Use enumerated types. 7. Control program flow with the switch statement.
7
he earliest uses for electronic computers were largely mathematical. One of the very first programming languages was called FORTRAN which means FORmula TRANslator. C++, like all modern languages, provides special facilities for performing mathematical tasks.
The pow() and sqrt() functions can also be called with integer arguments. When this is done, int values are promoted to double if needed. The abs() and fabs() functions should be used with int and double arguments respectively. The abs() function was not overloaded to handle both types because the math library is carried over from traditional C programming where overloading is not possible. Note carefully the preconditions. If they are violated in a call to one of these functions, the program will terminate with an error message.
71
The arguments to these functions are assumed to be in radians. A value in degrees may be converted to radians using the formula:
ValueInRadians = (PI/180)*ValueInDegrees;
To demonstrate the trigonometric functions, the following program displays a table of sine and cosine values for angles from 0 to 90 degrees, stepping by 5 degrees:
/* Sine and Cosine program. Displays a table of sine and cosine values for various angles from 0 to 90 degrees */ #include <math.h> #include <iostream.h> int main() { const double PI = 3.14; const int Width = 6; const int Precision = 3; cout.setf(ios::fixed); cout.precision(Precision); const int MaxAngle = 90; const int AngleStep = 5; cout << " Angle sin() cos()" << endl; for (int int Angle=0; Angle<=MaxAngle; Angle+=AngleStep) { cout.width(Width); double RadAngle = (PI/180)*Angle; cout << Angle; cout.width(Width); cout << sin(RadAngle); cout.width(Width); cout << cos(RadAngle); cout << endl; } return (0); }
72
When run, the program output looks like: Angle sin() 0 0.000 5 0.087 10 0.174 15 0.259 20 0.342 25 0.423 30 0.500 35 0.574 40 0.643 45 0.707 ... cos() 1.000 0.996 0.985 0.966 0.940 0.906 0.866 0.819 0.766 0.707
Mathematical work often requires finding the angle that corresponds with a trigonometric value. This is called the inverse trigonometric function, also supplied in the math library:
double atan(double double x); /* Post: The arctangent of x in radians returned -PI/2 < atan() < +PI/2 */ double asin(double double x); /* Pre: -1 <= x <= 1 Post: The arcsine of x in radians returned -PI/2 < asin() < +PI/2 */ double acos(double double x); /* Pre: -1 <= x < = 1 Post: The arccosine of x in radians returned 0 < acos() < +PI */
73
Review 1
Write a program to display powers of 2 in a table like the following: 2^1 2^2 2^3 ... 2^10 2 4 8 1024
Review 2
Write a function PerfectSquare() that takes an integer argument and returns true if and only if it is a perfect square. You can determine this by finding the square root, rounding it, then squaring the result, and checking to see if it is equal to the original number. Write a program that calls PerfectSquare() for integers 1 through 20 and displays the result.
Review 3
Modify the Sine and Cosine program so that it displays a fourth column that displays the sum of the squares of the sine and cosine values.
It appears that equal should be displayed since 4.80 times 100 is 480. However, this code displays not equal. The number 4.80 cannot be exactly represented in binary. Therefore, when 4.80 is multiplied by 100 this rounding error becomes large enough so that it is slightly different from 480. The following code demonstrates this:
cout << (4.80*100 480) << endl;
74
7
tolerance
Though a very small number (0.0000000000000177636) it is enough so that 4.80*100 is not exactly 480. A simple rule should be followed when comparing noninteger values: Never use == or != in comparisons. The result will often be unexpected. If two double values must be compared for equality, use a tolerance, an acceptable difference. For example, instead of:
if (x == y)
write:
if (fabs(xy) < 0.00001)
This way if the difference between x and y is very small (smaller than the tolerance, 0.00001), then the condition will be true.
Review 4
Modify the Round() function in Section 7.6 so that is works correctly for negative numbers. For example, Round(1.6) should return 2, and Round(1.4) should return 1, and so on.
Review 5
Overload the Round() function in Section 7.6 by writing a new version with the following header:
double Round(double double x, int NumDecimals) /* Returns x rounded to the NumDecimals decimal places Post: x to NumDecimals decimal places returned */
75
Review 6
Predict the behavior of the following code:
double S = 0; do { S += 0.1; cout << "Value is " << S << endl; } while (S != 1);
7.7 Recursion
A function can include calls to itself. This process is called recursion and the calls are referred to as recursive calls. Recursion is a programming technique that can be used whenever a problem can be solved by solving one or more smaller versions of the same problem and combining the results. The recursive calls solve the smaller problems. One problem which has a recursive solution is raising a number to a power. For example, 24 can be thought of as: 24 = 2 * 23 which can be thought of as 23 = 2 * 22 which can be thought of as 22 = 2 * 21 which can be thought of as 21 = 2 * 20 which can be thought of as 1 In each case, the power problem is reduced to a smaller power problem. A more general solution is: xn = x * xn1 A function IntPower() that raises a number to an integer power to return an integer (as opposed to pow() which returns a double) could be written with the header:
long IntPower(long long x, int n)
infinite recursion
A call to find 28 returns 2 times 27, which returns 2 times 26, and so on. However, this statement has no place to stop! This is called infinite recursion and clearly is not desirable. To provide a solution, recursion requires a case that has no recursive solution. In this problem, when n is zero the answer is simply 1. IntPower() then becomes:
long IntPower(long long x, int n) /* returns x to the power of n Pre: x and n are not both zero Post: x to the n returned */ { if (n == 0) return return(1); else return return(x * IntPower(x, n1)); }
76
Review 7
Rewrite IntPower() without using recursion and compare this solution to the recursive solution.
Review 8
IntPower() only works for positive values of n. Modify IntPower() to work with negative values of n using the solution:
Review 9
Write a recursive function Factorial() that returns the factorial (a long) of its int argument. The factorial of a positive integer is the product of it and all the positive integers less than it. For example, the factorial of 5 is 5*4*3*2*1 or 120. The symbol for factorial is the exclamation point, therefore 5! = 120. Computing this factorial can also be thought of as 5! = 5*4! or more generally, N! = N*(N-1)! By definition, 0! is equal to 1.
When the call Example(1) is made the if condition is false. This is the nonrecursive case which produces the output: Entering function, N = 1 Leaving function, N = 1 Now consider what happens when the call Example(2) is made. First, the cout statement displays Entering function, N = 2 and then the if statement is executed. The condition N>1 is true, therefore a recursive call, Example(N1), is made. Since N1=1, the nonrecursive call Example(1) produces Entering function, N = 1 Leaving function, N = 1 and then the statement after the if is executed, producing: Leaving function, N = 2 The total effect of the call Example(2) is to produce four lines of output: Entering function, N = 2 Entering function, N = 1 Leaving function, N = 1 Leaving function, N = 2
77
To review, the call Example(2) starts the N=2 function, then performs the N=1 function (via the recursive call), and then finishes the N=2 function. With this in mind, the call Example(3) can be predicted to produce: Entering function, N = 3 Entering function, N = 2 Entering function, N = 1 Leaving function, N = 1 Leaving function, N = 2 Leaving function, N = 3 The diagram below shows a recursive call tree for the call Example(3). Keep in mind that each call maintains its own, private, value for N:
Review 10
Using a recursive call tree diagram, illustrate the effect of the call IntPower(2, 3).
Review 11
Predict the output of the call Review(9):
void Review(int int N) { cout << "Entering function, N = " << N << endl; if (N > 0) Review(N/2); cout << "Leaving function, N = " << N << endl; }
78
The first and third steps are smaller versions of the three-ring problem. Instead of moving three rings, steps one and three only require two rings to be moved. Next, a recursive solution requires a case which has no recursive solution. For the Towers of Hanoi problem moving zero rings requires nothing at all. The pseudocode for the recursive Hanoi function is: if the number of rings is greater than zero move the top n1 rings from the source peg to the spare peg move the bottom ring from the source peg to the destination peg move the n1 rings from the spare peg to the destination peg Rather than referring to left, right, and middle pegs, the pseudocode refers to the source peg (from which the rings are to be moved), the destination peg (to which all the rings are to be moved) and the spare peg (available for temporary use during the transfer). During recursive calls, the pegs may change roles. For example, a source peg in one call may be a spare peg in another. The actual code is surprisingly concise. There are more lines of documentation than there are statements:
void Hanoi(int int NumRings, PegClass &SourcePeg, PegClass &DestPeg, PegClass &SparePeg) /* Moves NumRings rings from SourcePeg to DestPeg using SparePeg for temporary storage. */ { if (NumRings > 0) { // Move N1 rings to the SparePeg for storage Hanoi(NumRings1, SourcePeg, SparePeg, DestPeg); // Move the single big ring over MoveRing(SourcePeg, DestPeg); // Move the N1 ring back from SparePeg to destination Hanoi(NumRings1, SparePeg, DestPeg, SourcePeg); } }
The call Hanoi(3, L, M, R) where L means left peg, M means middle peg, and R means right peg, could be represented with the recursive call tree:
79
The Hanoi() function was modified to include a call to getch() after each move so that the action does not take place too quickly. This program illustrates the solution to the three-ring problem. However, by changing the value of NumRings, it will correctly show the solution to larger (or smaller) sized problems. A note of caution: the Towers of Hanoi problem requires over 1000 moves for the ten-ring problem! Recursion is a difficult concept and deep understanding takes time. Later we will present more examples and explanation, and your mastery of this technique will increase.
7 10
Review 12
Modify the Towers of Hanoi program so that the user is asked how many rings are desired. Build the pegs so that they hold just one more than the number of rings (e.g., if the user asks for three rings, build the pegs with height four.)
Review 13
Write a function HanoiMoves() that returns the number of moves required to solve the Towers of Hanoi problem with the number of rings given as an argument. Hint: To solve a five-ring Tower, you must solve two four-ring Towers and also move the base ring. The sum of all these moves is the total for the five-ring problem.
ASCII code
displays A. Conversely, casting a character into an integer results in the ASCII integer code corresponding to that character, as in the statement
cout << int int('A');
which displays 65. The following page contains the ASCII table for displayable characters. It is often useful to create a character constant to represent an ASCII value in a program. For example:
const char POUND = char char(163);
which displays:
Total cost is 200
7 11
7
230
space 32
D 68
G 71 H 72 I J K L 73 74 75 76
m 109
198
M 77 N 78 O 79 P R S T V X Y Z [ \ ] ^ _ ` a b c d e 80 82 83 84 86 88 89 90 91 92 93 94 95 96 97 98 99 100 101 Q 81
169
w 119
U 85 W 87
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
174
133 137
@ 64
188
7 12
creates a type called DayType that has seven possible values. By default, um list corresponds to the integer value representenum each identifier in an en ing the position in the list. In this case, Monday is equal to 0, Tuesday is equal to 1, Wednesday is equal to 2, and so on. An enumerated type must be defined before any functions that use it. Therefore, enumerated types are usually placed at the beginning of a program before any function definitions. The following statements show how an enumerated type might be used:
enum DayType {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}; DayType Today = Wednesday; // enum type in an assignment statement if (Today == Monday) cout << "Go to work." << endl; else if (Today == Saturday) cout << "Go to the beach!" << endl; for (Today = Monday; Today <= Sunday; Today++) // enum type counter DisplaySchedule(Monday); // enum type in a function call
display 2 rather than the string Wednesday as might be desired. To improve the usage of enumerated types, functions to read and write them should be written. For example, the PrintDay() function displays the string corresponding to the constants value:
void PrintDay(DayType Day) /* Displays a string corresponding to Day Post: string corresponding to Day displayed */ { if (Day == Monday) cout << "Monday"; else if (Day == Tuesday) cout << "Tuesday"; else if (Day == Wednesday)
The identifiers in an enumerated type may be assigned a value if the default values are not to be used. For example:
enum SummerType {June=6, July=7, August=8}
7 13
where integer expression is an integer, constant of type int, variable storing an integer, or an expression that results in an integer. The integer expression is called the selector of the switch statement. Based upon its value, the statement of the matching case integer constant is executed. statement is a legal C++ statement or compound statement. Once a correctly matching case integer constant value is found, all of the remaining code in the switch eak is encountered. statement is executed until a br break The switch statement is especially useful for handling enumerated types. For example, the PrintDay() function could be rewritten using a switch statement:
void PrintDay(DayType Day) /* Displays a string corresponding to Day Post: string corresponding to Day displayed */ { switch (Day) { case Monday: cout << "Monday"; break break; case Tuesday: cout << "Tuesday"; break break; case Wednesday: cout << "Wednesday"; break break; case Thursday: cout << "Thursday"; break break; case Friday: cout << "Friday"; break break; case Saturday: cout << "Saturday"; break break; case Sunday: cout << "Sunday"; break break; } }
Because the switch statement executes all the code after a matching case, it allows simplicity when multiple values are to execute the same statements. For example, when Day is equal to Tuesday, the statement
switch (Day) { case Monday: case Tuesday: case Wednesday: case Thursday: case Friday: cout << "Weekday"; break break; case Saturday: case Sunday: cout << "Weekend"; break break; }
displays Weekday If any of the first five case integer constants match the selector, then Weekday is displayed. If either of the last two match, then Weekend is displayed.
7 14
default case
A switch statement can also have a default case. The default executes if none of the case is a match. This is accomplished with the keyword default. For example:
switch (Day) { case Monday: case Tuesday: case Wednesday: case Thursday: case Friday: cout << "Weekday"; break break; case Saturday: case Sunday: cout << "Weekend"; break break; default default: cout << "Invalid day value"; break break; }
programming style
As with any C++ statement, alignment in the switch statement is irrelevant to the compiler. Often it is preferable to put code indented underneath the corresponding case, as in:
switch (Day) { case Monday: cout << "Monday"; break break; case Tuesday: cout << "Tuesday"; break break; case Wednesday: cout << "Wednesday"; break break;
The style used should make the code as clear as possible, given the number and length of the statements within the switch.
Review 14
Write a function LowerCase() that returns the lowercase equivalent of its char argument. If the argument is not an uppercase letter, it should just return the value of the argument unchanged.
Review 15
um type MonthType that holds the months of the year. Write a funcWrite a declaration of an en enum tion NextMonth() that returns the month following the month given as its argument.
Review 16
Write a switch statement that displays the season (Winter, Spring, Summer, Fall) corresponding to the value of Month of type MonthType declared in Review 15.
Case Study
In this Case Study, a program will be written to perform numerical integration for several mathematical functions. Among the most useful and important discoveries in mathematics is the collection of techniques for finding the area under a curve, also called integration. A curve can be specified in a mathematical function that gives the height (y-value) of the curve for every legal x value.
7 15
A technique for finding the area under a curve is called numerical integration. Numerical integration approximates an area by summing the areas of a large number of trapezoids under the curve. A trapezoid is a foursided figure with two sides parallel. For example, the area under the curve specified by the function f(x)=1/x is overlaid with a trapezoid:
Notice how the trapezoid roughly approximates the area under the curve between the limits A and B. The area of the trapezoid can be found using the formula Area = 0.5*(h1+h2)*b where h1 and h2 are the y-values of the curve for x values A and B, and b is the width (base) of the trapezoid. A more precise approximation can be obtained by using multiple trapezoids. For example, the sum of the areas of six trapezoids give a better approximation of the area under the curve:
specification
Write a program that calculates the area under a curve using numerical integration. Have the program display some introductory information to the user, and then display a menu with an option to quit and a list of mathematical functions to choose from. The functions should include x2, x2+1, sqrt(x), sin(x), and log(x). For the selected function, allow the user to enter the endpoints of the area to be found and the number of trapezoids to be used in the approximation. The program should then display the approximate area, and then display the menu again to allow the user to continue experimenting with numerical integration. The main() function is designed first. The pseudocode for the major tasks is: Give the description while (true) Get the users mathematical function choice (or quit) if the choice is to quit break Find the approximation desired To complete the design for main(), the pseudocode is used to determine the data design. A variable is not needed for loop control since the boolean constant true will be used to control the while loop. However, a variable is needed to hold the users menu choice.
designlevel 1
7 16
7
codinglevel 1
7 17
designlevel 2
In the next level of design, the functions called by main() are refined. GiveDescription() displays introductory information using cout. ChooseFunction() displays a menu of functions and an option to quit using cout. User input is handled with GetInt() from the utility library. As our first-level design indicates, ChooseFunction() returns the menu selection as an integer. FindArea() obtains the limit information from the user and the number of trapezoids desired, and then calculates and displays the area. The area calculation is a major task that requires a separate function Approximate(). Approximate() calculates the area of a function for the specified limits using a specified number of trapezoids. The parameters needed by Approximate() are FunctionNum, LowLimit, HighLimit, and NumTraps. Approximate() returns a double for the area. Level 2 design may be represented as:
codinglevel 2
7 18
//-------------------------------------------------------------------------------int ChooseFunction() /* Allows user to choose a function from a menu. Post: The function number chosen by the user returned or 0 to quit returned */ { cout << "Function list" << endl; cout << " 0. QUIT" << endl; cout << " 1. x^2" << endl; cout << " 2. x^2 + 1" << endl; cout << " 3. sqrt(x)" << endl; cout << " 4. sin(x)" << endl; cout << " 5. log(x)" << endl; cout << "Enter your choice: "; int Choice = GetInt(0, 5); return (Choice); } //-------------------------------------------------------------------------------double Approximate(int int FunctionNum, double LowLimit, double HighLimit, int NumTraps) /* Approximates the area under a curve using trapezoids Pre: FunctionNum is a defined function LowLimit..HighLimit values are defined for the function NumTraps >= 1 Post: The area under the function between LowLimit and HighLimit returned */ { return return(0); // For debugging purposes } //-------------------------------------------------------------------------------void FindArea(int int FunctionNum) /* Prompts user for endlimits and the number of trapezoids to use, and then calculates and displays the area under the curve FunctionNum using these values Post: area of selected function returned */ { double LowLimit, HighLimit, Area; int NumTraps; cout << "Enter the low limit: "; cin >> LowLimit; cout << "Enter the high limit: "; cin >> HighLimit; cout << "Enter the number of trapezoids: "; cin >> NumTraps; Area = Approximate(FunctionNum, LowLimit, HighLimit, NumTraps); cout << "The area is approximately " << Area << endl; } //-------------------------------------------------------------------------------int main() { GiveDescription(); while (true) { int FunctionNum = ChooseFunction(); if (FunctionNum == 0) break break; FindArea(FunctionNum); } return return(0); }
7 19
At this level, the program will run and generate some output. Therefore, program flow can be tested and debugged. A sample run is shown below: This program approximates the area under a curve by numerical integration. Numerical integration calculates the area under a curve by summing the areas of a set of trapezoids that represent the curve. The user chooses the function, the endlimits, and the number of trapezoids. Function list 0. QUIT 1. x^2 2. x^2 + 1 3. sqrt(x) 4. sin(x) 5. log(x) Enter your choice: 1 Enter the low limit: 1 Enter the high limit: 10 Enter the number of trapezoids: 100 The area is approximately 0 Function list 0. QUIT 1. x^2 2. x^2 + 1 3. sqrt(x) 4. sin(x) 5. log(x) Enter your choice: 0 This run shows that the flow of control appears to work correctly. However, the screen display is hard to read because it runs together. At the next level of coding, Pause() from the utility library and clrscr() from the conio library will be used to improve the readability.
designlevel 3
At the next level of design, the Approximate() function must be refined. The Approximate() pseudocode is based on numerical integration theory: Determine the base length for each trapezoid For each trapezoid Calculate its area Add its area to the summation of trapezoid areas Return the summation of the trapezoid areas When calculating trapezoid area, the values of h1 and h2 are required. This task is substantial enough to require another function, f(), which returns a y-value based on parameters FunctionNum and x. f() uses a switch statement to select the correct mathematical function.
7 20
codinglevel 3
All the design work has been completed. Therefore, the coding can be completed as shown below:
/* Area Under a Curve program. Approximates the area under curve by summing the area of a number of trapezoids that represent the area under the curve. The user specifies the function, the endlimits, and the number of trapezoids. */ #include <iostream.h> #include <conio.h> #include <lvp\bool.h> #include <math.h> #include "utility.h" //-------------------------------------------------------------------------------void GiveDescription() /* Provides a description of the program Post: A description of the program displayed */ { cout << "This program approximates the area under a curve by" << endl; cout << "numerical integration. Numerical integration calculates" << endl; cout << "the area under a curve by summing the areas of" << endl; cout << "a set of trapezoids that represent the curve." << endl; cout << "The user chooses the function, the endlimits, and" << endl; cout << "and the number of trapezoids." << endl; Pause(); } //-------------------------------------------------------------------------------int ChooseFunction() /* Allows user to choose a function from a menu. Post: The function number chosen by the user returned or 0 to quit returned */ { cout << "Function list" << endl; cout << " 0. QUIT" << endl; cout << " 1. x^2" << endl; cout << " 2. x^2 + 1" << endl; cout << " 3. sqrt(x)" << endl; cout << " 4. sin(x)" << endl; cout << " 5. log(x)" << endl; cout << "Enter your choice: "; int Choice = GetInt(0, 5); return (Choice); }
7 21
//-------------------------------------------------------------------------------int FunctionNum, double x) double f(int /* Returns the value of the function at x Pre: FunctionNum represents a valid function f(x) is defined for the function Post: The value of the function at x is returned or 0 if FunctionNum is not valid. */ { switch (FunctionNum) { case 1: return return(x*x); case 2: return return(x*x + 1); case 3: return return(sqrt(x)); case 4: return return(sin(x)); case 5: return return(log(x)); default default: return return(0); } } //-------------------------------------------------------------------------------double Approximate(int int FunctionNum, double LowLimit, double HighLimit, int NumTraps) /* Approximates the area under a curve using trapezoids Pre: FunctionNum is a defined function LowLimit..HighLimit values are defined for the function NumTraps >= 1 Post: The area under the function between LowLimit and HighLimit returned */ { double TrapWidth = (HighLimit LowLimit)/NumTraps; double x = LowLimit; double Area = 0; for (int int TrapCount = 1; TrapCount <= NumTraps; TrapCount++) { Area += 0.5*(f(FunctionNum, x)+f(FunctionNum, x+TrapWidth)) *TrapWidth; x += TrapWidth; } return return(Area); } //-------------------------------------------------------------------------------void FindArea(int int FunctionNum) /* Prompts user for endlimits and the number of trapezoids to use, and then calculates and displays the area under the curve FunctionNum using these values Post: area of selected function returned */ { double LowLimit, HighLimit, Area; int NumTraps; cout << "Enter the low limit: "; cin >> LowLimit; cout << "Enter the high limit: "; cin >> HighLimit; cout << "Enter the number of trapezoids: "; cin >> NumTraps; Area = Approximate(FunctionNum, LowLimit, HighLimit, NumTraps); cout << "The area is approximately " << Area << endl; Pause(); }
7 22
//-------------------------------------------------------------------------------int main() { GiveDescription(); while (true) { clrscr(); int FunctionNum = ChooseFunction(); if (FunctionNum == 0) break break; FindArea(FunctionNum); } return return(0); }
Because of the use of clrscr() it is hard to show a full run of this program on paper. However, a portion is shown below: Function list 0. QUIT 1. x^2 2. x^2 + 1 3. sqrt(x) 4. sin(x) 5. log(x) Enter your choice: 4 Enter the low limit: 0 Enter the high limit: 3.14 Enter the number of trapezoids: 20 The area is approximately 1.99589 Press a key to continue
Review 17
Suppose that, in violation of the precondition, Approximate() is called with a negative value for NumTraps. What would be the result? Modify the Case Study so that the user must enter a positive value for the number of trapezoids.
Review 18
Modify the Case Study to include three more mathematical functions: x^3, exp(x), and fabs(x).
Review 19
The Case Study used trapezoids in approximating the area under a curve. Another method of approximating the area under a curve uses rectangles rather than trapezoids. The height of each rectangle is taken to be the height of the curve at the midpoint of the rectangle. Modify the Case Study to implement this method. Compare the results obtained from each method.
7 23
Chapter Summary
This chapter introduced many of the functions available in the math library. These functions included pow(), sqrt(), abs(), and fabs(). Trigonometric functions are also available in math.h These include tan(), sin(), and cos() and the inverse trigonometric functions atan(), asin(), and acos(). Logarithmic and exponentiation functions include log(), log10(), and exp(). Online help can be used to learn more about the math library. The precision of double values is limited due to roundoff error. An equality should not be used to compare doubles. If an equality comparison must be made, it should be done with a tolerance included for an acceptable difference. Type casting can be used in a function that rounds a double. Recursion is a programming technique that can be used whenever a problem can be solved by solving one or more smaller versions of the same problem. Infinite recursion occurs if a stopping condition has not been included in a recursive function. The Towers of Hanoi can be solved using a recursive function. A computer stores characters through a standard conversion called the ASCII code. In C++, casting integer values into characters results in the ASCII character corresponding to the integer. An enumerated type is a named set of constants that can make a program easier to read and modify. Enumerated types are created using the um. When using enumerated types functions should be writenum keyword en ten to handle reading and writing them. The switch statement controls program flow and is especially useful for handling enumerated types.
Vocabulary
ASCII American Standard Code for Information Interchange. Specifies a character equivalent for every decimal value below 127. Extended Characters Character equivalents for decimal values above 127. Infinite Recursion A recursive function in which no stopping point has been designated. Integration Technique for finding the area under a curve. See Numerical Integration. Numerical Integration A technique in which the area under a curve is determined by representing the area as a number trapezoids and then summing the areas of the trapezoids. Recursion A programming technique that can be used whenever a problem can be solved by solving one or more smaller versions of the same problem. A process by which a function calls itself.
7 24
7
C++
Recursive Call A function call in which the calling function is the same as the function being called. Roundoff Error An error in representation of a double because the computer cannot exactly represent values with decimal portions.
abs() A function in the math library that returns the absolute value of an integer x. acos() A function in the math library that returns the arcosine of x in radians. asin() A function in the math library that returns the arcsine of x in radians. atan() A function in the math library that returns the arctangent of x in radians. cos() A function in the math library that returns the cosine of x, an angle in radians.
en um Keyword used to define an enumerated type. enum
exp() A function in the math library that raises e to the power of x. fabs() A function in the math library that returns the absolute value of a
double x.
log() A function in the math library that returns the natural logarithm of x. log10() A function in the math library that returns the base 10 logarithm of x. pow() A function in the math library that returns x to the power of y. sin() A function in the math library that returns the sine of x, an angle in radians. sqrt() A function in the math library that returns the square root of x.
switch Statement used to control program flow.
tan() A function in the math library that returns the tangent of x, an angle in radians.
7 25
Exercises
Exercise 1
x 1 2 3 4 5 6 x^2 1 4 9 16 25 36 x^3 1 8 27 64 125 216 x^4 1 16 81 256 625 1296 x^5 1 32 243 1024 3125 7776 Write a program that displays a table of powers as follows:
Exercise 2
Write a boolean function IsFactor() that takes two integers parameters and returns true if and only if the first is a factor of the second. A factor of a number is an integer value which divides evenly into the number. For example, 3 is a factor of 9 but 4 is not.
Exercise 3
Write a program that displays all perfect integers up to 100. A perfect integer is a number which is equal to the sum of all its factors except itself. For example, 6 is a perfect number because 1 + 2 + 3 = 6. Write a boolean function IsPerfect() to use in the program.
Exercise 4
Write a program that compares the square of the square root of a number with the number itself, for all whole numbers from 1 to 100. If they are not equal, have the program display the original number and the difference between the two values. What could cause this?
Exercise 5
Write a program that gives the solution to any quadratic equation. Have the program accept values for a, b, and c (ax2 + bx + c = 0) and then display the roots, if any. Recall the quadratic formula:
7 26
Exercise 6
trigonometry required
a) Write a function SinD() that returns the sine of its argument, an angle given in degrees. b) Write a function CosD() that returns the cosine of its argument, an angle given in degrees. c) Write a program that calls SinD() and CosD() to produce a table of sine and cosine values for all angles from 0 to 360 degrees in 10 degree increments.
Exercise 7
trigonometry required
a) Write a function Quadrant() that takes the X and Y coordinates of a point as parameters and returns either 1, 2, 3, or 4 depending upon the Cartesian quadrant the point lies in.
b) Write a function RectToPolar() that takes the X and Y coordinates of a point and returns (using reference parameters) the radius R and angle $ of the point in polar coordinates. The formulae are: R =sqrt(X2 + Y2) $ = atan(Y/X) In finding $, be sure to consider the quadrant of the angle and the value of X. c) Write a function PolarToRect() that takes the radius and angle $ of a point in polar coordinates and returns the X, Y Cartesian coordinates of the point. The formulae are: X = R * cos($) Y = R * sin($)
In finding X and Y, be sure to consider the quadrant of the angle to determine the signs of X and Y. d) Write a program that contains the functions from (a) through (c) above and gives the user an opportunity to test each one via a menu.
Exercise 8
A Pythagorean triple is a set of three integers that fits the equation A2 + B2 = C 2. Use PerfectSquare() from Review 2 in a program that displays all Pythagorean triples with values of A and B less than 100. (Hint: You will need to generate all possible combinations of A and B and display just those that work.)
7 27
Exercise 9
X = exp(Y * log(X))
Y
Write a function MyPow() and compare the output to that produced by pow() from the math library for a variety of values.
Exercise 10
Can the body of the Round() function in Section 7.6 be replaced with the single line below?
return int return(int int(x+0.5));
Compare the results of this version with those of the one in the text, and explain.
Exercise 11
A faster recursive IntPower() function can be constructed by using the equations: XN = (XN/2)2 for even values of N XN = X * (XN/2)2 for odd values of N If one is careful to calculate the value of XN/2 only once and then square it, this is much more efficient than the algorithm used in the chapter. Use this algorithm to construct a new IntPower() function.
Exercise 12
Consider the following recursive function:
void Exer(int int N) { cout << "Starting " << N << endl; if (N > 0) { Exer(N/3); cout << "Middle " << N << endl; } }
What output is generated when it is called with Exer(13)? with Exer(3)? With Exer(0)?
7 28
Exercise 13
Consider the following recursive function:
void Exer(int int N) { cout << N << endl; if (N > 0) { if (N % 2 == 1) Exer(N/3); else Exer(N/2); } }
What output is generated when it is called with Exer(13)? with Exer(14)? With Exer(15)?
Exercise 14
Consider the following recursive function:
void Exer(int int N) { if (N > 0) { cout << (N % 10); Exer(N/10); } }
What output is generated when it is called with Exer(13)? with Exer(124)? With Exer(21785)? State, in general, what this function does.
Exercise 15
Describe the output of the following function when the user enters the characters T, E, S, T, . ?
void WhatzItDo() { char ch = getche(); if (ch != '.') { WhatzItDo(); cout << ch; } else cout << endl; }
Exercise 16
Write a recursive function SumUp() that returns the sum of all positive integers less than or equal to its argument. Use the idea that the sum of all numbers from 1 to N is equal to the N plus the sum of all numbers from 1 to N-1.
7 29
Exercise 17
Write a recursive function NumDigits() that returns the number of digits in its integer parameter. Numbers 9 through 9 have one digit; numbers 99 to 10 and 10 to 99 have two digits, and so on. (Hint: the number of digits of a number N is one more than the number of digits in N/10.)
Exercise 18
Newtons method is taught in calculus classes as a way of finding roots of functions. One application is in finding cube roots. To do this, take an initial guess (say 1.00) and generate a new guess at the root using the formula: NewGuess = OldGuess (pow(OldGuess, 3)N)/(3*pow(OldGuess, 2)) where N is the number whose root is to be determined. The NewGuess becomes the old guess in the next round. For example, if N=29 and the initial guess is 1.00, the next guess is: NewGuess = 1.0 (1.0*1.0*1.0 29)/(3*1.0*1.0) = 10.3333 which is then put in the equation to get the next guess: NewGuess = 10.3333 (10.3333*10.3333*10.3333 29)/(3*10.3333*10.3333) = 6.97941959 Write a function to find cube roots using this process. Repeat the process until two consecutive guesses are equal within 0.000001.
Exercise 19
You are a spy who will use the computer to produce a secret code. A simple code can be produced by replacing each letter in a message with another letter several letters later in the alphabet. For example, A could be replaced with D, B with E, and so on, replacing X with A, Y with B, and finally Z with C. Write a function Code() that takes a character and an integer as arguments and returns the coded character using the system described. For example,
cout << Code('A', 3) ;
should display: D You may assume that the integer value is between 1 and 25 inclusive, and that the character is an uppercase letter.
7 30
Exercise 20
The Approximate() function in the Case Study returns an approximation of the area under a curve. A better approximation can be calculated by increasing the number of trapezoids used. This process can be repeated using an even greater number of trapezoids, and so on. Write a function PerfectArea() that uses Approximate() to produce a perfect approximation. The idea is to call Approximate() repeatedly with greater and greater numbers of trapezoids until two consecutive calls return similar numbers. By similar, we mean within 0.00001 of each other. Start with eight trapezoids, and each time the function is called, double the number of trapezoids. Modify the Case Study to include PerfectArea(). Allow the user to test this function by allowing a response of zero when asked for the number of trapezoids to use.
Advanced Exercise 21
A root of a mathematical function is the x-value that makes the function equal to zero. With some functions, it is easy to find the root or roots. For example, the root of 2x + 6 is the value 3 because the function is zero when x is 3. For other functions, the root may be harder to find. Visually, the root is where the curve crosses the x-axis, as shown below:
The method of finding roots by bisection is as follows. Begin with two x-values, low and high, that have corresponding y-values that are of different signs. That is, one value produces a yvalue that is above the x-axis, and the other produces a y-value that is below the x-axis. This means that the curve must cross the x-axis somewhere between the two points.
7 31
Calculate the midpoint of the two x-values, and determine whether its y-value is above or below the x-axis. Choose to make this midpoint the new high or new low so that the high and low continue to be on different sides of the x-axis. In our example, the midpoint has a y-value above the x-axis, so it becomes a new low.
Continue this process until the low and high x-values are within 0.000001 of each other. Modify the Case Study to display the roots of an equation using bisection. Have the program ask the user whether roots or areas are desired. If roots are chosen, low and high values must be obtained from the user. The program must verify that the low and high values are on opposite sides of the x-axis. Use the same set of functions as in the current Case Study.
7 32
8
Objectives
After completing this chapter you will be able to: 1. Use arrays to store values. 2. Implement arrays using the vector class. 3. Understand range errors. 4. Search an array for a specific value. 5. Use dynamic arrays. 6. Use a typedef statement to associate an identifier with a type. 7. Manipulate a String object as an array of chars. 8. Employ arrays with meaningful indexes. 9. Use two-dimensional arrays to represent a matrix. 10. Use the struct statement to create a user-defined type. 11. Understand three-dimensional arrays.
8
n this chapter you will learn about array and matrix data types for storing many values of the same type. The struct statement will be used to create user-defined types that can store many values of different types. The typedef statement will be used to simplify code.
A value in an array is accessed by giving its index number in the array. In C++, the index number is given in square brackets, and counting starts from zero. For example, the statement
cout << NameArray[1];
displays Chris because Chris is the second value in array NameArray. The second item has an index number of 1 since counting begins at zero. C++ has a built-in array type that is widely regarded as difficult to use and prone to error. Therefore, in this text the vector library will be used to implement arrays, as described in the next section.
81
More simply, this statement declares an array NameArray that can contain six strings, indexed from 0 to 5. The portion <String> specifies the type to be used by the template. The type is specified in angle brackets directly after the class name. Following is the vector class documentation: vector (vector.h) Constructors
vector(); /*Creates an array of capacity 0 Post: An array of a capacity of 0 items created. Array will need to be resized
*/
vector(int int size); /*Creates an array of capacity size Post: An array of a capacity of size items created. */ vector(int int size, const ItemType &FillValue); /*Creates an array of capacity size with each element containing FillValue Post: An array of a capacity of size items with each element containing FillValue created. */
Functions
int length(); /*Determines the size of the array Post: Size of array returned */ void resize(int int NewSize); /*Resizes an array Pre: NewSize >= 0 Post: Array resized to NewSize */
Operators [] Returns the item at the index number in [ ] = Assigns one array to another. The following program demonstrates the vector class:
/* vector class demonstration program */ #include <iostream.h> #include <lvp\string.h> #include <lvp\vector.h> int main() { const int NumItems = 3; vector<String> NameArray(NumItems); int Index; // Load array for (Index=0; Index<NumItems; Index++) { cout << "Enter a name: "; cin >> NameArray[Index]; }
82
// Display array for (Index=0; Index<NumItems; Index++) cout << NameArray[Index] << endl; return return(0); }
A constant value, NumItems, is used for the number of items stored in the array. This clarifies the code and makes it easier to change the number of values if needed. The for loops access elements 0 through 2 (NumItems1) of the array, since array indexing starts at zero. When run, program output may look similar to: Enter a name: Angelou Enter a name: Austin Enter a name: Dickinson Angelou Austin Dickinson
Review 1
Write declarations for an array storing 12 int values, an array storing 100 double values, and an array storing 80 char values.
Review 2
What is the output of the following program segment?
vector<int int> Num(3); int Num[0] = 23; Num[1] = 61; Num[2] = 98; cout << Num[0] << '|' << Num[1] << endl; cout << Num[0] + Num[1] << '|' << Num[0+1] << endl; Num[1] = Num[2]; Num[2] = Num[0]; Num[0] = Num[1]; cout << Num[0] << '|' << Num[1] << '|' << Num[2] << endl;
83
Review 3
Modify the vector class demonstration program to include an array, VoteArray, that stores five
long values. Have the program ask the user for the number of votes associated with each name,
and then display a table. The program output should be similar to: Enter name: Pooh Enter votes: 123 Enter name: Piglet Enter votes: 32 ... Results: Pooh 123 Piglet 32 ...
resize()
The resize() member function is used to modify the size of an array during program execution. For example, the statement
NameArray.resize(10); //Array now holds 10 names, indexed from 0 to 9
allows NameArray to hold 10 values. If an array is resized to be smaller, values after the new maximum index are discarded. If an array is resized to be larger, the original items are maintained, and space for additional items is made available.
length()
Since the size of an array may vary during a program run, it is sometimes necessary to determine the current array size. The length() member function is used to do this, as in the statement:
cout << "The array now holds " << NameArray.length() << endl;
Note that the loop executes until one less than the length since array indexing starts at zero.
assignment
The assignment operator member function allows one array can be assigned to another. The sizes of the arrays need not be the same before the assignment. After the assignment, they both hold the same number of values and the same values. For example, the statements
vector<double double> BigArray(100), SmallArray(10); double // Code here to put values in SmallArray BigArray = SmallArray; cout << BigArray.length() << endl; // Displays 10
display 10 84
SumOfItems() and LoadArray() both use reference parameters. However, SumOfItems() does not need to change the array, so its reference parameter is a const. When run, program output may look similar to: Enter number 0: 78.6 Enter number 1: 87.5 Enter number 2: 105.7 Enter number 3: 55.6 Enter number 4: 67.8 Average is 79.04
85
Review 4
Modify Review 3 so that it uses two functions: LoadData() and DisplayResults().
Review 5
Most users prefer to count from one on up rather than from zero. Modify the program in Section 8.5 to display prompts similar to the following: Enter number 1: 78.6 Enter number 2: 87.5 Enter number 3: 105.7 Enter number 4: 55.6 Enter number 5: 67.8 Average is 79.04
create an array ValueArray with 10 elements each containing a value of 0, and an array NameArray with 30 elements each containing a string Empty.
default constructor
A third constructor, called the default constructor, takes no parameters and creates an array with zero elements. This constructor is useful when the size of an array is unknown at the start of a program. For example, the statement
vector<double double> DataArray; double
creates an array of zero double elements. An array with zero elements must be resized in order to be used. The resize() member function can be used to change the array size.
Review 6
Modify the Average of Array Elements program to allow the user to specify the number of items to be entered. Have the program declare an array to a size of zero, and then resize it once the number of values desired is obtained from the user. The program output should look similar to: How many numbers to enter? 7 Enter number 0: 78.6 Enter number 1: 87.5 Enter number 2: 105.7 Enter number 3: 55.6 Enter number 4: 67.8 Enter number 5: 15.7 Enter number 6: 59.0 Average is 67.1286
86
If the Goal is found, its index is returned and the function terminates. If the loop completes without finding Goal, the value 1 is returned.
Note that RemoveFromArray() uses FindItemIndex() from Section 8.7 to determine the index of the element to delete.
87
Review 7
Write a program that uses a dynamic array to add and delete names to an array. Have the program allow the user to find names. Initially, the array should contain no names. When run, program output should look similar to: Choose action (Add/Delete/Find/Quit):A Enter name to add: Zaphod Choose action (Add/Delete/Find/Quit):A Enter name to add: Trillian Choose action (Add/Delete/Find/Quit):F Enter name to find: Adams Not found. Choose action (Add/Delete/Find/Quit):F Enter name to find: Trillian Found in location 1 Choose action (Add/Delete/Find/Quit):D Enter name to delete: Zaphod Choose action (Add/Delete/Find/Quit):F Enter name to find: Trillian Found in location 0 Choose action (Add/Delete/Find/Quit):Q
where type is a built-in C++ type or a user-defined type, and identifier is a legal C++ identifier. For example, the statement
typedef String ItemType;
establishes that the name ItemType represents the type String. With this statement, the AddToArray() function header in Section 8.8 can be written:
void AddToArray(vector<ItemType> &Array, const ItemType &ValToAdd) typedef can also be used to define names for more complex types. For example, the statements: typedef String ItemType; typedef vector<ItemType> ArrayType;
define the name ArrayType to represent a vector of String values. With these definitions, an array can be declared like:
ArrayType MyList;
88
typedef declarations must come before any functions that use the defined type. Therefore, they are usually placed at the beginning of a program before any function definitions. For example: /*typedef program */ #include <iostream.h> #include <lvp\string.h> #include <lvp\vector.h> typedef String ItemType; //-------------------------------------------------------------------------------// Definitions of functions, i.e. AddToArray() //-------------------------------------------------------------------------------int main() { // Variable definitions, possibly using ItemType // Statements return return(0); }
Review 8
Modify Review 7 to use typedef statements for both ItemType and ArrayType. Demonstrate the fact that changing a single statement will convert the program from manipulating an array of strings to an array of integers.
Uppercase()
Many useful functions can be written based on the array properties of a String. For example, a function to allow string comparisons that are not case sensitive. With this function, the strings apple, APPLE, and Apple would be recognized as the same. The following program uses this function:
89
/*Compare Strings program */ #include <iostream.h> #include <lvp\string.h> //-------------------------------------------------------------------------------String Uppercase(String S) /*Returns a copy of S with all lowercase characters converted to uppercase characters Post: String in all uppercase letters returned */ { for (int int Letter=0; Letter<S.length(); Letter++) if ((S[Letter]>='a') && (S[Letter]<='z')) S[Letter]=S[Letter]'a'+'A'; return return(S); } //-------------------------------------------------------------------------------int main() { String String1, String2; cout << "Enter a string: "; cin >> String1; cout << "Enter another string: "; cin >> String2; if (Uppercase(String1)==Uppercase(String2)) cout << "Strings are equal." << endl; else cout << "Strings are not equal." << endl; return return(0); }
When run, program output may look similar to: Enter a string: Apple Enter another string: apple Strings are equal. The vector library is not included in this program because the String class automatically creates a String object as an array of chars. In Uppercase(), S is a value parameter so that a local copy is made. This local copy is then manipulated, and returned by the function.
Review 9
Write a function Reverse() that returns the reverse of its single String argument. For example, if the argument is able, it should return elba.
Review 10
Write a function Palindrome() that returns true if its string argument is the same backwards and forwards, regardless of case. For example, Palindrome() should return true for Dad and Mom, and false for kids. Palindrome() may make calls to Reverse() and Uppercase().
8 10
8 11
generates a random roll of two dice, and then the outcome of the trial is used to update a counter in the statement:
Count[Roll]++;
In this statement, one is added to the location in Count corresponding to the roll outcome. If a three was rolled, Count[3] is incremented. There is no need to search for the location where the 3s are counted since the index is used as a label. A typedef statement was used to create a name, CountType, to represent the array. The elements of the Count array were initialized to zero using the vector constructor. When run, program output may look similar to: Roll Count 2 21 3 71 4 90 5 114 6 151 7 151 8 145 9 94 10 74 11 56 12 33
offsetting indexes
In the Dice Rolls program, the outcomes ranged from 2 through 12 making it possible to store counters at array indexes directly corresponding to the outcomes. However, this approach for a range of years 1900 through 2000 would require an array of 2001 elements with only the last 100 elements in use. For ranges such as these, the solution is to store counters at offset array indexes. For example, for an outcome of 1900, a counter at index 0 would be updated. For an outcome of 1901, a counter at index 1 would be updated, and so on. A standard way of formulating the array size to handle an offset is:
vector<int int> Count(HighLow+1); int
where High is the highest value in the range and Low is the lowest value in the range. The following statement updates a counter stored at an offset index:
Count[ValueLow]++;
8 12
A program that counts the frequency of uppercase characters in a string could use an array to store the counts. To further simplify storage of the counters, the indexes could be used to determine which counter corresponds to which letter. For example, the letter A in ASCII is 65, B is 66, and so on. Therefore, the counters could be stored at offset array indexes corresponding to the ASCII equivalent of uppercase letters. The Uppercase Characters program implements this algorithm:
/* Uppercase Characters program */ #include <iostream.h> #include <lvp\vector.h> #include <lvp\string.h> int main() { const char Low = 'A'; const char High = 'Z'; int vector<int int> Count(HighLow+1, 0); String S; cout << "Enter a string:" << endl; getline(cin, S); // Count frequency of uppercase characters int index=0; index<S.length(); index++) { for (int char Letter = S[index]; if ((Letter >= Low) && (Letter <=High)) Count[LetterLow]++; } // Display counts char Letter=Low; Letter<=High; Letter++) for (char cout << Letter << " " << Count[LetterLow] << endl; return return(0); }
In the declaration of Count, C++ automatically typecast the characters to ints to determine the size of the array. Automatic typecasting came into effect again when the elements of Count were accessed (Count[LetterLow]). Here is part of a sample run: Enter a string: THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. A 1 B 1 C 1 D 1 E 3 F 1 G 1 H 2 I 1 J 1 K 1 L 1 ...
8 13
Review 11
Modify the Dice Rolls program so that it allows the user to specify the number of trials to make, and displays the results as percentages. The program output should look similar to: Enter number or trials to perform: 2000 Roll Percent 2 2.1% 3 4.5% 4 10.2% ...
Review 12
Modify the Dice Rolls program so that it counts rolls of three dice rather than two and displays the counts of each roll. The program output should look similar to: Roll Count 3 20 4 43 5 110 ...
Review 13
Write a complete set of definitions to create an array that would store the number of times the word Internet appeared in the New York Times during each of the years 1960 through 1996.
matrix type
More simply, this statement declares a two-dimensional array Board that can contain nine chars. The first argument is the number of rows, and the second is the number of columns. The following illustrates a matrix with a character stored in each element:
8 14
To access a matrix element, both its column and row numbers must be given in square brackets. For example, the statement
cout << Board[0][1]
displays the element in the first row and the second column: O Following is the matrix class documentation: matrix (matrix.h) Constructors
matrix(); /*Creates a matrix of capacity 0 Post: A matrix of a capacity of 0 items created. Matrix will need to be resized matrix(int int rows, int cols); /*Creates a matrix of rows rows by cols columns Post: A matrix of a capacity of rows rows by cols columns items created.
*/
*/
int rows, int cols, const ItemType &FillValue); matrix(int /*Creates a matrix of capacity rows rows by cols columns with each element containing FillValue Post: An array of a capacity of rows rows by cols columns with each element containing FillValue created.
*/
Functions
int numrows(); /*Determines the number of rows in the matrix Post: Number of rows in matrix returned */ int numcols(); /*Determines the number of columns in the matrix Post: Number of columns in matrix returned */ void resize(int int NewRows, int NewCols); /*Resizes a matrix Pre: NewRows, NewCols >= 0 Post: Array resized to NewRows by NewCols */
Operators [] Returns one row of a matrix whose type is vector = Assigns one matrix to another. A tic-tac-toe program will be used to demonstrate matrices. Consider the tic-tac-toe board. It has three columns and three rows:
Each cell of the board can hold an X, an O, or be empty. A space character can represent an empty cell. Therefore, the board can be represented as a matrix of characters.
8 15
The Tic-Tac-Toe program allows two players to play a game of tic-tactoe using the computer to keep track of the board:
/* Tic-Tac-Toe program */ #include <iostream.h> #include <lvp\matrix.h> #include <lvp\bool.h> typedef matrix<char char char> TTTBoard; //-------------------------------------------------------------------------------const TTTBoard &Board) void DisplayBoard(const /*Displays board Post: Board displayed */ { for (int int Row=0; Row<Board.numrows(); Row++) { // Display a row for (int int Col=0; Col<Board.numcols(); Col ++) cout << "[" << Board[Row][Col]<< "]" ; cout << endl; } } //-------------------------------------------------------------------------------void GetMove(int int &Row, int &Col, const TTTBoard &Board) /*Obtains a valid move (Row, Col) from user Post: Row and Col of matrix returned as valid move */ { while (true) { cout << "Enter row of move (0, 1, 2): "; cin >> Row; cout << "Enter column of move (0, 1, 2): "; cin >> Col; if ((Row >= 0) && (Row < Board.numrows()) && (Col >= 0) && (Col < Board.numcols()) && (Board[Row][Col] == ' ')) break break; cout << "Invalid move, please re-enter!" << endl; } } //-------------------------------------------------------------------------------char Winner(const const TTTBoard &Board) /*Returns X or O indicating the winner. If no winner, a blank is returned. If there are multiple winning sets, returns the first one encountered Post: X, O, or a blank returned */ { int Row, Col; // Try all rows for for(Row = 0; Row < Board.numrows(); Row++) if (Board[Row][0]==Board[Row][1] && Board[Row][1]==Board[Row][2] && Board[Row][0] != ' ') return return(Board[Row][0]); // Try all columns for for(Col = 0; Col < Board.numcols(); Col++) if (Board[0][Col]==Board[1][Col] && Board[1][Col]==Board[2][Col] && Board[0][Col] != ' ') return return(Board[0][Col]); // Try one diagonal if (Board[0][0]==Board[1][1] && Board[1][1]==Board[2][2] && Board[0][0] != ' ') return return(Board[0][0]);
8 16
// Try the other diagonal if (Board[0][2]==Board[1][1] && Board[1][1]==Board[2][0] && Board[0][2] != ' ') return return(Board[0][2]); // Return blank, if all others fail return return(' '); } //-------------------------------------------------------------------------------int main() { TTTBoard Board(3, 3, ' '); char CurrPlayer; int Row, Col, NumMoves = 0; CurrPlayer = 'X'; do { DisplayBoard(Board); GetMove(Row, Col, Board); Board[Row][Col] = CurrPlayer; NumMoves++; if (CurrPlayer == 'X') CurrPlayer = 'O'; else CurrPlayer = 'X'; } while ((Winner(Board) == ' ') && (NumMoves != 9)); DisplayBoard(Board); cout << "Winner is " << Winner(Board) << endl; return return(0); }
matrix parameters
DisplayBoard() has a matrix parameter. As with array objects, matrix objects that are not to be changed should be passed as a const reference parameter. Nested for loops are used in DisplayBoard() to process all the elements in the matrix. When run, program output may look similar to: [ ][ ][ ] [ ][ ][ ] [ ][ ][ ] Enter row to Enter column [ ][ ][ ] [ ][X][ ] [ ][ ][ ] Enter row to Enter column [O][ ][ ] [ ][X][ ] [ ][ ][ ] Enter row to Enter column [O][ ][ ] [X][X][ ] [ ][ ][ ]
8 17
... Enter row to Enter column [O][ ][X] [X][X][O] [ ][ ][O] Enter row to Enter column [O][ ][X] [X][X][O] [X][ ][O] Winner is X
Review 14
Modify the Tic-Tac-Toe program so that the user enters rows and columns in the range 1 to 3 instead of 0 to 2, and so that the display shows the row and column numbers. The program output should look similar to: 1 2 3 1 [X][O][ ] 2 [ ][X][O] 3 [ ][X][O]
Review 15
Modify the Tic-Tac-Toe program so that the user may play against the computer, with the computer picking a random but legal move on its turn. Write a function GetComputerMove() to use in the program.
Note the semicolon that must be included to end the type definition. A
str uct type must be defined before any functions that use it. Therefore, struct str uct types are usually placed at the beginning of a program before any struct
function definitions.
8 18
8
struct parameters
uct has four data members. The data members are struct The StudentType str accessed using the same dot notation used with classes. For example, the statements StudentType Student; cout << "Enter class: "; cin >> Student.Class; uct Student of type StudentType, and ask the user for the declare a str struct value to assign to the Class data member of Student. uct variable can be passed as a parameter, just as any other varistruct A str uct reference parameter: struct able. For example, the function below has a str void GetStudentData(StudentType &Student) /*Obtains values for all data members of Student from user Post: Values entered for data members of Student */ { cout << "Enter last name: "; cin >> Student.Last; cout << "Enter first name: "; cin >> Student.First; cout << "Enter middle initial: "; cin >> Student.Initial; cout << "Enter class: "; cin >> Student.Class; }
This function obtains values from the user and places them in the Student data members.
Review 16
Write a function DisplayStudentData() that displays the values of its StudentType argument. Write a program that uses GetStudentData() and DisplayStudentData() to generate output similar to: Enter last name: Yamaguchi Enter first name: Kristi Enter middle initial: A Enter class: 2004 Kristi A. Yamaguchi 2004
Review 17
uct named CollegeType that holds information about a college. Include Write a definition for a str struct data members for name, state, and enrollment.
8 19
The Grades data member is declared as an IntArray. However, no constructor parameters are given because variables and objects cannot be iniuct definition. Like classes, structs can have member funcstruct tialized in a str tions that are constructors. To initialize variables and instantiate objects, uct constructor must be written, as described in the next section. struct a str
initializer list
are part of the constructor syntax. A special feature of a constructor is an initializer list that is used to instantiate objects or make assignments to uct. The colon preceding initializer list may be omitstruct data members of the str ted if there is no initialization of data members.
8 20
StudentType()
The body of this constructor is empty. This is common for constructors because much of the work can be done in the initializer list.
uct constructor struct In addition to calling data member constructors, a str can initialize variables. For example, the StudentType constructor could be written: StudentType::StudentType() : Grades(10,1), Gender(female), Class(0) /*Grades initialized to 10 items with each element storing 1; Gender and Class initialized to default values. */ { }
programming style
It is good programming style to use a constructor initializer list, rather than making simple assignments to these data members in the body of the constructor. The following constructor is an example of poor programming style:
StudentType::StudentType() // Poor programming style! : Grades(10,-1) /*Example of poor programming style */ { Gender = female; Class = 0; }
8 21
*/
After giving a const a value, it may be used in other initializations. In this case, MaxGrades is used in the Grades initialization.
uct is the order in which struct The order in which data members appear in a str uct declare data struct they are initialized. Therefore, it is important that a str members in the order in which they are needed. For example, the uct declared MaxGrades before Grades because the inistruct StudentType str tialization of Grades depends on the definition of MaxGrades: struct StudentType { StudentType(); // Constructor member function const int MaxGrades; // Must come before Grades IntArray Grades; // Requires MaxGrades };
Review 18
uct PegBoard with a constructor that initializes three pegs of size 7. Write a str struct
Review 19
Write a function TotalRings() that takes a PegBoard argument from Review 18 and returns the total number of rings on the three pegs. Write a program to test the function.
Each element of School has data members that can be given values through assignment, as in the following statements:
School[7].Last = "Morrison"; School[7].First = "Toni";
To demonstrate an array of structs, the following Student Records program maintains student information. For this program, a dynamic array is used because the actual number of students may vary due to new admissions. To efficiently handle additions to the array, the array will initially be size 10, then resized to 20 when the first 10 elements are taken, then resized to 30 when the first 20 elements are taken, and so on. Increasing the array by 10 elements at a time is much more efficient than resizing the array every time a new student is added. However, in order
8 22
to use this algorithm for resizing the array, a variable must be used to store the number of array elements taken. The array is then resized only if the addition of a student record means that the number of array elements taken will be greater than the current array size. For example, an array currently of size 20 with 17 student records can be illustrated as:
Adding students Ollie, Kurt, and Lily does not require the array to be resized, as illustrated below:
Adding a fourth student, Vito, requires resizing the array. Since 10 elements are added at a time, there is now room for nine more students, as illustrated below:
uct SchoolType is used in the To better implement this algorithm, a str struct program: struct StudentType { String Last; String First; int Class; }; struct SchoolType { SchoolType(); // Constructor const int SizeChange; // Amount to increase array by int NumStudents; // Current number of students vector<StudentType> Students; // Student records };
A constructor for SchoolType initializes NumStudents and SizeChange and initializes Students:
SchoolType::SchoolType() : SizeChange(10), NumStudents(0), Students(10) /*Start with space for 10 students, increase by SizeChange when needed */ { }
8 23
struct StudentType { String Last; String First; int Class; }; //-------------------------------------------------------------------------------void GetStudentData(StudentType &Student) /*Obtains values for all data members of Student from user Post: Values entered for data members of Student */ { cout << "Enter last name: "; cin >> Student.Last; cout << "Enter first name: "; cin >> Student.First; cout << "Enter class: "; cin >> Student.Class; } //-------------------------------------------------------------------------------void DisplayStudentData(const const StudentType &Student) /* Displays the data in Student, one element per line Post: Data in Student displayed */ { cout << Student.First << " " << Student.Last << " " << Student.Class << endl; } //-------------------------------------------------------------------------------struct SchoolType { SchoolType(); // Constructor const int SizeChange; // Amount to increase array by int NumStudents; // Current number of students vector<StudentType> Students; // Student records }; //-------------------------------------------------------------------------------SchoolType::SchoolType() : SizeChange(10), Students(10), NumStudents(0) /*Start with space for 10 students, increase by SizeChange when needed */ { } //-------------------------------------------------------------------------------void DisplaySchool(const const SchoolType &School) /*Displays a list of all students in School, one per line Post: Elements of School displayed */ { for (int int i=0; i<School.NumStudents; i++) DisplayStudentData(School.Students[i]);
8 24
} //-------------------------------------------------------------------------------void AddStudent(SchoolType &School, const StudentType &NewStudent) /*Adds NewStudent to School, increasing size of School.Students if needed Post: NewStudent added to School */ { if (School.NumStudents == School.Students.length()) School.Students.resize(School.NumStudents+School.SizeChange); School.Students[School.NumStudents] = NewStudent; School.NumStudents++; } //-------------------------------------------------------------------------------int main() { StudentType Student; SchoolType School; bool Quit=false; do { cout << "Press choice Add, Display, Quit: "; char Choice = getche(); cout << endl; switch (Choice) { case 'A': case 'a': GetStudentData(Student); AddStudent(School, Student); break break; case 'D': case 'd': DisplaySchool(School); break break; case 'q': case 'Q':Quit=true; break break; } } while while(!Quit); return return(0); } uct The organization of this program is important. First, the StudentType str struct is defined followed by all its support functions (GetStudentData(), uct is defined followed struct DisplayStudentData()). Next, the SchoolType str by its support functions (constructor SchoolType() and DisplaySchool()). The SchoolType declarations must come after the StudentType declarations because SchoolType requires StudentType. Finally, main() is written. This building block approach will become increasingly important.
When run, the program output may look similar to: Press Enter Enter Enter Press Enter Enter Enter Press Enter Enter Enter choice Add, Display, Quit: A last name: Howell first name: Louis class: 1997 choice Add, Display, Quit: a last name: Wu first name: Shiu class: 1996 choice Add, Display, Quit: A last name: Kubak first name: Michael class: 1999
8 25
Press choice Add, Display, Quit: D Louis Howell 1997 Shiu Wu 1996 Michael Kubak 1999 Press choice Add, Display, Quit: Q
Review 20
Modify the Student Records program to allow the user to search for a record matching an entered last name and first name. To do this, write a function that returns the student record, if any, that matches the name. The program output should look similar to: ... Enter choice Add, Display, Search, Quit: S Enter last name: Kubak Enter first name: Michael Michael Kubak 1999 Enter choice Add, Display, Search, Quit: S Enter last name: Cenker Enter first name: Brian Brian Cenker not found! ...
With these definitions, the declaration of the three-dimensional array would be:
SalesType Sales(10, 5, MonthArray(12, 0.0));
Sales is a three-dimensional array of 10 by 5 by 12 elements, all initialized to 0.0. The third argument to the Sales constructor is itself a constructor that creates array MonthArray of size 12 filled with 0.0 values. Each element of the matrix contains a MonthArray array. Data is accessed using three indices. For example, the statement
Sales[3][0][11]+=234.95;
adds 234.95 to the value stored in the twelfth element of the array stored in the fourth column and the first row of the matrix. Rather than represent the sales with a three-dimensional array, a more uct. struct common approach is for some part of the nesting to be handled by a str Using the above example, EmployeeType could be defined as follows: 8 26
struct EmployeeType { EmployeeType(); // Constructor String Last; String First; double matrix<double double> Sales; }; EmployeeType::EmployeeType() : Sales(5, 12, 0.0) // 5 products, 12 months { } typedef vector<EmployeeType> SalesType;
While it still has the characteristics of a three-dimensional array, the nesting is more subtle, and code is easier to understand:
SalesType Employee(10); // Make room for 10 employees ... Employee[3].Sales[0][11]+=234.95;
programming style
When designing a data structure, carefully consider whether the information to be stored falls naturally into a multidimensional structure, or whether a more structured organization is possible and preferable.
Case Study
In this Case Study, a vote analysis program will be written.
specification
Write a program to provide vote analysis for an election, as might be needed by a television station covering the election. There are three candidates and five precincts. The program should be menu-driven to allow the names of the candidates to be entered, the precinct data to be entered as it arrives, and a grid of the data to be displayed. When run, the programs output should be similar to: Enter name for candidate 1: Carter Enter name for candidate 2: Ford Enter name for candidate 3: McCarthy Enter precinct, Display results, Quit: e What precinct? 3 Enter votes for this precinct for Carter: 342 Enter votes for this precinct for Ford: 300 Enter votes for this precinct for McCarthy: 65 Enter precinct, Display results, Quit: d Candidate 1 2 3 4 5 Total Carter 0 0 342 0 0 342 Ford 0 0 300 0 0 300 McCarthy 0 0 65 0 0 65 Enter precinct, Display results, Quit: e What precinct? 1 Enter votes for this precinct for Carter: 427 Enter votes for this precinct for Ford: 432 Enter votes for this precinct for McCarthy: 48
8 27
Enter precinct, Display results, Quit: Candidate 1 2 3 4 Carter 427 0 342 0 Ford 432 0 300 0 McCarthy 48 0 65 0
designlevel 1
The main() function is designed first. The pseudocode for the major tasks is: Get candidates names do Display menu of choices (Enter precinct, Display results, Quit) switch E or e: Load precinct with votes D or d: Display candidates and votes for each precinct Q or q: quit is true while (!Quit) Next, the main() pseudocode is used to determine the data design. A
char variable Choice is needed to hold the users menu choice. A bool variable Quit is needed to end the do loop. An array can be used to store
A matrix can be used to store the votes for each precinct for each candidate:
matrix<int int> Votes; int
The matrix should have three rows (const int NumCandidates) and five columns (const int NumPrecincts). The array and matrix data is related uct: struct information that would best be represented by a str
struct ResultsType { ResultsType(); // Constructor const int NumCandidates; const int NumPrecincts; vector<String> Candidates; int matrix<int int> Votes; }; //-------------------------------------------------------------------------------ResultsType::ResultsType() : NumCandidates(3), NumPrecincts(5), Votes(NumCandidates, NumPrecincts, 0), Candidates(NumCandidates) { }
The constructor initializes the Votes matrix to all zeroes. These zeroes will be replaced by votes entered by the user. Candidates was not initialized since the names will be entered by the user at the start of the program.
8 28
8
codinglevel 1
At this point, rather than coding main() as designed, a main() that tests uct will be coded. To test ResultsType, the LoadNames() struct the ResultsType str function, which gets candidate names from the user, must be coded:
void LoadNames(ResultsType &R) /*Prompts user to enter all candidate names, and stores them in R Post: Candidate names are stored in R */ { for (int int CNum=0; CNum<R.NumCandidates; CNum++) { cout << "Enter name for candidate " << (CNum+1) << ": "; cin >> R.Candidates[CNum]; } } const NumCandidates is used to control the for loop. A variable, CNum
is used as the loop control and the array index. However, CNum+1 is displayed in the program output as defined by the specification because, while the array is indexed from 0 to 2, the numbers 1 to 3 are more understandable to the user. Although not needed in the final program, a function DisplayNames() uct: struct is written to test LoadNames() and the ResultsType str
void DisplayNames(const const ResultsType &R) /*Function to test loading and retrieval of names Post: Contents of R displayed */ { for (int int CNum=0; CNum< R.NumCandidates; CNum++) cout << (CNum+1) << ": " << R.Candidates[CNum] << endl; } uct: Finally, a main() to test LoadNames() and the ResultsType str struct int main() { ResultsType Results; LoadNames(Results); DisplayNames(Results); return return(0); }
A program with the declaration of ResultsType, the function definitions, and the main() above displays output similar to the following: Enter name for candidate 1: Carter Enter name for candidate 2: Ford Enter name for candidate 3: McCarthy 1: Carter 2: Ford 3: McCarthy
8 29
designlevel 2
In the next level of design, the real main() and the functions it calls are refined. The refined main() pseudocode is: ResultsType Results bool Quit=false LoadNames(Results) do Display menu of choices (Enter precinct, Display results, Quit) switch E or e: LoadAPrecinct(Results) D or d: DisplayAll(Results) Q or q: quit is true while (!Quit) A boolean variable controls the loop. The quit commands, Q and q, need only be specified in the switch statement. LoadNames() was created in level 1 of coding. The LoadAPrecinct() pseudocode is: Ask user for precinct number for each candidate Ask user for votes received The data design of LoadAPrecinct() includes variables UserPct and PctNum to account for the user entering a precinct number that is one greater than its matrix position. For example, data for precinct number 1 (UserPct) is stored in the 0th column (PctNum) of the matrix. The DisplayAll() pseudocode is: for each precinct display precinct number as a title for each candidate Display candidate name Display votes for each precinct Display total votes for all precincts The task of the second for loop is complex enough that another function DisplayCandidateRow() should be written. DisplayCandidateRow() will require parameters for the Results and the current candidate number. The DisplayCandidateRow() pseudocode is: Display candidate name corresponding to candidate number for each precinct Display votes corresponding to candidate number Display total votes for that candidate
8 30
codinglevel 2
struct ResultsType { ResultsType(); // Constructor const int NumCandidates; const int NumPrecincts; vector<String> Candidates; int matrix<int int> Votes; }; //-------------------------------------------------------------------------------ResultsType::ResultsType() : NumCandidates(3), NumPrecincts(5), Votes(NumCandidates, NumPrecincts, 0), Candidates(NumCandidates) { } //-------------------------------------------------------------------------------void LoadNames(ResultsType &R) /*Prompts user to enter all candidate names, and stores them in Results Post: Candidate names are stored in Results */ { for (int int CNum=0; CNum<R.NumCandidates; CNum++) { cout << "Enter name for candidate " << (CNum+1) << ": "; cin >> R.Candidates[CNum]; } } //-------------------------------------------------------------------------------void LoadAPrecinct(ResultsType &R) /*Prompts user to choose a precinct, and then prompts for and stores votes for each candidate for that precinct Post: Votes entered for a precinct */ { int UserPct; cout << "What precinct? " ; cin >> UserPct; int PctNum = UserPct 1; for (int int CNum=0; CNum<R.NumCandidates; CNum++) { cout << "Enter votes for this precinct for " << R.Candidates[CNum] << ": "; cin >> R.Votes[CNum][PctNum]; } }
8 31
//-------------------------------------------------------------------------------const ResultsType &R, int CNum, void DisplayCandidateRow(const const int CField, const int VField) /*Displays data for one candidate in the format: Name p1 p2 p3 Total Pre: 0 <= CNum < R.NumCandidates Post: Data for candidate CNum displayed */ { cout.setf(ios::left); cout.width(CField); cout << R.Candidates[CNum]; cout.setf(ios::right); int Total = 0; for (int int PNum=0; PNum<R.NumPrecincts; PNum++) { cout.width(VField); cout << R.Votes[CNum][PNum]; Total = Total + R.Votes[CNum][PNum]; } cout.width(VField); cout << Total << endl; } //-------------------------------------------------------------------------------void DisplayAll(const const ResultsType &R) /*Displays all data entered as well as totals for each candidate Post: Candidate names, votes, and total votes displayed */ { const int CandidateField = 10; const int VotesField = 6; // Display headings cout.setf(ios::left); cout.width(CandidateField); cout << "Candidate"; cout.setf(ios::right); for (int int PNum=0; PNum<R.NumPrecincts; PNum++) { cout.width(VotesField); cout << (PNum+1); } cout.setf(ios::right); cout.width(VotesField); cout << "Total" << endl; // Display rows int CNum=0; CNum<R.NumCandidates; CNum++) for (int DisplayCandidateRow(R, CNum, CandidateField, VotesField); } //-------------------------------------------------------------------------------int main() { ResultsType Results; bool Quit=false; LoadNames(Results); do { cout << endl; char Choice; cout << "Enter precinct, Display results, Quit: "; cin >> Choice; switch (Choice){ case 'E': case 'e': LoadAPrecinct(Results); break break; case 'D': case 'd': DisplayAll(Results); break break; case 'Q': case 'q': Quit = true; break break; } } while (!Quit); return (0); }
8 32
DisplayCandidateRow() has parameters for field widths. This requires field widths changes be made in only one function, which may avoid bugs later.
Some testing and debugging was done at level 1 coding. However, additional runs with different sets of test data need to be done at this point.
Review 21
Modify DisplayCandidateRow() in the Case Study so that percentages are displayed for each candidate, similar to: Candidate 1 Carter 427 Ford 432 McCarthy 48 2 0 0 0 3 342 300 65 4 0 0 0 5 0 0 0 Total 769 732 113 % 48% 45% 7%
Review 22
Modify the Case Study so that it prevents a precinct from being entered twice with a message similar to: What precinct? 3 That precinct has already been entered. Choose another: 2 (Hint: One approach is to use an array of bools with false indicating that a precinct has not been uct, and struct entered, and true indicating that it has. This array should be added to the ResultsType str it should be initialized to all false in the constructor.)
Review 23
The Case Study is not user proof. There are a variety of ways in which the user may crash the program, or enter nonsensical values. Create a list of all of the potential problems, and then indicate how they might be solved.
Chapter Summary
An array, sometimes called a vector, is used to store many values of the same type. Elements of an array are accessed using an index number enclosed in square brackets (Array[0]). An attempt to access an array element outside the declared array size causes a range error. The vector class is used to implement arrays. The vector class includes member functions that allow for dynamic arrays which vary in size throughout program execution. An algorithm for finding an element in an array is linear search, which proceeds from one element to the next until the desired value is found. The typedef statement allows an identifier to be associated with a type, and it can make code easier to read and less error-prone. A string can be manipulated as an array of chars. This allows many useful functions to be written.
8 33
Many algorithms can be developed using an arrays indexes as labels to simplify data storage. Array indexes usually do not directly correspond to the data to be stored, and an algorithm must include offsetting index numbers. A two-dimensional arrays is called a matrix. Matrices are implemented using the matrix library. Elements of a matrix are accessed using row and column numbers enclosed in square brackets following the matric name. Game[0][4] refers to the element in the first row (0) and fifth column (4). The vector and matrix classes are class templates that allow creation of objects of any type. To indicate the type of value that will be stored in the array or matrix, angle brackets enclose the type after the class name when the object is instantiated (vector<int> GradeArray).
uct A struct is a user-defined type that is a simpler form of a class. A str struct uct often contains can contain member functions and data members. A str struct a constructor member function to initialize variables, instantiate objects, and assign values to constants. Most of the work done by a struct constructor is in the initializer list.
Three-dimensional arrays are created using a matrix of arrays. However, multidimensional arrays are rarely used because a more structured organization is usually preferred.
Vocabulary
Array A data type that can store many values of the same type where each element is accessed with an index number. Data Members Variables of a struct which are accessed using dot notation. Default Constructor A constructor that takes no parameters. Dynamic Array An array that varies in size throughout program execution. The vector class enables dynamic arrays to be used in a program. Index The number by which the element in an array is accessed.
uct constructor that is used to invoke str uct Initializer List A part of a str struct struct uct data members. object constructors and make assignments to str struct
Linear Search A searching algorithm that works by proceeding from one element to the next in an array until the desired value is found. Matrix A two-dimensional array. struct A user-defined type that is a simpler form of a class.
uct member function that is automatically called struct Constructor A str struct uct variable is declared. struct when a str
Template A body of code in which one or more types are left initially unspecified. Two-Dimensional Array A matrix implemented with the matrix class. Vector See Array.
8 34
C++
< > Used to enclose the type for a class template declaration.
the matrix library. vector.h The library that implements the vector type.
vector An array type. This type is available by including the vector library. str uct Keyword used to create a user-defined type that can include data struct
8 35
Exercises
Exercise 1
Write a program that generates 25 random numbers between 0 and 99, and then displays all the odd numbers in one list and the even numbers in another. The program output should look similar to: ODD: 13 21 97 ... EVEN: 22 4 84 ...
Exercise 2
Write a program that picks 500 random numbers between 0 and 9, and then displays the number of occurrences of each number. The program output should look similar to:
Exercise 3
Write a program to ask the user for 15 integers, and then display them in reverse order.
Exercise 4
A program that analyzes a set of numbers can be very useful. Write a program that allows the user to enter numbers in the range 1 through 50, terminated by a sentinel, and then perform the following functions on the numbers: Determine the average number Determine the maximum number Determine the range (maximumminimum) Determine the mode (the number that occurs most often) Display a bar graph called a histogram showing the numbers in each five unit range (i.e., 15, 610, 1115, etc.). The histogram may look similar to: 1-5: *** 6-10: ***** 11-15: ****** 16-20: **** 21-25: ****** 26-30: ******** 31-35: **** 36-40: ****** 41-45: ****** 46-50: **
8 36
Exercise 5
Write a function StrUpperCase() that returns the uppercase equivalent of its String argument. (Hint: A lowercase letter can be converted to uppercase by subtracting the quantity (aA))
Exercise 6
When reading an integer from the keyboard, a single incorrect character typed (e.g. a letter rather than a digit) causes the program to crash with a run-time error. This could be prevented by storing the users input in a string variable and then converting the string to an integer. If an error is detected, the value can be re-entered. Write a function StrToInt() that takes a String argument and returns its numerical value. The function should also have a bool reference parameter indicating whether or not an error was detected. (Hint: A single digit character, NumChar, can be converted to an integer by using NumChar0) Use the header:
int StrToInt(const const String &S, bool &Error) /*If S contains only digits which represent an int value, then this value is returned and Error is false. Otherwise, error is true. Post: S converted to an integer returned and Error false. If S cannot be converted, 0 returned and Error true. */
Exercise 7
One variation of the game of Nim, described in Chapter 5 Exercise 12, is played with four piles of stones. Initially, the piles contain 1, 2, 3, and 4 stones. On each turn, a player may take 1, 2, or 3 stones from a single pile. The player who takes the last stone loses. a) Write a program that allows two players to play Nim. Be sure to allow only legal moves. The program should be written so that it can easily be modified for more or less than four piles. The program output should look similar to: Name for player #1: Petra Name for player #2: Elaine Board: 1 2 3 4 Petra Which pile? 3 How many? 2 Board: 1 2 1 4 Elaine Which pile? 4 How many? 3 Board: 1 Petra ... 2 1 1
8 37
b) Modify the program to use an array of PegClass objects to represent the piles as stacks of rings, similar to: | | | | | | | XXX|XXX | | XXX|XXX XXX|XXX | XXX|XXX XXX|XXX XXX|XXX XXX|XXX XXX|XXX XXX|XXX XXX|XXX ---------------------------------------------
Exercise 8
In the game of Hangman one player determines a word that another player tries to guess one letter at a time. a) Write a hangman program that allows one person to enter a word to be guessed, and then clears the screen. Another person can then guess the word by entering letters. The program output should look similar to: Enter word to be guessed: BANANA (screen clears) Word is -----Your letter ($ to guess the word)? S Sorry, there are no Ss Your letter ($ to guess the word)? N Word is --N-NYour letter ($ to guess the word)? B Word is B-N-NYour letter ($ to guess the word)? $ Your guess? BANANA CORRECT! You took 3 tries. b) Modify the hangman program to keep track of the letters that have been guessed, and give an error message if the user enters the same guess twice. The program output should look similar to: ... Word is -N-N... Your letter ($ to guess the word)? S Sorry, you guessed S already. Try again. ... c) Advanced. In traditional hangman, one piece of a stick figure is drawn for each wrong guess. Modify the hangman program to use gotoxy() to illustrate the traditional hangman near the top of the window. When six wrong guesses have been made, the hangman part of the program output should look similar to: -----| o /|\ / \
8 38
Exercise 9
Modify the Mastermind program from Chapter 5 Exercise 13 to use arrays with the following features: Permit the number of pegs (from 1 to 10) to be specified at the start of the program. Permit the number of colors (from 1 to 9) to be specified at the start of the program. Permit both the guess and the secret code to contain duplicates. This will require extra care when counting the number of pegs of the correct color. For example, if the secret code is 1, 2, 3, 4, 5 and the guess is 2, 1, 1, 2, 2 then the program should only report two correct colors (a single 1 and a single 2).
Exercise 10
An array is said to be sorted if its elements are in either increasing or decreasing order. The selection sort algorithm works by repeatedly taking the lowest item from an array and adding it to a new array, so that all the elements in the new array are sorted from low to high. a) Write a function FindLowest() that returns the index of the lowest value in the array. Use the following typedef and function header:
typedef vector<int int int> ArrayType; int FindLowest(const const ArrayType &A) /*Returns the index of the lowest value in the array Post: Index of lowest value in array returned */
b) Write a function Sort() that repeatedly finds the lowest value in an array A, removes it, and adds it to an array T. When all values of A have been moved, T is copied to A with an assignment statement. Use the following header and functions FindLowest() from part (a) and AddToArray() and RemoveFromArray() from the text:
void Sort(ArrayType &A) /*Sorts elements of A from low to high Post: Elements of A are in order from lowest to highest. */
Exercise 11
Use the following steps to write a program to store grades for a class. There are 20 students in the class and each student has five grades during the term. a) Write a type declaration that will store these grades and student names. b) Write a function LoadGrades() that asks the user for the five grades for each student and stores them in the array declared in (a).
8 39
c) Write a function DisplayGrades() that displays a table of the data in the array: STUDENT Brewer Reynolds Warren 1 85 66 89 ... 2 77 75 88 TEST 3 4 89 97 66 77 94 90 5 88 85 93
d) Write a function StuAvg() that displays a list of student averages similar to: STUDENT Brewer Reynolds ... AVERAGE 87.2 73.8
e) Write a function TestAvg() that displays the averages on each test: TEST 1 2 3 4 5 AVERAGE 77.4 67.9 90.1 86.2 83.1
f) Write a menu-driven program that allows the user to select from the four functions above.
Exercise 12
The Penny Pitch game is popular in amusement parks. Pennies are tossed onto a board that has certain areas marked with different prizes. For example:
PUZZLE POSTER PUZZLE BALL GAME POSTER DOLL GAME POSTER GAME BALL DOLL BALL
PUZZLE DOLL
The prizes available on this board are puzzle, game, ball, poster, and doll. At the end of the game, if all of the squares that say BALL in them are covered by a penny, the player gets a ball. This is also true for the other prizes. The board is made up of 25 squares (5 x 5). Each prize appears on 3 randomly chosen squares so that 15 squares contain prizes. Write a penny pitch game program that simulates ten pennies being randomly pitched onto the board. At the end of the game display a list of the prizes won or NONE.
8 40
Exercise 13
The game Life was devised by a mathematician as a model of a very simple world. The Life world is a two-dimensional plane of cells. Each cell may be empty or contain a single creature. Each day, creatures are born or die in each cell according to the number of neighboring creatures on the previous day. A neighbor is a cell that adjoins the cell either horizontally, vertically, or diagonally. The rules in pseudocode style are: If the cell is alive on the previous day Then if the number of neighbors was 2 or 3 the cell remains alive otherwise the cell dies (of either loneliness or overcrowding) If the cell is not alive on the previous day Then if the number of neighbors was exactly 3 the cell becomes alive otherwise it remains dead. For example, the world displayed as: OOOOOOOOOO OOOOOOOOOO OOOXXXOOOO OOOOOOOOOO OOOOOOOOOO OOOOOOOOOO where Xs indicate live cells, becomes OOOOOOOOOO OOOOXOOOOO OOOOXOOOOO OOOOXOOOOO OOOOOOOOOO OOOOOOOOOO Write a program to play Life on a 20 x 20 grid. To initialize the grid, have the program ask the user for the coordinates of live cells on the first day. Generate each days world so long as the user wishes to continue, or until there are no more live cells.
8 41
Exercise 14
A shoe store manager wishes to maintain an inventory of shoes on hand. There are 22 styles of shoes, each of which come in four colors (black, brown, tan, and suede) and 8 sizes (6 through 13). Write a menu-driven program that uses a three-dimensional array to store data, and displays output similar to: Add shoe, Remove shoe, Find Shoe, Quit: A Enter style: 3 Enter color (Black/Brown/Tan/Suede): Tan Enter size: 6 Shoe added. ... Add shoe, Remove shoe, Find Shoe, Quit: F Enter style: 14 Enter color (Black/Brown/Tan/Suede): Brown Enter size: 8 There are 3 shoes of this type. Add shoe, Remove shoe, Find Shoe, Quit: F ...
Exercise 15
Modify the Case Study so that it begins by asking the user for the number of candidates and the number of precincts rather than using constants 3 and 5.
Advanced Exercise 16
In order to better organize its business, the Lawrenceville Lawn Service wants to computerize its customer list. The information for each customer (name, address, size of lawn, and day of the week that they wish their lawn to be mowed) should be stored in parallel arrays. Write a program that allows the user to perform the following functions: Add a new customer Remove a customer Display a table of jobs for a given day. The table should be similar to the one shown in the sample run below, showing the name, address, and total charge including 6% sales tax. LLS charges 2 cents per square yard for cutting. When run, the program output should look similar to: Enter ADD Enter Enter Enter Enter Display, Add, dElete, Quit: a name to be added: Tiger Woods address: 65 Lakeshore Drive lawn size: 1262 day to be cut: Saturday
8 42
Enter Display, Add, dElete, Quit: a ADD Enter name to be added: Julia Winitsky Enter address: 16 Manor Dr Enter lawn size: 2500 Enter day to be cut: Tuesday Enter Display, Add, dElete, Quit: e DELETE Enter name for deletion: Tiger Woods ** Deleted ** Enter Display, Add, dElete, Quit: e DELETE Enter name for deletion: Josephine Bouchard ** Error Name not on list ** Enter Display, Add, dElete, Quit: X ** Please enter D, A, E, or Q ** Enter Display, Add, dElete, Quit: d DISPLAY Enter day to display: Tuesday LAWRENCEVILLE LAWN SERVICE Schedule for: Tuesday NAME Julia Winitsky ADDRESS 16 Manor Dr. COST $50.00
Advanced Exercise 17
The game of Mankala is played on a board like that illustrated below:
Players sit on opposite sides with the large bin to a players right designated her home bin. On a turn, a player selects one of the six pits nearest her, removes the stones, and sows them counterclockwise around the board, placing one stone in each pit including her home bin (but excluding her opponents home bin). If the last stone lands in her home bin, she gets another turn. If the last stone lands in an empty pit on her side of the board, she takes all stones on the corresponding pit of the opponents side and places them in her home bin. When a player cannot play, the game is over and all stones remaining in the opponents pits go to the opponents home bin. The winner is the player with the most stones in his home bin at the end of the game.
8 43
For example, if the bottom player plays first and chooses the fourth pit to play from, the board looks like:
Since the last stone landed in her bin, she plays again. She may choose the first pit this time in order to capture her opponents stones:
Her turn is now over, and her opponent now has a turn. Write a Mankala program. Use simple characters to illustrate the board, and letters to identify the pits, similar to that shown below:
3 0 3 A
3 3 B
3 3 C
3 3 D
3 3 E
3 0 3 F
8 44
9
Objectives
After completing this chapter you will be able to: 1. Understand how a stream processes characters. 2. Use the fstream library. 3. Read numeric and character data from a file. 4. Use the ofstream class. 5. Pass and return stream objects as parameters. 6. Use sequential and random access files.
9
n this chapter you will learn how to read, write, and manipulate files on disk. Files are used by programs to store user data, configuration information, and the results of calculations. Files can also be used as input to a program. Programs of any complexity usually require access to files stored on disk.
9.1 Streams
A stream processes characters, and in C++, streams are implemented with classes. The ios class, discussed in Chapter Six, is the basis of all stream classes. The ios objects, cin (console input stream) and cout (console output stream), are the standard console stream objects. For example, the statement
cout << "This is output";
displays This is output because the string was processed by the console output stream which sends characters to the screen. To process the data in a file, a file stream is used, as discussed in the next section.
ios::nocreate inheritance
More simply, this statement creates an input file stream InFile that can be used to read the data in the file ask-not.txt stored on disk. The constant ios::nocreate prevents the file from being created if it does not exist, which is preferred when opening a file for input. The ifstream class is derived from the ios class, its base class. A derived class has all the properties of its base class. This means that an ifstream object has all the properties of an ios object. For example, an ifstream object can use all the member functions in the ios class. This property of object-oriented programming in which a class can be derived from another class is called inheritance.
91
Following is the ifstream documentation. The most useful functions are described, including some found in the ifstream base class, the ios class: ifstream (fstream.h) Constructors
ifstream(); /*Creates an input file stream Post: Input file stream created that is not attached to a file */ ifstream(const const C-string FileName, int Mode); /*Creates an input file stream and opens FileName. Mode should be ios::nocreate Pre: File with FileName exists Post: Input file open */
Functions
void open(const const C-string FileName, int Mode); /*Opens FileName Mode should be ios::nocreate Post: Input file open */ void close(); /*Closes file associated with calling ifstream object Post: FileName closed */ int fail(); /*Determine if last operation on the stream failed Post: true (1) returned if last operation failed, false (0) returned if last operation succeeded */ int eof(); /*Determines if calling ifstream object is at the end of file Post: 1 returned if ifstream object is at end of file, 0 returned if ifstream object is not at end of file. */ istream & get(char char character); /*Assigns the next character in calling ifstream object to character Post: character assigned the next character in ifstream object */ int NumChars = 1, int Delimiter = EOF); istream & ignore(int /*Extracts up to NumChars from the ifstream until Delimiter is read Post: Characters extracted from ifstream until Delimiter read or NumChars characters read */ long StreamPos); istream & seekg(long /*Moves read pointer to position StreamPos Post: Current read position at StreamPos */ long tellg(); /*Returns the current position of read pointer Post: Current position of read pointer returned */
Operators >> Extracts one data item from the stream into a variable.
92
Many of the ifstream member functions are discussed later in this chapter. The Read File program demonstrates the basic ifstream functions:
/* Read File program */ #include <iostream.h> #include <fstream.h> #include <lvp\string.h> int main() { ifstream InFile("ask-not.txt", ios::nocreate); if (InFile.fail()) { cout << "File could not be opened"; return return(0); } else { String S; while (getline(InFile, S)) cout << ">" << S << endl; cout << "Done" << endl; return return(0); } }
The first line of main() instantiates an ifstream object InFile that is the testing an attempt to file stream associated with disk file ask-not.txt. When an ifstream object open a file is instantiated, the associated file is opened. If an attempt to open the file fails, C++ does not generate a runtime error. Therefore, it is up to the programmer to include code to test for this condition, as is done in the condition of the if statement. The fail() member function returns a value fail() that evaluates to true if the last operation on the stream failed, and false if it succeeded.
getline()
getline(), as used with cin, processes the file through the file stream one line at a time. Each line is then sent to the console output stream for displaying. For this program, a > symbol was also sent to cout to clarify the output. When run, the program displays: >Ask not, what your country can do for you; >Ask what you can do for your country! >John F. Kennedy, Inaugural Speech, 1961 Done
The getline() function is used as the condition of the while loop because it returns a value that evaluates to false when an input operation is false. For example, when the end of the file is reached, getline() returns false. In general, all functions and operators that process a file stream return a value that evaluates to true when an operation is successful and false when an operation fails.
93
Text Files
Text files, sometimes called ASCII files, contain only ASCII characters. There are no special formatting codes or extended ASCII characters in a text file. Most importantly, a text file is in a file format that can be read by any program. For example, an Excel spreadsheet file is saved in a format that can be read only by Excel. This is indicated by the extension .xls that is part of the filename. A text file usually has the extension .txt and contains plain text that can be read by any file. ASCII files may also use the extension .dat to indicate they contain characters that should be interpreted as numbers. For example, a file grades.dat may contain the characters 98 77 60 100. A text file can be created in Turbo C++ or Microsoft Visual C++ by creating a new file, typing the desired data, and then saving the file with a .txt extension. By default, Turbo C++ and Microsoft Visual C++ do not add any special formatting codes to a file. A word processor may also be used to create a text file. However, it is important that the file be saved in the text or ASCII file format. This is usually a special option available in the Save As dialog box of the word processor.
Review 1
Modify the Read File program to display a summary of the file contents. The program output should look similar to: lines: 3 characters: 118
Review 2
Modify the Read File program to count the number of times the word you occurs in the file. The word you embedded in the word your should count as an occurrence. The program output should look similar to: "you" occurs 4 times
94
int main() { ifstream InFile("scores.dat", ios::nocreate); if (InFile.fail()) { cout << "File could not be opened"; return return(0); } else { int Num; int Sum = 0; while (InFile >> Num) { cout << ">" << Num << endl; Sum += Num; } cout << Sum << endl; return return(0); } }
When run, the program displays: >77 >66 >88 >78 >98 407 In this program, each number is read, sent to cout, and then added to Sum to create a running total. The > symbol was also sent to cout to indicate which values were read from the file.
>> whitespace
The >> operator automatically skips whitespace, and is usually used to process a file containing numeric data. Whitespace is spaces, tabs, and newline (end of line) characters. For example, the Read Scores program would produce the same output if scores.dat looked like 77 88 98 66 78
because the extra spaces and new lines would be ignored. Like getline() used in the Read File program, the >> operator is used within the condition of the while loop because it returns a value that evaluates to false when an input operation is false. For example, when the end of the file is reached, >> returns false. When reading data as numeric values, false is also returned when there is an attempt to read non-numeric data. For example, if scores.dat looked like: 77 66 eighty-eight 78 98 the Read Scores program would produce the output: >77 >66 143
read error
95
Review 3
Modify the Read Scores program to display the number of integers and the following statistics on the values in the data file. The program output should look similar to: Average: 81.4 Number of values: 5 Maximum: 98 Minimum: 66
Review 4
Create a text file that contains the following: Objectville 23094 10239 1 Bjarne City 4562 328 125 1 In the file above, each group of lines represents a city. The first line holds the name of the city. The remaining lines hold the number of voters in each district of the city. A value of 1 indicates the end of the list of districts. Write a program that displays a summary of this file. The program output should look similar to: Objectville: 33333 Bjarne City: 5015
96
The file quick.txt contains: Hi and Bye! When the Read Characters program is run, the following is displayed: >H >i > >a >n >d > >B >y >e >! > Done The blank line after the word and is the end-of-line character that was read from the file. This character can be recognized by comparing it to the newline character, \n. For example, the while loop can be written as:
while (InFile.get(Character)) if (Character == '\n') cout << ">end-of-line" << endl; else cout << ">" << Character << endl;
When run, the program now displays: >H >i > >a >n >d >end-of-line >B >y >e >! >end-of-line Done Tab characters (\t) can be detected in the same way.
Review 5
Modify the Read Characters program to display a summary of the number of characters in quick.txt. Do not count end-of-line characters.
97
programming style
reads an item from the InFile stream. If the end-of-file has been reached, the loop is exited, otherwise the loop continues. However, unexpected data (a letter when numbers are being read) or a missing file do not return true for eof() and may lead to an infinite loop. It is good programming style to use the return value of a read operation as the loop condition to determine file status. For example, InFile >> Num used in the Read Scores program is preferred over eof(). The ignore() function is used to read and then discard characters from the input file stream. For example, the statement
MyFile.ignore(20); // extracts 20 characters
reads and discards 20 characters from the MyFile stream. By default the ignore delimiter is end-of-file. If there are fewer than 20 characters left in the file, all the remaining characters are discarded until end-of-file is read. A delimiter may also be specified in ignore(), as in the statement
MyFile.ignore(80,'\n'); // extracts up to 80 chars until '\n' is reached
which extracts characters until 80 characters have been extracted or an end-of-line character is extracted. This form of ignore() is often used to skip the rest of a line of input from a file.
More simply, this statement creates an output file stream OutFile that can be used to write data to the file my-data.txt on disk. Like the ifstream class, the ofstream class is derived from the ios class. Following is documentation of some of the most useful ofstream functions:
98
Functions
void open(const const C-string FileName); /*Opens FileName Post: Output file open */ void close(); /*Closes file associated with calling ofstream object Post: FileName closed */ int fail(); /*Determine if last operation on the stream failed Post: false (0) returned if last operation failed, true (1) returned if last operation succeeded */ long StreamPos); ostream & seekp(long /*Moves write pointer to position StreamPos Post: Current write position at StreamPos */ long tellp(); /*Returns the current position of write pointer Post: Current position of write pointer returned */ int width(int int FieldWidth); /*Sets field width used when data written to a file Post: Field width set for writing data to a file */ long setf(ios::fixed); /*Uses floating point notation when writing data to a file Post: Data formatted as floating point for writing to a file */ int precision(int int NumDecimals); /*Sets number of decimals to use in floating point notation Post: Data formatted as floating point to NumDecimals decimal places for writing to a file */
Operators << Inserts one data item into the file stream.
99
Many of the ofstream member functions are discussed later in this chapter. The Write File program demonstrates the basic ofstream functions:
/* Write File program */ #include <iostream.h> #include <fstream.h> #include <lvp\string.h> int main() { ofstream OutFile("my-data.txt"); if (OutFile.fail()) { cout << "File could not be opened"; return return(0); } else { OutFile << "The first line of the file." << endl; OutFile << (12 + 34) << endl; OutFile << "PI="; OutFile.setf(ios::fixed); OutFile.precision(2); double PI=3.1415926; OutFile.width(10); OutFile << PI << endl; OutFile << "The last line of the file."; return return(0); } }
fail()
The first line of main() instantiates an ofstream object OutFile that is the file stream associated with disk file my-data.txt. When an ofstream object is instantiated, the associated file is opened. If the file does not exist, the ofstream object creates one. If an attempt to open or create the file fails, C++ does not generate a runtime error. Therefore, it is up to the programmer to include code to test for this condition, as done in the condition of the if statement. The fail() member function returns a value that evaluates to false if the last operation on the stream failed, and true if it succeeded. The << operator is used to send data to the OutFile stream for writing to a file. Formatted data is written to a file using the width(), setf(), and precision() member functions. When run, the program displays no output unless there is a problem creating or opening my-data.txt. After running the program, opening my-data.txt displays: The first line of the file. 46 PI= 3.14 The last line of the file.
<<
9 10
instantiate an ifstream MyFile and then associate the file my-data.txt with the MyFile stream. Files are closed automatically by the ifstream and ofstream classes. However, by explicitly closing a file within a program, a different file can be associated with a stream, as in the statements:
ifstream MyFile; MyFile.open("my-data.txt", ios::nocreate); // process file MyFile.close(); MyFile.open("progdata.txt", ios::nocreate) // process file
c_str()
9 11
/*File Statistics program. Counts number of characters and lines in one or more text files specified by the user. End-of-line characters are not counted as characters. */ #include #include #include #include <iostream.h> <fstream.h> <lvp\string.h> <lvp\bool.h>
//-------------------------------------------------------------------------------void DisplayStats(ifstream &InFile) /*Displays the number of characters and lines in InFile. End-of-line characters are not counted as characters. Pre: InFile open. Post: File statistics displayed. */ { String S; long TotalChars = 0; long TotalLines = 0; while (getline(InFile, S)) { TotalChars+=S.length(); TotalLines++; } cout << "Total characters: " << TotalChars << endl; cout << "Total lines: " << TotalLines << endl; } //-------------------------------------------------------------------------------int main() { ifstream InFile; String FileName; while (true) { cout << "Enter name of file (Enter to quit): "; getline(cin, FileName); if (FileName.length() == 0) break break; InFile.open(FileName.c_str(), ios::nocreate); if (InFile.fail()) cout << "File cannot be opened" << endl; else { DisplayStats(InFile); InFile.close(); } } return return(0); }
When run, the program may display output similar to: Enter name of file (Enter File cannot be opened Enter name of file (Enter Total characters: 118 Total lines: 3 Enter name of file (Enter Total characters: 1244 Total lines: 47 Enter name of file (Enter to quit): ask-what.txt to quit): ask-not.txt
to quit): filestat.cpp
to quit):
9 12
Review 6
Modify the File Statistics program so that its output is written to a file, stats.dat, rather than to the screen. Do this by including an argument for the output stream in DisplayStats(). Run the program and then verify that it worked by opening stats.dat.
Review 7
Write a function FileExists() that returns a bool value that is true if and only if its argument is an existing filename. Use the prototype:
const String & FileName); bool FileExists(const
deletes my-file.txt from disk. The remove() function requires a C-style string as an argument. If a String type variable is used as an argument, it must call c_str(). For example:
String FileToDelete; cout << "Enter name of file to delete: "; getline(cin, FileToDelete); remove(FileToDelete.c_str());
The rename() function takes the name of a file as its first argument and the new name of the file as a second argument. For example, the statement
rename("foo.txt", "bar.txt");
renames the file foo.txt as bar.txt. The rename() function also requires C-style string arguments. Both the remove() and rename() functions return integer values indicating the result of the operation. A returned value of 0 indicates success; a returned value of 1 indicates an error occurred. The return values may be used as follows:
String FileToDelete; cout << "Enter name of file to delete: "; getline(cin, FileToDelete); if (remove(FileToDelete.c_str())!=0) cout << "Remove operation failed" << endl; else cout << FileToDelete << " has been removed" << endl;
9 13
istream class
Note the ampersand used to indicate that this function returns a reference to a stream. The istream class (input stream) is in the iostream library, and is inherited by the ifstream class. To demonstrate a function that returns a reference, the following getline() function reads a long value and then ignores the rest of the line:
istream & getline(istream &InFile, long &N) /*Assigns the next value in InFile to N Post: Value from InFile stream assigned to N */ { InFile >> N; InFile.ignore(80,'\n'); return return(InFile); }
This getline() assumes that there are no more than 80 characters after the
long value in the stream. The syntax in the retur n statement does not vary eturn
Review 8
Write two variations of getline() that obtain a particular value type from a line in a file and ignores the rest of the characters on the line. One function should obtain the first int from a line in a file. The other should obtain the first char value from a line in a file.
Review 9
Write a variation of getline() that obtains a bool value from a line in a file and ignores the rest of the characters. It should return true if and only if the first characters on the line are TRUE or true, and false otherwise.
to read every other item until the desired item is found, which means only three items would need to be read.
file pointers
Random access to a file is possible because the file stream maintains a pair of position indicators or pointers. The get pointer tells where the next reading operation will start. The put pointer tells where the next writing operation will occur. For example, a stream may look like:
A write operation to this stream would take place at the put pointer. For example, writing the character R overwrites the character N, and the put pointer moves to the next character, B:
Similarly, a read operation to this stream reads the character T and moves the get pointer to the next character, H.
seekp() seekg()
A program that uses random access files must manipulate the get and put pointers. To move the pointers, the seekg() and seekp() functions are used. These function prototypes appear in the ifstream and ofstream documentation. The positions of the pointers are indicated in bytes (characters) with the first character in the file considered to be at position 0. For example, if file composer.txt contains BEETHOVENBACH, and MyFile is the file stream, then the statements:
char ch; MyFile.seekg(4); MyFile >> ch; MyFile.seekp(0); MyFile << ch; // Move the get pointer to character 4 ("H") // Read character at get pointer // Move the put pointer to character 0 ("B") // Write ch ("H") at put pointer (overwriting "B")
will modify the file to contain HEETHOVENBACH. The get and put pointers are moved to the beginning of the file stream with the statements:
MyFile.seekg(0); MyFile.seekp(0);
ios::end
To move a pointer to the end of the file stream, the constant ios::end can be used. For example, the statement
MyFile.seekp(0, ios::end);
moves the put pointer 0 characters past the end of the file.
To append data to a file, the put pointer must first be moved to the end of the file before writing the data to the file. For example, the statements
MyFile.seekp(0, ios::end); MyFile << "MOZART" << endl;
9 15
More simply, this statement creates a file stream MyFile that can be used to read or write data to the file composer.txt on disk.
fstream()
The fstream constructor requires two parameters. The first parameter indicates the filename, the second indicates how the stream should be used. The ios constant in indicates the stream will be read from. The ios constant out indicates the stream will be written to. In this case, the | symbol was used in the parameters to tell the compiler that both in and out are to be used. The fstream class is derived from the ios class. The fstream class includes all the functions and operators found in the ifstream and ofstream classes, and therefore its documentation will not be included here. The Read and Write File program demonstrates the fstream class:
/*Read and Write File program. */ #include <iostream.h> #include <fstream.h> int main() { fstream MyFile("composer.txt", ios::in | ios::out); if (MyFile.fail()) { cout << "File could not be opened"; return return(0); } else { char Character; MyFile.seekg(4); // Advance to character 4 MyFile >> Character; // Read character at get pointer MyFile.seekp(0); // Move the put pointer to character 0 MyFile << Character; // Write the character at put pointer MyFile.close(); return return(0); } }
When run, the program displays no output unless there is a problem opening composer.txt. Before running the program, composer.txt contains: BEETHOVENBACH After running the program, composer.txt contains: HEETHOVENBACH
9 16
\n
The end-of-line character (\n) is stored as two characters in a file. This is important to note when manipulating data with file pointers.
Review 10
Write a program that encodes a file by replacing each letter in the file with a coded version, leaving non-letters unchanged. Use the function CodeChar() to encode each letter:
char CodeChar(const const char Plain) /*Encodes Plain Pre: Plain is a letter, uppercase or lowercase Post: Coded version of Plain returned */ { switch switch(Plain) { case 'Z': return ('A'); case 'z': return ('a'); default char default: return return(char char(Plain+1)); } }
Review 11
Write a function that appends one file to another, with the file names given as String arguments. For example, if the two files are foo.txt and bar.txt, then the program should copy the contents of bar.txt onto the end of foo.txt. Assume that the files can be processed as lines of text using String and getline().
Case Study
In this Case Study, an inventory management program will be written. The programs in this chapter are simplistic in that they only use character-level access. More commonly, a program manipulates larger units of data, for example structures containing information about a student in a school or a book in a bookstore. In more sophisticated C++ programming, this is accomplished by carefully formatting the data into a memory buffer, which is beyond the scope of this text. However, we can accomplish the same thing at only a small cost in efficiency by using random access files.
specification
Write an inventory management program for a bookstore. The program should be menu-driven to allow a title to be recorded (the author and copies in stock), a list of all the titles to be displayed, a selected title examined, and to update the stock for a title. Each book has a unique identification number. When run, the program output should be similar to:
9 17
Add title, Check/Change, List, Quit: L 0. The Shipping News E. Annie Proulx 1. A Good Scent Robert Butler 2. A Thousand Acres Jane Smiley Add title, Check/Change, List, Quit: A Enter title: Rabbit at Rest Enter author: John Updike Enter number of copies: 3 Add title, Check/Change, List, Quit: C Enter number of book to change: 2 2. A Thousand Acres Jane Smiley Add one to copies, Subtract one, Cancel: Add title, Check/Change, List, Quit: L 0. The Shipping News E. Annie Proulx 1. A Good Scent Robert Butler 2. A Thousand Acres Jane Smiley 3. Rabbit at Rest John Updike Add title, Check/Change, List, Quit: Q
12 6 8
8 A 12 6 9 3
designlevel 1
The main() function is designed first. The pseudocode for the major tasks is: do Display menu of choices (Add title, Check/Change, List, Quit) switch A or a: AddBook C or c: ChangeBook L or l: ListBooks Q or q: Quit is true while (!Quit) Next, the main() pseudocode is used to determine the data design. A
char variable Choice is needed to hold the users menu choice. A bool variable Quit is needed to end the do loop. To store the book data perma-
nently, a file on disk will be used. Since the file will be both read from and written to, an fstream object BookFile is needed. The best data structure for storing the related information about a single uct: struct book, or record, is a str
struct BookType { long CopiesInStock; String Title; String Author; };
An algorithm for storing and locating the book records must now be uct could be writstruct developed. To store records, each data member in the str ten to the file separated by end-of-line characters (endl). To efficiently locate the records in the random access file, each record should take up the same amount of space. With each record having the same length the file is essentially divided into units. This makes it possible to know where to move the get and put pointers to access a specific record. In this case, the unit length could be computed as 80 characters for the book title, 50 characters for the author, 3 characters for the number of copies, and 2 charac9 18
ters for each end-of-line so in this case 6 characters for each record, for a total unit size of 139 characters. As a measure of safety, 150 characters will be allowed per record. The random access file could be thought of as:
Using this algorithm, the following statement moves the put pointer to the beginning of the second record:
F.seekp(1*150);
could be used to move the put pointer. A RecNum of 0 will move the pointer to the 0th character in the file; a RecNum of 1 will move the pointer to the 150th character in the file, and so on. This algorithm requires a constant to store the maximum record size:
const long MaxRecSize = 150;
codinglevel 1
At this point, rather than coding main() as designed, a main() that tests writing and reading book records will be coded. For writing and reading records, a function NumRecords is needed for determining the number of records in the file:
long NumRecords(fstream &F) /*Determines number of records in F based on record size of MaxRecSize Pre: F is open Post: Number of records in F returned */ { F.seekp(0, ios::end); if (F.tellp()==0) return return(0); else return return(1+F.tellp()/MaxRecSize); }
This function moves a pointer to the last character in the file and determines the location of the pointer. If the pointer is at 0, then the file contains no records. If the pointer is at some value greater than 0, the location of the pointer is divided by MaxRecSize. Since the last record will likely not use all 150 characters available for it, the number of characters in the file will not be a multiple of 150. Therefore, the integer division truncates any decimals and then 1 added to the quotient to compute the number of records. For example, if there are three records in the file, and the last record has 107 characters, tellp() returns 407. The expression 407/150 results in 2.71333, which is truncated to 2. Adding 1 results in 3.
9 19
The order of the if condition is important. Checking for a valid RecNum must be done before checking the success of seekp(). If a seek is performed with a bad value, the results are unpredictable. A RecNum equal to the number of records occurs when a new record is to be appended. To read a record in the file, the ReadBook() function must be coded:
bool ReadBook(fstream &F, const long RecNum, BookType &Book) /*Reads record RecNum into Book Pre: F is open f or reading Post: Book contains record RecNum. false returned if the read fails, otherwise true returned */ { if ((RecNum < NumRecords(F)) && (F.seekg(RecNum*MaxRecSize))) { getline(F, Book.CopiesInStock); getline(F, Book.Title); getline(F, Book.Author); return return(true); } else return return(false); }
ReadBook uses the getline() for long values created in Section 9.11, as well as the getline() for strings. All three functions require the constant, MaxRecSize. Defining this constant inside each function may lead to inconsistency and bugs. Defining the constant in main() and then passing it as a parameter is cumbersome. A third approach is to define the constant before the definitions of the functions, which makes the constant accessible from any function. Defining a constant this way is called a global declaration. Global constants should be used only when absolutely necessary because they can make a program harder to understand. A more elegant solution is presented in the next chapter.
global declaration
9 20
const long MaxRecSize = 150; // Global constant struct BookType { long CopiesInStock; String Title; String Author; }; //-------------------------------------------------------------------------------istream & getline(istream &InFile, long &N) /*Assigns the next value in InFile to N Post: Value from InFile stream assigned to N */ { InFile >> N; InFile.ignore(100,'\n'); return return(InFile); } //-------------------------------------------------------------------------------long NumRecords(fstream &F) /*Determines number of records in F based on record size of MaxRecSize Pre: F is open Post: Number of records in F returned */ { F.seekp(0, ios::end); if (F.tellp()==0) return return(0); else return return(1+F.tellp()/MaxRecSize); } //-------------------------------------------------------------------------------bool ReadBook(fstream &F, const long RecNum, BookType &Book) /*Reads record RecNum into Book Pre: F is open for reading Post: Book contains record RecNum. false returned if the read fails, otherwise true returned */ { if ((RecNum < NumRecords(F)) && (F.seekg(RecNum*MaxRecSize))) { getline(F, Book.CopiesInStock); getline(F, Book.Title); getline(F, Book.Author); return return(true); } else return return(false); }
9 21
//-------------------------------------------------------------------------------bool WriteBook(fstream &F, const long RecNum, const BookType &Book) /*Writes Book to F at position RecNum Pre: F is open for reading Post: Book written to F at RecNum record. false returned if read fails, true returned otherwise */ { if ((RecNum <= NumRecords(F)) && (F.seekp(RecNum*MaxRecSize))) { F.seekp(RecNum*MaxRecSize); F << Book.CopiesInStock << endl << Book.Title << endl << Book.Author << endl; return return(true); } else return return(false); } //-------------------------------------------------------------------------------int main() { fstream BookFile("BookTest.txt", ios::in | ios::out); cout << NumRecords(BookFile) << endl; BookType Book1, Book2; Book1.Title = "First Book!"; Book1.Author = "Author Name"; Book1.CopiesInStock = 12; WriteBook(BookFile, 0, Book1); ReadBook(BookFile, 0, Book2); cout << Book2.Title << "/" << Book2.Author << "/" << Book2.CopiesInStock << endl; cout << NumRecords(BookFile) << endl; return return(0); }
When run, the program displays: 0 First Book!/Author Name/12 1 This simple test shows that the functions appear to work. However, more complex test programs are usually desired to thoroughly test functions.
Review 12
Write a function ListBooks() that displays a list of all books in the file used in the Case Study. Use the header:
void ListBooks(fstream &F) /*Displays a list of the books in F Pre: F is open for reading Post: List of books displayed */
Review 13
Modify WriteBook() in the Case Study so that it first checks the total length of the fields to verify that they do not exceed MaxRecSize.
9 22
designlevel 2
In the next level of design, the real main() and the functions it calls are refined. The refined main() pseudocode is: fstream BookFile("bookdata.txt", ios::in | ios::out) char Choice bool Quit = false do Display menu of choices (Add title, Check/Change, List, Quit) switch A or a: AddBook(BookFile) C or c: ChangeBook(BookFile) L or l: ListBooks(BookFile) Q or q: Quit=true while (!Quit) The AddBook() pseudocode is: Get book title, author, and stock from user WriteBook(BookFile, NumRecords(BookFile), Book) The ChangeBook() pseudocode is: Get book number from user Show book selected by user Display menu of choices (Add one to copies, Subtract one, Cancel) switch A or a: add one to copies in stock S or s: subtract one from copies in stock C or c: make no changes The ListBooks() pseudocode is: for each book in the file ReadBook(BookFile, RecNum, Book) show book The ChangeBook() and ListBooks() functions include a step that shows a books data. The show book step should also be a function. Using the final design, the graphical representation of the program is:
9 23
The diagram shows that there is a set functions handling BookType operations (WriteBook(), ShowBook(), ReadBook(), NumRecords()), and two utility functions (the two getline() functions) to access the file.
codinglevel 2
9 24
//-------------------------------------------------------------------------------bool WriteBook(fstream &F, const long RecNum, const BookType &Book) /*Writes Book to F at position RecNum Pre: F is open for reading Post: Book written to F at RecNum record. false returned if read fails, true returned otherwise */ { if ((RecNum <= NumRecords(F)) && (F.seekp(RecNum*MaxRecSize))) { F.seekp(RecNum*MaxRecSize); F << Book.CopiesInStock << endl << Book.Title << endl << Book.Author << endl; return return(true); } else return return(false); } //-------------------------------------------------------------------------------void ShowBook(const const long N, const BookType &Book) /*Displays a book's data in a formatted line Post: N, Book displayed on a formatted line */ { cout.width(2); cout << N << ". "; cout.setf(ios::left); cout.width(20); cout << Book.Title << " "; cout.width(20); cout << Book.Author << " "; cout.setf(ios::right); cout.width(5); cout << Book.CopiesInStock << endl; } //-------------------------------------------------------------------------------void ChangeBook(fstream &BookFile) /*Displays a book and allows user to change its stock. Pre: BookFile is open for read/write Post: Book selected by user has been displayed and stock may have been changed. */ { long BookNum; BookType Book; while (true) { cout << "Enter number of book to change: "; getline(cin, BookNum); if (ReadBook(BookFile, BookNum, Book)) break break; cout << "Bad book number" << endl; } ShowBook(BookNum, Book); char Choice; cout << "Add one to copies, Subtract one, Cancel: "; Choice = getche(); cout << endl; switch (Choice) { case 'A': case 'a': Book.CopiesInStock++; WriteBook(BookFile, BookNum, Book); break break; case 'S': case 's': Book.CopiesInStock--; WriteBook(BookFile, BookNum, Book); break break; case 'C': case 'c': cout << "Change canceled" << endl; break break; } }
9 25
//-------------------------------------------------------------------------------void AddBook(fstream &BookFile) /*Adds a book record to BookFile Pre: BookFile is open for read/write Post: Book data entered by user appended to BookFile. */ { BookType Book; cout << "Enter title: "; getline(cin,Book.Title); cout << "Enter author: "; getline(cin,Book.Author); cout << "Enter number of copies: "; getline(cin,Book.CopiesInStock); WriteBook(BookFile, NumRecords(BookFile), Book); } //-------------------------------------------------------------------------------void ListBooks(fstream &BookFile) /*Displays a formatted table of book data. Pre: BookFile is open for reading Post: List of books displayed */ { long i; for (i=0; i < NumRecords(BookFile); i++) { BookType Book; ReadBook(BookFile, i, Book); ShowBook(i, Book); } } //-------------------------------------------------------------------------------int main() { fstream BookFile("BookData.txt", ios::in | ios::out); bool Quit = false; char Choice; do { cout << "Add title, Check/Change, List, Quit: "; Choice = getche(); cout << endl; switch (Choice) { case 'A': case 'a': AddBook(BookFile); break break; case 'C': case 'c': ChangeBook(BookFile); break break; case 'L': case 'l': ListBooks(BookFile); break break; case 'q': case 'Q': Quit = true; break break; default default: cout << "Bad command" << endl; } } while (!Quit); return return(0); }
When run, the program output is similar to that shown in the specification.
Review 14
uct BookType with two additional data members, Publisher Modify the Case Study to use the str struct and PubYear. Be sure to modify all the code to use the two additional data members.
9 26
Review 15
Modify the Case Study to display titles that contain a word entered by the user. The program output should look similar to: ... Enter a word from the title: good Matches: 1. A Good Scent 2. Good Grief, Charlie Brown! Choose by number: 2 ...
Review 16
Modify the Case Study to include a purge command that removes all the records from the file with zero CopiesInStock. To do this, copy all the nonzero records to a new file, and then use remove() and rename() to make this new file the one used by the program.
Chapter Summary
A stream processes characters, and in C++, streams are implemented with classes. The fstream library contains the ifstream class, ofstream class, and the fstream class. The fstream classes are derived from the ios class and therefore inherits all the properties of the ios class. The ifstream class is used to instantiate an input (read) file stream. The ofstream class is used to instantiate an output (write) file stream. The fstream class is used to instantiate a file stream for input or output. In general, all functions and operators that process a file stream return a value that evaluates to true when an operation is successful and false when an operation fails. A file on disk is a set of characters. To process a file, it must have a file stream associated with it. Characters can be read from the file stream as numbers, strings, or characters. The >> operator automatically skips whitespace and is usually used to process a file containing numbers. The get() member function is usually used to process a file containing characters. The getline() function is usually used to process a file containing strings. The ignore() function is used to read and then discard characters from the file stream. The eof() function is used to detect the end-of-file. The << operator is used to write data to the output stream. The width(), setf(), and precision() member functions can be used to write formatted data to a file. The open() and close() member functions can be used to change the file associated with a file stream. This is useful when opening a file specified by the user. The c_str() function is a member function of the string class and is used to convert a string entered by the user to a C-style string which is required by the open() function. Stream object parameters must be passed as reference arguments. A function may return a reference to a stream object. The remove() and rename() functions in the stdio library are used to rename or delete a file.
9 27
The items in a sequential access file are accessed one item at a time in the order that they are stored. The items in a random access file are accessed in any order, usually determined by an algorithm implemented in a program. Random file access is possible because the file stream maintains the get and put pointers for reading and writing to a file. The pointers are moved with the seekg() and seekp() functions, respectively. The tellg() and tellp() functions are used to determine the positions of the get and put pointers, respectively.
Vocabulary
Base Class A class that is used as the basis of an inherited class. Derived Class A class that has all the properties of its base class. Get Pointer The file stream pointer that tells where the next read operation will start. Global Declaration Defining a constant before function definitions to make it accessible from any function. Inheritance The property of object-oriented programming in which a class can be derived from another class. Put Pointer The file stream pointer that tells where the next write operation will occur. Random Access File A file with items that are accessed in an arbitrary order, usually determined by an algorithm implemented in a program. Sequential Access File A file with items that are accessed one after the other in the order stored. Stream Processes characters. Whitespace Spaces, tabs, and newlines in a file.
C++
& Used to indicate that a reference is being returned by a function. >> Operator used to read data from a file stream.
c_str() A String member function that converts a string to a C-style string. fstream A class in the fstream library that is used to create an output or input file stream. ifstream A class in the fstream library that is used to create an input file stream. ios::end The ios constant that moves the file pointer to the end of a file. ofstream A class in the fstream library that is used to create an output file stream. stdio.h The standard input/output library that contains the rename() and remove() functions for renaming and deleting a file.
9 28
Exercises
Exercise 1
Write a program that displays the number of words and the average word length in the text file source.txt. Consider a word to be any sequence of letters terminated by nonletters. For example, forty-nine is two words.
Exercise 2
Enter name of file: myfile.txt Enter word to search for: gotta Enter word to replace it with: got to
Write a program that replaces all occurrences of a word or phrase in a file with a specified word or phrase. The program output should be similar to:
Exercise 3
Write a program that copies a file named source.cpp containing C++ code to another file named src.cpp with all comments eliminated. Be sure to consider both /* */ and // formatted comments.
Exercise 4
Pascal required
Write a program that provides some Pascal to C++ translation. The program should replace Pascal keywords and symbols with their C++ equivalents. Store the list of translations in a file so that it can be easily extended. The following table provides some of the translations: Pascal begin { (* := <> if else while do C++ { /* /* = != if ( ; else while ( ) Pascal end } *) = not then repeat until C++ } */ */ == ! ) do { } while (
9 29
Exercise 5
Enter name of file: myfile.txt WORD NUMBER the 57 boy 8 and 12 ...
a) Write a program that lists all the unique words in a file, and how many times they occurred. Ignore capitalization. The program output should be similar to:
b) Modify the program to list the words in alphabetical order. Do this by using either the sorting algorithm presented in Chapter Eight Exercise 10, or by keeping the words in order as they are read.
Exercise 6
Line 1: The correct answers, one character per answer Line 2: Name of the first student (length <= 30 chars) Line 3: Answers for the student in line 2 The remaining lines: student names and answers on separate lines
Test results for a multiple choice test can be stored in a text file as follows:
For example: BADED Smithgall BADDD DeSalvo CAEED Darji BADED Write a program that processes the test results file for any number of students. The program output should be similar to: Smithgall DeSalvo Darji 80% 60% 100%
Exercise 7
Write a program that processes the data file described in Exercise 6 to produce a statistical analysis showing the responses given to each question, and the percent of students who gave the correct answer. To easily understand the output, the correct answers should be marked with an asterisk. For example: 1 2 3 4 5 9 30 A 0 3* 0 0 0 B 2* 0 0 0 0 C 1 0 0 0 0 D 0 0 2* 1 3* E 0 0 1 2* 0 % 67 100 67 67 100
Exercise 8
A Mad-Lib story is a story where nouns and verbs in a paragraph are randomly replaced with other nouns and verbs, usually with humorous results. Write a program that displays a Mad-Lib story. The program should use three files: story.txt which contains a story with # signs as noun placeholders, and % signs as verb placeholders. For example: Bugsy Kludge is a # with our company. His job is to % all of the #s. verbs.txt which contains verbs, one per line. For example: run display eat nouns.txt which contains nouns, one per line. For example: banana soprano elephant vegetable The program output may be similar to: Bugsy Kludge is a vegetable with our company. His job is to display all of the elephants.
Exercise 9
The idea of merging two or more files is an important one in programming. One approach is to merge the ordered data of two files into a third file, keeping the data in order. Write a program that merges the integers ordered from low to high in two files into a third file, keeping the order from low to high. First, create two files containing about 15 to 20 integer values, each file in order from low to high. Have the files hold different numbers of integers. For example: File 1: 12 23 34 45 56 67 69 123 133 File 2: 4 5 10 20 35 44 100 130 150 160 180 The program should not use an array to temporarily store the numbers, but should merge the two files by taking one element at a time from each. Do not use the seekp() or seekg() functions in the program. After running the program, the third file should look similar to: 4 5 10 12 20 23 34 35 44 45 56 67 69 100 123 130 133 150 160 180
9 31
Exercise 10
The algorithm used in the program in Exercise 9 is sometimes used as part of a sorting algorithm with data that is too large to be stored in memory at once. For example, to sort a large file large.dat that is twice as large as will fit in memory, half can be read into an array, the array sorted and then written to a file numbers1.dat. Next, the second half of large.dat can be read into the array, sorted, and then written to numbers2.dat. Finally, the two files can be merged in order back into large.dat. All of this can be done without using the seek functions. Implement this algorithm in a program. Test the program with a file that contains 30 integers sorted from low to high.
Exercise 11
The early success of the World Wide Web is largely due to the simplicity of HTML (HyperText Markup Language), the code used to represent pages. HTML provides a way to describe Web pages that can be interpreted by any computer, any screen width, etc. A Web page might be stored in a file like this: Do not go gentle into that good night, <BR> Old age should burn and rave at close of day; <BR> Rage, rage against the dying of the light. <P> Though wise men at their end know dark is right, <BR> Because their words had forked no lightning they <BR> Do not go gentle into that good night.<P> <HR> Tags are enclosed in angle brackets, < >. The command <BR> means to start a new line. The command <P> means to start a new paragraph (a blank line). The command <HR> means to draw a horizontal rule. When these commands are interpreted, the following is displayed: Do not go gentle into that good night, Old age should burn and rave at close of day; Rage, rage against the dying of the light. Though wise men at their end know dark is right, Because their words had forked no lightning they Do not go gentle into that good night. -----------------------------------------------a) Write a program that properly displays a file containing these HTML format codes. b) Modify the program so that the user may specify the display line width. For example, a width of 30 should display the HTML document as: Do not go gentle into that good night, Old age should burn and rave at close of day; Rage, rage against the dying of the light. ...
9 32
Exercise 12
The manager of the campus radio station needs a program to keep track of the CDs in the stations library. Write a program that stores each CD title, artist, status, and location in a file. The status may be OK, damaged, or lost. The location should be the shelf number (an integer). The station librarian should be able to perform the following functions on the file: Add CDs Find and change the information stored for a CD by specifying the title Display the information for all of the lost CDs Display the information for all of the CDs on a given shelf Display the information for all of the CDs by a given artist
Exercise 13
Modify the HangMan program from Chapter Eight Exercise 8 to use words stored in a file. Have the program choose words from the file at random. One algorithm for doing this is to generate a random number and then use the word that correlates to that number. For example, if the number generated is 7, the 7th word in the file is used.
Exercise 14
All database programs perform basically the same tasks, whether the database stores student, CD, book, or soccer game records. This realization led to general database programs like dBase and Access. Write a small-scale general database program. Have the program get the filename from the user. If it is found on the disk, it will be opened. If not, it will be set up as a new file. The user specifies the names of the fields, the field types (number or text), and their field lengths (if text). The program writes the setup information to the 0th record of the file, along with the maximum record size. The user then has the option of adding or listing records. The program output should be similar to: Enter name of file to use: soccer.dat File not found. Set up a new file (Y/N)? Y Enter a field (blank to quit): Opponent Text or Numeric: T Enter length: 25 Enter a field (blank to quit): OppScore Text or Numeric: N Enter a field (blank to quit): OurScore Text or Numeric: N Enter a field (blank to quit): Setup, Add, List, Quit: A Enter Opponent: South Fork High Enter OppScore: 2 Enter OurScore: 3 Setup, Add, List, Quit: L Opponent OppScore OurScore South Fork High 2 3 Setup, Add, List, Quit: Q
9 33
Exercise 15
Owners of Web servers like to monitor access to their servers so they can determine if their servers are getting used, if customers are visiting, etc. All servers create a log file of requests. A typical log file may look like this:
38.249.60.78 - - [22/Mar/1996:08:07:13 -0500] "GET / HTTP/1.0" 200 1260 38.249.60.78 - - [22/Mar/1996:08:07:14 -0500] "GET /new.gif HTTP/1.0" 200 285 38.249.60.78 - - [22/Mar/1996:08:07:16 -0500] "GET /seal.gif HTTP/1.0" 200 9529 202.32.234.125 - - [22/Mar/1996:09:42:43 -0500] "GET /new.gif HTTP/1.0" 200 285 202.32.234.125 - - [22/Mar/1996:09:42:46 -0500] "GET / HTTP/1.0" 200 1260 202.32.234.125 - - [22/Mar/1996:09:42:57 -0500] "GET /seal.gif HTTP/1.0" 200 9529 159.164.29.128 - - [22/Mar/1996:09:51:14 -0500] "GET / HTTP/1.0" 200 1260 159.164.29.128 - - [22/Mar/1996:09:51:14 -0500] "GET /new.gif HTTP/1.0" 200 285 159.164.29.128 - - [22/Mar/1996:09:51:16 -0500] "GET /seal.gif HTTP/1.0" 200 9529 159.164.29.128 - - [22/Mar/1996:09:51:48 -0500] "GET /coll3.htm HTTP/1.0" 200 8665 159.164.29.128 - - [22/Mar/1996:09:51:51 -0500] "GET /grads.gif HTTP/1.0" 200 3705 159.164.29.128 - - [22/Mar/1996:09:53:02 -0500] "GET /gallry.htm HTTP/1.0" 200 279
The first group of numbers is the Internet address of the computer accessing the server. This is followed by the date and time, some other data, the GET command, and the page requested (e.g., /new.gif or /coll3.htm) and finally some other information. If the GET command shows just a slash character, /, it indicates a request for the home page of the site. Write a program that processes a log file in the format shown above to produce a breakdown of hits in output similar to: home page new.gif seal.gif coll3.htm grads.gif gallry.htm 3 3 3 1 1 1
Exercise 16
Modify the Case Study to include a backup command that makes a copy of the data file to a new file using a name entered by the user.
9 34
Advanced Exercise 17
Write a data-driven Survey Administrator program that conducts a survey and stores the data in a file. The program should give the user the option to tabulate data, as well as add data. The program output with the survey questions to ask should look similar to: Enter data, Display stats, or Quit: E Do you know programming languages other than C++? Y What computer do you own (Pc, Mac, Other, None)? N Have you ever used a word processor (Y/N)? N Enter data, Display stats, or Quit: E Do you know programming languages other than C++? N What computer do you own (Pc, Mac, Other, None)? M Have you ever used a word processor (Y/N)? Y Enter data, Display stats, or Quit: D Do you know programming languages other than C++? Yes 17 No 23 What computer do you own (Pc, Mac, Other, None)? P 13 M 5 O 3 N 10 Have you ever used a word processor (Y/N)? N 15 Y 25 In the sample run above, the statistics displayed are for more than the two entries because previous respondents to the survey are stored in a file. The program should be data-driven. This means that the behavior of the program is substantially modified simply by changing the contents of one or more data files. In this case, the data driving the program is the survey questions contained in a text file: Do you know programming languages other than C++? What computer do you own (Pc, Mac, Other, None)? Have you ever used a word processor (Y/N)? The program is to read this text file, and then provide the menu options. The results should be stored so that users can enter more data at any time.
9 35
9 36
10
Objectives
After completing this chapter you will be able to: 1. Create classes and include them as part of a library. 2. Build utility classes. 3. Use compiler directives. 4. Understand the concepts of object-oriented programming and design.
10
he central concept of C++ programming is the class. In this chapter you will learn how to create classes.
Building Classes
10 1
specification public
The specification of a class defines how an object may be accessed by a programmer, and is called the public section of a class. The AccountClass public member functions are:
// Constructor AccountClass(String AcctName, String AcctOpenDate); /*Opens AcctName account on AcctOpenDate. Post: AcctName balance is zero, and transaction recorded */ void Deposit(double double Amt, String Date); /*Adds deposit to Acct and records transaction Post: Amt added to account, and transaction recorded */ double Amt, String Date); bool Withdrawal(double /*Subtracts withdrawal from account and records transaction Post: if Amt<=Balance, Amt deleted from account, transaction recorded, and true returned. Otherwise, false returned, attempt recorded, and balance unchanged. */ double GetBalance() const const; /*Determines current balance Post: Current balance returned */ void WriteTransactions(ostream & OutFile) const const; /*Writes transactions to OutFile Post: All information about the account written to OutFile, including a list of all transactions. */
10
The public member functions of a class specify the only way that objects of the class can be accessed. In other words, the data associated with an object can be changed only through public member functions. In this case, these member functions guarantee that all transactions are recorded because both Deposit() and Withdrawal() record the transaction. The constructor requires the account name and opening date as arguments, and also records the opening transaction. Part of the power of classes is the ability to restrict access to data so that the integrity and consistency of the data can be maintained. The AccountClass member functions do not have preconditions because the only prerequisite for their proper operation is that an AccountClass object has been instantiated, which is guaranteed by the constructor.
const
The functions GetBalance() and WriteTransactions() do not change their calling object in any way. To strictly reinforce this, the keyword const appears in the member function header. A const member function cannot change any object data. The WriteTransactions() function has an ostream (output stream) object as its parameter. This allows the function to be passed the console output stream (cout) for transactions to be written to the screen, or a file output stream (ofstream object) for transactions to be written to a file.
design private
In designing the class, there are also private functions and data members that are not accessible to code outside of the class, but are needed by the public part of the class.
10 2
10
class declaration
The variables associated with a class are called data members, and are usually private. The AccountClass class needs data members that store the account name (String Name), opening date (String Date), and current balance (double Balance). Arrays are the best data structure to store the date (vector<String> TransDates), type (vector<String> TransKinds), and amount (vector<double> TransAmts) of transactions. The class declaration includes the public member function and private data member declarations, and has the form:
class classname { public public: // public members listed here private private: // private members listed here };
Note that the declaration ends with a semicolon. Coding the member functions and testing the class still remain.
Review 1
Write a program with main() instantiating an AccountClass object and exercising each of the member functions. Write down the expected output of the program.
Building Classes
10 3
Review 2
A struct is a simpler form of a class. Using the struct syntax described in Chapter Eight, write a constructor for AccountClass according to its specification.
10
constructor
uct conA class constructor member function has the same form as a str struct structor described in Chapter Eight. Constructors cannot have a return n statement. A constructor is used eturn type, and therefore never include a retur uct constructor, it is good prostruct to initialize data members. As with a str gramming style to perform initializations in the initializer list. For example, the AccountClass class constructor is defined as: AccountClass::AccountClass(String AcctName, String AcctOpenDate) : Name(AcctName), OpenDate(AcctOpenDate), Balance(0), TransDates(0), TransKinds(0), TransAmts(0) /*Opens AcctName account on AcctOpenDate. Post: AcctName balance is zero, and transaction recorded */ { }
10 4
10
class AccountClass { public public: // Constructor AccountClass(String AcctName, String AcctOpenDate); /* Opens AcctName account on AcctOpenDate. Post: AcctName balance is zero, and transaction recorded */ void Deposit(double double Amt, String Date); /* Adds deposit to Acct and records transaction Post: Amt added to account, and transaction recorded */ double Amt, String Date); bool Withdrawal(double /* Subtracts withdrawal from account and records transaction Post: if Amt<=Balance, Amt deleted from account, transaction recorded, and true returned. Otherwise, false returned, attempt recorded, and balance unchanged. */ double GetBalance() const const; /* Determines current balance Post: Current balance returned */ void WriteTransactions(ostream & OutFile) const const; /* Writes transactions to OutFile Post: All information about the account written to OutFile, including a list of all transactions. */ private private: String Name; String OpenDate; double Balance; vector<String> TransDates, TransKinds; double vector<double double> TransAmts; }; #include "account.cpp"
Building Classes
10 5
To inform the compiler that account.h requires the code in account.cpp it ends with the statement:
#include "account.cpp"
10
The .cpp file must be included at the end so that the implementations are compiled after the declaration of the class. Double-quotation marks are used rather than angle brackets to indicate that the #include file is in the current directory rather than in the standard include directory. account.cpp
/*AccountClass class implementation */ #include <iostream.h> #include <lvp\vector.h> #include <lvp\string.h> //-------------------------------------------------------------------------------AccountClass::AccountClass(String AcctName, String AcctOpenDate) : Name(AcctName), OpenDate(AcctOpenDate), Balance(0), TransDates(0), TransKinds(0), TransAmts(0) /*Opens AcctName account on AcctOpenDate. Post: AcctName balance is zero, and transaction recorded */ { } //-------------------------------------------------------------------------------void AccountClass::Deposit(double double Amt, String Date) /*Adds deposit to Acct and records transaction Post: Amt added to account, and transaction recorded */ { Balance += Amt; TransDates.resize(TransDates.length() + 1); TransDates[TransDates.length()1] = Date; TransKinds.resize(TransKinds.length() + 1); TransKinds[TransKinds.length()1] = "Deposit"; TransAmts.resize(TransAmts.length() + 1); TransAmts[TransAmts.length()1] = Amt; } //-------------------------------------------------------------------------------double Amt, String Date) bool AccountClass::Withdrawal(double /*Subtracts withdrawal from account and records transaction Post: if Amt<=Balance, Amt deleted from account, transaction recorded, and true returned. Otherwise, false returned, attempt recorded, and balance unchanged. */ { TransDates.resize(TransDates.length() + 1); TransDates[TransDates.length()1] = Date; TransKinds.resize(TransKinds.length() + 1); TransAmts.resize(TransAmts.length() + 1); TransAmts[TransAmts.length()1] = Amt; if (Amt <= Balance) { Balance = Amt; TransKinds[TransKinds.length()1] = "Withdrawal"; return return(true); } else { TransKinds[TransKinds.length()1] = "Withdrawal/Failed"; return return(false); } }
10 6
10
//-------------------------------------------------------------------------------double AccountClass::GetBalance() const /*Determines current balance Post: Current balance returned */ { return (Balance); } //-------------------------------------------------------------------------------void AccountClass::WriteTransactions(ostream & OutFile) const /*Writes transactions to OutFile Post: All information about the account written to OutFile, including a list of all transactions. */ { OutFile.setf(ios::fixed); OutFile.precision(2); OutFile << Name << endl; OutFile << "Acct opened on " << OpenDate << " Balance: " << Balance << endl; OutFile << "Transactions" << endl; for (int int i=0; i<TransDates.length(); i++) { OutFile.width(12); OutFile << TransDates[i]; OutFile.width(22); OutFile << TransKinds[i]; OutFile.width(12); OutFile << TransAmts[i] << endl; } }
client program
The account library can now be included in a program to use the AccountClass class. A program that uses a class is often called the client program. The following client program demonstrates AccountClass:
/*AccountClass class demonstration program */ #include "account.h" #include <iostream.h> int main() { AccountClass Storer("Ms. Tomacina Storer", "1/2/98"); Storer.Deposit(100,"1/2/98"); Storer.Withdrawal(10,"1/7/98"); Storer.Withdrawal(15,"1/9/98"); Storer.Withdrawal(95,"1/19/98"); Storer.WriteTransactions(cout); return return(0); }
When run, the program output is: Ms. Tomacina Storer Acct opened on 1/2/98 Balance: 75.00 Transactions 1/2/98 Deposit 1/7/98 Withdrawal 1/9/98 Withdrawal 1/19/98 Withdrawal/Failed
It is usually necessary to compile only the client program because most compilers automatically compile and link any libraries used by the client program.
Building Classes
10 7
A program that uses a class cannot access the private members of the class. For example, if the main() function above contained the statement
cout << Storer.Balance << endl;
10
a compiler error would be generated indicating that Balance is not accessible. Designating Balance as private in the AccountClass class guarantees that its value cannot be modified without the change being recorded in the transaction list.
Review 3
Write a program that tests a function TransFunds(). Use the following header for TransFunds():
bool TransFunds(AccountClass &Source, AccountClass &Dest, double Amount) /*Transfers funds from Source account to Dest account. Post: If Source >=Amount, true returned, Amount subtracted from Source account, and Amount added to Dest account. If Source<Amount, false returned, Source and Dest unchanged. */
Review 4
Write a function GiveInterest() that adds interest to an AccountClass object using the Deposit() member function. The account and interest rate should be passed as arguments.
Review 5
The Withdrawal() function returns a bool value indicating whether the withdrawal was successful or not. Modify the AccountClass Class Demonstration program to examine this returned value. Have the program display an appropriate message depending on the return value.
When a default constructor is used to instantiate an object, the class must include member functions to initialize the object. The AccountClass class is modified to include a default constructor by first adding the default constructor prototype to the class declaration in account.h:
class AccountClass { public public: AccountClass(); /* Default constructor */ AccountClass(String AcctName, String AcctOpenDate); /* Opens AcctName account on AcctOpenDate. Post: AcctName balance is zero, and transaction recorded */ Remainder of AccountClass class declaration
10 8
10
Next, data members and member functions for initializing an object must be added to the class. Good programming style dictates that access to data be restricted so that the integrity and consistency of the data can be maintained. Therefore, when modifying AccountClass: No transactions may be made on an account until a name and date have been specified. The name and date may be specified only once on a given account. The AccountClass class declaration in account.h is modified to contain three more additional members. Two public member functions:
void SpecifyAccount(String AcctName, String AcctOpenDate); /*Assigns AcctName and AcctOpenDate to account if account not initialized Post: AcctName assigned to Name and AcctOpenDate assigned to OpenDate if account was not already initialized. IsOpen is true. */ String GetName() const const; /*Determines account name Post: Name returned */
The new data member, IsOpen, keeps track of the state of the account, and is initialized to false in the default constructor and true in the constructor with parameters. GetName() is useful when there is an array of accounts. Other AccountClass member functions will need to be modified. The Deposit() and Withdrawal() functions should check IsOpen before proceeding, and return false if the operation failed because the account was not open. This will require changing the Deposit() function to return a bool value rather than void. Since the WriteTransactions() and GetBalance() functions do not modify the account in any way, they remain unchanged. Finally, the new member function definitions are added to account.cpp. The default constructor, SpecifyAccount(), and GetName() member function definitions are:
AccountClass::AccountClass() : Balance(0), TransDates(0), TransKinds(0), TransAmts(0), IsOpen(false) /* default constructor */ { } //-------------------------------------------------------------------------------void AccountClass::SpecifyAccount(String AcctName, String AcctOpenDate) /*Assigns AcctName and AcctOpenDate to account if account not initialized Post: AcctName assigned to Name and AcctOpenDate assigned to OpenDate if account was not already initialized. IsOpen is true. */ { if (!IsOpen) { Name = AcctName; OpenDate = AcctOpenDate; IsOpen = true; } }
Building Classes
10 9
//-------------------------------------------------------------------------------String AccountClass::GetName() const /*Determines account name Post: Name returned */ { return return(Name); }
10
Also in account.cpp, the Deposit() and Withdrawal() member functions are modified to check the status of IsOpen. For demonstration purposes, the modified AccountClass class is saved in account2.h and account2.cpp. The program below demonstrates the modified AccountClass class:
/*AccountClass class with default constructor program */ #include "account2.h" #include <iostream.h> #include <lvp\vector.h> int main() { vector<AccountClass> Bank(100); int NumAccounts = 0; int i; const int NumToTest = 3; String Name, Date; double InitialDeposit; // Enter account data for (i=0; i<NumToTest; i++) { cout << "Enter name #" << (i+1) << ": " ; getline(cin, Name); cout << "Enter date #" << (i+1) << ": " ; getline(cin, Date); cout << "Enter initial deposit for #" << (i+1) << ": " ; cin >> InitialDeposit; cin.ignore(80,'\n'); Bank[i].SpecifyAccount(Name, Date); Bank[i].Deposit(InitialDeposit, Date); NumAccounts++; } // Display a list of accounts for (i=0; i<NumAccounts; i++) { cout.width(25); cout.setf(ios::left); cout << Bank[i].GetName() << Bank[i].GetBalance() << endl; } return return(0); }
When run, the program displays: Enter Enter Enter Enter Enter Enter 10 10 name #1: Samantha Jones date #1: 3/10/97 initial deposit for #1: 100 name #2: Daniel Adams date #2: 3/21/97 initial deposit for #2: 345
10
Enter name #3: Matthew Curry Enter date #3: 2/16/97 Enter initial deposit for #3: 260 Samantha Jones 100 Daniel Adams 345 Matthew Curry 260
Review 6
Will the AccountClass class demonstration program in Section 10.4 work as expected with the modified AccountClass class (account2.h)? Explain your reasoning, and then test it.
Review 7
Modify the demonstration program in Section 10.5 to use a function AddAccount() that has the following header:
void AddAccount(vector<AccountClass> &Bank, int &NumAccounts, String NameOfAcct, String DateOfAcct) /*Adds NameOfAcct account to Bank Pre: NumAccounts < Bank.length() Post: NameOfAcct account added to Bank array and NumAccounts incremented. */
Review 8
Use function GiveInterest() from Review 4 to write a function AddInterest() that adds interest to all accounts numbered 0 to NumAccount1 in the bank array used in Section 10.5. The function should take the interest rate, the Bank array, and NumAccounts as arguments.
Building Classes
10 11
bool Read(istream & InFile); /*Reads a date from InFile. Input is assumed to be in mm/dd/yy form. If read fails, returns false. Post: Date read from InFile. true returned for successful read, false returned otherwise.*/ const DateClass Date2) const bool IsEqualTo(const const; /*Determines if date is equal to Date2 Post: true returned if date=date2, false returned otherwise */ const DateClass Date2) const bool IsEarlierThan(const const; /*Determines if date is less than Date2 Post: true returned if date<date2, false returned otherwise */ const DateClass Date2) const bool IsLaterThan(const const; /*Determines if date is greater than Date2 Post: true returned if date>date2, false returned otherwise */
10
programming style
Good programming style dictates that a default constructor be included. Including the default constructor requires that a SetDate function be included. Write() is designated as const since it does not change the value of its object. The Read() function returns a bool to indicate whether the read was successful. The last three functions are for comparing dates. The data members for DateClass need to store int values for the month, day, and year. Therefore, the private section of the class declaration is:
private private: int Month; int Day; int Year;
design
coding
Most of the member function definitions are straightforward, and are shown later in the chapter. The Read() function has to parse (cut up and analyze) the input to determine the parts of the date. The Read() algorithm uses getline() to read an entire line of input into a string. The find() string function can then be used to find the / characters, and the atoi() function from the stdlib library used to convert the numeric portions into integer values:
bool DateClass::Read(istream & InFile) /*Reads a date from InFile. Input is assumed to be in mm/dd/yy form. true returned if date not 0/0/0. Post: String read from InFile and parsed into Month, Day, and Year. true returned if date not 0/0/0. false returned otherwise. */ { String S, MonthStr, DayStr, YearStr; getline(InFile,S); MonthStr = S.substr(0,S.find('/')); S = S.substr(S.find('/')+1,S.length()S.find('/')1); DayStr = S.substr(0, S.find('/')); YearStr = S.substr(S.find('/')+1, S.length()S.find('/')1); Month = atoi(MonthStr.c_str()); Day = atoi(DayStr.c_str()); Year = atoi(YearStr.c_str()); return ((Month!=0) && (Day!=0) && (Year!=0)); }
10 12
10
Read() needs to be tested carefully with various kinds of input. If the input is not in the correct format, atoi() will try to convert at least one string that is not an integer quantity and will therefore return zero. This is used to determine the value to be returned from the function.
Review 9
Write a program that tests the DateClass class member functions. main() should call each function at least once, and display output indicating whether each function has worked correctly.
Review 10
Write the code for the DateClass class comparison member functions. (Hint: Write IsLaterThan() using only IsEqualTo() and IsEarlierThan() and boolean operators for and, or, not.)
the == operator could be overloaded so that the following statement could be used:
if (Date1 == Date2) cout << "Equal! " << endl;
An operator member function has the name operator followed by the operator to overload. For example, the DateClass member function IsEqual() could be replaced with:
operator ==(const bool DateClass::operator const DateClass Date2) const { return ((Day == Date2.Day) && (Month == Date2.Month) && (Year == Date2.Year)); }
Whenever the compiler encounters an operator, the types in the expression are used to determine which operator is used. In this case, the overloaded == operator in DateClass is automatically called when two DateClass objects are compared using ==.
programming style
It is good programming style to overload all similar operators for a utility class, or not overload them at all. For example, if the < operator is overloaded to mean IsEarlierThan() for DateClass, then the <= operator should also be overloaded to mean is the same or earlier than. When one relational operator is overloaded, then all relational operators should be overloaded.
Building Classes
10 13
To use an overloaded operator from another member function, the function name must be used. For example, the following DateClass member function overloads the != operator:
operator !=(const bool DateClass::operator const DateClass Date2) const { return !(operator operator operator==(Date2)); }
10
The not symbol (!) must appear outside the parentheses. It is important to understand that overloaded operators implicitly use the left object in an expression as the object whose member function is to be used. For example, the code:
if (OneDay == AnotherDay)
Overloaded stream operator member functions have the same form as other overloaded operator member functions. However, for DateClass, the simplest way to overload the << operator is with a nonmember function that uses the member function Write():
ostream & operator <<(ostream &OutFile, const DateClass &D) /*Writes D to the output stream Post: D written to OutFile */ { D.Write(OutFile); return (OutFile); }
The first argument is the stream (on the left of the << expression), and the second is the DateClass object (on the right of the expression). The function returns a stream reference, which is good programming style with stream operations. The overloaded << function can be added to the end of the date library implementation file (date.cpp). Since it is not a member function of DateClass, the << function does not need to be added to the class interface in the header file (date.h). Library functions that are not member functions of a class are called free functions.
free functions
10 14
10
Since the << operator is overloaded for DateClass, the >> operator should be overloaded as well. For the overloaded >> function, the Read() member function will be used:
istream & operator >>(istream &InFile, DateClass &D) /*Reads from InFile to D Post: D is read from Infile */ { D.Read(InFile); return (InFile); }
When run, the program displays: Enter todays date: 3/14/98 Hooray! 3/14/98 is my un-birthday!
Review 11
Write a program that asks the user for the birthdays of two people, and then displays which person is older. The program output should be similar to: Enter first persons birthdate: 1/3/76 Enter second persons birthdate: 5/14/76 The first person is older.
Review 12
If a user enters two dates, one as 1/5/98 and the other as 01/05/98, will the two dates be considered equal by the DateClass equality comparison? Explain your answer, and indicate why you think this is or is not a good behavior for the class.
Building Classes
10 15
10
#ifndef
#endif #define
and tests to see if identifier has been defined. If it has not, then compilation proceeds to the next line. If it has been defined, code is skipped until the #endif directive is encountered. The #define directive has the form
#define identifier statements associated with identifier
programming style
It is good programming style to use compiler directives in a library. For example, the date.h file should use the following directives:
#ifndef _DATECLASS_ #define _DATECLASS_ DateClass class declaration #include "date.cpp" #endif
When the compiler first encounters date.h, the identifier _DATECLASS_ has not yet been defined. Therefore, _DATECLASS_ is defined, the class declaration compiled, and date.cpp compiled. The second time date.h is encountered, _DATECLASS_ has already been defined. Therefore, the compiler skips all the code to the #endif.
programming style
It is considered good programming style to choose a #define identifier that begins and ends with underscore characters (_) and is in all uppercase. This helps avoid conflict with identifiers in program code.
10 16
10
class DateClass { public public: DateClass(); int MonthArg, int DayArg, int YearArg); DateClass(int bool Read(istream & InFile); int MonthArg, int DayArg, int YearArg); void SetDate(int void Write(ostream & OutFile) const const; const DateClass Date2) const bool operator ==(const const; const DateClass Date2) const const; bool operator !=(const const DateClass Date2) const bool operator <(const const; const DateClass Date2) const bool operator <=(const const; const DateClass Date2) const bool operator >(const const; const DateClass Date2) const const; bool operator >=(const private private: int Month; int Day; int Year; }; #include "date.cpp" #endif
date.cpp
/*Implementation of a DateClass class that stores month, day, and year. Two free functions are included: operator << and operator >> */ DateClass::DateClass() : Month(0), Day(0), Year(0) { } //-------------------------------------------------------------------------------int MonthArg, int DayArg, int YearArg) DateClass::DateClass(int : Month(MonthArg), Day(DayArg), Year(YearArg) { }
Building Classes
10 17
//-------------------------------------------------------------------------------bool DateClass::Read(istream & InFile) /*Reads a date from InFile. Input is assumed to be in mm/dd/yy form. true returned if date not 0/0/0. Post: String read from InFile and parsed into Month, Day, and Year. true returned if date not 0/0/0. false returned otherwise. */ { String S, MonthStr, DayStr, YearStr; getline(InFile,S); MonthStr = S.substr(0,S.find('/')); S = S.substr(S.find('/')+1,S.length()S.find('/')1); DayStr = S.substr(0,S.find('/')); YearStr = S.substr(S.find('/')+1,S.length()S.find('/')1); Month = atoi(MonthStr.c_str()); Day = atoi(DayStr.c_str()); Year = atoi(YearStr.c_str()); return ((Month!=0) && (Day!=0) && (Year!=0)); } //-------------------------------------------------------------------------------void DateClass::SetDate(int int MonthArg, int DayArg, int YearArg) { Month = MonthArg; Day = DayArg; Year = YearArg; } //-------------------------------------------------------------------------------void DateClass::Write(ostream & OutFile) const /*Writes D to the output stream Post: D written to OutFile */ { OutFile.width(2); OutFile << Month << '/'; OutFile.width(2); OutFile << Day << '/'; OutFile.width(2); OutFile << Year; } //-------------------------------------------------------------------------------operator <(const const DateClass Date2) const bool DateClass::operator { if (Year < Date2.Year) return (true); else if (Year > Date2.Year) return (false); else if (Month < Date2.Month) return (true); else if (Month > Date2.Month) return (false); else return (Day < Date2.Day); } //-------------------------------------------------------------------------------operator > (const const DateClass Date2) const bool DateClass::operator { return (!(operator operator operator operator==(Date2)) && !(operator operator<(Date2))); } //-------------------------------------------------------------------------------operator == (const const DateClass Date2) const bool DateClass::operator { return ((Day == Date2.Day) && (Month == Date2.Month) && (Year == Date2.Year)); }
10
10 18
10
//-------------------------------------------------------------------------------operator != (const const DateClass Date2) const bool DateClass::operator { return !(operator operator operator==(Date2)); } //-------------------------------------------------------------------------------operator >= (const const DateClass Date2) const bool DateClass::operator { return ((operator operator operator operator==(Date2)) || (operator operator>(Date2))); } //-------------------------------------------------------------------------------operator <= (const const DateClass Date2) const bool DateClass::operator { return ((operator operator operator operator==(Date2)) || (operator operator<(Date2))); } //-------------------------------------------------------------------------------ostream& operator << (ostream & OutFile, const DateClass &D) { D.Write(OutFile); return (OutFile); } //-------------------------------------------------------------------------------istream & operator >>(istream &InFile, DateClass &D) /*Reads from InFile to D Post: D is read from Infile */ { D.Read(InFile); return (InFile); }
Review 13
Add to the date library an operator function that overloads the subtraction operator () so that when two dates are subtracted, it gives the approximate number of days between the two dates. Assume each month has 30 days and each year has 365 days. Use the header:
long DateClass::operator operator (const const DateClass &Date2)
Review 14
Write a function MaxDate() that returns the latest date in an array of dates passed as an argument. Use the header:
DateClass MaxDate(const const vector<DateClass> &DateList) /*Returns the value of the latest date in DateList Pre: DateList contains 1 or more dates Post: The value of the latest date in DateList is returned */
Building Classes
10 19
10
The assignment operator, which is called whenever one object is copied to another in an assignment statement. When an object is somehow connected to data or a device outside the object itself, these special member functions need to be explicitly declared and defined in a class. For example, a TopListClass object uses files that need to be opened, read from, and closed. Therefore, the TopListClass class must include constructor, destructor, and assignment operator member functions that handle files. PegClass, which draws to the screen, also needs to explicitly include these special member functions. Default constructor member functions have been covered in detail in Section 10.5.
destructor
The destructor member function cannot have parameters, and must be given the name of the class preceded by the tilde symbol, ~. For example, the TopListClass class is used to create and maintain a file of scores. The TopListClass destructor declaration appears in toplist.h like:
class TopListClass { public public: TopListClass(String Filename, int MaxItemsArg=10); ~TopListClass(); // Destructor // Other member functions private private: vector<String> NameList; long vector<long long> ScoreList; String FN; // Filename to store data int MaxItems; };
10 20
10
The TopListClass constructor loads data from a specified file on disk into the arrays shown in the private section of the declaration. Changes to a TopListClass object are maintained only in memory in arrays NameList and ScoreList. When the object goes out of scope, the destructor is called. The TopListClass destructor writes the data stored in NameList and ScoreList to the file associated with the TopListClass object. The TopListClass destructor definition appears in toplist.cpp like:
TopListClass::~TopListClass() /*Pre: TopListClass object exists Post: Object destroyed, and data stored */ { fstream File(FN.c_str(), ios::out); if (File.fail()) { cout << "Error opening file to save!" << FN << endl; } else { for (int int i=0; i<MyMaxItems; i++) { File << NameList[i] << endl; File << ScoreList[i] << endl; } File.close(); } }
The copy constructor and assignment operator functions are discussed in the next section.
What should the effect be? Should T2 now store T1s data? Should T2 store data in toplist1.dat or toplist2.dat? There is no clear answer. Similar questions arise when a TopListClass object is passed by value. The compiler automatically generates copy constructor and assignment operator functions unless they are declared in the class. In the case of TopListClass, copying and assignment is to be prevented. Therefore, the copy constructor and assignment operator functions are declared in the private section of the class where they will not be accessible to a client program:
class TopListClass { public public: TopListClass(String Filename, int MaxItemsArg=10); ~TopListClass(); // Destructor // Other member functions
Building Classes
10 21
private private: vector<String> NameList; long vector<long long> ScoreList; String FN; // File name to store data int MaxItems; // Private functions to prevent copying of objects const TopListClass &T); // Copy constructor TopListClass(const operator const TopListClass &T); // Assignment operator operator=(const };
10
A copy constructor takes the class as a const reference parameter. The definitions of the copy constructor and assignment operator functions do not need to exist at all. Therefore, the TopListClass implementation file does not contain the private member function definitions. If an attempt is made to assign or pass an object as a value parameter, the compiler generates an error message. For example, attempting to copy an object, as in the statements
TopListClass TopList("Toplist.dat"); TopListClass Foo = TopList;
generates a compiler error indicating that the copy constructor is not accessible. Similarly, attempting assignment, as in the statements
TopListClass TopList("Toplist.dat"); TopListClass Foo; Foo = TopList;
generates a compiler error indicating that the assignment member function is not accessible.
10 22
10
Reduction of complexity: As software becomes more and more complex, it becomes more and more difficult to manage. The object-oriented approach helps divide the total programming task so that programmers can work on welldefined, smaller tasks. This is especially important since most software is now written by teams of programmers.
Review 15
Write a class called PermanentStringClass that has the following member functions: A constructor that reads a string from the first line of the file onestr.dat. A destructor that writes a string to the file onestr.dat. A function Display() that displays the string on the screen. A function Replace() that replaces the string with one given as an argument. Write a program to test PermanentStringClass that includes the code:
PermanentStringClass Test; String NewString; Test.Display(); cout << "Enter a new string: "; getline(cout,NewString); Test.Replace(NewString); Test.Display();
Case Study
In this Case Study, AccountClass will be improved. One improvement will be incorporating DateClass in AccountClass.
specification
Improve AccountClass by incorporating DateClass and making the following enhancements: 1. Transactions are to be displayed in order by date. 2. Add member functions Store() and Retrieve() to allow an entire account to be stored in a file stream and retrieved. 3. Add the following member functions so that a client program can obtain all information about the account, including the individual transactions:
DateClass GetOpenDate() const const; String GetName() const const; int GetTransCount() const const; //returns the number of transactions int TransNum) const DateClass GetTransDate(int const; int TransNum) const String GetTransKind(int const; double GetTransAmt(int int TransNum) const const;
Building Classes
10 23
designlevel 1
To complete Task 1 in the specification, transactions (deposits and withdrawals) will be stored in the transaction arrays in order by date. To store transaction data in the appropriate position of the arrays, a private member function AddTransaction() will be added to AccountClass, and called by both Deposit() and Withdrawal(). To complete Task 2 in the specification, a file with the following format will be implemented: Line 1: Account name Line 2: Opening date Line 3: Balance Line 4: Number of transactions Line 5: First transaction date Line 6: First transaction kind Line 7: First transaction amount Lines 5 through 7 repeat for remaining transactions. Entire structure repeats for remaining accounts. By storing the number of transactions, a for loop can be used to retrieve an accounts transactions without inadvertently reading into the next account in the file. To complete Task 3 in the specification, new member functions will be added to AccountClass.
10
codinglevel 1
Modifications to the AccountClass interface include new member function declarations, and using DateClass to implement dates. Compiler directives will also be added. The new interface file is shown below: account3.h
/*Improved bank account class which maintains and can display a list of all transaction on the account */ #ifndef _ACCOUNTCLASS_ #define _ACCOUNTCLASS_ #include #include #include #include #include #include <fstream.h> <iostream.h> <lvp\bool.h> <lvp\string.h> <lvp\vector.h> "date.h"
class AccountClass { public public: AccountClass(); /* Default constructor */ AccountClass(String AcctName, DateClass AcctOpenDate); /* Opens AcctName account on AcctOpenDate. Post: AcctName balance is zero, and transaction recorded */ void SpecifyAccount(String AcctName, DateClass AcctOpenDate); /* Assigns AcctName and AcctOpenDate to account if account not initialized Post: AcctName assigned to Name and AcctOpenDate assigned to OpenDate if account was not already initialized. IsOpen is true. */
10 24
10
double Amt, DateClass Date); bool Deposit(double /* Post: If account open, adds deposit to Acct, records transaction, and returns true; returns false otherwise. */ double Amt, DateClass Date); bool Withdrawal(double /* Post: if Amt<=Balance, Amt deleted from account, transaction recorded, and true returned. Otherwise, false returned, attempt recorded, and balance unchanged. */ //Access functions that return account information DateClass GetOpenDate() const const; /* Post: Account open date returned. */ String GetName() const const; /* Post: Name returned */
double GetBalance() const const; /* Post: Current balance returned */ //Access functions that return transaction information const; int GetTransCount() const /* Post: Number of transactions returned */ int TransNum) const DateClass GetTransDate(int const; /* Post: Date of transaction returned */ int TransNum) const String GetTransKind(int const; /* Post: Type of transaction returned */ double GetTransAmt(int int TransNum) const const; /* Post: Amount of transaction returned */ //Stream functions void WriteTransactions(ostream & OutFile) const const; /* Writes transactions to OutFile Post: All information about the account written to OutFile, including all transactions in order by date. */ void Store(ostream & OutFile) const const; /* Pre: InFile is open Post: Account written in standard format to OutFile */ void Retrieve(istream & InFile); /* Pre: InFile is open and positioned at a properly formatted account Post: Next account has been read from InFile into account */ private private: bool IsOpen; String Name; DateClass OpenDate; double Balance; vector<DateClass> TransDates; vector<String> TransKinds; double vector<double double> TransAmts; void AddTransaction(String Kind, DateClass Date, double Amt); /* Post: Transaction recorded at appropriate position by date. */ }; #include "account3.cpp" #endif
Building Classes
10 25
designlevel 2
In the next level of design, the new member functions are refined. The new member functions for accessing account information simply return the value of a data member. With the simplicity of these functions, it is fair to ask why the data members should not be made public so that they can be accessed directly. By using private data members: The writer of the class has full control over the way data members can be manipulated. By allowing manipulation only through calls to member functions, the integrity and consistency of objects is maintained. The writer of the class has complete freedom in designing the class code. The author may change the names or types of the date members, modify the way they are implemented, etc., without needing to change the interface. These are clear benefits of the OOP approach. The Store() function sends all the data in the three transaction arrays into the file stream for writing to a file. Similarly, the Retrieve() function reads all information into the three transaction arrays from a file. The AddTransaction() function is used to maintain the transactions in order by date. This means that when a new transaction is to be added, it must be inserted in the correct location in the array. An algorithm for doing this is to move all items with later dates than the one to be inserted up by one place in the array, and then to insert the new item in the open space. This can be illustrated as:
10
The AddTransaction() algorithm is implemented by moving all items which have later dates one position later in the array, making room for the new data in its correct spot. The AddTransaction() pseudocode is: increase by one the array size start with the last item in the array as the last item while (current item date > new date) move current item to the next position in the array go to previous item in the array put the new data in the current spot The transaction kind and amount arrays are handled the same way.
codinglevel 2
The next step is to write the code to implement the new member functions. The new access functions (GetName(), GetOpenDate(), etc.) can each be implemented in a single line. For example:
String AccountClass::GetName() const /*Post: Account name returned */ { return (Name); }
10 26
10
int AccountClass::GetTransCount() const /*Post: Date of transaction returned */ { return (TransDates.length()); } int TransNum) const DateClass AccountClass::GetTransDate(int /*Post: Date of transaction returned */ { return (TransDates[TransNum]); }
The Deposit() and Withdrawal() functions must be modified to use AddTransaction(). For example, Withdrawal() becomes:
double Amt, DateClass Date); bool AccountClass::Withdrawal(double /*Post: if Amt<=Balance, Amt deleted from account, transaction recorded, and true returned. Otherwise, false returned, attempt recorded, and balance unchanged. */ { if (Amt <= Balance) { Balance = Amt; AddTransaction("Withdrawal", Date, Amt); return return(true); } else { AddTransaction("Withdrawal/Failed", Date, Amt); return return(false); } }
Building Classes
10 27
The Store() and Retrieve() functions are written based on the file structure in the design. For example, Store() sends data to the file stream:
void AccountClass::Store(ostream & OutFile) const const; /*Pre: InFile is open Post: Account written in standard format to OutFile */ { OutFile << Name << endl; OutFile << OpenDate << endl; OutFile << Balance << endl; OutFile << TransDates.length() << endl; for (int int TransNum = 0; TransNum < TransDates.length(); TransNum++) { OutFile << TransDates[TransNum] << endl; OutFile << TransKinds[TransNum] << endl; OutFile << TransAmts[TransNum] << endl; } }
10
Similar to Store(), Retrieve() is coded using getline() to retrieve strings, the >> operator combined with ignore() to obtain numbers, and the DateClass overloaded >> operator to retrieve dates. Retrieve() should also include the statement:
IsOpen = true;
so that it may be used to initialize an account opened with the default constructor. The complete AccountClass implementation is shown below: account3.cpp
/*AccountClass class implementation */ #include <iostream.h> #include <lvp\vector.h> #include <lvp\string.h> //-------------------------------------------------------------------------------AccountClass::AccountClass() : Balance(0), TransDate(0), TransKinds(0), TransAmts(0), IsOpen(false) { } //-------------------------------------------------------------------------------AccountClass::AccountClass(String AcctName, DateClass AcctOpenDate) : Name(AcctName), OpenDate(AcctOpenDate), Balance(0), TransDates(0), TransKinds(0), TransAmts(0), IsOpen(true) /* Opens AcctName account on AcctOpenDate with 0 balance */ { } //-------------------------------------------------------------------------------void AccountClass::SpecifyAccount(String AcctName, DateClass AcctOpenDate) /*Assigns AcctName and AcctOpenDate to account if account not initialized Post: AcctName assigned to Name and AcctOpenDate assigned to OpenDate if account was not already initialized. IsOpen is true. */ { if (!IsOpen) { Name = AcctName; OpenDate = AcctOpenDate; IsOpen = true; } }
10 28
10
//-------------------------------------------------------------------------------double Amt, DateClass Date) bool AccountClass::Deposit(double /*Post: If account open, adds Amt to Acct, records transaction, and returns true; returns false otherwise. */ { if (IsOpen) { Balance += Amt; AddTransaction("Deposit", Date, Amt); return return(true); } else return return(false); } //-------------------------------------------------------------------------------double Amt, DateClass Date) bool AccountClass::Withdrawal(double /*Post: if Amt<=Balance, Amt deleted from account, transaction recorded, and true returned. Otherwise, false returned, attempt recorded, and balance unchanged. */ { if (Amt <= Balance) { Balance = Amt; AddTransaction("Withdrawal", Date, Amt); return return(true); } else { AddTransaction("Withdrawal/Failed", Date, Amt); return return(false); } } //-------------------ACCESS FUNCTIONS--------------------------------double AccountClass::GetBalance() const //Returns current balance { return (Balance); } String AccountClass::GetName() const { return (Name); } DateClass AccountClass::GetOpenDate() const { return (OpenDate); } int AccountClass::GetTransCount() const //Returns number of trans { return (TransDates.length()); } int TransNum) const DateClass AccountClass::GetTransDate(int { return (TransDates[TransNum]); } int TransNum) const String AccountClass::GetTransKind(int { return (TransKinds[TransNum]); } double AccountClass::GetTransAmt(int int TransNum) const { return (TransAmts[TransNum]); } //-------------------------------------------------------------------------------void AccountClass::WriteTransactions(ostream & OutFile) const const; /*Writes transactions to OutFile Post: All information about the account written to OutFile, including a list of all transactions. */ { OutFile.setf(ios::fixed); OutFile.precision(2); OutFile << Name << endl; OutFile << "Acct opened on " << OpenDate << " Balance: " << Balance << endl; OutFile << "Transactions" << endl; for (int int i=0; i<TransDates.length(); i++) { OutFile.width(12); OutFile << TransDates[i]; OutFile.width(22); OutFile << TransKinds[i]; OutFile.width(12); OutFile << TransAmts[i] << endl; } }
Building Classes
10 29
//-------------------------------------------------------------------------------void AccountClass::AddTransaction(String Kind, DateClass Date, double Amt) /*Records transaction in appropriate position of arrays by date Post: Transaction recorded in appropriate position by date */ { int NewSize = TransDates.length() + 1; TransDates.resize(NewSize); TransKinds.resize(NewSize); TransAmts.resize(NewSize); int NewSpot = NewSize 2; while ((NewSpot >= 0) && (TransDates[NewSpot] > Date)) { TransDates[NewSpot+1] = TransDates[NewSpot]; TransKinds[NewSpot+1] = TransKinds[NewSpot]; TransAmts[NewSpot+1] = TransAmts[NewSpot]; NewSpot--; } TransDates[NewSpot+1] = Date; TransKinds[NewSpot+1] = Kind; TransAmts[NewSpot+1] = Amt; } //-------------------------------------------------------------------------------void AccountClass::Store(ostream & OutFile) const /*Pre: InFile is open Post: Account written in standard format to OutFile */ { OutFile << Name << endl; OutFile << OpenDate << endl; OutFile << Balance << endl; OutFile << TransDates.length() << endl; for (int int TransNum = 0; TransNum < TransDates.length(); TransNum++) { OutFile << TransDates[TransNum] << endl; OutFile << TransKinds[TransNum] << endl; OutFile << TransAmts[TransNum] << endl; } } //-------------------------------------------------------------------------------void AccountClass::Retrieve(istream & InFile) /*Pre: InFile is open and positioned at a properly formatted account Post: Next account has been read from InFile into account */ { getline(InFile, Name); OpenDate.Read(InFile); InFile >> Balance; InFile.ignore(80,'\n'); int TransCount; InFile >> TransCount; InFile.ignore(80,'\n'); TransDates.resize(TransCount); TransKinds.resize(TransCount); TransAmts.resize(TransCount); for (int int TransNum = 0; TransNum < TransCount; TransNum++) { InFile >> TransDates[TransNum]; getline(InFile, TransKinds[TransNum]); InFile >> TransAmts[TransNum]; InFile.ignore(80,'\n'); } IsOpen = true; }
10
Testing such a large and complex class is a formidable task. Testing must include verifying that the store/retrieve sequence works properly for all sizes of accounts, and transactions are properly added at the end, beginning, and middle of the transaction list.
10 30
10
The AccountClass library is tested with a menu-driven program that reads a file of accounts into an array of accounts, allows the user to add accounts and transactions, and stores all accounts at the end of the program. When run, the client program displays output similar to: AddAccount/Deposit/Withdrawal/disPlay/Quit: John Nicola Acct opened on 2/ 3/97 Balance: 60123.45 Transactions 2/ 3/97 Deposit 10000.00 2/ 5/97 Deposit 20000.00 2/ 10/97 Deposit 123.45 2/ 15/97 Deposit 30000.00 Craig Mackay Acct opened on 2/ 5/97 Balance: 1109.00 Transactions 12/23/97 Deposit 100.00 2/ 4/98 Withdrawal/Fail 1000.00 2/ 5/98 Deposit 1009.00 AddAccount/Deposit/Withdrawal/disPlay/Quit: Enter name: Alex Rhett Enter date: 2/6/98 Enter initial deposit: 300 AddAccount/Deposit/Withdrawal/disPlay/Quit: Enter account number: 1 Enter amount: 200 Enter date: 1/3/98 AddAccount/Deposit/Withdrawal/disPlay/Quit: P
For the sake of brevity, the test program is written in a single main() function. However, it would be better programming style to divide the tasks of the program into functions. The file of accounts used by the program has the format: Line 1: Number of accounts in the file remaining lines: Accounts formatted as expected by the AccountClass Store() function. The client program is shown below:
/* Improved AccountClass demonstration program */ #include #include #include #include #include "account3.h" "date.h" <iostream.h> <lvp\vector.h> <conio.h> // for getche()
int main() { vector<AccountClass> Bank(100); fstream BankData; int NumAccounts = 0; int AcctNum;
Building Classes
10 31
// Retrieve accounts from file BankData.open("bankdata.dat", ios::in); BankData >> NumAccounts; BankData.ignore(80,'\n'); for (AcctNum=0; AcctNum < NumAccounts; AcctNum++) { Bank[AcctNum].Retrieve(BankData); } BankData.close(); //Test AccountClass char Choice; String Name; DateClass Date; double Amount; while (true) { cout << "AddAccount/Deposit/Withdrawal/disPlay/Quit: "; Choice = getche(); cout << endl; if (Choice == 'Q' || Choice == 'q') break break; switch (Choice) { case 'A': case 'a': //Add an account cout << "Enter name: "; getline(cin, Name); cout << "Enter date: "; Date.Read(cin); cout << "Enter initial deposit: "; cin >> Amount; cin.ignore(80,'\n'); Bank[NumAccounts].SpecifyAccount(Name, Date); Bank[NumAccounts].Deposit(Amount, Date); NumAccounts++; break break; case 'D': case 'd': //Deposit cout << "Enter account number: "; cin >> AcctNum; cout << "Enter amount: "; cin >> Amount; cin.ignore(80,'\n'); cout << "Enter date: "; Date.Read(cin); Bank[AcctNum].Deposit(Amount, Date); break break; case 'W': case 'w': //Withdrawal cout << "Enter account number: "; cin >> AcctNum; cout << "Enter amount: "; cin >> Amount; cin.ignore(80,'\n'); cout << "Enter date: "; Date.Read(cin); Bank[AcctNum].Withdrawal(Amount, Date); break break; case 'P': case 'p': //Display accounts for (AcctNum=0; AcctNum < NumAccounts; AcctNum++) { Bank[AcctNum].WriteTransactions(cout); } break break; } }
10
10 32
10
}
// Save accounts in file BankData.open("bankdata.dat", ios::out); BankData << NumAccounts << endl; for (AcctNum=0; AcctNum < NumAccounts; AcctNum++) { Bank[AcctNum].Store(BankData); } BankData.close(); return (0);
All three transactions performed in the switch statement require a date entered by the user. To get the date typed by the user, the DateClass member function Read() was passed cin as the InFile parameter.
Review 16
Can the Case Study client program add a transaction directly? For example, explain why or why not the following statement is legal:
Bank[1].AddTransaction("Special",Today, 1000);
Review 17
A weakness of the Case Study client program is that accounts must be accessed by number. Write a function FindAccount() that finds the account number for the name given as an argument:
int FindAccount(const const vector<AccountClass> &Bank, const int NumAccounts, const String &Name) /*Post: Account number of Name account returned, or 1 returned if Name account not found. */
Review 18
The access functions of the account3 library do not determine if an account is open before trying to return information about the account. This causes a runtime error in a program that tries to access an account that is not open. Modify the access functions (declarations and definitions) to first check for an open account.
Chapter Summary
The methodology for creating a class is specification, design, coding, and testing and debugging. The specification of a class defines how an object may be accessed by a program, and is called the public section of a class. The private part of a class is the functions and data members not accessible to code outside the class, and is part of the design of a class. A library is coded in two files and often contains classes. The header file, also called the interface file, contains the class declaration. The declaration of a class has the form:
class classname { public public: // public members listed here private private: // private members listed here
The implementation file contains class member function definitions. The compiler is informed that the implementation file requires the code in the header file with an #include directive at the end of the header file.
Building Classes
10 33
Member functions may be public or private. Public member functions are accessible to the client code. Private member functions are accessible only within the class. Member functions that do not change their calling object in any way include the keyword const in the header to reinforce this. Member functions that overload built-in operators are called operator member functions. Special member functions are the default constructor, copy constructor, assignment operator, and destructor. Each of these functions are automatically created by the compiler if a declaration does not exist in the class. The copy constructor and assignment operator member functions are not always desirable, and can be made inaccessible to a client program by including their declarations in the private section of a class. A library may also contain free functions that are not member functions of a class, but may be useful to class object operations. Compiler directives tell the compiler to take a special step in compiling a program. The #include directive tells the compiler to load in and compile additional files. The #ifndef, #endif, and #define directives are used to prevent a program from including a library more than once. The #ifndef directive tests to see if an identifier has been defined. If the identifier has been defined, the code after the #ifndef is skipped until an #endif is encountered. The #define directive defines an identifier. The object-oriented approach to programming offers reusable, reliable code that can reduce the complexity of a program.
10
Vocabulary
Application Specific Term applied to a class that is primarily useful only in the single application for which it was designed. Assignment Operator Member Function Member function that is automatically called when an object copied through assignment. Automatically created by the compiler if not declared in the class. Class Declaration Member function and data member declarations of a class. Client Program A program that uses a class. Compiler Directive Used to tell the compiler to take a special step in compiling a program. Copy Constructor Member function that is automatically called when an object is copied. Automatically created by the compiler if not declared in the class. Data Hiding The property of object-oriented programming in which classes can be used without regard to how they are implemented. Default Constructor Member function that is automatically called when an object is instantiated with no parameters. Automatically created by the compiler if not declared in the class. Destructor Member function that is automatically called when an object goes out of scope. Automatically created by the compiler if not declared in the class. 10 34
10
Encapsulation The property of object-oriented programming in which code is self-contained in a separate unit Free Function Library functions that are not member functions of a class. Header File The class declaration file that is saved with a .h extension. Implementation File The file containing class member function definitions and free functions. Interface File A header file. Library Files that contain classes and functions for use in client programs. Operator Member Function Member function that overloads a built-in operator or stream operator. Private The section of a class declaration that is not accessible to a client program. Public The section of a class declaration that is accessible to a client program. Reduction of Complexity An advantage of OOP/OOD in which the total programming task can be divided into well-defined, smaller tasks, which reduces the overall complexity. Reliability An advantage of OOP/OOD in which classes that are written for many applications have been fully tested, making them more reliable. Reusability An advantage of OOP/OOD in which a well-designed class can be reused, saving programming effort.
C++
:: Used to separate a class name and function name in a member function definition. ~ Used to indicate a destructor member function. #define Compiler directive that defines an identifier. Used in conjunction with #ifndef and #endif to prevent a program from including a library more
than once. Compiler directive that is used to signify the end of the #ifndef directive.
#endif #ifndef Compiler directive that tests to see if an identifier has been defined. If the identifier has been defined, the code after the #ifndef is skipped until an #endif directive is encountered. #include Compiler directive that tells the compiler to load in and compile additional files. oper ator Keyword used to indicate a member function is written to overoperator
Building Classes
10 35
Exercises
Exercise 1
Modify the Student Records program on page 8-24 to use a class, StudentClass that has member functions Read() and Write().
10
Exercise 2
a) Write a class called BookClass to replace the BookType structure used in the Case Study of Chapter Nine. Include member functions Read(), Write(), AddACopy(), and SubtractACopy() and any other functions needed. b) Modify the Chapter Nine Case Study to use the BookClass library.
Exercise 3
In Chapter Eight, a Tic-Tac-Toe program was written. Write this program by designing and implementing a TTTClass. A TTTClass object should display the board on the screen, and have member functions Move() that get a move and update the screen, and Winner() that returns a code indicating who has won, if anyone. To simplify the class code, an enumerated type should be specified in TTTClass.h:
enum PlayerCode {XCode, OCode, BlankCode};
Exercise 4
Chapter Five Exercise 18 gave the specification of a Horse Race simulation. Write this program by designing and implementing a HorseClass. A HorseClass object should display its horse and track on the screen, and update the display when the horse moves.
Exercise 5
a) Design and implement a FractionClass utility class. It should allow reading and writing numbers in fractional form, and arithmetic operations on fractions. Overload the <<, >>, +, , *, and / operators to work on fractions. b) Write a client program that uses FractionClass to simulate a fraction-based calculator. The program output should look similar to: Enter a fraction: Enter an operator Enter a fraction: Result: 7/12 Enter an operator Enter a fraction: Result: 7/3 Enter an operator 1/3 (= to quit): + 1/4 (= to quit): * 4/1 (= to quit): =
10 36
10
Exercise 6
a) Design and implement an ElapsedTimeClass utility. It should allow reading and writing of times in the form: 15:13:27 (fifteen hours, thirteen minutes, and 27 seconds). Member functions should include operator functions that overload <<, >>, +, and . b) Write a client program that fully tests the library.
Exercise 7
Format command Standard Standard4 Fullmonthtext Style mm/dd/yy mm/dd/yyyy m dd, yyyy Example 11/ 4/97 11/ 4/1997 November 4, 1997
A weakness of DateClass is that output is in the form mm/dd/yy. Add a member function SetFormat() that sets the format for the output of the date to one of several possible formats:
Exercise 8
The Millennium bug is the difficulty many computer programs will have in the year 2000 because they store dates as two-digit numbers. For example, an afflicted computer will consider the date 1/3/00 (i.e., January 3, 2000) to be before 1/3/99 in a comparison. The DateClass class suffers from exactly this problem. Modify the class so that it stores four digit years (e.g., 1999 or 2000). When a date is read, it should allow four or two digit years to be entered. If only two digits are entered, the class should assume it is in the 1900s.
Exercise 9
a) Write a DateClass operator member function that overloads the ++ operator to add one day to a date. Use the following header:
Be sure that the function correctly handles leap years. The rule is that leap years occur in any year divisible by four, unless the year ends in 00, in which case only if the year is also divisible by 400. b) Write a DateClass operator member function that overloads the -- operator to subtract one day from a date. c) Modify the date library to include the overloaded increment and decrement operators, and write a test program.
Building Classes
10 37
Exercise 10
a) Using the information in Exercise 9, modify the subtraction operator member function created in Review 13 to return the correct number of days between two dates (a long value). Use the header:
long DateClass::operator operator (const const DateClass &Date2)
10
b) Modify the date library to include the modified operator function, and write a test program.
Exercise 11
Use the DateClass library to implement a database of historical events. The client program should allow events to be stored using the date and a description (a string), and allow the events to be displayed in chronological order. The program output should be similar to: ... Add, Display, Quit: A Enter date: 1/28/97 Enter Description: Clinton inaugurated for second term Add, Display, Quit: D 11/ 5/96 Clinton wins election 1/28/97 Clinton inaugurated for second term
Exercise 12
a) Write a class called DumbbellClass that uses conio library functions to animate a dumbbell figure on the screen. The dumbbell is displayed with characters O=O. DumbbellClass should have three member functions: A constructor that draws the dumbbell at location 40, 10. The Move() member function that erases the dumbbell from its current position by overwriting it with blanks, and redraws it one position to the left or right, depending upon which way it is moving. Initially, the dumbbell moves right until the right side of the screen (position 80) is reached, and then it changes direction. A destructor that erases the dumbbell by overwriting with blanks. b) Write a program that moves the dumbbell 500 times. c) Modify the dumbbell class created in Review 15 so that the dumbbell can move in eight directions (up, down, left, right, and the four diagonal directions). When the dumbbell reaches the edge of the screen, it should pick a new direction at random and keep moving.
Exercise 13
Improve the Case Study client program so that it implements a BankClass class. The BankClass class should store the accounts and the NumAccounts value, and contain member functions to perform all operations needed by the program. The constructor should load the data from disk, and the destructor should save data back to disk. 10 38
11
Objectives
After completing this chapter you will be able to: 1. Understand event-driven programming. 2. Use a minimal GUI program to write event-driven programs. 3. Write programs that display message boxes using the GUI libraries. 4. Write programs that display graphics using the GUI libraries.
11
n this chapter you will learn how to write programs that use some of the basic graphical user interface features of Windows (the GUI). While a full treatment of Windows programming is beyond the scope of this text, you will gain the ability to create GUI-based programs in a style similar to that used by professional programmers.
11 1
GuiClass is a special class that is used by the gui_top library to instantiate an object. The programs in this chapter will be written by modifying the GuiClass class. With this approach, a minimal GUI program is:
/*Minimal GUI program */ #include <lvp\gui_top.h> class GuiClass { public public: GuiClass(); void GuiMouseClick(int int x, int y); // Action if mouse click void GuiPaint(); // Repaint the entire window String Title(); // Return the title for the Window private private: }; //-------------------------------------------------------------------------------GuiClass::GuiClass() { } //-------------------------------------------------------------------------------String GuiClass::Title() { return ("A minimal GUI program"); } //-------------------------------------------------------------------------------void GuiClass::GuiMouseClick(int int x, int y) { } //-------------------------------------------------------------------------------void GuiClass::GuiPaint() { } //-------------------------------------------------------------------------------#include <lvp\gui_bot.h>
11
In order to work correctly, GuiClass must be declared with a default constructor and three public member functions: GuiMouseClick(), GuiPaint(), and Title(). As it stands, this program displays nothing (because the GuiPaint() function is empty) and does not respond to mouse clicks (because the GuiMouseClick() function is empty), but it does compile and create a window with the title provided by the Title() function. Note that the empty functions may generate warning messages that can be safely ignored for now.
11 2
11
pixel
void Rectangle(int int x1, int y1, int x2, int y2); /*Draws a rectangle with upper-left corner at x1, y1 and lower-right corner at x2, y2 */ void FilledRectangle(int int x1, int y1, int x2, int y2); /*Draws a filled rectangle with upper-left corner at x1, y1 and lower-right corner at x2, y2 */ void SetPixel(int int x, int y); /* Plots the indicated pixel using the current pen color */
The parameters of the functions correspond to pixel units. A pixel is a single dot, or picture element on the screen. Position (0, 0) is in the upperleft of the window, with y-values increasing downward and x-values increasing toward the right. The program below uses Circle() to produce the Olympic symbol:
/*Olympic Symbol program */ #include <lvp\gui_top.h> class GuiClass { public public: GuiClass(); void GuiMouseClick(int int x, int y); // Action if mouse click void GuiPaint(); // Repaint the entire window String Title(); // Return the title for the Window private private: }; //-------------------------------------------------------------------------------GuiClass::GuiClass() { } //-------------------------------------------------------------------------------String GuiClass::Title() { return "The Olympic Symbol!"; } //-------------------------------------------------------------------------------void GuiClass::GuiMouseClick(int int x, int y) { } //-------------------------------------------------------------------------------void GuiClass::GuiPaint() { Circle(180,200,50); Circle(250,200,50); Circle(320,200,50); Circle(215,270,50); Circle(285,270,50); } //-------------------------------------------------------------------------------#include <lvp\gui_bot.h>
11 3
11
Review 1
Add a line of code to the Olympic symbol program that will put a large circle around the entire symbol. Modify the program to title the display window Olympics Logo.
Review 2
Write a GUI program that produces a window titled Wheels! with a display similar to:
SetColor() remains in effect until the next use of SetColor(). The color constants are a Windows-defined type, COLORREF, that can be used to store colors and allow them to be used as parameters, as in the following function:
11 4
11
filled objects line thickness
void ColoredCircle(COLORREF Color, int x, int y, int r) /*Post: Circle drawn of color Color at (x, y) with radius r */ { SetColor(Color); Circle(x, y, r); }
For filled objects, the outline of the object is specified with SetColor(), and the inside, or fill, is specified with SetFillColor(). This uses the same color constants as SetColor(). For example, the following statements draw a gray box with a black outline:
SetFillColor(GRAY); SetColor(BLACK); FilledRectangle(120, 120, 140, 140);
The line thickness of the pen used to draw figures and to outline filled figures is specified with SetThickness(), where the thickness is specified in pixels. For example, the following statements draw a box with lines that are two pixels thick:
SetThickness(2); Rectangle(100,100,200,200);
11 5
// Windows and door SetColor(BLACK); SetThickness(1); SetFillColor(GRAY); FilledRectangle(120,120,140,140); FilledRectangle(160,120,180,140); FilledRectangle(135,160,165,200); SetColor(WHITE); SetPixel(160,180); // Doorknob! // Sun SetFillColor(YELLOW); SetColor(YELLOW); FilledCircle(280,50,30); } //-------------------------------------------------------------------------------#include <lvp\gui_bot.h>
11
The program output displays a bright yellow sun, and looks similar to:
11.5 Floodfill
The FloodFill() function is used to color in a region that is irregularly shaped. For example, in the Sunny Day program, FloodFill() could be used to color the house red and the roof gray. To identify the region to be filled, FloodFill() requires a starting point within the region. It then floods the region with the current fill color. The FloodFill() prototype is:
void FloodFill(int int x, int y); /*Post: All pixels connected to (x, y) with the same color are changed to the fill color */
FloodFill() considers any pixel which differs in color from the first pixel to be the border of the region and does not color it or go beyond it. Therefore, the following statements color the house and roof:
SetFillColor(RED); // Paint house red FloodFill(150, 110); SetFillColor(GRAY); // Paint roof gray FloodFill(150, 90);
The x, y parameters passed to FloodFill() are not important so long as the points are in the region to be colored. 11 6
11
Review 3
Modify the Sunny Day program to display a small orange dog house next to the house.
Review 4
Modify Review 2 to display a yellow car using FilledRectangle().
Review 5
Modify Review 4 to display gray wheels on the car using FloodFill().
The system keeps track of the last graphics operation, and starts the text output at this position. For example, if a line is drawn from 10,10 to 100,100, text output starts at 100,100. To start text output at a position other than where the last graphics operation ended, the following functions may be used:
void gotoxy(int int x, int y); /*Moves the "output cursor" to the indicated position for subsequent text output */ int Wherex(); /*Returns the current x-coordinate of the output cursor */ int Wherey(); /*Returns the current y-coordinate of the output cursor */
For example, adding the following statements to the Sunny Day program
// Label gotoxy(90, 220); DrawText("Home, Sweet, Home!");
11 7
11
For example, the following statements display Lawrenceville Press in RED, Times New Roman, 20 point:
SetTextFont("Times New Roman"); SetTextColor(RED); SetTextSize(20); DrawText("Lawrenceville Press");
Note that these functions return the sizes of the entire screen, not the program window. For example, the following statement draws a circle in the center of the screen, regardless of the screen size, and makes it approximately half the height of the display:
Circle(GetMaxX()/2, GetMaxY()/2, GetMaxY()/4);
11 8
11
A sprig of grass is displayed at base location 60,200. To change the location, only the values of the constants need to be changed. Implementing a Grass() function adds more versatility to the Sunny Day program:
void Grass(int int x, int y) /*Draws a sprig of grass with base at x, y */ { SetColor(GREEN); SetThickness(1); Line(x, y, x+10, y-20); Line(x, y, x10, y20); Line(x5,y,x+15,y15); }
The function could be made a standalone function outside of our GuiClass, or it could be made a member function of GuiClass. The modified Sunny Day program below implements Grass() as a standalone function.
/*Sunny Day with Grass() program */ #include <lvp\gui_top.h> void Grass(int int x, int y) /*Draws a sprig of grass with base at x, y */ { SetColor(GREEN); SetThickness(1); Line(x, y, x+10, y20); Line(x, y, x10, y20); Line(x5, y, x+15, y15); } //-------------------------------------------------------------------------------class GuiClass { public public: GuiClass(); void GuiMouseClick(int int x, int y); // Action if mouse click void GuiPaint(); // Repaint the entire window String Title(); private private: };
11 9
//-------------------------------------------------------------------------------GuiClass::GuiClass() { } //-------------------------------------------------------------------------------String GuiClass::Title() { return ("Grassy Sunny day!"); } //-------------------------------------------------------------------------------void GuiClass::GuiMouseClick(int int x, int y) { } //-------------------------------------------------------------------------------void GuiClass::GuiPaint() { // House SetColor(BLACK); SetThickness(2); Rectangle(100, 100, 200, 200); Line(100, 100, 150, 50); Line(150, 50, 200, 100); SetFillColor(RED); // Paint house red FloodFill(150,110); SetFillColor(GRAY); // Paint roof gray FloodFill(150,90); // Lawn int x = 30; x <= 300; x += 12) for (int Grass(x, 215); // Windows and door SetColor(BLACK); SetThickness(1); SetFillColor(GRAY); FilledRectangle(120, 120, 140, 140); FilledRectangle(160, 120, 180, 140); FilledRectangle(135, 160, 165, 200); SetColor(WHITE); SetPixel(160, 180); // Doorknob! // Sun SetFillColor(YELLOW); SetColor(YELLOW); FilledCircle(280, 50, 30); // Label gotoxy(150, 230); SetTextColor(RED); SetTextFont("Times New Roman"); SetTextSize(26); DrawCenteredText("Home, Sweet, Home"); } //-------------------------------------------------------------------------------#include <lvp\gui_bot.h>
11
11 10
11
The program output shows a field of green grass in front of the house:
Review 6
Modify Review 5 to display a taxi, as shown below:
Review 7
Modify the Sunny Day program to display an additional row of grass in front of the existing grass, increasing the size of the lawn.
Review 8
Write a GUI program with a standalone function DrawCar() that draws a car at the location given by the x and y coordinate parameters. Have the program draw several cars at different locations.
Review 9
Write a GUI program with a standalone function DrawBorder() that puts a green border four pixels thick in the output window, where each side of the border is 20 pixels from the edge of the window. Be sure the program is designed to work regardless of the screen resolution.
11 11
11
GuiMouseClick() updates the values of these variables when a mouse click occurs:
void GuiClass::GuiMouseClick(int int x, int y) { LastX = x; LastY = y; NumClicks++; }
LastX and LastY are initialized to 100 so that at least one circle appears in the window.
11 12
11
The private data members are used in producing a filled circle at the location last clicked, and displaying near the top of the screen the coordinates and the number of clicks. The complete program for handling mouse click events is:
/*Click Tracker program */ #include <lvp\gui_top.h> class GuiClass { public public: GuiClass(); void GuiMouseClick(int int x, int y); // Action if mouse click int GuiPaint(); // Repaint the entire window String Title(); // Return the title for the Window private private: int LastX; // Last location clicked int LastY; int NumClicks; }; //-------------------------------------------------------------------------------GuiClass::GuiClass(): LastX(100),LastY(100),NumClicks(0) { } //-------------------------------------------------------------------------------String GuiClass::Title() { return ("Click tracker!"); } //-------------------------------------------------------------------------------void GuiClass::GuiMouseClick(int int x, int y) { LastX = x; LastY = y; NumClicks++; }
11 13
//-------------------------------------------------------------------------------GuiClass::GuiPaint() { FilledCircle(LastX, LastY, 10); gotoxy(10, 20); DrawText("Clicked at ("); DrawText(LastX); DrawText(","); DrawText(LastY); DrawText(") Number of clicks: "); DrawText(NumClicks); } //-------------------------------------------------------------------------------#include <lvp\gui_bot.h>
11
The program output after two mouse clicks looks similar to:
Review 10
Modify the Click Tracker program so that the last two clicks are recorded and circles displayed for each, with a red circle for the most recent, and a black circle for the previous one. (The message can continue to display the coordinates of just the last click.)
Review 11
Modify the Click Tracker program so that it maintains a list (using an array) of all previous click locations. Have the GuiPaint() function draw circles for all the locations on the list. You need not print information across the top of the window.
To illustrate hit detection, a game program called Treasure Hunt will be written in this section. In this game, the user is presented with an empty grid. In one box of the grid, a treasure is hidden. The user must guess boxes by clicking on them. When a box is clicked and found empty, it changes to gray. When a box is clicked and the treasure is found, it changes to red and the game ends, and the number of clicks is reported. Program output looks similar to that shown at the top of the next page:
11 14
11
Rather than modifying the minimal GUI program, a new class GridClass will be created to encapsulate the game actions. GridClass will have Paint() and MouseClick() member functions that will handle these events. Private to GridClass are data members and functions that will support the game. The grid can be represented using a matrix structure with each item in the matrix storing a value that indicates the status of the box. This status may be empty-and-unpicked, empty-and-already-picked, treasureand-unpicked, and treasure-and-already-picked. These four cases can be represented with four constants. The data member declarations are:
// Constants for board; must all differ const int Empty, EmptyPicked, Treasure, TreasurePicked; int matrix<int int> Board; // Uses above constants int GridDimension; // # of rows and columns in grid
Other data members will track how many boxes the user has clicked on, and whether or not the treasure has been found. To display the grid in the most general way possible, constants which describe the location in the window will be used:
int BoxSize; // Pixels per box int LeftMargin; // Pixels from left int TopMargin; // Pixels from top
These constants can be initialized in the constructor using GetMaxX() and GetMaxY() so that the display looks roughly the same regardless of the screen resolution:
BoxSize(GetMaxY()/2/GridDimension), // Fill half of y-dimension LeftMargin((GetMaxX()BoxSize*GridDimension)/2), TopMargin(GetMaxY()/4)
The box size is computed so that the grid fills half of the vertical dimension. The margins center the grid on the screen. The appearance will be nearly the same on an 800x600 screen as on a 640x480 or any other screen.
11 15
The grid is drawn using two loops. The first loop draws the lines for the columns:
for (Col=0; Col<=GridDimension; Col++) Line(LeftMargin+Col*BoxSize, TopMargin, LeftMargin+Col*BoxSize, TopMargin+GridDimension*BoxSize);
11
Note how the constants are used to position and size the lines. If the grid is five boxes across, this loop draws six lines, thus including lines for the left and right side. A similar loop is needed for the rows. The boxes must be colored according to their contents. To do this, a private member function MarkBox() is called for each item in the grid. MarkBox() calculates the screen coordinates corresponding to the row and column, and then draws a rectangle of the appropriate color using these coordinates:
void GridClass::MarkBox(int int Row, int Col, int BoxContents) /*Post: Row, Col box in appropriate color */ { SetColor(BLACK); // For outline SetFillColor(WHITE); if (BoxContents==EmptyPicked) SetFillColor(GRAY); else if (BoxContents==TreasurePicked) SetFillColor(RED); FilledRectangle(Col*BoxSize+LeftMargin, Row*BoxSize+TopMargin, (Col+1)*BoxSize+LeftMargin, (Row+1)*BoxSize+TopMargin); }
The constants are used with the rows and columns multiplied by the BoxSize in order to find the correct screen position. To manage hit detection the coordinates of a mouse click must be translated to the grid coordinates. This is the opposite of the problem MarkBox() solves. Private member function XYToRowCol() does the translation:
void GridClass::XYToRowCol(int int x, int y, int &Row, int &Col) /*Post: Row and Column corresponding to x, y returned, or 1 returned if x, y is not on the board */ { int DistFromLeft = x LeftMargin; Col = (DistFromLeft+BoxSize)/BoxSize1; int DistFromTop = y TopMargin; Row = (DistFromTop+BoxSize)/BoxSize1; if (Col < 0 || Col >= GridDimension || Row < 0 || Row >= GridDimension) { Row = 1; Col = 1; } }
11 16
11
class GridClass { public public: GridClass(); void Paint(); void MouseClick(int int x, int y); private private: const int GridDimension; // # of rows and columns in grid // Constants for board; must all differ const int Empty, EmptyPicked, Treasure, TreasurePicked; int matrix<int int> Board; // Uses above constants bool GameOver; int NumClicks; int BoxSize; // Pixels per box int LeftMargin; // Pixels from left int TopMargin; // Pixels from top void XYToRowCol(int int x, int y, int &Row, int &Col); void MarkBox(int int Row, int Col, int BoxContents); }; GridClass::GridClass() : GridDimension(5), Empty(0), EmptyPicked(1), Treasure(1), TreasurePicked(2), Board(GridDimension, GridDimension,0), NumClicks(0), GameOver(false), BoxSize(GetMaxY()/2/GridDimension), // Fill half of y LeftMargin((GetMaxX()BoxSize*GridDimension)/2), TopMargin(GetMaxY()/4) { randomize(); Board[random(GridDimension)][random(GridDimension)] = Treasure; } //-------------------------------------------------------------------------------void GridClass::XYToRowCol(int int x, int y, int &Row, int &Col) /*Post: Row and Column corresponding to x, y returned, or 1 returned if x, y is not on the board */ { int DistFromLeft = x LeftMargin; Col = (DistFromLeft+BoxSize)/BoxSize1; int DistFromTop = y TopMargin; Row = (DistFromTop+BoxSize)/BoxSize1; if (Col < 0 || Col >= GridDimension || Row < 0 || Row >= GridDimension) { Row = 1; Col = 1; } }
11 17
//-------------------------------------------------------------------------------int Row, int Col, int BoxContents) void GridClass::MarkBox(int /*Post: Row, Col box in appropriate color */ { SetColor(BLACK); // For outline SetFillColor(WHITE); if (BoxContents==EmptyPicked) SetFillColor(GRAY); else if (BoxContents==TreasurePicked) SetFillColor(RED); FilledRectangle(Col*BoxSize+LeftMargin, Row*BoxSize+TopMargin, (Col+1)*BoxSize+LeftMargin, (Row+1)*BoxSize+TopMargin); } //-------------------------------------------------------------------------------void GridClass::MouseClick(int int x, int y) { int Row, Col; XYToRowCol(x, y, Row, Col); if (Row != 1 && Col != 1 && Board[Row][Col] != EmptyPicked) { if (Board[Row][Col] == Empty) Board[Row][Col] = EmptyPicked; else if (Board[Row][Col] == Treasure) { Board[Row][Col] = TreasurePicked; GameOver = true; } NumClicks++; } } //-------------------------------------------------------------------------------void GridClass::Paint() { SetColor(BLACK); int Row,Col; // Draw lines for (Col = 0; Col <= GridDimension; Col++) Line(LeftMargin+Col*BoxSize, TopMargin, LeftMargin+Col*BoxSize, TopMargin+GridDimension*BoxSize); for (Row = 0; Row <= GridDimension; Row++) Line(LeftMargin, TopMargin+Row*BoxSize, LeftMargin+GridDimension*BoxSize, TopMargin+Row*BoxSize); // Color in boxes for (Row=0; Row < GridDimension; Row++) for (Col=0; Col < GridDimension; Col++) MarkBox(Row, Col, Board[Row][Col]); // Display results if (GameOver==true) { gotoxy(20, 20); DrawText("Game over! Score = "); DrawText(NumClicks); } } //-------------------------------------------------------------------------------//-------------------------------------------------------------------------------class GuiClass { public public: GuiClass(); void GuiMouseClick(int int x, int y); // Action if mouse click void GuiPaint(); // Repaint the entire window String Title(); // Title to display private private: GridClass Game; };
11
11 18
11
//-------------------------------------------------------------------------------GuiClass::GuiClass() { } //-------------------------------------------------------------------------------string GuiClass::Title() { return ("Treasure hunt!"); } //-------------------------------------------------------------------------------void GuiClass::GuiMouseClick(int int x, int y) { Game.MouseClick(x, y); } //-------------------------------------------------------------------------------void GuiClass::GuiPaint() { Game.Paint(); } //-------------------------------------------------------------------------------#include <lvpress\gui_bot.h>
Notice that all the application-specific code is stored in the new class, GridClass. This allows the GuiClass code to be kept simple, and makes it possible to have a single program perform a number of different tasks.
Review 12
The Treasure Hunt program has the odd behavior that after the treasure is found, it keeps counting clicks made to the red treasure box (but not to gray boxes) and also continues to allow the user to click on empty boxes. Determine why this is so, and modify the program to prevent this.
Review 13
Modify the Treasure Hunt program so that clicks off the side of the board cause an error message to be displayed at the top of the screen.
11 19
This function generates a system beep sound. The arguments used with this function are the constants listed below: Argument Sound -1 Standard beep using the computer speaker. MB_ICONASTERISK Plays the sound identified by the SystemAsterisk entry in the [sounds] section of WIN.INI. MB_ICONEXCLAMATION Plays the sound identified by the SystemExclamation entry MB_ICONHAND Plays the sound identified by the SystemHand entry. MB_ICONQUESTION Plays the sound identified by the SystemQuestion entry. MB_OK Plays the sound identified by the SystemDefault entry. Messages are displayed with the following functions:
int MessageBox(String Text, String Title); /*Post: A message box with an OK button displayed */ int MessageBoxYN(String Text, String Title); /*Post: A message box with YES and NO buttons displayed. Returns 1 if user hits YES button; 0 if hits NO button */
11
Each of these functions stop program execution, and wait for the user to click on a button. For example, the following statements:
MessageBox("Box Text", "Box Title"); MessageBoxYN("Box Text", "Box Title");
These boxes, like other windows, can be dragged to reveal information behind them. It is very important that these functions not be called by the Paint() function because this will cause the boxes to be generated whenever the window is moved, resized, or otherwise repainted. Typically, these functions are called in response to other events; for example, mouse click events. The PostQuitMessage() function immediately terminates the program n statement, and eturn and closes the window. This function behaves like a retur is usually given an argument of 0 to indicate normal termination, as in the statement
PostQuitMessage(0);
11 20
11
Case Study
In this Case Study, the Treasure Hunt game will be improved. In addition, a ButtonClass will be written to serve as a utility in other GUI programs.
specification
The Treasure Hunt should contain the following improvements: The program beeps when an illegal click is made When the player wins, the program asks if another game is to be played. The screen contains a I give up! button that when clicked stops the program after giving a simple message and showing the location of the treasure. Program output should look similar to:
11 21
design
Creating beeps and querying the user when the game is over can be done with modifications to MouseClick(). Creating a button is a harder task, but one which could be useful in many programs. Therefore, a new ButtonClass class will be created. ButtonClass will have the following specifications:
class ButtonClass { public public: int Y1, int X2, int Y2); ButtonClass(String Text, int X1,int /* Post: A button created with upper-left corner at X1,Y1 and lower-right corner at X2,Y2 with Text centered in box */ void Paint(); int x, int y); bool IsHit(int /* Post: true returned if and only if (x,y) is on the button */ private private: int MyX1, MyY1, MyX2, MyY2; String MyText; };
11
The GridClass functions can call the Paint() and IsHit() functions of the ButtonClass object. Private data members keep track of the location of the button, and the text of the button.
coding
The text is centered by calculating the middle of the button, and using the DrawCenteredText() function. The value 5 is used to roughly center the text vertically in the button. The IsHit() function is coded as:
int x, int y) bool ButtonClass::IsHit(int /*Post: true returned if and only if point (x, y) is on the button */ { return (x >= MyX1 && x <= MyX2 && y >= MyY1 && y <= MyY2); }
The button object is defined by GridClass as a private data member. The GridClass Paint() function calls the button objects Paint() function. The GridClass MouseClick() function calls the button objects IsHit() function:
11 22
11
void GridClass::MouseClick(int int x, int y) { int Row, Col; if (QuitButton.IsHit(x,y)) { GameOver = true; Board[TreasureRow][TreasureCol] = TreasurePicked; Paint(); // To show the treasure square MessageBox("Come back again!", "Quit button clicked"); PostQuitMessage(0); } else { XYToRowCol(x, y, Row, Col); if (Row != -1 && Col != 1 && Board[Row][Col] != EmptyPicked) { if (Board[Row][Col] == Empty) Board[Row][Col] = EmptyPicked; else if (Board[Row][Col] == Treasure) { Board[Row][Col] = TreasurePicked; GameOver = true; Paint(); // To show treasure square if (MessageBoxYN("Play again?", "Game over")==1) InitGrid(); else PostQuitMessage(0); } NumClicks++; } else MessageBeep(1); } }
The GridClass Paint() function is called each time a message box is displayed. This is so the user can see the effects of the last mouse click before the message box is displayed. An InitGrid() function is needed to reinitialize the grid before playing for a second time. This function will be added to the GridClass declaration. The improved version of the Treasure Hunt is as follows:
/* Improved Treasure Hunt game */ #include #include #include #include #include <lvp\gui_top.h> <lvp\matrix.h> <lvp\string.h> <lvp\bool.h> <lvp\random.h>
//-------------------------------------------------------------------------------class ButtonClass { public public: int Y1, int X2, int Y2); ButtonClass(String Text, int X1,int /* Post: A button created with upper-left corner at X1,Y1 and lower-right corner at X2,Y2 with Text centered in box */ void Paint(); int x, int y); bool IsHit(int /* Post: true returned if and only if (x,y) is on the button */ private private: int MyX1, MyY1, MyX2, MyY2; String MyText; };
11 23
//-------------------------------------------------------------------------------ButtonClass::ButtonClass(String Text, int X1, int Y1, int X2, int Y2) : MyText(Text), MyX1(X1), MyY1(Y1), MyX2(X2), MyY2(Y2) /*Post: Button created with upper-left corner at X1, Y1 and lower right corner at X2,Y2 with Text centered in box */ { } //-------------------------------------------------------------------------------void ButtonClass::Paint() { SetColor(BLACK); Rectangle(MyX1, MyY1, MyX2, MyY2); gotoxy((MyX1+MyX2)/2, 5+(MyY1+MyY2)/2); DrawCenteredText(MyText); } //-------------------------------------------------------------------------------int x, int y) bool ButtonClass::IsHit(int /*Post: true returned if and only if point (x, y) is on the button */ { return (x >= MyX1 && x <= MyX2 && y >= MyY1 && y <= MyY2); } //-------------------------------------------------------------------------------//-------------------------------------------------------------------------------class GridClass { public public: GridClass(); void Paint(); void MouseClick(int int x, int y); void InitGrid(); private private: const int GridDimension; // # of Rows/columns in grid // Constants for board; must all differ const int Empty, EmptyPicked, Treasure, TreasurePicked; int matrix<int int> Board; // Uses above constants int TreasureRow, TreasureCol; bool GameOver; int NumClicks; int BoxSize; // Pixels per box int LeftMargin; // Pixels from left int TopMargin; // Pixels from top void XYToRowCol(int int x, int y, int &Row, int &Col); void MarkBox(int int Row, int Col, int BoxContents); ButtonClass QuitButton; }; //-------------------------------------------------------------------------------GridClass::GridClass() : GridDimension(5), Empty(0), EmptyPicked(1), Treasure(1), TreasurePicked(2), Board(GridDimension,GridDimension,0), NumClicks(0), GameOver(false), BoxSize(GetMaxY()/2/GridDimension), // Fill half of y-dimension LeftMargin((GetMaxX()BoxSize*GridDimension)/2), TopMargin(GetMaxY()/4), QuitButton("I give up!",10,10,100,40) { randomize(); TreasureRow = random(GridDimension); TreasureCol = random(GridDimension); Board[TreasureRow][TreasureCol] = Treasure; }
11
11 24
11
//-------------------------------------------------------------------------------void GridClass::InitGrid() /*Post: Grid initialized for a new game */ { NumClicks = 0; GameOver = false; for (int int Row=0; Row < GridDimension; Row++) for (int int Col=0; Col < GridDimension; Col++) Board[Row][Col] = Empty; TreasureRow = random(GridDimension); TreasureCol = random(GridDimension); Board[TreasureRow][TreasureCol] = Treasure; } //-------------------------------------------------------------------------------void GridClass::XYToRowCol(int int x, int y, int &Row, int &Col) /*Post: Row and Column corresponding to x, y returned, or -1 for if x, y is not on the board */ { int DistFromLeft = x LeftMargin; Col = (DistFromLeft+BoxSize)/BoxSize 1; int DistFromTop = y TopMargin; Row = (DistFromTop+BoxSize)/BoxSize 1; if (Col < 0 || Col >= GridDimension || Row < 0 || Row >= GridDimension) { Row = -1; Col = -1; } } //-------------------------------------------------------------------------------void GridClass::MarkBox(int int Row, int Col, int BoxContents) /*Post: Row, Col box in appropriate color */ { SetColor(BLACK); // For outline SetFillColor(WHITE); if (BoxContents==EmptyPicked) SetFillColor(GRAY); else if (BoxContents==TreasurePicked) SetFillColor(RED); FilledRectangle(Col*BoxSize+LeftMargin, Row*BoxSize+TopMargin, (Col+1)*BoxSize+LeftMargin, (Row+1)*BoxSize+TopMargin); }
11 25
//-------------------------------------------------------------------------------int x, int y) void GridClass::MouseClick(int { int Row, Col; if (QuitButton.IsHit(x,y)) { GameOver = true; Board[TreasureRow][TreasureCol] = TreasurePicked; Paint(); // To show the treasure square MessageBox("Come back again!", "Quit button clicked"); PostQuitMessage(0); } else { XYToRowCol(x, y, Row, Col); if (Row != 1 && Col != 1 && Board[Row][Col] != EmptyPicked) { if (Board[Row][Col] == Empty) Board[Row][Col] = EmptyPicked; else if (Board[Row][Col] == Treasure) { Board[Row][Col] = TreasurePicked; GameOver = true; Paint(); // To show treasure square if (MessageBoxYN("Play again?", "Game over")==1) InitGrid(); else PostQuitMessage(0); } NumClicks++; } else MessageBeep(1); } } //-------------------------------------------------------------------------------void GridClass::Paint() { QuitButton.Paint(); SetColor(BLACK); int Row, Col; // Draw lines for (Col = 0; Col <= GridDimension; Col++) Line(LeftMargin+Col*BoxSize, TopMargin, LeftMargin+Col*BoxSize, TopMargin+GridDimension*BoxSize); for (Row = 0; Row <= GridDimension; Row++) Line(LeftMargin, TopMargin+Row*BoxSize, LeftMargin+GridDimension*BoxSize, TopMargin+Row*BoxSize); // Color in boxes for (Row=0; Row < GridDimension; Row++) for (Col=0; Col < GridDimension; Col++) MarkBox(Row,Col,Board[Row][Col]); // Display results if (GameOver==true) { gotoxy(20,GetMaxY()60); DrawText("Game over! Score = "); DrawText(NumClicks); } }
11
11 26
11
//-------------------------------------------------------------------------------//-------------------------------------------------------------------------------class GuiClass { public public: GuiClass(); int x, int y); //Action if mouse click void GuiMouseClick(int void GuiPaint(); // Repaint the entire window String Title(); // Title to display private private: GridClass Game; }; //-------------------------------------------------------------------------------GuiClass::GuiClass() { } //-------------------------------------------------------------------------------String GuiClass::Title() { return ("Treasure hunt!"); } //-------------------------------------------------------------------------------void GuiClass::GuiMouseClick(int int x, int y) { Game.MouseClick(x, y); } //-------------------------------------------------------------------------------void GuiClass::GuiPaint() { Game.Paint(); } //-------------------------------------------------------------------------------#include <lvp\gui_bot.h>
The ButtonClass may be useful in other programs as well. To make it easily accessible to other programs, it would be best to create a library with ButtonClass. For this reason, it is included with this text and may be used in your programs that have the statement:
#include <lvp\button.h>
Review 14
Modify the Case Study program to include a Trap Door placed randomly. If the user clicks on the trap door before finding the treasure, he loses. To win, the user must find the treasure first.
Review 15
Use button.h to create a program with three buttons labeled Circle, Square, and Quit. Show a square if the Square button is clicked, a circle if the Circle button is clicked, and terminate the program if the Quit button is clicked.
Chapter Summary
Event-driven programming is used to program in a GUI environment. The event-driven program is a set of instructions indicating what is to be done for each possible event. This type of programming differs from console based programming because the program waits for the user to tell the computer what to do.
11 27
The gui_top and gui_bot libraries included with this text allow eventdriven programs to be written by creating an object that responds to events, and adding this object to the system. Functions introduced in this chapter to create graphic images include Circle(), FilledCircle(), Line(), Rectangle(), FilledRectangle(), and SetPixel(). The parameters of these functions refer to pixel units which are single dots on the screen. The upper-left corner of the screen is position (0,0). The outline color and fill color of a graphic image can be specified using SetColor() and SetFillColor() respectively. The line thickness of the outline can be specified with SetThickness(). The color and thickness specified when using these functions stay in effect until the color or thickness is changed again. To color in a region that is irregularly shaped, the FloodFill() function is used. The parameters passed to FloodFill() need to be a single point within the region to be colored. FloodFill() colors any pixel which differs in color from the passed pixel with the current fill color. Because a GUI-based program displays only graphics, cout and cin cannot be used to display text. To display text, the DrawText() and DrawCenteredText() functions are used. Text output is displayed after the last graphics operation. To specify the position of text output, the gotoxy(), wherex(), and wherey() functions are used. Text can also be formatted for font, color, and size using SetTextFont(), SetTextColor(), and SetTextSize(). Because screen resolution can differ from computer to computer, it is useful for a program to know the size of the current screen. The GetMaxX() and GetMaxY() functions are used to return the size of the current screen. Having named constants or variables to identify the location of an object on the screen is useful so that changing a single value is all that is required to modify the object. Mouse click events are handled by the system passing arguments to GuiMouseClick() indicating the x and y coordinates of the location clicked. Code can be added to the GuiMouseClick() function to register the event and the GuiPaint() function can be coded to use this information to update the display. Hit detection is the process of determining what window object has been clicked. This enables a program to have items in a window that can be clicked on to perform certain actions. Message boxes are used to communicate with the user. Message box functions include MessageBeep(), MessageBox(), and MessageBoxYN().
11
Vocabulary
Console Based Program Program that interacts with the user through text displayed on the screen, and keystrokes from the user. Event Something to which a program must respond. Event-driven A program that becomes a set of instructions indicating what is to be done for each event possible.
11 28
11
C++
GUI Based Program A program that waits for the user to tell the computer what to do, usually using graphics and mouse input. Hit Detection The Process of determining what window object has been clicked. Message Box Used to display an important message or ask for specific information. Picture Element A single dot on the screen. Pixel A picture element on the screen. Resolution The fineness of detail that can be displayed on the screen; it depends upon the display and hardware and software.
gui_bot.h A library that creates an object that responds to an event, and adds this object to the system. gui_top.h A library that implements the GuiClass class.
11 29
Exercises
Exercise 1
Write a program that draws the Lawrenceville Press symbol (shown below) roughly in the middle of a window. Use GetMaxX() and GetMaxY() so that it appears in the middle regardless of the screen resolution.
11
Exercise 2
Write a program that draws 10 rectangles with random coordinates.
Exercise 3
Modify Review 11 so that every time a circle is drawn, matching circles are drawn in the other three quarters of the screen. A sample display is shown below:
Exercise 4
Modify Review 11 to add buttons for blue, red, and green. When a button is clicked, the drawing pen is changed to that color so that subsequent circles are drawn in the color clicked.
Exercise 5
Modify Review 11 so that a sprig of grass is placed wherever the user clicks.
Exercise 6
Write a program that allows two people to play Tic-Tac-Toe. The program should let X play first, and then have the players alternate turns. Moves off the board should generate a beep. When a player wins, the program should detect this, give a message, and end the program. 11 30
11
Exercise 7
Modify Exercise 6 to play a 4 x 4 game of Tic-Tac-Toe.
Exercise 8
Write a program that allows a person to play the 15 solitaire game. In this game, the numbers 1 through 15 are randomly distributed around a 4 x 4 grid. Moves are made by sliding numbers into the empty slot. The game is won by getting all the numbers in order with the empty slot in the lower-right corner. In the computer version, the user clicks on a number to slide it into the empty spot. For example, clicking on the 15 below:
Note that not every random board has a solution! To make sure there is a solution, the program must randomly push the numbers around, starting with a correct layout.
Exercise 9
Write a program that plays the game Concentration with the user. A 6 x 6 grid forms a board with all squares initially shown as blank. Behind each square is a number from 1 to 18, in pairs. On each turn, the user clicks on a square, sees what is behind it, then tries to click on the box containing a match. If a match is hit, then the boxes are colored gray, and the player gets another turn. Have the program display which players (computer or user) turn it is, and keep score by counting the number of matches found by each player.
Exercise 10
Write a program to play Connect-Four. This game is played on a grid that contains 7 columns each 5 squares tall. On each turn, the player drops a disk of his or her color into a column, and it falls until it hits the bottom or a previous disk. The game is won by forming a sequence of four disks diagonally, horizontally, or vertically all of one color.
11 31
Exercise 11
Write a program that allows the user to play a game of Battleship against the computer. The program randomly places 4 ships under the water in a 10 x 10 grid. The ships are placed horizontally or vertically, and occupy 2, 3, 4, and 5 squares respectively. The user then clicks on squares in the grid, trying to sink the ships by clicking on all of the squares each occupies. Keep score by showing the number of ships sunk and the number of clicks taken.
11
Exercise 12
Create a DieClass that implements a die with Paint(), GetValue(), and Roll() functions that could be used in a dice-based game.
Exercise 13
Write a program to play Clacker. In Clacker, the numbers 1 through 12 are initially uncovered. The player throws two dice, and may cover the number representing either the total, or the two numbers on the individual dice. For a throw of 3 and 5, for example, the player may cover the 3 and the 5, or just the 8. Play continues until all numbers are covered. The goal is to have the lowest number of rolls. You may wish to use a DieClass as described in the previous exercise.
Exercise 14
Write a program that allows the game Nim to be played with the mouse. Nim is described in Chapter 5 Exercise 12. When a circle is clicked, it becomes highlighted, and all circles in other groups are de-highlighted. When a player has made a selection, a button labeled Take Stones can be clicked and the stones will be removed from the board. You may wish to devise a StoneClass to assist in implementing this game.
Exercise 15
Write a program that allows the Hanoi puzzle to be played on the computer screen. Clicking on a column highlights (or de-highlights) the top ring on the peg. Clicking on another peg causes the ring to be moved. You may want to devise a new PegClass to implement the pegs in this game.
Exercise 16
Write a program that implements a simple flash card system with pairs of items from a file. Initially a word is displayed on the card. When a button labeled Flip Card is clicked, the corresponding word is displayed. When the Flip Card button is clicked again, the original word is displayed. Another button labeled Next Card brings up the next card, and so on.
11 32
11
Exercise 17
Write a class RadioClass the implements radio buttons. In a set of radio buttons, only one button is selected at a time. If the user clicks on another button, it becomes the selected button and the others are deselected. The declaration for the class should be:
class RadioClass { public public: int xLoc, int yLoc); RadioClass(int // location of top left of first button void AddButton(String Text); void Paint(); int x, int y); bool MouseClick(int // returns true if click was on a button String NowSelected(); // returns text of currently selected button private private: };
Exercise 18
Write a program to display the graph of a function on the screen, complete with axes, etc. Use constants to specify the maximum x and y values on the graph. Use the function y = x2 to test your program. Note that since you may wish to graph the function from 0 to 4 on the xaxis and from 0 to 16 on the y-axis, but the screen measures in pixels from 0 to the size of the screen, you will want to write a function to convert pixel location values to x and y values for your graph.
Exercise 19
Write a program that simulates a game of Life as described in Chapter Eight Exercise 13 but which obtains the starting grid by allowing the user to use mouse clicks to add and remove cells. Have the program display buttons at the bottom of the screen to quit and go to the next generation.
Exercise 20
An important area of current mathematical research concerns the topic of iteration. Iteration is the repetition of a mathematical process, and the research concerns how values behave after many iterations. Because of the need for large amounts of computation, this research is possible only because of the computer. Mathematicians have found that many processes behave chaotically meaning that small variations in starting values lead to dramatic variations in results.
11 33
A famous example of this is the Mandelbrot Set. This is a diagram showing the results of iterating a certain operation on points in the x, y plane. If the iteration leads to values that grow very large, the point is colored black. If the iteration leads to values that do not grow, the point is colored white. A graph of the most interesting region of the Mandelbrot Set is shown below:
11
Use this function in a program to display the Mandelbrot Set. Experiment with different ranges of x and y for the picture.
11 34
12
Objectives
After completing this chapter you will be able to: 1. Implement the selection sort and merge sort algorithms. 2. Implement a binary search algorithm. 3. Implement the depth-first search algorithm.
12
n this chapter you will learn advanced algorithms for manipulating and analyzing information.
12 1
12
typedef vector<int int> ArrayType; int //-------------------------------------------------------------------------------const ArrayType &A) int FindLowest(const /*Returns the index of the lowest value in the array. Post: Index of lowest value in array returned */ { int LowSpotSoFar = 0; for (int int i=1; i<A.length(); i++) { if (A[i] < A[LowSpotSoFar]) LowSpotSoFar = i; } return return(LowSpotSoFar); } //-------------------------------------------------------------------------------void AddToArray(ArrayType &A, const int NewItem) /*Increases size of A by 1 and adds NewItem to A Post: Size of A increased by 1, NewItem last element in A */ { A.resize(A.length()+1); A[A.length()1] = NewItem; } //-------------------------------------------------------------------------------void RemoveFromArray(ArrayType &A, const int Index) /*Removes element A[Index] by sliding later elements back. Assumes 0 <= Index < A.length()1 Post: A[Index] deleted, size of A decreased by 1 */ { for (int int i=Index; i<A.length()1; i++) A[i] = A[i+1]; A.resize(A.length()1); } //-------------------------------------------------------------------------------void SelectionSort(ArrayType &A) /*Sorts A from low to high Post: Elements of A in order from low to high */ { ArrayType Temp(0); while (A.length() != 0) { int LowSpot = FindLowest(A); AddToArray(Temp, A[LowSpot]); RemoveFromArray(A, LowSpot); } A = Temp; } //-------------------------------------------------------------------------------void LoadRandomArray(ArrayType &A, int Size) /*Fills array A with Size random values in the range 0..999 */ { const int MaxValue = 999; A.resize(Size); for (int int i=0; i<Size; i++) A[i] = random(MaxValue+1); }
12 2
12
//-------------------------------------------------------------------------------const ArrayType &A) void DisplayArray(const /*Displays the items of A, with field width of 5, 10 per line */ { for (int int i=0; i<A.length(); i++) { cout.width(5); cout << A[i]; if ((i+1)%10 == 0) cout << endl; } cout << endl; } //-------------------------------------------------------------------------------void Sort (ArrayType &A) /*Sorts array A from low to high */ { SelectionSort(A); } //-------------------------------------------------------------------------------int main() { randomize(); ArrayType Sample; const int SampleSize = 20; LoadRandomArray(Sample, SampleSize); DisplayArray(Sample); Sort(Sample); DisplayArray(Sample); return return(0); }
The Sort() function is not necessary, but hides the details of the sort from the programmer coding main(). The program output is similar to: 915 30 16 629 629 902 19 712 19 774 30 712 712 798 86 774 86 564 96 798 712 800 198 800 442 405 365 848 365 198 405 867 848 16 442 902 867 96 564 915
When testing such a complex program, it is important to use several different sample sizes, arrays that are already in order, arrays in reverse order, arrays with many duplicates, etc.
12 3
To time SelectionSort() in the Selection Sort program, the stopwat library is included in the program, and main() is modified as follows:
int main() { StopWatchClass S; S.Reset(); Sort(Sample); cout << S.Reading() << endl; }
12
In this case, the call to Reset() is unnecessary since the constructor automatically resets the stopwatch to 0.0.
Review 1
Modify the Selection Sort program to display the time required for Sort() to execute, and to allow the user to enter the sample size. Run the program using sample sizes of 1000, 2000, 3000, and 4000. Sketch a graph of sample size vs. time required. Be sure to time just Sort().
Review 2
The SelectionSort() uses a temporary array, which takes extra storage space, and makes frequent calls to resize(), increasing execution time. A different version of the selection sort algorithm orders elements by swapping values within the original array, which does not require a second array. This selection sort algorithm requires FindLowest() to find the lowest item in a range:
int FindLowest(const const ArrayType &A, int Start, int End) /*Returns the index of the lowest value in A[Start]..A[End] Post: Index of lowest value in A[Start]..A[End] returned */
Modify the Selection Sort program to implement the algorithm above. Include the timing code as done in Review 1, and perform time trials on sample sizes of 1000, 2000, 3000, and 4000. Compare the results with those in Review 1.
12 4
12
Sorting code can then be defined in terms of ItemType, rather than a specific type. For example:
void AddToArray(ArrayType &A, const ItemType NewItem) /*Increases size of A by 1 and adds NewItem to A Post: Size of A increased by 1, NewItem last element in A */
uct or an object for which the compariIf the items to be sorted are a str struct son operators (<, >, <=, >=) are not defined, the comparison between eleucts ments must be changed accordingly. For example, if the items are str struct containing both Name and Age fields, and it is desired to sort by Age, then the FindLowest() statement
if (A[i] < A[LowSpotSoFar]) LowSpotSoFar = i;
12 5
The MergeSort() subtasks are recursive calls to MergeSort() and a call to Merge(). Thus MergeSort() will need arguments indicating which portion of the array is to be sorted:
void MergeSort(ArrayType &A, int Start, int End) /*Sorts A[Start..End] elements from low to high Pre: Start, End >= 0 Post: Elements A[Start..End] are sorted from low to high */
12
Similarly, Merge() implements the merging of two halves and needs arguments indicating which portion of the array is to be merged:
void Merge(ArrayType &A, int Start, int Mid, int End) /*Merges two sorted portions of A Pre: A[Start..Mid] is sorted, A[Mid+1..End] is sorted Start <= Mid <= End Post: A[Start..End] is sorted */
The stopping condition for the recursive function is determined by comparing Start and End. The middle of the array is calculated using integer division, which automatically truncates the decimal portion of division. Merge() uses a temporary array to store items moved from two sorted portions of A. The items are moved so that the temporary array is sorted. To illustrate the Merge() algorithm, suppose at entry to Merge() the array looks like:
The array is sorted from Start to Mid and from Mid+1 to End. Merge() starts by examining the first element of each sorted portion, Start and Mid+1, as indicated by P1 and P2:
12 6
12
Since A[P1] < A[P2], the element A[P1] is moved to the new array, and P1 is incremented:
In this case, A[P1] > A[P2], so the the element A[P2] is moved to the new array and P2 incremented:
This process is repeated until all items have been moved. Since it is likely that one array portion will be exhausted before the other, Merge() tests for this case and just moves items from the remaining list. Finally, Merge() copies the merged items in the temporary array to the original array. The Merge() code is:
void Merge(ArrayType &A, int Start, int Mid, int End) /*Merges two sorted portions of A Pre: A[Start..Mid] is sorted, A[Mid+1..End] is sorted Start <= Mid <= End Post: A[Start..End] is sorted */ { ArrayType Temp(A.length()); int P1 = Start; int P2 = Mid+1; // Indexes of current item in each sublist int Spot = Start; // Present location in Temp while (!(P1>Mid && P2>End)) { if ((P1>Mid) || ((P2<=End) && (A[P2]<A[P1]))) { Temp[Spot] = A[P2]; P2++; } else { Temp[Spot] = A[P1]; P1++; } Spot++; } // Copy values from Temp back to A for (int int i=Start; i<=End; i++) A[i] = Temp[i]; }
The if says that if the P1 (left) sublist is exhausted, or if the P2 (right) sublist is not exhausted and the P2 element is less than the P1 element, then move an item from the P2 sublist to the Temp array, otherwise move an item from the P1 sublist. The process continues until both sublists are exhausted.
12 7
The Merge Sort program includes all the code for the sort and tests the merge sort:
/* Merge Sort program */ #include #include #include #include <stdlib.h> <iostream.h> <lvp\vector.h> <lvp\random.h>
12
typedef int ItemType; typedef vector<ItemType> ArrayType; //-------------------------------------------------------------------------------void Merge(ArrayType &A, int Start, int Mid, int End) /*Merges two sorted portions of A Pre: A[Start..Mid] is sorted, A[Mid+1..End] is sorted Start <= Mid <= End Post: A[Start..End] is sorted */ { ArrayType Temp(A.length()); int P1 = Start; int P2 = Mid+1; // Indexes of current item in each sublist int Spot = Start; // Present location in Temp while (!(P1>Mid && P2>End)) { if ((P1>Mid) || ((P2<=End) && (A[P2]<A[P1]))) { Temp[Spot] = A[P2]; P2++; } else { Temp[Spot] = A[P1]; P1++; } Spot++; } // Copy values from Temp back to A for (int int i=Start; i<=End; i++) A[i] = Temp[i]; } //-------------------------------------------------------------------------------void MergeSort(ArrayType &A, int Start, int End) /*Sorts A[Start..End] elements from low to high Pre: Start, End >= 0 Post: Elements A[Start..End] are sorted from low to high */ { if (Start < End) { int Mid = (Start+End)/2; MergeSort(A, Start, Mid); MergeSort(A, Mid+1, End); Merge(A, Start, Mid, End); } } //-------------------------------------------------------------------------------void LoadRandomArray(ArrayType &A, int Size) /*Fills array A with Size random values in the range 0..999 */ { const int MaxValue = 999; A.resize(Size); for (int int i=0; i<Size; i++) A[i] = random(MaxValue+1); }
12 8
12
//-------------------------------------------------------------------------------const ArrayType &A) void DisplayArray(const /*Displays the items of A, with field width of 5, 10 per line */ { for (int int i=0; i<A.length(); i++) { cout.width(5); cout << A[i]; if ((i+1)%10 == 0) cout << endl; } cout << endl; } //-------------------------------------------------------------------------------void Sort (ArrayType &A) /*Sorts array A from low to high */ { MergeSort(A, 0, A.length()1); } //-------------------------------------------------------------------------------int main() { randomize(); ArrayType Sample; const int SampleSize = 20; LoadRandomArray(Sample, SampleSize); DisplayArray(Sample); Sort(Sample); DisplayArray(Sample); return return(0); }
A merge sort is much faster than a selection sort. For example, on a Pentium PC, a sample size of 10,000 took almost 4 minutes to sort using the Selection Sort program. The Merge Sort program sorted the same size array in only 4 seconds!
Review 3
Modify the Merge Sort program to perform time trials on MergeSort() for 1000, 2000, 3000, and 4000 items, and compare the results to those for SelectionSort() in Review 1.
Review 4
Draw a recursive call tree for MergeSort() for an array with seven elements. Refer to Chapter Seven (p. 7-9) for more on recursive call trees.
12 9
The BinarySearch() pseudocode is: if (goal == A[middle point]) return (middle point) else if (goal < A[middle point]) return (BinarySearch(lower-half)) else return (BinarySearch(upper-half)) The coded BinarySearch() is:
int BinarySearch(const const ArrayType &A, int Start, int End, int Goal) /*Returns position of Goal, or 1 if Goal not found Pre: Array A[Start..End] is sorted from low to high Post: Position of Goal in A[Start..End] returned, or 1 if Goal not found */ { if (Start > End) return (1); else { int Mid = (Start+End)/2; if (Goal == A[Mid]) return (Mid); else if (Goal < A[Mid]) return (BinarySearch(A, Start, Mid-1, Goal)); else return (BinarySearch(A, Mid+1, End, Goal)); } }
12
n statements. This compact notaThe recursive calls are made from retur eturn tion passes the result of the recursive call back to the calling function. The stopping condition for the recursive function is when the Start index is greater than the End index, which indicates the item is not in the array. The Binary Search program implements the binary search code:
#include <lvp\bool.h> // Merge sort functions here //-------------------------------------------------------------------------------const ArrayType &A, int Start, int End, int Goal) int BinarySearch(const /*Returns position of Goal, or 1 if Goal not found Pre: Array A[Start..End] is sorted from low to high Post: Position of Goal in A[Start..End] returned, or 1 if Goal not found */ { if (Start > End) return (1); else { int Mid = (Start+End)/2; if (Goal == A[Mid]) return (Mid); else if (Goal < A[Mid]) return (BinarySearch(A, Start, Mid-1, Goal)); else return (BinarySearch(A, Mid+1, End, Goal)); } }
12 10
12
//-------------------------------------------------------------------------------int Search(ArrayType &A, int Goal) /*Searches an array for position of Goal Pre: Array A is sorted from low to high Post: Position of Goal in A returned, or 1 returned if Goal not found */ { return return(BinarySearch(A, 0, A.length()-1, Goal)); } //-------------------------------------------------------------------------------int main() { randomize(); ArrayType Sample; const int SampleSize = 20; LoadRandomArray(Sample, SampleSize); Sort(Sample); DisplayArray(Sample); do { int Goal; cout << "Enter a number to search for (1 = done): "; cin >> Goal; if (Goal == 1) break break; cout << "Found at: " << Search(Sample,Goal) << endl; } while (true); return return(0); }
The Search() function is not necessary, but hides the details of the search from the programmer coding main(). When run, the program displays output similar to: 45 354 Enter Found Enter Found Enter Found Enter Found Enter Found Enter 48 379 86 408 99 426 207 552 209 561 230 874 246 910 293 955 319 985
a number at: -1 a number at: 9 a number at: 0 a number at: 19 a number at: -1 a number
to search for (-1 = done): 22 to search for (-1 = done): 319 to search for (-1 = done): 45 to search for (-1 = done): 985 to search for (-1 = done): 998 to search for (-1 = done): -1
The program was tested with values present and not present in the array, at and before the first element in the array, and at and after the last value in the array. The efficiency of the binary search algorithm is remarkable. For example, in an array of 1,000,000 items, the search examines at most 20 elements. If a list of the entire worlds inhabitants were to be searched using this algorithm, less than 40 items would need to be examined!
12 11
Review 5
Modify the BinarySearch() function so that it displays the locations examined in a search. For example: 30 516 52 571 98 585 196 605 286 668 299 720 407 779 409 780 485 868 486 966
12
Enter a number to search for (-1 = done): 196 Examining 9 Examining 4 Examining 1 Examining 2 Examining 3 Found at: 3 Enter a number to search for (-1 = done): -1 Determine at what position an item in the array requires the most examinations to find.
Review 6
The binary search algorithm can be implemented without recursion by the following steps: while loop Enclose the function body with a do do-w Replace the recursive calls with appropriate assignments to the values of Start or End. Write and test a nonrecursive version of BinarySearch().
12
For example, a slide file might contain: 7 9 ** ***** **** **** **** ** Cells are considered to be part of the same colony if they touch horizontally or vertically. This slide contains three colonies. Counting rows and columns starting from zero, one colony has a cell at (1, 3) and contains 9 elements. Another colony has four elements with a cell at (1, 6), and the third has eight elements with a cell at (4, 3). Note that the first and third colonies are considered separate because they touch across a diagonal but not horizontally or vertically. The program output from the analysis of the above slide will be: Colony at (1,3) with size 9 Colony at (1,6) with size 4 Colony at (4,3) with size 8 Depth-first search is appropriate here because once a colony cell is detected, all the possible directions for connected cells must be searched. If a connected cell is a colony cell, then all the possible directions for that cell must be searched, and so on. The basic idea is that, given a starting cell at (Row, Col) in a colony, the total number of connected cells in that colony can be found as: 1 + + + + for the starting cell Count of connected cells Count of connected cells Count of connected cells Count of connected cells starting starting starting starting with with with with (Row+1, Col) (Row1, Col) (Row, Col+1) (Row, Col1)
The latter four lines are recursive calls. To find all the starting cells, all the cells in the slide are tested with a nested for loop.
infinite recursion
When implementing a depth-first search algorithm, code must be included to avoid infinite recursion. For example, a starting cell of (1, 3) generates a recursive call with cell (2, 3), which generates a call with (1, 3) again, which generates a call with (2, 3), and so on. For this program, a cell will be changed to the background color once it has been examined. This makes counting colonies a destructive algorithm, so the original slide contents must be saved and then restored after counting.
12 13
SlideClass class
A SlideClass class will be written to implement slide tasks (LoadSlide(), DisplaySlide(), and DisplayColonies()). To store the slide, an array data member S will be included in the class. Constants will be used to represent the characters * and that are considered part of a colony (Colony) and not part of a colony (NonColony) so that these are easily recognized and easy to modify. The key function, DisplayColonies() checks each cell of the entire slide, and whenever a colony cell is encountered, DisplayColonies() determines the colony size and displays data about the colony. To determine the size, DisplayColonies() calls a private member function with prototype:
int CollectCells(int int Row, int Col); /*Post: All Colony cells adjoining and including cell (Row,Col) have been changed to NonColony, and count of these cells is returned. */
12
Note the use of a temporary matrix, Temp, to restore the contents of the matrix after CollectCells() has destroyed it. The depth-first search algorithm is implemented in CollectCells():
int SlideClass::CollectCells(int int Row, int Col) /*Post: All Colony cells adjoining and including cell (Row,Col) have been changed to NonColony, and count of these cells is returned. */ { if ((Row<0) || (Row>=S.numrows()) || (Col<0) || (Col>=S.numcols()) || (S[Row][Col] != Colony)) return return(0); else { S[Row][Col] = NonColony; // Set to avoid multiple counting return return(1+ CollectCells(Row+1,Col)+ CollectCells(Row-1,Col)+ CollectCells(Row,Col+1)+ CollectCells(Row,Col-1)); } }
programming style
The first if statement checks to see if the current position is on the board, and contains a colony cell. This eliminates the need to check before each recursive call. As good programming style, it is better to check data at the start of the recursive function rather than before each call.
12 14
12
class SlideClass { public public: SlideClass(); void LoadSlide(const const String &FileName); void DisplaySlide() const const; void DisplayColonies(); private private: char matrix<char char> S; int CollectCells(int int Row, int Col); const char Colony, NonColony; }; //-------------------------------------------------------------------------------SlideClass::SlideClass(): Colony('*'), NonColony('-') { } //-------------------------------------------------------------------------------int SlideClass::CollectCells(int int Row, int Col) /*Post: All Colony cells adjoining and including cell (Row,Col) have been changed to NonColony, and count of these cells is returned. */ { if ((Row<0) || (Row>=S.numrows()) || (Col<0) || (Col>=S.numcols()) || (S[Row][Col] != Colony)) return return(0); else { S[Row][Col] = NonColony; return return(1+ CollectCells(Row+1,Col)+ CollectCells(Row-1,Col)+ CollectCells(Row,Col+1)+ CollectCells(Row,Col-1)); } } //-------------------------------------------------------------------------------void SlideClass::DisplayColonies() /*Post: Displays a list of the colonies on the slide S, giving coordinates of a point in each colony and its size */ { // Make copy since CollectCells destroys matrix char matrix<char char> Temp = S; for (int int Row = 0; Row < S.numrows(); Row++) for (int int Col = 0; Col < S.numcols(); Col++) { if (S[Row][Col] == Colony) { int Count = CollectCells(Row,Col); cout << "Colony at (" << Row << "," << Col << ") with size " << Count << endl; } } S = Temp; // Restore matrix }
12 15
//-------------------------------------------------------------------------------const String &FileName) void SlideClass::LoadSlide(const /*Pre: File FileName exists and is formatted as: First line: length of slide Second line: width of slide Remaining lines: characters representing cells. Post: S loaded from file */ { ifstream SlideData(FileName.c_str()); int Length; int Width; SlideData >> Length; SlideData >> Width; S.resize(Length, Width); for (int int Row = 0; Row < Length; Row++) { for (int int Col = 0; Col < Width; Col++) SlideData >> S[Row][Col]; } } //-------------------------------------------------------------------------------void SlideClass::DisplaySlide() const /*Post: Contents of the slide displayed in a compact format */ { for (int int Row = 0; Row<S.numrows(); Row++) { for (int int Col=0; Col<S.numcols(); Col++) { cout << S[Row][Col]; } cout << endl; } } //-------------------------------------------------------------------------------int main() { SlideClass S; S.LoadSlide("slide.dat"); S.DisplaySlide(); S.DisplayColonies(); return return(0); }
12
When run, program output is similar to: -----------*--*---***-*****---*-**-**------****----*--*-Colony at (1,3) with size 9 Colony at (1,6) with size 4 Colony at (4,3) with size 8
Review 7
How must the Depth-First Search program be modified if the definition of a colony allowed the colony to be connected across diagonals? What colonies would be reported by the Depth-First Search program for the sample slide?
12 16
12
Review 8
In the Depth-First Search program, suppose it is desired to display the slide colonies from largest to smallest. Briefly describe how the code would need to be modified to accomplish this, and then modify the code to implement this change.
Review 9
A programmer incorrectly saves and restores the matrix just before and after the call to CollectCells() in DisplayColonies(), as shown in the statements below:
if (S[Row][Col] == Colony) { Temp = S; int Count = CollectCells(Row,Col); S = Temp; cout << "Colony at (" << Row << "," << Col << ") with size " << Count << endl; }
Chapter Summary
Sorting is the process of putting items in a designated order, either from low to high or high to low. The selection sort and merge sort algorithms were presented in this chapter. The merge sort algorithm takes a divideand-conquer approach to sorting. It is implemented recursively and is much faster than a selection sort. One measure of the efficiency of a sorting algorithm is the time it takes. The StopWatchClass, included with this text, can be used to determine the time required for a function to execute. A binary search algorithm can be used to find an element in a sorted array. Binary search is implemented recursively and is very efficient. The depth-first searching algorithm can be used to search through a series of possibilities. When implementing depth-first searching, code must be included to avoid infinite recursion.
Vocabulary
Sorting The process of putting items in a designated order. Selection Sort A sorting algorithm that repeatedly selects the lowest item from a list and moves it to a new list until all the items are ordered from low to high in the new list. Merge Sort A sorting algorithm that recursively sorts a list by dividing the list in half, sorting the halves, and then merging the lists so that the items are in order. Binary Search A searching algorithm that recursively checks the middle of a sorted list for the item sought. Depth-First Searching A searching algorithm that recursively checks a given starting position, processes that position, and then searches adjacent positions.
12 17
Exercises
Exercise 1
Write a program that allows the user to enter any number of names in any order, and then displays the names in alphabetical order.
12
Exercise 2
a) Write a program that allows the user to enter any number of names of people and their ages in any order, and then displays the names in alphabetical order with their age. b) Modify the program to allow the peoples names and their ages to be displayed in order from lowest to highest age.
Exercise 3
Write a program to compare the efficiency of the linear and binary searches. Have the program load an array with random integers in order and then perform the binary search and linear search. For fairness, choose values to search for which are not in the array. Use StopWatchClass to compare the times taken. If a performance is so fast that StopWatch reports zero for the time, modify the program to perform 1000 trials, and then divide the total trial times by 1000 to find the time for one trial. Have the program allow the user to specify the number of elements to place in the array. To avoid having to sort the array, generate the numbers like this:
A[0] = 1; for (Index=1; Index<NumItems; Index++) { A[Index] = A[Index1] + random (3) + 1;
Compare the times with 10, 100, 1000, and 5000 elements.
Exercise 4
a) Perform time trials of the selection sort for different numbers of elements, and make a plot (either by hand or using the computer) of the time (y-axis) versus the number of elements (x-axis). b) Perform time trials of the selection sort of Chapter Eight Exercise 10 for different numbers of elements, and make a plot (either by hand or using the computer) of the time (y-axis) versus the number of elements (x-axis). c) Perform time trials of the merge sort for different numbers of elements, and make a plot (either by hand or using the computer) of the time (y-axis) versus the number of elements (x-axis). d) Compare the results (a), (b), and (c). You may want to write the program output to a file, which can then be loaded into Excel or another spreadsheet for charting.
12 18
12
Exercise 5
const ArrayType &L1, const ArrayType &L2); bool HasItemInCommon(const /*Returns true if and only if L1 and L2 have at least one value in common. */
Since it is not in the precondition, we cannot assume that the arrays are sorted. This function could be implemented in a number of ways, including: a) Take each item from L1 and perform a linear search for it in L2. b) Sort L2 via Merge Sort. Then take each item from L1 and perform a binary search for it in L2. c) Sort L1 and L2 via Merge Sort. Then search for common values through an algorithm similar to merging. Which algorithm do you think will be most efficient for large arrays? Write and test a program using one of these methods with arrays of 1000 integer values.
Exercise 6
1. 2. 3. 4. 5. Create a new list Display the list in date order Display the list in alphabetical order by names Find names with specified date Quit
Write a birthday database program that stores names and birthdays. Include DateClass from Chapter Ten in the database implementation. Have the program provide a menu similar to:
Note that there may be more than one name with a given birth date. Have the program save the information entered by the user in a file when the user quits.
Exercise 7
Write a program to merge two files containing integers. It should take two low-to-high ordered files and create a new file containing all of the elements from both files also in low-tohigh order. Your program must not read the files into an array but instead should read from each file as they are being merged.
Exercise 8
Write a function TernarySearch(), similar to BinarySearch(), that divides the array into three pieces rather than two. TernarySearch() finds the points that divide the array into three roughly equal pieces, and then uses these points to determine where the goal should be searched for. Do time trials to determine if ternary search is faster than binary search.
12 19
Exercise 9
One variation of binary search is called the interpolation search. The idea is to look in a likely spot, not necessarily the middle of the array. For example, if the value sought is 967 in an array that holds items ranging from 3 to 1022, it would be intelligent to look nearly at the end of the array. Mathematically, because 967 is about 95% of the way from 3 to 1022, the position to start searching at is a position 95% of the way down the array. For example, if the array holds 500 elements, the first position to examine is 475 (95% of the way from 1 to 500). The search then proceeds to a portion of the array (either 1..474 or 476..500) depending upon whether 967 is greater or less than the 475th element. a) Modify BinarySearch() to implement interpolation search for an array of integers. Perform time trials to determine if InterpolationSearch() is faster, with random numbers used for the array and also the items sought. b) Can you determine a goal and an array that will produce poor results when the search used is an interpolation search.
12
Exercise 10
A sorting algorithm is said to be stable if two items in the original array that have the same key value (the value to be sorted on) maintain their relative position in the sorted version. For example, assume an array with the following data: Kiki Jon 20 19 Mel 18 Tom 19 Kim 22
When the array is sorted by age, a stable sort would guarantee that Jon would stay ahead of Tom in the sorted array, as in: Kim 22 and not: Kim 22 Kiki Tom 20 19 Jon 19 Mel 18 Kiki Jon 20 19 Tom 19 Mel 18
Which of the sorts presented in this chapter (Selection, Merge) is stable? For each which is not stable, give an example of data to illustrate this.
Excerise 11
A bubble sort works as follows: A pass is made through the array in which each element is compared with the one following it, and the two are swapped if they are out of order. Thus A[1] is compared with A[2] and swapped if needed, then A[2] is compared with A[3], and so on. Passes like this are made repeatedly until a pass is completed with no swaps. Write a Sort() function to implement Bubble Sort().
12 20
12
Exercise 12
A researcher has a new digitizer that reports color codes instead of just black or white. For example, a slide file might contain: 6 8 00550000 00050000 00005500 01200000 01111000 00000030 The digits 1 through 9 represent various colors. The digit 0 represents black (background color). Write a program that displays a listing of the size, location, and color value of each colony found on the slide. A colony is defined as a connected (horizontally or vertically) sequence of cells holding the same color value. For the above slide, the output would be: Color 5 5 1 2 3 Size 3 2 5 1 1 Location 1,3 3,5 4,2 4,3 6,7
Exercise 13
A well-known problem in computer science is called the knapsack problem. A variation is as follows: Given a collection of objects of (possibly) different integral weights, is it possible to place some of the weights in a knapsack so as to fill it to some exact total weight? For example, if the weights are 3, 5, 6, and 9, then it is possible for such totals as 3, 8, 11, 14, 17, etc. to be made exactly, but 2, 4, 22, etc. are not possible. Write a function IsPossible() to solve a given knapsack problem. Use the following header:
const ArrayType &A, int Goal) bool IsPossible(const /* Pre: All elements of A are > 0 Post: true returned if and only if there exists a subset of the elements of A whose sum is exactly Goal */
Hint: This is a depth-first search problem which can be solved using recursion. Write a function Knapsack() using the following header:
const ArrayType &A, int Goal, int Start) bool KnapSack(const /* Pre: All elements of A[Start..A.length()] are > 0 Post: true returned if and only if there exists a subset of the elements of A[Start..A.length()] that sums to exactly Goal */
This handles the first item, and then recursively handles the remaining items in the array.
12 21
The algorithm is to determine if the goal can be found in all of the elements not including the first, or if it can be found by including the first in the subset. The pseudocode is: if (simple case) handle simple cases else if (KnapSack(A, Goal, Start+1)) return(true); else if (KnapSack(A, Goal-A[Start], Start+1)) return(true); else return(false); Note that the simple cases will need to be determined and handled properly.
12
Exercise 14
A Maze can be defined in a file using X characters to represent walls, space characters to represent paths, and a $ character to represent the goal. For example: 8 10 XXXXXXXXXX X X XX XXX XXX XX X X XXXX X X X X X XXX X XXXX $X XXXXXXXXXX The starting point is assumed to be location (1, 1) and the maze is assumed to have a border. Write a program that displays the sequence of positions in a path from the start to the goal, or indicate if no path is available. For example, for the maze above, the program displays: Path: (1,1) (1,2) (1,3) (1,4) (1,5) (1,6) (2,6) (3,6) (4,6) (5,6) (6,6) (6,7) (6,8)
12 22
12
Advanced Exercise 15
The game of Boggle is played on a square board with random letters. The object is to find words formed on the board by contiguous sequences of letters. Letters are considered to be touching if they are horizontally, vertically, or diagonally adjacent. For example, the board: Q A Z Y G W S X U H E D C A J R F V O K T G B P L
contains the words WAS, WAXY, JOB, and others, but not the word BOX. Words can contain duplicate letters, but a single letter on the board may not appear twice in a single word, for example POP is not contained on this board. Write a program that displays a random board, and allows the user to enter words found on the board. Have the program report if the word entered by the user is indeed on the board. Hint: Search the board for the first letter of the word entered, and then recursively search around the found letter for the remaining letters of the word.
12 23
12
12 24
13
Objectives
After completing this chapter you will be able to: 1. Understand stack and queue data structures. 2. Use the stack and queue libraries to implement stacks and queues. 3. Implement linked lists in dynamic memory. 4. Understand pointers. 5. Implement a binary search tree.
13
D
esigning efficient data structures is of equal importance as designing algorithms in creating effective programs. In this chapter the stack and queue data structures will be explained. Linked lists will also be explained, and binary search trees will be implemented for efficiently searching linked lists.
pop
There are two standard operations that can be performed on a stack, and only the top item of a stack can be processed. One operation is the pop stack operation which removes the top item. For example, when a pop is executed on the stack above, the top value, 11, is removed:
The next item, 34, is now at the top of the stack, and is the only item that can be accessed.
push
Another operation is the push stack operation which adds an item to the top of the stack. For example, if the value 27 is pushed onto the stack, the stack becomes:
Data Structures
13 1
LIFO
Since the stack is designed so that the last item pushed on is the first item to be popped, it is sometimes referred to as a last-in-first-out (LIFO) data structure. There are a number of applications of stacks, particularly in writing compiler software. For example, each of the following is generally performed using a stack: Matching of braces, { and }. In C++ programs a close brace, }, always goes with the last open brace, }. Matching of else with if: An else always goes with the last if encountered. Matching of parentheses in an expression: A right parenthesis always goes with the last open parenthesis. Recursion: After completion of a recursive call, control returns to the last call that was executed. In fact, recursion is sometimes replaced with a stack.
13
More simply, this statement declares a stack S that can store integers. The following is the stack class documentation: stack (stack.h) Constructor
stack(); /*Creates a stack Post: A stack with no elements created */
Functions
const ItemType & top(); /*Returns top element without removing it from the stack Post: Value of top element of stack returned */ bool empty(); /*Determines if stack is empty Post: true returned if stack empty, false otherwise */ int length(); /*Determines number of elements in stack Post: Number of elements in stack returned */ void pop(); /*Removes top element from the stack Post: Top element of stack removed */ void pop(ItemType &Item); /*Removes and returns top element from the stack Post: Top element of stack removed and returned */
13 2
13
void push(ItemType &Item); /*Adds item to top of stack Post: Item added to top of stack */ void makeEmpty(); /*Removes all items from stack Post: Stack is empty */
Operators = Copies one stack to another The following program demonstrates a stack:
/* Stack Demonstration program */ #include <iostream.h> #include <lvp\stack.h> int main() { int stack<int int> S; S.push(12); S.push(34); S.push(11); int x; S.pop(x); cout << x << endl; cout << S.top() << endl; return return(0); }
Review 1
What is the output of the following program?
#include <iostream.h> #include <lvp\stack.h> int main() { int stack<int int> S; int x, y; S.push (5); S.push (8); S.pop (x); S.push (x); S.push (12); S.push (13); S.pop(y); cout << x << " " << y << endl; S.pop (y); x = S.top(); cout << x << " " << y << endl; return return(0); }
Data Structures
13 3
Review 2
Complete the function below, and write a program to test it.
const String &L) bool BracketsMatch(const /* Returns true if and only if L contains correctly matching and nonoverlapping brackets, []{}(). For instance: "[t(es)(ti)g]123" returns true "[te(st]ing)" returns false */
13
Hint: Push opening symbols onto a stack of char. When closing symbol is encountered, pop the stack and check to see if it is a match.
Review 3
Consider the hot plate problem: In a busy restaurant, fresh salad plates are brought out and added to the existing pile of plates. This means that, even though there may be plates that were washed long ago, the customer is frequently stuck with a warm plate for salad. Explain how this is analogous to a stack.
All insertions are made at the rear and all removals are made at the front.
dequeue
There are two standard operations that can be performed on a queue. One operation is the dequeue operation which removes an item from the front. For example, when a dequeue is executed on the queue above, the value at the front, 12, is removed from the queue:
enqueue
Another operation is the enqueue operation which adds an item to the rear of the queue. For example, if the value 27 is enqueued, the queue becomes:
FIFO
A queue is analogous to a line at a ticket counter where first come, first served, and is sometimes referred to as a first in first out (FIFO) data structure. There are a number of real-world situations that can be represented as a queue structure. For example: Lines at a toll booth or bank teller
13 4
13
queue type
Waiting lists for tickets on planes Requests made for disk access to a central, shared server Pages of data queued up for a printer Performing breadth-first-searching where all items near the starting position are examined before looking at those farther away.
More simply, this statement declares a queue Q that can store integers. The following is the queue class documentation: queue (queue.h) Constructor
queue(); /*Creates a queue Post: A queue with no elements created */
Functions
const ItemType & front(); /*Returns front element without removing it from the queue Post: Value of front element of queue returned */ bool empty(); /*Determines if queue is empty Post: true returned if queue empty, false otherwise */ int length(); /*Determines number of elements in queue Post: Number of elements in queue returned */ void dequeue(); /*Removes front element from the queue Post: Front element of queue removed */ void dequeue(ItemType &Item); /*Removes and returns front element from the queue Post: Front element of queue removed and returned */ void enqueue(ItemType &Item); /*Adds item to rear of queue Post: Item added to rear of queue */ void makeEmpty(); /*Removes all items from queue Post: Queue is empty */
Data Structures
13 5
13
Review 4
What is the output of the following program?
#include <iostream.h> #include <lvp\queue.h> int main() { int queue<int int> Q; int x, y; Q.enqueue (5); Q.enqueue (8); Q.dequeue (x); Q.enqueue (x); Q.enqueue (12); Q.enqueue (13); Q.dequeue(y); cout << x << " " << y << endl; Q.dequeue (y); x = Q.front(); cout << x << " " << y << endl; return return(0); }
Review 5
Many bakeries have a Take a Number board where the customer takes a number from a hook containing numbers in numerical order, and the salesperson calls out the next number when she is ready for the next customer. Write a program that could replace this board. When a customer arrives, he enters his name in the computer. When the salesperson is ready, she presses a button and the program displays the name of the next customer. Program output should look similar to:
13 6
13
New-customer, Salesperson-ready, Enter your name: Bowen New-customer, Salesperson-ready, Enter your name: Katie New-customer, Salesperson-ready, Salesperson is ready for Bowen! New-customer, Salesperson-ready,
stack implementation
However, as a programmer it is important to at least understand how a stack and a queue might be implemented. For both data structures, it seems natural that a vector be used to store data. In the case of a stack class, the private section could contain a vector to hold all the items on the stack, and an int variable indicating the index of the top of the stack. For example, the following depicts the structure of a stack:
An item is popped by reading the top item and decrementing the value of data member top. Once top is decremented, the contents of the array in location 2 no longer matter, as depicted:
Implementing the empty(), top(), length(), and makeEmpty() functions is a relatively simple matter.
queue implementation
In the case of the queue class, the private section could contain a vector to hold all the items on the queue, and an int variable indicating the index of the front of the queue. For example, the following depicts the structure of a queue:
When an item is dequeued, exactly the same steps are taken as when an item is popped from a stack:
Data Structures
13 7
When an item is enqueued, all the existing items must be moved up by one and the new item stored at index zero:
13
Clearly enqueue is an inefficient, but effective, operation using this approach. The other functions, front(), empty(), length(), and makeEmpty() are straightforward to perform and can be efficiently done.
Review 6
Write a program that uses a class for implementing a stack of ItemType. Include member functions for the constructor, push(const ItemType &Item), pop(ItemType &Item), and top(ItemType &Item). Have the program use a typedef int ItemType, and test the class.
Review 7
Write a program that uses a class for implementing a queue of ItemType. Include member functions for the constructor, enqueue(const ItemType &Item), dequeue(ItemType &Item), and front(ItemType &Item). Have the program use a typedef int ItemType, and test the class.
pointers
Another way of storing lists of data in memory requires each item to store a number that indicates where the next item is stored. These numbers are called pointers because they point to a data location. Rather than using an array of contiguous data, a list where each item points to the next item could be used. This kind of list is called a linked list. A linked list is illustrated like the following:
The pointer to the first item in a linked list is called the head. The last item points to nothing and is called the tail. Each element of a linked list is called a node. Although the pointer number can be determined, this is usually not the way to determine the next data item in a linked list, as discussed in the next two sections.
13 8
13
The advantage of linked lists is that items can be inserted and deleted without moving other items. For example, to insert an item in the linked list, only pointers need to be changed:
declaring a pointer
The following statement declares a pointer to a dynamic memory location storing a string:
String *p; // Declare a pointer to a string
The asterisk indicates that it is a pointer to a string, not a string variable. At this stage, p is a pointer, but does not yet have anything to point at.
allocating memory
storing data
The pointer now points to an area in memory. To store data in memory allocated to p, the following statement is used:
(*p) = "Sandburg"; // Store data at the location pointed to by p
*p is thought of as the location pointed to by p. To access the data at this location, a statement with the following notation is used:
cout << (*p) << endl; // Display data at location pointed to by p
Data Structures
13 9
deallocating memory
When the allocated memory is no longer needed, the following statement deallocates memory:
delete p; // Deallocate the memory pointed to by p
13
The program output is: Sandburg In this program, the use of delete is unnecessary since the computer automatically deallocates the memory when the program terminates.
Review 8
The output of the following code is 17. Explain how this can be true, in words or drawings.
int *p; int *q; p = new int int; q = new int int; (*p) = 12; (*q) = 15; p = q; (*p) = 17; cout << (*q) << endl;
13 10
13
NULL ListClass class
uct that is generic. Using this structure, struct ItemType is used to created a str each node can be depicted as:
The head of the linked list will simply be a NodeType with no data that points to the first element with data. The tail of the linked list must point to nothing. To do this the C++ built-in constant NULL will be used. Using this structure, a ListClass class can be implemented. The ListClass declaration is:
class ListClass { public public: ListClass(); ~ListClass(); void AddAtFront(const const ItemType &Item); void Write(ostream &Output) const const; private private: NodeType *First; };
ListClass()
Write()
The Write() pseudocode is: define a pointer Curr that points to the element pointed to by First While Curr points to a node Display the data in the node Advance Curr to the next node Write() is coded as:
NodeType *Curr = First; while (Curr != NULL) { Output << (*Curr).Data << endl; Curr = (*Curr).Next; }
The notation, (*Curr).Data is used because Curr is a pointer, *Curr is the uct, and .Data refers to a field in the struct object pointed to, in this case a str str uct. The parentheses are needed because the rules of operator precestruct dence require them.
Data Structures
13 11
~ListClass()
The destructor code is similar to Write(). As the list is traversed, each node is deleted. It is illegal to use the data in a node that has already been deleted. Therefore, two pointers must be used:
NodeType *Curr = First; NodeType *Previous; while (Curr != NULL) { Previous = Curr; Curr = (*Curr).Next; delete Previous; }
13
The pointer Previous points to the node behind the current node.
AddAtFront()
The AddAtFront() pseudocode is best described using a picture. For example, assume the following list:
The new node must now be added to the list, using the statement:
(*Temp).Next = First;
13 12
13
Data Structures
13 13
//-------------------------------------------------------------------------------const ItemType &Item) void ListClass::AddAtFront(const /* Post: New node containing Item added at front of list */ { NodeType *Temp; Temp = new NodeType; (*Temp).Data = Item; (*Temp).Next = First; First = Temp; } //-------------------------------------------------------------------------------void ListClass::Write(ostream &Output) const /* Post: Write the data of nodes to Output */ { NodeType *Curr = First; while (Curr != NULL) { Output << (*Curr).Data << endl; Curr = (*Curr).Next; } } //-------------------------------------------------------------------------------int main() { ListClass L; L.AddAtFront("Sandburg"); L.AddAtFront("Strand"); L.AddAtFront("Angelou"); L.Write(cout); return return(0); }
13
The program output is: Angelou Strand Sandburg Since nodes were inserted with AddAtFront(), the list appears in the opposite order from which the items were inserted.
13 14
13
For the purposes of this text, we suggest that the copy constructor and the assignment operator functions be hidden, or made inaccessible. As discussed in Chapter Ten, this requires declaring these member functions in the private section of the class declaration:
private private: const ListClass &L); // Copy constructor ListClass(const operator const ListClass &L); // Assignment operator operator=(const
If there is a need to assign or make a copy of a linked list, then it may be done by copying each of the data items on the list individually, possibly using a Copy() member function.
If the asterisk is omitted from the second variable, then q will be declared as a NodeType rather than as a pointer. The notation (*pointer ).fieldname can be replaced by the notation pointer>fieldname. For example, the statement
(*Temp).Next = First;
This is largely a matter of programmer preference. When passing a pointer as a reference parameter, the declaration of the parameter must have the asterisk first, as in the prototype:
int Foo(NodeType *&p);
Review 9
Modify the ListClass class to include a member function Length() that returns the number of elements in the list.
Review 10
Modify the ListClass class to include a member function LastOnList() that returns the data value stored in the last node of the list.
Data Structures
13 15
13
The node at the top of the tree is called the root. In this tree the root stores 45. The nodes pointed to by any given node are called its children, and that node the parent. For example, the parent of 22 and 41 is 37. Nodes with no children, for example 81, are called leaves. The algorithm for searching is start at the root and if the value sought is less than the root, search the left subtree. If it is greater, search the right. For example, in a search for 41, the root is greater than 41 so the left subtree is searched. Since the left subtree is a tree, this search algorithm can be applied recursively. This proceeds until the data item is found, or an attempt is made to search an empty tree. Note how this approach is similar to binary search. New data is inserted in a binary search tree by following the appropriate left and right pointers until a NULL pointer is found. The new data is put in a node and the NULL pointer is set to point to the new node. Binary search trees are easily traversed, and therefore its data is easily displayed in order. Data stored in the nodes of a binary search tree are displayed by recursively displaying the data in the left subtree, then displaying the root, and then recursively displaying the right subtree.
searching
inserting data
displaying data
13 16
13
TreeClass class
class TreeClass { public public: TreeClass(); ~TreeClass(); void Insert(const const ItemType &Item); void Display(ostream &Output) const const; const ItemType &Item); bool InTree(const private private: TreeNodeType *Root; const TreeClass &L); // Copy constructor TreeClass(const operator const TreeClass &L); // Assignment operator operator=(const }; ivate section holds a single pointer to the root of the tree, and hides The pr pri the copy and assignment functions. The constructor sets the value of Root to NULL.
InTree()
The InTree() pseudocode is: While (Tree not Null) If (goal == root) return true else if (goal < root) Search left subtree else Search right subtree A public member function that requires only the goal as the parameter will be created. This function will call a private member function that implements the recursive search. This is similar to what was done in Chapter Twelve with the Binary Search program where a Sort() function was used to hide the sort details for the programmer coding main(). The private function is coded as:
bool TreeClass::MyInTree(TreeNodeType *T, const ItemType &Item) { if (T == NULL) return (false); else if (Item == (*T).Data) return (true); else if (Item < (*T).Data) return MyInTree( (*T).Left, Item ); else return MyInTree( (*T).Right, Item ); }
Data Structures
13 17
13
Insert()
A similar approach can be taken with Insert(). In this case, the algorithm is to search for an empty subtree. When found, a new node is inserted. Since the tree will be modified, it is passed as a reference parameter to the private function:
void TreeClass::MyInsert(TreeNodeType* &T, const ItemType &Item) { if (T == NULL) { // Insert as root of subtree T = new TreeNodeType; (*T).Data = Item; (*T).Left = NULL; (*T).Right = NULL; } else if (Item < (*T).Data) // Insert elsewhere MyInsert( (*T).Left, Item ); else MyInsert( (*T).Right, Item ); }
Display()
Both MyInsert() and MyInTree() examine only one branch from any given node. The MyDisplay() function, on the other hand, must examine every node. Thus, instead of deciding which direction to follow, it must follow both directions, as shown below:
void TreeClass::MyDisplay(TreeNodeType* T, ostream &Output) const { if (T != NULL) { MyDisplay( (*T).Left, Output ); Output << (*T).Data << endl; MyDisplay( (*T).Right, Output); } }
~TreeClass()
The destructor must examine every node and deallocate the memory it uses. Once again, the simplest approach is to use recursion with another function, MyDestructor():
void TreeClass::MyDestruct(TreeNodeType *&T) { if (T != NULL) { MyDestruct( (*T).Left ); MyDestruct( (*T).Right ); delete T; } }
Note, that the two subtrees are deleted before the root. Once the root node is deleted, the left and right subtrees are not accessible.
13 18
13
Data Structures
13 19
//-------------------------------------------------------------------------------const ItemType &Item) bool TreeClass::InTree(const { return MyInTree(Root, Item); } //-------------------------------------------------------------------------------void TreeClass::MyInsert(TreeNodeType* &T, const ItemType &Item) { if (T == NULL) { T = new TreeNodeType; (*T).Data = Item; (*T).Left = NULL; (*T).Right = NULL; } else if (Item < (*T).Data) MyInsert( (*T).Left, Item ); else MyInsert( (*T).Right, Item ); } //-------------------------------------------------------------------------------void TreeClass::Insert(const const ItemType &Item) { MyInsert(Root, Item); } //-------------------------------------------------------------------------------void TreeClass::MyDisplay(TreeNodeType* T, ostream &Output) const { if (T != NULL) { MyDisplay( (*T).Left, Output ); Output << (*T).Data << endl; MyDisplay( (*T).Right, Output); } } //-------------------------------------------------------------------------------void TreeClass::Display(ostream &Output) const { MyDisplay(Root, Output); } //-------------------------------------------------------------------------------int main() { TreeClass T; T.Insert("Sandburg"); T.Insert("Strand"); T.Insert("Angelou"); T.Display(cout); return (0); }
13
When run, the program output is: Angelou Sandburg Strand Note that, without explicitly sorting, output is sorted. This is a very useful feature of the binary tree structure.
13 20
13
Review 11
Draw a binary tree that has 6 nodes with 3 leaves. Draw one with 6 nodes but only 2 leaves, and one with 6 nodes and only 1 leaf.
Review 12
Modify the TreeClass class to include member functions Length() and MyLength() that return the number of nodes in the tree.
Review 13
Assume that the items 45, 67, 34, 78, and 22 are placed in this sequence in an ordered binary tree of int values using the Insert() function of the TreeClass class. Draw the tree that would be formed. Draw the tree when same items are inserted but in the order 78, 67, 45, 34, 22.
Chapter Summary
A stack is a data structure in which only the top element can be processed. The operations that can be performed on a stack are push and pop. The push operation places an element in the stack as the top element. The pop operation removes the top element of the stack. A stack is sometimes called a LIFO because the first element in is the first element out. The stack library contains a stack class that implements a stack type.
Data Structures
13 21
The queue is a data structure that has a rear and a front. The dequeue operation removes an element from the front. An enqueue operation adds an element to the rear. A queue is sometimes called a FIFO because the first element in is the first element out. The queue library contains a queue class that implements a queue type. A linked list contains nodes where each node contains data and a pointer to the next node in the list. The first node is called the head, and the last the tail. Linked lists are usually implemented in dynamic memory with uct and the entire list represented with a class. struct each element a str The three fundamental operations needed to work in dynamic memory are declaring a pointer, allocating memory for storage, and storing data in allocated space. A binary search tree is a structure that allows for fast insertion and fast searching. In a binary tree, each node has two pointers. The left pointer points to a subtree containing only nodes with lower values of data, and the right contains only nodes with higher values of data. A binary search tree can be quickly searched by using recursion. Inserting and displaying data are also done recursively. Binary search trees are usually implemented uct and the entire tree represtruct in dynamic memory with each element a str sented with a class.
13
Vocabulary
Binary search tree A data structure usually implemented in dynamic memory where each node contains two pointers. Children The nodes pointed to by a parent node. Dequeue The queue operation that removes an element from the front. Dynamic memory Memory allocated from a free area called the heap for use during program execution. Enqueue The queue operation that adds an element to the rear. FIFO First In First Out. Term used to refer to a queue. Front The position of the first element of a queue. Head The first node of a linked list. Heap An area of memory that can be used by a program during execution. LIFO Last In First Out. Term used to refer to a stack. Leaves A node that does not point to another node. Linked list A data structure usually implemented in dynamic memory in which each element points to the next element in a list. Node An element in a linked list or binary tree. Parents Nodes that point to other nodes. Pointer Used by an element of a linked list or binary tree to point to another element.
13 22
13
C++
Pop The stack operation that removes the top element. Push The stack operation that adds the top element. Queue A data structure that has a rear and a front. Rear The position of the last element of a queue. Root The top node of a binary search tree. Stack A data structure in which only the top element can be processed. Tail The last element of a linked list. Top The position of the element just added to a stack.
* Used to declare a pointer uct. > Symbol used to read the data pointed to in a str struct delete Keyword used to deallocate memory. ne w Keyword used to allocate memory new NULL Built-in constant used to indicate nothing.
Data Structures
13 23
Exercises
Exercise 1
The stack implementation presented in this chapter employs an array. A stack can also be implemented using a linked list. Write a stack class that uses a linked list. What are the advantages or disadvantages of using a linked list rather than an array?
13
Exercise 2
Write a program that uses a stack to reverse a set of integers entered by the user and terminated by 999. The program output should look similar to:
Exercise 3
To analyze an expression with parentheses, the computer must be able to determine which left parenthesis any given right parenthesis matches. a) Write a program that asks the user to enter an expression with parentheses, and then displays a list of the positions of pairs of parentheses. The program output should look similar to: Enter an expression (3+4*(4-6)) Pair: 10 and 6 Pair: 11 and 1 You must store the positions of the left parentheses on a stack when they are found. b) Modify the program to detect the two errors below and display appropriate error messages: 1. Attempt to pop an empty stack. 2. Stack not empty at the end of the program.
13 24
13
Exercise 4
The queue implementation presented in the text uses an array, with the rear at the 0th location growing upward, but other array and linked list approaches exist. For each approach described below, implement a class with the standard queue operations. a) Store the queue in an array with the 0th element being the front of the queue. When a dequeue operation is performed, move all of the elements up one space to fill in the gap. b) Store the queue in an array, keeping track of the front and the rear positions with the front towards the 0th element of the array, and the rear toward the end. When an element is dequeued, increment the front counter. When an element is enqueued, increment the rear counter. If the end of the array is reached, slide all the elements forward so that the front is in the 0th position. c) Store the elements in a linked list, maintaining pointers to the first and last nodes on the list. Enqueue items by adding them to the end of the list, and dequeue items from the start of the list.
Exercise 5
int main() { int *A, *B, *C; int; A = new int (*A) = 10; B = A; C = new int int; (*C) = (*A); cout << (*A) << " " << (*B) << " " << (*C) << endl; (*A) = 23; cout << (*A) << " " << (*B) << " " << (*C) << endl; return return(0); }
Exercise 6
struct NodeType { int Data; NodeType *Next; }; int main() { NodeType *S, *T; S = new NodeType; S->Data = 12; T = new NodeType; T->Next = S; T->Data = 23; S->Next = T; return return(0); }
Draw diagrams to illustrate the situation after each statement in the following program. Note that the program produces no output.
Data Structures
13 25
Exercise 7
a) Modify the ListClass to include a member function Sum() that returns the sum of the data fields of all nodes in the list. Note that this will restrict the use of the class to ItemTypes which can be added. b) Modify the ListClass to include a member function Maximum() that returns the largest value found in any data field in the list. Note that this will restrict the use of the class to ItemTypes which can be compared.
13
Exercise 8
a) Modify the TreeClass to include a member function Sum() that returns the sum of the data fields of all nodes in the tree. Note that this will restrict the use of the class to ItemTypes which can be added. b) Modify the TreeClass to include a member function Maximum() that returns the largest value found in any data field in the tree. Note that this will restrict the use of the class to ItemTypes which can be compared.
Exercise 9
Modify the ListClass to include a member function AddAtEnd() that adds new information at the end of the list rather than at the front. The function will need to search for the end of the list, and then add the information.
Exercise 10
A doubly-linked list has pointers to the next and previous nodes, and can be thought of as:
The previous field of the first node is set to NULL. The doubly-linked list may then be implemented with a class that has two pointers, First and Last, as private data members. a) What advantages does this structure offer? What disadvantages?
13 26
13
b) Compare the doubly-linked list with the singly linked list. When would you choose to use one rather than the other? c) Write a class that implements a doubly linked list. Include member functions Write() and WriteReverse(). d) Modify the class in (c) to include a member function Delete() that has the following prototype:
void Delete(const const ItemType &ItemToDelete); /* Deletes first node in the list with data field holding ItemToDelete */
Exercise 11
The height of a binary tree can be thought of as the number of levels in the tree. Below are three trees of height 3:
a) What is the least number of nodes in a tree of height 3? Of height 4? Of height 5? Of height N? b) What is the most number of nodes in a tree of height 3? Of height 4? Of height 5? Of height N? c) Modify TreeClass to include a member function that returns the height of the tree. Use recursion, and the idea that the height of a tree is one more than the height of the taller of its two subtrees. The height of an empty tree is zero.
Exercise 12
An ordered tree can be used to create sorted output, and is therefore the basis of a sort algorithm called TreeSort. The TreeSort algorithm involves adding all the items from an array oneby-one into a tree, and then recovering them back into an array by using a function similar to the Binary Search Tree Display() function. Write a Sort() function based on this idea, and perform timing tests for arrays of various sizes. Plot the results.
Data Structures
13 27
Advanced Exercise 13
It is often useful to be able to analyze a text file and determine the number of different words it contains and how often they appear. A binary search tree can be especially helpful in solving this problem because it allows easy insertion and efficient searching. Write a program that reads each word in a text file and then places it in an alphabetically ordered tree. Each node of the tree should contain a word and a counter which records the number of times the word has been read. Each time a new word is encountered the tree is searched to see if it contains the word, and if it does, its frequency counter is increased by 1. If it does not, the word is added to the tree. You may assume that no word contains more than 15 characters, and may use a simple definition of a word as follows: a word is any sequence of letters terminated by nonletters. Thus cant is treated as a three-letter word followed by a one-letter word.
13
13 28
hapter Two introduced object-oriented programming with C++ and explained how a program is compiled before it can be run on the computer. This appendix introduces how to use the Turbo C++, version 4.5 for Windows 95 compiler.
A1
A
The Save File As dialog box
Selecting the OK button saves the program to disk. After a program is saved it can be run. When finished working in Turbo C++, the Exit command from the File menu is selected to close any edit windows and remove the Turbo C++ IDE from the Desktop.
Review 1
In this review, you will enter the Hello world program.
1) ENTER A PROGRAM
a. Start Turbo C++. The IDE is displayed with a blank edit window. b. In the edit window, type the following program
/*Hello world program. Your Name Date */ #include <iostream.h> int main() { cout << "Hello, world!"; return return(0); }
A2
A.2 Compiling
The Turbo C++ IDE automatically compiles the C++ source code into the object code and links the object code to create the executable file when the Run command (Ctrl+F9) from the Debug menu is selected or the Run button on the Tool bar ( ) is clicked. The program, in linked object form, is then executed by the system. When a program is run, its output is displayed in a window. For example, when the Hello world program is run its output looks similar to:
A.3 Errors
The Turbo C++ compiler will notify you of any syntax errors when the program is compiled:
A3
Save As
Review 2
In this review you will run the Hello world program.
1) OPEN HELLO.CPP
a. From the File menu, select the Open command. The Open a File dialog box is displayed. b. Select hello.cpp from the list of file names. c. Select OK. The program is displayed in an edit window.
A4
3) RUN HELLO.CPP
From the Debug menu, select the Run command. The program is compiled. If there are no errors the program is also linked and then run, and the output from the program displayed in a window. If the program has errors, they must be corrected and then the Run command selected again to compile, link, and run the program.
A5
Errors in a program can become more obvious if the values of variables are known throughout program execution. Highlighting a variable name in the edit window, selecting the Add watch command, and then selecting OK in the dialog box adds the variable name to a Watch window. The values of variables in the Watch window are updated as the statements in the program are executed. The watch window is most useful when stepping through a program.
A.7 Libraries
All C++ compilers include standard libraries that can be used in programs, such as the iostream library. However, each compiler may have additions to a library that are specific to that compiler. Below are notes about the libraries used in this text:
bool.h random.h
Turbo C++ does not implement a bool type. Therefore, the bool library must be included in a program implementing this type. The random() and randomize() functions may alternatively be implemented by including the stdlib library supplied by Borland. Please refer to the Teachers Resource Package and the README.TXT file supplied on disk for more information about libraries used in this text.
A6
hapter Two introduced object-oriented programming with C++ and explained how a program is compiled before it can be run on the computer. This appendix introduces how to use the Microsoft Visual C++, version 4.0 for Windows compiler.
Select OK to display the New Project Workspace dialog box and then select Console Application in the Type options:
Typing a descriptive name in the Name entry box and then selecting the Create button will create the project workspace.
B1
After the project workspace has been created, a program can be typed in an edit window. To display the edit window, select the New command from the File menu and then select Text File in the New dialog box. In the example below, a project workspace was created and then the Hello world program typed into the edit window:
When finished working in Visual C++, the Exit command from the File menu is selected to close any edit windows and remove the Visual C++ MDS window from the Desktop.
B2
Review 1
In this review, you will enter the Hello world program.
2) ENTER A PROGRAM
a. b. c. d. From the File menu, select New. Select Text File in the New dialog box. Select OK. A blank edit window is displayed. In the edit window, type the following program:
/*Hello world program. Your Name Date */ #include <iostream.h> int main() { cout << "Hello, world!"; return return(0); }
B.2 Compiling
After the C++ source code has been saved, the file needs to be added to the project workspace before it can be compiled. To do this, select the Files into Project command from the Insert menu. Next, select the file name with the .cpp extension and select the Add button.
B3
Visual C++ automatically compiles the C++ source code into the object code and links the object code to create the executable file when the Build <project name>.exe command from the Build menu is selected or the Build button on the Tool bar ( ) is clicked. The program, in linked object form, is then executed and the output displayed in a window by selecting the Execute <project name>.exe command from the Build menu. For example, when the Hello world program is run its output looks similar to:
B.3 Errors
The Visual C++ compiler will notify you of any syntax errors when the program is compiled. A message is displayed at the bottom of the Visual C++ MDS window listing possible causes for errors:
printing a program
B4
Review 2
In this review you will run the Hello world program.
B5
B.7 Libraries
All C++ compilers include standard libraries that can be used in programs, such as the iostream library. However, each compiler may have additions to a library that are specific to that compiler. Below are notes about the libraries used in this text:
iostream.h
To format output in a field, as done in Chapter Three, alignment can be changed from left to right by first unsetting the left alignment before setting the alignment to right. For example, to change a fields alignment from left to right, the following statements are required:
cout.unsetf(ios::left); cout.setf(ios::right);
Please refer to the Teachers Resource Package and the README.TXT file supplied on disk for more information about the libraries used in this text.
B6
hroughout this text C++ keywords were introduced. Keywords have special meanings in C++, therefore they may not be used as identifiers. The following is a list of the C++ keywords. asm auto break case catch char class const continue default delete do double else enum extern float for friend goto if inline int long new operator private protected public register return short signed sizeof static struct switch template this throw try typedef union unsigned virtual void volatile while
C1
C2
Program Index
AccountClass ...................................................... 10-24 AccountClass class ..................................... 10-1, 10-5 AccountClass class demonstration ................... 10-7 AccountClass class with default constructor .. 10-10 Area Under a Curve ........................ 7-17, 7-18, 7-21 Average of Array Elements .................................. 8-5 Binary Search tree .............................................. 13-19 Bookstore Inventory ............................................ 9-24 Calculate Average ................................................ 4-15 Circle Area............................................. 2-5, 3-3, 4-10 CircleClass ............................................................... 6-1 Click Tracker ....................................................... 11-13 CollegeClass .................................................. 6-2, 6-13 Compare Strings ................................................... 8-10 date library .......................................................... 10-17 DateClass ............................................................. 10-11 Default Parameter DrawBar() .............................. 5-6 Depth-First Search ............................................. 12-15 Dice Rolls ............................................................... 8-11 Doodle .................................................................... 4-21 Dynamic Memory Demonstration .................. 13-10 Election Summary ................................................ 8-31 File Statistics .......................................................... 9-12 fstream class .......................................................... 9-16 Game of 21 ............................................................. 5-24 GridClass class ................................................... 11-15 Guessing Game ..................................................... 4-23 GUI library .......................................................... 11-12 gui_bot library ...................................................... 11-1 gui_top library ...................................................... 11-1 GuiClass class ....................................................... 11-2 Hello world ............................................................. 2-2 ifstream class ........................................................... 9-1 Improved AccountClass demonstration ........ 10-31 Improved Treasure Hunt Game ...................... 11-19 ios .............................................................................. 6-5 Linked List ........................................................... 13-13 ListClass class ..................................................... 13-11 math library ............................................................. 7-1 matrix library ........................................................ 8-14 Merge Sort ............................................................. 12-8 Minimal GUI ......................................................... 11-2 ofstream class .......................................................... 9-8 Olympic Symbol ................................................... 11-3 Overload DrawBar() .............................................. 5-5 PegClass ........................................................... 6-2, 6-6 PegClass Class Demonstration ............................ 6-7 Queue Demonstration ......................................... 13-6 queue library ......................................................... 13-5 Read and Write File ............................................. 9-16 Read Characters ..................................................... 9-6 Read File .................................................................. 9-3 Read Scores ............................................................. 9-4 Recursive Towers of Hanoi ................................ 7-10 Reference Parameters .......................................... 5-10 Sailboat Picture ....................................................... 2-7 Selection Sort ......................................................... 12-2 Sine and Cosine ...................................................... 7-2 SlideClass class ................................................... 12-14 Stack Demonstration ........................................... 13-3 stack library ........................................................... 13-2 stopwat.h ............................................................... 12-3 StopWatchClass class .......................................... 12-3 string ......................................................................... 6-3 String type demonstration .................................. 3-10 Student Records ................................................... 8-24 Sunny Day ............................................................. 11-5 Sunny Day with Grass() ...................................... 11-9 Temperature ............................................................ 4-2 Tic-Tac-Toe ............................................................ 8-16 Time Conversion .......................................... 5-2, 5-19 Top Colleges by Enrollment ............................... 6-14 TopListClass .................................................. 6-2, 6-10 TopListClass Class Demonstration ................... 6-11 Tower of Hanoi ....................................................... 6-9 Treasure Hunt ..................................................... 11-17 TreeClass class .................................................... 13-17 Uppercase Characters ......................................... 8-13 Utility library ........................................................ 5-16 Value Parameters ................................................... 5-9 vector class demonstration ................................... 8-2 vector library ........................................................... 8-1 Vote Analysis ........................................................ 3-17 Write File ............................................................... 9-10
Index
I1
Index
- .................................................................................. 2-6 -- .............................................................................. 4-18 ! .................................................................................. 4-8 #define .................................................................. 10-16 #endif .................................................................... 10-16 #ifndef .................................................................. 10-16 #include .................................................................... 6-2 #include ................................................................ 10-16 & .............................................................................. 5-10 && ............................................................................. 4-8 * ...................................................................... 2-6, 13-15 *& .......................................................................... 13-15 */ ............................................................................... 2-3 .cpp ......................................................................... 10-5 .h .............................................................................. 10-5 / ................................................................................. 2-6 /* ............................................................................... 2-3 // .............................................................................. 2-3 :: ............................................................................... 10-4 ; ................................................................ 2-3, 4-3, 4-13 \ ................................................................................. 2-6 \\ .............................................................................. 2-7 \................................................................................ 2-7 \ ............................................................................... 2-7 \a ............................................................................... 2-7 \n ................................................... 2-7, 3-12, 9-7, 9-17 \t ............................................................................... 2-7 \t ............................................................................... 9-7 ^ ................................................................................. 3-8 _ ............................................................................. 10-16 { .................................................................................. 2-3 | ............................................................................... 9-16 || .............................................................................. 4-8 } .................................................................................. 2-3 ~ ............................................................................. 10-20 .................................................................................. 3-6 ..................................................................... 3-10, 5-16 + ................................................................................. 2-6 + with strings .......................................................... 6-4 ++ ............................................................................ 4-16 += ............................................................................ 4-16 += with strings ........................................................ 6-4 < ............................................................................... 5-16 << .................................................................... 2-2, 9-10 = ................................................................................. 3-1 -= ............................................................................. 4-18 == .............................................................................. 4-3 > ............................................................................... 5-16 -> ........................................................................... 13-15 >> .............................................................................. 9-5
I
A
abacus ....................................................................... 1-2 actual argument ...................................................... 5-4 actual parameter ..................................................... 5-4 Ada, Countess of Lovelace ......................... 1-5, 1-18 Add watch command ........................................... A-5 Aiken, Howard ....................................................... 1-6 algorithm ............................................................... 4-11 algorithms .............................................................. 12-1 allocating memory ............................................... 13-9 ALTAIR .................................................................. 1-11 ALU ........................................................................ 1-14 American National Standards Institutes ......... 1-23 Analytical Engine ................................................... 1-4 append data to a file ............................................ 9-15 Apple Computers ................................................. 1-11 application specific ............................................ 10-11 Arabic numerals ..................................................... 1-2 arguments ................................................................ 5-3 array ............................................................... 8-1, 8-22 array index ............................................................ 8-11 array type ................................................................ 8-1 ASCII ...................................................................... 1-16 ASCII code ............................................................. 7-11 ASCII files ................................................................ 9-4 assignment ............................................................... 3-1 assignment operator .......................................... 10-20 assignment operator functions ........................ 10-21 assignment vector .................................................. 8-4 Association for Computing Machinery ............ 1-23 Atanasoff Berry Computer ................................... 1-8 Atanasoff, John ....................................................... 1-8 atof() ......................................................................... 6-4 atoi() .......................................................................... 6-4 auxiliary memory ....................................... 1-13, 1-14
B
Babbage, Charles .................................................... 1-4 base 10 .................................................................... 1-15 base 16 .................................................................... 1-15 base 2 ...................................................................... 1-15 base class .................................................................. 9-1 Bell Laboratories .................................................... 2-1 Bell Labs ................................................................. 1-18 binary ....................................................................... 7-4 binary search ......................................................... 12-9 binary search trees ............................................. 13-16
I2
binary system ........................................................ 1-15 binary tree, height .............................................. 13-27 bit ............................................................................ 1-16 body .......................................................................... 2-2 bool ......................................................................... 4-18 bool.h ....................................................................... A-6 Boolean expression ................................................ 4-1 Boolean variable ................................................... 4-18 booting ................................................................... 1-17 Brain Kernighan ..................................................... 2-1 break ....................................................................... 4-19 bubble sort ........................................................... 12-20 Build command ..................................................... B-4 building linked lists ........................................... 13-10 byte ......................................................................... 1-16
C
C ...................................................................... 1-18, 2-1 c_str() .............................................................. 6-4, 9-11 C++ ....................................................... 1-18, 2-1, 4-16 call-by-reference parameters ................................ 5-9 call-by-value parameters ...................................... 5-9 called ........................................................................ 5-2 case .......................................................................... 7-14 case-sensitive .......................................................... 2-2 casting .................................................................... 7-11 CD-ROM ...................................................... 1-12, 1-14 Census Bureau ................................................ 1-6, 1-8 central processing unit ................................ 1-8, 1-12 char ........................................................................... 3-6 character data storage ......................................... 7-11 children ................................................................ 13-16 chips .......................................................................... 1-9 cin .............................................................. 3-3, 6-5, 9-1 class ................................................................. 6-1, 10-1 class constructor ................................................... 10-4 class declaration ................................................... 10-3 classes ....................................................................... 2-1 client program ...................................................... 10-7 close() ..................................................................... 9-11 clreol() .................................................................... 4-20 clrscr() .................................................................... 4-20 COBOL ................................................................... 1-18 code design ............................................................ 4-23 coding ..................................................................... 3-15 college.h ................................................................. 6-13 colors ............................................................ 11-4, 11-8 comments ................................................................. 2-3 compiler directives ............................................ 10-16 compiling ................................................................. 2-4 compiling a program ................................... A-3, B-4 compound statement ............................................. 4-4 computer .................................................................. 1-1 computer architecture ......................................... 1-12 computer pirates .................................................. 1-22
concatenated ................................................. 3-11, 6-4 conio.h .................................................................... 4-20 console based program ....................................... 11-1 console output stream ........................................... 9-1 const .............................................................. 3-14, 10-2 const parameters .................................................... 6-6 constant .................................................................... 3-4 constant data members ......................................... 6-5 constructor member function .............................. 6-5 copy constructor ................................................. 10-20 copy constructor ................................................. 10-21 counters .................................................................. 4-15 counting ................................................................. 4-14 cout ........................................................... 2-2, 6-5, 9-1 CPU ................................................................. 1-8, 1-12 creating a project workspace .............................. B-1 C-style string ................................................. 6-4, 9-11
D
dangling else ........................................................... 4-6 data ........................................................................... 1-1 data design ............................................................ 4-23 data hiding ............................................................ 10-1 data members ....................................................... 8-21 deallocating memory ......................................... 13-10 debug ...................................................................... 1-18 debugging ............................................. 3-15, A-6, B-6 decimal system ..................................................... 1-15 declaring a pointer ............................................... 13-9 decrement operator ............................................. 4-18 default case ............................................................ 7-14 default constructor ........................... 8-6, 10-8, 10-20 default parameter ................................................... 5-6 defining member functions ................................ 10-4 delete .................................................................... 13-10 Dennis Ritchie ......................................................... 2-1 depth-first search ............................................... 12-12 dequeue .................................................................. 13-4 derived class ........................................................... 9-1 design ..................................................................... 3-15 destructor ............................................................ 10-20 dialog box .............................................................. 1-17 Difference Engine ................................................... 1-4 disk operating system ......................................... 1-17 diskette drive ........................................................ 1-12 diskettes ................................................................. 1-14 documentation, classes ......................................... 6-2 documentation, libraries ....................................... 6-2 double ............................................................. 3-1, 3-14 doubly-linked list ............................................... 13-26 do-while ................................................................. 4-10 dynamic array ......................................................... 8-7 dynamic memory ................................................. 13-9 dynamic memory bugs ..................................... 13-14 dynamic memory pointers ................................. 13-9
Index
I3
E
Eckert, J. Presper .................................................... 1-7 edit window .................................................. A-1, B-2 EDSAC ..................................................................... 1-8 EDVAC .................................................................... 1-8 efficiency ................................................................ 12-3 Electronic Communications Privacy Act ......... 1-21 Electronic Tabulating Machine ............................ 1-5 else-if ladder ........................................................... 4-6 else-if ladder logic .................................................. 4-6 encapsulation ........................................................ 10-1 end of line ................................................................ 2-7 endl ........................................................................... 2-6 ENIAC ............................................................ 1-7, 1-11 enqueue .................................................................. 13-4 entering a program in Turbo C++ ...................... A-1 entering a program in Visual C++ ..................... B-1 enumerated type .................................................. 7-13 eof() ........................................................................... 9-8 errors, displaying ......................................... A-3, B-4 escape character ..................................................... 2-7 escape sequence ...................................................... 2-7 ethical consequences ............................................ 1-20 ethical responsibilities ......................................... 1-19 event-driven program ......................................... 11-1 executable file ......................................................... 2-4 execute ...................................................................... 2-4 Execute command ................................................. B-4 Exit command ............................................... A-2, B-2 exiting Visual C++ ................................................ B-2 exiting Turbo C++ ................................................. A-2 exponent ................................................................ 1-17 exponential functions ............................................ 7-3 extended characters ............................................. 7-11
FORTRAN ..................................................... 1-18, 7-1 Fourth Generation computers ........................... 1-11 free functions ...................................................... 10-14 free-form .................................................................. 2-8 front ........................................................................ 13-4 fstream ..................................................................... 9-1 function ............................................................ 2-3, 5-1 function definition ................................................. 5-2 function header ....................................................... 2-3 function overloading ............................................. 5-5 function prototype ............................................... 5-18 functions, methodology ...................................... 5-12
G
General Protection Fault error ......................... 13-14 generic code .......................................................... 12-5 get from operator ................................................... 3-3 get pointer ............................................................. 9-15 get() ........................................................................... 9-6 getch() ..................................................................... 4-20 getche() ................................................................... 4-20 getline() .......................................................... 3-10, 9-3 gigbytes .................................................................. 1-16 global declaration ................................................. 9-20 gotoxy() .................................................................. 4-20 graphical user interface ....................................... 1-17 graphics .................................................................. 11-7 GUI ............................................ 1-17, 2-1, 11-1, 13-21 GUI based program ............................................. 11-1
H
hackers ................................................................... 1-22 hard disk ...................................................... 1-12, 1-14 hardware components ......................................... 1-12 head ........................................................................ 13-8 header file .............................................................. 10-5 heap ........................................................................ 13-9 help ........................................................................... 2-8 Help menu, using ......................................... A-5, B-5 hexadecimal system ............................................. 1-15 hit detection ........................................................ 11-14 Hoff, Marcian ........................................................ 1-11 Hollerith, Herman .................................................. 1-5 Hopper, Grace Murray ....................................... 1-18
F
fail() ................................................................. 9-3, 9-10 Fair Credit Reporting Act ................................... 1-21 false ......................................................................... 4-18 FIFO ........................................................................ 13-4 file pointers ............................................................ 9-15 File into Project command ................................... B-3 filled objects .......................................................... 11-5 Financial Privacy Act ........................................... 1-21 find() ......................................................................... 6-3 First Generation computers ................................ 1-11 flag .......................................................................... 4-15 floating point ........................................................... 3-6 floating point numbers ........................................ 1-17 floating point random number .......................... 4-20 fonts ........................................................................ 11-8 for ............................................................................ 4-17 formal argument .................................................... 5-4 formal parameter ................................................... 5-4
I
IBM ........................................................................... 1-6 IDE ........................................................................... A-1 identifier .................................................................. 3-1 if ................................................................................. 4-1 if-else ........................................................................ 4-4 ignore() ........................................................... 3-12, 9-8
I4
implementation file .............................................. 10-5 increment operator .............................................. 4-16 index offsetting ..................................................... 8-12 infinite loop ........................................................... 4-13 infinite recursion ........................................ 7-6, 12-13 inheritance ............................................................... 9-1 initialized ............................................................... 4-15 initializer list ............................................... 8-20, 10-4 input devices ......................................................... 1-12 input stream .......................................................... 9-14 instance .................................................................... 6-1 instantiation ............................................................ 6-1 int .................................................................... 3-6, 3-14 integer division ....................................................... 3-8 integer to character equivalents ........................ 7-12 integrated circuits .................................................. 1-9 Integrated Development Environment ............. A-1 integration ............................................................. 7-15 Intel Corporation .................................................. 1-11 interface file ........................................................... 10-5 interpolation search ........................................... 12-20 ios::end ................................................................... 9-15 ios::fixed ................................................................. 3-13 ios::in ...................................................................... 9-16 ios::left .................................................................... 3-13 ios::out .................................................................... 9-16 iostream.h ............................................................... B-6 istream class .......................................................... 9-14 iteration .................................................................. 4-10
logarithmic functions ............................................ 7-3 logic error .............................................................. 4-12 logic operators ........................................................ 4-8 long ................................................................. 3-6, 3-14 looping ................................................................... 4-10
M
machine language ........................................ 1-18, 2-4 main() ............................................................... 2-3, 5-8 mainframes ............................................................ 1-10 mantissa ................................................................. 1-17 Mark I ....................................................................... 1-6 math library ............................................................. 7-4 math.h ...................................................................... 7-1 matrix parameters ................................................ 8-17 matrix type ............................................................ 8-14 Mauchly, John ......................................................... 1-7 MDS ......................................................................... B-1 megabytes .............................................................. 1-16 member function .................................................... 6-1 memory .................................................................. 1-12 memory address ................................................... 1-16 merge sort .............................................................. 12-5 message boxes ..................................................... 11-19 method ..................................................................... 6-1 MFC ...................................................................... 13-21 microcomputer ..................................................... 1-11 microprocessors ................................................... 1-11 Microsoft Developer Studio ................................ B-1 Microsoft Visual C++ ........................................... B-1 modulus division ................................................... 3-8 mouse click events ............................................. 11-12 multidimensional arrays ..................................... 8-26 multitasking .......................................................... 1-17
J
Jacquard, Joseph ..................................................... 1-4
K
kbhit() ..................................................................... 4-20 keywords ................................................................. 3-5 keywords, list of .................................................... C-1 kilobytes ................................................................. 1-16 knapsack problem .............................................. 12-21
N
National Information Infrastructure ................ 1-20 nested if .................................................................... 4-5 networked .............................................................. 1-12 new ......................................................................... 13-9 New command ............................................. A-4, B-1 node ........................................................................ 13-8 non-filled objects .................................................. 11-4 NULL .................................................................... 13-11 number systems .................................................... 1-15 numerical integration .......................................... 7-16
L
leaves .................................................................... 13-16 Leibniz Wheel ......................................................... 1-3 length() ............................................................. 6-3, 8-4 libraries used in text, about ........................ A-6, B-6 library ............................................................... 2-3, 3-9 library, building .................................................... 5-15 LIFO ........................................................................ 13-2 line thickness ............................................... 11-4, 11-5 linear search ............................................................ 8-7 linked lists ............................................................. 13-8 linking ...................................................................... 2-4 log() ......................................................................... 7-16
O
object ............................................................... 1-17, 6-1 object code ............................................................... 2-4 object-oriented ........................................................ 2-1 object-oriented design ....................................... 10-22 object-oriented program ................................... 10-22
Index
I5
offsetting indexes ................................................. 8-12 OOD ...................................................................... 10-22 OOP ...................................................................... 10-22 open() ..................................................................... 9-11 Open command ............................................ A-4, B-4 Open Workspace command ................................ B-4 opening a program ...................................... A-4, B-4 operator member function ....................... 6-4, 10-13 operator precedence .............................................. 3-9 outpur devices ...................................................... 1-12 overflow error ....................................................... 1-17 overloading operators ....................................... 10-13 overloading stream operators .......................... 10-14 OWL ..................................................................... 13-21
R
RAM ....................................................................... 1-13 random access files .............................................. 9-14 random number generating ............................... 4-19 random() ................................................................ 4-19 random.h ................................................................ A-6 randomize() ........................................................... 4-19 range errors ............................................................. 8-3 read error ................................................................. 9-5 reading character data .......................................... 9-6 reading numeric data ............................................ 9-4 real numbers ......................................................... 1-17 rear .......................................................................... 13-4 recursion .................................................................. 7-6 recursive call tree ................................................... 7-8 recursive calls ......................................................... 7-6 reduction of complexity .................................... 10-23 reference parameters ............................................. 5-9 relational operator ................................................. 4-1 reliability .............................................................. 10-22 remove() ................................................................. 9-13 rename() ................................................................. 9-13 resize() ...................................................................... 8-4 resolution ............................................................... 11-8 return ........................................................................ 2-2 return statement ..................................................... 5-7 returning stream objects references .................. 9-14 reusability ............................................................ 10-22 right to privacy ..................................................... 1-21 robots ...................................................................... 1-20 ROM ....................................................................... 1-13 Roman numerals .................................................... 1-2 root ........................................................................ 13-16 rounding double values ........................................ 7-5 roundoff error ....................................... 1-17, 4-2, 7-4 Run command ....................................................... A-3 running ..................................................................... 2-4 running a program ....................................... A-3, B-4 run-time error ....................................................... 3-19
P
parameter order ............................................. 5-4, 5-5 parameters ............................................................... 5-3 parents .................................................................. 13-16 Pascal ...................................................................... 1-18 Pascal, Blaise ........................................................... 1-3 Pascaline .................................................................. 1-3 PC ............................................................................ 1-11 pegclass.h ................................................................. 6-6 pen .......................................................................... 11-4 personal computers ............................................. 1-11 picture element ..................................................... 11-3 pixel .............................................................. 11-3, 11-8 Pointer notation .................................................. 13-15 pointers ........................................................ 9-15, 13-8 pop .......................................................................... 13-1 postcondition ........................................................ 5-13 precision ......................................................... 3-13, 7-4 precondition .......................................................... 5-13 Print command ............................................. A-4, B-4 printing a program ...................................... A-4, B-4 Privacy Act ............................................................ 1-21 private ........................................................ 10-2, 10-21 program ........................................................... 1-1, 1-4 program, entering ........................................ A-1, B-1 programming style ................................................ 2-8 project workspace ................................................. B-1 promotion ................................................................ 3-8 prototype ............................................................... 5-18 pseudocode ........................................................... 4-11 public ...................................................................... 10-2 punched card .......................................................... 1-4 push ........................................................................ 13-1 put pointer ............................................................. 9-15
S
Save command ............................................. A-1, B-2 saving a C++ program ................................ A-1, B-2 scientific notation ................................................... 3-6 searching .............................................................. 13-16 searching an array .................................................. 8-7 Second Generation computers ........................... 1-11 seekg() .................................................................... 9-15 seekp() .................................................................... 9-15 selection sort ......................................................... 12-1 selector ................................................................... 7-14 send to operator ..................................................... 2-2 sentinel ................................................................... 4-15 sequential access files .......................................... 9-14
Q
queue ............................................................ 13-4, 13-5 queue implementation ........................................ 13-7 queue type ............................................................. 13-5
I6
setf() ........................................................................ 3-13 sin() ......................................................................... 7-16 sizes ........................................................................ 11-8 skip a line of input ................................................. 9-8 social consequences ............................................. 1-20 software ....................................................... 1-12, 1-14 sorting .................................................................... 12-1 source code .............................................................. 2-4 spec ......................................................................... 3-15 special assignment operator ..................... 4-16, 4-18 specification .......................................................... 3-15 sqrt() ....................................................................... 7-16 stack .............................................................. 13-1, 13-2 stack implementation .......................................... 13-7 stack type ............................................................... 13-2 statements ................................................................ 2-2 stdio.h ..................................................................... 9-13 stdlib.h ............................................................ 4-19, 6-4 step .......................................................................... 4-13 Step Into command ............................................... B-6 Step Over command ............................................. A-5 Stepped Reckoner .................................................. 1-3 step-wise refinement ........................................... 5-18 Stop Debugging command .................................. B-6 stopping case, recursion ....................................... 7-6 stopwat.h ............................................................... 12-3 storing data ........................................................... 13-9 stream ............................................................... 2-2, 9-1 stream object parameters .................................... 9-11 string ......................................................... 2-2, 3-9, 8-9 string library ........................................................... 3-9 String type ............................................................... 3-9 struct ....................................................................... 8-18 struct constructor ....................................... 8-20, 10-4 struct parameters ................................................. 8-19 substr() ..................................................................... 6-3 summing ................................................................ 4-14 switch ..................................................................... 7-14 syntax error ............................................................. 2-4
top-down design .................................................. 5-18 toplist.h .................................................................. 6-10 Tower of Hanoi Puzzle ......................................... 6-8 Towers of Hanoi ..................................................... 7-8 transistor .................................................................. 1-9 trapezoid ................................................................ 7-16 trigonometric functions ......................................... 7-2 true .......................................................................... 4-18 Turbo C++ .............................................................. A-1 two-dimensional array ........................................ 8-14 type ........................................................................... 3-1 type casting ............................................................. 3-8 typedef ..................................................................... 8-8
U
Undefined symbol ................................................ 4-11 UNIVAC ........................................................ 1-8, 1-11 user-defined functions .......................................... 5-1 user-defined type ......................................... 6-1, 10-1 utility class ........................................................... 10-11
V
value parameters .................................................... 5-9 variable ..................................................................... 3-1 variable definitions ................................................ 3-7 vector ........................................................................ 8-1 vector Constructors ............................................... 8-6 vector index ........................................................... 8-11 vector member function ........................................ 8-4 vector parameters .................................................. 8-5 virus ........................................................................ 1-22 Visual C++, Microsoft .......................................... B-1 void ........................................................................... 5-1 von Leibniz, Gottfried Wilhelm .......................... 1-3 von Neumann, John ............................................... 1-8
T
tail ........................................................................... 13-8 telecommunications ............................................. 1-20 tellg() ....................................................................... 9-17 tellp() ...................................................................... 9-17 template ................................................................... 8-1 terminals ................................................................ 1-10 TernarySearch() .................................................. 12-19 testing ..................................................................... 3-15 testing for end of file ............................................. 9-3 text .......................................................................... 11-8 text files .................................................................... 9-4 text functions ........................................................ 11-7 Third Generation computers ............................. 1-11 three-dimensional arrays .................................... 8-26
W
warning .................................................................... 6-6 warning message .................................................... 2-4 watch window .............................................. 4-13, B-6 while ....................................................................... 4-12 whitespace ............................................................... 9-5 width() .................................................................... 3-12 window .................................................................. 1-17 word processor ....................................................... 9-4 words ...................................................................... 1-17 Wozniak, Stephen ................................................ 1-11
X
x2+1 ......................................................................... 7-16
Index
I7
I8
A GUIDE TO PROGRAMMING IN C++ emphasizes the development of good problem-solving and programming skills in a clear, easy-to-understand format, continuing the tradition of the Lawrenceville Press series of programming texts. To date, more than two million students have learned computing using a Lawrenceville Press text.
Features of A Guide to Programming in C++: I PROGRAMMING TECHNIQUES The object-oriented approach to programming is taught with an emphasis on good programming style. I C++ TOPICS Important topics such as functions, classes, and streams are covered in detail. Encapsulation, data-hiding, and inheritance are also discussed. I DEMONSTRATION PROGRAMS Every chapter includes many demonstration programs with runs that show the output produced by C++. I REVIEWS After a new concept is discussed, review problems are presented to provide immediate reinforcement. I CASE STUDIES By presenting complex problems and their solutions, students are taught the good programming methodology of specification, design, coding, and testing and debugging. I CHAPTER SUMMARY Each chapter ends with an outline of the important topics and statements covered as well as new vocabulary in the chapter. I EXERCISES Numerous exercise problems with a wide range of difficulty are provided at the end of each chapter. I GRAPHICS Chapter Eleven uses libraries, included with the Teachers Resource Package, to develop programs that produce graphics. I SEARCHING AND SORTING Chapter Twelve covers searching and sorting algorithms. I DYNAMIC DATA STRUCTURES Chapter Thirteen covers advanced data structures, including stacks, queues, trees, and linked lists. I LIBRARIES Included on diskette with the Teachers Resource Package are libraries for implementing arrays, graphics, strings, and many other classes.
ISBN 1-879233-90-8
~<(sl)r*=cd jae<
Softcover