Hello ! Nice to meet you again ! How is the lessons ? It was a great quiz, wasn't it ? Well, time's getting more difficult to pass through. I've got a very busy semester, so that I may not even keep my promise in the Web........ Sorry ! But I keep moving on, don't worry !
Contents :
OK ! Let's start ! We know that Pascal is a structured language. It means that the problems is divided into steps and subproblems and then is coded in a structure. This division is made through procedures and functions. Well, what the hell are procedures and functions ? It is like a subprogram that has its own begin..end. It is useful when a part of program must be performed more than once in scattered parts of the program. May be it is a bit murky, but let's take a look on its syntax :
Procedure procname; begin : { commands } : : end; begin end.
This is the simplest form of a procedure. (Functions are discussed later) As we can see that procedures are always placed ABOVE the main begin...end. Example :
uses crt; procedure pause; begin writeln('Press any key when ready ...'); readkey; end; begin clrscr; writeln('ABC'); pause; { Make a call to procedure pause } writeln('Hey, let''s pause !'); pause; { Make a call to procedure pause } writeln('Pause again !'); pause; { Make a call to procedure pause } end.
Run the previous example. Look at this example :
uses crt; begin clrscr; writeln('ABC'); writeln('Press any key when ready ...'); readkey; writeln('Hey, let''s pause !'); writeln('Press any key when ready ...'); readkey; writeln('Pause again !'); writeln('Press any key when ready ...'); readkey; end.
It gives the same effect as the first example, isn't it ? Which is nicer ? Writing silly same phrases or efficiently using procedures. If you are normal guy, you would love the first example. It is clearer and cleaner. Easy to read. Especially the lines to be replaced with procedures are very long. Procedures, and functions too, make the codes healthier and easier to read. It makes life easier in debugging the program, too.
Procedures could have its own variable, called local variable. The variable is only known inside the procedure. For example :
procedure foo; var a : byte; begin a:=10; writeln(a); end; begin { main begin...end block } foo; a:=15; { This will be an error, since a is only known inside foo } end.
Global variable is a variable that is known throughout the program and its procedures or functions. Example :
var b : byte; procedure foo; var a : byte; begin a:=10; b:=15; { This is legal } end; begin { main begin...end block } foo; a:=15; { This is illegal } b:=5; { This is perfectly legal } end.
If a local variable is declared inside a procedure with the same name as the global variable, the global variable is overrided. For example :
uses crt; var a : byte; { This is the global variable } procedure foo; var a : byte; begin a:=15; writeln('foo is ',a); end; begin a:=10; writeln(a); foo; writeln(a); end.
Functions are pretty much the same, except it has a return value. It just like mathematic functions. Syntax :
function funcname : returntype; begin : { commands } : : end; begin end.
Functions are also placed before the main begin...end. Example :
uses crt; function yesno : boolean; var c : char; begin write('Are you sure (Y/N) ? '); repeat c:=upcase(readkey); { Make it upcase letters } until (c='Y') or (c='N'); writeln(c); if c='Y' then yesno:=true else yesno:=false; end; var x : boolean; { Don't be tricked, this is a LOCAL variable of main block } begin clrscr; writeln('Discard all changes made'); x:=yesno; if x=true then writeln('Changes discarded !'); else writeln('Changes saved !'); writeln('Quitting'); x:=yesno; if x then begin writeln('Process terminated !'); halt; end; writeln('Quit cancelled !'); writeln('Continuing process ...'); end.
Can you see a big difference between procedures and functions ? Use function if we want to get a return value. Suppose the yesno function. It returns true if user presses y and returns false if user presses n. Yes, yes, it is pretty complex. But, try to understand. Or... try to understand this simple excerpt : (This is only the begin...end part. All above is the same as the previous one.)
begin x:=yesno; if x then writeln('You answered "Yes"') else writeln('You answered "No"'); end.
OK ! Any questions ? Send them to me ! Let's continue...
In a well-structured program, we use global variables as minimal as possible and use the optimum amount of local variables. How can we ? Well, practice a lot ! Sometimes, we need some value to be known inside a procedure. In that case, we need parameters. We can put parameters just beside the procedure's or function's name, suppose :
procedure myproc (a:integer; b:real); begin : : end; function abc (a,b : integer; c:byte) : longint; begin : : end;
Let's see it in 'real life' !
uses crt; procedure makewin(x1,y1,x2,y2 : byte); var i,j : byte; begin { top } gotoxy(x1,y1); write(#201); for i:=x1+1 to x2-1 do write(#205); write(#187); { middle } for i:=y1+1 to y2-1 do begin gotoxy(x1,i); write(#186); for j:=x1+1 to x2-1 do write(' '); write(#186); end; { bottom } gotoxy(x1,y2); write(#200); for i:=x1+1 to x2-1 do write(#205); write(#188); end; begin makewin(1,1,30,8); makewin(10,10,60,18); end.
Simple example above tell us about making a window in a coordinate (x1, y1) to (x2, y2). With this engine, we could make many windows with just entering coordinates and the SAME code. Parameters makes us easier to customize the procedures and functions. Let's see this example :
function factorial(n : byte):longint; var i : byte; result : longint; begin result:=1; for i:=1 to n do result:=result*i; factorial:=result; end; var x : byte; begin writeln('Enter a value : '); readln(x); writeln(x,'! is ',factorial(x)); end.
Those previous examples are widely used in programming life. Let's look at this :
procedure foo(a : byte); begin writeln(a); {15} a:=10; writeln(a); {10} end; var x : byte; begin x:=15; writeln(x); {15} foo(x); writeln(x); {Still 15} end.
It outputs :
15 15 10 15
At first, x is 15, then passed to procedure foo as passing parameter a. Eventhough it is legal to modify a inside foo, the value of x is unaffected anyway. This type of passing method is called PASS BY VALUE. How about this :
procedure foo(var a : byte); { See the difference ? } begin writeln(a); {15} a:=10; writeln(a); {10} end; var x : byte; begin x:=15; writeln(x); {15} foo(x); writeln(x); {10} end.
It outputs :
15 15 10 10
If we add var before a as passing parameter, the value of x is changed whenever a is changed. This type of passing method is called PASS BY REFERENCE.
We must pass by value if the parameters are not necessarily be changed in the procedure. If the parameters need changing and the change is important to be known by the caller, use pass by reference.
In Borland Pascal 7.0, we could omit the return values of a function. In our examples so far, we use readkey, right ? Readkey is actually a function but a built-in one. Before version 7.0, we must take a return value of it (readkey), like this : c:=readkey;. But, from version 7.0, we could omit it by just calling readkey like this : readkey;
You CAN call another procedure inside a procedure or function as long as the caller procedure/function lies below it. Example :
procedure a; begin : : end; procedure b; begin : a; { legal } end; begin : end.
It is legal for procedure b to call procedure a. But procedure a can NEVER call procedure b. It is ILLEGAL. Function can call procedures, procedures can call functions, functions can also call other functions as long as the caller is below the target (the one which is invoked). So, you'd better arrange the procedures and functions you might have.
If the if-structure and loop structures could nest each other, can procedures and functions nest each other ? YES, IT COULD ! Example :
procedure e; { e cannot access a, b, c, and d } begin : end; procedure a; procedure b; begin c; {illegal} e; {legal} end; procedure c; begin b; {legal} e; {legal} end; begin : b; {legal} c; {legal} e; {legal} end; procedure d; begin : b; {illegal} c; {illegal} a; {legal} e; {legal} end; begin : b; {illegal} c; {illegal} a; {legal} d; {legal} e; {legal} end.
Procedure c can call procedure b since c is below b, but procedure b cannot call procedure c. Procedure a, whose begin..end block below procedure b and procedure c, can call procedure b and c. Procedure b and c cannot be access ed by procedure d and main block. So, nested procedure can only be accessed by their brothers/sisters (among the same level of nested procedure), and their parent (the procedure who endow them). Accesses between brothers follow the rule of normal procedure calling.
How about calling ourselves ? Well, IT IS PERFECTLY LEGAL too !! Example :
procedure a; begin a; end; begin a; end.
But it will say error since it call itself ENDLESSLY. The method of calling oneselves is called RECURSIVE CALLS. In recursive calls, we must :
Let's see a very good example of recursive calls : It's factorial. See the non-recursive method of factorial function above, then see this recursive version :
function factorial (n:byte):factorial; begin if n<2 then { This is the terminating condition } factorial:=1; else factorial:=n*factorial(n-1); { This is the recursive part } end; var x : byte; begin writeln('Enter a value : '); readln(x); writeln(x,'! is ',factorial(x)); end.
If x = 5, At first call, n = 5. Factorial:=5*factorial(4); => need second call Second call, n = 4. Factorial:=4*factorial(3); => need third call Third call, n = 3. Factorial:=3*factorial(2); => need fourth call Fourth call, n = 2. Factorial:=2*factorial(1); => need fifth call Fifth call, n = 1. Factorial:=1; => inserted back to above so 4th call becomes : Factorial:=2*1; (=2) => inserted back to above so 3rd call becomes : Factorial:=3*2; (=6) => inserted back to above so 2nd call becomes : Factorial:=4*6; (=24) => inserted back to above so 1st call becomes : Factorial:=5*24; (=120)
As you may see that factorial in recursive method is simpler than ever. Suppose you miswrite n-1 to n, the terminating condition would never be functional. So, it will loop forever ! Be careful !
Well, we come to a quite advanced matter. It is sometimes used though. Inter-referenced calls. It means that 2 procedures or functions could call each other.
procedure a; begin b; { illegal } end; procedure b; begin a; end;
As you may see, calling a from b is legal, but calling b from a is illegal. It sometimes necessary for a to call b and for b to call a. The real-life problem is like context-sensitive help. Sometimes the description, when it is pointed or clicked, it call the index. But also, the index has to call its description after a topic is picked. The solution is : FORWARD CALL. Example :
procedure b; forward; procedure a; begin b; { now legal } end; procedure b; begin a; end;
Use the statement forward to make b visible to a, so a can call b. It is more dangerous than recursive call. If you are not careful, you may find the same symptoms as recursive call did. What you must do is also the same as in the recursive call. Just beware : Calling procedures uses a part of memory called stack. Reciprocal calls wastes stacked much faster than recursive calls. If you run out of stack, your program would stuck.
How could I break down complex problems ? How good your ability in breaking problems is actually depends on your experience in programming. But, I can only tell you this :
Well, that's one of the complex problems. You may follow the guidelines. OK, that's all for today ! Have a good quiz ! =)
Where to go ?
Back to main page
Back to Pascal Tutorial Lesson 1 contents
To the quiz
Back to Chapter 5 about looping
To Chapter 7 about arrays
My page of programming link
Contact me here
By : Roby Joehanes, © 1996, 2000