| My Training Period: xx hours
This is a continuation from the previous Module. The source code for this Module is:C/C++ functions source codes. and the lab worksheets for your practice:Function lab worksheet 1,lab worksheet 2,lab worksheet 3 andlab worksheet 4.
The C and C++ skills that should be acquired:
4.6 Passing Arguments To A Function
#include <iostream> using namespace std;
// a function prototype void prt(int);
// the main function definition int main() { // declare an integer variable int x=12; // calls prt() and passes x, so main() is a caller prt(x); cout<<endl; return 0; }
// the prt() function definition, receive an argument copied into y and return nothing // this is a callee void prt(int y) { // local variable… int p = 30; // value from caller cout<<"Value from the calling program..."<<endl; cout<<"x's value = "<<y<<endl; // local variable value cout<<"\nLocal variable value..."<<endl; cout<<"p's value = "<<p<<endl; }
|
Sample output:
The number of arguments and the type of each argument must match the parameters in the function header and prototype.
If the function takes multiple arguments, the arguments listed in the function call are assigned to the function parameters in order.
The first argument to the first parameter, the second argument to the second parameter and so on as illustrated below.
Basically, there are three ways how we can pass something to function parameters:
Passing by value – you learn in this Module.
Passing by (memory) address – you will learn in Array and Pointer Modules.
Passing by reference (C++ only) – also in Array and Pointer Modules.
If the same sequence of steps or instructions is required in several different places in a program, you will normally write a function for the steps and call the function whenever these steps are required. But this involves time overhead.
Also can place the actual sequence of steps wherever they are needed in the program, but this increase the program size and memory required to store the program. Also need retyping process or copying a block of program.
Use function if the sequence of steps is long. If small, use macros or inline function, to eliminate the need for retyping and time overhead.
Need#define compiler directive. For example, to obtain just the area of a triangle, we could use the directive:
When we have defined the above macro, you can use it anywhere in the program as shown below:
cout<<"\nArea = "<<area(4.0, 6.0);
Example for finding an average of 4 numbers ( a, b, c and d):
#define avg(x, y) (x + y)/2.0
Then in the program we can define something like this:
avg1 = avg(avg(a, b), avg(c, d))
Substitution:
avg4 = ((a + b)/2.0 + (c + d)/2.0) / 2.0
The drawback: nesting of macros may result in code that difficult to read.
Is preferred alternative to themacro since it provides most of the features of the macro without its disadvantages.
Same as macro, the compiler will substitute the code for the inline function wherever the function is called in the program.
Inline function is a true function whereas a macro is not.
Includes the keyword inline placed before the function.
A program example:
// calculating an area of triangle using inline function
#include <iostream>
using namespace std;
// an inline function, no need prototype…
inline float triangle_area(float base, float height)
{
float area;
area = (0.5 * base * height);
return area;
}
int main()
{
float b, h, a;
b = 4;
h = 6;
a = triangle_area(b, h);
cout<<"Area = (0.5*base*height)"<<endl;
cout<<"where, base = 4, height = 6"<<endl;
// compiler will substitute the inline function code.
cout<<"\nArea = "<<a<<endl;
return 0;
}
------------------------------------------------------------------
Header files contain numerous frequently used functions that programmers can use without having to write codes for them.
Programmers can also write their own declarations and functions and store them in header files which they can include in any program that may require them (these are called user-defined header file that contains user defined functions).
To simplify and reduce program development time and cycle, C/C++ provides numerous predefined functions. These functions are normally defined for most frequently used routines.
These functions are stored in what are known as standard library such as ANSI C (ISO/IEC C), ANSI C++ (ISO/IEC C++) and GNU glibc header files etc. or not so standard (implementation dependent) header files (with extension .h, .hh etc) and some just called this collection as C/C++ libraries. For template based header files in C++ there are no more .h extension (refer toC++ Namespaces).
In the wider scope, each header file stores functions, macros, structures (struct) and types that are related to a particular application or task.
This is one of the skills that you need to acquire, learning how to use these readily available functions in the header files and in most C / C++ books, courses or training, this part is not so emphasized. So, you have to learn it by yourself, check your compiler documentation where normally, they also contain program examples.
You have to know which functions you are going to use, how to write the syntax to call the functions and which header files to be included in your program.
Before any function contained in a header file can be used, you have to include the header file in your program. You do this by including the:
#include <header_filename.h>
This is called preprocessor directive, normally placed before the main() function of your program.
You should be familiar with these preprocessor directives, encountered many times in the program examples presented in this Tutorial such as:
#include <iostream>
int main()
{ return 0; }
Every C/C++ compiler comes with many standard and non-standard header files. Header files, also called include files; provide function prototype declarations for functions library, macros and types. Data types and symbolic constants used with the library functions are also defined in them.
Companies that sold compilers or third party vendors, normally provide the standard function libraries such as ISO/IEC C, their own extension or other special header files, normally for specific applications such as for graphics manipulation, engineering applications and databases. These non standard headers are implementation dependent.
For example, the following table is a partial list of an ANSI C, ANSI C++ and non-standard header files.
There may be new header files introduced from time to time by Standard and Non-standard bodies and there may be obsoletes header files.
Some may be implementation dependant so check your compiler documentation.
Note: The middle column indicates C++ header files, header files defined by ANSI C or non-standard header files (mark as - (dash)). The Standard C++ header files don’t have the .h anymore for example the<iostream.h> will be <iostream>. For more information please readC++ Namespaces.
Header file | ANSI C/ISO/IEC? | Purpose |
alloc.h | - | Declares memory-management functions (allocation, de-allocation, and so on). Example:calloc(),malloc(),farfree(). |
assert.h | ANSI C | Defines theassert debugging macro. |
bcd.h | C++ | Declares the C++ class bcd (binary coded decimal) and the overloaded operators for bcd and bcd math functions. |
bios.h | - | Declares various functions used in calling IBM®-PC ROM BIOS routines. Example:biosequip(),bioskey(),biosprint(). |
checks.h | C++ | Defines the class diagnostic macros. |
complex.h | C++ | Declares the C++ complex math functions. |
conio.h | - | Declares various functions used in calling the operating system console I/O routines. Example: getch(),gotoxy(),putch(),outport(). |
constrea.h | C++ | Defines theconbuf and constream classes. |
cstring.h | C++ | Defines the string classes. |
ctype.h | ANSI C | Contains information used by the character classification and character conversion macros (such as isalpha() and toascii()). Example: isalnum(),isupper(),isspace(). |
date.h | C++ | Defines thedate class. |
dir.h | - | Contains structures, macros, and functions for working with directories and path names. Example: chdir(),getcurdir(),mkdir(),rmdir(). |
direct.h | - | Defines structures, macros, and functions for dealing with directories and path names. |
dirent.h | - | Declares functions and structures for POSIX directory operations. Example: closedir(),opendir(),readdir(). |
dos.h | - | Defines various constants and gives declarations needed for DOS and 8086-specific calls. Example: bdos(),_chmod(),getdate(),gettime(). |
errno.h | ANSI C | Defines constant mnemonics for the error codes. |
except.h | C++ | Declares the exception-handling classes and functions. |
excpt.h | - | Declares C structured exception support. |
fcntl.h | - | Defines symbolic constants used in connection with the library routine open. Example: _fmode(),_pipe(). |
file.h | C++ | Defines the file class. |
float.h | ANSI C | Contains parameters for floating-point routines. |
fstream.h | C++ | Declares the C++ stream classes that support file input and output. |
generic.h | C++ | Contains macros for generic class declarations. |
io.h | - | Contains structures and declarations for low-level input/output routines. Example:access(),create(),close(),lseek(),read(),remove(). |
iomanip.h | C++ | Declares the C++ streams I/O manipulators and contains templates for creating parameterized manipulators. |
iostream.h | C++ | Declares the basic C++ streams (I/O) routines. |
limits.h | ANSI C | Contains environmental parameters, information about compile-time limitations, and ranges of integral quantities. |
locale.h | ANSI C | Declares functions that provide country- and language-specific information. Example:localeconv(),setlocale(). |
malloc.h | - | Declares memory-management functions and variables. |
math.h | ANSI C | Declares prototypes for the math functions and math error handlers. Example:abs(),cos(),log(),pow(),sin(),tan(). |
mem.h | - | Declares the memory-manipulation functions. (Many of these are also defined in string.h.). Example: memccpy(),movedata(),memset(),_fmemmove(),memchr(). |
memory.h |
| Contains memory-manipulation functions. |
new.h | C++ | Access to_new_handler, and set_new_handler. |
process.h | - | Contains structures and declarations for the spawn... and exec... functions. Example: abort(),exit(),getpid(),wait(). |
search.h | - | Declares functions for searching and sorting. Example: bsearch(),lfind(),qsort(). |
setjmp.h | ANSI C | Declares the functionslongjmp and setjmp and defines a type jmp_buf that these functions use. Example: longjmp(),setjmp(). |
share.h | - | Defines parameters used in functions that make use of file-sharing. |
signal.h | ANSI C | Defines constants and declarations for use by the signal and raise functions. Example: raise(),signal(). |
stdarg.h | ANSI C | Defines macros used for reading the argument list in functions declared to accept a variable number of arguments (such as vprintf,vscanf, and so on). |
stddef.h | ANSI C | Defines several common data types and macros. |
stdio.h | ANSI C | Defines types and macros needed for the standard I/O package defined in Kernighan and Ritchie and extended under UNIX System V. Defines the standard I/O predefined streams stdin,stdout,stdprn, and stderr and declares stream-level I/O routines. Example: printf()/printf_s(),scanf()/scanf_s(),fgets()/fgets_s(),getchar(),fread(). |
stdiostr.h | C++ | Declares the C++ (version 2.0) stream classes for use with stdioFILE structures. You should use iostream.h for new code. |
stdlib.h | ANSI C | Declares several commonly used routines such as conversion routines and search/sort routines. Example: system(),time(),rand(),atof(),atol(),putenv(). |
string.h | ANSI C | Declares several string-manipulation and memory-manipulation routines. Example: strcmp(),setmem(),_fstrcpy(),strlen(). |
strstrea.h | C++ | Declares the C++ stream classes for use with byte arrays in memory. |
sys\locking.h | - | Contains definitions for mode parameter of locking function. |
sys\stat.h | - | Defines symbolic constants used for opening and creating files. |
sys\timeb.h | - | Declares the functionftime and the structure timeb that ftime returns. |
sys\types.h | - | Declares the typetime_t used with time functions. |
thread.h | C++ | Defines the thread classes. |
time.h | ANSI C | Defines a structure filled in by the time-conversion routines asctime,localtime, and gmtime, and a type used by the routines ctime,difftime,gmtime,localtime, and stime. It also provides prototypes for these routines. |
typeinfo.h | C++ | Declares the run-time type information classes. |
utime.h | - | Declares theutime function and the utimbufstruct that it returns. |
values.h | - | Defines important constants, including machine dependencies; provided for UNIX System V compatibility. |
varargs.h | - | Definitions for accessing parameters in functions that accept a variable number of arguments. Provided for UNIX compatibility; you should use stdarg.h for new code. |
Table 4.1: A list of some standard and non standard header files |
Many of the functions in the standard (ANSI, ISO/IEC, Single UNIX Specification, GNU glibc etc.) header files were used throughout this tutorial. You have to learn how to use these readily available functions in the specific header file and must know how to write the syntax to call these functions. Do not reinvent the wheels :o).
Complete information about the functions and the header file normally provided by the compiler documentation. They also may have program examples that you can try.
Don’t forget also there are also tons of the non standard predefined header files available from the compiler vendors, for specific machine/platform or third party.
For Borland, Microsoft and other implementations, the functions contained in the non standard header files normally begin with underscore (_ ) such as _chmod() but using the similar function name.
If you wrongly use or the include path is incorrect, normally the compiler will generates error mentioning the file cannot be found/opened or can’t recognize the function names used in your program.
In reality the include files just act as an interface for our programs. The definition of the include files actually already loaded into the system memory area as a library files (mainly for the standard header files) typically with the .lib extension.
Another error normally done by programmers is using wrong types, number and order of the function parameters.
We can define program segments (including functions) and store them in files. Then, we can include these files just like any standard header file in our programs.
For example:
#include "myfile.h"
// enclosed with " ", instead of < >
// because it is located in the same folder/directory
// as the main() program instead of the standard path of
// of the include files set during the compiler installation.
int main()
{ return 0; }
Here,myfile.h is a user-defined header file, located in the same folder as the main() program.
All the program segments contained in myfile.h are accessible to the function main().
An example is given at the end of this Module how to create and use the user-defined function.
This is the concept that is quite similar to the Object Oriented Programming using the classes that contain methods which you will learnC++ and Object Oriented Idea tutorial.
ANSI C (ISO/IEC C) defines syntax for declaring a function to take a variable number or type of arguments. Such functions are referred to asvarargs functions or variadic functions.
However, the language itself provides no mechanism for such functions to access their non-required arguments; instead, you use the variable arguments macros defined in stdarg.h.
The example of variadic function used in Standard ANSI C is printf() function. If you have noticed, printf() can accept variable number or type of arguments.
Many older C dialects provide a similar, but incompatible, mechanism for defining functions with variable numbers of arguments, usingvarargs.h header file.
Ordinary C functions take a fixed number of arguments. When you define a function, you specify the data type for each argument.
Every call to the function should supply the expected number of arguments in order, with types that can be converted to the specified ones. Thus, if a function named let say testfunc() is declared like the following:
int testfunc(int, char *);
Then you must call it with two arguments, an integer number (int) and a string pointer (char *).
But some functions perform operations that can meaningfully accept an unlimited number of arguments.
In some cases a function can handle any number of values by operating on all of them as a block. For example, consider a function that allocates a one-dimensional array with malloc() to hold a specified set of values.
This operation makes sense for any number of values, as long as the length of the array corresponds to that number. Without facilities for variable arguments, you would have to define a separate function for each possible array size.
The library function printf() is an example of another class of function where variable arguments are useful. This function prints its arguments (which can vary in type as well as number) under the control of a format template string.
These are good reasons to define a variadic function which can handle as many arguments as the caller chooses to pass.
Defining and using a variadic function involves three steps:
Define the function as variadic, using an ellipsis ('...') in the argument list, and using special macros to access the variable arguments.
Declare the function as variadic, using a prototype with an ellipsis ('...'), in all the files which call it.
Call the function by writing the fixed arguments followed by the additional variable arguments.
A prototype of a function that accepts a variable number of arguments must be declared with that indication. You write the fixed arguments as usual, and then add an '...' to indicate the possibility of additional arguments.
The syntax of ANSI C requires at least one fixed argument before the '...'. For example:
int varfunc(const char *a, int b, ...)
{ return 0; }
Outlines a definition of a function varfunc() which returns an int and takes two required arguments, a const char * and an int. These are followed by any number of anonymous arguments.
Ordinary fixed arguments have individual names, and you can use these names to access their values. But optional arguments have no names that are nothing but '...'. How can you access them?
The only way to access them is sequentially, in the order they were written, and you must use special macros from stdarg.h in the following three step process:
You initialize an argument pointer variable of type va_list usingva_start. The argument pointer when initialized points to the first optional argument.
You access the optional arguments by successive calls to va_arg. The first call tova_arg gives you the first optional argument; the next call gives you the second, and so on. You can stop at any time if you wish to ignore any remaining optional arguments. It is perfectly all right for a function to access fewer arguments than were supplied in the call, but you will get garbage values if you try to access too many arguments.
You indicate that you are finished with the argument pointer variable by calling va_end.
Steps 1 and 3 must be performed in the function that accepts the optional arguments. However, you can pass the va_list variable as an argument to another function and perform all or part of step 2 there.
You can perform the entire sequence of the three steps multiple times within a single function invocation. If you want to ignore the optional arguments, you can do these steps zero times.
You can have more than one argument pointer variable if you like. You can initialize each variable with va_start when you wish, and then you can fetch arguments with each argument pointer as you wish.
Each argument pointer variable will sequence through the same set of argument values, but at its own pace.
There is no general way for a function to determine the number and type of the optional arguments it was called with. So whoever designs the function typically designs a convention for the caller to tell it how many arguments it has, and what kind.
It is up to you to define an appropriate calling convention for each variadic function, and write all calls accordingly.
One kind of calling convention is to pass the number of optional arguments as one of the fixed arguments. This convention works provided all of the optional arguments are of the same type.
A similar alternative is to have one of the required arguments be a bit mask, with a bit for each possible purpose for which an optional argument might be supplied. You would test the bits in a predefined sequence; if the bit is set, fetch the value of the next argument, and otherwise use a default value.
A required argument can be used as a pattern to specify both the number and types of the optional arguments. The format string argument toprintf() is one example of this.
You don't have to write anything special when you call a variadic function. Just write the arguments (required arguments, followed by optional ones) inside parentheses, separated by commas, as usual.
But you should prepare by declaring the function with a prototype, and you must know how the argument values are converted.
In principle, functions that are defined to be variadic must also be declared to be variadic using a function prototype whenever you call them. This is because some C compilers use a different calling convention to pass the same set of argument values to a function depending on whether that function takes variable arguments or fixed arguments.
Conversion of the required arguments is controlled by the function prototype in the usual way: the argument expression is converted to the declared argument type as if it were being assigned to a variable of that type.
The following Table list the descriptions of the macros used to retrieve variable arguments. These macros are defined in the stdarg.h header file.
Data Type: va_list |
The type |
|
Macro: void va_start (va_list ap,last-required) |
This macro initializes the argument pointer variable ap to point to the first of the optional arguments of the current function;last-required must be the last required argument to the function. |
|
Macro:typeva_arg (va_list ap,type) |
The The type of the value returned by |
|
Macro:void va_end (va_list ap) |
This ends the use of ap. After a |
The following is an example of a function that accepts a variable number of arguments. The first argument to the function is the count of remaining arguments, which are added up and the result returned.
This example just to illustrate how to use the variable arguments facility.
/* variadic function */
#include <stdarg.h>
#include <stdio.h>
/* variadic function's prototype, count variable is the number of arguments */
int sum_up(int count,...)
{
va_list ap;
int i, sum;
/* Initialize the argument list. */
va_start (ap, count);
sum = 0;
for (i = 0; i < count; i++)
/* Get the next argument value. */
sum += va_arg (ap,int);
/* Clean up. */
va_end (ap);
return sum;
}
int main(void)
{
/* This call prints 6. */
printf("%d\n", sum_up(2, 2, 4));
/* This call prints 16. */
printf("%d\n", sum_up(4, 1, 3, 5, 7));
return 0;
}
- ISO/IEC 9899 (ISO/IEC 9899:1990) - C Programming languages.
- ISO/IEC 9899 (ISO/IEC 9899:2018) - C Programming languages.
- ISO/IEC 9945-1:2003 POSIX Part 1 Base Definition.
- ISO/IEC 14882:1998 on the programming language C++.
- Latest, ISO/IEC 14882:2017 on the programming language C++.
- ISO/IEC 9945:2018, The Single UNIX Specification, Version 4.
- Get the GNU C library information here.
- Read online the GNU C library here.