In the previous unit, you learned how to pass data between functions. Passing data around is an important requirement in Visual C++ programming. As you continue, you will see another method by which you can return a value to the calling function. Then
you will explore the restrictions of type safety, and look at the way C++ provides special features to enable you to work safely and easily with different types.
Often you will want to make functions multipurpose. C++ recognizes this by giving you default parameters, which are a great way to avoid unwieldy parameter lists.
The return statement gives your functions the capability to return a single value from a called function.
You've already seen the passing of data to a function. Using the return statement, you can see how to return a value back to the calling function. Every program in this book has used the return statement at the end of main(). The return
command can also take a value:
return 1;
Sometimes, Visual C++ programmers put the return value in parentheses:
return (0);
You can return, at most, one value from a function! As Figure 14.1 shows, you can pass several parameters to a function, but you can return only one.
Figure 14.1. At most, you can return only a single value.
Although Figure 14.1 contains an outline of two functions, you can see that the calling function's function call looks unlike any you've seen so far. Instead of calling AFunction() on a line by itself,
AFunction(a, b, c);
main() assigns AFunction to a variable like this:
value = AFunction(a, b, c);
The assignment is needed to hold AFunction()'s return value. In other words, when a function returns a value, you should have some way to capture that return value.
If a function returns a value, the calling function doesn't have to capture the value. However, although the calling function can ignore the return value, a return value must always be provided.
Before you look at a program that uses a return value, there's one more thing you should know. If a function returns a value, you must tell Visual C++ what kind of value that function is returning. Put the return value data type before the function
name. If a function isn't going to return a value, you must put void before the function name.
Therefore, you know from the following function definition, without looking at its return statement, exactly what kind of data the function returns:
double FunctionA(int i, float j)
This function returns a double value. The return data type appears on the same line as the function definition so that you can specify the return data type in the prototype as well. Here is the prototype for the preceding function:
double FunctionA(int i, float j);
If you don't specify a return value, Visual C++ assumes that you're returning an integer. Therefore, the following function prototypes are identical:
int Compute(int age, float factor);
Compute(int age, float factor); // Assumed to return an int
However, C++ syntax is confusing enough without leaving such things to memory. (You would probably guess that the default was void and be puzzled as to why the compiler threw an error on a return statement without a value.) Therefore, C++ programmers
always specify the return type, even if it is int.
Because you can write a program that can return a value using a reference or address of parameter, you might wonder why you would bother with a return value. The answer is that it is very handy to be able to call functions in the middle of a
calculation, or even in a parameter list. For example, imagine that the POOL.CPP program in the previous unit (Listing 13.6) had a CalcArea function. In that case, CalcCubic could be written like this:
// CalcArea function int CalcArea(int length, int width) { return (length * width); } // new CalcCubic void CalcCubic(int length, int width, int depth, int &cubic) { cubic = CalcArea(length,width) * depth; return; }
Note that the return value can be an expression and that the function can be used exactly like a variable (though you cannot assign into a function return value). You can use the return value of a function as an argument to another function:
int CalcArea(int length, int width) { return (length * width); } // another CalcCubic int CalcCubic(int area, int depth) { return area * depth; } void main() { cout << "Cubic is " << CalcCubic(CalcArea(5,4),5); }
You have to carefully count the parentheses to follow this. Visual C++ will first work out all the functions in the argument list before continuing with the function call.
You can have more than one return statement in a function. This can pass different values back as long as the types match the return type.
Listing 14.1 contains a program that uses three functions (including main()). The first function that main() calls asks for the user's name, and the second calculates the number of years left until the user's retirement.
The passing and returning of data provide Visual C++'s vehicle for sharing data. You can pass data by value or by address. The method you use depends on whether you want the receiving function to be able to change the calling function's variables.
1:// Filename: PASSRET.CPP 2:// Program that passes by value and by address. 3:// This program also demonstrates prototypes and 4:// how to return a value from one function to 5:// the calling function. 6:#include <iostream.h> 7: 8:void GetUserName(char userName[50]); 9:int ComputeRetire(int age); 10: 11:void main() 12:{ 13: char userName[50]; 14: int age = 0; 15: int yearsToRetire = 0; 16: 17: GetUserName(userName); // Fill the array in the function 18: 19: cout << "How old are you, " << userName << " ?"; 20: cin >> age; 21: yearsToRetire = ComputeRetire(age);// Pass and return values 22: 23: cout << "You have " << yearsToRetire 24: << " years until retirement at 65" << endl; 25: 26: return; 27:} 28://********************************************************** 29:void GetUserName(char userName[50]) // 50 is optional here 30:{ 31: cout << "What is your name? "; 32: cin.getline(userName,50); 33: return; // No need to return anything 34:} 35://********************************************************** 36:int ComputeRetire(int age) 37:{ 38: return (65 - age); // Return the number of years until 65 39:}
Output
What is your name? Andy Smith How old are you, Andy Smith? 40 You have 25 years until retirement at 65
Analysis
Lines 8 and 9 contain prototypes for the two functions that follow main(). Always put main() first in your programs. Not only is main() executed first, but other Visual C++ programmers who might maintain your programs expect main() to appear first.
In line 17, main() calls the next function in the program, GetUserName(). main() passes the character array to this function so that the function can fill the array. Visual C++ receives all arrays by address, so when the user enters a value into the
array within the GetUserName() function, main()'s array also gets filled at the same time. When you pass an array, a copy of the array values doesn't get sent. Instead, Visual C++ passes the actual array.
The cout in line 19 shows that the user's name resides in main()'s array when GetUserName() returns control to main(). After the user enters his or her age, main() passes the age in line 21 to the ComputeRetire() function. The body of ComputeRetire()
consists of a single statementthe return statement on line 38that computes the number of years until the user reaches 65. As you can see from line 38, you can return an expression from a function instead of a single variable if you choose.
There is no reason for main() to pass age by address to ComputeRetire(), because ComputeRetire() doesn't need to change main()'s age value. It only uses age to compute the retirement years. You won't find any global variables in Listing 14.1 because
they're not needed. There is rarely ever a need for them.
Definition
const means the value cannot be changed.
const parameters enable you to stop the function changing values of arguments even if passed by reference or by address.
In the last unit, you saw that arrays were passed by address; therefore, the called function was allowed to change the value of the passed array. There are two places where this could mean trouble:
If the program was allowed to pass a const value to a function, the "unchangeability" of a const would be broken. Worse, a literal only exists as a piece of text in your program. How could the compiler change it?
void PrintIntRef(int & i); void main() { PrintIntRef(1); // error C++ cannot change 1
C++ has a simple rule: You can't pass constant values to a nonconstant parameter. A pass by value parameter is a constant parameter, so that is not a problem. However, a pass by address or pass by reference parameter means that the calling value can be
changed. By declaring the parameter const, you can tell C++ that although you pass by address or reference, you promise that the called function will not change the argument's value. In fact, Visual C++ then won't let you write code that changes the value
in the called function because it treats the parameter as a const that is initialized with the argument value. When you declare a const parameter, Visual C++ can automatically treat a non-const value as a const value. You declare a const parameter as
follows:
void PrintIntRef(const int& printValue);
This means that it will not change printValue even though it is passed the real printValue, not a copy. Similarly,
void PrintString(const char str[]);
tells the programmer that the string will not change when the array is passed.
The real benefit of this to a programmer is that you can use routines that someone else has written and know which parameters might be changed by the routine and which might not. You saw in the last unit that a pass by value parameter did the same job.
When passing large amounts of data, it is more efficient to pass by reference. Of course, you don't have the choice with an array; they are always passed by address.
Listing 14.2 shows how you can use const to tell the rest of the program that you are being careful not to change array data.
1:// Filename: INITIALS.CPP 2:// Shows a routine that given a name 3:// finds the initials 4:// 5: 6:#include <string.h> // header for strlen function 7:#include <iostream.h> 8: 9:// GetInitials prototype: returns 1 if successful, 10:// 0 if fails 11:int GetInitials(char initials[],const char name[]); 12: 13:void main() 14: { 15: char initials[15] = ""; // Allow for silly strings 16: char name[30] = ""; 17: while (1) // Do forever 18: { 19: cout << "Type name, (0 to quit): "; 20: cin.getline(name,30); 21: if (name[0] == '0')// Stop when the user asks 22: break; 23: 24: // 25: // Extract the initials, and report if error 26: // 27: if (GetInitials(initials,name)) 28: { 29: cout << "The initials for '" << name 30: << "' are: '" << initials << "'" << endl; 31: } 32: else 33: { 34: cout << "Something wrong with '" 35: << name << "'" << endl; 36: } 37: } 38: } 39://*********************************************************** 40:int GetInitials(char initials[],const char name[]) 41: { 42: int count = 0; 43: int initialCount = 0; 44: 45: int length = strlen(name); 46: if (length == 0) // error if no string 47: return 0; 48: 49: while (count < length) 50: { 51: while (count < length 52: && name[count] == ' ') 53: count++; 54: if (count < length) 55: { 56: initials[initialCount] = name[count]; 57: initialCount++; 58: count++; 59: } 60: while (count < length 61: && name[count] != ' ') 62: count++; 63: } 64: initials[initialCount] = '\0';// Ensure terminated string 65: return (initialCount > 0); // Success if found 66: // one or more initials 67: }
Output
Type name, (0 to quit): Gary Smith The initials for 'Gary Smith' are: 'GS' Type name, (0 to quit): Stefan Winman The initials for 'Stefan Winman' are: 'SW' Type name, (0 to quit): Kenneth Lee Michael Noble The initials for 'Kenneth Lee Michael Noble' are: 'KLMN' Type name, (0 to quit): Something wrong with ' ' Type name, (0 to quit): 0
Analysis
The GetInitials prototype in line 11 tells the programmer a lot about the function without needing much explanation. GetInitials tells what the function does, the non-const character array called initials is a big clue that the result is returned into
the first parameter, and the second parameter is a clue that the name to be examined should be passed in the second parameter. It is not clear what the returned int is for, so this is documented by way of a comment in lines 9 and 10.
The program simply loops, asking for input and processing the result. In line 17, there is an odd statement, while(1). This means the loop will never end. Fortunately, the programmer has done this deliberately and has remembered to put a test in line 21
to stop the loop if the user enters a 0.
The call in line 27 is a typical C++ statement when a function returns success or failure. Remember that the if statement tests the expression to see whether it is zero or nonzero. The GetInitials function has been written to return a value that says
whether the function worked, and the if statement can easily test this value. It does not have to be stored somewhere first. Would the following have been more clear?
if (GetInitials(initials,name) != 0)
Using the result, the program can put out an error message or the answer as appropriate.
The function definition in line 40 tells the programmer that he can pass any length of string to the program because the special [] notation has been used for the array. Lines 45 to 47 check that there is something worth processing, returning a failed
value if the sting length is zero.
In lines 49, 51, and 54, the program checks the length of the string before allowing the value of the character to be examined. This makes sure that the program does not fall off the end of the string. Remember that string lengths are a bit confusing.
The last real character of the string is at the string length - 1 position because the character arrays start at zero.
The while loop in line 49 ensures that each word is processed. For each word in the string, the loop in lines 51 to 53 skips any blanks (notice there are no brackets around line 53). In line 54, the program knows that there is either a nonblank
character or that the string is ended. If there is a valid character, this is stored away and the program moves on. In line 57, a count is maintained of how many initials have been found. In lines 60 to 62, the program skips forward through the word until
it finds a space or the end of string terminator. At this point, the main while loop decides whether to terminate on the end of string or to carry on with the next word.
In line 64, you must make sure that the initials result is a valid string by placing a terminator on the end. In line 65, there is a simple test on the initialCount. If there were no initialsfor example, in a blank stringthe test would be
false and the test would evaluate to a 0. Otherwise, the test would be true and 1 would be returned.
Definition
Typesafe means that C++ stops mistakes caused by mixing up different types.
Visual C++ typing means that you have to be careful about the arguments you pass to parameters.
To understand how Visual C++ works with parameters, you need to do some revision on C++'s typing mechanism. Remember that C++'s main aim of typing is that you cannot accidentally assign a variable of one type into another. To be friendly, C++ does know
that some type conversions are safe and performs them automatically, and also provides the casting mechanism to enable the programmer to force the language to change types. When passing by value, C++ has an easy job. All it needs to do is create a
temporary value of the right type if the argument and parameter are different types. If C++ knows how to convert one type to another (such as an int to a float), it can do so. When passing by reference, things get more complicated. In the last unit, you
saw that when passing a reference, the parameter used is actually the argument passed, not a copy. This means that C++ has a problem when a reference parameter is of a different type than that of an argument passed to it. Consider this example:
#include <iostream.h> void PrintInt(int i); void PrintIntRef(int & i); void main() { float value = 19.99 PrintInt(value); // ok, but will lose decimals PrintIntRef(value); // Error! }
C++ does not need to see the body of PrintIntRef to know it has trouble. It must use an int in PrintIntRef when it is being handed a float. Even the explicit cast
PrintIntRef((int)value);
will not do the trick. C++ must have an int. One solution is to make a temporary value. Another solution is to consider why you are trying to print a float with an int printing function, which is a nasty mistake. Or another solution is to write a
PrintFloatRef function.
Visual C++ enables you to have more than one function with the same name using function overloading.
C++ needs different functions to deal with different types. This is not a big deal because different types might need different code, but it is difficult trying to invent names to deal with the different combinations of types. Imagine that you have a
print function that codes the cout statements for a different number of decimal places for float and doubles. (Remember that a double is like a float, except it can hold more digits of precision.) You would have to code the following:
void PrintFloat(float outputNumber,int decimalPlaces) { cout.precision(decimalPlaces); cout.setf(ios::showpoint); cout.setf(ios::fixed); cout << outputNumber; }
And, similarly, the following:
void PrintDouble(double outputNumber,int decimalPlaces) // same code as before
Inventing names for these examples is easy. But what if several parameters need handling in this different way? C++ has a handy mechanism called function overloading. This enables you to use the same name for more than one function. Visual C++ tells
them apart by looking at the function signature. The function signature is the name of the function and the type of each parameter. It does not include the return type, so you cannot have a function that returns a different type with the same
parameter list. For example,
void Print(int value); void Print(float value);
are allowed to be declared in the same program. When you call these functions, Visual C++ looks at the type of the argument to decide which function to call. So, given the previous functions, the code snippet that follows needs to sort out which version
to call.
void main() { int i = 5; float f = 1.25; Print(i); // calls Print(int) Print; // calls Print(float) Print((int)f); // calls Print(int)
The calls get sorted out by looking at the type of the arguments.
You do not even need the same number of parameters in the different function declarations. Remember the pool calculation? You could develop a CalcCubic that takes three dimensions, or you could use an area and another single dimension like this:
int CalcCubic(int length, int width, int depth); int CalcCubic(int area, int depth); void main() { int area = 50; int aveDepth = 5; int cube = CalcCubic(area,aveDepth); // Second version called as only two int arguments
The great thing about overloading is that you can have lots of functions that do the same thing to different parameters. However, you must be careful to not use the same name for different functions that do different things. Normally, if you choose a
vague name, it will not be clear what the function does, and the programmer calling the function might be surprised when the expected function does not happen:
// Calculate the area of a cicle int Circle(int radius); // Calculate the area of a rectangle int Rectangle(int length, int width); // Print a rectangle int Rectangle(int left, int top, int right, int bottom);
The programmer writing a geometry calculation might use the circle area function and be surprised that the second Rectangle function does not calculate the area of a rectangle as well.
Definition
A default parameter specifies what value should be used if an argument is missing.
Use default parameters to simplify parameter lists and combine similar functions.
Default parameters are to C++ functions what automatic gear selection is to a car. You can leave C++ to decide what value a parameter can have, or you can fiddle around with the call and give it a specific value, just as you can leave an automatic
gearbox in drive or choose a specific gear with the gear shift.
Why would you want to do this? Often, you want to write functions that are similar except for some optional features. These optional features might need extra data (that means new parameters for a function) so that the new features can work. There is no
problem adding extra parameters, but they are a nuisance to provide if you do not want them. Here is how you declare a default parameter:
int CalcCubic(int length, int width, int depth = 5);
This means that depth, when not explicitly stated, will be 5. The default value should only be specified once, and specification should be in the function prototype so that the calling functions know about the default. The following calls produce the
same result:
cube = CalcCubic(10,6,5); cube = CalcCubic(10,6);
There is a simple rule for default parameters: After a parameter is defaulted, all of the following parameters in the function call must be defaulted. This means that you are not allowed to declare
int Cubic(int length, int width = 5, int depth); // Wrong!
because you would still have to supply a value for depth when trying to default width. When putting several defaults into a parameter list, the order of parameters is decided by how frequently you expect to omit the parameter.
For example, you might develop your specialized floating point printing routine so that it automatically prints out two decimal places unless there is a special requirement:
void Print(float value, int noOfDPs = 2); main() { float length = 12.25F; float width = 5.50F; float depth = 4.75F; Print(length); Print(width); Print(depth); float cube = CalcCube(length,width,depth); Print(cube,6); // six places for full accuracy
You can also use a default parameter to control function logic. If a function needs to do nothing most of the time, the default parameter can be used with a value that says "do nothing." Then when the programmer needs the special situation,
the parameter can be set as in the following example:
float CalculateTax(float pay, int promptForRate = 0) { if (promptForRate) { cout << "What is tax rate?"; cin >> taxRate; } else { taxRate = 0.25; } // Calculate tax }
This routine might have been designed to be used as a routine to calculate tax in a standard way, or if the programmer chooses, the routine can be used to ask for a tax rate if a nonzero value has been set.
There is a useful trick for pass by address parameters that you can use. If you want an optional pass by address parameter, you can set a default value of 0. In your called routine, you can test the parameter itself (not the dereferenced value) to see whether it has been set. Here's an example:
void Default(int * i = 0, const char str[] = 0); void main() { Default(); Default(23,"Hello World!"); } void Default(int * i,const char str[]) { if (i == 0) // test address of i not *i { // No i parameter // (and cannot be a str either - why?) } if (!str) // another way of testing for zero { // no str parameter } }
Definition
Argument matching is the process C++ uses to determine which version of an overloaded function to call.
Definition
An overloaded function is more than one function with the same name with different parameter lists.
C++ has a sequence for parameter matching to decide which overloaded function to call.
You can't declare two functions with the same parameter list, but what happens in the following case?
void Print(float value, int dps = 2); // specify precision void Print(float value); // standard cout print
The compiler will accept these declarations as different. When you call the first example with Print(value,5), the compiler can see which version you wanted by the two parameters. But if the program calls Print(value), there would be a problem. The call
would be ambiguous; Visual C++ would not know whether you meant to call the first Print with a default of 5 or the second version with no parameter. Visual C++ makes the decision easy for itself, in that case. It will not use either version, and it
tells you at compile time that it can't tell the calls apart. In this example, either the two functions do the same thing and the second version is redundant, or the one version should be renamed.
Now consider a trickier example. C++ automatically converts types if it cannot find a match. It searches for the next best function to call, if any. So, if you have
void Print(int); void main() { Print(3.3F); // Pass a float
and you pass Print(int) a float, C++ automatically converts the value to a float.
Add a Print(char):
void Print(int); void Print(char); void main() { Print(3.3F); // Pass a float
C++ first checks to see whether there is a function that is an exact match. If there is not, it checks for all possible functions to which it can convert the number. Perhaps surprisingly, C++ can change a float to a char as well as to an int. (Remember
that a char is almost like an int.) When it tries to match your call to Print with a float, C++ can't guess which version you really meant:
void Print(int){} void Print(char){} int main() { float f = 4.5; Print(1); // OK, 1 is type int Print('C'); // OK, 'C' is a char Print; // Ambigous, can convert to either Print("Hello World!"); // Error! no match at all for char[] Print((int)f);// OK, cast tells C++ which version to use }
C++ has a lot of work to do to sort out how to match parameter lists with defaults and type conversions. What C++ does is work through a sequence:
Don't worry about this last step; it's only included here for completeness. The important message is that you can sort out an ambiguous function call by using a cast to force a parameter to be an exact match, but only if the function signature itself is
not ambiguous.
The process becomes even more complicated with multiple parameters, but basically if it does not find an exact match, it looks at all the nearest matches and chooses the function where the most parameters match exactly. The exact rules are very
complicated, but C++ programmers should avoid writing overloaded functions with only slightly different parameter lists, so normally the match is quite easy to find.
Here is something for you to think about. In C++, the operators such as +, -, and << can be thought of as functions. Can you see that cout overloads the << operator function to work with different types?
In Listing 14.3, you see an example of using overloaded functions and defaults.
1:// File : OVERLOAD.CPP 2:// Demonstration of overloading and defaults. 3:// in a program that prints loan repayments 4:#include <iostream.h> 5: 6: 7:const int TRUE = 1; 8:const int FALSE = 0; 9: 10:void Print(int i, int newline = FALSE); 11:void Print(float f, int newline = FALSE, int width = 5); 12:void Print(char str[],int newline = FALSE); 13: 14:void main() 15: { 16: float amount = 0; 17: float rate = 0; 18: float repayment = 0; 19: 20: Print("Enter amount to repay: "); 21: cin >> amount; 22: Print("Enter interest rate per annum: "); 23: cin >> rate; 24: 25: Print("Amount of loan: "); 26: Print(amount,TRUE); 27: Print("Interest rate: "); 28: Print(rate, TRUE); 29: Print("Repayment table", TRUE); 30: Print("---------------", TRUE); 31: Print("Months\tRepayment\tMonthly Amt",TRUE); 32: 33: // Print a table for 3 to 48 months in 3 monthly intervals 34: for (int months = 3; months <= 48; months+=3) 35: { 36: // Interest will be rate * months / 12 37: if (rate >= 0) 38: { 39: repayment = amount 40: + amount * rate * months / 12 / 100; 41: Print(months); 42: Print("\t"); 43: Print(repayment,FALSE,8); 44: Print("\t"); 45: // C++ will also recognize the type of an expression 46: Print(repayment / months,TRUE,8); 47: } 48: 49: } 50: return; 51: 52: } 53://************************************************************ 54:void Print(int i, int newline) 55: { 56: cout << i; 57: if (newline) 58: cout << endl; 59: } 60://************************************************************ 61:void Print(float f, int newline,int width) 62: { 63: cout.precision(2); 64: cout.setf(ios::showpoint); 65: cout.setf(ios::fixed); 66: cout.width(width); 67: cout << f; 68: if (newline) 69: cout << endl; 70: } 71://************************************************************ 72:void Print(char str[], int newline) 73: { 74: cout << str; 75: if (newline) 76: cout << endl; 77: }
Output
Enter amount to repay: 6000 Enter interest rate per annum: 6.5 Amount of loan: 6000.00 Interest rate: 6.50 Repayment table --------------- Months Repayment Monthly Amt 3 6097.50 2032.50 6 6195.00 1032.50 9 6292.50 699.17 12 6390.00 532.50 15 6487.50 432.50 18 6585.00 365.83 21 6682.50 318.21 24 6780.00 282.50 27 6877.50 254.72 30 6975.00 232.50 33 7072.50 214.32 36 7170.00 199.17 39 7267.50 186.35 42 7365.00 175.36 45 7462.50 165.83 48 7560.00 157.50
Analysis
In lines 10 to 12, the prototypes for the overloaded Print functions are declared. These also use an extra parameter to enable the programmer to easily code when newlines are to be inserted in the output.
The main body of the code, starting at line 14, asks the user some questions and reports the answers in a neat form to confirm that the program has understood the input. In lines 25 to 31, the char[] and float versions of Print are called, with some
skipping lines and some not.
The main for loop that starts in line 34 drives a listing of repayments over three monthly intervals up to 48 months. In line 41, it calls the int version of Print.
Perhaps the more difficult one to recognize is which version is called in line 46. The rules of the expression are that the type of an expression is expanded to the biggest type of the values in the expression. So, just as repayment is a float, the
result of the expression is a float, even though months is an int.
Even if the expression had been an int, the same function would have been called. Why? The rules on parameter matching say that there is no exact match for a Print function with three parameters, but no other version of Print has three parameters.
Automatically converting an int to a float allows Visual C++ to come up with a good match of the arguments given to it. Visual C++ would not try to match to the Print(int,int) version because of the extra parameter.
This lesson began with a discussion on structured programming, and it is going to end with one! Now you can see how you can break up a large program into lots of small ones. You have a technique for breaking a big problem into lots of small problems,
and you can solve lots of small problems quicker than one big problem.
When you write a program, you can quickly draft an outline of what it should do by writing a main() that simply consists of function calls. Function by function, you can then decide the detail of how each function performs its task (perhaps even
breaking down the called functions into several functions themselves). Often you can decide at the high level what parameters the functions will need. This top-down programming technique enables you to concentrate on a sensible structure to your code. If
you just start at the beginning and work to the end, you are more likely to end up with a heap of spaghetti code, because you will not have considered properly how a big function can be broken down.
For really complicated programs, you can write dummy functions that do nothing except assign sensible return values and perhaps a comment as to what they are supposed to do. This means that you do not always have to write all the code before you can
start testing your program. This technique is called stepwise-refinement, making your program more detailed step by step.
This lesson began by separating a payroll program into different functions. This lesson's project contains the full code and a description of the program.
main() functions function prototypes includes
The following two questions contain complete programs. Look at the programs and decide what the output should be. You should note which version of the overloaded functions is called and why.
#include <iostream.h> #include <string.h> void Replace(char str[]) { strcpy(str,"Hello World!"); } void Replace(int i) { i = 99; } void main() { int j = 50; char hi[30] = "Hi there!"; Replace(j); Replace(hi); cout << hi << endl << j; }
#include <iostream.h> void Print(int i); void Print(float f, int skip = 0); void main() { float f = 3.3; Print; } void Print(int i) { cout << "Integer" << endl; } void Print(float f, int skip) { cout << "Float"; if (skip != 0) cout << endl; }
#include <iostream.h> void Print(int i); void Print(float f, int skip = 0); void main() { Print(3.3); } void Print(int i) { cout << "Integer" << endl; } void Print(float f, int skip) { cout << "Float"; if (skip != 0) cout << endl; }
#include <iostream.h> #include <string.h> int NameLength(const char name[]); void main() { char testName[30] = "Philippa Spencer"; int length = NameLength(testName); cout << testName << " " << length; } int NameLength(const char name[]) { // Suzi's change strcpy(name,"Philippa is silly"); // End of Suzi's change int count = -1; while (name[++count]); return count; }
event(int a);