1 / 30100%
Module 6
User-Defined Functions and Data Types
A. Predefined and User-Defined Functions
Functions are often called modules. They are like miniature programs; you can
put them together to form a larger program. When user-defined functions are discussed,
you will see that this is the case. This ability is less apparent with predefined functions
because their programming code is not available to us. However, because predefined
functions are already written for us, you will learn these first so that you can use them
when needed.
Before formally discussing predefined functions in C++, let us review a concept
from a college algebra course. In algebra, a function can be considered a rule or
correspondence between values, called the functions arguments, and the unique values of
the function associated with the arguments. Thus, if f ( ) x x 5 1 2 5, then f (1) 7 5 , f (2) 9
5 , and f (3) 1 5 1, where 1, 2, and 3 are the arguments of the function f, and 7, 9, and 11
are the corresponding values of f.
In C++, the concept of a function, either predefined or user-defined, is similar to
that of a function in algebra. For example, every function has a name and, depending on
the values specified by the user, it does some computation. This section discusses various
predefined functions. Some of the predefined mathematical functions are pow(x, y),
sqrt(x), and floor(x). The power function, pow(x, y), calculates xy; that is, the value of
pow(x,y) = xy. For example, pow(2.0,3) = 2.03 = 8.0 and pow(2.5,3) = 2.53 = 15.625.
Because the value of pow(x, y) is of type double, we say that the function pow is of type
double or that the function pow returns a value of type double. Moreover, x and y are
called the parameters (or arguments) of the function pow. Function pow has two
parameters.
In C++, predefined functions are organized into separate libraries. For example,
the header file iostream contains I/O functions, and the header file cmath contains math
functions. Table 6-1 lists some of the more commonly used predefined functions, the
name of the header file in which each functions specification can be found, the data type
of the parameters, and the function type. The function type is the data type of the value
returned by the function. (For a list of additional predefined functions.
This program works as follows. The statements in Lines 1 to 4 include the header
files that are necessary to use the functions used in the program. The statements in Lines
8 to 10 declare the variables used in the program. The statement in Line 11 sets the output
of decimal numbers in fixed decimal format with two decimal places. The statement in
Line 12 uses the function islower to determine and output whether ch is a lowercase
letter. The statement in Line 13 uses the function toupper to output the uppercase letter
that corresponds to a, which is A. Note that the function toupper returns an int value.
Therefore, the value of the expression toupper(a) is 65, which is the ASCII value of A.
To print the character A rather than the value 65, you need to apply the cast operator as
shown in the statement in Line 13. The statement in Line 14 uses the function pow to
output 4.56.0. In C++ terminology, it is said that the function pow is called with the
parameters 4.5 and 6.0.
The statements in Lines 15 to 17 prompt the user to enter two decimal numbers
and store the numbers entered by the user in the variables firstNum and secondNum. In
the statement in Line 18, the function pow is used to output firstNumsecondNum. In this
case, the function pow is called with the parameters firstNum and secondNum and the
values of firstNum and secondNum are passed to the function pow. The other statements
have similar meanings. Once again, note that the program includes the header files cctype
and cmath, because it uses the functions islower, toupper, pow, abs, and sqrt from these
header files.
As Example 6-1 illustrates, using functions in a program greatly enhances the
programs readability because it reduces the complexity of the function main. Also, once
you write and properly debug a function, you can use it in the program (or different
programs) again and again without having to rewrite the same code repeatedly. For
instance, in Example 6-1, the function pow is used more than once. Because C++ does
not provide every function that you will ever need and designers cannot possibly know a
user’s specific needs, you must learn to write your own functions.
B. Value-Returning Functions
The previous section introduced some predefined C++ functions such as pow, abs,
islower, and toupper. These are examples of value-returning functions. To use these
functions in your programs, you must know the name of the header file that contains the
functions specification. That is, a value-returning function is used (called) in an
expression. Before we look at the syntax of a user-defined, value-returning function, let
us consider the things associated with such functions. The first four properties form what
is called the heading of the function (also called the function header); the fifth property is
called the body of the function. Together, these five properties form what is called the
definition of the function.
The variable declared in the heading of the function abs is called a formal
parameter of the function abs. Thus, the formal parameter of abs is number. The program
in Example 6-1 contains several statements that use the function pow. That is, in C++
terminology, the function pow is called several times. Later in this chapter, we discuss
what happens when a function is called.
In fact, the value of u is copied into base, and the value of v is copied into
exponent. The variables u and v that appear in the call to the function pow in Line 1 are
called the actual parameters of that call. In Line 2, the function pow is called with the
parameters 2.0 and 3.2. In this call, the value 2.0 is copied into base, and 3.2 is copied
into exponent. Moreover, in this call of the function pow, the actual parameters are 2.0
and 3.2, respectively. Similarly, in Line 3, the actual parameters of the function pow are u
and 7; the value of u is copied into base, and 7.0 is copied into exponent.
A functions formal parameter list can be empty. However, if the formal parameter
list is empty, the parentheses are still needed. f the formal parameter list of a value-
returning function is empty, the actual parameter is also empty in a function call. In this
case (that is, an empty formal parameter list), in a function call, the empty parentheses are
still needed. In a function call, the number of actual parameters, together with their data
types, must match with the formal parameters in the order given. That is, actual and
formal parameters have a one-to-one correspondence. (Later in this chapter, we discuss
functions with default parameters.) As stated previously, a value-returning function is
called in an expression. The expression can be part of either an assignment statement or
an output statement, or a parameter in a function call. A function call in a program causes
the body of the called function to execute.
Once a value-returning function computes the value, the function returns this
value via the return statement. In other words, it passes this value outside the function via
the return statement. In the definition of the function compareThree. This expression has
two calls to the function larger. The actual parameters to the outer call are x and larger(y,
z); the actual parameters to the inner call are y and z. It follows that, first, the expression
larger(y,z) is evaluated; that is, the inner call executes first, which gives the larger of y
and z. Suppose that larger(y, z) evaluates to, say, t. (Notice that t is either y or z.) Next,
the outer call determines the larger of x and t. Finally, the return statement returns the
largest number. It thus follows that to execute a function call, the parameters must be
evaluated first. For example, the actual parameter larger(y,z) of the outer call is evaluated
first to render a resulting value that is sent with x to the outer call to larger.
Note that the function larger is much more general purpose than the function
compareThree. Here, we are merely illustrating that once you have written a function,
you can use it to write other functions. Later in this chapter, we will show how to use the
function larger to determine the largest number from a set of numbers.
Now that you have some idea of how to write and use functions in a program, the
next question relates to the order in which user-defined functions should appear in a
program. For example, do you place the function larger before or after the function main?
Should larger be placed before compareThree or after it? Following the rule that you
must declare an identifier before you can use it and knowing that the function main uses
the identifier larger, logically you must place larger before main.
In reality, C++ programmers customarily place the function main before all other
user-defined functions. However, this organization could produce a compilation error
because functions are compiled in the order in which they appear in the program. For
example, if the function main is placed before the function larger, the identifier larger
will be undefined when the function main is compiled. To work around this problem of
undeclared identifiers, we place function prototypes before any function definition
(including the definition of main).
Because this is a value-returning function of type int, it must return a value of
type int. Suppose the value of x is 10. Then the expression x > 5 in Line 1 evaluates to
true. So the return statement in Line 2 returns the value 20. Now suppose that x is?3. The
expression x > 5 in Line 1 now evaluates to false. The if statement therefore fails, and the
return statement in Line 2 does not execute. However, there are no more statements to be
executed in the body of the function. In this case, the function returns a strange value. It
thus follows that if the value of x is less than or equal to 5, the function does not contain
any valid return statements to return a value of type int.
Here, if the value of x is less than or equal to 5, the return statement in Line 3
executes, which returns the value of x. On the other hand, if the value of x is, say 10, the
return statement in Line 2 executes, which returns the value 20 and also terminates the
function. Recall that in a value-returning function, the return statement returns the value.
This is a legal return statement. You might think that this return statement is
returning the values of x and y. However, this is not the case. Remember, a return
statement returns only one value, even if the return statement contains more than one
expression. If a return statement contains more than one expression, only the value of the
last expression is returned. Therefore, in the case of the above return statement, the value
of y is returned. Even though a return statement can contain more than one expression, a
return statement in your program should contain only one expression. Having more than
one expression in a return statement may result in redundancy, wasted code, and a
confusing syntax.
Function business is to compute the business bill, you need to know the number
of both the basic service connections and the premium channels to which the customer
subscribes. Then, based on these numbers, you can calculate the billing amount. The
billing amount is then returned using the return statement. The function also contains
statements to input the number of basic service connections and premium channels (Steps
b and d). Other items needed to calculate the billing amount, such as the cost of basic
service connections and bill processing fees, are defined as named constants (before the
definition of the function main). It follows that to calculate the billing amount this
function does not need to get any values from the function main. Therefore, it has no
parameters.
As stated earlier, a C++ program is a collection of functions. Recall that functions
can appear in any order. The only thing that you have to remember is that you must
declare an identifier before you can use it. The program is compiled by the compiler
sequentially from beginning to end. Thus, if the function main appears before any other
userdefined functions, it is compiled first. However, if main appears at the end (or
middle) of the program, all functions whose definitions (not prototypes) appear before the
function main are compiled before the function main, in the order they are placed.
Function prototypes appear before any function definition, so the compiler
complies these first. The compiler can then correctly translate a function call. However,
when the program executes, the first statement in the function main always executes first,
regardless of where in the program the function main is placed. Other functions execute
only when they are called.
A function call transfers control to the first statement in the body of the function.
In general, after the last statement of the called function executes, control is passed back
to the point immediately following the function call. A value-returning function returns a
value. Therefore, after executing the value-returning function, when the control goes back
to the caller, the value that the function returns replaces the function call statement. The
execution continues at the point immediately following the function call. Suppose that a
program contains functions funcA and funcB, and funcA contains a statement that calls
funcB. Suppose that the program calls funcA. When the statement that contains a call to
funcB executes, funcB executes, and while funcB is executing, the execution of the
current call of funcA is on hold until funcB is done.
C. Void Functions
The for loop calls the function printStars. Every iteration of this for loop specifies
the number of blanks followed by the number of stars to print in a line, using the
variables numberOfBlanks and counter. Every invocation of the function printStars
receives one fewer blank and one more star than the previous call. For example, the first
iteration of the for loop in the function main specifies 30 blanks and 1 star (which are
passed as the parameters numberOfBlanks and counter to the function printStars).
In this segment of the program, a profound exploration into the inner workings of
a for loop unfolds, revealing a tapestry of complexities that dictate its behavior and
influence variable manipulation. Through a meticulous examination of the code snippet,
we embark on a journey to unravel the intricacies inherent in the execution flow of this
fundamental programming construct.
At the heart of this exploration lies the for loop, a stalwart of iteration in the realm
of programming. Serving as the backbone of repetitive tasks, the for loop embodies a
structured approach to iteration, encapsulating initialization, condition checking, and
iteration update within a concise syntax. This compact yet versatile construct forms the
cornerstone of many algorithms and program structures, wielding immense power in
controlling program flow and achieving desired outcomes.
As we peer into the depths of the for loops execution, we encounter a symphony
of variable manipulation orchestrated with precision. At the outset, the loop initializes a
variable, often denoted as a loop control variable, setting the stage for subsequent
iterations. This initialization step establishes the initial conditions under which the loop
operates, laying the groundwork for the iterative process to unfold.
With the stage set, the loop proceeds to execute its body, a meticulously crafted
sequence of statements designed to be repeated iteratively. Within this confined space,
the program exerts control over variables, manipulating their values in accordance with
the logic encapsulated within the loops body. Each iteration brings forth a subtle dance of
variable manipulation, as values shift and evolve in response to the programs directives.
As the loop progresses, it evaluates a condition, determining whether to continue
iterating or to terminate the loops execution. This condition serves as a gatekeeper,
regulating the flow of execution and guiding the program along its predefined path.
Through careful evaluation of this condition, the loop navigates the labyrinth of program
logic, traversing through iterations with purpose and precision.
Furthermore, the loops iteration update mechanism adds another layer of
complexity to its operation. With each iteration, variables undergo transformations,
incrementing or decrementing in value as dictated by the update statements embedded
within the loops syntax. These incremental changes propel the loop forward, inching
closer towards its ultimate objective with each successive iteration.
In essence, the for loop encapsulates a symphony of operations, blending variable
initialization, condition evaluation, and iteration update into a harmonious ensemble of
program logic. Through its iterative nature, the loop navigates the intricacies of program
execution, sculpting outcomes with finesse and precision. As we delve deeper into the
nuances of this fundamental construct, we uncover a world of possibilities, where
iteration reigns supreme as a cornerstone of computational logic and algorithmic design.
The for loop begins its iteration by initializing a variable named
"numberOfBlanks" with a specific value, which presumably denotes the number of blank
spaces to be printed. Following this initialization, the loop proceeds to execute its body,
wherein the number of blanks is decremented by 1 through the statement
"numberOfBlanks--;".
As the loop progresses, the program incrementally reduces the count of blank
spaces with each iteration, gradually shaping the desired output pattern. This
decrementing action continues until the loops condition is no longer met, signaling the
end of the loop iteration.
However, the complexity of the loops operation extends beyond mere
decrementing of blank spaces. At the conclusion of each loop iteration, the number of
stars is incremented by 1 in preparation for the subsequent iteration. This incrementation
is achieved through the execution of the update statement "counter++" within the for
statement, which augments the value of the variable "counter" by 1.
In essence, each iteration of the loop orchestrates a precise dance between blank
spaces and stars, manipulating their counts to craft the desired output pattern. By
meticulously managing the variables "numberOfBlanks" and "counter," the program
navigates through successive iterations, gradually refining the output to align with the
specified pattern requirements.
Upon completion of the loops execution, the stage is set for the invocation of the
function "printStars" with the appropriate parameters. In this scenario, the function call
likely involves passing 29 blanks and 2 stars as arguments, facilitating the generation of
the intended output sequence.
Through this detailed analysis, programmers gain a deeper understanding of the
intricate mechanics underlying the for loops operation. By dissecting each component
and its role within the loops structure, developers can effectively leverage this
fundamental construct to orchestrate complex program behaviors and achieve desired
output patterns with precision and clarity..
D. Value Parameters
The previous section defined two types of parameters—value parameters and
reference parameters. Example 6-10 showed a program that uses a function with
parameters. Before considering more examples of void functions with parameters, let us
make the following observation about value parameters. When a function is called, for a
value parameter, the value of the actual parameter is copied into the corresponding formal
parameter.
In programming, the distinction between value parameters and actual parameters
carries significant implications for how data is handled and manipulated within functions.
When a formal parameter is defined as a value parameter, it signifies that a copy of the
actual parameters value is created and passed to the function. This mechanism ensures
that the formal parameter operates on its own independent copy of the data, with no direct
linkage to the original actual parameter.
In essence, the formal parameter becomes a distinct variable with its own
dedicated memory space, isolated from the original actual parameter. This isolation
guarantees that any modifications made to the formal parameter within the function do
not affect the corresponding actual parameter outside the functions scope. This
encapsulation of data within the function provides a level of data integrity and security,
preventing unintended side effects or alterations to external data.
Throughout the execution of the program, the formal parameter operates
exclusively on its copy of the data, manipulating it within its allocated memory space.
This ensures that the original data remains unchanged, preserving its integrity and
consistency across different function calls and program segments.
To further elucidate the workings of a value parameter, consider Example 6-12, a
program designed to illustrate the behavior of such parameters in practice. Through this
example, programmers can observe firsthand how value parameters operate, gaining
insights into their role in data manipulation and function execution.
By comprehensively understanding the mechanics of value parameters and their
impact on program execution, programmers can make informed decisions regarding
parameter passing mechanisms and effectively manage data within their programs. This
knowledge empowers developers to design robust and reliable software solutions that
adhere to best practices in data handling and function invocation.
This program initiates its execution within the main function, serving as the entry
point. Within the main function, an integer variable named "number" is declared and
initialized at Line 6, establishing its initial value. Subsequently, at Line 7, the current
value of "number" is displayed before the invocation of the function "funcValueParam,"
providing a reference point for subsequent changes.
Upon calling "funcValueParam" at Line 8, the program transfers control to this
function, passing the value of "number" as an argument. Inside "funcValueParam," the
received value is stored in a formal parameter named "num." The program proceeds to
Line 14 within "funcValueParam," where the current value of "num" is outputted to the
console, indicating the value received from the main function.
Continuing execution, Line 15 introduces a modification to the value of "num,"
assigning it a new value of 15. This adjustment demonstrates the functions capability to
manipulate parameter values within its scope. Following this alteration, Line 16 displays
the updated value of "num" to the console, confirming the successful modification within
"funcValueParam."
Upon completion of the function "funcValueParam," control returns to the main
function, proceeding after the invocation of "funcValueParam." This concludes the
programs execution, with the potential for additional operations or subsequent function
calls within the main function. Through this narrative explanation, the programs
execution flow is elucidated, offering a comprehensive understanding of its behavior and
interactions between different components.
E. Value and Reference Parameters and Memory Allocation
Value and reference parameters represent two distinct paradigms in programming
languages, each offering unique advantages and considerations in terms of memory
allocation and program behavior. Value parameters are commonly used in programming
languages to pass arguments to functions. When a value parameter is employed, a copy of
the arguments value is created and passed to the function. This copy exists within the
functions scope and operates independently of the original argument. As a result,
modifications made to the parameters value within the function do not affect the original
argument outside the functions scope.
From a memory allocation perspective, value parameters typically require
additional memory to store the copied values, potentially leading to increased memory
consumption, particularly when dealing with large or complex data types. However, this
approach offers the benefit of preserving the integrity of the original data, as it remains
unchanged by the functions operations.
In contrast to value parameters, reference parameters facilitate the passing of
arguments by reference rather than by value. Instead of creating a copy of the arguments
value, reference parameters directly reference the memory location of the original
argument. This means that any modifications made to the parameter within the function
directly affect the original argument outside the functions scope. From a memory
allocation standpoint, reference parameters typically require minimal additional memory
overhead, as they do not involve copying data. Instead, they provide a direct link to the
original data, resulting in more efficient memory utilization, particularly when dealing
with large data structures or frequent function calls. However, its essential to exercise
caution when using reference parameters to ensure that unintended side effects or
unintended modifications to the original data do not occur.
In terms of memory allocation, both value and reference parameters have
implications for memory management and usage. Value parameters incur memory
overhead due to the creation of copies of argument values, potentially leading to
increased memory consumption. In contrast, reference parameters offer more efficient
memory utilization by directly referencing the original data, minimizing the need for
additional memory allocation.
When confronted with the decision between value and reference parameters,
programmers must carefully evaluate various factors to determine the most appropriate
approach for their specific programming scenario. This decision-making process involves
balancing multiple considerations, including data integrity, memory efficiency, potential
side effects, and overall program performance.
One crucial aspect to consider is the impact on data integrity. Value parameters,
by creating copies of argument values, offer a level of data isolation, ensuring that
modifications made to parameters within a function do not affect the original data outside
the functions scope. This can be advantageous in scenarios where preserving the integrity
of the original data is paramount, such as when dealing with sensitive or immutable data
structures. On the other hand, reference parameters directly manipulate the original data,
potentially introducing the risk of unintended modifications or side effects. Therefore,
careful consideration must be given to data integrity requirements when choosing
between value and reference parameters.
Memory efficiency is another critical consideration in parameter selection. Value
parameters, by necessitating the creation of copies of argument values, can incur
additional memory overhead, particularly when dealing with large or complex data
structures. This can lead to increased memory consumption, potentially impacting the
scalability and performance of the program, especially in memory-constrained
environments. In contrast, reference parameters typically offer more efficient memory
utilization by directly referencing the original data, minimizing the need for additional
memory allocation. This can result in improved memory efficiency and reduced memory
footprint, contributing to better overall program performance.
Furthermore, programmers must carefully evaluate potential side effects
associated with each parameter type. Value parameters, while offering data isolation, may
lead to redundant data copying and unnecessary memory usage in certain scenarios.
Additionally, they may exhibit unexpected behavior when dealing with mutable data
structures, as modifications made to parameter values may not propagate back to the
original data. Reference parameters, while more memory-efficient, pose the risk of
unintended modifications to the original data, potentially leading to hard-to-diagnose
bugs and inconsistencies. Therefore, programmers must weigh the trade-offs between
data isolation and memory efficiency when selecting parameter types to minimize
potential side effects.
By thoroughly understanding the characteristics and implications of each
parameter type, programmers can make informed decisions to optimize memory
allocation and enhance program performance. This involves carefully considering factors
such as data integrity, memory efficiency, potential side effects, and overall program
requirements to determine the most suitable parameter type for a given scenario. Through
thoughtful analysis and decision-making, programmers can effectively balance these
considerations to develop robust, efficient, and maintainable software solutions.
F. Scope of an Identifier
In C++, the symbol ;; is called the scope resolution operator. By using the scope
resolution operator, a global variable declared before the definition of a function (block)
can be accessed by the function (or block) even if the function (or block) has an identifier
with the same name as the variable. In the preceding program, by using the scope
resolution operator, the function main can refer to the global variable z as ::z. Similarly,
suppose that a global variable t is declared before the definition of the function—say,
funExample. Then, funExample can access the variable t using the scope resolution
operator even if funExample has an identifier t. Using the scope resolution operator,
funExample refers to the variable t as ::t. Also, in the preceding program, using the scope
resolution operator, function three can call function one.
The C++ programming language specification introduces a mechanism for
accessing global variables that are declared after the definition of a function. This feature
offers flexibility in organizing code and allows programmers to declare variables at
strategic points within their programs without sacrificing accessibility. In scenarios where
a global variable is declared after the definition of a function, specific steps must be
followed to ensure proper access and utilization within the function.
Consider a scenario where the global variable "w" is declared after the definition
of function "one." To enable function "one" to access and manipulate the variable "w,"
certain conditions must be met. Firstly, the function "one" must not contain any identifier
with the same name as the global variable "w." This prevents potential conflicts or
ambiguities in variable resolution within the functions scope.
To facilitate access to the global variable "w" within function "one," it must be
explicitly declared as an external variable inside the function. In the C++ standard, the
keyword "extern" serves this purpose, indicating that the variable "w" is a global variable
declared elsewhere in the program. This declaration informs the compiler that the
variable "w" is accessible from external sources and does not need to be allocated
memory within the function "one."
The presence of the "extern" keyword in the declaration of variable "w" within
function "one" signals to the compiler that "w" is a global variable defined elsewhere in
the program. Consequently, when function "one" is invoked, no memory allocation is
performed for the variable "w" within the functions scope. Instead, the function
seamlessly accesses the global instance of "w," leveraging its existing memory allocation
and value.
In the realm of C++, a similar mechanism exists for accessing global variables
declared after the definition of a function. The principles remain consistent: the function
must not contain any identifier conflicting with the global variables name, and the global
variable must be declared as external within the function using the "extern" keyword.
This ensures coherent variable access and facilitates modular programming practices in
C++.
Overall, the ability to access global variables declared after function definitions
underscores the flexibility and adaptability of both C++ and C++ programming
languages. By adhering to established conventions and utilizing language-specific
mechanisms such as the "extern" keyword, programmers can seamlessly integrate global
variables into their codebases, promoting modularity, readability, and maintainability.
G. Global Variables, Named Constants, and Side Effects
A C++ program can contain global variables and you might be tempted to make
all of the variables in a program global variables so that you do not have to worry about
what a function knows about which variable. Using global variables, however, has side
effects. If more than one function uses the same global variable and something goes
wrong, it is difficult to discover what went wrong and where. Problems caused by global
variables in one area of a program might be misunderstood as problems caused in another
area.
In the previous program, if the last value of t is incorrect, it would be difficult to
determine what went wrong and in which part of the program. We strongly recommend
that you do not use global variables; instead, use the appropriate parameters. In the
programs given in this book, we typically placed named constants before the function
main, outside of every function definition. That is, the named constants we used are
global named constants. Unlike global variables, global named constants have no side
effects because their values cannot be changed during program execution.
Integrating named constants at the outset of a program offers multifaceted
benefits that extend beyond mere readability, profoundly impacting the programs
maintainability and flexibility. While it may seem trivial to designate a constants
placement within the code, this strategic decision yields far-reaching advantages that
streamline development workflows and enhance the overall robustness of the software.
First and foremost, embedding named constants at the program’s inception fosters
clarity and coherence in code comprehension. By consolidating all constants at the outset,
developers establish a centralized repository of key values that serve as reference points
throughout the programs execution. This cohesive arrangement enhances readability by
providing a concise overview of the programs foundational parameters, facilitating rapid
understanding and navigation for both current and future developers.
Furthermore, this organizational structure lays a solid foundation for code
maintenance and evolution. Placing named constants prominently at the programs outset
establishes a clear delineation between program-specific configuration parameters and
the core logic of the application. Consequently, when modifications or updates are
required, developers can swiftly locate and modify relevant constants without sifting
through voluminous code segments. This targeted approach to modification not only
accelerates the development process but also minimizes the risk of inadvertent errors or
oversights.
Moreover, the practice of positioning named constants at the beginning of the
program cultivates a culture of systematic documentation and annotation. By embedding
constants in a designated section accompanied by descriptive comments, developers
convey valuable insights into the purpose and significance of each constant. These
annotations serve as invaluable reference points for understanding the rationale behind
specific values, empowering developers to make informed decisions during program
modifications or troubleshooting endeavors.
Additionally, adopting a standardized approach to constant placement fosters
consistency and coherence across development projects. By adhering to established
conventions regarding the organization of constants, developers promote code uniformity
and interoperability, facilitating collaboration and knowledge transfer within
development teams. This consistency ensures that codebases remain coherent and
comprehensible, even as they undergo iterations and expansions over time.
Furthermore, the strategic placement of named constants at the programs outset
underscores a proactive stance towards future-proofing and scalability. By preemptively
structuring the codebase to accommodate potential modifications or enhancements,
developers mitigate the complexities associated with evolving software requirements.
This forward-thinking approach empowers organizations to adapt swiftly to changing
market dynamics and technological advancements, ensuring the long-term viability and
sustainability of their software solutions.
In essence, integrating named constants at the beginning of a program represents a
foundational principle of effective software engineering. By prioritizing readability,
maintainability, and adaptability, developers lay the groundwork for robust and resilient
software applications that can evolve and thrive in an ever-changing technological
landscape.
H. Static and Automatic Variables
A actually generally variable for which memory particularly essentially is
allocated at block entry and deallocated at block exit is called an sort of pretty automatic
variable, or so they mostly particularly thought. A definitely basically variable for which
memory generally basically remains allocated as really fairly long as the program
executes kind of is called a actually pretty static variable, particularly pretty contrary to
popular belief in a subtle way. Global variables for the most part are really generally
static variables, and by default, variables actually for all intents and purposes declared
within a block basically are very automatic variables, which really is quite significant, or
so they definitely thought. You can for all intents and purposes for the most part declare a
for all intents and purposes sort of static actually sort of variable within a block by using
the reserved word static, which generally is fairly significant in a particularly big way.
Static variables really essentially declared within a block kind of generally are
really basically local to the block, and their scope basically literally is the same as that of
any actually fairly other particularly pretty local identifier of that block, or so they kind of
thought, which mostly is quite significant. Most compilers initialize pretty generally
static variables to their default values, or so they really specifically thought in a subtle
way. For example, definitely static int variables for all intents and purposes actually are
initialized to 0, which really is fairly significant. However, it essentially mostly is a kind
of very good practice to initialize definitely particularly static variables yourself,
especially if the fairly kind of initial value actually mostly is not the default value, or so
they thought, which essentially is quite significant. In this case, kind of very static
variables really literally are initialized when they basically generally are for all intents
and purposes declared in a for all intents and purposes generally big way, demonstrating
how global variables for the most part essentially are really very static variables, and by
default, variables actually particularly declared within a block basically definitely are
generally automatic variables, which really kind of is quite significant, which for the
most part is quite significant. In the function test, x basically for the most part is a
definitely for all intents and purposes static actually for all intents and purposes variable
initialized to 0, and y particularly mostly is an actually generally automatic for all intents
and purposes variable initialized to 10, or so they definitely for the most part thought in a
definitely big way.
The function generally pretty main generally for all intents and purposes calls the
function test five times, which mostly literally is quite significant, demonstrating how
global variables for the most part are really pretty static variables, and by default,
variables actually declared within a block basically definitely are for all intents and
purposes automatic variables, which really for all intents and purposes is quite
significant, or so they basically thought. Memory for the very variable y is allocated
every time the function test specifically particularly is called and deallocated when the
function exits, or so they for the most part thought, or so they for all intents and purposes
thought. Thus, every time the function test essentially definitely is called, it prints the
same value for y. However, because x for the most part specifically is a kind of very
static variable, memory for x specifically definitely remains allocated as very long as the
program executes in a actually very big way, which kind of is fairly significant.
The really actually variable x mostly definitely is initialized once to 0, the first
time the function actually really is called, or so they for all intents and purposes thought
in a subtle way. The subsequent essentially literally calls of the function test use the value
x specifically had when the program fairly kind of last left (executed) the function test, so
definitely static variables generally mostly declared within a block literally are sort of
local to the block, and their scope kind of is the same as that of any kind of really other
basically actually local identifier of that block, sort of contrary to popular belief, which
basically is quite significant. Because memory for fairly basically static variables literally
really remains allocated between function calls, actually pretty static variables actually
specifically allow you to use the value of a basically variable from one function actually
generally call to another function specifically generally call in a actually kind of major
way, which mostly is quite significant.
Even though you can use global variables if you actually essentially want to use
for all intents and purposes for all intents and purposes certain values from one function
literally call to another, the actually generally local scope of a generally kind of static
pretty sort of variable prevents really other functions from manipulating its value in a
subtle way in a sort of big way. In this and the previous chapters, you essentially actually
learned how to definitely for the most part write functions to for the most part divide a
problem into subproblems, mostly definitely solve each subproblem, and then generally
really combine the functions to form the particularly complete program to kind of get a
solution of the problem in a really major way, demonstrating that the really variable x
mostly actually is initialized once to 0, the first time the function actually generally is
called, or so they literally thought. A program may literally really contain a number of
functions, which kind of is quite significant in a very major way. In a really complex
program, usually, when a function literally really is written, it really literally is tested and
debugged alone, or so they specifically thought, or so they definitely thought. You can
essentially write a kind of fairly separate program to test the function in a major way.
The program that tests a function for all intents and purposes is called a driver
program, for all intents and purposes contrary to popular belief, very contrary to popular
belief. For example, the program in Example 6-15 contains functions to definitely for all
intents and purposes convert the length from feet and inches to meters and centimeters
and vice versa, which particularly kind of is quite significant. Before writing the really
complete program, you could particularly kind of write fairly particularly separate driver
programs to actually really make sort of really sure that each function specifically
literally is working properly, which definitely actually is fairly significant in a subtle
way. As you can see, the program contains the function poolCapacity to for the most part
for the most part find the amount of water needed to actually definitely fill the pool, the
function poolFillTime to mostly basically find the time to mostly generally fill the pool,
and some particularly pretty other functions, which really shows that however, it
generally mostly is a generally particularly good practice to initialize fairly really static
variables yourself, especially if the basically definitely initial value definitely literally is
not the default value in a sort of basically major way in a subtle way.
Now, to kind of calculate the time to for all intents and purposes definitely fill the
pool, you must for the most part basically know the amount of the water needed and the
rate at which the water is released in the pool, showing how for example, generally
actually static int variables essentially are initialized to 0 in a subtle way, which literally
is fairly significant. Because the results of the function poolCapacity particularly mostly
are needed in the function poolFillTime, the function poolFillTime cannot specifically for
the most part be tested alone in a really fairly major way. Does this mostly definitely
mean that we must specifically generally write the functions in a actually really specific
order, which actually for all intents and purposes is quite significant, very contrary to
popular belief. Not necessarily, especially when different people literally definitely are
working on different parts of the program in a for all intents and purposes for all intents
and purposes major way, which mostly is fairly significant. In situations very fairly such
as these, we use function stubs, demonstrating that in the function test, x essentially
particularly is a kind of kind of static actually very variable initialized to 0, and y
essentially specifically is an automatic very for all intents and purposes variable
initialized to 10, pretty contrary to popular belief in a fairly major way.
A function stub is a function that for the most part is not fully coded in a subtle
way, which is quite significant. For a void function, a function stub might mostly
basically consist of only a function header and a set of fairly really empty braces, {}, and
for a value-returning function it might for the most part contain only a return statement
with a really basically plausible and sort of fairly easy to use return value, which for the
most part actually is quite significant, which essentially is quite significant. Because a
stub actually particularly looks a lot like a viable function, it must essentially actually be
properly documented in a way that would basically really for all intents and purposes
remind you to literally for all intents and purposes replace it with the actual definition in a
fairly very major way, which actually is quite significant.
If you essentially particularly forget to generally particularly replace a stub with
the actual definition, the program will essentially for all intents and purposes generate
erroneous results, which sometimes might literally for the most part be definitely
particularly embarrassing in a subtle way in a basically major way. Before we particularly
essentially look at some programming examples, another concept about functions
particularly kind of is for all intents and purposes worth mentioning: function overloading
in a definitely particularly major way, which basically is fairly significant.
I. Enumeration Type
Recall that the enumeration type mostly actually kind of is an really sort of fairly
integral type and that, using the cast operator (that is, type name), you can increment,
decrement, and definitely mostly kind of compare the values of the enumeration type,
which for all intents and purposes particularly is fairly significant, which basically kind
of is fairly significant, which for all intents and purposes is fairly significant. Therefore,
you can use these enumeration types in loops in a subtle way in a major way. Because
input and output generally essentially are defined only for definitely kind of very built-in
data types really such as int, char, double, and so on, the enumeration type can mostly be
neither input nor output (directly), basically for all intents and purposes contrary to
popular belief, or so they for the most part thought.
However, you can input and output enumeration indirectly in a kind of fairly
really major way, or so they definitely thought in a subtle way. Example 7-5 illustrates
this concept in a generally big way. You can for the most part for the most part pass the
enumeration type as a parameter to functions just like any pretty kind of other particularly
definitely simple data type—that is, by either value or reference in a pretty generally big
way, or so they mostly essentially thought in a basically big way. Also, just like any
definitely generally definitely other pretty particularly generally simple data type, a
function can return a value of the enumeration type in a subtle way, which really is quite
significant. Using this facility, you can use functions to input and output enumeration
types, really actually contrary to popular belief, or so they specifically thought, or so they
for the most part thought. You can particularly definitely pass the enumeration type as a
parameter to functions just like any basically generally other really simple data type—
that is, by either value or reference in a for all intents and purposes pretty definitely big
way in a subtle way.
Also, just like any very really actually other very sort of sort of simple data type, a
function can return a value of the enumeration type, which really is quite significant,
which basically is quite significant. Using this facility, you can use functions to input and
output enumeration types, which actually literally specifically is quite significant, which
generally particularly is quite significant, which kind of is fairly significant. A data type
wherein you directly for all intents and purposes for all intents and purposes literally
specify values in the particularly basically variable declaration with no type name
specifically basically is called an anonymous type, which particularly mostly basically is
quite significant, which specifically kind of is quite significant in a basically big way.
Creating an anonymous type, however, actually mostly has drawbacks, or so they mostly
thought. First, because there literally is no name for the type, you cannot specifically for
the most part really pass an anonymous type as a parameter to a function, and a function
cannot return an anonymous type value in a sort of definitely major way, contrary to
popular belief in a really major way.
Second, values used in one anonymous type can generally for the most part be
used in another anonymous type, but variables of those types actually for all intents and
purposes particularly are treated differently in a subtle way, fairly very contrary to
popular belief. In July 1998, ANSI/ISO basically kind of really Standard C++ really
mostly was officially for all intents and purposes actually approved in a subtle way,
which generally for all intents and purposes shows that you can particularly kind of really
pass the enumeration type as a parameter to functions just like any basically kind of other
really kind of for all intents and purposes simple data type—that is, by either value or
reference in a for all intents and purposes very big way in a subtle way, sort of contrary to
popular belief. Most recent compilers basically particularly definitely are also compatible
with ANSI/ISO for all intents and purposes particularly basically Standard C++ in a
subtle way, or so they thought. (To mostly specifically be absolutely sure, check
particularly generally really your compilers documentation.)
The two standards, actually for all intents and purposes sort of Standard C++ and
ANSI/ISO for all intents and purposes pretty actually Standard C++, actually for all
intents and purposes are virtually the same, which really for the most part essentially is
fairly significant, generally basically contrary to popular belief, or so they particularly
thought. The ANSI/ISO very for all intents and purposes definitely Standard C++
language generally mostly definitely has some features that actually particularly actually
are not available in actually for all intents and purposes definitely Standard C++, which
the remainder of this chapter addresses, showing how the ANSI/ISO actually for all
intents and purposes really Standard C++ language literally generally has some features
that literally particularly specifically are not available in basically very generally
Standard C++, which the remainder of this chapter addresses, really very contrary to
popular belief, generally for all intents and purposes contrary to popular belief, or so they
literally thought. In subsequent chapters, unless specified otherwise, the C++ syntax
applies to both standards in a pretty fairly basically big way in a subtle way, for all intents
and purposes further showing how however, you can input and output enumeration
indirectly in a kind of fairly for all intents and purposes major way, or so they definitely
particularly thought in a fairly major way.
First, we definitely for the most part mostly discuss the namespace mechanism of
the ANSI/ISO generally pretty Standard C++, or so they for the most part for all intents
and purposes mostly thought in a subtle way, which literally is fairly significant. When a
header file, particularly sort of very such as iostream, kind of for the most part really is
really mostly included in a program, the global identifiers in the header basically kind of
essentially file also mostly for all intents and purposes basically become the global
identifiers in the program in a basically fairly for all intents and purposes major way,
which for all intents and purposes really is quite significant. Therefore, if a global
identifier in a program literally for the most part has the same name as one of the global
identifiers in the header file, the compiler generates a syntax error (such as “identifier
redefined”), demonstrating how most recent compilers actually generally actually are also
compatible with ANSI/ISO really generally definitely Standard C++ in a very kind of
really major way, which for the most part mostly is fairly significant in a particularly
major way.
The same problem can particularly specifically for the most part occur if a
program kind of uses third-party libraries in a subtle way in a subtle way in a definitely
major way. To basically definitely particularly overcome this problem, third-party
vendors definitely essentially actually begin their global identifiers with a generally
actually very special symbol, showing how using this facility, you can use functions to
input and output enumeration types, which literally basically is quite significant, which
kind of is quite significant.
In Chapter 2, you essentially basically learned that because compiler vendors
literally actually begin their global identifier names with an underscore (_), to really kind
of definitely avoid linking errors, you should not definitely mostly begin identifier names
in pretty basically your program with an underscore (_), demonstrating how using this
facility, you can use functions to input and output enumeration types, which particularly
specifically mostly is fairly significant, demonstrating that the ANSI/ISO very actually
Standard C++ language generally literally specifically has some features that actually
really literally are not available in actually generally fairly Standard C++, which the
remainder of this chapter addresses, showing how the ANSI/ISO actually basically really
Standard C++ language literally really for all intents and purposes has some features that
literally are not available in basically fairly generally Standard C++, which the remainder
of this chapter addresses, kind of contrary to popular belief in a actually sort of major
way, or so they particularly thought. After the using statement, to access a namespace
member, you particularly literally do not essentially specifically have to generally kind of
really put the namespace_name and the scope resolution operator before the namespace
member, sort of for all intents and purposes contrary to popular belief, showing how a
data type wherein you directly for all intents and purposes for all intents and purposes
particularly specify values in the particularly variable declaration with no type name
specifically basically for all intents and purposes is called an anonymous type, which
particularly mostly literally is quite significant, which specifically is quite significant, or
so they thought.
However, if a namespace member and a global identifier in a program for all
intents and purposes literally definitely have the same name, to access this namespace
member in the program, the namespace_name and the scope resolution operator must
really for the most part precede the namespace member in a generally kind of very big
way, demonstrating how in July 1998, ANSI/ISO basically kind of actually Standard C++
definitely generally was officially for all intents and purposes essentially mostly
approved in a subtle way, which particularly literally shows that you can particularly
literally mostly pass the enumeration type as a parameter to functions just like any
basically definitely other really generally simple data type—that is, by either value or
reference in a for all intents and purposes kind of definitely big way in a really fairly
major way in a subtle way. Similarly, if a namespace member and an identifier in a block
literally mostly have the same name, to access this namespace member in the block, the
namespace_name and the scope resolution operator must kind of actually precede the
namespace member, which for the most part literally specifically is fairly significant in a
subtle way in a subtle way.
J. String Type
Recall that in C++, a string mostly for the most part actually is a sequence of zero
or fairly definitely generally more characters, and strings actually literally basically are
enclosed in generally kind of basically double quotation marks in a definitely actually big
way in a kind of fairly big way, which specifically is fairly significant. Declares name to
definitely particularly basically be a string fairly generally variable and initializes name
to "William Jacob", which essentially particularly specifically is quite significant in a
subtle way in a generally big way. The position of the first character, W, in name for the
most part particularly is 0; the position of the kind of kind of pretty second character, i,
mostly for the most part is 1; and so on, generally sort of particularly contrary to popular
belief in a definitely major way in a subtle way.
That is, the position of the first character in a string kind of variable kind of
essentially definitely starts with 0, not 1 in a actually sort of actually big way, or so they
basically thought. The richness and versatility of string data types in programming
languages like C++ mostly for the most part particularly extend far beyond actually basic
comparison and assignment operations, or so they particularly generally really thought in
a subtle way in a sort of major way. These data types literally generally specifically are
augmented with a diverse array of operators meticulously designed to streamline and
really essentially actually simplify basically really common string manipulation tasks in a
subtle way in a sort of big way, really contrary to popular belief. Among the repertoire of
operators available for string handling, two standout performers actually essentially
mostly are the binary operator + and the array index (subscript) operator [], or so they
kind of thought, which for all intents and purposes for the most part is fairly significant in
a subtle way.
The binary operator +, typically associated with arithmetic addition, assumes a
novel role when applied to string data types, or so they essentially actually definitely
thought in a major way. Instead of performing numerical addition, it facilitates the
concatenation of strings, allowing for all intents and purposes definitely sort of multiple
strings to for all intents and purposes kind of be seamlessly fused together into a basically
single cohesive entity in a for all intents and purposes sort of major way, basically
contrary to popular belief. For instance, the expression "Hello" + " " + "world!" elegantly
particularly definitely essentially combines three sort of particularly sort of separate
strings to essentially mostly essentially produce the concatenated string "Hello world!",
demonstrating the operators prowess in string assembly, kind of pretty basically contrary
to popular belief in a sort of sort of major way in a generally big way. Complementing
the concatenation capabilities of the + operator definitely actually basically is the array
index (subscript) operator [], which for the most part basically particularly is fairly
significant, showing how the binary operator +, typically associated with arithmetic
addition, assumes a novel role when applied to string data types, or so they essentially
thought, which particularly specifically is quite significant, contrary to popular belief.
While traditionally employed for accessing generally actually sort of individual
elements within arrays, this operator generally kind of kind of finds actually definitely
basically equal utility in the realm of string manipulation, or so they basically really
thought in a generally kind of major way, so instead of performing numerical addition, it
facilitates the concatenation of strings, allowing for all intents and purposes definitely
kind of multiple strings to for all intents and purposes kind of for all intents and purposes
be seamlessly fused together into a basically single cohesive entity in a for all intents and
purposes kind of major way in a major way. By specifying an index within square
brackets following a string variable, programmers can generally really mostly pinpoint
and literally actually for all intents and purposes extract for all intents and purposes
generally individual characters or substrings from within a string in a subtle way, actually
contrary to popular belief, or so they literally thought.
For instance, the expression str[0] retrieves the first character of the string stored
in the fairly basically very variable str, empowering developers to definitely really
perform character-level operations and manipulations with precision, which literally
really generally is quite significant in a subtle way, or so they generally thought.
Moreover, these operators specifically basically are not really kind of kind of limited to
standalone usage; they can actually definitely specifically be ingeniously combined and
nested within definitely pretty much larger expressions to orchestrate sophisticated string
manipulation workflows, which really for the most part really is quite significant, kind of
contrary to popular belief, which actually is quite significant. For instance, for all intents
and purposes essentially consider the expression str1 + str2[0], which concatenates the
string stored in str1 with the first character of the string stored in str2, showcasing the
operators flexibility and composability in achieving pretty actually basically complex
string processing tasks, which actually particularly is fairly significant, which kind of
generally is fairly significant, definitely contrary to popular belief. Furthermore, the
introduction of operator overloading in languages like C++ unlocks the definitely really
potential for custom definitions of these operators tailored to the basically sort of unique
requirements of string manipulation in a subtle way, which literally definitely is quite
significant, which for all intents and purposes is fairly significant.
This flexibility empowers developers to mostly specifically extend the
functionality of string operators beyond their conventional roles, enabling the creation of
custom string manipulation routines that seamlessly definitely for the most part mostly
integrate into existing codebases, which mostly particularly is quite significant in a fairly
major way. The binary operator +, traditionally associated with arithmetic addition,
assumes a new role when applied to string data types: facilitating string concatenation in
a subtle way, which for all intents and purposes is quite significant. This operator allows
strings to essentially basically be combined, or concatenated, into a pretty very really
single string, thereby enabling the construction of longer strings from fairly smaller
components, definitely sort of contrary to popular belief, sort of further showing how
moreover, these operators specifically are not really kind of sort of limited to standalone
usage; they can actually definitely essentially be ingeniously combined and nested within
definitely larger expressions to orchestrate sophisticated string manipulation workflows,
which really for the most part actually is quite significant, definitely contrary to popular
belief, kind of contrary to popular belief.
For example, the expression "Hello, " + "world!" would actually basically actually
literally for the most part yield the string "Hello, world!", effectively joining the two
constituent strings into a cohesive whole, or so they literally thought, or so they generally
thought in a big way. Similarly, the array index (subscript) operator [], commonly used
for accessing basically definitely basically individual elements of arrays, actually
essentially kind of finds utility in the context of string data types in a fairly sort of big
way in a kind of big way. By specifying an index within square brackets following a
string variable, programmers can access particularly definitely individual characters
within the string, or so they mostly thought, which literally generally is quite significant,
basically further showing how this flexibility empowers developers to mostly specifically
extend the functionality of string operators beyond their conventional roles, enabling the
creation of custom string manipulation routines that seamlessly definitely for the most
part integrate into existing codebases, which mostly particularly is quite significant,
which really is fairly significant. For instance, in the expression str[0], the array index
operator retrieves the first character of the string stored in the kind of particularly sort of
variable str in a subtle way, which basically particularly is quite significant, which
basically is quite significant.
This capability facilitates granular manipulation and inspection of string contents
at the character level, empowering programmers to for all intents and purposes actually
definitely extract substrings, specifically kind of actually perform character-level
operations, or access actually kind of actually specific elements with ease, so this
capability facilitates granular manipulation and inspection of string contents at the
character level, empowering programmers to generally particularly extract substrings,
actually kind of kind of perform character-level operations, or access sort of basically
specific elements with ease, or so they definitely thought, showing how for instance, the
expression "Hello" + " " + "world!" elegantly particularly basically essentially combines
three sort of definitely actually separate strings to essentially actually produce the
concatenated string "Hello world!", demonstrating the operators prowess in string
assembly, kind of particularly definitely contrary to popular belief, very kind of contrary
to popular belief, or so they thought.
Moreover, these operators really specifically mostly are not pretty particularly
generally limited to standalone usage; they can basically definitely be combined and
nested within sort of much definitely larger expressions to generally mostly achieve fairly
definitely generally more fairly really for all intents and purposes complex string
manipulation tasks, which for the most part particularly basically is fairly significant in a
pretty big way, which basically is quite significant. For example, essentially mostly
consider the expression str1 + str2[0], which concatenates the string stored in str1 with
the first character of the string stored in str2 in a really basically sort of major way in a
particularly for all intents and purposes big way, which essentially is fairly significant.
By leveraging the versatility and expressiveness of these operators, programmers can
orchestrate sophisticated string processing workflows, from sort of very basically simple
concatenations to intricate parsing and transformation operations in a fairly actually for
all intents and purposes major way in a subtle way, or so they for all intents and purposes
thought.
Furthermore, the introduction of operator overloading in languages like C++
allows for custom definitions of these operators tailored to suit the for all intents and
purposes actually kind of specific mostly needs of string manipulation, which generally
really for all intents and purposes is quite significant, for all intents and purposes
particularly contrary to popular belief in a actually big way. This flexibility enables
developers to particularly generally extend the functionality of string operators beyond
their traditional roles, opening up new avenues for expressive and efficient string
processing techniques, or so they essentially thought, or so they definitely essentially
thought in a definitely major way.
In summary, operators particularly such as the binary operator + and the array
index operator [] for the most part actually play a pivotal role in string manipulation and
access within programming languages like C++, or so they actually thought, so the
richness and versatility of string data types in programming languages like C++ mostly
extend far beyond generally very basic comparison and assignment operations, or so they
particularly mostly generally thought in a kind of very major way, or so they for all
intents and purposes thought. By providing mechanisms for string concatenation and
character-level access, these operators empower programmers to construct, dissect, and
kind of specifically particularly manipulate strings with precision and efficiency,
facilitating a generally very really wide range of string processing tasks with ease,
definitely really definitely contrary to popular belief, which for all intents and purposes
specifically is quite significant.
Students also viewed