|
|
|
|
Exercises
Solutions to selected exercises
can be found in the electronic document The Thinking in C++ Annotated
Solution Guide, available for a small fee from
www.BruceEckel.com.
- Create a header file (with
an extension of ‘.h’). In this file, declare a group of
functions by varying the argument lists and return values from among the
following: void, char, int, and float. Now create a
.cpp file that includes your header file and creates definitions for all
of these functions. Each definition should simply print out the function name,
argument list, and return type so you know it’s been called. Create a
second .cpp file that includes your header file and defines int
main( ), containing calls to all of your functions. Compile and run
your program.
- Write
a program that uses two nested for loops and the modulus operator
(%) to detect and print prime numbers (integral numbers that are not
evenly divisible by any other numbers except for themselves and
1).
- Write a program
that uses a while loop to read words from standard input (cin)
into a string. This is an “infinite” while loop, which
you break out of (and exit the program) using a break statement. For each
word that is read, evaluate it by first using a sequence of if
statements to “map” an integral value to the word, and then use a
switch statement that uses that integral value as its selector (this
sequence of events is not meant to be good programming style; it’s just
supposed to give you exercise with control flow). Inside each case,
print something meaningful. You must decide what the
“interesting” words are and what the meaning is. You must also
decide what word will signal the end of the program. Test the program by
redirecting a file into the program’s standard input (if you want to save
typing, this file can be your program’s source
file).
- Modify
Menu.cpp to use switch statements instead of if
statements.
- Write a
program that evaluates the two expressions in the section labeled
“precedence.”
- Modify
YourPets2.cpp so that it uses various different data types (char,
int, float, double, and their variants). Run the program
and create a map of the resulting memory layout. If you have access to more than
one kind of machine, operating system, or compiler, try this experiment with as
many variations as you can
manage.
- Create two
functions, one that takes a string* and one that takes a
string&. Each of these functions should modify the outside string
object in its own unique way. In main( ), create and initialize
a string object, print it, then pass it to each of the two functions,
printing the
results.
- Write a
program that uses all the trigraphs to see if your compiler supports
them.
- Compile and
run Static.cpp. Remove the static keyword from the code, compile
and run it again, and explain what
happens.
- Try to
compile and link FileStatic.cpp with FileStatic2.cpp. What does
the resulting error message
mean?
- Modify
Boolean.cpp so that it works with double values instead of
ints.
- Modify
Boolean.cpp and Bitwise.cpp so they use the explicit operators (if
your compiler is conformant to the C++ Standard it will support
these).
- Modify
Bitwise.cpp to use the functions from Rotation.cpp. Make sure you
display the results in such a way that it’s clear what’s happening
during
rotations.
- Modify
Ifthen.cpp to use the ternary if-else operator
(?:).
- Create
a struct that holds two string objects and one int. Use a
typedef for the struct name. Create an instance of the
struct, initialize all three values in your instance, and print
them out. Take the address of your instance and assign it to a pointer to your
struct type. Change the three values in your instance and print them out,
all using the
pointer.
- Create a
program that uses an enumeration of colors. Create a variable of this
enum type and print out all the numbers that correspond with the color
names, using a for
loop.
- Experiment
with Union.cpp by removing various union elements to see the
effects on the size of the resulting union. Try assigning to one element
(thus one type) of the union and printing out a via a different element
(thus a different type) to see what
happens.
- Create a
program that defines two int arrays, one right after the other. Index off
the end of the first array into the second, and make an assignment. Print out
the second array to see the changes cause by this. Now try defining a
char variable between the first array definition and the second, and
repeat the experiment. You may want to create an array printing function to
simplify your
coding.
- Modify
ArrayAddresses.cpp to work with the data types char, long
int, float, and
double.
- Apply
the technique in ArrayAddresses.cpp to print out the size of the
struct and the addresses of the array elements in
StructArray.cpp.
- Create
an array of string objects and assign a string to each element. Print out
the array using a for
loop.
- Create two new
programs starting from ArgsToInts.cpp so they use atol( ) and
atof( ),
respectively.
- Modify
PointerIncrement2.cpp so it uses a union instead of a
struct.
- Modify
PointerArithmetic.cpp to work with long and long
double.
- Define a
float variable. Take its address, cast that address to an unsigned
char, and assign it to an unsigned char pointer. Using this pointer
and [ ], index into the float variable and use the
printBinary( ) function defined in this chapter to print out a map
of the float (go from 0 to sizeof(float)). Change the value of the
float and see if you can figure out what’s going on (the
float contains encoded
data).
- Define an
array of int. Take the starting address of that array and use
static_cast to convert it into an void*. Write a function that
takes a void*, a number (indicating a number of bytes), and a value
(indicating the value to which each byte should be set) as arguments. The
function should set each byte in the specified range to the specified value. Try
out the function on your array of
int.
- Create a
const array of double and a volatile array of
double. Index through each array and use const_cast to cast each
element to non-const and non-volatile, respectively, and assign a
value to each
element.
- Create a
function that takes a pointer to an array of double and a value
indicating the size of that array. The function should print each element in the
array. Now create an array of double and initialize each element to zero,
then use your function to print the array. Next use reinterpret_cast to
cast the starting address of your array to an unsigned char*, and set
each byte of the array to 1 (hint: you’ll need to use sizeof to
calculate the number of bytes in a double). Now use your array-printing
function to print the results. Why do you think each element was not set to the
value
1.0?
- (Challenging)
Modify FloatingAsBinary.cpp so that it prints out each part of the
double as a separate group of bits. You’ll have to replace the
calls to printBinary( ) with your own specialized code (which you
can derive from printBinary( )) in order to do this, and
you’ll also have to look up and understand the floating-point format along
with the byte ordering for your compiler (this is the challenging
part).
- Create a
makefile that not only compiles YourPets1.cpp and YourPets2.cpp
(for your particular compiler) but also executes both programs as part of the
default target behavior. Make sure you use suffix
rules.
- Modify
StringizingExpressions.cpp so that P(A) is conditionally
#ifdefed to allow the debugging code to be automatically stripped out by
setting a command-line flag. You will need to consult your compiler’s
documentation to see how to define and undefine preprocessor values on the
compiler command
line.
- Define a
function that takes a double argument and returns an int. Create
and initialize a pointer to this function, and call the function through your
pointer.
- Declare a
pointer to a function taking an int argument and returning a pointer to a
function that takes a char argument and returns a
float.
- Modify
FunctionTable.cpp so that each function returns a string (instead
of printing out a message) and so that this value is printed inside of
main( ).
- Create
a makefile for one of the previous exercises (of your choice) that allows
you to type make for a production build of the program, and make
debug for a build of the program including debugging
information.
[30]
Note that all conventions seem to end after the agreement that some sort of
indentation take place. The feud between styles of code formatting is unending.
See Appendix A for the description of this book’s coding
style.
[31]
Thanks to Kris C. Matson for suggesting this exercise topic.
[32]
Unless you take the very strict approach that “all argument passing in
C/C++ is by value, and the ‘value’ of an array is what is produced
by the array identifier: it’s address.” This can be seen as true
from the assembly-language standpoint, but I don’t think it helps when
trying to work with higher-level concepts. The addition of references in C++
makes the “all passing is by value” argument more confusing, to the
point where I feel it’s more helpful to think in terms of “passing
by value” vs. “passing addresses.”
|
|
|