Declaring Variables Constantly - Getting Started with C++ Programming - C++ For Dummies (2014)

C++ For Dummies (2014)

Part I

Getting Started with C++ Programming

Chapter 2

Declaring Variables Constantly

In This Chapter

arrow Declaring variables

arrow Declaring different types of variables

arrow Using floating-point variables

arrow Declaring and using other variable types

The most fundamental of all concepts in C++ is the variable — a variable is like a small box. You can store things in the box for later use, particularly numbers. The concept of a variable is borrowed from mathematics. A statement such as

x = 1

stores the value 1 in the variable x. From that point forward, the mathematician can use the variable x in place of the constant 1 — until he changes the value of x to something else.

Variables work the same way in C++. You can make the assignment

x = 1;

From that point forward in the execution of the program, the value of x is 1 until the program changes the value to something else. References to x are replaced by the value 1. In this chapter, you will find out how to declare and initialize variables in C++ programs. You will also see the different types of variables that C++ defines and when to use each.

Declaring Variables

A mathematician might write something like the following:

(x + 2) = y / 2
x + 4 = y
solve for x and y

Any reader who’s had algebra realizes right off that the mathematician has introduced the variables x and y. But C++ isn’t that smart. (Computers may be fast, but they’re stupid.)

You have to announce each variable to C++ before you can use it. You have to say something soothing like this:

int x;
x = 10;

int y;
y = 5;

These lines of code declare that a variable x exists, is of type int, and has the value 10; and that a variable y of type int also exists with the value 5. (The next section discusses variable types.) You can declare variables (almost) anywhere you want in your program — as long as you declare the variable before you use it.

Declaring Different Types of Variables

If you’re on friendly terms with math (and who isn’t?), you probably think of a variable in mathematics as an amorphous box capable of holding whatever you might choose to store in it. You might easily write something like the following:

x = 1
x = 2.3
x = "this is a sentence"

Alas, C++ is not that flexible. (On the other hand, C++ can do things that people can’t do, such as add a billion numbers or so in a second, so let’s not get too uppity.) To C++, there are different types of variables just as there are different types of storage bins. Some storage bins are so small that they can handle only a single number. It takes a larger bin to handle a sentence.

image Some computer languages try harder to accommodate the programmer by allowing her to place different types of data in the same variable. These languages are called weakly typed languages. C++ is a strongly typed language — it requires the programmer to specifically declare each variable along with its exact type.

The variable type int is the C++ equivalent of an integer — a number that has no fractional part. (Integers are also known as counting numbers or whole numbers.)

Integers are great for most calculations. I made it through most of elementary school with integers. It isn’t until I turned 11 or so that my teachers started mucking up the waters with fractions. The same is true in C++: More than 90 percent of all variables in C++ are declared to be of typeint.

Unfortunately, int variables aren’t adapted to every problem. For example, if you worked through the temperature-conversion program in Chapter 1, you might have noticed that the program has a potential problem — it can calculate temperatures to the nearest degree. No fractions of a degree are allowed. This integer limitation wouldn’t affect daily use because it isn’t likely that someone (other than a meteorologist) would get all excited about being off a fraction of a degree. There are plenty of cases, however, where this isn’t the case — for example, you wouldn’t want to come up a half mile short of the runway on your next airplane trip due to a navigational round-off.

Reviewing the limitations of integers in C++

The int variable type is the C++ version of an integer. int variables suffer the same limitations as their counting-number integer equivalents in math do.

Integer round-off

Lopping off the fractional part of a number is called truncation. Consider the problem of calculating the average of three numbers. Given three int variables — nValue1, nValue2, and nValue3 — an equation for calculating the average is

int nAverage; int nValue1; int nValue2; int nValue3;
nAverage = (nValue1 + nValue2 + nValue3) / 3;

Because all three values are integers, the sum is assumed to be an integer. Given the values 1, 2, and 2, the sum is 5. Divide that by 3, and you get 123, or 1.666. C++ uses slightly different rules: Given that all three variables nValue1, nValue2, and nValue3 are integers, the sum is also assumed to be an integer. The result of the division of one integer by another integer is also an integer. Thus, the resulting value of nAverage is the unreasonable but logical value of 1.

