Pages

Kamis, 22 November 2012

C++ Artikel Lengkap Tentang Fungsi



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:
f(type varname1, type varname2, . . . , type varnameN)

 
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(n1)*n. To evaluate this expression, factr() is called with n1. 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
}
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:
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)
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:
# Include
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;
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.

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;
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;
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:
#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.
/ * Sebuah versi sederhana dari standar mendapat () fungsi perpustakaan. */
char * xgets (char * s)
{
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;
}
}
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.
#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.
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.
#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.
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.
#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.
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.

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:
/* 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.

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.
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.
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:
/* 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.)
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.
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.

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.
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,
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.

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.
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.
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;
{
fungsi kode
}
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
#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 + +.

1 komentar:

  1. if three types of passing parameter mechanism (value, reference & pointer)

    BalasHapus