B. DOS 10H, 21H, and 33H Interrupt Parameters

Chapter 7 - Program Control

Visual C++ 6: The Complete Reference
Chris H. Pappas and William H. Murray, III
  Copyright 1998 The McGraw-Hill Companies

Loop Controls
The C and C++ language include the standard set of repetition control statements: for loops, while loops, and do-while loops (called repeat-until loops in several other high-level languages). You may be surprised, however, by the ways a program can leave a repetition loop. C and C++ provide four methods for altering the repetitions in a loop. All repetition loops can naturally terminate based on the expressed test condition. In C and C++, however, a repetition loop can also terminate because of an anticipated error condition by using either a break or exit statement. Repetition loops can also have their logic control flow altered by a break statement or a continue statement.
The basic difference between a for loop and a while or do-while loop has to do with the “known” number of repetitions. Typically, for loops are used whenever there is a definite predefined required number of repetitions, and while and do-while loops are reserved for an “unknown” number of repetitions.
for
The syntax for a for loop is
for(initialization_exp; test_exp; increment_exp)
statement;
When the for loop statement is encountered, the initialization_exp is executed first. This is done at the start of the loop, and it is never executed again. Usually, this statement involves the initialization of the loop control variable. Following this, test_exp, which is called the loop terminating condition, is tested. Whenever test_exp evaluates to TRUE, the statement or statements within the loop are executed. If the loop was entered, then after all of the statements within the loop are executed, increment_exp is executed. However, if test_exp evaluates to FALSE, the statement or statements within the loop are ignored, along with increment_exp, and execution continues with the statement following the end of the loop. The indentation scheme applied to for loops with several statements to be repeated looks like this:
for(initialization_exp; test_exp; increment_exp) {
statement_a;
statement_b;
statement_c;
statement_n;
}
In the case where several statements need to be executed, a pair of braces is required to tie their execution to the loop control structure. Let’s examine a few examples of for loops.
The following example sums up the first five integers. It assumes that isum and ivalue have been predefined as integers:
isum = 0;
for(ivalue=1; ivalue <= 5; ivalue++)
 isum += ivalue;
After isum has been initialized to zero, the for loop is encountered. First, ivalue is initialized to 1 (this is done only once); second, ivalue‘s value is checked against the loop terminating condition, <= 5. Since this is TRUE, a 1 is added to isum. Once the statement is executed, the loop control variable (ivalue) is incremented by 1. This process continues four more times until ivalue is incremented to 6 and the loop terminates.
In C++, the same code segment could be written as follows. See if you can detect the subtle difference:
for(int ivalue=1; ivalue <= 5; ivalue++)
 isum += ivalue;
C++ allows the loop control variable to be declared and initialized within the for loop. This brings up a very sensitive issue among structured programmers, which is the proper placement of variable declarations. In C++, you can declare variables right before the statement that actually uses them. In the preceding example, since ivalue is used only to generate an isum, with isum having a larger scope than ivalue, the local declaration for ivalue is harmless. However, look at the following code segment:
int isum = 0;
for(int ivalue=1; ivalue <= 5; ivalue++)
 isum += ivalue;
This would obscure the visual “desk check” of the variable isum because it was not declared below the function head. For the sake of structured design and debugging, it is best to localize all variable declarations. It is the rare code segment that can justify the usefulness of moving a variable declaration to a nonstandard place, in sacrifice of easily read, easily checked, and easily modified code.
The value used to increment for loop control variables does not always have to be 1 or ++. The following example sums all the odd numbers up to 9:
iodd_sum = 0;
for(iodd_value=1; iodd_value <= 9; iodd_value+=2);
 iodd_sum += iodd_value;
In this example, the loop control variable iodd_value is initialized to 1 and is incremented by 2.
Another unique feature is that for loops don’t always have to go from a smaller value to a larger one. The following example uses a for loop to read into an array of characters and then print the character string backward:
//
//  forlp.cpp
//  A C++ program that uses a for loop to input a character array
//  Copyright (c) Chris H. Pappas and William H. Murray, 1998
//
#include <stdio.h>

#define CARRAY_SIZE 10