The problem is much worse in the following mathematically equivalent formulation:

int nAverage; int nValue1; int nValue2; int nValue3;
nAverage = nValue1/3 + nValue2/3 + nValue3/3;

Plugging in the same 1, 2, and 2 values, the resulting value of nAverage is 0 (talk about unreasonable). To see how this can occur, consider that 13 truncates to 0, 23 truncates to 0, and 23 truncates to 0. The sum of 0, 0, and 0 is 0. You can see that integer truncation can be completely unacceptable.

Limited range

A second problem with the int variable type is its limited range. A normal int variable can store a maximum value of 2,147,483,647 and a minimum value of -2,147,483,648 — roughly from positive 2 billion to negative 2 billion, for a total range of about 4 billion.

image Two billion is a very large number: plenty big enough for most uses. But it’s not large enough for some applications, including computer technology. In fact, your computer probably executes faster than 2 gigahertz, depending on how old your computer is. (Giga is the prefix meaning billion.) A single strand of communications fiber — the kind that’s been strung back and forth from one end of the country to the other — can handle way more than 2 billion bits per second.

Solving the truncation problem

The limitations of int variables can be unacceptable in some applications. Fortunately, C++ understands decimal numbers that have a fractional part. (Mathematicians also call those real numbers.) Decimal numbers avoid many of the limitations of int type integers. To C++ all decimal numbers have a fractional part even if that fractional part is 0. In C++, the number 1.0 is just as much a decimal number as 1.5. The equivalent integer is written simply as 1. Decimal numbers can also be negative, such as -2.3.

When you declare variables in C++ that are decimal numbers, you identify them as floating-point or simply float variables. The term floating-point means the decimal point is allowed to float back and forth, identifying as many decimal places as necessary to express the value. Floating-point variables are declared in the same way as int variables:

float fValue1;

Once declared, you cannot change the type of a variable. fValue1 is now a float and will be a float for the remainder of the program. To see how floating-point numbers fix the truncation problem inherent with integers, convert all the int variables to float. Here’s what you get:

float fValue;
fValue = 1.0/3.0 + 2.0/3.0 + 2.0/3.0;

is equivalent to

fValue = 0.333... + 0.666... + 0.666...;

which results in the value

fValue = 1.666...;

image I have written the value 1.6666 … as if the number of trailing 6s goes on forever. This is not necessarily the case. A float variable has a limit to the number of digits of accuracy that we'll discuss in the next section.

image A constant that has a decimal point is assumed to be a floating-point value. However, the default type for a floating-point constant is something known as a double precision, which in C++ is called simply double, as we’ll see in the next section.

The programs IntAverage and FloatAverage are available from www.dummies.com/extras/cplusplus in the CPP_Programs_from_Book\Chap02 directory to demonstrate the round-off error inherent in integer variables.

Looking at the limits of floating point numbers

Although floating-point variables can solve many calculation problems, such as truncation, they have some limitations themselves — the reverse of those associated with integer variables. Floating-point variables can’t be used to count things, are more difficult for the computer to handle, and also suffer from round-off error (though not nearly to the same degree as int variables).

Counting

You cannot use floating-point variables in applications where counting is important. This includes C++ constructs that count. C++ can’t verify which whole number value is meant by a given floating-point number.

For example, it’s clear to you and me that 1.0 is 1 but not so clear to C++. What about 0.9 or 1.1? Should these also be considered as 1? C++ simply avoids the problem by insisting on using int values when counting is involved.

Calculation speed

Historically, a computer processor can process integer arithmetic quicker than it can floating-point arithmetic. Thus, while a processor can add 1 million integer numbers in a given amount of time, the same processor may be able to perform only 200,000 floating-point calculations during the same period.

Calculation speed is becoming less of a problem as microprocessors get faster. In addition, today’s general-purpose microprocessors include special floating-point circuitry on board to increase the performance of these operations. However, arithmetic on integer values is just a heck of a lot easier and faster than performing the same operation on floating-point values.

Loss of accuracy

Floating-point float variables have a precision of about 6 digits, and an extra-economy size, double-strength version of float known as a double can handle about 13 significant digits. This can cause round-off problems as well.

