Functions are the building
blocks of C and C++ and the place where all program activity occurs. This
chapter examines their C-like features, including passing arguments, returning
values, prototypes, and recursion.
The General Form of a Function
The general form of a function
is ret-type function-name(parameter list)
{
body of the
function
}
The ret-type specifies the type of data
that the function returns.Afunction may return any type of data except an
array. The parameter
list is a
comma-separated list of variable names and their associated types that receive
the values of the arguments when the function is called. Afunction may
bewithout parameters, in which case the parameter list is empty. However, even
if there are no parameters, the parentheses are still required. In variable
declarations, you can declare many variables to be of a common type by using a
comma-separated list of variable names. In contrast, all function parameters must
be declared individually, each including both the type and name. That is, the parameter
declaration list for a function takes this general form:
For example, here are correct
and incorrect function parameter declarations:
f(int i, int k,
int j) /* correct */
f(int i, k,
float j) /* incorrect */
Scope Rules of Functions
The scope rules of a language are the rules
that govern whether a piece of code knows about or has access to another piece
of code or data. Each function is a discrete block of code. A function's code
is private to that function and cannot be accessed by any statement in any
other function except through a call to that function. (For instance, you
cannot use goto to jump into the middle of
another function.) The code that constitutes the body of a function is hidden
from the rest of the program and, unless it uses global variables or data, it can
neither affect nor be affected by other parts of the program. Stated another
way, the code and data that are defined within one function cannot interact
with the code or data defined in another function because the two functions
have a different scope. Variables that are defined within a function are called
local variables. A local variable
comes into existence when the function is entered and is destroyed upon exit.
That is, local variables cannot hold their value between function calls. The
only exception to this rule is when the variable is declared with the static storage class specifier. This
causes the compiler to treat the variable as if it were a global variable for
storage purposes, but limits its scope to within the function.
In C (and C++) you cannot
define a function within a function. This is why neither C nor C++ are
technically block-structured languages.
Function Arguments
If a function is to use
arguments, it must declare variables that accept the values of the arguments.
These variables are called the formal parameters of the function. They behave like other local variables inside the
function and are created upon entry into the function and destroyed upon exit.
As shown in the following function, the parameter declarations occur after the
function name:
/* Return 1 if c
is part of string s; 0 otherwise. */
int is_in(char
*s, char c)
{
while(*s)
if(*s==c) return
1;
else s++;
return 0;
}
The function is_in() has two parameters: s and c. This function returns 1 if
the character c is part of the string s; otherwise, it returns 0. As with local variables, you may make
assignments to a function's formal parameters or use them in an expression.
Even though these variables perform the special task of receiving the value of
the arguments passed to the function,you can use them as you do any other local
variable.
Call by Value, Call by Reference
In a computer language, there
are two ways that arguments can be passed to a subroutine. The first is known
as call by value. This method copies the value of an argument into the formal
parameter of the subroutine. In this case, changes made to the parameter have
no effect on the argument. Call by reference is the second way of passing arguments to a subroutine. In this method,
the address of an argument is copied into
the parameter. Inside the subroutine, the address is used to access the actual
argument used in the call. This means that changes made to the parameter affect
the argument. By default, C/C++ uses call by value to pass arguments. In general,
this means that code within a function cannot alter the arguments used to call
the function. Consider the following program:
#include
<stdio.h>
int sqr(int x);
int main(void)
{
int t=10;
printf("%d
%d", sqr(t), t);
return 0;
}
int sqr(int x)
{
x = x*x;
return(x);
}
In this example, the value of
the argument to sqr() , 10, is copied into the parameter x. When the assignment x = x*x takes place, only the local
variable x is modified. The variable t, used to call sqr() , still has the value 10.
Hence, the output is 100 10. Remember that it is a copy of the value of the argument that is
passed into the function. What occurs inside the function has no effect on the
variable used in the call.
Creating a Call by Reference
Even though C/C++ uses call by
value for passing parameters, you can create a call by reference by passing a
pointer to an argument, instead of the argument itself. Since the address of
the argument is passed to the function, code within the function can change the
value of the argument outside the function. Pointers are passed to functions
just like any other value. Of course, you need to declare the parameters as
pointer types. For example, the function swap() , which exchanges the values of the two integer variables pointed
to by its arguments, shows how.
void swap(int
*x, int *y)
{
int temp;
temp = *x; /*
save the value at address x */
*x = *y; /* put
y into x */
*y = temp; /*
put x into y */
}
swap() is able to exchange the values
of the two variables pointed to by x and y because their addresses (not their values) are passed. Thus,
within the function, the contents of the variables can be accessed using
standard pointer operations, and the contents of the variables used to call the
function are swapped. Remember that swap() (or any other function that uses pointer parameters) must be
called with the addresses of the arguments. The following program shows the correct way to call swap() :
void swap(int
*x, int *y);
int main(void)
{
int i, j;
i = 10;
j = 20;
swap(&i,
&j); /* pass the addresses of i and j */
return 0;
}
In this example, the variable i is assigned the value 10 and j is assigned the value 20. Then
swap() is called with the addresses
of i and j. (The unary operator & is used to produce the address
of the variables.) Therefore, the addresses of i and j, not their values, are passed
into the function swap() . C++ allows you to fully automate a call by reference through the
use of reference parameters. This feature is described in Part Two.ote
Calling Functions with Arrays
This section discusses passing
arrays as arguments to functions because it is an exception to the normal
call-by-value parameter passing.
When an array is used as a
function argument, its address is passed to a function. This is an exception to
the call-by-value parameter passing convention. In this case, the code inside
the function is operating on, and potentially altering, the actual contents of the
array used to call the function. For example, consider the function print_upper(), which prints its string
argument in uppercase:
#include
<stdio.h>
#include
<ctype.h>
void
print_upper(char *string);
int main(void)
{
char s[80];
gets(s);
print_upper(s);
printf("\ns
is now uppercase: %s", s);
return 0;
}
/* Print a string
in uppercase. */
void
print_upper(char *string)
{
register int t;
for(t=0;
string[t]; ++t) {
string[t] =
toupper(string[t]);
putchar(string[t]);
}
}
After the call to print_upper() , the contents of array s in main() will change to uppercase. If this
is not what you want, you could write the program like this:
#include
<stdio.h>
#include
<ctype.h>
void
print_upper(char *string);
int main(void)
{
char s[80];
gets(s);
print_upper(s);
printf("\ns
is unchanged: %s", s);
return 0;
}
void
print_upper(char *string)
{
register int t;
for(t=0;
string[t]; ++t)
putchar(toupper(string[t]));
}
In this version, the contents
of array s remain unchanged because its
values are not altered inside print_upper().
The standard library function gets() is a classic example of
passing arrays into functions. Although the gets() in your standard library is more sophisticated, the following
simpler version, called xgets() , will give you an idea of how it works.
/* A simple
version of the standard gets() library function. */
char *xgets(char
*s)
{
char ch, *p;
int t;
p = s; /* gets()
returns a pointer to s */
for(t=0;
t<80; ++t){
ch = getchar();
switch(ch) {
case '\n':
s[t] = '\0'; /*
terminate the string */
return p;
case '\b':
if(t>0) t--;
break;
default:
s[t] = ch;
}
}
s[79] = '\0';
return p;
}
The xgets() function must be called with a
character pointer. This, of course, can be the name of a character array, which
by definition is a character pointer. Upon entry, xgets() establishes a for loop from 0 to 79. This
prevents larger strings from being entered at the keyboard. If more than 80 characters
are entered, the function returns.
(The real gets() function does not have this
restriction.) Because C/C++ has no built-in bounds checking, you should make
sure that any array used to call xgets() can accept at least 80 characters. As you type characters on the
keyboard, they are placed in the string. If you type a backspace, the counter t is reduced by 1, effectively
removing the previous character from the array. When you press ENTER, a null is
placed at the end of the string, signaling its termination. Because the actual
array used to call xgets() is modified, upon return it contains the characters that you type.
argc and argv—Arguments
to main( )
Sometimes it is useful to pass
information into a program when you run it. Generally, you pass information
into the main() function via command line
arguments. A command line argument is the information that follows the program's name on the command
line of the operating system. For example, when you compile a program, you
might type something like the following after the command prompt: cc program_name
where program_name is a command line argument
that specifies the name of the program you wish to compile.
There are two special built-in
arguments, argv and argc, that are used to receive command
line arguments. The argc parameter holds the number of arguments on the command line and is
an integer. It is always at least 1 because the name of the program qualifies
as the first argument. The argv parameter is a pointer to an array of character pointers. Each
element in this array points to a command line argument. All command line
arguments are strings—any numbers will have to be converted by the program into
the proper internal format. For example, this simple program prints Hello and your name on the screen if
you type it directly after the program name.
#include
<stdio.h>
#include
<stdlib.h>
int main(int
argc, char *argv[])
{
if(argc!=2) {
printf("You
forgot to type your name.\n");
exit(1);
}
printf("Hello
%s", argv[1]);
return 0;
}
If you called this program name and your name were Tom, you
would type name Tom
to run the program. The output
from the program would be Hello Tom. In many environments, each command line argument must be
separated by a space or a tab. Commas, semicolons, and the like are not
considered separators. For example, run Spot, run is made up of three strings, while Herb,Rick,Fred is a single string since commas are not generally legal
separators. Some environments allow you to enclose within double quotes a
string containing spaces. This causes the entire string to be treated as a
single argument. Check your operating system documentation for details on the
definition of command line parameters for your system.
You must declare argv properly. The most common
method is char *argv[];
The empty brackets indicate
that the array is of undetermined length. You can now access the individual
arguments by indexing argv. For example, argv[0] points to the first string, which is always the program's name; argv[1] points to the first argument, and
so on.
Another short example using
command line arguments is the program called countdown, shown here. It counts down from a starting value (which is
specified on the command line) and beeps when it reaches 0. Notice that the
first argument containing the number is converted into an integer by the
standard function atoi() .If the string "display" is the second command line
argument, the countdown will also be displayed on the screen.
/* Countdown
program. */
#include
<stdio.h>
#include
<stdlib.h>
#include
<ctype.h>
#include
<string.h>
int main(int
argc, char *argv[])
{
int disp, count;
if(argc<2) {
printf("You
must enter the length of the count\n");
printf("on
the command line. Try again.\n");
exit(1);
}
if(argc==3
&& !strcmp(argv[2], "display")) disp = 1;
else disp = 0;
for(count=atoi(argv[1]);
count; --count)
if(disp)
printf("%d\n", count);
putchar('\a');
/* this will ring the bell */
printf("Done");
return 0;
}
Notice that if no command line
arguments have been specified, an error message is printed. A program with
command line arguments often issues instructions if the user attempts to run
the program without entering the proper information. To access an individual
character in one of the command line arguments, add a second index to argv. For example, the next
program displays all of the arguments with which it was called, one character
at a time:
#include
<stdio.h>
int main(int
argc, char *argv[])
{
int t, i;
for(t=0;
t<argc; ++t) {
i = 0;
while(argv[t][i])
{
putchar(argv[t][i]);
++i;
}
printf("\n");
}
return 0;
}
Remember, the first index
accesses the string, and the second index accesses the individual characters of
the string. Normally, you use argc and argv to get initial commands into your program. In theory, you can have
up to 32,767 arguments, but most operating systems do not allow more than a
few. You typically use these arguments to indicate a filename or an option. Using
command line arguments gives your program a professional appearance and facilitates
its use in batch files.
When a program does not
require command line parameters, it is common practice to explicitly declare main() as having no parameters. For C
programs this is accomplished by using the void keyword in its parameter list. (This is the approach used by the
programs in Part One of this book.) However, for C++ programs you may simply
specify an empty parameter list. In C++, the use of void to indicate an empty parameter
list is allowed, but redundant.
The names argc and argv are traditional but arbitrary.
You may name these two parameters to main() anything you like. Also, some compilers may support additional arguments
to main() , so be sure to check your
user's manual.
The return Statement
The return statement has two important uses.
First, it causes an immediate exit from the function that it is in. That is, it
causes program execution to return to the calling code. Second, it may be used
to return a value. This section examines how the return statement is used.
Returning from a Function
There are two ways that a
function terminates execution and returns to the caller. The first occurs when
the last statement in the function has executed and, conceptually, the
function's ending curly brace (}) is encountered. (Of course, the curly brace isn't actually
present in the object code, but you can think of it in this way.) For example,
the pr_reverse() function in this program
simply prints the string "I like C++" backwards on the screen and
then returns.
#include
<string.h>
#include
<stdio.h>
void
pr_reverse(char *s);
int main(void)
{
pr_reverse("I
like C++");
return 0;
}
void
pr_reverse(char *s)
{
register int t;
for(t=strlen(s)-1;
t>=0; t--) putchar(s[t]);
}
Once the string has been displayed,
there is nothing left for pr_reverse() to do, so it returns to the place from which it was called. Actually,
not many functions use this default method of terminating their execution. Most
functions rely on the return statement to stop execution either because a value must be
returned or to make a function's code simpler and more efficient. A function
may contain several return statements. For example, the find_substr() function in the following program returns the
starting position of a substring within a string, or returns −1 if no match is found.
#include
<stdio.h>
int
find_substr(char *s1, char *s2);
int main(void)
{
if(find_substr("C++
is fun", "is") != -1)
printf("substring
is found");
return 0;
}
/* Return index
of first match of s2 in s1. */
int
find_substr(char *s1, char *s2)
{
register int t;
char *p, *p2;
for(t=0; s1[t];
t++) {
p = &s1[t];
p2 = s2;
while(*p2
&& *p2==*p) {
p++;
p2++;
}
if(!*p2) return
t; /* 1st return */
}
return -1; /*
2nd return */
}
Returning Values
All functions, except those of
type void, return a value. This value
is specified by the return statement. In C, if a non-void function does not explicitly return a value via a return statement, then a garbage
value is returned. In C++, a non-void function must contain a return statement that returns a value. That is, in C++, if a function is
specified as returning a value, any return statement within it must have a value associated with it. However,
if execution reaches the end of a non-void function, then a garbage value is returned. Although this
condition is not a syntax error, it is still a fundamental error and should be
avoided. As long as a function is not declared as void, you may use it as an operand
in an expression. Therefore, each of the following expressions is valid:
x = power(y);
if(max(x,y) >
100) printf("greater");
for(ch=getchar(); isdigit(ch); )
... ;
As a general rule, a function
cannot be the target of an assignment.
A statement such as
swap(x,y) = 100; /* incorrect
statement */
is wrong. The C/C++ compiler
will flag it as an error and will not compile a program that contains it. (As
is discussed in Part Two, C++ allows some interesting exceptions to this
general rule, enabling some types of functions to occur on the left side of an assignment.)
When you write programs, your functions generally will be of three types. The first
type is simply computational. These functions are specifically designed to perform
operations on their arguments and return a value based on that operation. A computational
function is a "pure" function. Examples are the standard library functions
sqrt() and sin() , which compute the square
root and sine of their arguments. The second type of function manipulates
information and returns a value that simply indicates the success or failure of
that manipulation. An example is the library function fclose() , which is used to close a
file. If the close operation is successful, the function returns 0; if the
operation is unsuccessful, it returns EOF. The last type of function has no explicit return value. In
essence, the function is strictly procedural and produces no value. An example
is exit() , which terminates a program.
All functions that do not return values should be declared as returning type void. By declaring a function as void, you keep it from being used
in an expression, thus preventing accidental misuse. Sometimes, functions that
really don't produce an interesting result return something anyway. For
example, printf()
returns the number of
characters written. Yet it would be unusual to find a program that actually
checked this. In other words, although all functions, except those of type void, return values, you don't
have to use the return value for anything. A common question concerning
function return values is, "Don't I have to assign this value to some
variable since a value is being returned?" The answer is no. If there is
no assignment specified, the return value is simply discarded. Consider the
following program, which uses the function mul() :
#include
<stdio.h>
int mul(int a,
int b);
int main(void)
{
int x, y, z;
x = 10; y = 20;
z = mul(x, y);
/* 1 */
printf("%d",
mul(x,y)); /* 2 */
mul(x, y); /* 3
*/
return 0;
}
int mul(int a,
int b)
{
return a*b;
}
In line 1, the return value of
mul() is assigned to z. In line 2, the return value
is not actually assigned, but it is used by the printf() function. Finally, in line 3,
the return value is lost because it is neither assigned to another variable nor
used as part of an expression.
Returning Pointers
Although functions that return
pointers are handled just like any other type of function, a few important
concepts need to be discussed. Pointers to variables are neither integers nor
unsigned integers. They are the memory addresses of a certain type of data. The
reason for this distinction is because
pointer arithmetic is relative
to the base type. For example, if an integer pointer is incremented, it will
contain a value that is 4 greater than its previous value (assuming 4-byte
integers). In general, each time a pointer is incremented (or decremented), it points
to the next (or previous) item of its type. Since the length of different data
types may differ, the compiler must know what type of data the pointer is
pointing to. For this reason, a function that returns a pointer must declare
explicitly what type of pointer it is returning. For example, you should not
use a return type of int * to return a char * pointer!
To return a pointer, a
function must be declared as having a pointer return type. For example, this
function returns a pointer to the first occurrence of the character c in string s:
/* Return
pointer of first occurrence of c in s. */
char *match(char
c, char *s)
{
while(c!=*s
&& *s) s++;
return(s);
}
If no match is found, a pointer
to the null terminator is returned. Here is a short program that uses match()
:
#include
<stdio.h>
char *match(char
c, char *s); /* prototype */
int main(void)
{
char s[80], *p,
ch;
gets(s);
ch = getchar();
p = match(ch,
s);
if(*p) /* there
is a match */
printf("%s
", p);
else
printf("No
match found.");
return 0;
}
This program reads a string
and then a character. If the character is in the string, the program prints the
string from the point of match. Otherwise, it prints No match found.
Functions of Type void
One of void's uses is to explicitly
declare functions that do not return values. This prevents their use in any
expression and helps avert accidental misuse. For example, the function print_vertical() prints its string argument
vertically down the side of the screen. Since it returns no value, it is
declared as void.
void
print_vertical(char *str)
{
while(*str)
printf("%c\n",
*str++);
}
Here is an example that uses print_vertical() .
#include
<stdio.h>
void
print_vertical(char *str); /* prototype */
int main(int
argc, char *argv[])
{
if(argc > 1)
print_vertical(argv[1]);
return 0;
}
void
print_vertical(char *str)
{
while(*str)
printf("%c\n",
*str++);
}
One last point: Early versions
of C did not define the void keyword. Thus, in early C programs, functions that did not return
values simply defaulted to type int. Therefore, don't be surprised to see many examples of this in
older code.
What Does main( ) Return?
The main() function returns an integer to
the calling process, which is generally the operating system. Returning a value
from main() is the equivalent of calling exit() with the same value. If main() does not explicitly return a
value, the value passed to the calling process is technically undefined. In
practice, most C/C++ compilers automatically return 0, but do not rely on this
if portability is a concern.
Recursion
In C/C++, a function can call
itself. A function is said to be recursive if a statement in the body of the function calls itself. Recursion
is the process of defining something in terms of itself, and is sometimes
called circular
definition. A
simple example of a recursive function is factr() , which computes the factorial of an integer. The factorial of a
number n is the product of all the
whole numbers between 1 and n. For example, 3 factorial is 1 x 2 x 3, or 6. B oth factr() and its iterative equivalent
are shown here:
/* recursive */
int factr(int n)
{
int answer;
if(n==1)
return(1);
answer =
factr(n-1)*n; /* recursive call */
return(answer);
}
/* non-recursive
*/
int fact(int n)
{
int t, answer;
answer = 1;
for(t=1;
t<=n; t++)
answer=answer*(t);
return(answer);
}
The nonrecursive version of fact() should be clear. It uses a
loop that runs from 1 to n and progressively multiplies each number by the moving product. The
operation of the recursive factr() is a little more complex. When factr() is called with an argument of 1, the function returns 1.
Otherwise, it returns the product of factr(n−1)*n. To evaluate this expression,
factr() is called with n−1. This happens until n equals 1 and the calls to the function begin returning.
Computing the factorial of 2,
the first call to factr() causes a second, recursive call with the argument of 1. This call
returns 1, which is then multiplied by 2 (the original n value). The answer is then 2.
Try working through the computation of 3 factorial on your own. (You might want
to insert printf()
statements into factr() to see the level of each call
and what the intermediate answers are.) When a function calls itself, a new set
of local variables and parameters are allocated storage on the stack, and the
function code is executed from the top with these new variables. A recursive
call does not make a new copy of the function. Only the values being operated
upon are new. As each recursive call returns, the old local variables and
parameters are removed from the stack and execution resumes at the point of the
function call inside the function. Recursive functions could be said to "telescope"
out and back.
Most recursive routines do not
significantly reduce code size or improve memory utilization. Also, the
recursive versions of most routines may execute a bit slower than their
iterative equivalents because of the overhead of the repeated function calls.
In fact, many recursive calls to a function could cause a stack overrun.
Because storage for function parameters and local variables is on the stack and
each new call creates a new copy of these variables, the stack could be
overrun. However, you probably will not have to worry about this unless a
recursive function runs wild.
The main advantage to
recursive functions is that you can use them to create clearer and simpler
versions of several algorithms. For example, the quicksort algorithm is difficult
to implement in an iterative way. Also, some problems, especially ones related to
artificial intelligence, lend themselves to recursive solutions. Finally, some
people seem to think recursively more easily than iteratively.
When writing recursive
functions, you must have a conditional statement, such as an if, somewhere to force the
function to return without the recursive call being executed. If you don't, the
function will never return once you call it. Omitting the conditional statement
is a common error when writing recursive functions. Use printf() liberally during program
development so that you can watch what is going on and abort execution if you
see a mistake.
Function Prototypes
In C++ all functions must be
declared before they are used. This is normally accomplished using a function prototype. Function prototypes were not
part of the original C language. They were, however, added when C was
standardized. While prototypes are not technically required by Standard C,
their use is strongly encouraged. Prototypes have always been required by C++. In this book, all
examples include full function prototypes. Prototypes enable both C and C++ to
provide stronger type checking, somewhat like that provided by languages such
as Pascal. When you use prototypes, the compiler can find and report any
illegal type conversions between the type of arguments used to call a function
and the type definition of its parameters. The compiler will also catch
differences between the number of arguments used to call a function and the
number of parameters in the function.
The general form of a function
prototype is
type
func_name(type parm_name1, type parm_name2,. . .,
type
parm_nameN);
The use of parameter names is
optional. However, they enable the compiler to identify any type mismatches by
name when an error occurs, so it is a good idea to include them. The following
program illustrates the value of function prototypes. It produces an error
message because it contains an attempt to call sqr_it() with an integer argument instead
of the integer pointer required. (It is illegal to convert an integer into a
pointer.)
/* This program
uses a function prototype to enforce strong type checking. */
void sqr_it(int
*i); /* prototype */
int main(void)
{
int x;
x = 10;
sqr_it(x); /*
type mismatch */
return 0;
}
void sqr_it(int
*i)
{
*i = *i * *i;
}
A function's definition can
also serve as its prototype if the definition occurs prior to the function's
first use in the program. For example, this is a valid program.
#include
<stdio.h>
/* This
definition will also serve as a prototype within this program. */
void f(int a,
int b)
{
printf("%d
", a % b);
}
int main(void)
{
f(10,3);
return 0;
}
In this example, since f() is defined prior to its use in
main(), no separate prototype is
required. While it is possible for a function's definition to serve as its prototype
in small programs, it is seldom possible in large ones especially when several files are used. The programs in this book
include a separate prototype for each function because that is the way C/C++
code is normally written in practice.
The only function that does
not require a prototype is main(), since it is the first function called when your program begins. Because
of the need for compatibility with the original version of C, there is a small
but important difference between how C and C++ handle the prototyping of a function
that has no parameters. In C++, an empty parameter list is simply indicated in
the prototype by the absence of any parameters. For example,
int f();
/* C++ prototype for a function with no
parameters */
However, in C this prototype
means something different. For historical reasons, an empty parameter list
simply says that no parameter information is given. As far as the compiler is concerned, the function could
have several parameters or no parameters. In C, when a function has no
parameters, its prototype uses void inside the parameter list. For example, here is f() 's prototype as it would
appear in a C program.
float f(void);
This tells the compiler that
the function has no parameters, and any call to that function that has
parameters is an error. In C++, the use of void inside an empty parameter list is still allowed, but is redundant.
In C++, f( ) and f(void) are equivalent.
Function prototypes help you
trap bugs before they occur. In addition, they help verify that your program is
working correctly by not allowing functions to be called with mismatched
arguments.
One last point: Since early
versions of C did not support the full prototype syntax, prototypes are
technically optional in C. This is necessary to support pre-prototype C code.
If you are porting older C code to C++, you may need to add full function prototypes
before it will compile. Remember: Although prototypes are optional in C, they
are required by C++. This means that every function in a C++ program must be fully
prototyped.
Standard Library Function Prototypes
Any standard library function
used by your program must be prototyped. To accomplish this, you must include
the appropriate header for each library function. All necessary headers are
provided by the C/C++ compiler. In C, all headers are files that use the .H
extension. In C++, headers may be either separate files or built into the
compiler itself. In either case, a header contains two main elements: any
definitions used by the library functions and the prototypes for the library
functions. For example,
stdio.h is included in almost all
programs in this part of the book because it contains the prototype for printf().
Remember
Declaring Variable-Length Parameter Lists
You can specify a function
that has a variable number of parameters. The most common example is printf() . To tell the compiler that an
unknown number of arguments may be passed to a function, you must end the declaration
of its parameters using three periods. For example, this prototype specifies
that func() will have at least two integer
parameters and an unknown number (including 0) of parameters after that.
int func(int a, int b, ...);
This form of declaration is
also used by a function's definition. Any function that uses a variable number
of parameters must have at least one actual parameter. For example, this is
incorrect:
int func(...);
/* illegal */
Old-Style Versus Modern
Function Parameter
Declarations
Early versions of C used a
different parameter declaration method than does either Standard C or Standard
C++. This early approach is sometimes called the classic form. This book uses a
declaration approach called the modern form. Standard C supports both forms, but strongly recommends the
modern form. Standard C++ only supports the modern parameter declaration
method. However, you should know the old-style form because many older C
programs still use it.
The old-style function
parameter declaration consists of two parts: a parameter list, which goes
inside the parentheses that follow the function name, and the actual parameter
declarations, which go between the closing parentheses and the function's opening
curly brace. The general form of the old-style parameter definition is
type func_name(parm1, parm2, . . .parmN)
type parm1;
type parm2;
.
..
type parmN;
{
function code
}
For example, this modern
declaration:
float f(int a,
int b, char ch)
{
/* ... */
}
will look like this in its
old-style form:
float f(a, b,
ch)
int a, b;
char ch;
{
/* ... */
}
Notice that the old-style form
allows the declaration of more than one parameter in a list after the type
name.
The old-style form of
parameter declaration is designated as obsolete by the C language and is not supported
by C++.
Implementation Issues
There are a few important
things to remember about functions that affect their efficiency and usability.
These issues are the subject of this section.
Parameters and General-Purpose Functions
A general-purpose function is
one that will be used in a variety of situations, perhaps by many different
programmers. Typically, you should not base general-purpose functions on global
data. All of the information a function needs should be passed to it by its
parameters. When this is not possible, you should use static variables.Besides
making your functions general purpose, parameters keep your code readable and
less susceptible to bugs resulting from side effects.
Efficiency
Functions are the building
blocks of C/C++ and are crucial to all but the simplest programs. However, in
certain specialized applications, you may need to eliminate a function and
replace it with inline code. Inline code performs the same actions as a function, but
without the overhead associated with a function call. For this reason, inline
code is often used instead of function calls when execution time is critical. Inline
code is faster than a function call for two reasons. First, a CALL instruction takes
time to execute. Second, if there are arguments to pass, these have to be
placed on the stack, which also takes time. For most applications, this very
slight increase in execution time is of no significance. But if it is, remember
that each function call uses time that would be saved if the function's code
were placed in line. For example, the following are two versions of a program
that prints the square of the numbers from 1 to 10. The inline version runs
faster than the other because the function call adds time. in line function call.
#include
<stdio.h>
int sqr(int a);
int main(void)
int main(void)
{ {
int x; int x;
for(x=1;
x<11; ++x) for(x=1; x<11; ++x)
printf("%d",
x*x); printf("%d", sqr(x));
return 0; return
0;
} }
int sqr(int a)
{
return a*a;
}
In C++, the concept of inline
functions is expanded and formalized. In fact, inline functions are an
important component of the C++ language.
Translate Bahasa Indonesia :
Fungsi adalah blok bangunan dari C dan C++
dan tempat di mana semua program aktivitas terjadi. Bab ini membahas C-fitur
seperti mereka, termasuk lewat argumen, kembali nilai-nilai, prototipe, dan
rekursi.
Bentuk
Umum Fungsi
Bentuk
umum dari suatu fungsi ret-tipe fungsi-nama (daftar parameter)
{
tubuh fungsi
tubuh fungsi
}
The ret-jenis menentukan jenis data yang
returns.Afunction fungsi dapat kembali semua jenis data kecuali array. Daftar
parameter adalah suatu daftar comma-separated variabel nama dan jenis yang
terkait yang menerima nilai-nilai dari argumen ketika
fungsi panggil. Sebuah fungsi mungkin saja tanpa ada parameter, dalam hal ini daftar parameter kosong. Namun, bahkan jika tidak ada parameter, tanda kurung masih diperlukan.
Dalam deklarasi variabel, Anda dapat mendeklarasikan banyak variabel untuk menjadi jenis umum dengan menggunakan suatu daftar comma-separated dari nama variabel. Sebaliknya, semua parameter fungsi harus dinyatakan secara individual, masing-masing termasuk jenis dan nama. Artinya, Parameter deklarasi daftar untuk fungsi mengambil bentuk umum:
fungsi panggil. Sebuah fungsi mungkin saja tanpa ada parameter, dalam hal ini daftar parameter kosong. Namun, bahkan jika tidak ada parameter, tanda kurung masih diperlukan.
Dalam deklarasi variabel, Anda dapat mendeklarasikan banyak variabel untuk menjadi jenis umum dengan menggunakan suatu daftar comma-separated dari nama variabel. Sebaliknya, semua parameter fungsi harus dinyatakan secara individual, masing-masing termasuk jenis dan nama. Artinya, Parameter deklarasi daftar untuk fungsi mengambil bentuk umum:
f (tipe varname1, tipe varname2, ..., varnameN
jenis)
Sebagai contoh, berikut adalah deklarasi fungsi
benar dan salah parameter:
f
(int i, int k, int j) / * benar * /
f (int i, k,
float j) / * salah * /
Lingkup Aturan Fungsi
Ruang lingkup aturan dari bahasa adalah
aturan yang mengatur apakah sepotong kode yang tahu tentang atau memiliki akses
ke bagian dari kode atau data.
Fungsi masing-masing adalah blok diskrit
kode. Kode Fungsi adalah swasta untuk fungsi yang dan tidak dapat diakses oleh
setiap pernyataan dalam fungsi lainnya kecuali melalui panggilan untuk fungsi.
(Misalnya, Anda tidak dapat menggunakan goto untuk melompat ke tengah lain Fungsi.)
Kode yang merupakan tubuh fungsi tersembunyi dari sisa program dan, kecuali
menggunakan variabel global atau data, tidak dapat mempengaruhi atau
dipengaruhi oleh bagian lain dari program tersebut. Lain cara lain, kode dan
data yang didefinisikan dalam satu fungsi tidak dapat berinteraksi dengan kode
atau data yang didefinisikan dalam fungsi lain karena kedua fungsi memiliki
ruang lingkup yang berbeda.
Variabel yang didefinisikan dalam fungsi
disebut variabel lokal. Lokal variabel datang menjadi ada ketika fungsi yang
dimasukkan dan dihancurkan pada keluar. Artinya, variabel lokal tidak dapat
memegang nilai mereka antara pemanggilan fungsi. Satu-satunya pengecualian
untuk aturan ini adalah ketika variabel dinyatakan dengan kelas penyimpanan
statis specifier. Hal ini menyebabkan compiler untuk mengobati variabel
seolah-olah itu adalah sebuah variabel global untuk tujuan penyimpanan, namun
membatasi ruang lingkup pada dalam fungsi.
Dalam C (dan C + +) Anda tidak dapat
menentukan fungsi dalam fungsi. Inilah sebabnya mengapa tidak C atau C + +
secara teknis blok-terstruktur bahasa.
Argumen
Fungsi
Jika fungsi adalah dengan menggunakan
argumen, harus mendeklarasikan variabel yang menerima nilai-nilai dari argumen.
Variabel ini dipanggil parameter formal fungsi. Mereka berperilaku seperti
variabel lokal lainnya dalam fungsi dan diciptakan pada saat masuk ke dalam
fungsi dan hancur setelah keluar. Seperti ditunjukkan dalam fungsi berikut, deklarasi
parameter jatuh setelah nama fungsi:
/
* Kembali 1 jika c adalah bagian dari string s, 0 sebaliknya. * /
int
is_in (char * s, char c)
{
sementara (* s)
sementara (* s)
if
(* s == c) return 1;
lain
s + +;
return
0;
}
The is_in function () memiliki dua
parameter: s dan c. Fungsi ini mengembalikan 1 jika c karakter merupakan bagian
dari string s, jika tidak, ia mengembalikan 0.
Seperti variabel lokal, Anda dapat membuat
tugas untuk fungsi yang resmi parameter atau menggunakannya dalam sebuah
ekspresi. Meskipun variabel ini melakukan tugas khusus menerima nilai dari
argumen dilewatkan ke fungsi, Anda dapat menggunakannya seperti yang Anda
lakukan setiap variabel lokal lainnya.
Panggilan dengan Nilai, Call oleh Referensi
Dalam bahasa komputer, ada dua cara yang argumen dapat dikirimkan ke subroutine.
Yang pertama dikenal sebagai panggilan dengan nilai. Metode ini salinan nilai
dari suatu argumen ke dalam parameter formal dari subrutin tersebut. Dalam hal
ini, perubahan yang dibuat pada parameter tidak berpengaruh pada argumen.
Panggilan dengan referensi adalah cara
kedua melewati argumen untuk subrutin. Dalam hal ini metode, alamat argumen
yang disalin ke parameter. Di dalam subrutin, alamat yang digunakan untuk
mengakses argumen aktual digunakan dalam panggilan. Ini berarti bahwa perubahan
yang dibuat untuk parameter mempengaruhi argumen itu.
Secara default, C / C + + menggunakan panggilan dengan nilai untuk lulus argumen. Secara umum, ini berarti bahwa kode dalam fungsi tidak dapat mengubah argumen yang digunakan untuk memanggil fungsi. Mempertimbangkan program berikut:
Secara default, C / C + + menggunakan panggilan dengan nilai untuk lulus argumen. Secara umum, ini berarti bahwa kode dalam fungsi tidak dapat mengubah argumen yang digunakan untuk memanggil fungsi. Mempertimbangkan program berikut:
#
Include
int
sqr (int x);
int
main (void)
{
int t = 10;
int t = 10;
printf
("% d% d", sqr (t), t);
return
0;
}
int sqr (int x)
int sqr (int x)
{
x = x * x;
x = x * x;
kembali
(x);
}
Dalam contoh ini, nilai dari argumen ke sqr
(),, 10 yang disalin ke parameter x. Ketika tugas x = x * x terjadi, hanya
variabel x lokal dimodifikasi. Itu t variabel, digunakan untuk memanggil sqr
(), masih memiliki nilai 10. Oleh karena itu, output adalah 100 10.
Ingat bahwa itu adalah salinan dari nilai argumen yang dilewatkan ke dalam fungsi. Apa yang terjadi di dalam fungsi tidak berpengaruh pada variabel yang digunakan dalam panggilan.
Ingat bahwa itu adalah salinan dari nilai argumen yang dilewatkan ke dalam fungsi. Apa yang terjadi di dalam fungsi tidak berpengaruh pada variabel yang digunakan dalam panggilan.
Membuat
Call oleh Referensi
Meskipun C / C + + menggunakan panggilan
dengan nilai parameter yang lewat, Anda dapat membuat panggilan dengan
referensi dengan melewatkan pointer ke sebuah argumen, bukan argumen itu
sendiri. Karena alamat argumen dilewatkan ke kode, fungsi dalam fungsi dapat
mengubah nilai argumen di luar fungsi.
Pointer yang dilewatkan ke fungsi seperti
nilai lain. Tentu saja, Anda perlu untuk menyatakan parameter sebagai jenis
pointer. Misalnya, fungsi swap (), yang pertukaran nilai-nilai dari dua
variabel integer ditunjuk oleh argumen, menunjukkan bagaimana.
void
swap (int * x, int * y)
{
int temp;
int temp;
temp
= * x; / * menyimpan nilai di alamat x * /
*
X = * y; / * menempatkan y ke x * /
*
Y = temp; / * dimasukkan x ke y * /
}
swap () dapat menukar nilai dari dua variabel
ditunjukkan oleh x dan y karena alamat mereka (bukan nilai-nilai mereka) yang berlalu.
Dengan demikian, dalam fungsi, isi dari variabel dapat diakses menggunakan
operasi pointer standar, dan isi dari variabel yang digunakan untuk memanggil
fungsi tertukar. Ingat bahwa swap () (atau fungsi lainnya yang menggunakan
parameter pointer) harus disebut dengan alamat dari argumen. Program berikut
menunjukkan yang benar Cara untuk memanggil swap ():
void
swap (int * x, int * y);
int
main (void)
{
int i, j;
int i, j;
i
= 10;
j
= 20;
swap
(& i, j &); / * lulus alamat i dan j * /
return
0;
}
Dalam contoh ini, variabel i diberi nilai
10 dan j diberi nilai 20. Kemudian swap () disebut dengan alamat i dan j.
(Operator unary & digunakan untuk menghasilkan alamat variabel.) Oleh
karena itu, alamat i dan j, bukan mereka nilai-nilai, yang dilewatkan ke fungsi
swap ().
C + + memungkinkan Anda untuk sepenuhnya
mengotomatisasi panggilan dengan referensi melalui penggunaan referensi parameter.
Fitur ini dijelaskan di Bagian Dua.
Memanggil
Fungsi dengan Array
Bagian ini membahas melewati array sebagai
argumen untuk fungsi karena merupakan pengecualian normal call-by-nilai parameter
passing.
Ketika array digunakan sebagai argumen
fungsi, alamatnya dilewatkan ke fungsi. Ini merupakan pengecualian konvensi
lewat call-by-nilai parameter. Dalam hal ini, kode di dalam fungsi ini
beroperasi pada, dan berpotensi mengubah, isi sebenarnya dari array digunakan
untuk memanggil fungsi. Sebagai contoh, mempertimbangkan print_upper function
(), yang mencetak argumen string dalam huruf besar:
#include
<stdio.h>
#include
<ctype.h>
void
print_upper(char *string);
int main(void)
{
char s[80];
gets(s);
print_upper(s);
printf("\ns
is now uppercase: %s", s);
return 0;
}
/ * Cetak string dalam huruf
besar. * /
void
print_upper(char *string)
{
register int t;
for(t=0;
string[t]; ++t) {
string[t] =
toupper(string[t]);
putchar(string[t]);
}
}
Setelah
panggilan untuk print_upper (), isi array dalam main () akan berubah menjadi
huruf besar. Jika hal ini tidak apa yang Anda inginkan, Anda bisa menulis program seperti ini:
huruf besar. Jika hal ini tidak apa yang Anda inginkan, Anda bisa menulis program seperti ini:
#include
<stdio.h>
#include
<ctype.h>
void
print_upper(char *string);
int main(void)
{
char s[80];
gets(s);
print_upper(s);
printf("\ns
is unchanged: %s", s);
return 0;
}
void
print_upper(char *string)
{
register int t;
for(t=0;
string[t]; ++t)
putchar(toupper(string[t]));
}
Dalam versi ini, isi array s tetap tidak
berubah karena nilai-nilainya tidak diubah dalam print_upper ().
Fungsi perpustakaan standar mendapat ()
adalah contoh klasik melewati array ke dalam
fungsi. Meskipun mendapat () di perpustakaan standar yang lebih canggih, mengikuti versi sederhana, disebut xgets (), akan memberi Anda gambaran mengenai cara kerjanya.
fungsi. Meskipun mendapat () di perpustakaan standar yang lebih canggih, mengikuti versi sederhana, disebut xgets (), akan memberi Anda gambaran mengenai cara kerjanya.
/
* Sebuah versi sederhana dari standar mendapat () fungsi perpustakaan. */
char
* xgets (char * s)
{
char ch, * p;
char ch, * p;
int
t;
p
= s; / * mendapatkan () mengembalikan pointer ke s * /
for
(t = 0; t <80, + + t) {
ch
= getchar ();
switch
(ch) {
Kasus
'\ n':
s
[t] = '\ 0'; / * mengakhiri string * /
kembali
p;
Kasus
'\ b':
if
(t> 0) t -;
break;
default:
s [t] = ch;
default:
s [t] = ch;
}
}
s [79] = '\ 0';
}
s [79] = '\ 0';
kembali
p;
}
Para xgets () fungsi harus dipanggil dengan
pointer karakter. Ini, tentu saja, bisa menjadi nama sebuah array karakter,
yang menurut definisi adalah pointer karakter. Setelah masuk, xgets ()
menetapkan loop untuk 0-79. Hal ini mencegah string yang lebih besar dari yang masuk
pada keyboard. Jika lebih dari 80 karakter dimasukkan, fungsi kembali.
(Real mendapat () fungsi tidak memiliki
pembatasan ini.) Karena C / C + + tidak memiliki built-in batas pemeriksaan,
Anda harus memastikan bahwa array apapun yang digunakan untuk memanggil xgets
() dapat menerima setidaknya 80 karakter. Saat Anda mengetik karakter pada
keyboard, mereka ditempatkan distring. Jika Anda mengetik backspace, t counter
dikurangi dengan 1, efektif menghilangkan sebelumnya karakter dari array.
Ketika Anda menekan ENTER, null ditempatkan di akhir string, sinyal diputus.
Karena array yang sebenarnya digunakan untuk memanggil xgets () adalah dimodifikasi,
setelah kembali mengandung karakter yang Anda ketik.
argc dan argv-Argumen ke main () kadang-kadang
berguna untuk menyampaikan informasi ke dalam program ketika Anda
menjalankannya. Umumnya, Anda menyampaikan informasi ke fungsi main () melalui
argumen baris perintah. Sebuah perintah argumen baris adalah informasi yang
berikut nama program pada baris perintah dari sistem operasi. Sebagai contoh,
ketika Anda mengkompilasi sebuah program, Anda mungkin mengetik sesuatu seperti
berikut setelah command prompt:
cc program_name dimana program_name adalah
baris perintah argumen yang menentukan nama program anda ingin mengkompilasi.
Ada dua khusus built-in argumen, argv dan
argc, yang digunakan untuk menerima
baris perintah argumen. Parameter argc memegang jumlah argumen pada baris perintah dan integer. Itu selalu setidaknya 1 karena nama program memenuhi syarat sebagai argumen pertama. Parameter argv adalah pointer ke array karakter pointer. Setiap elemen dalam array ini menunjuk ke sebuah argumen baris perintah. Semua argumen baris perintah adalah string-setiap nomor harus dikonversi oleh program ke format internal yang tepat. Sebagai contoh, ini program sederhana mencetak “Halo dan nama Anda” pada layar jika Anda mengetik langsung setelah nama program.
baris perintah argumen. Parameter argc memegang jumlah argumen pada baris perintah dan integer. Itu selalu setidaknya 1 karena nama program memenuhi syarat sebagai argumen pertama. Parameter argv adalah pointer ke array karakter pointer. Setiap elemen dalam array ini menunjuk ke sebuah argumen baris perintah. Semua argumen baris perintah adalah string-setiap nomor harus dikonversi oleh program ke format internal yang tepat. Sebagai contoh, ini program sederhana mencetak “Halo dan nama Anda” pada layar jika Anda mengetik langsung setelah nama program.
#include
<stdio.h>
#include
<stdlib.h>
int main(int
argc, char *argv[])
{
if(argc!=2) {
printf("Anda
lupa mengetik nama anda.\n");
exit(1);
}
printf("Hello
%s", argv[1]);
return 0;
}
Jika Anda menyebut nama program dan nama
Anda adalah Tom, Anda akan ketik nama Tom untuk menjalankan program tersebut.
Output dari program ini akan Hello Tom.
Di banyak lingkungan, setiap argumen baris perintah harus dipisahkan oleh spasi atau tab. Koma, titik koma, dan sejenisnya tidak dianggap pemisah. Misalnya, menjalankan Spot, jalankan terdiri dari tiga senar, sementara Herb, Rick, Fred adalah string tunggal karena koma tidak pemisah umumnya hukum.
Di banyak lingkungan, setiap argumen baris perintah harus dipisahkan oleh spasi atau tab. Koma, titik koma, dan sejenisnya tidak dianggap pemisah. Misalnya, menjalankan Spot, jalankan terdiri dari tiga senar, sementara Herb, Rick, Fred adalah string tunggal karena koma tidak pemisah umumnya hukum.
Beberapa lingkungan memungkinkan Anda untuk
melampirkan dalam tanda kutip ganda string yang berisi spasi. Hal ini
menyebabkan seluruh string diperlakukan sebagai sebuah argumen tunggal. Periksa
operasi sistem dokumentasi untuk rincian tentang definisi baris perintah parameter
untuk sistem anda.
Anda harus menyatakan argv benar. Metode
yang paling umum adalah char * argv [];
Tanda kurung yang kosong menunjukkan bahwa
array adalah panjang ditentukan. Sekarang Anda dapat mengakses argumen individu
oleh argv pengindeksan. Misalnya, argv [0] menunjuk ke pertama string, yang
selalu nama program, argv [1] menunjuk ke argumen pertama, dan sebagainya.
Contoh lain pendek menggunakan argumen
baris perintah adalah program yang disebut countdown, ditampilkan di sini. Ini
menghitung mundur dari nilai awal (yang ditetapkan pada baris perintah) dan
mengeluarkan bunyi bip saat mencapai 0. Perhatikan bahwa argumen pertama mengandung
nomor diubah menjadi integer oleh atoi fungsi standar (). Jika string
"display" adalah argumen baris perintah kedua, hitung mundur juga
akan ditampilkan pada layar.
/* Program
Countdown. */
#include
<stdio.h>
#include
<stdlib.h>
#include
<ctype.h>
#include
<string.h>
int main(int
argc, char *argv[])
{
int disp, count;
if(argc<2) {
printf("Anda
harus memasukan panjang count\n");
printf("Pada
baris perinrah. Coba lagi.\n");
exit(1);
}
if(argc==3
&& !strcmp(argv[2], "display")) disp = 1;
else disp = 0;
for(count=atoi(argv[1]);
count; --count)
if(disp)
printf("%d\n", count);
putchar('\a');
/* Ini akan membunyikan bell */
printf("Selesai");
return 0;
}
Perhatikan bahwa jika argumen perintah ada
garis telah ditetapkan, pesan kesalahan dicetak. Sebuah program dengan argumen
baris perintah yang sering mengeluarkan petunjuk jika pengguna mencoba untuk
menjalankan program tanpa memasukkan informasi yang tepat.
Untuk mengakses karakter individu di salah
satu argumen baris perintah, tambahkan kedua indeks argv. Sebagai contoh,
program berikutnya menampilkan semua argumen dengan yang disebut, satu karakter
pada satu waktu:
#include
<stdio.h>
int main(int
argc, char *argv[])
{
int t, i;
for(t=0;
t<argc; ++t) {
i = 0;
while(argv[t][i])
{
putchar(argv[t][i]);
++i;
}
printf("\n");
}
return 0;
}
Ingat, indeks pertama mengakses string, dan
indeks kedua mengakses individu karakter dari string. Biasanya, Anda
menggunakan argc dan argv untuk mendapatkan perintah awal ke dalam program
Anda. Diteori, Anda dapat memiliki hingga 32.767 argumen, tetapi sistem operasi
yang paling tidak mengizinkan lebih dari beberapa. Anda biasanya menggunakan
argumen ini untuk menunjukkan nama file atau pilihan.
Menggunakan argumen baris perintah
memberikan program anda penampilan profesional dan memfasilitasi penggunaannya
dalam file batch. Ketika program tidak memerlukan parameter baris perintah, itu
adalah umum berlatih secara eksplisit menyatakan main () sebagai tidak memiliki
parameter. Untuk program C ini dilakukan dengan menggunakan kata kunci
kekosongan dalam daftar parameter. (Ini adalah pendekatan digunakan oleh
program-program di Bagian Satu buku ini) Namun, untuk C + + program. Anda mungkin
hanya menentukan daftar parameter kosong. Dalam C + +, penggunaan void untuk
menunjukkan daftar parameter kosong diperbolehkan, tapi berlebihan.
Nama-nama argc dan argv tradisional tapi
sewenang-wenang. Anda dapat menamai kedua parameter untuk main () apa pun yang
Anda suka. Juga, beberapa kompiler dapat mendukung tambahan argumen untuk main
(), jadi pastikan untuk memeriksa manual pengguna Anda.
The return Statement
Pernyataan kembali memiliki dua penting menggunakan.
Pertama, hal itu menyebabkan segera keluar dari fungsi itu adalah masuk
Artinya, hal itu menyebabkan eksekusi program untuk kembali ke kode panggilan.
Kedua, hal itu dapat digunakan untuk mengembalikan nilai. Bagian ini membahas
bagaimana pernyataan kembali digunakan.
Kembali dari sebuah Fungsi ada dua cara yang fungsi mengakhiri eksekusi dan kembali ke pemanggil. Itu pertama kali terjadi ketika pernyataan terakhir dalam fungsi tersebut telah dijalankan dan, secara konseptual, mengakhiri fungsi yang keriting brace (}) ditemui. (Tentu saja, tanda kurung kurawal tidak benar-benar hadir dalam kode obyek, tetapi Anda dapat memikirkan hal itu dengan cara ini) Sebagai contoh., yang
pr_reverse () fungsi dalam program ini hanya mencetak string "Saya suka C + +" mundur pada layar dan kemudian kembali.
Kembali dari sebuah Fungsi ada dua cara yang fungsi mengakhiri eksekusi dan kembali ke pemanggil. Itu pertama kali terjadi ketika pernyataan terakhir dalam fungsi tersebut telah dijalankan dan, secara konseptual, mengakhiri fungsi yang keriting brace (}) ditemui. (Tentu saja, tanda kurung kurawal tidak benar-benar hadir dalam kode obyek, tetapi Anda dapat memikirkan hal itu dengan cara ini) Sebagai contoh., yang
pr_reverse () fungsi dalam program ini hanya mencetak string "Saya suka C + +" mundur pada layar dan kemudian kembali.
#include
<string.h>
#include
<stdio.h>
void
pr_reverse(char *s);
int main(void)
{
pr_reverse("I
like C++");
return 0;
}
void
pr_reverse(char *s)
{
register int t;
for(t=strlen(s)-1;
t>=0; t--) putchar(s[t]);
}
Setelah string telah ditampilkan, tidak ada
yang tersisa untuk pr_reverse () untuk melakukan, sehingga kembali ke tempat
dari mana itu disebut.
Sebenarnya, tidak banyak fungsi menggunakan
metode default mengakhiri mereka
eksekusi. Fungsi yang paling bergantung pada pernyataan kembali untuk menghentikan eksekusi baik karena nilai harus dikembalikan atau untuk membuat kode fungsi yang lebih sederhana dan lebih efisien.
eksekusi. Fungsi yang paling bergantung pada pernyataan kembali untuk menghentikan eksekusi baik karena nilai harus dikembalikan atau untuk membuat kode fungsi yang lebih sederhana dan lebih efisien.
Sebuah fungsi mungkin berisi pernyataan
kembali beberapa. Sebagai contoh, find_substr () fungsi dalam program berikut
mengembalikan posisi awal dari substring dalam
string, atau mengembalikan -1 jika tidak ada yang cocok.
string, atau mengembalikan -1 jika tidak ada yang cocok.
#include
<stdio.h>
int
find_substr(char *s1, char *s2);
int main(void)
{
if(find_substr("C++
is fun", "is") != -1)
printf("substring
is found");
return 0;
}
/* Return index
of first match of s2 in s1. */
int
find_substr(char *s1, char *s2)
{
register int t;
char *p, *p2;
for(t=0; s1[t];
t++) {
p = &s1[t];
p2 = s2;
while(*p2 &&
*p2==*p) {
p++;
p2++;
}
if(!*p2) return
t; /* 1st return */
}
return -1; /*
2nd return */
}
Returning Values
Semua fungsi, kecuali tipe void,
mengembalikan nilai. Nilai ini ditentukan oleh kembali pernyataan. Dalam C,
jika fungsi non-void tidak secara eksplisit mengembalikan nilai melalui kembali
pernyataan, maka nilai sampah dikembalikan. Dalam C + +, fungsi non-void harus mengandung
pernyataan kembali yang mengembalikan nilai. Artinya, di C + +, jika fungsi
tersebut ditentukan sebagai kembali nilai, pernyataan kembali di dalamnya harus
memiliki nilai yang terkait dengan itu. Namun, jika eksekusi mencapai akhir
dari fungsi non-void, maka nilai sampah dikembalikan. Meskipun kondisi ini
bukan kesalahan sintaks, itu masih merupakan kesalahan mendasar dan harus
dihindari.
Selama fungsi tidak dinyatakan sebagai
batal, Anda dapat menggunakannya sebagai operan dalam ekspresi. Oleh karena
itu, setiap ekspresi berikut ini berlaku:
x = power(y);
if(max(x,y) >
100) printf("greater");
for(ch=getchar(); isdigit(ch); )
... ;
Sebagai aturan umum, fungsi tidak bisa
menjadi target tugas. Sebuah pernyataan seperti
swap (x, y) = 100; / * pernyataan yang
salah * /
salah. C / C + + compiler akan bendera itu
sebagai kesalahan dan tidak akan mengkompilasi program yang berisi itu.
(Seperti dibahas di Bagian Dua, C + + memungkinkan beberapa pengecualian menarik
untuk aturan umum ini, memungkinkan beberapa jenis fungsi terjadi di sisi kiri
dari sebuah tugas.)
Ketika Anda menulis program, fungsi Anda
umumnya akan menjadi tiga jenis. Itu Jenis pertama hanya komputasi.
Fungsi-fungsi ini secara khusus dirancang untuk melakukan operasi pada argumen
mereka dan mengembalikan nilai didasarkan pada operasi itu.
Sebuah fungsi komputasi adalah
"murni" fungsi. Contohnya adalah perpustakaan standar fungsi sqrt ()
dan dosa (), yang menghitung akar kuadrat dan sinus dari argumen mereka.
Tipe kedua fungsi memanipulasi informasi
dan mengembalikan nilai yang hanya menunjukkan keberhasilan atau kegagalan manipulasi
itu. Contohnya adalah perpustakaan Fungsi fclose (), yang digunakan untuk
menutup file. Jika operasi dekat berhasil, mengembalikan fungsi 0, jika operasi
tidak berhasil, ia mengembalikan EOF.
Jenis terakhir dari fungsi tidak memiliki nilai kembali eksplisit. Pada dasarnya, fungsi ini
ketat prosedural dan menghasilkan nilai. Contohnya adalah exit (), yang berakhir dengan program. Semua fungsi yang tidak mengembalikan nilai harus dinyatakan sebagai jenis kembali batal. Dengan menyatakan fungsi sebagai void, Anda tetap dari yang digunakan dalam ekspresi, sehingga mencegah penyalahgunaan disengaja.
Kadang-kadang, fungsi yang benar-benar tidak menghasilkan hasil pengembalian yang menarik sesuatu yang tetap. Misalnya, printf () mengembalikan jumlah karakter yang tertulis.
Namun akan menjadi tidak biasa untuk menemukan program yang benar-benar memeriksa ini. Dengan kata lain, meskipun semua fungsi, kecuali tipe void, nilai kembali, Anda tidak harus menggunakan nilai kembali untuk apa pun. Sebuah pertanyaan umum tentang nilai-nilai fungsi kembali adalah, "Bukankah aku harus menetapkan nilai ini ke beberapa variabel karena nilai dikembalikan?" Jawabannya adalah tidak. Jika tidak ada tugas yang ditentukan, nilai pengembalian hanya dibuang.
Jenis terakhir dari fungsi tidak memiliki nilai kembali eksplisit. Pada dasarnya, fungsi ini
ketat prosedural dan menghasilkan nilai. Contohnya adalah exit (), yang berakhir dengan program. Semua fungsi yang tidak mengembalikan nilai harus dinyatakan sebagai jenis kembali batal. Dengan menyatakan fungsi sebagai void, Anda tetap dari yang digunakan dalam ekspresi, sehingga mencegah penyalahgunaan disengaja.
Kadang-kadang, fungsi yang benar-benar tidak menghasilkan hasil pengembalian yang menarik sesuatu yang tetap. Misalnya, printf () mengembalikan jumlah karakter yang tertulis.
Namun akan menjadi tidak biasa untuk menemukan program yang benar-benar memeriksa ini. Dengan kata lain, meskipun semua fungsi, kecuali tipe void, nilai kembali, Anda tidak harus menggunakan nilai kembali untuk apa pun. Sebuah pertanyaan umum tentang nilai-nilai fungsi kembali adalah, "Bukankah aku harus menetapkan nilai ini ke beberapa variabel karena nilai dikembalikan?" Jawabannya adalah tidak. Jika tidak ada tugas yang ditentukan, nilai pengembalian hanya dibuang.
Perhatikan program berikut, yang
menggunakan fungsi mul():
#include
<stdio.h>
int mul(int a,
int b);
int main(void)
{
int x, y, z;
x = 10; y = 20;
z = mul(x, y);
/* 1 */
printf("%d",
mul(x,y)); /* 2 */
mul(x, y); /* 3
*/
return 0;
}
int mul(int a,
int b)
{
return a*b;
}
Sejalan 1, nilai kembalian dari mul ()
ditugaskan untuk z. Sejalan 2, nilai kembali tidak
sebenarnya ditugaskan, tetapi digunakan oleh fungsi printf (). Akhirnya, di baris 3, kembalinya nilai hilang karena tidak ditugaskan untuk variabel lain atau digunakan sebagai bagian dari ekspresi.
sebenarnya ditugaskan, tetapi digunakan oleh fungsi printf (). Akhirnya, di baris 3, kembalinya nilai hilang karena tidak ditugaskan untuk variabel lain atau digunakan sebagai bagian dari ekspresi.
Returning Pointers
Meskipun fungsi yang pointer kembali ditangani
sama seperti jenis lainnya fungsi, konsep penting yang perlu dibahas.
Pointer ke variabel yang tidak integer atau
unsigned integer. Mereka adalah alamat memori dari jenis tertentu data. Alasan
untuk perbedaan ini adalah karena aritmatika pointer adalah relatif terhadap
tipe dasar. Sebagai contoh, jika sebuah pointer integer
bertambah, maka akan berisi nilai yang lebih besar dari nilai 4 sebelumnya (dengan asumsi 4-byte integer). Secara umum, setiap kali pointer bertambah (atau decremented), maka poin ke item (atau sebelumnya) berikutnya jenisnya. Karena panjang tipe data yang berbeda mungkin berbeda, compiler harus tahu apa jenis data pointer yang menunjuk ke. Untuk alasan ini, sebuah fungsi yang mengembalikan pointer harus menyatakan secara eksplisit jenis pointer itu kembali. Misalnya, Anda tidak harus menggunakan jenis kembalinya * int untuk kembali pointer char *! Untuk mengembalikan sebuah pointer, fungsi harus dinyatakan sebagai memiliki tipe kembali pointer. Misalnya, fungsi ini mengembalikan pointer ke kejadian pertama c karakter
dalam string s:
bertambah, maka akan berisi nilai yang lebih besar dari nilai 4 sebelumnya (dengan asumsi 4-byte integer). Secara umum, setiap kali pointer bertambah (atau decremented), maka poin ke item (atau sebelumnya) berikutnya jenisnya. Karena panjang tipe data yang berbeda mungkin berbeda, compiler harus tahu apa jenis data pointer yang menunjuk ke. Untuk alasan ini, sebuah fungsi yang mengembalikan pointer harus menyatakan secara eksplisit jenis pointer itu kembali. Misalnya, Anda tidak harus menggunakan jenis kembalinya * int untuk kembali pointer char *! Untuk mengembalikan sebuah pointer, fungsi harus dinyatakan sebagai memiliki tipe kembali pointer. Misalnya, fungsi ini mengembalikan pointer ke kejadian pertama c karakter
dalam string s:
/* Return
pointer dari kejadian pertama c di s. */
char *match(char
c, char *s)
{
while(c!=*s
&& *s) s++;
return(s);
}
Jika tidak ada yang cocok, pointer ke null
terminator dikembalikan. Berikut adalah singkat Program yang menggunakan
pertandingan ():
#include
<stdio.h>
char *match(char
c, char *s); /* prototype */
int main(void)
{
char s[80], *p,
ch;
gets(s);
ch = getchar();
p = match(ch,
s);
if(*p) /* Ada
pembandingan */
printf("%s
", p);
else
printf("Tidakada
yang cocok.");
return 0;
}
Program ini membaca sebuah string dan
kemudian karakter. Jika karakter dalam string,
Program mencetak string dari sudut pertandingan. Jika tidak, ia mencetak Tidak cocok ditemukan.
Program mencetak string dari sudut pertandingan. Jika tidak, ia mencetak Tidak cocok ditemukan.
Fungsi
Tipe Void
Salah satu kegunaan kekosongan adalah untuk
secara eksplisit menyatakan fungsi yang tidak mengembalikan nilai. Ini mencegah
penggunaan mereka dalam ekspresi apapun dan membantu menghindari penyalahgunaan
disengaja. Misalnya, yang fungsi print_vertical() mencetak argumen string
secara vertikal di sisi layar. Karena tidak mengembalikan nilai, maka dinyatakan
tidak sah dan batal.
void
print_vertical(char *str)
{
while(*str)
printf("%c\n",
*str++);
}
Berikut adalah contoh yang menggunakan
print_vertical ().
#include
<stdio.h>
void
print_vertical(char *str); /* prototype */
int main(int
argc, char *argv[])
{
if(argc > 1)
print_vertical(argv[1]);
return 0;
}
void
print_vertical(char *str)
{
while(*str)
printf("%c\n",
*str++);
}
Satu titik terakhir: Versi awal dari C
tidak menentukan kata kunci void. Dengan demikian, dalam program C dini, fungsi
yang tidak mengembalikan nilai hanya gagal untuk mengetik int.
Oleh karena itu, jangan heran melihat
banyak contoh dari hal ini dalam kode yang lebih tua.
Apa yang dimaksud main() return ?
The (utama) mengembalikan fungsi integer
untuk proses pemanggilan, yang umumnya
sistem operasi. Mengembalikan nilai dari main () adalah setara dengan memanggil keluar () dengan nilai yang sama. Jika main () tidak secara eksplisit mengembalikan nilai, nilai berlalu untuk proses pemanggilan secara teknis tidak terdefinisi. Dalam prakteknya, kebanyakan C / C + + compiler otomatis kembali 0, tapi jangan bergantung pada ini jika portabilitas adalah kekhawatiran.
sistem operasi. Mengembalikan nilai dari main () adalah setara dengan memanggil keluar () dengan nilai yang sama. Jika main () tidak secara eksplisit mengembalikan nilai, nilai berlalu untuk proses pemanggilan secara teknis tidak terdefinisi. Dalam prakteknya, kebanyakan C / C + + compiler otomatis kembali 0, tapi jangan bergantung pada ini jika portabilitas adalah kekhawatiran.
Rekursi
Dalam C / C + +, fungsi dapat memanggil dirinya sendiri. Sebuah fungsi dikatakan rekursif jika pernyataan dalam tubuh fungsi menyebut dirinya. Rekursi adalah proses mendefinisikan sesuatu dalam hal itu sendiri, dan kadang-kadang disebut definisi melingkar.
Dalam C / C + +, fungsi dapat memanggil dirinya sendiri. Sebuah fungsi dikatakan rekursif jika pernyataan dalam tubuh fungsi menyebut dirinya. Rekursi adalah proses mendefinisikan sesuatu dalam hal itu sendiri, dan kadang-kadang disebut definisi melingkar.
Sebuah contoh sederhana dari fungsi
rekursif adalah factr (), yang menghitung faktorial dari integer. Faktorial
dari bilangan n adalah produk dari semua bilangan bulat antara
1 dan n. Sebagai contoh, 3 faktorial adalah 1 x 2 x 3, atau 6. B lembaga lainnya factr () dan yang berulang setara yang ditampilkan di sini:
1 dan n. Sebagai contoh, 3 faktorial adalah 1 x 2 x 3, atau 6. B lembaga lainnya factr () dan yang berulang setara yang ditampilkan di sini:
/* RecursiF */
int factr(int n)
{
int answer;
if(n==1)
return(1);
answer =
factr(n-1)*n; /* Pemanggilan Recursif */
return(answer);
}
/* non-recursif
*/
int fact(int n)
{
int t, answer;
answer = 1;
for(t=1;
t<=n; t++)
answer=answer*(t);
return(answer);
}
Versi nonrecursive fakta () harus jelas.
Ini menggunakan loop yang berjalan dari 1 sampai n dan progresif mengalikan
setiap nomor dengan produk bergerak.
Pengoperasian factr rekursif () adalah
sedikit lebih kompleks. Ketika factr () adalah
disebut dengan argumen dari 1, fungsi kembali 1. Jika tidak, ia mengembalikan produk
dari factr (n-1) * n. Untuk mengevaluasi ungkapan ini, factr () dipanggil dengan n-1. Hal ini terjadi sampai n sama dengan 1 dan panggilan ke fungsi mulai kembali.
Menghitung faktorial 2, panggilan pertama untuk factr () menyebabkan panggilan, kedua rekursif dengan argumen dari 1. Panggilan ini kembali 1, yang kemudian dikalikan dengan 2 (asli n nilai). Jawabannya adalah kemudian 2. Cobalah bekerja melalui perhitungan faktorial 3 pada Anda sendiri. (Anda mungkin ingin memasukkan pernyataan printf () ke factr () untuk melihat tingkat setiap panggilan dan apa jawaban menengah adalah.)
disebut dengan argumen dari 1, fungsi kembali 1. Jika tidak, ia mengembalikan produk
dari factr (n-1) * n. Untuk mengevaluasi ungkapan ini, factr () dipanggil dengan n-1. Hal ini terjadi sampai n sama dengan 1 dan panggilan ke fungsi mulai kembali.
Menghitung faktorial 2, panggilan pertama untuk factr () menyebabkan panggilan, kedua rekursif dengan argumen dari 1. Panggilan ini kembali 1, yang kemudian dikalikan dengan 2 (asli n nilai). Jawabannya adalah kemudian 2. Cobalah bekerja melalui perhitungan faktorial 3 pada Anda sendiri. (Anda mungkin ingin memasukkan pernyataan printf () ke factr () untuk melihat tingkat setiap panggilan dan apa jawaban menengah adalah.)
Ketika fungsi menyebut dirinya, satu set
baru variabel lokal dan parameter yang
dialokasikan penyimpanan pada stack, dan kode fungsi dijalankan dari atas dengan
baru ini variabel. Panggilan rekursif tidak membuat salinan baru dari fungsi. Hanya
nilai-nilai yang dioperasi baru. Karena setiap panggilan rekursif kembali, lama lokal
variabel dan parameter dikeluarkan dari tumpukan resume dan eksekusi di
titik panggilan fungsi dalam fungsi. Fungsi rekursif bisa dikatakan "Teleskop" keluar dan kembali.
Kebanyakan rutinitas rekursif tidak signifikan mengurangi ukuran kode atau meningkatkan daya ingat pemanfaatan. Juga, versi rekursif dari rutinitas yang paling dapat melakukan sedikit lebih lambat dari mereka berulang setara karena overhead dari fungsi panggilan ulang. Di Bahkan, panggilan rekursif banyak fungsi dapat menyebabkan pelampauan tumpukan. Karena penyimpanan untuk Fungsi parameter dan variabel lokal pada stack dan setiap panggilan baru menciptakan baru salinan dari variabel, tumpukan dapat dikuasai. Namun, Anda mungkin tidak akan perlu khawatir tentang hal ini kecuali fungsi rekursif berjalan liar.
dialokasikan penyimpanan pada stack, dan kode fungsi dijalankan dari atas dengan
baru ini variabel. Panggilan rekursif tidak membuat salinan baru dari fungsi. Hanya
nilai-nilai yang dioperasi baru. Karena setiap panggilan rekursif kembali, lama lokal
variabel dan parameter dikeluarkan dari tumpukan resume dan eksekusi di
titik panggilan fungsi dalam fungsi. Fungsi rekursif bisa dikatakan "Teleskop" keluar dan kembali.
Kebanyakan rutinitas rekursif tidak signifikan mengurangi ukuran kode atau meningkatkan daya ingat pemanfaatan. Juga, versi rekursif dari rutinitas yang paling dapat melakukan sedikit lebih lambat dari mereka berulang setara karena overhead dari fungsi panggilan ulang. Di Bahkan, panggilan rekursif banyak fungsi dapat menyebabkan pelampauan tumpukan. Karena penyimpanan untuk Fungsi parameter dan variabel lokal pada stack dan setiap panggilan baru menciptakan baru salinan dari variabel, tumpukan dapat dikuasai. Namun, Anda mungkin tidak akan perlu khawatir tentang hal ini kecuali fungsi rekursif berjalan liar.
Keuntungan utama untuk fungsi rekursif
adalah bahwa Anda dapat menggunakannya untuk membuat lebih jelas dan versi
sederhana dari beberapa algoritma. Sebagai contoh, algoritma quicksort adalah sulit
untuk diterapkan dalam cara yang iteratif. Juga, beberapa masalah, terutama
yang berkaitan untuk kecerdasan buatan,
meminjamkan diri untuk solusi rekursif. Akhirnya, beberapa orang tampaknya
berpikir rekursif lebih mudah daripada iteratif.
Ketika menulis fungsi rekursif, Anda harus
memiliki pernyataan kondisional, seperti
sebagai jika, suatu tempat untuk memaksa fungsi untuk mengembalikan tanpa panggilan rekursif yang dieksekusi. Jika Anda tidak, fungsi tidak akan kembali setelah Anda menyebutnya. Menghilangkan pernyataan kondisional adalah kesalahan umum saat menulis fungsi rekursif. Menggunakan printf () secara bebas selama pengembangan program sehingga Anda dapat menonton apa yang sedang terjadi dan eksekusi batalkan jika Anda melihat kesalahan.
sebagai jika, suatu tempat untuk memaksa fungsi untuk mengembalikan tanpa panggilan rekursif yang dieksekusi. Jika Anda tidak, fungsi tidak akan kembali setelah Anda menyebutnya. Menghilangkan pernyataan kondisional adalah kesalahan umum saat menulis fungsi rekursif. Menggunakan printf () secara bebas selama pengembangan program sehingga Anda dapat menonton apa yang sedang terjadi dan eksekusi batalkan jika Anda melihat kesalahan.
Fungsi
Prototip
Dalam C + + semua fungsi harus
dideklarasikan sebelum mereka digunakan. Ini biasanya dicapai dengan
menggunakan prototipe fungsi. Prototipe fungsi yang bukan bagian dari asli C
bahasa. Mereka, Namun, ditambahkan ketika C adalah standar. Sementara prototipe
tidak secara teknis diperlukan oleh Standar C, penggunaannya sangat dianjurkan.
Prototip selalu dibutuhkan oleh C + +.
Dalam buku ini, semua contoh termasuk penuh
Fungsi prototipe. Prototip memungkinkan kedua C dan C + + untuk menyediakan jenis kuat memeriksa, agak seperti yang disediakan oleh bahasa seperti Pascal. Bila Anda menggunakan prototipe, compiler dapat menemukan dan melaporkan setiap konversi tipe ilegal antara jenis argumen yang digunakan untuk memanggil fungsi dan definisi jenis parameter. Itu compiler juga akan menangkap perbedaan antara jumlah argumen yang digunakan untuk memanggil fungsi dan jumlah parameter dalam fungsi.
Fungsi prototipe. Prototip memungkinkan kedua C dan C + + untuk menyediakan jenis kuat memeriksa, agak seperti yang disediakan oleh bahasa seperti Pascal. Bila Anda menggunakan prototipe, compiler dapat menemukan dan melaporkan setiap konversi tipe ilegal antara jenis argumen yang digunakan untuk memanggil fungsi dan definisi jenis parameter. Itu compiler juga akan menangkap perbedaan antara jumlah argumen yang digunakan untuk memanggil fungsi dan jumlah parameter dalam fungsi.
Bentuk umum dari sebuah prototipe fungsi
tipe func_name(tipe
parm_name1, tipe parm_name2,. . .,
tipe
parm_nameN);
Penggunaan nama parameter adalah opsional.
Namun, mereka memungkinkan compiler untuk mengidentifikasi ketidaksesuaian
jenis apa pun dengan nama ketika terjadi kesalahan, sehingga merupakan ide yang
baik untuk menyertakan mereka.
Program berikut menggambarkan nilai prototipe
fungsi. Ini menghasilkan pesan kesalahan karena mengandung upaya untuk memanggil
sqr_it () dengan argumen integer bukan integer pointer diperlukan. (Ini adalah
ilegal untuk mengubah integer menjadi pointer.)
/* Program ini menggunakan
prototipe fungsi untuk memeriksa tipe kuat. */
void sqr_it(int
*i); /* prototype */
int main(void)
{
int x;
x = 10;
sqr_it(x); /* Tipe
tidak cocok */
return 0;
}
void sqr_it(int
*i)
{
*i = *i * *i;
}
Definisi Sebuah fungsi juga dapat berfungsi
sebagai prototipe apabila definisi terjadi sebelum untuk penggunaan pertama
fungsi dalam program. Sebagai contoh, ini adalah program yang sah.
#include
<stdio.h>
/* Definisi ini
juga akan melayani sebagai prototipe dalam program ini. */
void f(int a,
int b)
{
printf("%d
", a % b);
}
int main(void)
{
f(10,3);
return 0;
}
Dalam contoh ini, karena f () didefinisikan
sebelum penggunaannya dalam main (), tidak terpisah prototipe diperlukan.
Meskipun dimungkinkan untuk definisi fungsi untuk melayani sebagai yang prototipe
dalam program kecil, jarang mungkin dalam yang besar terutama ketika beberapa
file yang digunakan. Program-program dalam buku ini termasuk prototipe terpisah
untuk fungsi masing-masing karena itu adalah cara C / C++ kode biasanya ditulis
dalam praktek.
Satu-satunya fungsi yang tidak memerlukan
prototipe adalah main (), karena itu adalah yang pertama Fungsi dipanggil saat
program Anda dimulai.
Karena kebutuhan untuk kompatibilitas
dengan versi asli C, ada kecil tapi penting perbedaan antara bagaimana C dan C
+ + menangani prototipe dari fungsi yang tidak memiliki parameter. Dalam C + +,
daftar parameter kosong hanya diindikasikan
dalam prototipe oleh tidak adanya parameter. Misalnya,
dalam prototipe oleh tidak adanya parameter. Misalnya,
int f (); / *
C + + prototipe untuk fungsi tanpa parameter * /
Namun, di C prototipe ini berarti sesuatu
yang berbeda. Untuk alasan historis, daftar parameter kosong hanya mengatakan
bahwa tidak ada informasi parameter yang diberikan. Sejauh compiler yang
bersangkutan, fungsi bisa memiliki beberapa parameter atau tanpa parameter. Di C,
ketika sebuah fungsi tidak memiliki parameter, prototipe yang menggunakan kekosongan
dalam daftar parameter. Sebagai contoh, di sini adalah f () 's prototipe karena
akan muncul dalam sebuah program C.
float f
(void);
Ini memberitahu compiler bahwa fungsi tidak
memiliki parameter, dan setiap panggilan untuk fungsi yang memiliki parameter
adalah sebuah kesalahan. Dalam C + +, penggunaan void dalam daftar kosong
parameter masih diperbolehkan, tapi berlebihan.
Dalam C + +, f () dan f (void) ekuivalen.
Prototipe Fungsi membantu Anda menjebak bug
sebelum terjadi. Selain itu, mereka membantu memverifikasi bahwa program Anda
bekerja dengan benar dengan tidak memungkinkan fungsi untuk dipanggil dengan
argumen tidak cocok.
Satu titik terakhir: Sejak versi awal C
tidak mendukung sintaks prototipe penuh, prototipe secara teknis opsional di C.
Hal ini diperlukan untuk mendukung pra-prototipe
C kode. Jika Anda porting kode yang lebih tua C ke C + +, Anda mungkin perlu menambahkan fungsi penuh prototipe sebelum akan mengkompilasi. Ingat: Meskipun prototipe adalah opsional dalam C, mereka diwajibkan oleh C + +. Ini berarti bahwa setiap fungsi dalam program C + + harus sepenuhnya prototyped.
C kode. Jika Anda porting kode yang lebih tua C ke C + +, Anda mungkin perlu menambahkan fungsi penuh prototipe sebelum akan mengkompilasi. Ingat: Meskipun prototipe adalah opsional dalam C, mereka diwajibkan oleh C + +. Ini berarti bahwa setiap fungsi dalam program C + + harus sepenuhnya prototyped.
Fungsi
Standar Library Prototipe
Setiap fungsi library standar yang
digunakan oleh program anda harus prototyped. Untuk mencapai hal ini, Anda
harus menyertakan header yang sesuai untuk masing-masing fungsi perpustakaan.
Semua header yang diperlukan disediakan
oleh C / C + + compiler. Dalam C, semua header adalah file yang menggunakan
ekstensi. H. Dalam C + +, header dapat berupa file terpisah atau dibangun ke compiler
itu sendiri. Dalam kedua kasus, header berisi dua elemen utama: setiap definisi
digunakan oleh fungsi perpustakaan dan prototipe untuk fungsi perpustakaan. Misalnya,
stdio.h termasuk dalam hampir semua program di bagian buku karena mengandung prototipe
untuk printf ().
Mendeklarasikan
Variable-Length Daftar Parameter
Anda dapat menetapkan fungsi yang memiliki
sejumlah variabel parameter. Yang paling contoh umum adalah printf (). Untuk
memberitahu compiler bahwa jumlah yang tidak diketahui argumen dapat dilewatkan
ke fungsi, Anda harus mengakhiri deklarasi yang
parameter menggunakan tiga periode. Sebagai contoh, prototipe ini menetapkan bahwa fungsi () akan memiliki minimal dua parameter integer dan jumlah yang tidak diketahui (termasuk 0) parameter setelah itu.
parameter menggunakan tiga periode. Sebagai contoh, prototipe ini menetapkan bahwa fungsi () akan memiliki minimal dua parameter integer dan jumlah yang tidak diketahui (termasuk 0) parameter setelah itu.
int func (int
a, int b, ...);
Bentuk deklarasi juga digunakan oleh
definisi fungsi ini. Setiap fungsi yang menggunakan sejumlah variabel parameter
harus memiliki setidaknya satu aktual parameter. Sebagai contoh, ini adalah
salah:
int func
(...); / * ilegal * /
Old-Style Versus modern Fungsi Parameter
Deklarasi
Versi awal C menggunakan metode parameter deklarasi yang berbeda daripada baik
Standar C atau C + + Standar. Pendekatan awal kadang-kadang disebut bentuk klasik.
Buku ini menggunakan pendekatan deklarasi yang disebut bentuk modern. Standar C mendukung kedua bentuk, tapi sangat menganjurkan bentuk modern. Standar C + + hanya mendukung metode deklarasi yang modern parameter. Namun, Anda harus tahu gaya lama bentuk karena banyak program C tua masih menggunakannya.
Versi awal C menggunakan metode parameter deklarasi yang berbeda daripada baik
Standar C atau C + + Standar. Pendekatan awal kadang-kadang disebut bentuk klasik.
Buku ini menggunakan pendekatan deklarasi yang disebut bentuk modern. Standar C mendukung kedua bentuk, tapi sangat menganjurkan bentuk modern. Standar C + + hanya mendukung metode deklarasi yang modern parameter. Namun, Anda harus tahu gaya lama bentuk karena banyak program C tua masih menggunakannya.
Gaya lama fungsi deklarasi parameter terdiri
dari dua bagian: parameter Daftar, yang berjalan di dalam kurung yang mengikuti
nama fungsi, dan aktual parameter deklarasi, yang pergi antara kurung menutup
dan fungsi yang membuka penjepit keriting. Bentuk umum dari definisi parameter
gaya lama adalah
Jenis FUNC_NAME (parm1, parm2, ... parmN)
Jenis parm1;
Jenis parm2;
.
..
Jenis parmN;
..
Jenis parmN;
{
fungsi kode
fungsi kode
}
Sebagai contoh, deklarasi modern:
Sebagai contoh, deklarasi modern:
float f(int a,
int b, char ch)
{
/* ... */
}
akan terlihat seperti ini dalam gaya lama
bentuk:
float
f (a, b, ch)
int
a, b;
char
ch;
{
/ * ... * /
/ * ... * /
}
Perhatikan bahwa bentuk gaya lama
memungkinkan deklarasi lebih dari satu parameter dalam daftar setelah nama
tipe.
Bentuk gaya lama deklarasi parameter
ditunjuk sebagai usang oleh C bahasa dan tidak didukung oleh C + +.
Implementasi Masalah
Ada beberapa hal penting yang harus diingat
tentang fungsi yang mempengaruhi mereka efisiensi dan kegunaan. Isu-isu ini
adalah subyek dari bagian ini.
Parameter
dan General-Purpose Fungsi
Sebuah fungsi tujuan umum adalah salah satu
yang akan digunakan dalam berbagai situasi, mungkin oleh programmer yang
berbeda. Biasanya, Anda tidak harus mendasarkan tujuan umum fungsi pada data
global. Semua informasi yang dibutuhkan fungsi harus dilalui kepadanya oleh
parameter. Bila hal ini tidak mungkin, Anda harus menggunakan variabel statis.
Selain membuat fungsi Anda tujuan umum,
parameter menjaga kode Anda dibaca dan kurang rentan terhadap bug yang
dihasilkan dari efek samping.
Efisiensi
Fungsi adalah blok bangunan dari C / C + + dan sangat penting untuk semua tapi yang paling sederhana program. Namun, dalam aplikasi khusus tertentu, Anda mungkin perlu untuk menghilangkan fungsi dan menggantinya dengan kode inline. Kode inline melakukan tindakan yang sama sebagai fungsi, tetapi tanpa overhead yang terkait dengan panggilan fungsi. Untuk alasan ini, inline kode sering digunakan sebagai pengganti fungsi panggilan bila waktu eksekusi sangat penting.
Kode inline lebih cepat daripada panggilan
fungsi untuk dua alasan. Pertama, instruksi panggilan dibutuhkan waktu untuk
mengeksekusi. Kedua, jika ada argumen untuk lulus, ini harus ditempatkan di
stack, yang juga membutuhkan waktu. Untuk sebagian besar aplikasi, ini
peningkatan yang sangat sedikit dalam waktu eksekusi tidak ada artinya. Tetapi
jika itu, ingatlah bahwa setiap pemanggilan fungsi menggunakan
waktu yang akan diselamatkan jika kode fungsi ditempatkan di baris. Sebagai contoh,
Berikut ini adalah dua versi dari sebuah program yang mencetak kuadrat dari angka dari 1 sampai 10. Versi inline berjalan lebih cepat dari yang lain karena fungsi panggil menambah waktu. Dalam panggilan fungsi baris
waktu yang akan diselamatkan jika kode fungsi ditempatkan di baris. Sebagai contoh,
Berikut ini adalah dua versi dari sebuah program yang mencetak kuadrat dari angka dari 1 sampai 10. Versi inline berjalan lebih cepat dari yang lain karena fungsi panggil menambah waktu. Dalam panggilan fungsi baris
#include
<stdio.h>
int sqr(int a);
int main(void)
int main(void)
{ {
int x; int x;
for(x=1;
x<11; ++x) for(x=1; x<11; ++x)
printf("%d",
x*x); printf("%d", sqr(x));
return 0; return
0;
} }
int sqr(int a)
{
return a*a;
}
Dalam C + +, konsep fungsi inline diperluas
dan diformalkan. Bahkan, inline fungsi komponen penting dari bahasa C + +.
if three types of passing parameter mechanism (value, reference & pointer)
BalasHapus