C Lecture #4 Ok, we had a good class Thursday evening, If you did NOT make it, I would recommend picking up the transcript because some things were covered there which will *NOT+ be in any of the lectures. Ok, onwards and upwards. *FUNCTIONS+ In C a *function+ is equivalent to a subroutine or function in FORTRAN, or a procedure in Pascal, etc. A function provides a way to encapsulate some computation in a black box which can then be used without worrying about 'how' it does it. Functions are really the only to way to deal with large complex programs. If we properly design our functions we can ignore *how+ jobs are done and concentrate on *what+ the job is. Knowing what the function does is sufficient to effectively use it. C is designed to make defining and using functions easy for the programmer. That they are efficient as well is a bonus. So far we have only used functions like *printf+, *getchar+, and *putchar+ that have been provided for us. Now it is time for us to get pushed out of the nest and 'fly' on our own. This does NOT mean that we are going to ignore functions which we do not write (this would be foolish behavio(u)r at best), but we are going to write a few for our future use. Since C has no exponiation operator (like the ** of FORTRAN), we will use write a function to do exponiation to illustrate the mechanics of writing a function. *power+(m, n) should raise the integer 'm' to the power 'n'. For example power(2, 5) is 32. This function is not a full implementation of ** (it only handles positive powers), but when writing programs (and functions) it's best to deal with only one (1) issue at a time. Here is an initial example: int power(x, n) /* raise x to the n-th power */ int x, n; /* although a large n would certainly cause some problems */ { int i, p; p = 1; for (i = 1; i <= n; i++) p = p * x; return(p); } main() /* test the power function */ { int i; for (i = 1; i < 10; i++) printf("%d %d %d\n", i, power(2,i), power(-3,i)); } Although the functions can appear in either order I have a *STRONG+ preference for the order presented. Just as we declare variables before we use them, I feel that functions ought to be declared before they are used. There will be instances where this is NOT possible, but there are solutions to that problem. In fact, these functions don't even need to be in the same file. Resolving that is a compiler, linker, and operating system problem and we will not deal with that right now. (This way we can get on with the language without your having to learn new ways to compile and run programs). The function *power+ is called twice in the line: printf("%ld %ld %ld\n", i, power(2,i), power(-3,i)); Each 'call' pases two arguments to *power+, which each time returns an integer to be formatted and printed. In an expression *power(2,i)+ is an integer just as 2 and i are. Not all functions produce integers, but we will take that up later. In *power+ the arguments have to be declared appropriately so their types are known to the compiler (so it can generate the proper code to deal with them). This is done in our example by the line: int x, n; which follows the function name. The argument declarations go between the 'argument list' (the list of names between the parentheses '()' ) and the opening curly brace '{'. As if we were declaring variables, each declaration is terminated with a semicolon ';' . The names used by *power+ for its arguments are purely 'local' to *power+, and are NOT accessable by any other function. That is, other functions can use the same names without conflict. This is also true of the variables 'i' and 'p'. The 'i' in *power+ is NOT the same as the 'i' in *main+. The value which *power+ computes is returned to *main+ by the *return+ statement. Any expression may appear within the parentheses (although you will probably get a warning if it is not the same 'type' as declared at the beginning of the function.....also it would confuse the program to be expecting a *char+ and to get an *int+). A function need not return a value; a *return+ statement with no expression causes control to return to the caller, but no useful value to be returned. 'Falling off the end' of the function by reaching the terminating curly brace '}' does the same thing. Note that we do this routinely in all of our programs and we return to the program which 'called' us namely AmigaDOS, normally through collusion with CLI. *Arguments - Call by Value+ One aspect of C function may be confusing to programmers who have learned other languages first, particularly FORTRAN and PL/I. In C, all function arguments are 'call by value'. This means that the called function is given the values of its arguments in temporary variables (on the Amiga...on the stack) rather than their addresses. This leads to different properties than are seen in "call by reference" languages like FORTRAN and PL/I, in which the function is handed the address of the argument, not its value. The main distinction (and in my opinion advantage) is that in C the called function CANNOT alster a variable in the calling function. It can ONLY alter its own private copy. One of the advantages is that functions can frequently be written without any extraneous variables. This is because it can consider its arguments to be local variables which have been conveniently initialized (by the calling function). For example look at this 'modification' to the *power+ function: int power(x, n) /* raise x to the n-th power */ int x, n; /* although a large n would certainly cause some problems */ { int p; for (p = 1; n > 0; n--) p = p * x; return(p); } Argument 'n' is used as a local variable and counted down until it becomes zero. There is no longer a need for the local variable 'i'. Whatever is done in to the argument 'n' inside *power+ has no effect on the value that *power+ was originally called with. When neccessary, it is possible to arrange for a function to modify a variable in a calling routine ("we shall hear more of this later"). By the way, if you haven't submitted homework #8, there is no need. This problem is a superset of homework #8. HOMEWORK #9 1. Expand on problem #8..... Refine the definition of word further such that a word cannot start with an character which is NOT a letter.....by that I mean 1323abcde is NOT a word however 123;abcde has 1 word in it (abcde and its length is 5). 2. Then histogram the results (always scaling so the the largest is 'full width') don't forget to 'label' the individual elements for readability. 3. 'Invent' some technique for burying the actual count into the histogram. To quote from the Intuition manual 'go wild'. NOTE: For those of you who have forgotten what a histogram looks like, the following is a rough approximation (without labels or scaling). ## ### ##### ######## ######### ####### ### # Use as input for your program one or more of the lectures for this class. Compare the results. Does tend to use longer words as the class continues, or did he use longer words in the beginning (no doubt in an attempt to 'impress' potential students)? Also use at input a captured set of messages from the AmigaTech message base (if you can easily get a collection of around 200 messages). Is there any substantial difference in the shape of the histograms? Can you draw any conclusions? Ok, why don't we head into the holidays without a LOT of things to do for class. Just ONE (1) homework problem which is officially due on January 5th, 1989. I will be 'holding office hours' on Thursday Dec 22 and Dec 29 at the regular place (room 3) and at the regular time (7PM-9PM PST). If you think you'll get bored just doing a text histogram, try reading up on the special codes you can send an Amiga console device (CON:) to change the colors. You have 4 colors to 'play' with on a standard WorkBench screen (which is where standard out normally gets put). A Merry Christmas and a Happy New Year to you and yours; see you on the 5th.