Consider that 13 is expressed as 0.333 … in a continuing sequence. The concept of an infinite series makes sense in math but not to a computer because it has a finite accuracy. The FloatAverage program outputs 1.66667 as the average 1, 2, and 2 — that’s a lot better than the 0 output by the IntAverage version but not even close to an infinite sequence. C++ can correct for round-off error in a lot of cases. For example, on output, C++ can sometimes determine that the user really meant 1 instead of 0.999999. In other cases, even C++ cannot correct for round-off error.

Not-so-limited range

Although the double data type has a range much larger than that of an integer, it’s still limited. The maximum value for an int is a skosh more than 2 billion. The maximum value of a double variable is roughly 10 to the 38th power. That’s 1 followed by 38 zeroes; it eats 2 billion for breakfast. (It’s even more than the national debt, at least at the time of this writing.)

image Only the first 13 digits or so of a double have any meaning; the remaining 25 digits are noise having succumbed to floating-point round-off error.

Declaring Variable Types

So far in this chapter, I have been trumpeting that variables must be declared and that they must be assigned a type. Fortunately (ta-dah!), C++ provides a number of variable types. See Table 2-1 for a list of variables, their advantages, and limitations.

Table 2-1 Common C++ Variable Types

Variable

Defining a Constant

What It Is

int

1

A simple counting number, either positive or negative.

short int

---

A potentially smaller version of int. It uses less memory but has a smaller range.

long int

10L

A potentially larger version of int. There is no difference between long and int with gcc.

long long int

10LL

A potentially even larger version of int.

float

1.0F

A single precision real number. This smaller version takes less memory than a double but has less accuracy and a smaller range.

double

1.0

A standard floating-point variable.

long double

---

A potentially larger floating-point number. On the PC, long double is used for the native size of the 80x86 floating-point processor, which is 80 bits.

char

‘c’

A single char variable stores a single alphabetic or digital character. Not suitable for arithmetic.

wchar_t

L'c'

A larger character capable or storing symbols with larger character sets like Chinese.

char string

“this is a string”

A string of characters forms a sentence or phrase.

bool

true

The only other value is false. No, I mean, it’s really false. Logically false. Not false as in fake or ersatz or … never mind.

image The long long int and long double were officially introduced with C++ ’11.

The integer types come in both signed and unsigned versions. Signed is always the default (for everything except char and wchar_t). The unsigned version is created by adding the keyword unsigned in front of the type in the declaration. The unsigned constants include a U or u in their type designation. Thus, the following declares an unsigned int variable and assigns it the value 10:

unsigned int uVariable;
uVariable = 10U;

The following statement declares the two variables lVariable1 and lVariable2 as type long int and sets them equal to the value 1, while dVariable is a double set to the value 1.0. Notice in the declaration of lVariable2 that the int is assumed and can be left off:

// declare two long int variables and set them to 1
long int lVariable1
long lVariable2; // int is assumed
lVariable1 = lVariable2 = 1;
// declare a variable of type double and set it to 1.0
double dVariable; dVariable = 1.0;

image You can declare a variable and initialize it in the same statement:

int nVariable = 1; // declare a variable and
// initialize it to 1

A char variable can hold a single character; a character string (which isn’t really a variable type but works like one for most purposes) holds a string of characters. Thus, ‘C’ is a char that contains the character C, whereas “C” is a string with one character in it. A rough analogy is that a‘C’ corresponds to a nail in your hand, whereas “C” corresponds to a nail gun with one nail left in the magazine. (Chapter 9 describes strings in detail.)

image If an application requires a string, you’ve gotta provide one, even if the string contains only a single character. Providing nothing but the character just won’t do the job.

Types of constants

A constant value is an explicit number or character (such as 1, 0.5, or ‘c’) that doesn’t change. As with variables, every constant has a type. In an expression such as n = 1; the constant value 1 is an int. To make 1 a long integer, write the statement as n = 1L;. The analogy is as follows: 1 represents a pickup truck with one ball in it, whereas 1L is a dump truck also with one ball. The number of balls is the same in both cases, but the capacity of one of the containers is much larger.

