2.3 Procedural Programming
The original programming paradigm is as follows:
Decide which procedures you want; use the best algorithms you can find.
The focus is on the processingthe algorithm needed to perform the desired computation. Languages support this paradigm by providing facilities for passing arguments to functions and returning values from functions. The literature related to this way of thinking is filled with discussion of ways to pass arguments, ways to distinguish different kinds of arguments, different kinds of functions (such as procedures, routines, and macros), and so on.
A typical example of "good style" is a square-root function. Given a double-precision floating-point argument, it produces a result. To do this, it performs a well-understood mathematical computation:
double sqrt(double arg) { // code for calculating a square root } void f() { double root2 = sqrt(2); // ... }
Curly braces, { }, express grouping in C++. Here, they indicate the start and end of the function bodies. The double slash, //, begins a comment that extends to the end of the line. The keyword void indicates that a function does not return a value.
From the point of view of program organization, functions are used to create order in a maze of algorithms. The algorithms themselves are written using function calls and other language facilities. The following subsections present a thumbnail sketch of C++'s most basic facilities for expressing computation.
2.3.1 Variables and Arithmetic
Every name and every expression has a type that determines the operations that may be performed on it. For example, the declaration
int inch;
specifies that inch is of type int; that is, inch is an integer variable.
A declaration is a statement that introduces a name into the program. It specifies a type for that name. A type defines the proper use of a name or an expression.
C++ offers a variety of fundamental types, which correspond directly to hardware facilities. For example:
Type |
Description |
bool |
Boolean, possible values are true and false |
char |
character, for example, 'a', 'z', and '9' |
int |
integer, for example, 1, 42, and 1216 |
double |
double-precision floating-point number, for example, 3.14 and 299793.0 |
A char variable is of the natural size to hold a character on a given machine (typically a byte), and an int variable is of the natural size for integer arithmetic on a given machine (typically a word).
The arithmetic operators can be used for any combination of these types:
Operator |
Description |
+ |
plus, both unary and binary |
- |
minus, both unary and binary |
* |
multiply |
/ |
divide |
% |
remainder |
So can the comparison operators:
Operator |
Description |
== |
equal |
!= |
not equal |
< |
less than |
> |
greater than |
<= |
less than or equal to |
>= |
greater than or equal to |
In assignments and in arithmetic operations, C++ performs all meaningful conversions between the basic types so that they can be mixed freely:
void some_function() // function that doesn't return a value { double d = 2.2; // initialize floating-point number int i = 7; // initialize integer d = d+i; // assign sum to d i = d*i; // assign product to i }
As in C, = is the assignment operator and == tests equality.
2.3.2 Tests and Loops
C++ provides a conventional set of statements for expressing selection and looping. For example, here is a simple function that prompts the user and returns a Boolean indicating the response:
bool accept() { cout << "Do you want to proceed (y or n)?\n"; // write question char answer = 0; cin >> answer; // read answer if (answer == 'y') return true; return false; }
The << operator ("put to") is used as an output operator; cout is the standard output stream. The >> operator ("get from") is used as an input operator; cin is the standard input stream. The type of the right-hand operand of >> determines what input is accepted and is the target of the input operation. The \n character at the end of the output string represents a newline.
The example could be slightly improved by taking an 'n' answer into account:
bool accept2() { cout << "Do you want to proceed (y or n)?\n"; // write question char answer = 0; cin >> answer; // read answer switch (answer) { case 'y': return true; case 'n': return false; default: cout << "I'll take that for a no.\n"; return false; } }
A switch-statement tests a value against a set of constants. The case constants must be distinct, and if the value tested does not match any of them, the default is chosen. The programmer need not provide a default.
Few programs are written without loops. In this case, we might like to give the user a few tries:
bool accept3() { int tries = 1; while (tries < 4) { cout << "Do you want to proceed (y or n)?\n"; // write question char answer = 0; cin >> answer; // read answer switch (answer) { case 'y': return true; case 'n': return false; default: cout << "Sorry, I don't understand that.\n"; tries = tries + 1; } } cout << "I'll take that for a no.\n"; return false; }
The while-statement executes until its condition becomes false.
2.3.3 Pointers and Arrays
An array can be declared like this:
char v[10]; // array of 10 characters
Similarly, a pointer can be declared like this:
char* p; // pointer to character
In declarations, [] means "array of" and * means "pointer to." All arrays have 0 as their lower bound, so v has ten elements, v[0]...v[9]. A pointer variable can hold the address of an object of the appropriate type:
p = &v[3]; // p points to v's fourth element
Unary & is the address-of operator.
Consider copying 10 elements from one array to another:
void another_function() { int v1[10]; int v2[10]; // ... for (int i=0; i<10; ++i) v1[i]=v2[i]; }
This for-statement can be read as "set i to zero, while i is less than 10, copy the ith element and increment i." When applied to an integer variable, the increment operator ++ simply adds 1.