1 / 27

Introduction

Introduction. We’ve used functions (e.g. sin, sqrt) for some time now. So far, however, the functions we’ve used have always be written by somebody else. Now we’re going to learn how to write our own functions.

Download Presentation

Introduction

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Introduction We’ve used functions (e.g. sin, sqrt) for some time now. So far, however, the functions we’ve used have always be written by somebody else. Now we’re going to learn how to write our own functions. Actually we’ve already written functions without knowing it – “main” is an example of a function. It is invoked by the operating system and, when it returns, causes program execution as a whole to come to an end. Other functions are invoked when used in expressions, and when they return, simply cause expression evaluation to be resumed where it was left off.

  2. A Simple Example double square (double x) { // could be simplified to a single statement… double result; result = x * x; return result; } void main (void) { double value, answer; cout << “Enter a value: “; cin >> value; answer = square (value); cout << “The square of the value is “ << answer << endl; }

  3. Example Execution function square return result; Square returns. Execution of main resumes.. Execution of main suspended. Square started. function main answer = square(value); Program execution begins Program execution ends.

  4. Function Headers type name (type name, type name ….) name of function. The type of the result produced by executiing the function. May be “void”, which means that the function does not produce a result. The “parameter list”. Defines both the number of values that must be supplied in invoking the function and the types of values required. May be “void”, meaning that no values are to supplied. “void main (void)” can now be understood as meaning that main does not produce a result and requires no arguments (i.e. it simply starts and stops). “int main ()” (as in the textbook) means that main must produce an int value when it stops (hence “return 0”).

  5. Parameter Details Within a function, parameters are just like variables, the only difference being that, when a function is invoked, its parameters are initialitized with the values (“arguments”) used in invoking the function. int sample (int x, double y) { int b; double w; . . . } void main (void) { { . . . sample (r + 4, w * 7); } When “sample” is invoked, “x” is initialized with the value of “r + 4”, and “y” with the value of “w * 7”. Otherwise “x” and “y” are variables just as “b” and “w” are. Parameter list. Argument list

  6. Return Details “Return” means “end execution of function and return to where we came from”. Within the main function this translates to “stop program”. Elsewhere it equates to “resume execution of the function which called us”. If a function is supposed to return a value (return type is not “void”), return statements must specify the value to be returned: return expression; Otherwise no value is required or allowed: return; Functions which do not return a value (“void functions”) need not end with a return statement. Instead they may just “run off the end” (an implicit “return” is assumed).

  7. Function Call Details function_name (expr, expr, expr …) Name of function to be invoked Argument list: One expression per function parameter. The Type of each expression must be compatible with (assignable to) the corresponding parameter. If a parameter is of type “double”, it is OK to supply an “int” value (because “int” values may be assigned to “double” variables). All the usual rules apply. If a “double” value is specified for an “int” parameter, the fractional part of the “double” value is discarded.

  8. Functions as Independent Entities Function may be written without having any idea exactly how they will be used. We could, for example, have written function “square” without having been shown the main function. Similarily we can use functions without knowing anything about the code involved. We have used the library function “sqrt” without having any idea of the algorithm used. All we need know is that the function requires a single double argument and returns a double value equal to the square root of the value supplied. Among other things, this allows large program-ming projects to be broken down into smaller units which can be worked on by individuals working independently of each other. It also makes it easier to solve complex problems by a process of “divide and conquer” (replacing a big problem with a series of smaller ones).

  9. Local “Scope” Everything (variable, constants, parameters) declared inside a function is “local” to that function and cannot be accessed from within other functions. Think of functions as independent “programs” whose only means of communication are passed arguments and returned values. Names may be re-used. Any number of functions may, for example, have a variable called “i”. The “i” of one function is quite unconnected to the “i” of every other function. A function’s variables come into existance when the function is called and cease to exist when it returns (excepting “static” variables, but these aren’t covered in this course). Values are not “remembered” from one call to the next.

  10. Void Functions Functions which do not return a value are called “void functions”. Such functions may only be used where no result is required (i.e. in an expression consisting solely of the function call). sample function: void output_dashes (int count) { while (count != 0) { cout << “-”; count--; } } function usage: output_dashes(6); // output 6 dashes output_dashes (i * 4); Note that parameters may be modified – apart from getting automatically initialized, they are just like normal variables.

  11. Functions Without Parameters Functions whose pasrameter list is “void” do not require any arguments when called. An empty argumernt list (just a pair of round brackets) is used. sample function: int get_positive_value (void) { int value; for (;;) { cin >> value; if (value >= 0) { // zero is positive break; // could just return right here } cout << “Not positive – try again: “; } return value; } function usage: cout << “Enter class size: “; class_size = get_positive_value();

  12. Function Prototypes (1) The fundamental C++ rule is that things must be defined before they can be used. The compiler will not let you invoke a function it hasn’t yet been told about (actually not quite true, but close enough for our purposes). One way of dealing with this is to put called function(s) before the function(s) which call them. double roof_area (. . .) { . . . } void main (void) { . . . roof_area (. . .); } A bit backwards in that, in reading a program, one must start at the end. Nontheless, this approach is widely used.

  13. Function Prototypes (2) An alternative is to first provide “prototypes” for functions to be called. The actual functions may then appear in any order. // function “prototype” double roof_area (double l, double w, double h); void main (void) { . . . roof_area (. . .); // OK because compiler has // seen the key information } double roof_area (. . .) { . . . } A function prototype consists of the function header followed by a semi-colon. Parameter names may be omitted because they aren’t relevent – all the compiler needs to know is how many parameters there are and the type of each parameter.

  14. Function Prototypes (3) Some library function prototypes (see Appendix 4 of the text): int abs (int); // absolute value double fabs (double); // absolute value double pow (double, double); // 1st argument raised to // the power of the 2nd double log10 (double); // log base 10 Parrameter names have in fact been omitted in this case. Prototypes only tell us so much (type returned, name of function, and arguments required). To be able to actually use a function, we also need the kind of information given by the comments associated with each prototype. The above prototypes are part of “math.h”. When we include this file, the compiler sees the prototypes, and so allows us to make use of the functions (which are actually stored in the run-time library). The real value of prototypes is that they permit this sort of thing.

  15. Function Example A gas company want a program which reads in meter readings and outputs the amount payable. inputs: initial meter reading (in m3) final meter reading (in m3) Meter readings are 4-digit numbers. They may wrap – we may have an initial reading of 9990 and a final reading of 0106 (in which case 116 m3 of gas were consumed). Outputs: amount due (in dollars and cents) first 70m3 - $5.00 minimum charge next 100m3 - 0.05/m3 next 230m3 - 0.025/m3 balance - 0.015/m3 Program is to continue accepting and processing readings until some special value is entered. See sample programs gasco0.cpp, etc.

  16. Call By Value • So far we’ve only used “call by value” in passing information to functions. A function’s parameters have always been assigned (or, more precisely, iniitialized with) the values of the arguments supplied. • int sample (double x) { • } • … sample (y + 4); • - Parameters are just like normal variables and may be used in exactly the same ways. • The only special thing about them is that, when the function is started up, they are initialized with the values of the arguments supplied. • Net effect: Dear Mr. Function, here is a value. Go away and play with it….. x x is initialized with the value of the expression “y + 4”

  17. Call By Reference • There is an alternative – “call by reference”. • int sample (double &x) { • } • double y • … • … sample (y); • Parameters are not just like the variables we’re used to. Instead they are “reference variables”. • Such variables do not contain values, but instead refer to (point to, contain the address of …) other variables (of exactly the right type). • Reference variables may be used in much the same way as normal variables. All operations on such variables are applied, not to the reference itself, but to the variable referred to (in the above case, all operations on “x” will be applied to “y”). x x is initialized with a reference to “y” (“x” is made to refer to “y”)

  18. temp a b ? Swap’s World Main’s World x y 4 6 Example – Swap Function void swap (int &a, int &b) { int temp; temp = a; a = b; b = temp; } void main (void) { int x = 4, y = 6; swap (x, y); cout << x << “ “ << y << endl; } Situation when “swap” begins executing:

  19. Call by Reference Details type &name Means “name” is a reference to a variable of type “type”. Such variables can only be initialized with a variable of exactly the correct type. Although int values can be assigned to double variables, and vice versa, a reference to a double can only be initialized with a double variable, and a reference to an int with an int variable. If a function has a reference parameter, the corresponding argument must be a variable of exactly the correct type. Things like “a + 4” don’t make sense in this context. Net effect: Dear Mr. Function – here is a variable. Go away and play with it. . .

  20. Type Long (1) In some C++ environments, “int” variables can only contain relatively small values (in the “16-bit” case, -32768 to 32767). If the capacity of “int” variables is inadequate, we can use type “long” (-2,147,483,648 to 2,147,483,647 in the same case). “long” variables are analogous “int” variables (“long” is actually shorthand for “long int”) except in that they can contain larger values. “long” constants are like “int” constants but have an ‘L’ (for “long”) at the end: 4 int constant 4L long constant 9836402 if too big for int, will result in a “constant is long” warning 9836402L long constant

  21. Type Long (2) Long values be assigned to int variables and vice versa. If a long value is too big to fit in an int variable, assigning it to an int variable will produce an incorrect result. “Long” to “int” assignments may result in a compiler warning (“this may not work out – are you sure you know what you’re doing”). If you are sure, this message can be suppressed by using an explicit cast. int a, long b; . . . a = (int) b; // we know what we’re doing Long values may be assigned to double variables and vice versa. If a double value is assigned to a long variable, the fractional part is lost.

  22. Arithmetic Type Summary We know have three “arithmetic” types: int, double, and long. The arithemetic operators (+, etc.) work on any combination of arithmetic types except in that the mod operator (%) may only be used with “integral” (int or long) operands. Revised rules for arithmetic results: if either operand is double then result is double else if either operand is long result is long // division is integer division else result is int // division is integer division The relational operators (< etc.) work on any combination of arithmetic operands.

  23. seconds Call by Reference Example (1) We want a function which, given a time since midnight (expressed in floating point seconds), “returns” the corresponding number of hours, minutes, and seconds (all integer – with input times being rounded to the nearest second). function prototype: void convert_to_hms (double seconds, int &hrs, int &mins, int &secs); hrs mins secs Initialized with a value supplied by the calling function. Initialized by being made to refer to variables supplied by the calling functions – the corresponding arguments must be variables.

  24. Call by Reference Example (2) void convert_to_hms (double seconds, int &hrs, int &mins, int &secs) { long integral_secs; // round number of seconds supplied to // the nearest whole second integral_secs = (long) (seconds + 0.5); // the casts to “int” in the following lines // avoid possible warning messages secs = (int) (integral_secs % 60); mins = (int) ((integral_secs / 60) % 60); hrs = (int) (integral_secs / (60 * 60)); } See sample program hms.cpp.

  25. Setfill Manipulator setfill (character expression) Character expression is an expression which evaulations to a chatracter value. For now, this will always be a single character enclosed in single quotes (e.g. ‘a’). The manipulator changes the “fill character” – the character used is padding output values to a specfied width. int a = 437; // produces “ 437” cout << setw(6) << a; // produces “XXX437” cout << setfill(‘X’) << setw(6) << a; // produces “000437” cout << setfill(‘0’) << setw(6) << a; The new fill character remains in effect until a further change is made.

  26. Setfill Example We want a function which, given a time in hours, minutes, and seconds, will output in hh:mm:ss format. Each of the three fields should always be two digits wide, with leading zeroes used as required. example output: 03:40:09 void print_hms (int hrs, int mins, int secs) { cout << setfill(‘0’) // fill with zeroes << setw(2) << hrs << “:” << setw(2) << mins << “:” << setw(2) << secs << setfill(‘ ‘); // restore default value } See sample program hms.cpp.

  27. Global “Scope” Variables and constants defined outside of any function belong to the “global scope” and can be accessed from within any function (subject only to the “define before using” rule). const double pi = 3.14; // “global” constant int x; // a “global” variable – BAD!! int func1 (. . .) { // can access pi and x here } int func2 (. . .) { // can also access pi and x here } Global constants are harmless. Global variables can result in programs which are difficult to undestand, maintain, and modify. They are not useful in the kinds of problems we’ll be doing in the course and are therefore banned.

More Related