int main( )
{
 int ioffset;
 char carray[CARRAY_SIZE];

 for(ioffset = 0; ioffset < CARRAY_SIZE; ioffset++)
   carray[ioffset] = getchar( );
 for(ioffset = CARRAY_SIZE - 1; ioffset >= 0; ioffset—)
   putchar(carray[ioffset]);

 return(0);
}
In this application, the first for loop initialized ioffset to zero (necessary since all array indexes are offsets from the starting address of the first array element), and while there is room in carray, reads characters in one at a time. The second for loop initializes the loop control variable ioffset to the offset of the last element in the array and, while ioffset contains a valid offset, prints the characters in reverse order. This process could be used to parse an infix expression that was being converted to prefix notation.
When combining or nesting for loops, as in the next example, take care to include the appropriate braces to make certain the statements execute properly:
/*
*   nslop1.c
*   A C program demonstrating
*   the need for caution when nesting for loops.
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>

int main( )
{
 int iouter_val, iinner_val;

 for(iouter_val = 1; iouter_val <= 4; iouter_val++) {
   printf(“\n%3d —”,iouter_val);
   for(iinner_val = 1; iinner_val <= 5; iinner_val++ )
     printf(“%3d”,iouter_val
* iinner_val);
 }

 return(0);
}
The output produced by this program looks like this:
1 —  1  2  3  4  5
2 —  2  4  6  8 10
3 —  3  6  9 12 15
4 —  4  8 12 16 20
However, suppose the outer for loop had been written without the braces, like this:
/*
*   nslop2.c
*   A C program demonstrating what happens when you nest
*   for loops without the logically required braces {}.
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>

int main( )
{
 int iouter_val, iinner_val;

for(iouter_val = 1; iouter_val <= 4; iouter_val++)
  printf(“\n%3d —”,iouter_val);
  for(iinner_val = 1; iinner_val <= 5; iinner_val++ )
    printf(“%3d”,iouter_val
* iinner_val);

 return(0);
}
The output now looks quite different:
1 —
2 —
3 —
4 —  5 10 15 20 25
Without the braces surrounding the first for loop, only the first printf( ) statement is associated with the loop. Once the printf( ) statement is executed four times, the second for loop is entered. The inner loop uses the last value stored in iouter_val, or 5, to generate the values printed by its printf( ) statement.
The need to include or not include braces can be a tricky matter at best that needs to be approached with some thought to readability. Look at the next two examples and see if you can figure out if they would produce the same output.
Here is the first application:
/*
*   lpdmo1.c
*   Another C program demonstrating the need
*   for caution when nesting for loops.
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>

int main( )
{
 int iouter_val, iinner_val;

 for(iouter_val = 1; iouter_val <= 4; iouter_val++) {
   for(iinner_val = 1; iinner_val <= 5; iinner_val++ )
     printf(“%d ”,iouter_val
* iinner_val);
 }

 return(0);
}
Compare the preceding program with the following example:
/*
*   lpdmo2.c
*   A comparison C program demonstrating the need
*   for caution when nesting for loops.
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>

int main( )
{
 int iouter_val, iinner_val;

 for(iouter_val = 1; iouter_val <= 4; iouter_val++)
   for(iinner_val = 1; iinner_val <= 5; iinner_val++ )
     printf(“%d ”,iouter_val
* iinner_val);

 return(0);
}
Both programs produce the identical output:
1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20
In these last two examples, the only statement associated with the outer for loop is the inner for loop. The inner for loop is considered a single statement. This would still be the case even if the inner for loop had multiple statements to execute. Since braces are needed only around code blocks or multiple statements, the outer for loop does not need braces to execute the program properly.
while
The C and C++ while loop is a pretest loop just like the for loop. This means that the program evaluates test_exp before entering the statement or statements within the body of the loop. Because of this, pretest loops may be executed from zero to many times. The syntax for a C while loop is
while(test_exp)
statement;
For while loops with several statements, braces are needed:
while(test_exp) {
statement1;  
statement2;  
statement3;  
statementn;
}
Typically, while loop control structures are used whenever an indefinite number of repetitions is expected. The following C program uses a while loop to control the number of times ivalue is shifted to the right. The program prints the binary representation of a signed integer.
/*
*   while.c
*   A C program using a pretest while loop with flag
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>

#define WORD 16
#define ONE_BYTE 8

int main( )
{
 int ivalue = 256, ibit_position=1;
 unsigned int umask = 1;

 printf(“The following value %d,\n”,ivalue);
 printf(“in binary form looks like: ”);

 while(ibit_position <= WORD) {
   if((ivalue >> (WORD - ibit_position)) & umask) /
*shift each*/
     printf(“1");                                 /
*bit to 0th*/
   else                                           /
*position &*/
     printf(”0");                                 /
*compare to*/
   if(ibit_position == ONE_BYTE)                  /
*umask     */
     printf(“ ”);
   ibit_position++;
 }

 return(0);
}
This application begins by defining two constants, WORD and ONE_BYTE, that can be easily modified for different architectures. WORD will be used as a flag to determine when the while loop will terminate. Within the while loop, ivalue is shifted, compared to umask, and printed from most significant bit to least. This allows the algorithm to use a simple printf( ) statement to output the results.
In the next example, the application prompts the user for an input filename and an output filename. The program then uses a while loop to read in and echo print the input file of unknown size.
/*
*   dowhile.c
*   A C program using a while loop to echo print a file
*   The program demonstrates additional file I/O techniques
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>
#include <process.h>

#define sz_TERMINATOR 1       /
* sz, null-string designator */
#define MAX_CHARS 30

