PART 2
Features of C++
Compiler options and error checking
Constants and variables
Data types and operations
Expressions and assignment
Control structures and looping
Type casting
Default parameters
Error Checking in Borland C++ 4.0 for Windows
1. Select options from main menu
2. Select project from options menu
3. Double click on messages (if preceded by a +)
3.a. This allows viewing the 8 message categories
4. Click on each message category in turn
4.a. This allows viewing of 3 to 13 check boxes
5. Click on each unchecked item to check it
6. Click on OK after completion of 8 message categories
OR
1. Select options from main menu
2. Select project from options menu
3. Click on messages
4. Click on ALL diamond to enable all messages (does not change selected messages in each category - messages not checked in each category will be disabled when the SELECTED diamond is clicked)
PROGRAM ERROR CHECKING
Borland C++ uses compiler switches or options to control the extent of error checking.
The sequence on the opposing page will make the Borland C++ compiler as error sensitive as possible.
Not all programming errors, of course, can be found during compile time. Be sure to watch for compiler, linking, and execution errors.
Thus, you should do separate compilation, linking, and running (Alt-F9, followed by F9, or Alt-F9 followed by Ctrl-F9).
To enable checking for stack overflow:
1. Select options from main menu
2. Select project from options menu
3. Click on compiler until compiler options expanded
4. Click on debugging until debugging options expanded
4. Click on TEST STACK OVERFLOW box until box is checked.
Be sure to watch for messages at the end of execution. If you have "left something behind" that is discovered at the end of execution, this is a very serious error and must be fixed.
Be particularly wary of any program that gives a “null pointer assignment” error message at the end of execution or warns of possible “memory leakage.”
Borland C++ 4.0 for Windows Error Options
The Borland C and C++ compilers have 51 to 56 independent error checking options that can be enabled or disabled. Borland C++ for Windows has 56 options divided into 8 categories.
PortabilityNon-portable pointer conversion
Non-portable pointer comparison
Constant out of range in comparison
Constant is long
Conversion may lose significant digits
Mixing pointers to different ‘char’ types
ANSI violationsVoid functions may not return a value
Both return and return with a value used
Suspicious pointer conversion
Undefined structure structure
Redefinition of macro is not identical
Hexadecimal value contains more than three digits
Bit fields must be signed or unsigned int
Identifier is declared as both external and static
Declare type prior to use in prototype
Division by zero
Initializing identifier with identifier
Initialization is only partially bracketed
Non-ANSI keyword used: word
Obsolete C++Base initialization without a class name is now obsolete
Style of function definition is now obsolete
Overloaded prefix operator used as a postfix operator
Inefficient C++ CodingFunctions containing identifier are not expanded inline
Temporary used to initialize identifier
Temporary used for parameter in call to identifier
Borland C++ 4.0 for Windows Error Options (Continued)
Potential C++ errorsConstant member identifier is not initialized
Assigning type to enumeration
Function1 hides virtual function function2
Non-const function function called for const object
Base class base1 is also a base class of base2
Array size for ‘delete’ ignored
Use qualified name to access nested type type
Handler for xxx is hidden by previous handler for yyy
Conversion to type will fail for members of virtual base base
Maximum precision used for member pointer type type
Use ‘> >‘ for nested templates instead of ‘>‘
Non-volatile function function called for volatile object
Potential ErrorsPossibly incorrect assignment
Possible use of identifier before definition
No declaration for function function
Call to function with no prototype
Function should return a value
Ambiguous operators need parentheses
Condition is always true/false
Inefficient CodingIdentifier is assigned a value that is never used
Parameter identifier is never used
Identifier is declared but never used
Structure passed by value
Unreachable code
Code has no effect
GeneralUnknown assembler instruction
Ill-formed pragma
Array variable variable is near
Superfluous & with function
Identifier is obsolete
Cannot create precompiled header: header
maxline.cpp
/* MAXLINE.CPP: Find & print the longest line from input.
Functions in separate files, parameters passed */
/* iostream.h should be in all files containing I/O */
#include <iostream.h>
/* all functions invoked should be declared external
and their type should be specified */
extern int getline(char [], int);
extern void copy(char [], char[]);
main() // Computes and prints the longest line
{
const int maxline=1000; // maximum input line size
int len,// current line length
max = 0;// maximum length seen so far
char line[maxline], // current input line
save[maxline]; // longest line saved here
while ( (len = getline(line, maxline)) > 0 )
if (len > max) // beat previous length
{
max = len; // record this length
copy(save, line); // and save line
}
if (max > 0) // there was a line
{
cout < "\nlength of longest line: " < (max-1);
cout < "\nthe longest line is:\n\n";
cout < save < endl;
}
return 0;
}
SEPARATE SOURCE FILES
Sometimes source code is so long that it must be divided into files.
Sometimes source code exists in project source code libraries for common use.
When defining classes and objects, each group of class definitions will generally reside in a separate file.
Variables and functions used across files must be declared in such a way that needed information is available when each file goes through the compiler. The extern specifier declares that variables and functions are to be found in other files. Actually, since functions are external by default, the extern specifier could have been omitted in front of the declarations (prototypes) for the functions getline and copy.
Each file can be compiled separately, or several files can be compiled together.
Finally, the parts are linked together to form the final executable version of the program.
For example, main, getline, and copy are divided into three files, with function main() in file maxline.cpp, function getline(s, lim) in file getline.cpp, and function copy(s1,s2) in file copy.cpp.
Note that the function main() in file maxline.cpp requires two extern statements to declare the functions called by the function main(), but not defined in the file maxline.cpp.
getline.cpp
/* GETLINE.CPP this routine fetches a line
- the file needs a define for input */
#include <iostream.h>
/* the file needs no external statements */
int getline(char s[], int lim)
/* Get input line into array s. Check is
performed to avoid overflowing the array. The
function getline returns the length of the input
line, including a newline character, if present.
The array s is terminated with an ascii null */
{
char c; // input character
int i = 0; // intra-line counter
while( i<lim-1 & cin.get(c) & c != '\n' )
s[i++] = c;
if (c == '\n') // did we fall out with a \n?
s[i++] = c; // if so, keep it
s[i] = '\0'; // always terminate strings!
return(i);
}
copy.cpp
// COPY.CPP: separately compiled function to copy a string
// needs no includes, defines, or externals
// copy 'from' into 'to'; assume 'to' is big enough
void copy(char to[], char from[])
{
int i = 0; // string position counter
while( (to[i] = from[i]) != '\0' ) // move & check
++i;
}
Compiling Separate Files
VMS
cxx getline
cxx copy
cxx maxline
link maxline, getline, copy
run maxline
Turbo C++
tcc -c getline
tcc -c copy
tcc maxline getline.obj copy.obj
maxline
Borland C++
bcc -c getline
bcc -c copy
bcc maxline getline.obj copy.obj
maxline
SEPARATE COMPILATION
Many times there are common functions that do not change. It is inefficient to recompile a function each time it is used in a program.
The idea is to not only divide the source code into separate files, but also to compile these files separately, storing the compiled version of the program rather than the source code.
The -c option on the tcc or bcc command tells the compiler to suppress the loading phase of the compilation (thus not looking for a function main(), nor expecting all parts of the program to be present.) It also forces the creation of the object files getline.obj and copy.obj, respectively.
Separate compilation reduces compile time if there are many programs that need the functions stored in getline.cpp and copy.cpp, or if they are lengthy functions not subject to frequent change.
In Borland C++ 4.0 for Windows you should first exit windows to run these commands from the DOS prompt. The resulting .exe file runs from the DOS prompt. If you want the program to run under Windows, add the -W compiler switch.
In Borland C++ 4.0 for Windows if you wish to the DOS compile from a DOS window you must first create a PIF file for the DOS window that specifies -1 (infinite) for extended memory (XMS) limit (KB Limit).SEPARATE COMPILATION
In VMS, the three compile lines may be replaced by the single line:
cxx maxline, getline, copy
In this case, three separate object files are created.
In addition, source files in VMS may be treated as if they were contained in a single file by using the single command line:
cxx maxline + getline + copy
In the above case, only the object file maxline.obj would be generated. (The first name is used.)
maxline2.cpp
/* MAXLINE2.CPP: Find & print the longest line from input.
Uses global variables, no parameters passed */
#include <iostream.h>
const int maxline = 1000; // maximum input line size
int max = 0; // maximum length seen so far
char line[maxline]; // current input line
char save[maxline]; // longest line saved here
int getline(void);
void copy(void);
/* Computes and prints longest line; specialized version*/
main()
{
int len; // current line length
max = 0;
while ( (len = getline()) > 0 )
if (len > max) // beat previous length
{
max = len; // record this length
copy(); // and save line
}
if (max > 0)// there was a line
{
cout < "\nlength of longest line: " < (max-1);
cout < "\nthe longest line is:\n\n";
cout < save < endl;
}
return 0;
}
maxline2.cpp EXPLANATION
The three functions comprising this program file accomplish the same goal as in maxline1.cpp, but are organized in a very different way.
In maxline1.cpp, all data was local to each function. Whenever one function needed information from another it had to be passed back and forth via parameters and return values. This is not always practical.
In maxline2.cpp, the integer max, and the character arrays line and save are defined to be external (or global) variables. This means they are available to all functions that want them without using parameters or return values. An external definition is made by merely placing the definition outside of any function.
Since the philosophy of data sharing between functions has been altered, the declarations of the functions, as well as the functions themselves, must be altered. No data needs to be passed to getline, so we must declare that getline takes no parameters. This is done with the statement
int getline(void);
which also declares that getline will (still) return an integer.
Likewise, the function copy does not need any parameters, and, since it doesn't need to return any values either, it is declared as
void copy(void);
For a function to use an external variable defined in the same file, it need do nothing but use the variable name in the correct way. For a function to use an external variable defined in another file, it must declare its use at the beginning. If another function that wished to use the variable max were written with its source code in a different file, it would need to have the following statement in the beginning:
extern int max;
maxline2.cpp (continued)
/* Get input line into array line. The function getline
returns the length of the input line, including a newline
character, if present. The array line is terminated with
an ascii null; specialized version */
int getline(void)
{
char c; // input character
int i = 0; // intra-line counter
while( i<maxline-1 & cin.get(c) & c != '\n' )
line[i++] = c;
if (c == '\n') // did we fall out with a \n?
line[i++] = c; // if so, keep it
line[i] = '\0'; // always terminate strings!
return(i);
}
/* copy: copy 'line' into 'save';
assume 'save' is big enough; specialized version */
void copy(void)
{
int i = 0; // string position counter
while( (save[i] = line[i]) != '\0' ) // move & check
++i;
}
maxline2.cpp EXPLANATION (Continued)
Note that this program becomes "easier" to write without parameters. It will probably also achieve minor performance gains in execution speed.
The functions, however, are much less general. They will only work with properly named external variables. The external names also get involved in the linking process. So while execution may go a bit faster, compiling and linking will take longer.
In general, external variables should be avoided in favor of passing parameters at almost all costs. The most notable exception to this rule is for keeping track of machine status information across a variety of routines. In particular, error status is the most common status information that might require the use of global variables.
UNIX AND DOS REDIRECTION AND PIPES
Normally, a C++ program written for a UNIX or DOS system is written to read its data from "standard input" and write its data to "standard output." Usually, standard input and standard output default to the user terminal.
If it is desired to take input from a file rather than the terminal, input redirection can be used. This is done by using the sign followed by the filename. For example, suppose that the C++ program maxline.cpp has been compiled to generate the executable file maxline.exe. To run the program, taking input from the file named mydata.dat, the following command is used:
maxline < mydata.datLikewise, if it is desired to send the output to a file rather than to a terminal, output redirection can be used. This is done by using the sign followed by the filename. Thus to run the maxline program sending the output to the file named myoutput.dat, the following command is used:
maxline > myoutput.datBoth input and output can be redirected in a single command as follows:
maxline < mydata.dat > myoutput.datSometimes it is desirable to make the output of one program the input to another following program. This is done by using the pipe construction. A pipe is constructed by placing a | character between the two processes. For example, the UNIX and DOS command more causes output to be sent to the terminal in screenfuls. To obtain the results of a C++ program at the terminal in screenfuls, use the following command:
maxline | moreVMS REDIRECTION
In VMS temporary input redirection is achieved by using a VMS command to temporarily change the default location that VMS uses for program input. Thus to run the compiled C++ program named maxline.exe that takes input from the file named mydata.dat, the following two commands need to be executed in sequence (with no other commands in between):
$ define /user_mode sys$input mydata.dat
$ run maxline
Likewise, temporary output redirection in achieved in VMS by a similar define statement. To run the compiled C++ program named maxline.exe that sends the output to a file named myoutput.dat, the following two commands need to be executed in sequence:
$ define /user_mode sys$output myoutput.dat
$ run maxline
If both input and output redirection are desired, then two define statements are required prior to the run statement. In addition, the define for sys$input must come after the define for sys$output as follows:
$ define /user_mode sys$output myoutput.dat
$ define /user_mode sys$input mydata.dat
$ run maxline
declar.cpp
/* DECLAR.CPP: The sqrt and log are math functions (in the
C or C++ library) that return the square root and
natural logarithm, respectively, of their arguments.
Both functions take doubles as their arguments and
return doubles. */
/* Under Unix, the fact that the math functions in the
math library are being used must be conveyed to the
linker. If prog.cpp is a C++ program that uses these
math functions, then the program is compiled as:
% cpp prog.cpp -o prog -lm
(-lm tells the linker to use the math library) */
#include <iostream.h>
/* The following declaration(s) for sqrt and log are
necessary - remove them or get them wrong and see what
happens. The point of this program is that all
functions MUST be declared before they are used. */
#include <math.h> // always gets it "right"
// extern double sqrt(), log(); // old C style won't work
// extern "C" double sqrt(double), log double); //Borland
// extern double sqrt(double), log(double); //VAX
// risky trying to "hand craft" library function prototype
main()
{
double c;
for ( c = 1.0; c <= 10.0; ++c )
cout < c < " " < sqrt(c) <
" " < log(c) < endl;
for ( c = 1.0; c <= 10.0; ++c)
cout < c < " " < log(c) <
" " < sqrt(c) < endl;
return 0;
}
declar.cpp EXPLANATION
This program invokes functions not included in any of the programmer's source code files. The functions are mathematical functions included in the C math library.
To use these functions two things are needed. First, the proper declarations must be given in the source file. Second, the proper object code for the functions used must be obtained.
It is very risky to try to specify the function declarations explicitly. The proper way to obtain a correct function prototype by using the statement: