In this chapter you’ll learn about the following:
• How to create and use arrays
• How to create and use C-style strings
• How to create and use string
-class strings
• How to use the getline()
and get()
methods for reading strings
• How to mix string and numeric input
• How to create and use structures
• How to create and use unions
• How to create and use enumerations
• How to create and use pointers
• How to manage dynamic memory with new
and delete
• How to create dynamic arrays
Say you’ve developed a computer game called User-Hostile in which players match wits with a cryptic and abusive computer interface. Now you must write a program that keeps track of your monthly game sales for a five-year period. Or you want to inventory your accumulation of hacker-hero trading cards. You soon conclude that you need something more than C++’s simple basic types to meet these data requirements, and C++ offers something more—compound types. These are types built from the basic integer and floating-point types. The most far-reaching compound type is the class, that bastion of OOP toward which we are progressing. But C++ also supports several more modest compound types taken from C. The array, for example, can hold several values of the same type. A particular kind of array can hold a string, which is a series of characters. Structures can hold several values of differing types. Then there are pointers, which are variables that tell a computer where data is placed. You’ll examine all these compound forms (except classes) in this chapter, take a first look at new
and delete
and how you can use them to manage data, and take an introductory look at the C++ string
class, which gives you an alternative way to work with strings.
An array is a data form that can hold several values, all of one type. For example, an array can hold 60 type int
values that represent five years of game sales data, 12 short
values that represent the number of days in each month, or 365 float
values that indicate your food expenses for each day of the year. Each value is stored in a separate array element, and the computer stores all the elements of an array consecutively in memory.
To create an array, you use a declaration statement. An array declaration should indicate three things:
• The type of value to be stored in each element
• The name of the array
• The number of elements in the array
You accomplish this in C++ by modifying the declaration for a simple variable and adding brackets that contain the number of elements. For example, the declaration
short months[12]; // creates array of 12 short
creates an array named months
that has 12 elements, each of which can hold a type short
value. Each element, in essence, is a variable that you can treat as a simple variable.
This is the general form for declaring an array:
typeName arrayName[arraySize];
The expression arraySize
, which is the number of elements, must be an integer constant, such as 10 or a const
value, or a constant expression, such as 8 * sizeof (int)
, for which all values are known at the time compilation takes place. In particular, arraySize
cannot be a variable whose value is set while the program is running. However, later in this chapter you’ll learn how to use the new
operator to get around that restriction.
Much of the usefulness of the array comes from the fact that you can access array elements individually. The way to do this is to use a subscript, or an index, to number the elements. C++ array numbering starts with zero. (This is nonnegotiable; you have to start at zero. Pascal and BASIC users will have to adjust.) C++ uses a bracket notation with the index to specify an array element. For example, months[0]
is the first element of the months
array, and months[11]
is the last element. Note that the index of the last element is one less than the size of the array. (See Figure 4.1.) Thus, an array declaration enables you to create a lot of variables with a single declaration, and you can then use an index to identify and access individual elements.
Figure 4.1. Creating an array.
The yam analysis program in Listing 4.1 demonstrates a few properties of arrays, including declaring an array, assigning values to array elements, and initializing an array.
Current versions of C++, as well as ANSI C, allow you to initialize ordinary arrays defined in a function. However, in some older implementations that use a C++ translator instead of a true compiler, the C++ translator creates C code for a C compiler that is not fully ANSI C compliant. In such a case, you can get an error message like the following example from a Sun C++ 2.0 system:
"arrayone.cc", line 10: sorry, not implemented: initialization of
yamcosts (automatic aggregate) Compilation failed
The fix is to use the keyword static
in the array declaration:
// pre-ANSI initialization
static int yamcosts[3] = {20, 30, 5};
The keyword static
causes the compiler to use a different memory scheme for storing the array, one that allows initialization even under pre-ANSI C. Chapter 9, “Memory Models and Namespaces,” discusses this use of static
.
Here is the output from the program in Listing 4.1:
Total yams = 21
The package with 8 yams costs 30 cents per yam.
The total yam expense is 410 cents.
Size of yams array = 12 bytes.
Size of one element = 4 bytes.
First, the program in Listing 4.1 creates a three-element array called yams
. Because yams
has three elements, the elements are numbered from 0
through 2
, and arrayone.cpp
uses index values of 0
through 2
to assign values to the three individual elements. Each individual yam
element is an int
with all the rights and privileges of an int
type, so arrayone.cpp
can, and does, assign values to elements, add elements, multiply elements, and display elements.
The program uses the long way to assign values to the yam
elements. C++ also lets you initialize array elements within the declaration statement. Listing 4.1 uses this shortcut to assign values to the yamcosts
array:
int yamcosts[3] = {20, 30, 5};
It simply provides a comma-separated list of values (the initialization list) enclosed in braces. The spaces in the list are optional. If you don’t initialize an array that’s defined inside a function, the element values remain undefined. That means the element takes on whatever value previously resided at that location in memory.
Next, the program uses the array values in a few calculations. This part of the program looks cluttered with all the subscripts and brackets. The for
loop, coming up in Chapter 5, “Loops and Relational Expressions,” provides a powerful way to deal with arrays and eliminates the need to write each index explicitly. For the time being, we’ll stick to small arrays.
As you should recall, the sizeof
operator returns the size, in bytes, of a type or data object. Note that if you use the sizeof
operator with an array name, you get the number of bytes in the whole array. But if you use sizeof
with an array element, you get the size, in bytes, of the element. This illustrates that yams
is an array, but yams[1]
is just an int
.
C++ has several rules about initializing arrays. They restrict when you can do it, and they determine what happens if the number of array elements doesn’t match the number of values in the initializer. Let’s examine these rules.
You can use the initialization form only when defining the array. You cannot use it later, and you cannot assign one array wholesale to another:
However, you can use subscripts and assign values to the elements of an array individually.
When initializing an array, you can provide fewer values than array elements. For example, the following statement initializes only the first two elements of hotelTips
:
float hotelTips[5] = {5.0, 2.5};
If you partially initialize an array, the compiler sets the remaining elements to zero. Thus, it’s easy to initialize all the elements of an array to zero—just explicitly initialize the first element to zero and then let the compiler initialize the remaining elements to zero:
long totals[500] = {0};
Note that if you initialize to {1}
instead of to {0}
, just the first element is set to 1
; the rest still get set to 0
.
If you leave the square brackets ([]
) empty when you initialize an array, the C++ compiler counts the elements for you. Suppose, for example, that you make this declaration:
short things[] = {1, 5, 3, 8};
The compiler makes things
an array of four elements.
The C++ Standard Template Library (STL) provides an alternative to arrays called the vector
template class. This alternative is more sophisticated and flexible than the built-in array composite type. Chapter 16, “The string
Class and the Standard Template Library,” discusses the STL and the vector
template class.
A string is a series of characters stored in consecutive bytes of memory. C++ has two ways of dealing with strings. The first, taken from C and often called a C-style string, is the first one this chapter examines. Later, this chapter discusses an alternative method based on a string
class library.
The idea of a series of characters stored in consecutive bytes implies that you can store a string in an array of char
, with each character kept in its own array element. Strings provide a convenient way to store text information, such as messages to the user (“Please tell me your secret Swiss bank account number”) or responses from the user (“You must be joking”). C-style strings have a special feature: The last character of every string is the null character. This character, written