Function with Arguments

I l @ ve RuBoard

Function with Arguments

By now, you're familiar with using function arguments. The next step along the road to function mastery is learning how to write your own functions that use arguments. Let's preview that skill now. (At this point, you might want to review the butler () function example near the end of Chapter 2, "Introducing C;" it shows how to write a function without an argument.) Listing 5.15 includes a pound () function that prints a specified number of pound signs ( # ). The example also illustrates some points about type conversion.

Listing 5.15 The pound.c program.
 /* pound.c -- defines a function with an argument        */ #include <stdio.h> void pound(int n);       /* ANSI prototype                */ int main(void) {   int times = 5;   char ch = '!';         /* ASCII code is 33             */   float f = 6.0;   pound(times);          /* int argument                 */   pound(ch);             /* char automatically -> int    */   pound((int) f);        /* cast forces f -> int         */   return 0; } void pound(int n)        /* ANSI-style function header    */ {                        /* says takes one int argument   */   while (n-- > 0)        printf("#");   printf("\n"); } 

Running the program produces this output:

 ##### ################################# ###### 

First, let's examine the function heading:

 void pound(int n) 

If the function took no arguments, the parentheses would be empty. Because the function takes one argument, you include one variable name , n , and indicate that this variable is type int . You can use any name consistent with C's naming rules.

Declaring an argument creates a variable called the formal argument or the formal parameter . In this case, you've created a type int variable called n . Making a function call like pound(10) acts to assign the value 10 to n . In this program, the call pound(times) assigns the value of times ( 5 ) to n . You say that the function call passes a value, and this value is called the actual argument or the actual parameter , so the function call pound(10) passes the actual argument 10 to the function, where 10 is assigned to the formal argument (the variable n ). That is, the value of the times variable in main() is copied to the new variable n in pound() .

Variable names are private to the function. This means that a name defined in one function doesn't conflict with the same name defined elsewhere. If you used times instead of n in pound() , that would create a variable distinct from the times in main() . That is, you would have two variables with the same name, but the program keeps track of which is which.

Now let's look at the function calls. The first one is pound(times) , and, as we said, it causes the times value of 5 to be assigned to n . This causes the function to print five pound signs and a newline. The second call is pound(ch) . Here, ch is type char . It is initialized to the ! character, which, on ASCII systems, means that ch has the numerical value 33. The automatic promotion of char to int converts this, on this system, from 33 stored in 1 byte to 33 stored in 4 bytes, so the value 33 is now in the correct form to be used as an argument to this function. The last call, pound ( (int) f) , uses a type cast to convert the type float variable f to the proper type for this argument.

Suppose you omit the type cast. With ANSI C, the program will make the type cast automatically for you. That's because of the ANSI prototype near the top of the file:

 void pound(int n);       /* ANSI prototype               */ 

A prototype is a function declaration that describes a function's return value and its arguments. This prototype says two things about the pound() function:

 The function has no return value The function takes one argument, which is a type int value 

Because the compiler sees this prototype before pound() is used in main() , the compiler knows what sort of argument pound() should have, and it inserts a type cast if one is needed to make the actual argument agree in type with the prototype. For instance, the call pound(3.859) will be converted to pound(3) .

K&R Function Declarations and Headings

K&R C uses a different syntax for function declarations and headings. The K&R function declaration specifies just the return type and is silent about arguments:

 void pound(int n);       /* ANSI prototype                */ void pound();            /* K&R function declaration     */ 

Also, the K&R function heading looks different:

 void pound(int n)        /* ANSI C     */ {    ... void pound(n)            /* K&R C  */ int n; {    ... 

Note that function arguments, such as n , are declared before the opening brace. Variables defined inside the function are declared after the opening brace . ANSI C recognizes both forms but will phase out the older form someday. Chapter 9 examines prototyping in more detail.

About the only reason to use the K&R forms is if your compiler doesn't support ANSI C. The ANSI C function prototype is a major improvement because it enables the compiler to check argument types. To see what prototypes do for you, consider how C behaves without them. Suppose, for example, you replace the ANSI prototype in Listing 5.15 with a K&R declaration and that you eliminate the type cast. Then, when the compiler reaches the pound() calls in main() , it knows that pound() has no return value, but it doesn't know what sort of argument pound() takes. In the absence of that knowledge, the compiler follows the usual default rules. Suppose you have this call:

 pound(f); 

First, the default promotion converts f to type double . On this system, that results in the function call putting an 8-byte value into the stack , a temporary storage area. Then the pound() function, expecting type int , reads just 4 of those bytes. The result bears little resemblance to the original value. In short, using a float or double argument when a function expects type int does not lead to an automatic type conversion; it leads to garbage. You can avoid that problem in K&R C by using an explicit type cast. With ANSI C, the problem is handled automatically.

I l @ ve RuBoard


C++ Primer Plus
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2000
Pages: 314
Authors: Stephen Prata

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