First, the program passes the int value of 2 to cube(), which expects type double. The compiler, noting that the cube() prototype specifies a type double argument, converts 2 to 2.0, a type double value. Then cube() returns a type double value (8.0) to be used as an argument to cheers(). Again, the compiler checks the prototypes and notes that cheers() requires an int. It converts the return value to the integer 8. In general, prototyping produces automatic type casts to the expected types. (Function overloading, discussed in Chapter 8, can create ambiguous situations, however, that prevent some automatic type casts.)
Automatic type conversion doesn’t head off all possible errors. For example, if you pass a value of 8.33E27 to a function that expects an int, such a large value cannot be converted correctly to a mere int. Some compilers warn you of possible data loss when there is an automatic conversion from a larger type to a smaller.
Also prototyping results in type conversion only when it makes sense. It won’t, for example, convert an integer to a structure or pointer.
Prototyping takes place during compile time and is termed
Function Arguments and Passing by Value
It’s time to take a closer look at function arguments. C++ normally passes arguments
double volume = cube(side);
Here side is a variable that, in the sample run, had the value 5. The function header for cube(), recall, was this:
double cube(double x)
When this function is called, it creates a new type double variable called x and initializes it with the value 5. This insulates data in main() from actions that take place in cube() because cube() works with a copy of side rather than with the original data. You’ll see an example of this protection soon. A variable that’s used to receive passed values is called a
Figure 7.2. Passing by value.
Variables, including parameters, declared within a function are private to the function. When a function is called, the computer allocates the memory needed for these variables. When the function terminates, the computer frees the memory that was used for those variables. (Some C++ literature refers to this allocating and freeing of memory as
Figure 7.3. Local variables.
Multiple Arguments
A function can have more than one argument. In the function call, you just separate the arguments with commas:
n_chars('R', 25);
This passes two arguments to the function n_chars(), which will be defined shortly.
Similarly, when you define the function, you use a comma-separated list of parameter declarations in the function header:
void n_chars(char c, int n) // two arguments
This function header states that the function n_chars() takes one type char argument and one type int argument. The parameters c and n are initialized with the values passed to the function. If a function has two parameters of the same type, you have to give the type of each parameter separately. You can’t combine declarations the way you can when you declare regular variables:
void fifi(float a, float b) // declare each variable separately
void fufu(float a, b) // NOT acceptable
As with other functions, you just add a semicolon to get a prototype:
void n_chars(char c, int n); // prototype, style 1
As with single arguments, you don’t have to use the same variable names in the prototype as in the definition, and you can omit the variable names in the prototype: