Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(ebook) Visual Studio .NET Mastering Visual Basic.pdf
Скачиваний:
137
Добавлен:
17.08.2013
Размер:
15.38 Mб
Скачать

THE STACK MECHANISM 829

application so that every time it runs into a ZIP file, it calls the MVFiles.bat program with the appropriate arguments and lets it process the ZIP file.

The Stack Mechanism

Now that you have seen examples of recursive programming and have a better understanding of this powerful technique, let’s look at the mechanism that makes recursion possible. I mentioned earlier that each time a procedure (function or subroutine) calls another, its status must be stored in memory so that it can later resume execution. The status of an interrupted procedure includes the location of the line where it was interrupted and the values of the local variables the moment it was interrupted. This information is enough for a procedure to resume operation and never be aware that it was interrupted.

Stack Defined

The area of memory in which the procedure’s status is stored is called the stack. The stack is a protected area of the system’s memory that’s handled exclusively by the operating system. The stack memory is regular memory, but the operating system handles it differently from the way it handles the rest of memory. For one thing, programs can’t grab any byte from the stack. The items in this memory are stacked on top of one another, and only the topmost item can be extracted.

Each time a program places a value on the stack, the new item is placed at the top of the stack. When a program reads a value from the stack, it can read only the item on top, which is the item that was placed on the stack last. This type of memory organization is called last in, first out, or LIFO. The item that is placed on the stack last is the first one to be read. This is exactly the mechanism used to pass arguments between procedures.

Recursive Programming and the Stack

If you aren’t familiar with the role of the stack in the computer’s operation, the following discussion will probably help you understand the mechanics of recursion a little better. The stack is one of the oldest models used in programming, and it’s still as useful and as popular as ever. In fact, it’s an important part of the operating system. Microprocessors provide special commands for manipulating the stack. Fortunately, you don’t have to worry about the stack, since it’s handled exclusively by the operating system and your favorite programming language. The description of the stack you’ll find in this section is a bit simplified. The goal is to explain how recursive procedures work without getting too technical.

Suppose the recursive procedure is a subroutine and it accepts no arguments, similar to the ScanFolder() subroutine. When the ScanFolder() subroutine calls itself, it must first store its status on the stack so that it can later resume. One component of the subroutine’s status is the line that was executing when the program was interrupted. The ScanFolder() subroutine calls itself from within a loop. When it resumes, it should be able to continue with the remaining loops and not start all over again. The loop’s counter, i, is part of the subroutine’s status, and it must also be stored on the stack along with all the information that makes up the function’s status.

The ScanFolder() subroutine’s status is stored on top of the stack, and the same subroutine starts executing again with a fresh set of local variables (a new loop counter, for example). When this copy

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

830 Chapter 18 RECURSIVE PROGRAMMING

of the ScanFolder() subroutine calls itself again, its status is stored on the stack on top of the status of the previously interrupted subroutine. As more instances of the same subroutine are called, the status of each is stored on top of the previously interrupted subroutine’s status. Eventually, the active ScanFolder() subroutine terminates, and the most recently interrupted one takes over. Its status is on the top of the stack. The operating system removes the values of its local variables from the stack so that the subroutine can resume execution.

What’s left on the top of the stack now is the status of the subroutine that must resume execution when the active subroutine terminates. When these values are removed from the stack, the status of another interrupted function surfaces on the stack. This simple mechanism allows procedures to interrupt each other and keep track of each other’s status without any complicated operations. Each procedure finds its status on the stack, as if no other information was ever placed on top of it.

Passing Arguments through the Stack

The same mechanism is used to pass arguments from one procedure to another. Suppose your program calls the function Payment(Amount, Interest), which expects to read two arguments (the loan amount and an interest rate) and return the monthly payment. As you know so well by now, you must supply the arguments in this order: first the amount, then the interest. The calling program leaves its status and the two arguments on the stack in the same order: first its status (the values of its local variables), then the value of the Amount argument, and finally, the value of the Interest argument. When the Payment() function takes over, it retrieves the two arguments from the top of the stack: first the value of the last argument, then the value of the first argument. After the removal of these two values from the stack, the status of the calling procedure is at the top of the stack. When the Payment() function finishes, it leaves its result on the top of the stack and relinquishes control to the calling procedure.

The calling procedure removes the value from the top of the stack (the result of the Payment() function) and uses it for its own purposes. It then removes the values of the local variables (its status) so that it can resume execution. As you can see, the LIFO structure is ideal for exchanging data between procedures.

Suppose the Payment() function calls another function. Again, the arguments of the new function are placed on the stack where the new function will find them. When the other function returns, it leaves its result on the top of the stack where the Payment() function will find it and remove it from the stack. It also finds its status information on the stack. No matter how many functions are called in such a nested manner, the information required is always at the top of the stack.

The only requirement when passing arguments through the stack is that they are placed there in the order they are needed. The procedure being called has no other means to decipher which value corresponds to which argument. That’s why these arguments are also known as positional arguments.

VB functions support named arguments as well, and you can pass arguments to them in any order, as long as you provide both the name and the value of the argument. If the Payment() function has a default interest rate, you can call it as follows: Payment(Amount:=29000). Even these procedures use the stack mechanism to pass the named arguments, but the mechanics are a bit more complicated. The basic idea is the same: The information is always placed on top of the stack, and when it’s read, it’s removed from the stack. In this way, each procedure is guaranteed to find the information it leaves on the stack the moment it needs it.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com