Following the int to long comparison, 1.0 represents the value 1 but in a floating-point container. Notice, however, that the default for floating-point constants is double. Thus, 1.0 is a double number and not a float.

You can use either uppercase or lowercase letters for your special constants. Thus, 10UL and 10ul are both unsigned long integers.

The constant values true and false are of type bool. In keeping with C++’s attention to case, true is a constant but TRUE has no meaning.

A variable can be declared constant when it is created via the keyword const:

const double PI = 3.14159; // declare a constant variable

A const variable must be initialized with a value when it is declared, and its value cannot be changed by any future statement.

image Variables declared const don’t have to be named with all capitals, but by convention they often are. This is just a hint to the reader that this so-called variable is, in fact, not.

I admit that it may seem odd to declare a variable and then say that it can’t change. Why bother? Largely because carefully named const variables can make a program a lot easier to understand. Consider the following two equivalent expressions:

double dC = 6.28318 * dR; // what does this mean?
double dCircumference = TWO_PI * dRadius; // this is a
// lot easier to understand

It should be a lot clearer to the reader of this code that the second expression is multiplying the radius of something by 2π to calculate the circumference.

Range of Numeric Types

It may seem odd, but the C++ standard doesn’t say exactly how big a number each of the data types can accommodate. The standard speaks only to the relative size of each data type. For example, it says that the maximum long int is at least as large as the maximum int.

The authors of C++ weren’t trying to be mysterious. They merely wanted to allow the compiler to implement the absolute fastest code possible for the base machine. The standard was designed to work for all different types of processors running different operating systems.

However, it is useful to know the limits for your particular implementation. Table 2-2 shows the size of each number type on a Windows PC using the Code::Blocks/gcc compiler.

0202

Attempting to calculate a number that’s beyond the range of its type is known as an overflow. The C++ standard generally leaves the results of an overflow as undefined. That’s another way that the definers of C++ remained flexible.

image On the PC, a floating-point overflow results in an exception, which if not handled will cause your program to crash. (I don’t discuss exceptions until Chapter 24.) As bad as that sounds, an integer overflow is worse — C++ silently generates an incorrect value without complaint.

Special characters

You can store any printable character you want in a char or string variable. You can also store a set of non-printable characters that are used as character constants. See Table 2-3 for a description of these important non-printable characters.

Table 2-3 Special Characters

Character Constant

What It Is

'\n'

newline

'\t'

tab

'\040'

The character whose value is 40 in octal (see Chapter 4 for a discussion of number systems)

'\x20'

The character whose value is 20 in hexadecimal (this is the same as '\040')

'\0'

null (i.e., the character whose value is 0)

'\\'

backslash


C++ collision with filenames

Windows uses the backslash character to separate folder names in the path to a file. (This is a remnant of MS-DOS that Windows has not been able to shake.) Thus, Root\FolderA\File represents File within FolderA, which is a subdirectory of Root.

Unfortunately, MS-DOS’s use of the backslash conflicts with the use of the backslash to indicate an escape character in C++. The character \\ is a backslash in C++. The MS-DOS path Root\FolderA\File is represented in C++ as the string “Root\\FolderA\\File”.


You have already seen the newline character at the end of strings. This character breaks a string and puts the parts on separate lines. A newline character may appear anywhere within a string. For example:

"This is line 1\nThis is line 2"

appears on the output as

This is line 1
This is line 2

Similarly, the \t tab character moves output to the next tab position. (This position can vary, depending on the type of computer you’re using to run the program.)

The numerical forms allow you to specify any non-printing character that you like, but results may vary. The character represented by 0xFB, for example, depends on the font and the character set (and may not be a legal character at all).

Because the backslash character is used to signify special characters, a character pair for the backslash itself is required. The character pair \\ represents the backslash.

Wide Loads on Char Highway

The standard char variable is a scant 1 byte wide and can handle only 255 different characters. This is plenty enough for European languages but not big enough to handle symbol-based languages such as kanji.

Several standards have arisen to extend the character set to handle the demands of these languages. UTF-8 uses a mixture of 8-, 16-, and 32-bit characters to implement almost every kanji or hieroglyph you can think of but still remain compatible with simple 8-bit ASCII. UTF-16 uses a mixture of 16- and 32-bit characters to achieve an expanded character set, and UTF-32 uses 32 bits for all characters.

