There is a need for a name for "something in memory." This is the simplest and most fundamental notion of an object. That is, an object is a contiguous region of memory storage. Variables represent objects in our programs. A type of a variable specifies amount of computer memory needed to instantiate the variable. In addition, type describes run-time behavior of the variable. Consider x = y + 2; For this to make sense in a C++ program, the names x and y must be suitably declared. That is, the programmer must specify what types are x and y: double x; // x is a floating-point variable int y = 7; // y is an integer variable with initial value 7 x = y + 2; // add 2 to y and assign the result to x. Furthermore, = (assignment) and + (addition) should be meaningful for these types. Every name (identifier) in a C++ program has a type associated with it. This type determines what operations can be applied to each name. Fundamental Types of the C++ Language
Microsoft VC++ Specific: the following table lists the amount of storage required for fundamental types Sizes of Fundamental Types
The boolean, character, and integer types are collectively called integral types. The integral and floating-point types are collectively called arithmetic types. The fundamental types are also called built-in types. For most applications, one could simply use bool for logical values, char for characters, int for integer values, and double for floating-point values. |
A Boolean, bool, can have one of the two values: true or false. A Boolean is used to express the results of logical operations. For example: int a = 2; int b = 2; bool is_equal = ( a == b ); // = is assignment, == is equality A variable of boolean type can be converted to an integer: true has the value 1 when converted to an integer, and false has the value 0. Conversely, integers can be implicitly converted to bool values: nonzero integers convert to true and 0 converts to false. For example: int i = -1; bool b = i; // b becomes true, because i is nonzero. |
A variable of type char can hold a character of platform-specific character set. For example: char ch = 'a'; Almost universally, a char has 8 bits so that it can hold one of 256 different values. Typically, the character set is a variant of ISO-646 standard, for example ASCII, thus providing the characters appearing on your keyboard. It is safe to assume that the implementation character set includes the decimal digits, the 26 alphabetic characters of English, and some of the basic punctuation characters. Values of particular characters are typically represented by constant character literals enclosed in single quotes. Each literal has an integer value. For example, the value of 'b' is 98 in the ASCII character set. Here is a small program that will tell you the integer value of any character you care to input: #include <iostream> void main() { char c; std::cin >> c; std::cout << "the value of '" << c << "' is " << int( c ) << '\ n'; } In this example, expression int( c ) gives the integer value for a character c. |
Again, a character literal, often called a character constant, is a character enclosed in single quotes, for example, 'a' and '0'. The type of a character literal is char. Such character literals are really symbolic constants for the integer value of the characters in the character set of the machine on which the C++ program is to run. For example, if you are running on a machine using the ASCII character set, the value of '0' is 48 . The use of character literals rather than decimal notation makes programs more portable. A few characters also have standard names that use the backslash \ as an escape character. For example, \n is a newline and \t is a horizontal tab. |
Like char, each integer type comes in three forms: "plain" int, signed int, and unsigned int. In addition, integers come in three sizes: short int, "plain" int, and long int. |
There are four kinds of notations for integer literals: decimal, octal, hexadecimal, and character literals. Decimal literals are the most commonly used and look as you would expect them to: 0, 123, 4976, and so on. A literal starting with zero followed by x, 0x is a hexadecimal (base 16) number. A literal starting with zero followed by a digit is an octal (base 8) number. For example:
As we already know from the previous lecture, letters a, b, c, d, e, and f or their uppercase equivalents represent decimal numbers 10, 11, 12, 13, 14, and 15, respectively. Octal and hexadecimal notations are most useful for expressing bit patterns. |
The floating-point types represent floating-point numbers. Please follow this link to read more about floating-point types and floating-point literals. |
Sizes of C++ types and variables are expressed in terms of multiples of the size of a char, so by definition the size of a char is 1. The size of an object or type can be obtained using the sizeof operator: #include <iostream> void main() { std::cout << "sizeof( char )==" << sizeof( char ); } This is what is guaranteed about sizes of fundamental types: 1 = sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) 1 <= sizeof(bool) <= sizeof(long) sizeof(float) <= sizeof(double) <= sizeof(long double) Assuming the scale 5 bytes = 1 inch, a megabyte of memory would stretch about three miles. |
In C++, all variables must be declared before they can be used. Declaration announces the properties of the new variable. Each declaration consists of a type name and a variable name. Multiple comma-separated names of variables may appear in a single declaration. However, this practice is not advisable, since program could quickly become difficult to read: int counter, month, day, year; Better: int counter; int month; int day; int year; Declarations may also have initializers to provide initial values: int counter = 1000; // Create variable and assign initial value of 1000 const double pi = 3.1415926535897932385; In contrast to a "variable", keyword const creates a constant value. For constants, the "value" is permanent, which means that the program cannot change it. Therefore, declaration initializer is the only way to provide a value for a constant. A variable name (identifier) consists of a sequence of letters, digits, and underscore characters. The first character must be a letter or underscore. Names starting with an underscore are reserved for system use, so such names should be avoided in application programs. Uppercase and lowercase letters are distinct, so Count and count are two different names. It is unwise to choose names that differ only by capitalization. In general, it is best to avoid names that differ only in subtle ways. Single-letter names are a very poor choice, too. Some names could create significant readability problems: O // is this a zero or an uppercase letter 'O' ? l // is this a lowercase 'L' or a digit '1' ? Names from a large scope ought to have relatively long and reasonably obvious names, such as department_number, or phone_book. It is important to maintain a consistent naming style in your programs. Throughout this course, we will re-visit this topic a few times. |
Each declaration introduces a variable into a specific part of the program. Accessibility (or visibility) of a variable from different parts of the program introduces an idea of a variable scope. Variables declared outside of functions are called global variables. Such variables belong to the global scope: int count; void main() { count = count + 1; } As demonstrated by the above example, global variables are visible inside any function. Global scope is a namespace, that is, an encapsulation of names. Global variables are initialized to zero by the compiler. Alternatively, a variable declared inside a function is said to be a local variable: void main() { int count; count = 1000; } Local variables are visible only inside the function. Localization is not limited only to the functions. Even smaller scopes may exist. For example, #include <iostream> void main() { int count = 10; while ( count > 0 ) { int var = -count; std::cout << var; count = count - 1; } }
This program prints |
Initializers of local variables are executed whenever the thread of control passes through the declaration. The reason for allowing declarations wherever a statement can be used is to minimize the errors caused by uninitialized variables. There is rarely a reason to introduce a variable before there is a value for it to hold. The most common reason to declare a variable without an initializer is that it requires a separate statement to initialize it. Examples are input variables: #include <iostream> void main() { int number; std::cin >> number; std::cout << "You entered: " << number; } |
Arithmetic operators are:
Integer division (i.e., where both the numerator and the denominator are integers) yields an integer quotient; for example, the expression 7 / 4 evaluates to 1 and the expression 17 / 5 evaluates to 3. Note that any fractional part in integer division is discarded (i.e., truncated) and no rounding occurs. Modulus operator, %, yields the remainder after integer division. The modulus operator can be used only with integer operands. The expression x % y yields the remainder after x is divided by y. Thus, 7%4 yields 3 and 17%5 yields 2. Modulus helps determining whether one number is a multiple of another, and as a special case determining whether a number is odd or even. |
Relational operators provide means to making decisions:
Equality operators also provide means to making decisions:
Each C++ operator has a built-in, immutable property of associativity. Here are a few examples of left-to-right associativity: Some operators with left-to-right associativity:
In contrast, right-to-left associativity operators have the following forms: Some operators with right-to-left associativity:
WARNING: it is a common mistake to think that associativity rules define the order in which parts of the expression (i.e. subexpressions) will be evaluated. You cannot assume that there will be a common left-to-right order of evaluation. Why? Because without order restrictions compiler is capable to generate the most efficient, fast, better code. If you need to enforce the order of evaluation, use the parentheses to group subexpressions. The operators , (comma), && (logical and), and || (logical or) guarantee that their left-hand operand is evaluated before their right-hand operand. For example, b = ( a = 2, a + 1 ) assigns 3 to b . The second operand of expr1 && expr2 is evaluated only if its first operand is true. The second operand of expr1 || expr2 is evaluated only if its first operand is false; this is sometimes called short-circuit evaluation. Short-circuiting should be considered very carefully if your expressions have side effects, such as increment or decrement of a variable. Parentheses can be used to force both grouping and order of evaluation. For example, a * b / c means ( a * b ) / c
so parentheses must be used to get |
Decision Making: arithmetic if
|
The assignment operator = assigns a value to a variable. For example, x = 1 sets x to 1, and a = b sets a to whatever b's value is. Any time there is a pattern variable = variable operator expression
where variable operator= expression For example, you can replace the expressions i = i + 1 j = j - 10 k = k * (n + 1) with i += 1 j -= 10 k *= n + 1 Please note that you don't always need as many explicit parentheses when using the arithmetic assignment operators: the expression k *= n + 1 is interpreted as k = k * (n + 1) |
When we are adding or subtracting the constant 1 from a variable, C++ provides an extremely useful set of shortcuts: the increment and decrement operators. In their simplest forms, they look like this: ++i; // add one to i --j; // subtract one from j These expressions correspond to their longer equivalents, i += 1; // or even longer form i = i + 1 j -= 1; // or even longer form j = j - 1 The ++ and -- operators apply to one operand. Therefore, they are unary operators. The expression ++i adds 1 to i, and stores the incremented result back in i. This means that increment and decrement operators don't just compute new values; they also modify the value of the variable. Consequently, increment and decrement share common property with assignment operators, that is, they modify the variable. We may say that these operators all have side effects. That is, besides the fact that a new value (i + 1) is being computed and returned as a result of the expression ++i, the side effect is also that the new value is being implicitly assigned to the variable i. In contrast, the expression (i + 1) clearly has no side effects. The incremented or decremented result is made available to the rest of the expression, so an expression like a = ++i; means "add one to i, store result in i, and assign i to a:" i = i + 1, a = i; Both the ++ and -- operators have an unusual property: they can be used in two ways, depending on whether they are written to the left or the right of the variable they're operating on. In either case, they increment or decrement the variable they're operating on; the difference concerns whether it's the old or the new value that is returned to the surrounding expression. The prefix form ++i increments i and returns the incremented value. The postfix form i++ increments i, but returns the prior, non-incremented value. A rewrite of the previous example, a = i++; means "assign i to a, add one to i, and store result in i:" a = i, i = i + 1; The distinction between the prefix and postfix forms of ++ and -- probably seems strange at first, but it will make more sense once we begin using these operators in more realistic situations. The increment ++ and decrement -- operators must be used in conjuction with modifiable values, such as variables. For example, the following statement will not compile: a = ++( x + y ); // *** will result in compiler error The programmer has probably intended to write a = x + y + 1; |
|