int main( )
{
 int c;
 FILE
*ifile, *ofile;
 char sziDOS_file_name[MAX_CHARS + sz_TERMINATOR],
      szoDOS_file_name[MAX_CHARS + sz_TERMINATOR];
 fputs(“Enter the input file’s name: ”,stdout);
 gets(sziDOS_file_name);

 if((ifile=fopen(sziDOS_file_name,"r")) == NULL) {
   printf(“\nFile: %s cannot be opened”,sziDOS_file_name);
   exit;
 }

 fputs(“Enter the output file’s name: ”,stdout);
 gets(szoDOS_file_name);

 if((ofile=fopen(szoDOS_file_name,"w")) == NULL) {
   printf(“\nFile: %s cannot be opened”,szoDOS_file_name);
   exit;
 }
 while(!feof(ifile)) {
   c=fgetc(ifile);
   fputc(c,ofile);
 }

 return(0);
}
Here, the while loop contains two executable statements, so the brace pair is required. The program also illustrates the use of several file I/O statements like fgetc( ) and fputc( ), along with feof( ) (discussed in Chapter 11).
do-while
The do-while loop differs from the for and while loops. The do-while loop is a post-test loop. In other words, the loop is always entered at least once, with the loop condition being tested at the end of the first iteration. In contrast, for loops and while loops may execute from zero to many times, depending on the loop control variable. Since do-while loops always execute at least one time, they are best used whenever there is no doubt you want the particular loop entered. For example, if your program needs to present a menu to the user, even if all the user wants to do is immediately quit the program, he or she needs to see the menu to know which key terminates the application.
The syntax for a do-while loop is
do
 action;
while(
test_condition);
Braces are required for do-while statements that have compound actions:
do {
 action1;
 action2;
 action3;
 actionn;
} while(
test_condition);
The following application uses a do-while loop to calculate some statistics for a user-entered sentence:
//
//  dowhile.cpp
//  A C++ program demonstrating the usefulness of a
//  do-while loop to process user-defined sentence.
//  Copyright (c) Chris H. Pappas and William H. Murray, 1998
//

#include <iostream.h>

#define LENGTH 80
#define NULL_TERM 1


