User-Defined Functions
I believe I mentioned something about functions in an article at the
beginning of this tutorial, but maybe it is a good idea to brush up on
the basics before I discuss some of the more tricky aspects. Earlier, I
defined a function as a subprogram that performs some specific task and
perhaps returns a value to the calling function. If you wish to see the
syntax of a function, go here [see C++ Syntax (section 2)] before
continuing. Using functions in a program is how programmers break down
the solution to a program into logical steps. A function that is
defined for use in one program may be of value in another program that
needs to perform the same task. Let me begin by showing an example of a
function used in a program that simply determines the average of a set
of scores, given that the total of all the scores and the number of
scores are passed to the function as parameters.
float getAverage ( totalScores, number )
{
float average;
average = float ( totalScores) / number;
return average;
}
In the above function, the two arguments (called function
parameters) are passed to the function by value. Passing by value means
that the function receives copies of the arguments and any changes to
the values of the variables are not returned to the calling function.
In a case when you need to return multiple values to the calling
function, you will have to pass your arguments by reference. Passing by
reference means that instead of getting a copy of the argument, the
function parameter will share the same memory address as the argument.
In other words, when passing by reference, any changes that are made to
the values of the variables will be sent back to the calling function.
This is why passing by reference is useful for returning multiple
values a function call. All reference arguments are preceded by the
ambersand symbol (&). An example of a function prototype that
passes arguments by reference is:
void myFunction ( int& a, int& b );
Notice that type void is used to declare a function that will be
returning multiple values to the calling function. We use void because
the function will not be returning one sole value of a specific type,
and it could be returning values that are of different types. Void lets
us return as many values to the calling function as we want as long as
they are passed by reference. Let me show you a complete program that
uses a function that passes values by reference.
///////////// BEGIN PROGRAM /////////////
#include <iostream.h>
#include <stdlib.h>
void myFunction ( int a, int& b );
void main ( )
{
int x = 5;, y = 10;
myFunction ( x, y );
cout << "x = " << x << endl;
cout << "y = " << y << endl;
system("PAUSE");
return 0;
}// end main ( )
void myFunction ( int a, int& b)
{
a = b * 3 + a * 2;
b = 10 * a;
}// end myFunction ( )
///////////// END PROGRAM /////////////
OUTPUT produced by program:
x = 5
y = 400
Here is another example: Write a function that will peform the
integer division of M by N and will return the quotient and the
remainder of the division.
void Divide ( int M, int N, int& quotient, int& remainder )
{
quotient = M / N;
remainder = M % N;
}// end Divide ( )
Something that may come in handy one day when you are faced with a
problem is a function that can swap the values of two variables,
whether they are of type int, float, double, char, etc. This can be
accomplished through the use of passing functions by reference.
NOTE: You can use the same name for multiple functions in a program
as long as those functions have different signatures. A function's
signature includes the function's class, name, number of parameters,
and types and order of parameters, but does not include its return
type. For more info, seek [Function Overloading (Section 11)].
void swap ( int& x, int& y )
{
int temp;
temp = x;
x = y;
y = temp;
}// end swap ( ) for integers
void swap ( double& x, double& y )
{
double temp;
temp = x;
x = y;
y = temp;
}// end swap ( ) for double
void swap ( char& x[], char& y[] )
{
char temp[21];
temp = x;
x = y;
y = temp;
}// end swap ( ) for strings [max number of chars = 21]
Getting used to functions will take some time, and you will only
become familiar with them by using them in your programs. Be able to
distinguish between an argument being passed by value and an argument
being passed by reference. In the next section, I dig into some C++
"built in" functions that are used for specific purposes. Read on for
more about "built in" functions...
"Built In" Functions
All of the following "built in" functions are contained in the
header file #include <string.h> (using Dev-C++ compiler) so be
sure to include it when using these functions. These functions are
standard functions that are built into the C++ langauge itself in order
to perform some operation that would be much harder to do if a
programmer was trying to write a user-defined function to acheive its
purpose. There are many built in functions, and I will only cover 11 in
this article. NOTE: the last example in this article uses pointers [see
Pointers], which is covered in more detail further below.
strcpy ( destination, source );
Performs a char-by-char copy of source into destination; primarily used for string assignment.
strncpy ( destination, source, N );
Copies at most N characters from source into destination; the additional N argument must be present.
strcat ( string1, string2 );
Concatenates string2 onto the end of string1; sort of like saying
string1 += string2 ( remember that string1 must be large enough to hold
string1 + string2 chars.
strncat ( string1, string2, N );
Concatenates at most N characters from string2 onto the end of string1; the additional N argument must be present.
strcmp ( string1, string2 );
Compares string1 and string2 and returns one of the following (useful for alphabetical order):
-1 if string1 < string2
0 if string1 = string2
1 if string1 > string2
strncmp ( string1, string2, N );
Compares at most N characters of string1 and string2 and returns a result similar to strcmp ( ).
strcmpi ( string1, string2 );
Performs exact operation of strcmp ( ) except it is not case sensitive.
strncmpi ( string1, string2, N );
Performs exact operation of strncmp ( ) except it is not case sensitive.
strlen ( string );
Returns the length of the string not including the null terminator.
strchr ( string, ch );
Returns a pointer to the first occurence of a given character (ch) in string; NULL is returned if ch is not found in the string.
strrchr ( string, ch );
Similar to strchr ( ) except it returns a pointer to the last (right most) occurence of a given char in string.
Suppose we have the following code segment in a program:
char string1[20] = "Programming";
char string2[20] = "Computer";
char string3[20] = "Programs";
char string4[20] = "proGRAMMING";
cout << strlen ( string1 );
cout << strcmp ( string1, string3 );
cout << strcmp ( string2, string3 );
cout << strncmp ( string1, string3, 6 );
cout << strcmpi ( string1, string4 );
OUTPUT produced from the above code segment would be using Dev's compiler:
11
-1
-1
0
0
Example: Suppose char name[30] contains a person's name in the following format:
First I. Last
Write a code segment that will find and print the person's middle initial.
char midInitial;
char* temp;
temp = strchr( name, '.' );
if ( temp = NULL )
cout << "There is no middle initial.";
else
{
temp--;
midInitial = temp[0];
cout << "The person's middle initial is: " << midInitial << endl << endl;
}
A pointer is used in the above example. Pointers are useful for
allowing direct access to the location of a variable in the memory of a
computer. Read on for more about pointers...
Using Pointers
A pointer provides direct access to the memory addresses deep
within the mind of a computer. They provide efficient methods and
techniques for manipulating data in arrays, they are used in functions
as reference parameters, and they are the basis for dynamic allocations
of memory.
A pointer is a derived data type. Its value is any of the memory
addresses available in a computer for storing and accessing data. A
pointer is built on the basic concept of a pointer constant, which is
drawn from the set of addresses for a computer and exists by itself. We
as programmers cannot change them; we can only use them. Every variable
that is declared in C++ has an associated memory location with it; the
location value can be thought of as a pointer constant.
Even though addresses are constant, there is no way to know or
predict what they will be during each new compile and run of a program.
We must still refer to these addresses symbolically to be able to work
with them. The address operator ( & ) makes it possible to
associate a pointer constant with any named location in memory. For
example,
&name
points directly to the memory location designated for name.
NOTE: When the ampersand ( & ) symbol is used as a prefix to a
variable name, it "means" address of variable. When it is used as a
suffix to a type, it "means" it is a reference parameter.
For int, float, double, and other types, ( two or four byte ), the
first byte in memory location for the specified variable is used as the
pointer. This byte is also referred to as the least significant byte (
LSB ). For char types, there is only one byte in memory so therefore
that byte serves as the location in memory for a pointer.
When you store the address of a variable into another variable, the
variable that holds the address is called a pointer variable. Accessing
a variable through a pointer requires use of the indirection operator (
* ) before the pointer variable name. You also use the indirection
operator ( * ) to define and declare pointer variables. For example,
char *p;
int *a;
float *s;
One of the most common errors by novices and professionals alike is
uninitialized pointers. As with variables, it is possible to initialize
pointers when they are declared and defined. For example,
int x;
int *p = &x;
However, it is not always recommended to initialize pointers. You could also initialize a pointer to nothing by issuing:
int *p = NULL;
Pointers are useful with functions. When dealing with passing
variables to functions, you can pass by value, reference, or by a
pointer which is an alternative for passing by reference. Passing by
reference and by pointer will accomplish the same task: changing the
values in the calling function's scope, but passing by reference is
highly recommended over passing by pointer.
Example 1: Using pointers as parameters in a swap function.
int a = 5;
int b = 10;
swap ( &a, &b );
.
.
.
void swap ( *px, *py )
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
Example 2: Suppose char name[30] contains a person's name in the following format:
First I. Last
Write a code segment that will find and print the person's middle initial.
char midInitial;
char* temp;
temp = strchr( name, '.');
if ( temp = NULL )
cout << "There is no middle initial.";
else
{
temp--;
midInitial = temp[0];
cout << "The person's middle initial is: " << midInitial << endl << endl;
}
Dynamically Allocating / Releasing Memory
Pointers "point" directly to internal memory locations in a
computer's hardware. A problem can arise when you need to assign a
value to a pointer that is larger than the pointer can handle. For
example, consider the situation where you have a pointer named quote
that is declared as follows:
char* quote;
Now, for instance, let's say that quote will be given a value somewhere in the program as follows:
quote = "C++ Rocks";
The program assigned "C++ Rocks", disregard the quotes, during
execution. Now, consider the situation which arises when we try to
assign "C++ Ripped Apart Rocks" to quote, which currently contains "C++
Rocks". With the current value of "C++ Rocks", quote has a size of 13
characters and is generally occupying 13 blocks of internal memory. The
value we wish to give it, "C++ Ripped Apart Rocks", has a size of 22
characters, and would generally need to occupy 22 blocks of memory.
Thus, if we tried to assign quote the value of "C++ Ripped Apart Rocks"
an error would occur because quote currently does not have enough
memory capacity to handle it. Therefore, there has to be some way we
can handle this type of situation, and the solution ultimately lies in
how we can allocate new memory for quote.
We can dynamically allocate and release memory for structured data
and non-structured data. Structured data is complex data which may
occupy many blocks of memory such as arrays, objects, strings.
Non-structured data is simple data which generally occupy 1 block of
memory such as integers, floating point values, double values, and
character values. In our example, we are using structured data since
quote is a pointer initially containing "C++ Rocks", which is a series
of character values or a string.
The general form for dynamically allocating or releasing memory for structured data is as follows:
type* ptrName; --> declaration of pointer
.
.
// ptrName gets a value
.
.
delete [ ] ptrName; --> release or "free" previously allocated memory for ptrName
.
.
ptrName = new type[size]; --> allocate memory for "new"; size is the size needed to handle the pointer data ptrName
The general form for dynamically allocating or releasing memory for non-structured data is as follows:
type* ptrName; --> declaration of pointer
.
.
// ptrName gets a value
.
.
delete ptrName; --> release or "free" previously allocated memory for ptrName
.
.
ptrName = new type; --> allocate memory for "new"
NOTE: When allocating memory, new is an operator that accomplishes
two things: it allocates the needed memory for the pointer, and it
returns or results the beginning address of the allocated memory.
Our previous quote example, could be handled as illustrated in the
following complete program, which was written using Dev-C++'s V.4
compiler.
#include <stdlib.h>
#include <iostream.h>
#include <string.h>
void main( )
{
char* quote = "C++ Rocks";
char* secondQuote = "C++ Ripped Apart Rocks";
cout << "Initially, your quote was " << '"' << quote << '"';
cout << endl << endl;
delete [] quote;
quote = new char[strlen(secondQuote)+1];
strcpy(quote, secondQuote);
cout << "Now, you prefer to say " << '"' << quote << '"';
cout << endl << endl;
system("PAUSE");
}
In the next article, you will be introduced to an array. An array
is necessary for programs that require storage of many values. Read on
for more about using arrays in your programs...
- Jan 07 Fri 2005 01:14
Programming in C++ - In-Depth Look at Functions...
close
Programming in C++ - In-Depth Look at Functions / Pointers
全站熱搜
留言列表