image UTF stands for Unicode Transformation Format, from which it gets the common nickname Unicode.

image Table 2-4 describes the different character types supported by C++. At first, C++ tried to get by with a vaguely defined wide character type, wchar_t. This type was intended to be the wide character type native to the application program’s environment. C++ ’11 introduced specific types for UTF-16 and UTF-32.

Table 2-4 The C++ Character Types

Variable

Example

What It Is

char

'c'

ASCII or UTF-8 characters

wchar_t

L'c'

Character in wide format

char_16t

u'c'

UTF-16 character

char_32t

U'c'

UTF-32 character

image UTF-16 is the standard encoding for Windows applications. The wchar_t type refers to UTF-16 in the Code::Blocks/gcc compiler.

Any of the character types in Table 2-4 can be combined into strings as well:

wchar_t* wideString = L"this is a wide string";

(Ignore the asterisk for now. I have a lot to say about its meaning in Chapter 8.)

Are These Calculations Really Logical?

C++ provides a logical variable called bool. The type bool comes from Boole, the last name of the inventor of the logical calculus. A Boolean variable has two values: true and false.

image There are actually calculations that result in the value bool. For example, “x is equal to y” is either true or false.

Mixed Mode Expressions

C++ allows you to mix variable types in a single expression. That is, you are allowed to add an integer with a double precision floating-point value. In the following expression, for example, nValue1 is allowed to be an int:

// in the following expression the value of nValue1
// is converted into a double before performing the
// assignment
int nValue1 = 1;
nValue1 + 1.0;

An expression in which the two operands are not the same type is called a mixed mode expression. Mixed mode expressions generate a value whose type is equal to the more capable of the two operands. In this case, nValue1 is converted to a double before the calculation proceeds. Similarly, an expression of one type may be assigned to a variable of a different type, as in the following statement:

// in the following assignment, the whole
// number part of fVariable is stored into nVariable
double dVariable = 1.0;
int nVariable;
nVariable = dVariable;

image You can lose precision or range if the variable on the left side of the assignment is smaller. In the preceding example, C++ truncates the value of dVariable before storing it in nVariable.

Converting a larger value type into a smaller value type is called demotion, whereas converting values in the opposite direction is known as promotion. Programmers say that the value of int variable nVariable1 is promoted to a double in expressions such as the following:

int nVariable1 = 1;
double dVariable = nVariable1;

image Mixed mode expressions are not a good idea. Avoid forcing C++ to do your conversions for you.


Naming conventions

You may have noticed that the name of each of the variables that I create begins with a special character that seems to have nothing to do with the name. These special characters are not special to C++ at all; they are merely meant to jog the reader’s memory and indicate the type of the variable. A partial list of these special characters follows. Using this convention, I can immediately recognize dVariable as a variable of type double, for example.

Character

Type

n

int

l

long

f

float

d

double

c

character

sz

string

Religious wars worse than the True Value of BitCoin have broken out over whether or not this naming convention clarifies C++ code. It helps me, so I stick with it. Try it for awhile. If after a few months, you don’t think it helps, feel free to change your naming convention.


Automatic Declarations

image If you are really lazy, you can let C++ determine the types of your variables for you. Consider the following declaration:

int nVar = 1;

You might ask, “Why can’t C++ figure out the type of nVar?” The answer is, it will if you ask nicely, as follows:

auto var1 = 1;
auto var2 = 2.0;

This says, “declare var1 to be a variable of the same type as the constant value 1 (which happens to be an int) and declare var2 to be the same type as 2.0 (which is a double).”

image I consider the term auto to be a particularly unfortunate choice for this purpose because prior to C++ ’11, the keyword auto had a completely different meaning. However, auto had fallen out of use for at least 20 years, so the standards people figured that it would be safe to usurp the term. Just be aware that if you see the keyword auto in some old code, you will need to remove it.

image You can also tell C++ that you want a variable to be declared to be of the same type as another variable, whatever that might be, using the keyword decltype().

int var1;
decltype(var1) var2; // declare var2 to be of the
// same type as var1

C++ replaces the decltype(var1) with the type of var1, again an int.