3rd Day |
||||||||||||||||||||||||||||||||||||||||||||||||||||
Day 3Variables and ConstantsToday you will learn
What Is a Variable?Your computer's memory can be viewed as a series of cubbyholes. Each cubbyhole is one of many, many such holes all lined up. Each cubbyhole--or memory location--is numbered sequentially. These numbers are known as memory addresses. A variable reserves one or more cubbyholes in which you may store a value. Your variable's name (for example, myVariable) is a label on one of these cubbyholes, so that you can find it easily without knowing its actual memory address. Figure 3.1 is a schematic representation of this idea. As you can see from the figure, myVariable starts at memory address 103. Depending on the size of myVariable, it can take up one or more memory addresses. Figure 3.1. A schematic representation of memory.
Setting Aside MemoryEach cubbyhole is one byte large. If the type of variable you create is two bytes in size, it needs two bytes of memory, or two cubbyholes. The type of the variable (for example, integer) tells the compiler how much memory (how many cubbyholes) to set aside for the variable. Because computers use bits and bytes to represent values, and because memory is measured in bytes, it is important that you understand and are comfortable with these concepts. For a full review of this topic, please read Appendix B, "C++ Keywords." Size of IntegersA char variable (used to hold characters) is most often one byte long. A short integer is two bytes on most computers, a long integer is usually four bytes, and an integer (without the keyword short or long) can be two or four bytes. Listing 3.1 should help you determine the exact size of these types on your computer.
1: #include <iostream.h> 2: 3: int main() 4: { 5: cout << "The size of an int is:\t\t" << sizeof(int) << " bytes.\n"; 6: cout << "The size of a short int is:\t" << sizeof(short) << " bytes.\n"; 7: cout << "The size of a long int is:\t" << sizeof(long) << " bytes.\n"; 8: cout << "The size of a char is:\t\t" << sizeof(char) << " bytes.\n"; 9: cout << "The size of a float is:\t\t" << sizeof(float) << " bytes.\n"; 10: cout << "The size of a double is:\t" << sizeof(double) << " bytes.\n"; 11: 12: return 0; 13: } Output: The size of an int is: 2 bytes. The size of a short int is: 2 bytes. The size of a long int is: 4 bytes. The size of a char is: 1 bytes. The size of a float is: 4 bytes. The size of a double is: 8 bytes.
signed and unsignedBecause you have the same number of bytes for both signed and unsigned integers, the largest number you can store in an unsigned integer is twice as big as the largest positive number you can store in a signed integer. An unsigned short integer can handle numbers from 0 to 65,535. Half the numbers represented by a signed short are negative, thus a signed short can only represent numbers from -32,768 to 32,767. If this is confusing, be sure to read Appendix A, "Operator Precedence." Fundamental Variable TypesFloating-point variables have values that can be expressed as fractions--that is, they are real numbers. Character variables hold a single byte and are used for holding the 256 characters and symbols of the ASCII and extended ASCII character sets.
Table 3.1. Variable Types.
Defining a Variableint myAge;As a general programming practice, avoid such horrific names as J23qrsnf, and restrict single-letter variable names (such as x or i) to variables that are used only very briefly. Try to use expressive names such as myAge or howMany. Such names are easier to understand three weeks later when you are scratching your head trying to figure out what you meant when you wrote that line of code. Try this experiment: Guess what these pieces of programs do, based on the first few lines of code: Example 1 main() { unsigned short x; unsigned short y; ULONG z; z = x * y; }Example 2 main () { unsigned short Width; unsigned short Length; unsigned short Area; Area = Width * Length; }Clearly, the second program is easier to understand, and the inconvenience of having to type the longer variable names is more than made up for by how much easier it is to maintain the second program. Case SensitivityThere are various conventions for how to name variables, and although it doesn't much matter which method you adopt, it is important to be consistent throughout your program. Many programmers prefer to use all lowercase letters for their variable names. If the name requires two words (for example, my car), there are two popular conventions: my_car or myCar. The latter form is called camel-notation, because the capitalization looks something like a camel's hump. Some people find the underscore character (my_car) to be easier to read, while others prefer to avoid the underscore, because it is more difficult to type. This book uses camel-notation, in which the second and all subsequent words are capitalized: myCar, theQuickBrownFox, and so forth.
Keywords
Creating More Than One Variable at a Timeunsigned int myAge, myWeight; // two unsigned int variables long area, width, length; // three longsAs you can see, myAge and myWeight are each declared as unsigned integer variables. The second line declares three individual long variables named area, width, and length. The type (long) is assigned to all the variables, so you cannot mix types in one definition statement. Assigning Values to Your Variablesunsigned short Width; Width = 5;You can combine these steps and initialize Width when you define it by writing unsigned short Width = 5;Initialization looks very much like assignment, and with integer variables, the difference is minor. Later, when constants are covered, you will see that some values must be initialized because they cannot be assigned to. The essential difference is that initialization takes place at the moment you create the variable. Just as you can define more than one variable at a time, you can initialize more than one variable at creation. For example: // create two long variables and initialize them ?long width = 5, length = 7;This example initializes the long integer variable width to the value 5 and the long integer variable length to the value 7. You can even mix definitions and initializations: int myAge = 39, yourAge, hisAge = 40;This example creates three type int variables, and it initializes the first and third. Listing 3.2 shows a complete program, ready to compile, that computes the area of a rectangle and writes the answer to the screen. Listing 3.2. A demonstration of the use of variables. 1: // Demonstration of variables 2: #include <iostream.h> 3: 4: int main() 5: { 6: unsigned short int Width = 5, Length; 7: Length = 10; 8: 9: // create an unsigned short and initialize with result 10: // of multiplying Width by Length 11: unsigned short int Area = Width * Length; 12: 13: cout << "Width:" << Width << "\n"; 14: cout << "Length: " << Length << endl; 15: cout << "Area: " << Area << endl; 16: return 0; 17: } Output: Width:5 Length: 10 Area: 50Analysis: Line 2 includes the required include statement for the iostream's library so that cout will work. Line 4 begins the program. On line 6, Width is defined as an unsigned short integer, and its value is initialized to 5. Another unsigned short integer, Length, is also defined, but it is not initialized. On line 7, the value 10 is assigned to Length. On line 11, an unsigned short integer, Area, is defined, and it is initialized with the value obtained by multiplying Width times Length. On lines 13-15, the values of the variables are printed to the screen. Note that the special word endl creates a new line. typedefIn effect, you are creating a synonym, and it is important to distinguish this from creating a new type (which you will do on Day 6). typedef is used by writing the keyword typedef, followed by the existing type and then the new name. For example typedef unsigned short int USHORTcreates the new name USHORT that you can use anywhere you might have written unsigned short int. Listing 3.3 is a replay of Listing 3.2, using the type definition USHORT rather than unsigned short int. Listing 3.3. A demonstration of typedef. 1: // ***************** 2: // Demonstrates typedef keyword 3: #include <iostream.h> 4: 5: typedef unsigned short int USHORT; //typedef defined 6: 7: void main() 8: { 9: USHORT Width = 5; 10: USHORT Length; 11: Length = 10; 12: USHORT Area = Width * Length; 13: cout << "Width:" << Width << "\n"; 14: cout << "Length: " << Length << endl; 15: cout << "Area: " << Area <<endl; 16: } Output: Width:5 Length: 10 Area: 50Analysis: On line 5, USHORT is typedefined as a synonym for unsigned short int. The program is very much like Listing 3.2, and the output is the same. When to Use short and When to Use longAs seen in Table 3.1, unsigned short integers, assuming that they are two bytes, can hold a value only up to 65,535. Signed short integers can hold only half that. Although unsigned long integers can hold an extremely large number (4,294,967,295) that is still quite finite. If you need a larger number, you'll have to go to float or double, and then you lose some precision. Floats and doubles can hold extremely large numbers, but only the first 7 or 19 digits are significant on most computers. That means that the number is rounded off after that many digits. Wrapping Around an unsigned IntegerWhen an unsigned integer reaches its maximum value, it wraps around and starts over, much as a car odometer might. Listing 3.4 shows what happens if you try to put too large a value into a short integer. Listing 3.4.A demonstration of putting too large a value in an unsigned integer. 1: #include <iostream.h> 2: int main() 3: { 4: unsigned short int smallNumber; 5: smallNumber = 65535; 6: cout << "small number:" << smallNumber << endl; 7: smallNumber++; 8: cout << "small number:" << smallNumber << endl; 9: smallNumber++; 10: cout << "small number:" << smallNumber << endl; 11: return 0; 12: } Output: small number:65535 small number:0 small number:1Analysis: On line 4, smallNumber is declared to be an unsigned short int, which on my computer is a two-byte variable, able to hold a value between 0 and 65,535. On line 5, the maximum value is assigned to smallNumber, and it is printed on line 6. On line 7, smallNumber is incremented; that is, 1 is added to it. The symbol for incrementing is ++ (as in the name C++--an incremental increase from C). Thus, the value in smallNumber would be 65,536. However, unsignedshort integers can't hold a number larger than 65,535, so the value is wrapped around to 0, which is printed on line 8. On line 9 smallNumber is incremented again, and then its new value, 1, is printed. Wrapping Around a signed IntegerListing 3.5. A demonstration of adding too large a number to a signed integer. 1: #include <iostream.h> 2: int main() 3: { 4: short int smallNumber; 5: smallNumber = 32767; 6: cout << "small number:" << smallNumber << endl; 7: smallNumber++; 8: cout << "small number:" << smallNumber << endl; 9: smallNumber++; 10: cout << "small number:" << smallNumber << endl; 11: return 0; 12: } Output: small number:32767 small number:-32768 small number:-32767Analysis: On line 4, smallNumber is declared this time to be a signed short integer (if you don't explicitly say that it is unsigned, it is assumed to be signed). The program proceeds much as the preceding one, but the output is quite different. To fully understand this output, you must be comfortable with how signed numbers are represented as bits in a two-byte integer. For details, check Appendix C, "Binary and Hexadecimal." The bottom line, however, is that just like an unsigned integer, the signed integer wraps around from its highest positive value to its highest negative value. CharactersIn the ASCII code, the lowercase letter "a" is assigned the value 97. All the lower- and uppercase letters, all the numerals, and all the punctuation marks are assigned values between 1 and 128. Another 128 marks and symbols are reserved for use by the computer maker, although the IBM extended character set has become something of a standard. Characters and NumbersThe value/letter relationship is arbitrary; there is no particular reason that the lowercase "a" is assigned the value 97. As long as everyone (your keyboard, compiler, and screen) agrees, there is no problem. It is important to realize, however, that there is a big difference between the value 5 and the character `5'. The latter is actually valued at 53, much as the letter `a' is valued at 97. Listing 3.6. Printing characters based on numbers 1: #include <iostream.h> 2: int main() 3: { 4: for (int i = 32; i<128; i++) 5: cout << (char) i; 6: return 0; 7: } Output: !"#$%G'()*+,./0123456789:;<>?@ABCDEFGHIJKLMNOP _QRSTUVWXYZ[\]^'abcdefghijklmnopqrstuvwxyz<|>~sThis simple program prints the character values for the integers 32 through 127. Special Printing Characterschar tabCharacter = `\t';This example declares a char variable (tabCharacter) and initializes it with the character value \t, which is recognized as a tab. The special printing characters are used when printing either to the screen or to a file or other output device.
ConstantsLiteral ConstantsA literal constant is a value typed directly into your program wherever it is needed. For example int myAge = 39;myAge is a variable of type int; 39 is a literal constant. You can't assign a value to 39, and its value can't be changed. Symbolic ConstantsIf your program has one integer variable named students and another named classes, you could compute how many students you have, given a known number of classes, if you knew there were 15 students per class: students = classes * 15; In this example, 15 is a literal constant. Your code would be easier to read, and easier to maintain, if you substituted a symbolic constant for this value: students = classes * studentsPerClassIf you later decided to change the number of students in each class, you could do so where you define the constant studentsPerClass without having to make a change every place you used that value. There are two ways to declare a symbolic constant in C++. The old, traditional, and now obsolete way is with a preprocessor directive, #define. Defining Constants with #define To define a constant the traditional way, you would enter this: #define studentsPerClass 15Note that studentsPerClass is of no particular type (int, char, and so on). #define does a simple text substitution. Every time the preprocessor sees the word studentsPerClass, it puts in the text 15. Because the preprocessor runs before the compiler, your compiler never sees your constant; it sees the number 15. Defining Constants with const Although #define works, there is a new, much better way to define constants in C++: const unsigned short int studentsPerClass = 15;This example also declares a symbolic constant named studentsPerClass, but this time studentsPerClass is typed as an unsigned short int. This method has several advantages in making your code easier to maintain and in preventing bugs. The biggest difference is that this constant has a type, and the compiler can enforce that it is used according to its type.
Enumerated ConstantsThe syntax for enumerated constants is to write the keyword enum, followed by the type name, an open brace, each of the legal values separated by a comma, and finally a closing brace and a semicolon. Here's an example: enum COLOR { RED, BLUE, GREEN, WHITE, BLACK };This statement performs two tasks:
enum Color { RED=100, BLUE, GREEN=500, WHITE, BLACK=700 };then RED will have the value 100; BLUE, the value 101; GREEN, the value 500; WHITE, the value 501; and BLACK, the value 700. You can define variables of type COLOR, but they can be assigned only one of the enumerated values (in this case, RED, BLUE, GREEN, WHITE, or BLACK, or else 100, 101, 500, 501, or 700). You can assign any color value to your COLOR variable. In fact, you can assign any integer value, even if it is not a legal color, although a good compiler will issue a warning if you do. It is important to realize that enumerator variables actually are of type unsigned int, and that the enumerated constants equate to integer variables. It is, however, very convenient to be able to name these values when working with colors, days of the week, or similar sets of values. Listing 3.7 presents a program that uses an enumerated type. Listing 3.7. A demonstration of enumerated constants. 1: #include <iostream.h> 2: int main() 3: { 4: enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, ?_Saturday }; 5: 6: Days DayOff; 7: int x; 8: 9: cout << "What day would you like off (0-6)? "; 10: cin >> x; 11: DayOff = Days(x); 12: 13: if (DayOff == Sunday || DayOff == Saturday) 14: cout << "\nYou're already off on weekends!\n"; 15: else 16: cout << "\nOkay, I'll put in the vacation day.\n"; 17: return 0; 18: } Output: What day would you like off (0-6)? 1 Okay, I'll put in the vacation day. What day would you like off (0-6)? 0 You're already off on weekends!Analysis: On line 4, the enumerated constant DAYS is defined, with seven values counting upward from 0. The user is prompted for a day on line 9. The chosen value, a number between 0 and 6, is compared on line 13 to the enumerated values for Sunday and Saturday, and action is taken accordingly. The if statement will be covered in more detail on Day 4, "Expressions and Statements." You cannot type the word "Sunday" when prompted for a day; the program does not know how to translate the characters in Sunday into one of the enumerated values.
SummaryYou must declare a variable before it can be used, and then you must store the type of data that you've declared as correct for that variable. If you put too large a number into an integral variable, it wraps around and produces an incorrect result. This chapter also reviewed literal and symbolic constants, as well as enumerated constants, and showed two ways to declare a symbolic constant: using #define and using the keyword const. Q&A
Q. What happens if I assign a number with a decimal point to an integer rather than to a float? Consider the following line of code: int aNumber = 5.4;
A. If you use the value in many places throughout your program, a symbolic constant allows all the values to change just by changing the one definition of the constant. Symbolic constants also speak for themselves. It might be hard to understand why a number is being multiplied by 360, but it's much easier to understand what's going on if the number is being multiplied by degreesInACircle. Q. What happens if I assign a negative number to an unsigned variable? Consider the following line of code: unsigned int aPositiveNumber = -1;
A. Yes, but not as effectively as if you do understand these topics. C++ does not do as good a job as some languages at "protecting" you from what the computer is really doing. This is actually a benefit, because it provides you with tremendous power that other languages don't. As with any power tool, however, to get the most out of C++ you must understand how it works. Programmers who try to program in C++ without understanding the fundamentals of the binary system often are confused by their results. WorkshopQuiz
3. What are the advantages of using a symbolic constant rather than a literal constant? 4. What are the advantages of using the const keyword rather than #define? 5. What makes for a good or bad variable name? 6. Given this enum, what is the value of BLUE? enum COLOR { WHITE, BLACK = 100, RED, BLUE, GREEN = 300 };
a. Age b. !ex c. R79J d. TotalIncome e. __Invalid Exercises
a. Your age. b. The area of your backyard. c. The number of stars in the galaxy. d. The average rainfall for the month of January. 2. Create good variable names for this information. 3. Declare a constant for pi as 3.14159. 4. Declare a float variable and initialize it using your pi constant. |