You are on page 1of 25

C : defining functions

Creating functions
With the exception of arrays and functions , C always passes arguments `by value': a copy of
the value of each argument is passed to the function; the function cannot modify the actual
argument passed to it:
void foo(int j) {
j = 0; /* modifies the copy of the argument received by the function
}
int main(void) {
int k=10;
foo(k);
/* k still equals 10
}

*/

If you do want a function to modify its argument you can obtain the desired effect using
pointer arguments instead:
void foo(int *j) {
*j = 0;
}
int main(void) {
int k=10;
foo(&k);
/* k now equals 0
}

*/

*/

Creating functions

pass by value

int func(int x) {
int i = 0 ;
x = 100 ;
printf("this is in the function\n");
i += x ;
return i ;
}

int main( int argc, char ** argv ) {

Result :
this is in the function
this is in the function
returned value of func(): 100
value of y : 50

int y = 50;
int x = func(y);
printf("returned value of func(): %d\n",func(y));
printf("value of y : %d\n",y);
return 0;
}

func(y) is not actually using the y directly, it's actually copying its value into the function.
This called call by value and all functions in C are called by value.
It's not actually passing a reference to the variable. So the function has no way of affecting this y.
The value of y will still being 50.
If the return type is void , void func(int x) , then it's no longer legal to return anything.

Creating functions

- pass by reference

int func(int *x) {


int i=0 ;
*x = 100 ;
printf("this is in the function\n");
i += *x ;
return i ;
}
int main( int argc, char ** argv ) {
int y = 50;
int x = func(&y);
printf("returned value of func(): %d\n",x);
printf("value of y : %d\n",y);
return 0;
}

Result :
this is in the function
returned value of func(): 100
value of y : 100

If we want to be able to affect y , then what we have to do is to pass a pointer.


Now the parameter is a pointer and what we are passing it s the address of a variable.
So now we are actually able to affect this variable, the value of y will be 100.
That's called pass by reference as opposed to pass by value.
C is always pass by value, and we are still passing a value, it's just the value is now a pointer.
And so that's how we are able to affect variables outside the function.

Creating functions Declaring functions


In order to properly use a function when it's used before its definition is to have a declaration.
int func(int) ;

Now it's common to include the name, because it gives a hint of how it's used
int func(int x) ;
We have told the compiler exactly what that function looks like, and that it will be defined later.

int func(int x) ;

// declaration of the function

int main( int argc, char ** argv ) {


int y = 50;
int x = func(&y);
printf("returned value of func(): %d\n",x);
printf("value of y : %d\n",y);
return 0;
}
// definition of the function
int func(int *x) {
int i=0 ;
*x = 100 ;
printf("this is in the function\n");
i += *x ;
return i ;
}

Creating functions header file


Func.c file
#include <stdio.h>
#include "func.h"
int main( int argc, char ** argv ) {
int y = 50;
int x = func(&y);
printf("returned value of func(): %d\n",x);
printf("value of y : %d\n",y);
return 0;
}
int func(int *x) {
int i=0 ;
*x = 100 ;
printf("this is in the function\n");
i += *x ;
return i ;
}

func.h file
#ifndef FUNC_H_
#define FUNC_H_
int func(int) ;
#endif /* FUNC_H_ */

It is really common is that the function itself


is actually in a separate translation unit, it's
in a separate source file, and it's linked in
later.

And what's even more common is instead of


having this function signature here to have it
in a header file.
That's the common way to do this, whatever
functions you are using in a particular source
file to have their function signatures in a
header file.

Creating functions - libraries


The common way is to have a set of functions in one source file, and have all of
their function signatures in the header file, and we can compile that as a separate
unit. And then when we want to use that and link to it, all of those function
signatures are in the header file, and we can simply include that header file in our
main program, and link to the code and everything will work the way that we want
it to.
So this is really the common way to do this, this is how libraries are created. In fact,
this is why we include at the beginning of all our programs. Because functions like
printf() and puts() that we use a lot are defined in. And then the actual code is
linked in with our program as we build it. So that's how our standard libraries work,
and that's really how all libraries work in C. So the function is the basic unit of code
in C. Everything starts from the main function and all code must be in function
blocks.
Understanding functions is a fundamental skill for C and C++ programming.

Defining Functions call by value, call by reference


Call by value
#include <stdio.h>

Call by reference
when a is incremented in
the function only its local
copy is affected

int f(int a){


return ++a ;
}
int main() {
int a

= 1;

#include <stdio.h>

int f(int *p){


return ++(*p) ;
}

Result :
f(a) is 2
a is 1

int main() {
int a

printf (" f(a) is %d\n" , f(a) );


printf ("
a is %d\n" ,
a );
return 0 ;
}

= 1;

f(&a) ;
printf ("

Result :
a is 2

a is %d\n" , a );

return 0 ;
}

In C and C++ arguments are always passed to functions


by value. So when you call a function, a copy of the
content of the variable is passed to the function. If the
function then changes that value the caller's copy
remains unchanged. For example, here we have a
variable a, with the value 1, this variable is passed to a
function f, after the function returns we print the value.
The function f() takes that value and assigns it to a local
variable also named a.
But this is absolutely a
different variable, it's in a
different scope.

f(&a), ampersand of the function


call parameter means to pass a
pointer to a, instead of the value
of a.
The Ampersand is called the
reference operator or sometimes
the address of operator.

Defining Functions signature , and call by reference type


Call by reference type
In C++ you may also use the reference type to implement call by
reference. This makes call by reference appear more implicit, this
feature is not available in C.
#include <stdio.h>

In C++ functions are identified by their function signature.


long volume( long a)

void f(int &p) {


++p ;
}

is different from

int main() {

double volume (double c)

int a = 1;
f(a) ;

Even the two functions have the same name.


The return type, the name of the function, and the types of the
function arguments are all combined to form the function
signature.

This function signature is used to identify the function. In C this


distinction does not exist and these two functions would cause a
name collision, because a function is identified only by its name
in C.

printf ("
return 0 ;
}

a is %d\n" , a );

Defining Functions passing parameters to a function


Parameters are passed to functions by declaring them inside the parentheses of the function
definition.
So in C and C++ functions always passed by value, so what that means is that when we make this
function call with the i in it, it actually makes a copy of that i and passes the copy into the function and
inside the function the copy is called i and so this is a copy that's being used inside the function.

Call by value

Call by reference

#include <iostream>
using namespace std;

#include <iostream>
using namespace std;

void func(int );

void func(int * );

int main( int argc, char ** argv ) {


int i = 7 ;
func(i);
printf("i is %d\n", i);
return 0;
}

int main( int argc, char ** argv ) {


int i = 7 ;
pass an
func(&i);
address
printf("i is %d\n", i);
return 0;
}

void func(int i) {
i = 132 ;
printf("in func(), i is %d\n", i);
}

void func(int *i) {


*i = 132 ;
printf("in func(), i is %d\n",
*i);
}

Result
in func(), i is 132
i is 7

Result
in func(), i is 132
i is 132

Defining Functions passing parameters to a function


#include <iostream>
using namespace std;
void func(int & );
int main( int argc, char ** argv ) {
int i = 7 ;
func(i);
printf("i is %d\n", i);
return 0;

Now if you're using C++ you can


do this with references instead of
pointers and the advantage and
disadvantage of references is that
this syntax is much simpler.
So the semantic is different, the
effect is the same.

void func(int &i) {


i = 132 ;
printf("in func(), i is %d\n", i);
}

in func(), i is 132
i is 132

Function calls always passed by


value, if you pass a reference or a
pointer it's the value of the
reference or the pointer that
you're passing.

Defining Functions
#include <iostream>
using namespace std;

passing parameters to a function

when you want to pass something big you'll always


want to use a reference or a pointer. That's how you
pass a larger object into a function using a reference.

void func(string & );

int main( int argc, char ** argv ) {

string s = "hello main" ;


func(s);
printf("%s\n", s.c_str());
return 0;

it's a good habit to get in every time you


are using a reference to use the keyword
const, and this prevents accidents from
happening with side effects.

}
#include <iostream>
using namespace std;
void func(string &s) {
s = "hello func()" ;
cout << s << endl ;
}

Result :
hello func()
hello func()

void func(const string & );


int main( int argc, char ** argv ) {
string s = "hello main" ;
func(s);
printf("%s\n", s.c_str());
return 0;
}
void func(const string &s) {
cout << s << endl ;
}

Defining Functions using automatic and static variables, stack


Variables declared in a function default to automatic storage. Other storage options are available.
#include <iostream>
using namespace std;

void func();
int main( int argc, char ** argv ) {
func();
func();
func();
return 0;
}

We get three times 5, The reason for that is this is in


temporary storage.
Automatic storage is stored on the stack which is
created fresh for each invocation of a function. So
the value is not carried from one invocation to the
other.

void func() {
int i = 5;
printf("this is func() , i is : %d\n", i++);
}

If on the other hand we declare this as being static storage


Result :
this is func() , i is : 5
this is func() , i is : 5
this is func() , i is : 5

static int i = 5;
The variable i will be incremented every time. Static storage is not
stored on the stack. It's not temporary. It's persistent for life of the
process. The value is carried from one invocation to another. Static
storage is typically used for keeping state and for other purposes where
you just need to keep the storage around.

Defining Functions using function pointers


#include <iostream>
using namespace std;
int f( int i) {
cout << "this is f()" << endl;
return i;
}

The function call operator is commonly


used for calling a function

int main( int argc, char ** argv ) {


int i;
i = f(47);

this is a function call operator

printf("i is %d\n", i);


return 0;

Pointer to function

we have the function pointer itself inside the


parentheses (*pFunc) because *pFunc doesn't tell the
compiler that this is a function type, and so we need a
pointer to the function type.
int i;
int (*pFunc) (int) ;
pFunc = &f ;
i = (*pFunc) (47);
printf("i is %d\n", i);

(int) includes the function signature .


So we have a pointer to a function that returns an int
and takes an int as a parameter.
We could do the assigment in the same line :
int (*pFunc) (int) = &f;

Defining Functions using function pointers


#include <stdio.h>

void func();

int main( int argc, char ** argv ) {


void (*fptr)() = func ;
(*fptr)() ;
return 0;

}
void func() {
printf("this is func()\n");
}

If we use
void (*fptr)() = &func ;
Instead of

void (*fptr)() = func ;


The result is the same !!!

Defining Functions using function pointers


#include <stdio.h>
void a() { puts("this
void b() { puts("this
void c() { puts("this
void d() { puts("this
void e() { puts("this
int jump( char * );
int prompt();

is
is
is
is
is

a()");
b()");
c()");
d()");
e()");

int jump( char * s ) {


char code = s[0];
if(code == 'q' || code == 'Q') return 0;
// get the length of the funcs array
int func_length;

}
}
}
}
}

for(func_length = 0; funcs[func_length] != NULL;


func_length++);
int i = (int) code - '0';

// array of function pointers


void (*funcs[])() = { a, b, c, d, e, NULL };

i--;

int main( int argc, char ** argv ) {


while(prompt());
puts("\nDone.");
return 0;
}

int prompt() {
puts("Choose an option:");
puts("");;
puts("1. Function a()");
puts("2. Function b()");
puts("3. Function c()");
puts("4. Function d()");
puts("5. Function e()");
puts("Q. Quit.");
printf(">> ");

// list is zero-based

if( ( i < 0 ) || ( i > 8 ) ) {


puts("invalid choice");
return 1;
}

if(i < func_length) {


funcs[i]();
return 1;
}
else {
puts("invalid choice");
return 1;

}
}

fflush(stdout);
enum { bufsz = 16 };
static char response[bufsz];
fgets(response, bufsz, stdin);
return jump(response);
}

// constant for buffer size


// static storage for response buffer
// get response from console

Defining Functions using function pointers


The previous code, is called a jump table.
This is a really simple way to implement a menu in a console-based application or to
implement any kind of a jump table where you might want to be calling different functions
based on a piece of data.

int i = (int) code - '0';


This line code is just a little trick for converting a character into an integer.
The first character of the response string, it simply subtracts the value of 0 of the ASCII character 0,
and then it's got an integer, it's got a 0 based integer.

#include <stdio.h>
int main( int argc, char ** argv ) {
char code = '3';
int i = (int) code - '0';

printf(" %d\n", i) ;
return 0;
}

Dec
48
49
50
51
52
53
54
55
56
57

Hex
30
31
32
33
34
35
36
37
38
39

Char
0
1
2
3
4
5
6
7
8
9

ASCII table

#include <iostream>
#include <vector>

Defining Functions using function pointers

using namespace std;


void
void
void
void
void

a()
b()
c()
d()
e()

{
{
{
{
{

puts("this
puts("this
puts("this
puts("this
puts("this

is
is
is
is
is

a()");
b()");
c()");
d()");
e()");

}
}
}
}
}

int jump( const string & s ) {

char code = s[0];


if(code == 'q' || code == 'Q') return false;
int i = (int) code - '0';
i--;
// list is zero-based

int jump( const string & );


int prompt();

if( ( i < 0 ) || ( i > 8 ) ) {


cout << "invalid choice" << endl;
return true;
}

vector<void (*)()> funcs = { a, b, c, d, e };


int main( int argc, char ** argv ) {
while(prompt());
puts("\nDone.");
return 0;
}
int prompt() {
cout << "Choose an option:" << endl
<< endl
<< "1. Function a()" << endl
<< "2. Function b()" << endl
<< "3. Function c()" << endl
<< "4. Function d()" << endl
<< "5. Function e()" << endl
<< "Q. Quit." << endl
<< ">> ";
string response;
cin >> response;
return jump(response);
}

if(i < funcs.size()) {


funcs[i]();
return true;
} else {
cout << "invalid choice" << endl;
return true;
}
}

The same previous code,


but now in C++
Using vectors (STL containers )

Defining Functions simple example


#include <stdio.h>

int func() ;

main() {
int (*ptr) () = func ;
printf(" this is i %d\n", (*ptr) ());
}

int func() {
int a =3, b = 4, c =7 ;
int i[] = { a , b , c } ;
return i[0] ;

We can have variables ( a,b,c )


inside array variables i[]

Defining Functions overloading function names


#include <iostream>
using namespace std;
// volume of a cube
int volume( int s ) {
cout << "cube of " << s << endl;
return s * s * s;
}

A function signature includes the return


type, the function name, and the type
and number of parameters.

// volume of a cylinder
double volume( double r, int h ) {
cout << "cylinder of " << r << " x " << h << endl;
return 3.14159 * r * r * h;
}
// volume of a cuboid
long volume( long a, long b, long c ) {
cout << "cuboid of " << a << " x " << b << " x " << c << endl;
return a * b * c;
}
int main( int argc, char ** argv ) {
cout << "volume of a 2 x 2 x 2 cube: " << volume(2) << endl;
cout << "volume of a cylinder, radius 2, height 2: " << volume( 2.0, 2 ) << endl;
cout << "volume of a 2 x 3 x 4 cuboid: " << volume(2, 3, 4) << endl;
return 0;
}

Defining Functions overloading operators with functions


When you're dealing with simple built-in scale or values, it's usually pretty obvious what most
operators will do, 2+2 will generally get you 4. But when you're dealing with classes in C++, it's
not obvious at all. In fact, C++ operators don't work with classes unless you tell them how. For
this purpose, you'll want to write your own code for some operators, this is called Operator
Overloading. There are basically two ways to overload operators in C++, one is with class
methods, the other is with functions.
#include <iostream>
using namespace std;
class A {
int a;

public:
A ( int a ) : a(a) {};
int value() { return a; }
};
int operator + (A & lhs, A & rhs ) {
cout << "operator + for class A" << endl;
return lhs.value() + rhs.value();
}
int main( int argc, char ** argv ) {
A a(5);
A b(42);
cout << "add em up: " << a + b << endl;
return 0;
}

Defining Functions defining a variable number of arguments


For those times when you need a function that may take a varying number of arguments, C
and C++ provide variadic functions.
You notice we including a header called standard arg , stdarg.h.
In C++, the equivalent header is cstdarg.h. ( this technique works in both C and C++).

Defining Functions defining a variable number of arguments


#include <stdio.h>
#include <stdarg.h>
double average(const int count, ...)
{
va_list ap;
int i;
double total = 0.0;
va_start(ap, count);
for(i = 0; i < count; i++) {
total += va_arg(ap, double);
}
va_end(ap);
return total / count;
}

int message(const char * fmt, ...) {


va_list ap;
va_start(ap, fmt);
int rc = vfprintf(stdout, fmt, ap);
fputs("\n", stdout);
va_end(ap);
return rc;
}
int main( int argc, char ** argv ) {
message("This is a message");
message("average: %lf", average(5, 25.0, 35.7, 50.1, 127.6, 75.0));
return 0;
}

Defining Functions using recursion


A recursive function is a function that calls itself.
Lets make an example that calculate the factorial of a number.
A factorial in math is typically defined in recursive terms. It is the product of n(n-1)(n-2), all the way down to 1.

#include <iostream>
using namespace std;
unsigned long int factorial( unsigned long int n ) {
if( n < 2 ) return 1;
return factorial( n - 1 ) * n;
}

Result :
factorial of 10 is 3628800

int main( int argc, char ** argv ) {


unsigned long int n = 10;
cout << "factorial of " << n << " is " << factorial(n) << endl;
return 0;
}

This actually called itself ten times. Now there is a limit to how many times you can do this, obviously there is
a limit of the size of unsigned long integer, but there is also the limit of the amount of resources that are
available on the computer. Every time you call a function, memory is allocated for the parameters, for any
local variables, and for the return value and all the other function called overhead. If you do this recursively, it
could happen many, many times, and all of those resources keep getting allocated and not deallocated until
the last one is returned, and then all of those resources get deallocated, so this can be very inefficient.

Defining Functions using recursion


Regarding the previous issue of recursive functions, So if you have a choice between a recursive function
and a function that works with a loop, oftentimes the loop will be a lot more efficient. For example, for
the previous code, we could change like :

#include <iostream>
using namespace std;

unsigned long int factorial( unsigned long int n ) {


if( n < 2 ) return 1;
unsigned long int result = n ;
while (n>1) result *= (--n);
return result ;

So C and C++ support recursive


functions, but you should be
careful for problems that may
require a lot of iterations.
Recursion can quickly use up a lot
of resources, it's often better to
find a different solution.

int main( int argc, char ** argv ) {


unsigned long int n = 10;
cout << "factorial of " << n << " is " << factorial(n) << endl;
return 0;
}

You might also like