int main( )
{
 const int LENGTH 80;
 char cSentence[LENGTH + NULL_TERM];
 int iNumChars = 0, iNumWords = 1;

 do {
   cout << “Please enter your sentence : ”;
   cin.getline(cSentence,LENGTH);
 } while (cSentence[0] == ‘\0’;

 while (cSentence[iNumChars] != ‘\0’) {
   if (cSentence[iNumChars] == ‘ ‘)
     iNumWords++;
   iNumChars++;
 }

 cout << “You entered ” << iNumChars << “ characters\n”;
 cout << “You entered ” << iNumWords << “ words”;

 return (0);
}
The do-while loop in this program repeats the prompt and input statements for the user-requested sentence until the user enters at least one character. Simply pressing the enter key causes the getline( ) function to store the null character in the first array element position, repeating the loop. Once the user enters the sentence, the program jumps out of the do-while loop printing the calculated statistics.
break
The break statement can be used to exit a loop before the test condition becomes FALSE. The break statement is similar in many ways to a goto statement, only the point jumped to is not known directly. When breaking out of a loop, program execution continues with the next statement following the loop itself. Look at this simple application:
/*
*   break.c
*   A C program demonstrating the use of the break statement.
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

int main( )
{
 int itimes = 1, isum = 0;

 while(itimes < 10){
   isum += isum + itimes;
   if(isum > 20)
     break;
   itimes++;
 }

 return(0);
}
Debugger Trace
Use the integrated debugger to trace through the preceding program. Trace the variables isum and itimes. Pay particular attention to which statements are executed after isum reaches the value 21. What you should have noticed is that when isum reached the value 21, the break statement was executed. This caused the increment of itimes to be jumped over, itimes++, with program execution continuing on the line of code below the loop. In this example, the next statement executed was the return.
continue
There is a subtle difference between the break statement and the continue statement. As you have already seen from the last example program, break causes the loop to terminate execution altogether. In contrast, the continue statement causes all of the statements following the continue statement to be ignored but does not circumvent incrementing the loop control variable or the loop control test condition. In other words, if the loop control variable still satisfies the loop test condition, the loop will continue to iterate.
The following program demonstrates this concept, using a number guessing game:
/*  
*   contnu.c
*   A C program demonstrating the use of the continue
*   statement.
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>

#define TRUE 1
#define FALSE 0

int main( )
{
 int ilucky_number=77,
     iinput_val,
     inumber_of_tries=0,
     iam_lucky=FALSE;

 while(!iam_lucky){
   printf(“Please enter your lucky guess: ”);
   scanf(“%d”,&iinput_val);
   inumber_of_tries++;
   if(iinput_val == ilucky_number)
     iam_lucky=TRUE;
   else
     continue;
   printf(“It only took you %d tries to get lucky!”,
     inumber_of_tries);
 }

 return(0);
}
Debugger Trace
As an exercise, enter the preceding program and trace the variables iinput_val, inumber_of_tries, and iam_lucky. Pay particular attention to which statements are executed after iinput_val is compared to ilucky_number.
The program uses a while loop to prompt the user for a value, increments the inumber_of_tries for each guess entered, and then determines the appropriate action to take based on the success of the match. If no match was found, the else statement is executed. This is the continue statement. Whenever the continue statement is executed, the printf( ) statement is ignored. Note, however, that the loop continues to execute. When iinput_val matches ilucky_number, the iam_lucky flag is set to TRUE and the continue statement is ignored, allowing the printf( ) statement to execute.
Combining break and continue
The break and continue statements can be combined to solve some interesting program problems. Look at the following C++ example:
//
//  bracntg.cpp
//  A C++ program demonstrating the usefulness of combining
//  the break and continue statements.
//  Copyright (c) Chris H. Pappas and William H. Murray, 1998
//

#include <iostream.h>
#include <ctype.h>

#define NEWLINE ‘\n’

int main( )
{
 int c;
 while((c=getchar( )) != EOF)
 {
   if(isascii(c) == 0) {
     cout << “Not an ASCII character; ”;
     cout << “not going to continue/n”;
     break;
   }

   if(ispunct(c) || isspace(c)) {
     putchar(NEWLINE);
     continue;
   }

   if(isprint(c) == 0) {
     c = getchar( );
     continue;
   }

   putchar(c);
 }

 return(0);
}
Before seeing how the program functions, take a look at the input to the program:
word control ^B exclamation! apostrophe’ period.
^Z
Also examine the output produced:
word
control
B
exclamation

apostrophe

period
This application continues to read character input until the EOF character ^Z is typed. It then examines the input, removing any nonprintable characters, and places each “word” on its own line. It accomplishes all of this by using some very interesting functions defined in CTYPE.H, including isascii( ), ispunct( ), isspace( ), and isprint( ). Each of the functions is passed a character parameter and returns either a zero or some other value indicating the result of the comparison.
The function isascii( ) indicates whether the character passed falls into the acceptable ASCII value range, ispunct( ) indicates whether the character is a punctuation mark, isspace( ) indicates whether the character is a space, and function isprint( ) reports whether the character parameter is a printable character.
By using these functions, the application determines whether to continue the program at all and, if it is to continue, what it should do with each of the characters input.
The first test within the while loop evaluates whether the file is even in readable form. For example, the input data could have been saved in binary format, rendering the program useless. If this is the case, the associated if statements are executed, printing a warning message and breaking out of the while loop permanently.
If no errors are encountered, the second if statement is encountered; it checks whether the character input is either a punctuation mark or a blank space. If either of these conditions is TRUE, the associated if statements are executed. This causes a blank line to be skipped in the output and executes the continue statement. The continue statement efficiently jumps over the remaining test condition and output statement but does not terminate the loop. It merely indicates that the character’s form has been diagnosed properly and that it is time to obtain a new character.
The third if statement asks whether the character is printable or not, but only if the file is in an acceptable format and the character input is not punctuation or a blank. This test takes care of any control codes. Notice that the example input to the program included a control ^B. Since ^B is not printable, this if statement immediately obtains a new character and then executes a continue statement. In like manner, this continue statement indicates that the character in question has been diagnosed, the proper action has been taken, and it is time to get another character. The continue statement also causes the putchar( ) statement to be ignored while not terminating the while loop.
exit( )
Under some circumstances, it is possible for a program to terminate long before all of the statements in the program have been examined and/or executed. For these specific circumstances, C incorporates the exit( ) library function. The function exit( ) expects one integer argument, called a status value. The UNIX and MS-DOS operating systems interpret a status value of zero as signaling a normal program termination, while any nonzero status values signify different kinds of errors.
The particular status value passed to exit( ) can be used by the process that invoked the program to take some action. For example, if the program were invoked from the command line and the status value indicated some type of error, the operating system might display a message. In addition to terminating the program, exit( ) writes all output waiting to be written and closes all open files.
The following application averages a list of up to 30 grades. The program will exit if the user requests to average more than SIZE number of integers.
//
//  exit1.cpp
//  A C++ program demonstrating the use of the exit function
//  Copyright (c) Chris H. Pappas and William H. Murray, 1998
//

#include <iostream.h>
#include <process.h>

#define LIMIT 30

int main( )
{
 int irow,irequested_qty,iscores[LIMIT];
 float fsum=0,imax_score=0,imin_score=100,faverage;

 cout << “\nEnter the number of scores to be averaged: ”;
 cin >>  irequested_qty;
 if(irequested_qty > LIMIT) {
   cout << “\nYou can only enter up to ” << LIMIT << \
           “ scores” << “ to be averaged.\n”;
   cout << “\n        >>> Program was exited. <<<\n”;
   exit;
 }
 for(irow = 0; irow < irequested_qty; irow++) {
   cout << “\nPlease enter a grade ” << irow+1 << “:  ”;
   cin >> iscores[irow];
 }

 for(irow = 0; irow < irequested_qty; irow++)
   fsum = fsum + iscores[irow];

 faverage = fsum/(float)irequested_qty;

 for(irow = 0; irow < irequested_qty; irow++) {
   if(iscores[irow] > imax_score)
     imax_score = iscores[irow];
   if(iscores[irow] < imin_score)
     imin_score = iscores[irow];
 }

 cout << “\nThe maximum grade is ” << imax_score;
 cout << “\nThe minimum grade is ” << imin_score;
 cout << “\nThe average grade is ” << faverage;

 return(0);
}
The application starts by including the PROCESS.H header file. Either PROCESS.H or STDLIB.H can be included to prototype the function exit( ). The constant LIMIT is declared to be 30 and is used to dimension the array of integers, iscores. After the remaining variables are declared, the program prompts the user for the number of iscores to be entered. For this program, the user’s response is to be typed next to the prompt.
The application inputs the requested value into the variable irequested_qty and uses this for the if comparison. When the user wants to average more numbers than will fit in iscores, the two warning messages are printed and then the exit( ) statement is executed. This terminates the program altogether.
Examine the following listing and see if you can detect the two subtle differences between the preceding program and this one:
//
//  exit2.cpp
//  A C++ program demonstrating the use of the exit function
//  in relation to the difference between the process.h
//  and stdlib.h header files.
//  Copyright (c) Chris H. Pappas and William H. Murray, 1998
//

#include <iostream.h>
#include <stdlib.h>

#define LIMIT 30
int main( )
{
 int irow,irequested_qty,iscores[LIMIT];
 float fsum=0,imax_score=0,imin_score=100,faverage;

 cout << “\nEnter the number of scores to be averaged: ”;
 cin >>  irequested_qty;
 if(irequested_qty > LIMIT) {
   cout << “\nYou can only enter up to ” << LIMIT << \
           “ scores” << “ to be faveraged.\n”;
   cout << “\n        >>> Program was exited. <<<\n”;
   exit(EXIT_FAILURE);
 }

 for(irow = 0; irow < irequested_qty; irow++) {
   cout << “\nPlease enter a grade ” << irow+1 << “:  ”;
   cin >> iscores[irow];
 }
 for(irow = 0; irow < irequested_qty; irow++)
   fsum = fsum + iscores[irow];

 faverage = fsum/(float)irequested_qty;

 for(irow = 0; irow < irequested_qty; irow++) {
   if(iscores[irow] > imax_score)
     imax_score = iscores[irow];
   if(iscores[irow] < imin_score)
     imin_score = iscores[irow];
 }

 cout << “\nThe maximum grade is ” << imax_score;
 cout << “\nThe minimum grade is ” << imin_score;
 cout << “\nThe average grade is ” << faverage;

 return(0);
}
Here, by the inclusion of the STDLIB.H header file instead of PROCESS.H, two additional definitions became visible: EXIT_SUCCESS (which returns a value of zero) and EXIT_FAILURE (which returns an unsuccessful value). This program used the EXIT_SUCCESS definition for a more readable parameter to the function exit( ).
atexit( )
Whenever a program invokes the exit( ) function or performs a normal program termination, it can also call any registered “exit functions” posted with atexit( ). The following C program demonstrates this capability:
/*
*   atexit.c
*   A C program demonstrating the relationship between the
*   function atexit and the order in which the functions
*   declared are executed.
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>
#include <stdlib.h>

void atexit_fn1(void);
void atexit_fn2(void);
void atexit_fn3(void);

int main( )
{

 atexit(atexit_fn1);
 atexit(atexit_fn2);
 atexit(atexit_fn3);
 printf(“Atexit program entered.\n”);
 printf(“Atexit program exited.\n\n”);
 printf(“>>>>>>>>>>> <<<<<<<<<<<\n\n”);

 return(0);
}

void atexit_fn1(void)
{
 printf(“atexit_fn1 entered.\n”);
}

void atexit_fn2(void)
{
 printf(“atexit_fn2 entered.\n”);
}

void atexit_fn3(void)
{
 printf(“atexit_fn3 entered.\n”);
}
The output from the program looks like this:
Atexit program entered.
Atexit program exited.

>>>>>>>>>>> <<<<<<<<<<<

atexit_fn3 entered.
atexit_fn2 entered.
atexit_fn1 entered.
The atexit( ) function uses the name of a function as its only parameter and registers the specified function as an exit function. Whenever the program terminates normally, as in the preceding example, or invokes the exit( ) function, all atexit( ) declared functions are executed.
Technically, each time the atexit( ) statement is encountered in the source code, the specified function is added to a list of functions to execute when the program terminates. When the program terminates, any functions that have been passed to atexit( ) are executed, with the last function added being the first one executed. This explains why the atexit_fn3 output statement was printed before the similar statement in atexit_fn1. atexit( ) functions are normally used as cleanup routines for dynamically allocated objects. Since one object (B) can be built upon another (A), atexit( ) functions execute in reverse order. This would delete object B before deleting object A.

Books24x7.com, Inc 2000 –  


Visual C++ 6(c) The Complete Reference
Visual Studio 6: The Complete Reference
ISBN: B00007FYGA
EAN: N/A
Year: 1998
Pages: 207

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net