Morteza Noferesti Experience has shown that the best way to develop - - PowerPoint PPT Presentation
Morteza Noferesti Experience has shown that the best way to develop - - PowerPoint PPT Presentation
Morteza Noferesti Experience has shown that the best way to develop and maintain a large program is to construct it from smaller pieces or modules, each of which is more manageable than the original program. This technique is called
Experience has shown that the best way to develop and
maintain a large program is to construct it from smaller pieces or modules, each of which is more manageable than the original program.
This technique is called divide and conquer. Modules in C are called functions.
A function is a group of statements that together
perform a task. Every C program has at least one function, which is main(), and all the most trivial programs can define additional functions.
You can divide up your code into separate functions.
How you divide up your code among different functions is up to you, but logically the division is such that each function performs a specific task.
A boss (the calling function or caller) asks a worker
(the called function) to perform a task and report back when the task is done
For example, a function needing to display information
- n the screen calls the worker function printf to
perform that task, then printf displays the information and reports back—or returns—to the calling function when its task is completed.
The boss function does not know how the worker
function performs its designated tasks
The worker may call other worker functions, and the
boss will be unaware of this.
Standard library functions
- inbuilt functions in C programming.
- The prototype and data definitions of the functions are present in
their respective header files, and must be included in your program to access them.
- For example: If you want to use printf() function, the header
file <stdio.h> should be included.
User defined functions
- C allow programmers to define functions. Such functions created
by the user are called user-defined functions.
- Depending upon the complexity and requirement of the program,
you can create as many user-defined functions as you want.
- These are sometimes referred to as programmer-defined functions.
Maintenance and debugging:
- The program will be easier to understand, maintain and debug.
Reusability:
- Reusable codes that can be used in other programs
Encapsulation:
- A large program can be divided into smaller modules. Hence, a
large project can be divided among many programmers.
Functions are normally used in a program by writing the
name of the function followed by a left parenthesis followed by the argument (or a comma-separated list of arguments) of the function followed by a right parenthesis.
For example, a programmer desiring to calculate and print the
square root of 900.0 might write
printf( "%.2f", sqrt( 900.0 ) );
When this statement executes, the math library function sqrt is
called to calculate the square root of the number contained in the parentheses (900.0).
The general form of a function definition in C programming
language is as follows
ReturnType functionName (type1 argument1,type2 argument2,...); { body of the function }
Return Type − A function may return a value. The return_type is the data
type of the value the function returns. Some functions perform the desired
- perations without returning a value. In this case, the return_type is the
keyword void.
Function Name − This is the actual name of the function. The function name
and the parameter list together constitute the function signature.
Parameters − A parameter is like a placeholder. When a function is invoked,
you pass a value to the parameter. This value is referred to as actual parameter
- r argument. The parameter list refers to the type, order, and number of the
parameters of a function. Parameters are optional; that is, a function may contain no parameters.
Function Body − The function body contains a collection of statements that
define what the function does.
int addNumbers (int a,int b) { int c; c=a+b; return c; } Return Type Functi tion
- n Name
Parameter ters Functi tion
- n Body
returnType functionName (type1 argument1, type2 argument2,...);
A function Prototype tells the compiler about a
function name and how to call the function. The actual body of the function can be defined separately.
int addNumbers(int a, int b);
is the function prototype which provides following
information to the compiler:
- name : addNumbers()
- return type : int
- arguments type: two integers are passed to the function
int addNumbers (int a,int b) { int c; c=a+b; return c; }
int max(int num1, int num2) ; /* function returning the max between two numbers */ int max(int num1, int num2) { /* local variable declaration */ int result; if (num1 > num2) result = num1; else result = num2; return result; }
#include <stdio.h> Function definition int main() { ... ... functionName(); ... ... } #include <stdio.h> Function prototype; int main() { ... ... functionName(); ... ... } Function definition
All variables defined in function definitions are local
variables—they’re known only in the function in which they’re defined.
Most functions have a list of parameters that provide
the means for communicating information between functions.
Function to compute square of a number
Parameter names are not important in function
declaration only their type is required, so the following is also a valid declaration
Function declaration is required when you define a
function in one source file and you call that function in another file. In such case, you should declare the function at the top of the file calling the function.
While creating a C function, you give a definition of what
the function has to do. To use a function, you will have to call that function to perform the defined task.
When a program calls a function, the program control is
transferred to the called function. A called function performs a defined task and when its return statement is executed or when its function-ending closing brace is reached, it returns the program control back to the main program.
To call a function, you simply need to pass the required
parameters along with the function name, and if the function returns a value, then you can store the returned value.
#include <stdio.h> /* function declaration */ int max(int num1, int num2); int main () { /* local variable definition */ int a = 100; int b = 200; int ret; /* calling a function to get max value */ ret = max(a, b); printf( "Max value is : %d\n", ret ); return 0; } /* function returning the max between two numbers */ int max(int num1, int num2) { /* local variable declaration */ int result; if (num1 > num2) result = num1; else result = num2; return result; }
In programming, argument refers to the variable passed to
the function.
The parameters a and b accepts the passed arguments in the
function definition. These arguments are called formal parameters of the function.
The type of arguments passed to a function and the formal
parameters must match, otherwise the compiler throws error.
If n1 is of char type, a also should be of char type. If n2 is
- f float type, variable b also should be of float type.
A function can also be called without passing an argument.
The return statement terminates the execution of a
function and returns a value to the calling function. The program control is transferred to the calling function after return statement.
In the above example, the value of variable result is
returned to the variable sum in the main() function.
For example, The type of value returned from the function and the return type
specified in function prototype and function definition must match.
return (expression); return a; return (a+b);
To understand how C performs function calls, we first need
to consider a data structure (i.e., collection of related data items) known as a stack.
Students can think of a stack as analogous to a pile of
dishes.
When a dish is placed on the pile, it’s normally placed at the
top (referred to as pushing the dish onto the stack).
Similarly, when a dish is removed from the pile, it’s always
removed from the top (referred to as popping the dish off the stack).
Stacks are known as last-in, first-out (LIFO) data
structures—the last item pushed (inserted) on the stack is the first item popped (removed) from the stack.
When a program calls a function, the called function
must know how to return to its caller, so the return address of the calling function is pushed onto the program execution stack (sometimes referred to as the function call stack).
If a series of function calls occurs, the successive return
addresses are pushed onto the stack in last-in, first-out
- rder so that each function can return to its caller.
The program execution stack also contains the memory
for the local variables used in each invocation of a function during a program’s execution.
This data, stored as a portion of the program execution
stack, is known as the activation record or stack frame
- f the function call.
When a function call is made, the activation record for
that function call is pushed onto the program execution stack.
When the function returns to its caller, the activation
record for this function call is popped off the stack and those local variables are no longer known to the program.
Of course, the amount of memory in a computer is
finite, so only a certain amount of memory can be used to store activation records on the program execution stack.
If more function calls occur than can have their
activation records stored on the program execution stack, an error known as a stack overflow occurs.
Each standard library has a corresponding header
containing the function prototypes for all the functions in that library and definitions of various data types and constants needed by those functions.
You can create custom headers. Programmer-defined headers should also use the .h
filename extension.
A programmer-defined header can be included by
using the #include preprocessor directive.
For example, if the prototype for our square function
was located in the header square.h, we’d include that header in our program by using the following directive at the top of the program:
#include "square.h"
A scope in any programming is a region of the
program where a defined variable can have its existence and beyond that variable it cannot be
- accessed. There are two places where variables can be
declared in C programming language −
Inside a function or a block which is called local
variables.
Outside of all functions which is called global
variables.
Variables that are declared inside a function or block
are called local variables. They can be used only by statements that are inside that function or block of code.
Local variables are not known to functions outside
their own. The following example shows how local variables are used. Here all the variables a, b, and c are local to main() function.
#include <stdio.h> int main () { /* local variable declaration */ int a, b; int c; /* actual initialization */ a = 10; b = 20; c = a + b; printf ("value of a = %d, b = %d and c = %d\n", a, b, c); return 0; }
Global variables are defined outside a function, usually
- n top of the program. Global variables hold their values
throughout the lifetime of your program and they can be accessed inside any of the functions defined for the program.
A global variable can be accessed by any function. That
is, a global variable is available for use throughout your entire program after its declaration. The following program show how global variables are used in a program.
#include <stdio.h> /* global variable declaration */ int g; int u=10; int main () { /* local variable declaration */ int a, b; /* actual initialization */ a = 10; b = 20; g = a + b; printf ("value of u= %d, a = %d, b = %d and g = %d\n", u,a, b, g); return 0; }
#include <stdio.h> #include <stdlib.h> int Sum; void sumFun(int ,int); int main() { sumFun(100,20); printf("%d",Sum); return 0; } void sumFun(int a,int b) { Sum=a+b; }
A program can have same name for local and global
variables but the value of local variable inside a function will take preference. Here is an example
#include <stdio.h> /* global variable declaration */ int g = 20; int main () { /* local variable declaration */ int g = 10; printf ("value of g = %d\n", g); return 0; }
A storage class defines the scope (visibility) and life-
time of variables and/or functions within a C
- Program. They precede the type that they modify.
We have four different storage classes in a C program
- auto
- register
- static
- extern
storage_classes variable_type variable_name
auto register static extern int float double char
The auto storage class is the default storage class for
all local variables.
Scope: the block which defines the auto variable Life time: created when it defined and ended at the
end of the block
The example below defines two variables with in the
same storage class. 'auto' can only be used within functions, i.e., local variables. {
int mount; auto int month; }
void main() { int x; int y; { int c=100; printf("%c %d",c,x); } c++; }
Compiler error!
The register storage class is used to define local
variables that should be stored in a register instead of RAM.
The register should only be used for variables that
require quick access such as counters. It should also be noted that defining 'register' does not mean that the variable will be stored in a register. It means that it MIGHT be stored in a register depending on hardware and implementation restrictions. {
register int miles; }
The static storage class instructs the compiler to keep a
local variable/global variable in existence during the life- time of the program instead of creating and destroying it each time it comes into and goes out of scope.
Therefore, making local variables static allows them to
maintain their values between function calls.
Static variables are initialized by zero! Are divided into two groups:
- Local static variables
- Global static variables
Life time: during the program life Scope: the function which the variable is defined in Created when the function is invoked the first time
and saves its value at the end of function
Are defined out of the
functions
Scope: the functions which
are defined after the variable definition
Life time: during the
program life
void f1(void ); void f2(void ); int main() { .... f1(); .... f2(); .... } static int x,y; void f1(void) { ..... } void f2(void) { ..... }
#include <stdio.h> /* function declaration */ void func(void); static int count = 5; /* global variable */ main() { while(count--) { func(); } return 0; } /* function definition */ void func( void ) { static int i = 5; /* local static variable */ auto int j = 5; i++; printf("i is %d, count is %d and j is %d\n", i, count,j); }
The extern storage class is used to give a reference of a
global variable that is visible to ALL the program files. When you use 'extern', the variable cannot be initialized however, it points the variable name at a storage location that has been previously defined.
When you have multiple files and you define a global
variable or function, which will also be used in other files, then extern will be used in another file to provide the reference of defined variable or function. Just for understanding, extern is used to declare a global variable or function in another file.
#include<stdio.h> int x,y; void f1(); void main() { extern int x,y; ... f1(); .... } void f1() { extern int x,y; .... } #include<stdio.h> int x,y; void f1(); void main() { ... f1(); .... } void f1() { .... }
The extern modifier is most commonly used when there
are two or more files sharing the same global variables
- r functions as explained below.
Scope: all the program files Life time: during the program life
First File: main.c #include <stdio.h> int count ; void write_extern(void ); main() { count = 5; write_extern(); } Second File: support.c #include <stdio.h> extern int count; void write_extern(void) { printf("count is %d\n", count); }
Call by value
- This method copies the actual value of an argument into the
formal parameter of the function. In this case, changes made to the parameter inside the function have no effect on the argument.
Call by reference
- This method copies the address of an argument into the formal
- parameter. Inside the function, the address is used to access the
actual argument used in the call. This means that changes made to the parameter affect the argument.
The call by value method of passing arguments to a function
copies the actual value of an argument into the formal parameter
- f the function. In this case, changes made to the parameter
inside the function have no effect on the argument.
When arguments are passed by value, a copy of the argument’s
value is made and passed to the called function.
Changes to the copy do not affect an original variable’s value in
the caller.
When an argument is passed by reference, the caller allows the
called function to modify the original variable’s value.
Call-by-value should be used whenever the called function does
not need to modify the value of the caller’s original variable.
#include<stdio.h> void sum(int a,int b,int*c); void main() { int cc; sum(10,12,&cc); printf("%d",cc); } void sum(int a,int b,int*c) { *c=a+b; }
#include <stdio.h> void swap(int *n1, int *n2); int main() { int num1 = 5, num2 = 10; // address of num1 and num2 is passed to the swap function swap( &num1, &num2); printf("Number1 = %d\n", num1); printf("Number2 = %d", num2); return 0; } void swap(int * n1, int * n2) { // pointer n1 and n2 points to the address of num1 and num2 respectively int temp; temp = *n1; *n1 = *n2; *n2 = temp; }
The address of memory location num1 and num2 are
passed to the function swap and the pointers *n1 and *n2 accept those values.
So, now the pointer n1 and n2 points to the address
- f num1 and num2 respectively.
When, the value of pointers are changed, the value in the
pointed memory location also changes correspondingly.
Hence, changes made to *n1 and *n2 are reflected
in num1 and num2 in the main function.
This technique is known as Call by Reference in C
programming.
When we tried to write the above code using call by
value method, the value of both the integer variables didn’t get change, however with this method of “call by reference” we have dealt with the address of actual arguments and got desired output.
We now take a brief and, hopefully, entertaining diversion
into a popular programming application, namely simulation and game playing.
The element of chance can be introduced into computer
applications by using the C Standard Library function rand from the <stdlib.h> header.
Consider the following statement:
i = rand();
The rand function generates an integer between 0 and
RAND_MAX (a symbolic constant defined in the <stdlib.h> header).
Standard C states that the value of RAND_MAX must be
at least 32767, which is the maximum value for a two- byte (i.e., 16-bit) integer.
The programs in this section were tested on a C system
with a maximum value of 32767 for RAND_MAX.
If rand truly produces integers at random, every
number between 0 and RAND_MAX has an equal chance (or probability) of being chosen each time rand is called.
The range of values produced directly by rand is often
different from what is needed in a specific application.
For example, a program that simulates coin tossing might
require only 0 for “heads” and 1 for “tails.”
A dice-rolling program that simulates a six-sided die would
require random integers from 1 to 6.
To demonstrate rand, let’s develop a program to simulate
20 rolls of a six-sided die and print the value of each roll.
The function prototype for function rand is in
<stdlib.h>.
We use the remainder operator (%) in conjunction with
rand as follows
rand() % 6
to produce integers in the range 0 to 5.
This is called scaling. The number 6 is called the scaling factor. We then shift the range of numbers produced by adding
1 to our previous result.
The output of Fig. 5.7 confirms that the results are in
the range 1 to 6—the output might vary by compiler.
To show that these numbers occur approximately with
equal likelihood, let’s simulate 6000 rolls of a die with the program of Fig. 5.8.
Each integer from 1 to 6 should appear approximately
1000 times.
As the program output shows, by scaling and shifting
we’ve used the rand function to realistically simulate the rolling of a six-sided die.
No default case is provided in the switch statement.
Executing the program of Fig. 5.7 again produces
exactly the same sequence of values.
How can these be random numbers? Ironically, this
repeatability is an important characteristic of function rand.
When debugging a program, this repeatability is essential
for proving that corrections to a program work properly.
Function rand actually generates pseudorandom numbers. Calling rand repeatedly produces a sequence of numbers
that appears to be random.
However, the sequence repeats itself each time the program
is executed.
Once a program has been thoroughly debugged, it can be
conditioned to produce a different sequence of random numbers for each execution.
This is called randomizing and is accomplished with
the standard library function srand.
Function srand takes an unsigned integer
argument and seeds function rand to produce a different sequence of random numbers for each execution of the program.
We demonstrate srand in Fig. 5.9.
The C library function time_t time(time_t *seconds) returns
the time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds. If seconds is not NULL, the return value is also stored in variable seconds.
Following is the declaration for time() function.
time_t time(time_t *t)
Let’s run the program several times and observe the results. Notice that a different sequence of random numbers is
- btained each time the program is run, provided that a
different seed is supplied.
To randomize without entering a seed each time, use a
statement like
srand( time( NULL NULL ) );
This causes the computer to read its clock to obtain the
value for the seed automatically.
Function time returns the number of seconds that have
passed since midnight on January 1, 1970.
This value is converted to an unsigned integer and used
as the seed to the random number generator.
Function time takes NULL as an argument (time is
capable of providing you with a string representing the value it returns; NULL disables this capability for a specific call to time).
The function prototype for time is in <time.h>.
The values produced directly by rand are always in the
range:
0 rand() RAND_MAX
As you know, the following statement simulates rolling a
six-sided die:
face = 1 + rand() % + rand() % 6;
This statement always assigns an integer value (at random)
to the variable face in the range 1 face 6.
The width of this range (i.e., the number of consecutive
integers in the range) is 6 and the starting number in the range is 1.
Referring to the preceding statement, we see that the
width of the range is determined by the number used to scale rand with the remainder operator (i.e., 6), and the starting number of the range is equal to the number (i.e., 1) that is added to rand % 6.
We can generalize this result as follows
n = a + rand() % b;
where a is the shifting value (which is equal to the first
number in the desired range of consecutive integers) and b is the scaling factor (which is equal to the width
- f the desired range of consecutive integers).