Unit - 1
Functions and Pointer
Similar to other languages, the C language also provides the facility of function. Function is the block of code which is used to perform a specific task. In c language the complete program is composed of functions.
Functions are useful to divide c programs into smaller modules. Programmer can invoked these modules anywhere inside c program for any number of times.
Functions are used to increase readability of the code. Size of program can be reduce by using functions. By using function, programmer can divide complex tasks into smaller manageable tasks and test them independently before using them together.
Functions of C language are defined with the type of function. The type of functions indicates the data type of value which will return by function. In order to use function in the program, initially programmer have to inform compiler about the function. This is also called as defining a function.
In C program all the function definition present outside the main function. All function need to be declared and defined before use. Function declaration requires function name, argument list, and return type.
Return TypeFunction name (Parameter list)
{
//body of function
Statement 1;
Statement 2;
…………...
Statement n;
}
In C programming, a function definition consists of a function header and a function body. All of the components of a function are listed here.
● Return Type − A function may return a value as its return type. The return type specifies the data type of the value returned by the function. Some functions do what they're supposed to do yet don't return a value. The keyword void is used as the return type in this scenario.
● Function Name - This is the function's real name. The function signature is made up of the function name and the argument list.
● Parameters − A parameter is similar to a placeholder. You pass a value to the parameter when you call a function. Actual parameter or argument refers to this value. The type, order, and number of parameters in a function are referred to as the parameter list. Parameters are optional; a function may or may not have them.
● Function Body − The function body is made up of a series of statements that specify what the function does.
Declaration
A function declaration tells the compiler the name of the function and how to invoke it. The function's actual body can be defined independently.
The following are the components of a function declaration:
Return_type function_name( parameter list );
The function declaration for the above-mentioned function max() is as follows:
Int max(int num1, int num2);
In a function declaration, the names of the parameters are not relevant; only their types are, hence the following is also a legal declaration:
Int max(int, int);
When a function is defined in one source file and called in another, a function declaration is necessary. In this situation, the function should be declared at the top of the file calling the function.
Prototype of function
One of the most essential characteristics of C programming, which evolved from C++, is the function prototype. A function prototype is a code declaration that tells the compiler about the function's data type, parameters, and parameter list. A function, as we all know, is a section of code that performs a specified task. A function prototype, on the other hand, is a function that tells the compiler the return type, function name, and parameter so that it can match the given function calls when they're needed.
Syntax
Return-type function-name ( datatype parameter1 , datatype parameter2 , datatype parameter3..);
Example:
Int addition(int a, int b);
In the preceding example, addition is the name of the function with an integer data type, and a and b are the arguments of two int arguments supplied to the function. Note that, depending on the necessity, we can pass as many parameters as we wish to our function. We can define as many prototypes as we wish in the same programme, but they must differ in either name or parameter list. All you have to do is create a prototype in the code and then use the function name to call it at any time.
Program for function prototype
#include <stdio.h>
Int Num_addition( int i , int j );// prototype for the function
Int main()
{
Int num1,num2,total;
Printf( " Please enters the 2 numbers you want to add : " ) ;
Scanf( "%d %d" , &num1 , &num2 ) ;
Total = Num_addition( num1 , num2 ) ; // calling the function
Printf( " The total of the given numbers is = %d " , total ) ;
Return 0 ;
}
Int Num_addition( int i , int j ) // function definition for prototype
{
Int results;
Results = i + j ;
Return results ;
}
Output
As you can see in the following code, we first declare the function prototype for the addition of two numbers with the name " Num addition " and an integer return type with two integer arguments named I and j. We defined three integers in the main class: num1, num2, and total. Following that, we collect user input before storing the total addition results of the two given values. The function " Num addition" is used once again to call it. Finally, you can see in the function declaration that we provide the logic to do addition and save the results.
Key takeaway
Functions are useful to divide c programs into smaller modules. Programmers can invoke these modules anywhere inside C program for any number of times.
A function prototype is a code declaration that tells the compiler about the function's data type, parameters, and parameter list.
Local variables
Local variables are variables that are declared within a function or block. They can only be utilised by statements that are included within that function or code block. Functions outside of their own are unaware of local variables. The following example demonstrates the use of local variables. The variables a, b, and c are all local to the function main().
#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;
}
Advantages of Local Variable
● Because a local variable's name is only recognised by the function in which it is declared, it can be used in several functions with the same name.
● Local variables only require memory for the duration of the function; after that, the same memory address can be reused.
Disadvantages of Local Variables
● The local variable's scope is restricted to its function and it cannot be used by other functions.
● The local variable is not allowed to share data.
Global Variables
Global variables are variables that are defined outside of a function, usually at the start of a programme. Global variables maintain their values throughout the life of your programme and can be accessed from any of the program's functions.
Any function has access to a global variable. That is, once a global variable is declared, it is available for use throughout your whole programme. The following programme demonstrates the use of global variables in a programme.
#include <stdio.h>
/* global variable declaration */
Int g;
Int main () {
/* local variable declaration */
int a, b;
/* actual initialization */
a = 10;
b = 20;
g = a + b;
printf ("value of a = %d, b = %d and g = %d\n", a, b, g);
return 0;
}
Local and global variables in a programme can have the same name, but the value of a local variable inside a function takes precedence. Here's an illustration:
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;
}
When the preceding code is compiled and run, the following result is obtained:
Value of g = 10
Advantages of Global Variable
● Global variables can be accessible by all of the program's functions.
● It is just necessary to make a single declaration.
● If all of the functions are accessing the same data, this is quite handy.
Disadvantages of Global Variable
● Because it can be utilised by any function in the programme, the value of a global variable can be modified by accident.
● If we employ a big number of global variables, there is a good possibility that the programme may generate errors.
Difference between Global variable and Local variable
Global Variable | Local Variable |
Outside of all the function blocks, global variables are declared. | Within a function block, local variables are declared. |
Throughout the programme, the scope is maintained. | The scope is restricted, and they can only be used in the function in which they are declared. |
Any modification to a global variable has an impact on the entire programme, regardless of where it is utilised. | Any changes to the local variable have no effect on the program's other functions.
|
A global variable is present in the programme for the duration of its execution. | After the function is executed, a local variable is created, and when the function is finished, the variable is destroyed. |
It can be accessed from anywhere in the programme using any of the program's functionalities. | It is only accessible through the function statements in which it is declared, not through other functions. |
If a global variable isn't initialised, it defaults to zero. | If a local variable isn't initialised, it defaults to a garbage value. |
The data segment of memory stores global variables. | Local variables are kept in memory on a stack. |
We can't use the same name for several variables. | Variables having the same name can be declared in several functions. |
Key takeaway
Local variables are variables that are declared within a function or block.
Global variables are variables that are defined outside of a function, usually at the start of a programme.
User defined function is the block of code written by programmer to perform a particular task. As compiler doesn’t have any idea about the user define function so programmer has to define and declare these functions inside the program body. Programmer can define these function outside the main function but declaration of user defined function should present in main function only. Whenever compiler executes function call (function declaration) then compiler shift the flow of program execution to the definition part of user define function.
Example
#include <stdio.h>
#include<conio.h>
Int add (int x, int y)
{
Int sum;
Sum = x + y;
Return (sum);
}
Main ()
{
Int a,b,c;
a = 15;
b = 25;
c = add(a,b);
Printf ("\n Addition is %d ", c);
}
Output:
Addition is 40
Key takeaway
User defined function is the block of code written by programmer to perform a particular task.
Programmer can define these function outside the main function but declaration of user defined function should present in main function only.
Recursion
In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.
Void recursion() {
Recursion(); /* function calls itself */
}
Int main() {
Recursion();
}
The C programming language supports recursion, i.e., a function to call itself. But while using recursion, programmers has to be careful to define an exit condition from the function, otherwise it will go into an infinite loop.
Recursive functions are useful to solve many mathematical problems, such as calculating the factorial of a number, generating Fibonacci series, etc.
The following example calculates the factorial of a given number using a recursive function −
#include <stdio.h>
Unsigned long long int factorial(unsigned int i) {
If(i <= 1) {
Return 1;
}
Return i * factorial(i - 1);
}
Int main() {
Int i = 12;
Printf("Factorial of %d is %d\n", i, factorial(i));
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Factorial of 12 is 479001600
The following example generates the Fibonacci series for a given number using a recursive function −
#include <stdio.h>
Int fibonacci(int i) {
If(i == 0) {
Return 0;
}
If(i == 1) {
Return 1;
}
Return fibonacci(i-1) + fibonacci(i-2);
}
Int main() {
Int i;
For (i = 0; i < 10; i++) {
Printf("%d\t\n", fibonacci(i));
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
0
1
1
2
3
5
8
13
21
34
Storage classes
Within a C programme, a storage class defines the scope (visibility) and lifetime of variables and/or functions. They come before the type they modify. In a C programme, there are four different storage classes:
● auto
● register
● static
● extern
Auto
At runtime, memory is automatically allocated to automated variables.
The automated variables' visibility is confined to the block in which they are defined. The automated variables' scope is constrained to the block in which they are defined. By default, the automated variables are set to garbage.
When you depart the block, the memory allotted to automatic variables is released. The auto keyword is used to define automatic variables.
By default, every local variable in C is automatic.
For all local variables, the auto storage class is the default storage class.
{
int mount;
auto int month;
}
The preceding example declares two variables in the same storage class. The keyword 'auto' can only be used within functions, i.e. within local variables.
Example:
#include <stdio.h>
Int main()
{
Int a; //auto
Char b;
Float c;
Printf("%d %c %f",a,b,c); // printing initial default value of automatic variables a, b, and c.
Return 0;
}
Output:
Garbage garbage garbage
Register
The memory is allocated to the CPU registers by the variables declared as the registers, depending on the size of the memory remaining in the CPU.
We can't dereference the register variables, which means we can't use & operator for them. The register variables have a faster access time than the automatic variables. The register local variables have a default value of 0.
The variable that should be saved in the CPU register is denoted by the register keyword. Is it, nevertheless, a compiler? The variables can be stored in the register at the user's discretion. We can store pointers in registers, which means that a register can hold the address of a variable. Because we can't use more than one storage specifier for the same variable, static variables can't be stored in the register.
{
register int miles;
}
Example:
#include <stdio.h>
Int main()
{
Register int a; // variable a is allocated memory in the CPU register. The initial default value of a is 0.
Printf("%d",a);
}
Output:
0
Static
The static storage class tells the compiler to keep a local variable alive for the duration of the programme, rather than creating and destroying it every time it enters and exits scope. As a result, making local variables static ensures that their values are preserved between function calls.
The static modifier can be used on global variables as well. When you do this, the scope of that variable is limited to the file in which it is declared.
When the keyword static is applied on a global variable in C programming, just one copy of that member is shared by all objects in that class.
#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 */
i++;
printf("i is %d and count is %d\n", i, count);
}
When the above code is compiled and executed, it produces the following result −
i is 6 and count is 4
i is 7 and count is 3
i is 8 and count is 2
i is 9 and count is 1
i is 10 and count is 0
Extern
The extern storage class is used to provide a reference to a global variable that is shared by all application files. The variable cannot be initialised when you use 'extern,' but it does direct the variable name to a previously established storage location.
When you have many files and specify a global variable or function that will be utilised in other files, extern is used in another file to provide a reference to the defined variable or function. To clarify, extern is a keyword that is used to declare a global variable or function in a different file.
Example:
#include <stdio.h>
Int main()
{
Extern int a;
Printf("%d",a);
}
Output
Main.c:(.text+0x6): undefined reference to a'
Collect2: error: ld returned 1 exit status
Key takeaway
In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.
Within a C programme, a storage class defines the scope (visibility) and lifetime of variables and/or functions. They come before the type they modify. In a C programme, there are four different storage classes.
Pointers in C language is a variable that stores/points the address of another variable. A Pointer in C is used to allocate memory dynamically i.e. at run time. The pointer variable might belong to any of the data type such as int, float, char, double, short etc.
Pointer Syntax: data_type *var_name; Example : int *p; char *p;
Where, * is used to denote that “p” is pointer variable and not a normal variable.
Normal variable stores the value whereas pointer variable stores the address of the variable.
The content of the C pointer always be a whole number i.e. address.
Always C pointer is initialized to null, i.e. int *p = null.
The value of null pointer is 0.
& symbol is used to get the address of the variable.
* symbol is used to get the value of the variable that the pointer is pointing to.
If a pointer in C is assigned to NULL, it means it is pointing to nothing.
Two pointers can be subtracted to know how many elements are available between these two pointers.
But, Pointer addition, multiplication, division are not allowed.
The size of any pointer is 2 byte (for 16 bit compiler).
Example:
#include <stdio.h>
Int main()
{
Int *ptr, q;
q = 50;
/* address of q is assigned to ptr */
Ptr = &q;
/* display q's value using ptr variable */
Printf("%d", *ptr);
Return 0;
}
Output:
1
2
3
4
5
6
7
8
9
10
11
Declaration
Pointers are declare with the help of operator ‘*’. ‘*’ is known as ‘value at address’. Pointers are the variables which are used to store the address of another variable As the address of variable is always whole numbers so pointer always contains whole numbers. The declaration of pointer are as follows.
Syntax: Data type * pointer Name.
Example: int *I;
Data type defines the type of value defined at the address of pointer variable. In the above example value at the address of ‘I’ is of type integer.
Consider the following program.
# include<stdio.h>
# include<conio.h>
Void main()
{
Int a,b,c;
Int *p,*q,*r;
p=&a;
q=&b;
r=&c;
Printf(“Enter two numbers”);
Scanf(“%d%d,&a,&b);
c=a + b;
Printf(“\n Address of variable C is %d”,&C);
Printf(“\n Address of variable C is %d,r);
Printf(“\n Address of variable r is %d”,&r);
Printf(“\n value of variable C is %d”,C);
Printf(“\n value of variable C is %d,*^);
Getch ();
}
In the above program variable ‘r’ is the integer pointer which holds the address of variable ‘C’
Case 1: In ‘printf’ statement whenever we used (“%d”,r) men me value of r is printed but ‘r’ is holding the address of variable ‘C’. So, address of variable C is copied to the value of ‘r’ and it is printed on output screen
Case 2: Whenever we used (“%d”,&r) in ‘printf’ function men the address of variable ‘r’ is pointed on o/p screen.
Case 3: When we used (“%d”,*r) in pointf function at mat time value which is stored at the address which holds by variable ‘r’ is printed.
Now me variable ‘r’ is holding the address of variable ‘C’. So, the value which is stored at the address of ‘C’ is printed on the output screen.
Consider the following example.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a=3;
Int *p;
p=&a;
Printf(“\n%d”,a);
Printf(“\n%d”,&a);
Printf(“\n%d”,P);
Printf(“\n%d”,&P);
Printf(“\n%d”,*P);
Printf(“\n%d”,*(&a));
}
Run the above program on the computer system so that you will familiar with the basic use of pointers. Following is the explanation O/p of above program.
● The first ‘printf’ statement prints the value of ‘C’ ie. 3
● The second ‘printf’ statement prints the address of ‘a’
● The third ‘printf’ statement prints me value of ‘p’ ie. The address of ‘a’
● The forth ‘printf’ statement prints the address of ‘p’
● The fifth ‘printf’ statement prints the value which is stored at the address holds in ‘p’ ie. 3
● The sixth ‘printf’ statement prints the value which is stored at the address of ‘a’ ie. 3
Data type of pointer variable can be anything. Such as char *C;
In the above instruction pointer ‘C’ is of type character so the variable ‘C’ can store the address of variable which contains character type of value. Consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int I,*ip;
Char C, *cp;
I = 3;
Ip = & I;
c=’M’;
Cp=&c;
Printf(“%d”,I);
Printf(“\n%d”,*ip);
Printf(“\n%C;,C);
Printf(“\n%c”, *cp);
Getch();
}
The output of above program is.
3
3
m
m
Defining pointers
One of the vital and heavily used features of ‘C’ is pointer. Most of the other programming languages also support pointers but only few of them use it freely. Support pointers but only few of them use it freely.
When we declare any variable in C language, there are three things associated with that variable.
- Data type of variable: Data type defines the type of data that variable can hold. Data type tells the compiler about the amount of memory allocated to the variable.
- Address of Variable: Address of variable represents the exact address of memory location which is allocated to variable.
- Value of variable: It is the value of variable which is stored at the address of memory location allocated to variable.
Example: int n = 5;
In the above example ‘int’ is the data type which tells the compiler to allocate 2 bytes of memory to variable ‘n’.
Once the variable is declared the compiler allocated two bytes of memory to variable ‘n’. Suppose the address of that memory location is 1020. At the address of memory location 1020 the value 5 is stored.
Memory map for the above declaration is as follows.
Use of &,/and ‘*’ operator
Consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a,b,c;
Printf(“Enter two numbers”);
Scanf(“%d%d”, &a,&b);
c = a+b;
Printf(“/n Addition is %d”, c);
Printf(“/n Addition of variable is %d”, &c);
Getch();
}
Above program is the program for addition of two numbers in ‘C’ language. In the seventh instruction of the above program we used operator ‘%’ and ‘&’ ‘%d’ is the access specifier which tells the compiler to take integer value as an input whereas. ‘&a’ tells the compiler to store the taken value at the address of variable ‘a’.
In the ninth instruction compiler will print me the value of ‘C’ so the output of the 9th instruction is as follows.
Addition is 5[Note: considering a = 2 and b = 3]
In the tenth instruction compiler will print me the address of variable C.
So the output of length instruction is as follows. Address of variable C is 1020.
Now consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a,b,c;
Printf(“Enter two numbers”);
Scanf(“%d%d”, &a,&b);
c = a+b;
Printf(“/n Addition is %d”, c);
Printf(“/n Addition of variable is %d”, &c);
Printf(“/n value of variable c is %d”, *(&c));
Getch();
}
Now, we all are clear about the output of instruction 9 and 10.
In the 11th instruction, operator *and & is used. ‘*’ operator tells compiler to pick up the value which is stored at the address of variable C. So the output of the 11th instruction is as follows. Value of variable C is 5 [considering a = 24 b = 3;]
Key takeaway:
One of the vital and heavily used features of ‘C’ is pointer.
Most of the other programming languages also support pointers but only few of them use it freely.
The process of assigning a variable's address to a pointer variable is known as pointer initialization. The address of a variable of the same data type can only be stored in a pointer variable. The address operator & is used to determine the address of a variable in the C programming language. The & (directly preceding a variable name) yields the variable's address.
#include<stdio.h>
Void main()
{
int a = 10;
int *ptr; //pointer declaration
ptr = &a; //pointer initialization
}
Variables of the same datatype are always pointed to by pointer variables. Let's look at an example to demonstrate this:
#include<stdio.h>
Void main()
{
float a;
int *ptr;
ptr = &a; // ERROR, type mismatch
}
If you're not sure which variable's address to assign to a pointer variable during declaration, it's best to leave it blank. A NULL pointer is a pointer that has been allocated the value NULL.
#include <stdio.h>
Int main()
{
int *ptr = NULL;
return 0;
}
Key takeaway
The process of assigning a variable's address to a pointer variable is known as pointer initialization. The address of a variable of the same data type can only be stored in a pointer variable.
Pointer arithmetic is slightly different from arithmetic we normally use in our daily life. The only valid arithmetic operations applicable on pointers are:
- Addition of integer to a pointer
- Subtraction of integer to a pointer
- Subtracting two pointers of the same type
The pointer arithmetic is performed relative to the base type of the pointer. For example, if we have an integer pointer ip which contains address 1000, then on incrementing it by 1, we will get 1004 (i.e 1000 + 1 * 4) instead of 1001 because the size of the int data type is 4 bytes. If we had been using a system where the size of int is 2 bytes then we would get 1002 ( i.e 1000 + 1 * 2 ).
Similarly, on decrementing it we will get 996 (i.e 1000 - 1 * 4) instead of 999.
So, the expression ip + 4 will point to the address 1016 (i.e 1000 + 4 * 4).
Let's take some more examples.
1
2
3
Int i = 12, *ip = &i;
Double d = 2.3, *dp = &d;
Char ch = 'a', *cp = &ch;
Suppose the address of i, d and ch are 1000, 2000, 3000 respectively, therefore ip, dp and cp are at 1000, 2000, 3000 initially.
Key takeaway
Pointer arithmetic is slightly different from arithmetic we normally use in our daily life.
The pointer arithmetic is performed relative to the base type of the pointer.
Consider the following example, which utilises an array of three integers to explain the notion of arrays of pointers.
#include <stdio.h>
const int MAX = 3;
Int main () {
int var[] = {10, 100, 200};
int i;
for (i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, var[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
There may be times when we need to keep an array that can store pointers to ints, chars, or any other possible data type. The declaration of an array of pointers to an integer is as follows:
Int *ptr[MAX];
It declares ptr as a MAX integer pointer array. As a result, each ptr element contains a pointer to an int value. The example below uses three integers that are stored in an array of pointers like follows:
#include <stdio.h>
Const int MAX = 3;
Int main () {
int var[] = {10, 100, 200};
int i, *ptr[MAX];
for ( i = 0; i < MAX; i++) {
ptr[i] = &var[i]; /* assign the address of integer. */
}
for ( i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, *ptr[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
You can also store a list of strings in an array of character pointers, as shown below:
#include <stdio.h>
Const int MAX = 4;
Int main () {
char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
int i = 0;
for ( i = 0; i < MAX; i++) {
printf("Value of names[%d] = %s\n", i, names[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali
Pointers and one-dimensional array
● For every of the array's items, the compiler allocates Continuous memory addresses.
● The array's base address is equal to the array's first element address (index 0).
● For instance, int a [5] = 10, 20, 30, 40, 50;
Elements
The five items are saved in the following order:
If 'p' is declared as an integer pointer, the following assignment can be used to point to an array 'a'.
p = a;
(or) p = &a[0];
Using p++ to travel from one element to another, every value of 'a' is accessed. When a pointer is incremented, the size of the datatype it points to is multiplied by its value. The "scale factor" is the name given to this length.
Below is an explanation of the link between 'p' and 'a.'
P = &a[0] = 1000
P+1 = &a[1] = 1004
P+2 = &a[2] = 1008
P+3 = &a[3] = 1012
P+4 = &a[4] = 1016
The address of an element is determined by its index and the datatype's scale factor. Here's an example to help you understand.
Address of a[3] = base address + (3* scale factor of int)
= 1000 + (3*4)
= 1000 +12
= 1012
Instead of utilising array indexing, pointers can be used to access array entries.
The value of a[3] is given by *(p+3).
a[i] = *(p+i)
Example
The C programme for pointers and one-dimensional arrays is shown below.
#include<stdio.h>
Main ( ){
int a[5];
int *p,i;
printf ("Enter 5 elements");
for (i=0; i<5; i++)
scanf ("%d", &a[i]);
p = &a[0];
printf ("Elements of the array are");
for (i=0; i<5; i++)
printf("%d", *(p+i));
}
Output
When the aforementioned programme is run, the following result is obtained:
Enter 5 elements: 10 20 30 40 50
Elements of the array are: 10 20 30 40 50
Pointers and two dimensional arrays
The following is the memory allocation for a two-dimensional array:
Int a[3] [3] = {1,2,3,4,5,6,7,8,9};
a[1] [2] = *(1234 + 1*3+2)
= *(1234 + 3+2)
= *(1234 + 5*4) // 4 is Scale factor
= * (1234+20)
= *(1254)
a[1] [2] = 6
Example
The C programme for pointers and two-dimensional arrays is shown below.
#include<stdio.h>
Main ( ){
int a[3] [3], i,j;
int *p;
clrscr ( );
printf ("Enter elements of 2D array");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
scanf ("%d", &a[i] [j]);
}
}
p = &a[0] [0];
printf ("elements of 2d array are");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
printf ("%d \t", *(p+i*3+j));
}
printf ("\n");
}
getch ( );
}
Output
When the aforementioned programme is run, the following result is obtained:
Enter elements of 2D array
1 2 3 4 5 6 7 8 9
Elements of 2D array are
1 2 3
4 5 6
7 8 9
Parameter Passing by Value
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called call by value. In case of parameter passing by value, the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function.
This mechanism is used when programmer don't want to change the value of passed parameters. When parameters are passed by value then functions in C create copies of the passed in variables and do required processing on these copied variables.
Pass-by-value is implemented by actual data transfer so additional storage is required to maintain the copies of passed parameters.
Example:
#include <stdio.h>
#include<conio.h>
/* function declaration goes here.*/
Void swap( int p1, int p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( a, b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
Getch();
}
Void swap( int p1, int p2 )
{
Int t;
t = p2;
p2 = p1;
p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", p1, p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b (p2) = 10
After: Value of a = 10 and value of b = 20
Note: In the above example the values of “a” and “b” remain unchanged before calling swap function and after calling swap function.
Parameter Passing by Reference
This mechanism is used when programmers want a function to do the changes in passed parameters and reflect those changes back to the calling function. This mechanism is also called as call by reference. This is achieved by passing the address of variable to the function and function body can directly work over the addresses. Advantage of pass by reference is efficiency in both time and space. Whereas disadvantages are access to formal parameters is slow and inadvertent and erroneous changes may be made to the actual parameter.
Example:
#include <stdio.h>
#include<conio.h>
Void swap( int *p1, int *p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( &a, &b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
}
Void swap( int *p1, int *p2 )
{
Int t;
t = *p2;
*p2 = *p1;
*p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", *p1, *p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b(p2) = 10
After: Value of a = 20 and value of b = 10
Note: In the above example the values of “a” and “b” are changes after calling swap function.
Call by reference
Array is a data structure which stores the collection of similar types of element in consecutive memory locations. Indexing of array always start with ‘0’ where as non-graphical variable ‘\0’ indicates the end of array. Syntax for declaring array is
Data typearray name[Maximum size];
● Data types are used to define type of element in an array. Data types are also useful in finding the size of total memory locations allocated for the array.
● All the rules of defining name of variable are also applicable for the array name.
● Maximum size indicates the total number of maximum elements that array can hold.
● Total memory allocated for the array is equal to the memory required to store one element of the array multiply by the total element in the array.
● In array, memory allocation is done at the time of declaration of an array.
Example:
Sr. No. | Instructions | Description |
1. | #include<stdio.h> | Header file included |
2. | #include<conio.h> | Header file included |
3. | Void main() | Execution of program begins |
4. | { |
|
5. | Int i,n,a[10]; | Memory is allocated for variable i,n and array a |
6. | Clrscr(); | Clear the output of previous screen |
7. | Printf("enter a number"); | Print “enter a number” |
8. | Scanf("%d",&n); | Input value is stored at the addres of variable n |
9. | For(i=0;i<=10;i++) | For loop started from value of i=0 to i=10 |
10. | { | Compound statement(scope of for loop starts) |
11. | a[i]=n*i; | Result of multiplication of n and I is stored at the ith location of array ieas i=0 so it is stores at first location. |
12. | Printf("\n %d",a[i]); | Value of ith location of the array is printed |
13. | } | Compound statement(scope of for loop ends) |
14. | Printf("\n first element in array is %d",a[0]); | Value of first element of the array is printed |
15. | Printf("\n fifth element in array is %d",a[4]); | Value of fifth element of the array is printed |
16. | Printf("\n tenth element in array is %d",a[9]); | Value of tenth element of the array is printed |
17. | Getch(); | Used to hold the output screen |
18. | } | Indicates end of scope of main function |
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called as call by value. In case of parameter passing by value, the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function.
This mechanism is used when programmer don't want to change the value of passed parameters. When parameters are passed by value then functions in C create copies of the passed in variables and do required processing on these copied variables.
Pass-by-value is implemented by actual data transfer so additional storage is required to maintain the copies of passed parameters.
Example:
#include <stdio.h>
#include<conio.h>
/* function declaration goes here.*/
Void swap( int p1, int p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( a, b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
Getch();
}
Void swap( int p1, int p2 )
{
Int t;
t = p2;
p2 = p1;
p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", p1, p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b (p2) = 10
After: Value of a = 10 and value of b = 20
Note: In the above example the values of “a” and “b” remain unchanged before calling swap function and after calling swap function.
Key takeaway
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called call by value.
C malloc()
The name "malloc" stands for memory allocation.
The malloc() function reserves a block of memory of the specified number of bytes. And, it returns a pointer of void which can be casted into pointers of any form.
Syntax of malloc()
Ptr = (castType*) malloc(size);
Example
Ptr = (float*) malloc(100 * sizeof(float));
The above statement allocates 400 bytes of memory. It's because the size of float is 4 bytes. And, the pointer ptr holds the address of the first byte in the allocated memory.
The expression results in a NULL pointer if the memory cannot be allocated.
C calloc()
The name "calloc" stands for contiguous allocation.
The malloc() function allocates memory and leaves the memory uninitialized. Whereas, the calloc() function allocates memory and initializes all bits to zero.
Syntax of calloc()
Ptr = (castType*)calloc(n, size);
Example:
Ptr = (float*) calloc(25, sizeof(float));
The above statement allocates contiguous space in memory for 25 elements of type float.
C free()
Dynamically allocated memory created with either calloc() or malloc() doesn't get freed on their own. You must explicitly use free() to release the space.
Syntax of free()
Free(ptr);
This statement frees the space allocated in the memory pointed by ptr.
Example 1: malloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) malloc(n * sizeof(int));
// if memory cannot be allocated
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i < n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
// deallocating the memory
Free(ptr);
Return 0;
}
Here, we have dynamically allocated the memory for n number of int.
Example 2: calloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) calloc(n, sizeof(int));
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i < n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
Free(ptr);
Return 0;
}
C realloc()
If the dynamically allocated memory is insufficient or more than required, you can change the size of previously allocated memory using the realloc() function.
Syntax of realloc()
Ptr = realloc(ptr, x);
Here, ptr is reallocated with a new size x.
Example 3: realloc()
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int *ptr, i , n1, n2;
Printf("Enter size: ");
Scanf("%d", &n1);
Ptr = (int*) malloc(n1 * sizeof(int));
Printf("Addresses of previously allocated memory: ");
For(i = 0; i < n1; ++i)
Printf("%u\n",ptr + i);
Printf("\nEnter the new size: ");
Scanf("%d", &n2);
// rellocating the memory
Ptr = realloc(ptr, n2 * sizeof(int));
Printf("Addresses of newly allocated memory: ");
For(i = 0; i < n2; ++i)
Printf("%u\n", ptr + i);
Free(ptr);
Return 0;
}
When you run the program, the output will be:
Enter size: 2
Addresses of previously allocated memory:26855472
26855476
Enter the new size: 4
Addresses of newly allocated memory:26855472
26855476
26855480
26855484
References:
- The C- Programming Language - By Brian W Kernighan and Dennis Ritchie
- C- Programming in an open source paradigm: By R.K. Kamat, K .S. Oza, S.R. Patil
- The GNU C Programming Tutorial -By Mark Burgess
- Let us C- By Yashwant Kanetkar
Unit - 1
Functions and Pointer
Similar to other languages, the C language also provides the facility of function. Function is the block of code which is used to perform a specific task. In c language the complete program is composed of functions.
Functions are useful to divide c programs into smaller modules. Programmer can invoked these modules anywhere inside c program for any number of times.
Functions are used to increase readability of the code. Size of program can be reduce by using functions. By using function, programmer can divide complex tasks into smaller manageable tasks and test them independently before using them together.
Functions of C language are defined with the type of function. The type of functions indicates the data type of value which will return by function. In order to use function in the program, initially programmer have to inform compiler about the function. This is also called as defining a function.
In C program all the function definition present outside the main function. All function need to be declared and defined before use. Function declaration requires function name, argument list, and return type.
Return TypeFunction name (Parameter list)
{
//body of function
Statement 1;
Statement 2;
…………...
Statement n;
}
In C programming, a function definition consists of a function header and a function body. All of the components of a function are listed here.
● Return Type − A function may return a value as its return type. The return type specifies the data type of the value returned by the function. Some functions do what they're supposed to do yet don't return a value. The keyword void is used as the return type in this scenario.
● Function Name - This is the function's real name. The function signature is made up of the function name and the argument list.
● Parameters − A parameter is similar to a placeholder. You pass a value to the parameter when you call a function. Actual parameter or argument refers to this value. The type, order, and number of parameters in a function are referred to as the parameter list. Parameters are optional; a function may or may not have them.
● Function Body − The function body is made up of a series of statements that specify what the function does.
Declaration
A function declaration tells the compiler the name of the function and how to invoke it. The function's actual body can be defined independently.
The following are the components of a function declaration:
Return_type function_name( parameter list );
The function declaration for the above-mentioned function max() is as follows:
Int max(int num1, int num2);
In a function declaration, the names of the parameters are not relevant; only their types are, hence the following is also a legal declaration:
Int max(int, int);
When a function is defined in one source file and called in another, a function declaration is necessary. In this situation, the function should be declared at the top of the file calling the function.
Prototype of function
One of the most essential characteristics of C programming, which evolved from C++, is the function prototype. A function prototype is a code declaration that tells the compiler about the function's data type, parameters, and parameter list. A function, as we all know, is a section of code that performs a specified task. A function prototype, on the other hand, is a function that tells the compiler the return type, function name, and parameter so that it can match the given function calls when they're needed.
Syntax
Return-type function-name ( datatype parameter1 , datatype parameter2 , datatype parameter3..);
Example:
Int addition(int a, int b);
In the preceding example, addition is the name of the function with an integer data type, and a and b are the arguments of two int arguments supplied to the function. Note that, depending on the necessity, we can pass as many parameters as we wish to our function. We can define as many prototypes as we wish in the same programme, but they must differ in either name or parameter list. All you have to do is create a prototype in the code and then use the function name to call it at any time.
Program for function prototype
#include <stdio.h>
Int Num_addition( int i , int j );// prototype for the function
Int main()
{
Int num1,num2,total;
Printf( " Please enters the 2 numbers you want to add : " ) ;
Scanf( "%d %d" , &num1 , &num2 ) ;
Total = Num_addition( num1 , num2 ) ; // calling the function
Printf( " The total of the given numbers is = %d " , total ) ;
Return 0 ;
}
Int Num_addition( int i , int j ) // function definition for prototype
{
Int results;
Results = i + j ;
Return results ;
}
Output
As you can see in the following code, we first declare the function prototype for the addition of two numbers with the name " Num addition " and an integer return type with two integer arguments named I and j. We defined three integers in the main class: num1, num2, and total. Following that, we collect user input before storing the total addition results of the two given values. The function " Num addition" is used once again to call it. Finally, you can see in the function declaration that we provide the logic to do addition and save the results.
Key takeaway
Functions are useful to divide c programs into smaller modules. Programmers can invoke these modules anywhere inside C program for any number of times.
A function prototype is a code declaration that tells the compiler about the function's data type, parameters, and parameter list.
Local variables
Local variables are variables that are declared within a function or block. They can only be utilised by statements that are included within that function or code block. Functions outside of their own are unaware of local variables. The following example demonstrates the use of local variables. The variables a, b, and c are all local to the function main().
#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;
}
Advantages of Local Variable
● Because a local variable's name is only recognised by the function in which it is declared, it can be used in several functions with the same name.
● Local variables only require memory for the duration of the function; after that, the same memory address can be reused.
Disadvantages of Local Variables
● The local variable's scope is restricted to its function and it cannot be used by other functions.
● The local variable is not allowed to share data.
Global Variables
Global variables are variables that are defined outside of a function, usually at the start of a programme. Global variables maintain their values throughout the life of your programme and can be accessed from any of the program's functions.
Any function has access to a global variable. That is, once a global variable is declared, it is available for use throughout your whole programme. The following programme demonstrates the use of global variables in a programme.
#include <stdio.h>
/* global variable declaration */
Int g;
Int main () {
/* local variable declaration */
int a, b;
/* actual initialization */
a = 10;
b = 20;
g = a + b;
printf ("value of a = %d, b = %d and g = %d\n", a, b, g);
return 0;
}
Local and global variables in a programme can have the same name, but the value of a local variable inside a function takes precedence. Here's an illustration:
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;
}
When the preceding code is compiled and run, the following result is obtained:
Value of g = 10
Advantages of Global Variable
● Global variables can be accessible by all of the program's functions.
● It is just necessary to make a single declaration.
● If all of the functions are accessing the same data, this is quite handy.
Disadvantages of Global Variable
● Because it can be utilised by any function in the programme, the value of a global variable can be modified by accident.
● If we employ a big number of global variables, there is a good possibility that the programme may generate errors.
Difference between Global variable and Local variable
Global Variable | Local Variable |
Outside of all the function blocks, global variables are declared. | Within a function block, local variables are declared. |
Throughout the programme, the scope is maintained. | The scope is restricted, and they can only be used in the function in which they are declared. |
Any modification to a global variable has an impact on the entire programme, regardless of where it is utilised. | Any changes to the local variable have no effect on the program's other functions.
|
A global variable is present in the programme for the duration of its execution. | After the function is executed, a local variable is created, and when the function is finished, the variable is destroyed. |
It can be accessed from anywhere in the programme using any of the program's functionalities. | It is only accessible through the function statements in which it is declared, not through other functions. |
If a global variable isn't initialised, it defaults to zero. | If a local variable isn't initialised, it defaults to a garbage value. |
The data segment of memory stores global variables. | Local variables are kept in memory on a stack. |
We can't use the same name for several variables. | Variables having the same name can be declared in several functions. |
Key takeaway
Local variables are variables that are declared within a function or block.
Global variables are variables that are defined outside of a function, usually at the start of a programme.
User defined function is the block of code written by programmer to perform a particular task. As compiler doesn’t have any idea about the user define function so programmer has to define and declare these functions inside the program body. Programmer can define these function outside the main function but declaration of user defined function should present in main function only. Whenever compiler executes function call (function declaration) then compiler shift the flow of program execution to the definition part of user define function.
Example
#include <stdio.h>
#include<conio.h>
Int add (int x, int y)
{
Int sum;
Sum = x + y;
Return (sum);
}
Main ()
{
Int a,b,c;
a = 15;
b = 25;
c = add(a,b);
Printf ("\n Addition is %d ", c);
}
Output:
Addition is 40
Key takeaway
User defined function is the block of code written by programmer to perform a particular task.
Programmer can define these function outside the main function but declaration of user defined function should present in main function only.
Recursion
In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.
Void recursion() {
Recursion(); /* function calls itself */
}
Int main() {
Recursion();
}
The C programming language supports recursion, i.e., a function to call itself. But while using recursion, programmers has to be careful to define an exit condition from the function, otherwise it will go into an infinite loop.
Recursive functions are useful to solve many mathematical problems, such as calculating the factorial of a number, generating Fibonacci series, etc.
The following example calculates the factorial of a given number using a recursive function −
#include <stdio.h>
Unsigned long long int factorial(unsigned int i) {
If(i <= 1) {
Return 1;
}
Return i * factorial(i - 1);
}
Int main() {
Int i = 12;
Printf("Factorial of %d is %d\n", i, factorial(i));
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Factorial of 12 is 479001600
The following example generates the Fibonacci series for a given number using a recursive function −
#include <stdio.h>
Int fibonacci(int i) {
If(i == 0) {
Return 0;
}
If(i == 1) {
Return 1;
}
Return fibonacci(i-1) + fibonacci(i-2);
}
Int main() {
Int i;
For (i = 0; i < 10; i++) {
Printf("%d\t\n", fibonacci(i));
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
0
1
1
2
3
5
8
13
21
34
Storage classes
Within a C programme, a storage class defines the scope (visibility) and lifetime of variables and/or functions. They come before the type they modify. In a C programme, there are four different storage classes:
● auto
● register
● static
● extern
Auto
At runtime, memory is automatically allocated to automated variables.
The automated variables' visibility is confined to the block in which they are defined. The automated variables' scope is constrained to the block in which they are defined. By default, the automated variables are set to garbage.
When you depart the block, the memory allotted to automatic variables is released. The auto keyword is used to define automatic variables.
By default, every local variable in C is automatic.
For all local variables, the auto storage class is the default storage class.
{
int mount;
auto int month;
}
The preceding example declares two variables in the same storage class. The keyword 'auto' can only be used within functions, i.e. within local variables.
Example:
#include <stdio.h>
Int main()
{
Int a; //auto
Char b;
Float c;
Printf("%d %c %f",a,b,c); // printing initial default value of automatic variables a, b, and c.
Return 0;
}
Output:
Garbage garbage garbage
Register
The memory is allocated to the CPU registers by the variables declared as the registers, depending on the size of the memory remaining in the CPU.
We can't dereference the register variables, which means we can't use & operator for them. The register variables have a faster access time than the automatic variables. The register local variables have a default value of 0.
The variable that should be saved in the CPU register is denoted by the register keyword. Is it, nevertheless, a compiler? The variables can be stored in the register at the user's discretion. We can store pointers in registers, which means that a register can hold the address of a variable. Because we can't use more than one storage specifier for the same variable, static variables can't be stored in the register.
{
register int miles;
}
Example:
#include <stdio.h>
Int main()
{
Register int a; // variable a is allocated memory in the CPU register. The initial default value of a is 0.
Printf("%d",a);
}
Output:
0
Static
The static storage class tells the compiler to keep a local variable alive for the duration of the programme, rather than creating and destroying it every time it enters and exits scope. As a result, making local variables static ensures that their values are preserved between function calls.
The static modifier can be used on global variables as well. When you do this, the scope of that variable is limited to the file in which it is declared.
When the keyword static is applied on a global variable in C programming, just one copy of that member is shared by all objects in that class.
#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 */
i++;
printf("i is %d and count is %d\n", i, count);
}
When the above code is compiled and executed, it produces the following result −
i is 6 and count is 4
i is 7 and count is 3
i is 8 and count is 2
i is 9 and count is 1
i is 10 and count is 0
Extern
The extern storage class is used to provide a reference to a global variable that is shared by all application files. The variable cannot be initialised when you use 'extern,' but it does direct the variable name to a previously established storage location.
When you have many files and specify a global variable or function that will be utilised in other files, extern is used in another file to provide a reference to the defined variable or function. To clarify, extern is a keyword that is used to declare a global variable or function in a different file.
Example:
#include <stdio.h>
Int main()
{
Extern int a;
Printf("%d",a);
}
Output
Main.c:(.text+0x6): undefined reference to a'
Collect2: error: ld returned 1 exit status
Key takeaway
In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.
Within a C programme, a storage class defines the scope (visibility) and lifetime of variables and/or functions. They come before the type they modify. In a C programme, there are four different storage classes.
Pointers in C language is a variable that stores/points the address of another variable. A Pointer in C is used to allocate memory dynamically i.e. at run time. The pointer variable might belong to any of the data type such as int, float, char, double, short etc.
Pointer Syntax: data_type *var_name; Example : int *p; char *p;
Where, * is used to denote that “p” is pointer variable and not a normal variable.
Normal variable stores the value whereas pointer variable stores the address of the variable.
The content of the C pointer always be a whole number i.e. address.
Always C pointer is initialized to null, i.e. int *p = null.
The value of null pointer is 0.
& symbol is used to get the address of the variable.
* symbol is used to get the value of the variable that the pointer is pointing to.
If a pointer in C is assigned to NULL, it means it is pointing to nothing.
Two pointers can be subtracted to know how many elements are available between these two pointers.
But, Pointer addition, multiplication, division are not allowed.
The size of any pointer is 2 byte (for 16 bit compiler).
Example:
#include <stdio.h>
Int main()
{
Int *ptr, q;
q = 50;
/* address of q is assigned to ptr */
Ptr = &q;
/* display q's value using ptr variable */
Printf("%d", *ptr);
Return 0;
}
Output:
1
2
3
4
5
6
7
8
9
10
11
Declaration
Pointers are declare with the help of operator ‘*’. ‘*’ is known as ‘value at address’. Pointers are the variables which are used to store the address of another variable As the address of variable is always whole numbers so pointer always contains whole numbers. The declaration of pointer are as follows.
Syntax: Data type * pointer Name.
Example: int *I;
Data type defines the type of value defined at the address of pointer variable. In the above example value at the address of ‘I’ is of type integer.
Consider the following program.
# include<stdio.h>
# include<conio.h>
Void main()
{
Int a,b,c;
Int *p,*q,*r;
p=&a;
q=&b;
r=&c;
Printf(“Enter two numbers”);
Scanf(“%d%d,&a,&b);
c=a + b;
Printf(“\n Address of variable C is %d”,&C);
Printf(“\n Address of variable C is %d,r);
Printf(“\n Address of variable r is %d”,&r);
Printf(“\n value of variable C is %d”,C);
Printf(“\n value of variable C is %d,*^);
Getch ();
}
In the above program variable ‘r’ is the integer pointer which holds the address of variable ‘C’
Case 1: In ‘printf’ statement whenever we used (“%d”,r) men me value of r is printed but ‘r’ is holding the address of variable ‘C’. So, address of variable C is copied to the value of ‘r’ and it is printed on output screen
Case 2: Whenever we used (“%d”,&r) in ‘printf’ function men the address of variable ‘r’ is pointed on o/p screen.
Case 3: When we used (“%d”,*r) in pointf function at mat time value which is stored at the address which holds by variable ‘r’ is printed.
Now me variable ‘r’ is holding the address of variable ‘C’. So, the value which is stored at the address of ‘C’ is printed on the output screen.
Consider the following example.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a=3;
Int *p;
p=&a;
Printf(“\n%d”,a);
Printf(“\n%d”,&a);
Printf(“\n%d”,P);
Printf(“\n%d”,&P);
Printf(“\n%d”,*P);
Printf(“\n%d”,*(&a));
}
Run the above program on the computer system so that you will familiar with the basic use of pointers. Following is the explanation O/p of above program.
● The first ‘printf’ statement prints the value of ‘C’ ie. 3
● The second ‘printf’ statement prints the address of ‘a’
● The third ‘printf’ statement prints me value of ‘p’ ie. The address of ‘a’
● The forth ‘printf’ statement prints the address of ‘p’
● The fifth ‘printf’ statement prints the value which is stored at the address holds in ‘p’ ie. 3
● The sixth ‘printf’ statement prints the value which is stored at the address of ‘a’ ie. 3
Data type of pointer variable can be anything. Such as char *C;
In the above instruction pointer ‘C’ is of type character so the variable ‘C’ can store the address of variable which contains character type of value. Consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int I,*ip;
Char C, *cp;
I = 3;
Ip = & I;
c=’M’;
Cp=&c;
Printf(“%d”,I);
Printf(“\n%d”,*ip);
Printf(“\n%C;,C);
Printf(“\n%c”, *cp);
Getch();
}
The output of above program is.
3
3
m
m
Defining pointers
One of the vital and heavily used features of ‘C’ is pointer. Most of the other programming languages also support pointers but only few of them use it freely. Support pointers but only few of them use it freely.
When we declare any variable in C language, there are three things associated with that variable.
- Data type of variable: Data type defines the type of data that variable can hold. Data type tells the compiler about the amount of memory allocated to the variable.
- Address of Variable: Address of variable represents the exact address of memory location which is allocated to variable.
- Value of variable: It is the value of variable which is stored at the address of memory location allocated to variable.
Example: int n = 5;
In the above example ‘int’ is the data type which tells the compiler to allocate 2 bytes of memory to variable ‘n’.
Once the variable is declared the compiler allocated two bytes of memory to variable ‘n’. Suppose the address of that memory location is 1020. At the address of memory location 1020 the value 5 is stored.
Memory map for the above declaration is as follows.
Use of &,/and ‘*’ operator
Consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a,b,c;
Printf(“Enter two numbers”);
Scanf(“%d%d”, &a,&b);
c = a+b;
Printf(“/n Addition is %d”, c);
Printf(“/n Addition of variable is %d”, &c);
Getch();
}
Above program is the program for addition of two numbers in ‘C’ language. In the seventh instruction of the above program we used operator ‘%’ and ‘&’ ‘%d’ is the access specifier which tells the compiler to take integer value as an input whereas. ‘&a’ tells the compiler to store the taken value at the address of variable ‘a’.
In the ninth instruction compiler will print me the value of ‘C’ so the output of the 9th instruction is as follows.
Addition is 5[Note: considering a = 2 and b = 3]
In the tenth instruction compiler will print me the address of variable C.
So the output of length instruction is as follows. Address of variable C is 1020.
Now consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a,b,c;
Printf(“Enter two numbers”);
Scanf(“%d%d”, &a,&b);
c = a+b;
Printf(“/n Addition is %d”, c);
Printf(“/n Addition of variable is %d”, &c);
Printf(“/n value of variable c is %d”, *(&c));
Getch();
}
Now, we all are clear about the output of instruction 9 and 10.
In the 11th instruction, operator *and & is used. ‘*’ operator tells compiler to pick up the value which is stored at the address of variable C. So the output of the 11th instruction is as follows. Value of variable C is 5 [considering a = 24 b = 3;]
Key takeaway:
One of the vital and heavily used features of ‘C’ is pointer.
Most of the other programming languages also support pointers but only few of them use it freely.
The process of assigning a variable's address to a pointer variable is known as pointer initialization. The address of a variable of the same data type can only be stored in a pointer variable. The address operator & is used to determine the address of a variable in the C programming language. The & (directly preceding a variable name) yields the variable's address.
#include<stdio.h>
Void main()
{
int a = 10;
int *ptr; //pointer declaration
ptr = &a; //pointer initialization
}
Variables of the same datatype are always pointed to by pointer variables. Let's look at an example to demonstrate this:
#include<stdio.h>
Void main()
{
float a;
int *ptr;
ptr = &a; // ERROR, type mismatch
}
If you're not sure which variable's address to assign to a pointer variable during declaration, it's best to leave it blank. A NULL pointer is a pointer that has been allocated the value NULL.
#include <stdio.h>
Int main()
{
int *ptr = NULL;
return 0;
}
Key takeaway
The process of assigning a variable's address to a pointer variable is known as pointer initialization. The address of a variable of the same data type can only be stored in a pointer variable.
Pointer arithmetic is slightly different from arithmetic we normally use in our daily life. The only valid arithmetic operations applicable on pointers are:
- Addition of integer to a pointer
- Subtraction of integer to a pointer
- Subtracting two pointers of the same type
The pointer arithmetic is performed relative to the base type of the pointer. For example, if we have an integer pointer ip which contains address 1000, then on incrementing it by 1, we will get 1004 (i.e 1000 + 1 * 4) instead of 1001 because the size of the int data type is 4 bytes. If we had been using a system where the size of int is 2 bytes then we would get 1002 ( i.e 1000 + 1 * 2 ).
Similarly, on decrementing it we will get 996 (i.e 1000 - 1 * 4) instead of 999.
So, the expression ip + 4 will point to the address 1016 (i.e 1000 + 4 * 4).
Let's take some more examples.
1
2
3
Int i = 12, *ip = &i;
Double d = 2.3, *dp = &d;
Char ch = 'a', *cp = &ch;
Suppose the address of i, d and ch are 1000, 2000, 3000 respectively, therefore ip, dp and cp are at 1000, 2000, 3000 initially.
Key takeaway
Pointer arithmetic is slightly different from arithmetic we normally use in our daily life.
The pointer arithmetic is performed relative to the base type of the pointer.
Consider the following example, which utilises an array of three integers to explain the notion of arrays of pointers.
#include <stdio.h>
const int MAX = 3;
Int main () {
int var[] = {10, 100, 200};
int i;
for (i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, var[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
There may be times when we need to keep an array that can store pointers to ints, chars, or any other possible data type. The declaration of an array of pointers to an integer is as follows:
Int *ptr[MAX];
It declares ptr as a MAX integer pointer array. As a result, each ptr element contains a pointer to an int value. The example below uses three integers that are stored in an array of pointers like follows:
#include <stdio.h>
Const int MAX = 3;
Int main () {
int var[] = {10, 100, 200};
int i, *ptr[MAX];
for ( i = 0; i < MAX; i++) {
ptr[i] = &var[i]; /* assign the address of integer. */
}
for ( i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, *ptr[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
You can also store a list of strings in an array of character pointers, as shown below:
#include <stdio.h>
Const int MAX = 4;
Int main () {
char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
int i = 0;
for ( i = 0; i < MAX; i++) {
printf("Value of names[%d] = %s\n", i, names[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali
Pointers and one-dimensional array
● For every of the array's items, the compiler allocates Continuous memory addresses.
● The array's base address is equal to the array's first element address (index 0).
● For instance, int a [5] = 10, 20, 30, 40, 50;
Elements
The five items are saved in the following order:
If 'p' is declared as an integer pointer, the following assignment can be used to point to an array 'a'.
p = a;
(or) p = &a[0];
Using p++ to travel from one element to another, every value of 'a' is accessed. When a pointer is incremented, the size of the datatype it points to is multiplied by its value. The "scale factor" is the name given to this length.
Below is an explanation of the link between 'p' and 'a.'
P = &a[0] = 1000
P+1 = &a[1] = 1004
P+2 = &a[2] = 1008
P+3 = &a[3] = 1012
P+4 = &a[4] = 1016
The address of an element is determined by its index and the datatype's scale factor. Here's an example to help you understand.
Address of a[3] = base address + (3* scale factor of int)
= 1000 + (3*4)
= 1000 +12
= 1012
Instead of utilising array indexing, pointers can be used to access array entries.
The value of a[3] is given by *(p+3).
a[i] = *(p+i)
Example
The C programme for pointers and one-dimensional arrays is shown below.
#include<stdio.h>
Main ( ){
int a[5];
int *p,i;
printf ("Enter 5 elements");
for (i=0; i<5; i++)
scanf ("%d", &a[i]);
p = &a[0];
printf ("Elements of the array are");
for (i=0; i<5; i++)
printf("%d", *(p+i));
}
Output
When the aforementioned programme is run, the following result is obtained:
Enter 5 elements: 10 20 30 40 50
Elements of the array are: 10 20 30 40 50
Pointers and two dimensional arrays
The following is the memory allocation for a two-dimensional array:
Int a[3] [3] = {1,2,3,4,5,6,7,8,9};
a[1] [2] = *(1234 + 1*3+2)
= *(1234 + 3+2)
= *(1234 + 5*4) // 4 is Scale factor
= * (1234+20)
= *(1254)
a[1] [2] = 6
Example
The C programme for pointers and two-dimensional arrays is shown below.
#include<stdio.h>
Main ( ){
int a[3] [3], i,j;
int *p;
clrscr ( );
printf ("Enter elements of 2D array");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
scanf ("%d", &a[i] [j]);
}
}
p = &a[0] [0];
printf ("elements of 2d array are");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
printf ("%d \t", *(p+i*3+j));
}
printf ("\n");
}
getch ( );
}
Output
When the aforementioned programme is run, the following result is obtained:
Enter elements of 2D array
1 2 3 4 5 6 7 8 9
Elements of 2D array are
1 2 3
4 5 6
7 8 9
Parameter Passing by Value
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called call by value. In case of parameter passing by value, the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function.
This mechanism is used when programmer don't want to change the value of passed parameters. When parameters are passed by value then functions in C create copies of the passed in variables and do required processing on these copied variables.
Pass-by-value is implemented by actual data transfer so additional storage is required to maintain the copies of passed parameters.
Example:
#include <stdio.h>
#include<conio.h>
/* function declaration goes here.*/
Void swap( int p1, int p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( a, b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
Getch();
}
Void swap( int p1, int p2 )
{
Int t;
t = p2;
p2 = p1;
p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", p1, p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b (p2) = 10
After: Value of a = 10 and value of b = 20
Note: In the above example the values of “a” and “b” remain unchanged before calling swap function and after calling swap function.
Parameter Passing by Reference
This mechanism is used when programmers want a function to do the changes in passed parameters and reflect those changes back to the calling function. This mechanism is also called as call by reference. This is achieved by passing the address of variable to the function and function body can directly work over the addresses. Advantage of pass by reference is efficiency in both time and space. Whereas disadvantages are access to formal parameters is slow and inadvertent and erroneous changes may be made to the actual parameter.
Example:
#include <stdio.h>
#include<conio.h>
Void swap( int *p1, int *p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( &a, &b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
}
Void swap( int *p1, int *p2 )
{
Int t;
t = *p2;
*p2 = *p1;
*p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", *p1, *p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b(p2) = 10
After: Value of a = 20 and value of b = 10
Note: In the above example the values of “a” and “b” are changes after calling swap function.
Call by reference
Array is a data structure which stores the collection of similar types of element in consecutive memory locations. Indexing of array always start with ‘0’ where as non-graphical variable ‘\0’ indicates the end of array. Syntax for declaring array is
Data typearray name[Maximum size];
● Data types are used to define type of element in an array. Data types are also useful in finding the size of total memory locations allocated for the array.
● All the rules of defining name of variable are also applicable for the array name.
● Maximum size indicates the total number of maximum elements that array can hold.
● Total memory allocated for the array is equal to the memory required to store one element of the array multiply by the total element in the array.
● In array, memory allocation is done at the time of declaration of an array.
Example:
Sr. No. | Instructions | Description |
1. | #include<stdio.h> | Header file included |
2. | #include<conio.h> | Header file included |
3. | Void main() | Execution of program begins |
4. | { |
|
5. | Int i,n,a[10]; | Memory is allocated for variable i,n and array a |
6. | Clrscr(); | Clear the output of previous screen |
7. | Printf("enter a number"); | Print “enter a number” |
8. | Scanf("%d",&n); | Input value is stored at the addres of variable n |
9. | For(i=0;i<=10;i++) | For loop started from value of i=0 to i=10 |
10. | { | Compound statement(scope of for loop starts) |
11. | a[i]=n*i; | Result of multiplication of n and I is stored at the ith location of array ieas i=0 so it is stores at first location. |
12. | Printf("\n %d",a[i]); | Value of ith location of the array is printed |
13. | } | Compound statement(scope of for loop ends) |
14. | Printf("\n first element in array is %d",a[0]); | Value of first element of the array is printed |
15. | Printf("\n fifth element in array is %d",a[4]); | Value of fifth element of the array is printed |
16. | Printf("\n tenth element in array is %d",a[9]); | Value of tenth element of the array is printed |
17. | Getch(); | Used to hold the output screen |
18. | } | Indicates end of scope of main function |
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called as call by value. In case of parameter passing by value, the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function.
This mechanism is used when programmer don't want to change the value of passed parameters. When parameters are passed by value then functions in C create copies of the passed in variables and do required processing on these copied variables.
Pass-by-value is implemented by actual data transfer so additional storage is required to maintain the copies of passed parameters.
Example:
#include <stdio.h>
#include<conio.h>
/* function declaration goes here.*/
Void swap( int p1, int p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( a, b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
Getch();
}
Void swap( int p1, int p2 )
{
Int t;
t = p2;
p2 = p1;
p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", p1, p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b (p2) = 10
After: Value of a = 10 and value of b = 20
Note: In the above example the values of “a” and “b” remain unchanged before calling swap function and after calling swap function.
Key takeaway
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called call by value.
C malloc()
The name "malloc" stands for memory allocation.
The malloc() function reserves a block of memory of the specified number of bytes. And, it returns a pointer of void which can be casted into pointers of any form.
Syntax of malloc()
Ptr = (castType*) malloc(size);
Example
Ptr = (float*) malloc(100 * sizeof(float));
The above statement allocates 400 bytes of memory. It's because the size of float is 4 bytes. And, the pointer ptr holds the address of the first byte in the allocated memory.
The expression results in a NULL pointer if the memory cannot be allocated.
C calloc()
The name "calloc" stands for contiguous allocation.
The malloc() function allocates memory and leaves the memory uninitialized. Whereas, the calloc() function allocates memory and initializes all bits to zero.
Syntax of calloc()
Ptr = (castType*)calloc(n, size);
Example:
Ptr = (float*) calloc(25, sizeof(float));
The above statement allocates contiguous space in memory for 25 elements of type float.
C free()
Dynamically allocated memory created with either calloc() or malloc() doesn't get freed on their own. You must explicitly use free() to release the space.
Syntax of free()
Free(ptr);
This statement frees the space allocated in the memory pointed by ptr.
Example 1: malloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) malloc(n * sizeof(int));
// if memory cannot be allocated
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i < n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
// deallocating the memory
Free(ptr);
Return 0;
}
Here, we have dynamically allocated the memory for n number of int.
Example 2: calloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) calloc(n, sizeof(int));
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i < n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
Free(ptr);
Return 0;
}
C realloc()
If the dynamically allocated memory is insufficient or more than required, you can change the size of previously allocated memory using the realloc() function.
Syntax of realloc()
Ptr = realloc(ptr, x);
Here, ptr is reallocated with a new size x.
Example 3: realloc()
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int *ptr, i , n1, n2;
Printf("Enter size: ");
Scanf("%d", &n1);
Ptr = (int*) malloc(n1 * sizeof(int));
Printf("Addresses of previously allocated memory: ");
For(i = 0; i < n1; ++i)
Printf("%u\n",ptr + i);
Printf("\nEnter the new size: ");
Scanf("%d", &n2);
// rellocating the memory
Ptr = realloc(ptr, n2 * sizeof(int));
Printf("Addresses of newly allocated memory: ");
For(i = 0; i < n2; ++i)
Printf("%u\n", ptr + i);
Free(ptr);
Return 0;
}
When you run the program, the output will be:
Enter size: 2
Addresses of previously allocated memory:26855472
26855476
Enter the new size: 4
Addresses of newly allocated memory:26855472
26855476
26855480
26855484
References:
- The C- Programming Language - By Brian W Kernighan and Dennis Ritchie
- C- Programming in an open source paradigm: By R.K. Kamat, K .S. Oza, S.R. Patil
- The GNU C Programming Tutorial -By Mark Burgess
- Let us C- By Yashwant Kanetkar
Unit - 1
Functions and Pointer
Similar to other languages, the C language also provides the facility of function. Function is the block of code which is used to perform a specific task. In c language the complete program is composed of functions.
Functions are useful to divide c programs into smaller modules. Programmer can invoked these modules anywhere inside c program for any number of times.
Functions are used to increase readability of the code. Size of program can be reduce by using functions. By using function, programmer can divide complex tasks into smaller manageable tasks and test them independently before using them together.
Functions of C language are defined with the type of function. The type of functions indicates the data type of value which will return by function. In order to use function in the program, initially programmer have to inform compiler about the function. This is also called as defining a function.
In C program all the function definition present outside the main function. All function need to be declared and defined before use. Function declaration requires function name, argument list, and return type.
Return TypeFunction name (Parameter list)
{
//body of function
Statement 1;
Statement 2;
…………...
Statement n;
}
In C programming, a function definition consists of a function header and a function body. All of the components of a function are listed here.
● Return Type − A function may return a value as its return type. The return type specifies the data type of the value returned by the function. Some functions do what they're supposed to do yet don't return a value. The keyword void is used as the return type in this scenario.
● Function Name - This is the function's real name. The function signature is made up of the function name and the argument list.
● Parameters − A parameter is similar to a placeholder. You pass a value to the parameter when you call a function. Actual parameter or argument refers to this value. The type, order, and number of parameters in a function are referred to as the parameter list. Parameters are optional; a function may or may not have them.
● Function Body − The function body is made up of a series of statements that specify what the function does.
Declaration
A function declaration tells the compiler the name of the function and how to invoke it. The function's actual body can be defined independently.
The following are the components of a function declaration:
Return_type function_name( parameter list );
The function declaration for the above-mentioned function max() is as follows:
Int max(int num1, int num2);
In a function declaration, the names of the parameters are not relevant; only their types are, hence the following is also a legal declaration:
Int max(int, int);
When a function is defined in one source file and called in another, a function declaration is necessary. In this situation, the function should be declared at the top of the file calling the function.
Prototype of function
One of the most essential characteristics of C programming, which evolved from C++, is the function prototype. A function prototype is a code declaration that tells the compiler about the function's data type, parameters, and parameter list. A function, as we all know, is a section of code that performs a specified task. A function prototype, on the other hand, is a function that tells the compiler the return type, function name, and parameter so that it can match the given function calls when they're needed.
Syntax
Return-type function-name ( datatype parameter1 , datatype parameter2 , datatype parameter3..);
Example:
Int addition(int a, int b);
In the preceding example, addition is the name of the function with an integer data type, and a and b are the arguments of two int arguments supplied to the function. Note that, depending on the necessity, we can pass as many parameters as we wish to our function. We can define as many prototypes as we wish in the same programme, but they must differ in either name or parameter list. All you have to do is create a prototype in the code and then use the function name to call it at any time.
Program for function prototype
#include <stdio.h>
Int Num_addition( int i , int j );// prototype for the function
Int main()
{
Int num1,num2,total;
Printf( " Please enters the 2 numbers you want to add : " ) ;
Scanf( "%d %d" , &num1 , &num2 ) ;
Total = Num_addition( num1 , num2 ) ; // calling the function
Printf( " The total of the given numbers is = %d " , total ) ;
Return 0 ;
}
Int Num_addition( int i , int j ) // function definition for prototype
{
Int results;
Results = i + j ;
Return results ;
}
Output
As you can see in the following code, we first declare the function prototype for the addition of two numbers with the name " Num addition " and an integer return type with two integer arguments named I and j. We defined three integers in the main class: num1, num2, and total. Following that, we collect user input before storing the total addition results of the two given values. The function " Num addition" is used once again to call it. Finally, you can see in the function declaration that we provide the logic to do addition and save the results.
Key takeaway
Functions are useful to divide c programs into smaller modules. Programmers can invoke these modules anywhere inside C program for any number of times.
A function prototype is a code declaration that tells the compiler about the function's data type, parameters, and parameter list.
Local variables
Local variables are variables that are declared within a function or block. They can only be utilised by statements that are included within that function or code block. Functions outside of their own are unaware of local variables. The following example demonstrates the use of local variables. The variables a, b, and c are all local to the function main().
#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;
}
Advantages of Local Variable
● Because a local variable's name is only recognised by the function in which it is declared, it can be used in several functions with the same name.
● Local variables only require memory for the duration of the function; after that, the same memory address can be reused.
Disadvantages of Local Variables
● The local variable's scope is restricted to its function and it cannot be used by other functions.
● The local variable is not allowed to share data.
Global Variables
Global variables are variables that are defined outside of a function, usually at the start of a programme. Global variables maintain their values throughout the life of your programme and can be accessed from any of the program's functions.
Any function has access to a global variable. That is, once a global variable is declared, it is available for use throughout your whole programme. The following programme demonstrates the use of global variables in a programme.
#include <stdio.h>
/* global variable declaration */
Int g;
Int main () {
/* local variable declaration */
int a, b;
/* actual initialization */
a = 10;
b = 20;
g = a + b;
printf ("value of a = %d, b = %d and g = %d\n", a, b, g);
return 0;
}
Local and global variables in a programme can have the same name, but the value of a local variable inside a function takes precedence. Here's an illustration:
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;
}
When the preceding code is compiled and run, the following result is obtained:
Value of g = 10
Advantages of Global Variable
● Global variables can be accessible by all of the program's functions.
● It is just necessary to make a single declaration.
● If all of the functions are accessing the same data, this is quite handy.
Disadvantages of Global Variable
● Because it can be utilised by any function in the programme, the value of a global variable can be modified by accident.
● If we employ a big number of global variables, there is a good possibility that the programme may generate errors.
Difference between Global variable and Local variable
Global Variable | Local Variable |
Outside of all the function blocks, global variables are declared. | Within a function block, local variables are declared. |
Throughout the programme, the scope is maintained. | The scope is restricted, and they can only be used in the function in which they are declared. |
Any modification to a global variable has an impact on the entire programme, regardless of where it is utilised. | Any changes to the local variable have no effect on the program's other functions.
|
A global variable is present in the programme for the duration of its execution. | After the function is executed, a local variable is created, and when the function is finished, the variable is destroyed. |
It can be accessed from anywhere in the programme using any of the program's functionalities. | It is only accessible through the function statements in which it is declared, not through other functions. |
If a global variable isn't initialised, it defaults to zero. | If a local variable isn't initialised, it defaults to a garbage value. |
The data segment of memory stores global variables. | Local variables are kept in memory on a stack. |
We can't use the same name for several variables. | Variables having the same name can be declared in several functions. |
Key takeaway
Local variables are variables that are declared within a function or block.
Global variables are variables that are defined outside of a function, usually at the start of a programme.
User defined function is the block of code written by programmer to perform a particular task. As compiler doesn’t have any idea about the user define function so programmer has to define and declare these functions inside the program body. Programmer can define these function outside the main function but declaration of user defined function should present in main function only. Whenever compiler executes function call (function declaration) then compiler shift the flow of program execution to the definition part of user define function.
Example
#include <stdio.h>
#include<conio.h>
Int add (int x, int y)
{
Int sum;
Sum = x + y;
Return (sum);
}
Main ()
{
Int a,b,c;
a = 15;
b = 25;
c = add(a,b);
Printf ("\n Addition is %d ", c);
}
Output:
Addition is 40
Key takeaway
User defined function is the block of code written by programmer to perform a particular task.
Programmer can define these function outside the main function but declaration of user defined function should present in main function only.
Recursion
In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.
Void recursion() {
Recursion(); /* function calls itself */
}
Int main() {
Recursion();
}
The C programming language supports recursion, i.e., a function to call itself. But while using recursion, programmers has to be careful to define an exit condition from the function, otherwise it will go into an infinite loop.
Recursive functions are useful to solve many mathematical problems, such as calculating the factorial of a number, generating Fibonacci series, etc.
The following example calculates the factorial of a given number using a recursive function −
#include <stdio.h>
Unsigned long long int factorial(unsigned int i) {
If(i <= 1) {
Return 1;
}
Return i * factorial(i - 1);
}
Int main() {
Int i = 12;
Printf("Factorial of %d is %d\n", i, factorial(i));
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Factorial of 12 is 479001600
The following example generates the Fibonacci series for a given number using a recursive function −
#include <stdio.h>
Int fibonacci(int i) {
If(i == 0) {
Return 0;
}
If(i == 1) {
Return 1;
}
Return fibonacci(i-1) + fibonacci(i-2);
}
Int main() {
Int i;
For (i = 0; i < 10; i++) {
Printf("%d\t\n", fibonacci(i));
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
0
1
1
2
3
5
8
13
21
34
Storage classes
Within a C programme, a storage class defines the scope (visibility) and lifetime of variables and/or functions. They come before the type they modify. In a C programme, there are four different storage classes:
● auto
● register
● static
● extern
Auto
At runtime, memory is automatically allocated to automated variables.
The automated variables' visibility is confined to the block in which they are defined. The automated variables' scope is constrained to the block in which they are defined. By default, the automated variables are set to garbage.
When you depart the block, the memory allotted to automatic variables is released. The auto keyword is used to define automatic variables.
By default, every local variable in C is automatic.
For all local variables, the auto storage class is the default storage class.
{
int mount;
auto int month;
}
The preceding example declares two variables in the same storage class. The keyword 'auto' can only be used within functions, i.e. within local variables.
Example:
#include <stdio.h>
Int main()
{
Int a; //auto
Char b;
Float c;
Printf("%d %c %f",a,b,c); // printing initial default value of automatic variables a, b, and c.
Return 0;
}
Output:
Garbage garbage garbage
Register
The memory is allocated to the CPU registers by the variables declared as the registers, depending on the size of the memory remaining in the CPU.
We can't dereference the register variables, which means we can't use & operator for them. The register variables have a faster access time than the automatic variables. The register local variables have a default value of 0.
The variable that should be saved in the CPU register is denoted by the register keyword. Is it, nevertheless, a compiler? The variables can be stored in the register at the user's discretion. We can store pointers in registers, which means that a register can hold the address of a variable. Because we can't use more than one storage specifier for the same variable, static variables can't be stored in the register.
{
register int miles;
}
Example:
#include <stdio.h>
Int main()
{
Register int a; // variable a is allocated memory in the CPU register. The initial default value of a is 0.
Printf("%d",a);
}
Output:
0
Static
The static storage class tells the compiler to keep a local variable alive for the duration of the programme, rather than creating and destroying it every time it enters and exits scope. As a result, making local variables static ensures that their values are preserved between function calls.
The static modifier can be used on global variables as well. When you do this, the scope of that variable is limited to the file in which it is declared.
When the keyword static is applied on a global variable in C programming, just one copy of that member is shared by all objects in that class.
#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 */
i++;
printf("i is %d and count is %d\n", i, count);
}
When the above code is compiled and executed, it produces the following result −
i is 6 and count is 4
i is 7 and count is 3
i is 8 and count is 2
i is 9 and count is 1
i is 10 and count is 0
Extern
The extern storage class is used to provide a reference to a global variable that is shared by all application files. The variable cannot be initialised when you use 'extern,' but it does direct the variable name to a previously established storage location.
When you have many files and specify a global variable or function that will be utilised in other files, extern is used in another file to provide a reference to the defined variable or function. To clarify, extern is a keyword that is used to declare a global variable or function in a different file.
Example:
#include <stdio.h>
Int main()
{
Extern int a;
Printf("%d",a);
}
Output
Main.c:(.text+0x6): undefined reference to a'
Collect2: error: ld returned 1 exit status
Key takeaway
In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.
Within a C programme, a storage class defines the scope (visibility) and lifetime of variables and/or functions. They come before the type they modify. In a C programme, there are four different storage classes.
Pointers in C language is a variable that stores/points the address of another variable. A Pointer in C is used to allocate memory dynamically i.e. at run time. The pointer variable might belong to any of the data type such as int, float, char, double, short etc.
Pointer Syntax: data_type *var_name; Example : int *p; char *p;
Where, * is used to denote that “p” is pointer variable and not a normal variable.
Normal variable stores the value whereas pointer variable stores the address of the variable.
The content of the C pointer always be a whole number i.e. address.
Always C pointer is initialized to null, i.e. int *p = null.
The value of null pointer is 0.
& symbol is used to get the address of the variable.
* symbol is used to get the value of the variable that the pointer is pointing to.
If a pointer in C is assigned to NULL, it means it is pointing to nothing.
Two pointers can be subtracted to know how many elements are available between these two pointers.
But, Pointer addition, multiplication, division are not allowed.
The size of any pointer is 2 byte (for 16 bit compiler).
Example:
#include <stdio.h>
Int main()
{
Int *ptr, q;
q = 50;
/* address of q is assigned to ptr */
Ptr = &q;
/* display q's value using ptr variable */
Printf("%d", *ptr);
Return 0;
}
Output:
1
2
3
4
5
6
7
8
9
10
11
Declaration
Pointers are declare with the help of operator ‘*’. ‘*’ is known as ‘value at address’. Pointers are the variables which are used to store the address of another variable As the address of variable is always whole numbers so pointer always contains whole numbers. The declaration of pointer are as follows.
Syntax: Data type * pointer Name.
Example: int *I;
Data type defines the type of value defined at the address of pointer variable. In the above example value at the address of ‘I’ is of type integer.
Consider the following program.
# include<stdio.h>
# include<conio.h>
Void main()
{
Int a,b,c;
Int *p,*q,*r;
p=&a;
q=&b;
r=&c;
Printf(“Enter two numbers”);
Scanf(“%d%d,&a,&b);
c=a + b;
Printf(“\n Address of variable C is %d”,&C);
Printf(“\n Address of variable C is %d,r);
Printf(“\n Address of variable r is %d”,&r);
Printf(“\n value of variable C is %d”,C);
Printf(“\n value of variable C is %d,*^);
Getch ();
}
In the above program variable ‘r’ is the integer pointer which holds the address of variable ‘C’
Case 1: In ‘printf’ statement whenever we used (“%d”,r) men me value of r is printed but ‘r’ is holding the address of variable ‘C’. So, address of variable C is copied to the value of ‘r’ and it is printed on output screen
Case 2: Whenever we used (“%d”,&r) in ‘printf’ function men the address of variable ‘r’ is pointed on o/p screen.
Case 3: When we used (“%d”,*r) in pointf function at mat time value which is stored at the address which holds by variable ‘r’ is printed.
Now me variable ‘r’ is holding the address of variable ‘C’. So, the value which is stored at the address of ‘C’ is printed on the output screen.
Consider the following example.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a=3;
Int *p;
p=&a;
Printf(“\n%d”,a);
Printf(“\n%d”,&a);
Printf(“\n%d”,P);
Printf(“\n%d”,&P);
Printf(“\n%d”,*P);
Printf(“\n%d”,*(&a));
}
Run the above program on the computer system so that you will familiar with the basic use of pointers. Following is the explanation O/p of above program.
● The first ‘printf’ statement prints the value of ‘C’ ie. 3
● The second ‘printf’ statement prints the address of ‘a’
● The third ‘printf’ statement prints me value of ‘p’ ie. The address of ‘a’
● The forth ‘printf’ statement prints the address of ‘p’
● The fifth ‘printf’ statement prints the value which is stored at the address holds in ‘p’ ie. 3
● The sixth ‘printf’ statement prints the value which is stored at the address of ‘a’ ie. 3
Data type of pointer variable can be anything. Such as char *C;
In the above instruction pointer ‘C’ is of type character so the variable ‘C’ can store the address of variable which contains character type of value. Consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int I,*ip;
Char C, *cp;
I = 3;
Ip = & I;
c=’M’;
Cp=&c;
Printf(“%d”,I);
Printf(“\n%d”,*ip);
Printf(“\n%C;,C);
Printf(“\n%c”, *cp);
Getch();
}
The output of above program is.
3
3
m
m
Defining pointers
One of the vital and heavily used features of ‘C’ is pointer. Most of the other programming languages also support pointers but only few of them use it freely. Support pointers but only few of them use it freely.
When we declare any variable in C language, there are three things associated with that variable.
- Data type of variable: Data type defines the type of data that variable can hold. Data type tells the compiler about the amount of memory allocated to the variable.
- Address of Variable: Address of variable represents the exact address of memory location which is allocated to variable.
- Value of variable: It is the value of variable which is stored at the address of memory location allocated to variable.
Example: int n = 5;
In the above example ‘int’ is the data type which tells the compiler to allocate 2 bytes of memory to variable ‘n’.
Once the variable is declared the compiler allocated two bytes of memory to variable ‘n’. Suppose the address of that memory location is 1020. At the address of memory location 1020 the value 5 is stored.
Memory map for the above declaration is as follows.
Use of &,/and ‘*’ operator
Consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a,b,c;
Printf(“Enter two numbers”);
Scanf(“%d%d”, &a,&b);
c = a+b;
Printf(“/n Addition is %d”, c);
Printf(“/n Addition of variable is %d”, &c);
Getch();
}
Above program is the program for addition of two numbers in ‘C’ language. In the seventh instruction of the above program we used operator ‘%’ and ‘&’ ‘%d’ is the access specifier which tells the compiler to take integer value as an input whereas. ‘&a’ tells the compiler to store the taken value at the address of variable ‘a’.
In the ninth instruction compiler will print me the value of ‘C’ so the output of the 9th instruction is as follows.
Addition is 5[Note: considering a = 2 and b = 3]
In the tenth instruction compiler will print me the address of variable C.
So the output of length instruction is as follows. Address of variable C is 1020.
Now consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a,b,c;
Printf(“Enter two numbers”);
Scanf(“%d%d”, &a,&b);
c = a+b;
Printf(“/n Addition is %d”, c);
Printf(“/n Addition of variable is %d”, &c);
Printf(“/n value of variable c is %d”, *(&c));
Getch();
}
Now, we all are clear about the output of instruction 9 and 10.
In the 11th instruction, operator *and & is used. ‘*’ operator tells compiler to pick up the value which is stored at the address of variable C. So the output of the 11th instruction is as follows. Value of variable C is 5 [considering a = 24 b = 3;]
Key takeaway:
One of the vital and heavily used features of ‘C’ is pointer.
Most of the other programming languages also support pointers but only few of them use it freely.
The process of assigning a variable's address to a pointer variable is known as pointer initialization. The address of a variable of the same data type can only be stored in a pointer variable. The address operator & is used to determine the address of a variable in the C programming language. The & (directly preceding a variable name) yields the variable's address.
#include<stdio.h>
Void main()
{
int a = 10;
int *ptr; //pointer declaration
ptr = &a; //pointer initialization
}
Variables of the same datatype are always pointed to by pointer variables. Let's look at an example to demonstrate this:
#include<stdio.h>
Void main()
{
float a;
int *ptr;
ptr = &a; // ERROR, type mismatch
}
If you're not sure which variable's address to assign to a pointer variable during declaration, it's best to leave it blank. A NULL pointer is a pointer that has been allocated the value NULL.
#include <stdio.h>
Int main()
{
int *ptr = NULL;
return 0;
}
Key takeaway
The process of assigning a variable's address to a pointer variable is known as pointer initialization. The address of a variable of the same data type can only be stored in a pointer variable.
Pointer arithmetic is slightly different from arithmetic we normally use in our daily life. The only valid arithmetic operations applicable on pointers are:
- Addition of integer to a pointer
- Subtraction of integer to a pointer
- Subtracting two pointers of the same type
The pointer arithmetic is performed relative to the base type of the pointer. For example, if we have an integer pointer ip which contains address 1000, then on incrementing it by 1, we will get 1004 (i.e 1000 + 1 * 4) instead of 1001 because the size of the int data type is 4 bytes. If we had been using a system where the size of int is 2 bytes then we would get 1002 ( i.e 1000 + 1 * 2 ).
Similarly, on decrementing it we will get 996 (i.e 1000 - 1 * 4) instead of 999.
So, the expression ip + 4 will point to the address 1016 (i.e 1000 + 4 * 4).
Let's take some more examples.
1
2
3
Int i = 12, *ip = &i;
Double d = 2.3, *dp = &d;
Char ch = 'a', *cp = &ch;
Suppose the address of i, d and ch are 1000, 2000, 3000 respectively, therefore ip, dp and cp are at 1000, 2000, 3000 initially.
Key takeaway
Pointer arithmetic is slightly different from arithmetic we normally use in our daily life.
The pointer arithmetic is performed relative to the base type of the pointer.
Consider the following example, which utilises an array of three integers to explain the notion of arrays of pointers.
#include <stdio.h>
const int MAX = 3;
Int main () {
int var[] = {10, 100, 200};
int i;
for (i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, var[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
There may be times when we need to keep an array that can store pointers to ints, chars, or any other possible data type. The declaration of an array of pointers to an integer is as follows:
Int *ptr[MAX];
It declares ptr as a MAX integer pointer array. As a result, each ptr element contains a pointer to an int value. The example below uses three integers that are stored in an array of pointers like follows:
#include <stdio.h>
Const int MAX = 3;
Int main () {
int var[] = {10, 100, 200};
int i, *ptr[MAX];
for ( i = 0; i < MAX; i++) {
ptr[i] = &var[i]; /* assign the address of integer. */
}
for ( i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, *ptr[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
You can also store a list of strings in an array of character pointers, as shown below:
#include <stdio.h>
Const int MAX = 4;
Int main () {
char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
int i = 0;
for ( i = 0; i < MAX; i++) {
printf("Value of names[%d] = %s\n", i, names[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali
Pointers and one-dimensional array
● For every of the array's items, the compiler allocates Continuous memory addresses.
● The array's base address is equal to the array's first element address (index 0).
● For instance, int a [5] = 10, 20, 30, 40, 50;
Elements
The five items are saved in the following order:
If 'p' is declared as an integer pointer, the following assignment can be used to point to an array 'a'.
p = a;
(or) p = &a[0];
Using p++ to travel from one element to another, every value of 'a' is accessed. When a pointer is incremented, the size of the datatype it points to is multiplied by its value. The "scale factor" is the name given to this length.
Below is an explanation of the link between 'p' and 'a.'
P = &a[0] = 1000
P+1 = &a[1] = 1004
P+2 = &a[2] = 1008
P+3 = &a[3] = 1012
P+4 = &a[4] = 1016
The address of an element is determined by its index and the datatype's scale factor. Here's an example to help you understand.
Address of a[3] = base address + (3* scale factor of int)
= 1000 + (3*4)
= 1000 +12
= 1012
Instead of utilising array indexing, pointers can be used to access array entries.
The value of a[3] is given by *(p+3).
a[i] = *(p+i)
Example
The C programme for pointers and one-dimensional arrays is shown below.
#include<stdio.h>
Main ( ){
int a[5];
int *p,i;
printf ("Enter 5 elements");
for (i=0; i<5; i++)
scanf ("%d", &a[i]);
p = &a[0];
printf ("Elements of the array are");
for (i=0; i<5; i++)
printf("%d", *(p+i));
}
Output
When the aforementioned programme is run, the following result is obtained:
Enter 5 elements: 10 20 30 40 50
Elements of the array are: 10 20 30 40 50
Pointers and two dimensional arrays
The following is the memory allocation for a two-dimensional array:
Int a[3] [3] = {1,2,3,4,5,6,7,8,9};
a[1] [2] = *(1234 + 1*3+2)
= *(1234 + 3+2)
= *(1234 + 5*4) // 4 is Scale factor
= * (1234+20)
= *(1254)
a[1] [2] = 6
Example
The C programme for pointers and two-dimensional arrays is shown below.
#include<stdio.h>
Main ( ){
int a[3] [3], i,j;
int *p;
clrscr ( );
printf ("Enter elements of 2D array");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
scanf ("%d", &a[i] [j]);
}
}
p = &a[0] [0];
printf ("elements of 2d array are");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
printf ("%d \t", *(p+i*3+j));
}
printf ("\n");
}
getch ( );
}
Output
When the aforementioned programme is run, the following result is obtained:
Enter elements of 2D array
1 2 3 4 5 6 7 8 9
Elements of 2D array are
1 2 3
4 5 6
7 8 9
Parameter Passing by Value
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called call by value. In case of parameter passing by value, the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function.
This mechanism is used when programmer don't want to change the value of passed parameters. When parameters are passed by value then functions in C create copies of the passed in variables and do required processing on these copied variables.
Pass-by-value is implemented by actual data transfer so additional storage is required to maintain the copies of passed parameters.
Example:
#include <stdio.h>
#include<conio.h>
/* function declaration goes here.*/
Void swap( int p1, int p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( a, b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
Getch();
}
Void swap( int p1, int p2 )
{
Int t;
t = p2;
p2 = p1;
p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", p1, p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b (p2) = 10
After: Value of a = 10 and value of b = 20
Note: In the above example the values of “a” and “b” remain unchanged before calling swap function and after calling swap function.
Parameter Passing by Reference
This mechanism is used when programmers want a function to do the changes in passed parameters and reflect those changes back to the calling function. This mechanism is also called as call by reference. This is achieved by passing the address of variable to the function and function body can directly work over the addresses. Advantage of pass by reference is efficiency in both time and space. Whereas disadvantages are access to formal parameters is slow and inadvertent and erroneous changes may be made to the actual parameter.
Example:
#include <stdio.h>
#include<conio.h>
Void swap( int *p1, int *p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( &a, &b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
}
Void swap( int *p1, int *p2 )
{
Int t;
t = *p2;
*p2 = *p1;
*p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", *p1, *p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b(p2) = 10
After: Value of a = 20 and value of b = 10
Note: In the above example the values of “a” and “b” are changes after calling swap function.
Call by reference
Array is a data structure which stores the collection of similar types of element in consecutive memory locations. Indexing of array always start with ‘0’ where as non-graphical variable ‘\0’ indicates the end of array. Syntax for declaring array is
Data typearray name[Maximum size];
● Data types are used to define type of element in an array. Data types are also useful in finding the size of total memory locations allocated for the array.
● All the rules of defining name of variable are also applicable for the array name.
● Maximum size indicates the total number of maximum elements that array can hold.
● Total memory allocated for the array is equal to the memory required to store one element of the array multiply by the total element in the array.
● In array, memory allocation is done at the time of declaration of an array.
Example:
Sr. No. | Instructions | Description |
1. | #include<stdio.h> | Header file included |
2. | #include<conio.h> | Header file included |
3. | Void main() | Execution of program begins |
4. | { |
|
5. | Int i,n,a[10]; | Memory is allocated for variable i,n and array a |
6. | Clrscr(); | Clear the output of previous screen |
7. | Printf("enter a number"); | Print “enter a number” |
8. | Scanf("%d",&n); | Input value is stored at the addres of variable n |
9. | For(i=0;i<=10;i++) | For loop started from value of i=0 to i=10 |
10. | { | Compound statement(scope of for loop starts) |
11. | a[i]=n*i; | Result of multiplication of n and I is stored at the ith location of array ieas i=0 so it is stores at first location. |
12. | Printf("\n %d",a[i]); | Value of ith location of the array is printed |
13. | } | Compound statement(scope of for loop ends) |
14. | Printf("\n first element in array is %d",a[0]); | Value of first element of the array is printed |
15. | Printf("\n fifth element in array is %d",a[4]); | Value of fifth element of the array is printed |
16. | Printf("\n tenth element in array is %d",a[9]); | Value of tenth element of the array is printed |
17. | Getch(); | Used to hold the output screen |
18. | } | Indicates end of scope of main function |
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called as call by value. In case of parameter passing by value, the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function.
This mechanism is used when programmer don't want to change the value of passed parameters. When parameters are passed by value then functions in C create copies of the passed in variables and do required processing on these copied variables.
Pass-by-value is implemented by actual data transfer so additional storage is required to maintain the copies of passed parameters.
Example:
#include <stdio.h>
#include<conio.h>
/* function declaration goes here.*/
Void swap( int p1, int p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( a, b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
Getch();
}
Void swap( int p1, int p2 )
{
Int t;
t = p2;
p2 = p1;
p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", p1, p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b (p2) = 10
After: Value of a = 10 and value of b = 20
Note: In the above example the values of “a” and “b” remain unchanged before calling swap function and after calling swap function.
Key takeaway
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called call by value.
C malloc()
The name "malloc" stands for memory allocation.
The malloc() function reserves a block of memory of the specified number of bytes. And, it returns a pointer of void which can be casted into pointers of any form.
Syntax of malloc()
Ptr = (castType*) malloc(size);
Example
Ptr = (float*) malloc(100 * sizeof(float));
The above statement allocates 400 bytes of memory. It's because the size of float is 4 bytes. And, the pointer ptr holds the address of the first byte in the allocated memory.
The expression results in a NULL pointer if the memory cannot be allocated.
C calloc()
The name "calloc" stands for contiguous allocation.
The malloc() function allocates memory and leaves the memory uninitialized. Whereas, the calloc() function allocates memory and initializes all bits to zero.
Syntax of calloc()
Ptr = (castType*)calloc(n, size);
Example:
Ptr = (float*) calloc(25, sizeof(float));
The above statement allocates contiguous space in memory for 25 elements of type float.
C free()
Dynamically allocated memory created with either calloc() or malloc() doesn't get freed on their own. You must explicitly use free() to release the space.
Syntax of free()
Free(ptr);
This statement frees the space allocated in the memory pointed by ptr.
Example 1: malloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) malloc(n * sizeof(int));
// if memory cannot be allocated
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i < n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
// deallocating the memory
Free(ptr);
Return 0;
}
Here, we have dynamically allocated the memory for n number of int.
Example 2: calloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) calloc(n, sizeof(int));
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i < n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
Free(ptr);
Return 0;
}
C realloc()
If the dynamically allocated memory is insufficient or more than required, you can change the size of previously allocated memory using the realloc() function.
Syntax of realloc()
Ptr = realloc(ptr, x);
Here, ptr is reallocated with a new size x.
Example 3: realloc()
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int *ptr, i , n1, n2;
Printf("Enter size: ");
Scanf("%d", &n1);
Ptr = (int*) malloc(n1 * sizeof(int));
Printf("Addresses of previously allocated memory: ");
For(i = 0; i < n1; ++i)
Printf("%u\n",ptr + i);
Printf("\nEnter the new size: ");
Scanf("%d", &n2);
// rellocating the memory
Ptr = realloc(ptr, n2 * sizeof(int));
Printf("Addresses of newly allocated memory: ");
For(i = 0; i < n2; ++i)
Printf("%u\n", ptr + i);
Free(ptr);
Return 0;
}
When you run the program, the output will be:
Enter size: 2
Addresses of previously allocated memory:26855472
26855476
Enter the new size: 4
Addresses of newly allocated memory:26855472
26855476
26855480
26855484
References:
- The C- Programming Language - By Brian W Kernighan and Dennis Ritchie
- C- Programming in an open source paradigm: By R.K. Kamat, K .S. Oza, S.R. Patil
- The GNU C Programming Tutorial -By Mark Burgess
- Let us C- By Yashwant Kanetkar
Unit - 1
Functions and Pointer
Similar to other languages, the C language also provides the facility of function. Function is the block of code which is used to perform a specific task. In c language the complete program is composed of functions.
Functions are useful to divide c programs into smaller modules. Programmer can invoked these modules anywhere inside c program for any number of times.
Functions are used to increase readability of the code. Size of program can be reduce by using functions. By using function, programmer can divide complex tasks into smaller manageable tasks and test them independently before using them together.
Functions of C language are defined with the type of function. The type of functions indicates the data type of value which will return by function. In order to use function in the program, initially programmer have to inform compiler about the function. This is also called as defining a function.
In C program all the function definition present outside the main function. All function need to be declared and defined before use. Function declaration requires function name, argument list, and return type.
Return TypeFunction name (Parameter list)
{
//body of function
Statement 1;
Statement 2;
…………...
Statement n;
}
In C programming, a function definition consists of a function header and a function body. All of the components of a function are listed here.
● Return Type − A function may return a value as its return type. The return type specifies the data type of the value returned by the function. Some functions do what they're supposed to do yet don't return a value. The keyword void is used as the return type in this scenario.
● Function Name - This is the function's real name. The function signature is made up of the function name and the argument list.
● Parameters − A parameter is similar to a placeholder. You pass a value to the parameter when you call a function. Actual parameter or argument refers to this value. The type, order, and number of parameters in a function are referred to as the parameter list. Parameters are optional; a function may or may not have them.
● Function Body − The function body is made up of a series of statements that specify what the function does.
Declaration
A function declaration tells the compiler the name of the function and how to invoke it. The function's actual body can be defined independently.
The following are the components of a function declaration:
Return_type function_name( parameter list );
The function declaration for the above-mentioned function max() is as follows:
Int max(int num1, int num2);
In a function declaration, the names of the parameters are not relevant; only their types are, hence the following is also a legal declaration:
Int max(int, int);
When a function is defined in one source file and called in another, a function declaration is necessary. In this situation, the function should be declared at the top of the file calling the function.
Prototype of function
One of the most essential characteristics of C programming, which evolved from C++, is the function prototype. A function prototype is a code declaration that tells the compiler about the function's data type, parameters, and parameter list. A function, as we all know, is a section of code that performs a specified task. A function prototype, on the other hand, is a function that tells the compiler the return type, function name, and parameter so that it can match the given function calls when they're needed.
Syntax
Return-type function-name ( datatype parameter1 , datatype parameter2 , datatype parameter3..);
Example:
Int addition(int a, int b);
In the preceding example, addition is the name of the function with an integer data type, and a and b are the arguments of two int arguments supplied to the function. Note that, depending on the necessity, we can pass as many parameters as we wish to our function. We can define as many prototypes as we wish in the same programme, but they must differ in either name or parameter list. All you have to do is create a prototype in the code and then use the function name to call it at any time.
Program for function prototype
#include <stdio.h>
Int Num_addition( int i , int j );// prototype for the function
Int main()
{
Int num1,num2,total;
Printf( " Please enters the 2 numbers you want to add : " ) ;
Scanf( "%d %d" , &num1 , &num2 ) ;
Total = Num_addition( num1 , num2 ) ; // calling the function
Printf( " The total of the given numbers is = %d " , total ) ;
Return 0 ;
}
Int Num_addition( int i , int j ) // function definition for prototype
{
Int results;
Results = i + j ;
Return results ;
}
Output
As you can see in the following code, we first declare the function prototype for the addition of two numbers with the name " Num addition " and an integer return type with two integer arguments named I and j. We defined three integers in the main class: num1, num2, and total. Following that, we collect user input before storing the total addition results of the two given values. The function " Num addition" is used once again to call it. Finally, you can see in the function declaration that we provide the logic to do addition and save the results.
Key takeaway
Functions are useful to divide c programs into smaller modules. Programmers can invoke these modules anywhere inside C program for any number of times.
A function prototype is a code declaration that tells the compiler about the function's data type, parameters, and parameter list.
Local variables
Local variables are variables that are declared within a function or block. They can only be utilised by statements that are included within that function or code block. Functions outside of their own are unaware of local variables. The following example demonstrates the use of local variables. The variables a, b, and c are all local to the function main().
#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;
}
Advantages of Local Variable
● Because a local variable's name is only recognised by the function in which it is declared, it can be used in several functions with the same name.
● Local variables only require memory for the duration of the function; after that, the same memory address can be reused.
Disadvantages of Local Variables
● The local variable's scope is restricted to its function and it cannot be used by other functions.
● The local variable is not allowed to share data.
Global Variables
Global variables are variables that are defined outside of a function, usually at the start of a programme. Global variables maintain their values throughout the life of your programme and can be accessed from any of the program's functions.
Any function has access to a global variable. That is, once a global variable is declared, it is available for use throughout your whole programme. The following programme demonstrates the use of global variables in a programme.
#include <stdio.h>
/* global variable declaration */
Int g;
Int main () {
/* local variable declaration */
int a, b;
/* actual initialization */
a = 10;
b = 20;
g = a + b;
printf ("value of a = %d, b = %d and g = %d\n", a, b, g);
return 0;
}
Local and global variables in a programme can have the same name, but the value of a local variable inside a function takes precedence. Here's an illustration:
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;
}
When the preceding code is compiled and run, the following result is obtained:
Value of g = 10
Advantages of Global Variable
● Global variables can be accessible by all of the program's functions.
● It is just necessary to make a single declaration.
● If all of the functions are accessing the same data, this is quite handy.
Disadvantages of Global Variable
● Because it can be utilised by any function in the programme, the value of a global variable can be modified by accident.
● If we employ a big number of global variables, there is a good possibility that the programme may generate errors.
Difference between Global variable and Local variable
Global Variable | Local Variable |
Outside of all the function blocks, global variables are declared. | Within a function block, local variables are declared. |
Throughout the programme, the scope is maintained. | The scope is restricted, and they can only be used in the function in which they are declared. |
Any modification to a global variable has an impact on the entire programme, regardless of where it is utilised. | Any changes to the local variable have no effect on the program's other functions.
|
A global variable is present in the programme for the duration of its execution. | After the function is executed, a local variable is created, and when the function is finished, the variable is destroyed. |
It can be accessed from anywhere in the programme using any of the program's functionalities. | It is only accessible through the function statements in which it is declared, not through other functions. |
If a global variable isn't initialised, it defaults to zero. | If a local variable isn't initialised, it defaults to a garbage value. |
The data segment of memory stores global variables. | Local variables are kept in memory on a stack. |
We can't use the same name for several variables. | Variables having the same name can be declared in several functions. |
Key takeaway
Local variables are variables that are declared within a function or block.
Global variables are variables that are defined outside of a function, usually at the start of a programme.
User defined function is the block of code written by programmer to perform a particular task. As compiler doesn’t have any idea about the user define function so programmer has to define and declare these functions inside the program body. Programmer can define these function outside the main function but declaration of user defined function should present in main function only. Whenever compiler executes function call (function declaration) then compiler shift the flow of program execution to the definition part of user define function.
Example
#include <stdio.h>
#include<conio.h>
Int add (int x, int y)
{
Int sum;
Sum = x + y;
Return (sum);
}
Main ()
{
Int a,b,c;
a = 15;
b = 25;
c = add(a,b);
Printf ("\n Addition is %d ", c);
}
Output:
Addition is 40
Key takeaway
User defined function is the block of code written by programmer to perform a particular task.
Programmer can define these function outside the main function but declaration of user defined function should present in main function only.
Recursion
In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.
Void recursion() {
Recursion(); /* function calls itself */
}
Int main() {
Recursion();
}
The C programming language supports recursion, i.e., a function to call itself. But while using recursion, programmers has to be careful to define an exit condition from the function, otherwise it will go into an infinite loop.
Recursive functions are useful to solve many mathematical problems, such as calculating the factorial of a number, generating Fibonacci series, etc.
The following example calculates the factorial of a given number using a recursive function −
#include <stdio.h>
Unsigned long long int factorial(unsigned int i) {
If(i <= 1) {
Return 1;
}
Return i * factorial(i - 1);
}
Int main() {
Int i = 12;
Printf("Factorial of %d is %d\n", i, factorial(i));
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Factorial of 12 is 479001600
The following example generates the Fibonacci series for a given number using a recursive function −
#include <stdio.h>
Int fibonacci(int i) {
If(i == 0) {
Return 0;
}
If(i == 1) {
Return 1;
}
Return fibonacci(i-1) + fibonacci(i-2);
}
Int main() {
Int i;
For (i = 0; i < 10; i++) {
Printf("%d\t\n", fibonacci(i));
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
0
1
1
2
3
5
8
13
21
34
Storage classes
Within a C programme, a storage class defines the scope (visibility) and lifetime of variables and/or functions. They come before the type they modify. In a C programme, there are four different storage classes:
● auto
● register
● static
● extern
Auto
At runtime, memory is automatically allocated to automated variables.
The automated variables' visibility is confined to the block in which they are defined. The automated variables' scope is constrained to the block in which they are defined. By default, the automated variables are set to garbage.
When you depart the block, the memory allotted to automatic variables is released. The auto keyword is used to define automatic variables.
By default, every local variable in C is automatic.
For all local variables, the auto storage class is the default storage class.
{
int mount;
auto int month;
}
The preceding example declares two variables in the same storage class. The keyword 'auto' can only be used within functions, i.e. within local variables.
Example:
#include <stdio.h>
Int main()
{
Int a; //auto
Char b;
Float c;
Printf("%d %c %f",a,b,c); // printing initial default value of automatic variables a, b, and c.
Return 0;
}
Output:
Garbage garbage garbage
Register
The memory is allocated to the CPU registers by the variables declared as the registers, depending on the size of the memory remaining in the CPU.
We can't dereference the register variables, which means we can't use & operator for them. The register variables have a faster access time than the automatic variables. The register local variables have a default value of 0.
The variable that should be saved in the CPU register is denoted by the register keyword. Is it, nevertheless, a compiler? The variables can be stored in the register at the user's discretion. We can store pointers in registers, which means that a register can hold the address of a variable. Because we can't use more than one storage specifier for the same variable, static variables can't be stored in the register.
{
register int miles;
}
Example:
#include <stdio.h>
Int main()
{
Register int a; // variable a is allocated memory in the CPU register. The initial default value of a is 0.
Printf("%d",a);
}
Output:
0
Static
The static storage class tells the compiler to keep a local variable alive for the duration of the programme, rather than creating and destroying it every time it enters and exits scope. As a result, making local variables static ensures that their values are preserved between function calls.
The static modifier can be used on global variables as well. When you do this, the scope of that variable is limited to the file in which it is declared.
When the keyword static is applied on a global variable in C programming, just one copy of that member is shared by all objects in that class.
#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 */
i++;
printf("i is %d and count is %d\n", i, count);
}
When the above code is compiled and executed, it produces the following result −
i is 6 and count is 4
i is 7 and count is 3
i is 8 and count is 2
i is 9 and count is 1
i is 10 and count is 0
Extern
The extern storage class is used to provide a reference to a global variable that is shared by all application files. The variable cannot be initialised when you use 'extern,' but it does direct the variable name to a previously established storage location.
When you have many files and specify a global variable or function that will be utilised in other files, extern is used in another file to provide a reference to the defined variable or function. To clarify, extern is a keyword that is used to declare a global variable or function in a different file.
Example:
#include <stdio.h>
Int main()
{
Extern int a;
Printf("%d",a);
}
Output
Main.c:(.text+0x6): undefined reference to a'
Collect2: error: ld returned 1 exit status
Key takeaway
In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.
Within a C programme, a storage class defines the scope (visibility) and lifetime of variables and/or functions. They come before the type they modify. In a C programme, there are four different storage classes.
Pointers in C language is a variable that stores/points the address of another variable. A Pointer in C is used to allocate memory dynamically i.e. at run time. The pointer variable might belong to any of the data type such as int, float, char, double, short etc.
Pointer Syntax: data_type *var_name; Example : int *p; char *p;
Where, * is used to denote that “p” is pointer variable and not a normal variable.
Normal variable stores the value whereas pointer variable stores the address of the variable.
The content of the C pointer always be a whole number i.e. address.
Always C pointer is initialized to null, i.e. int *p = null.
The value of null pointer is 0.
& symbol is used to get the address of the variable.
* symbol is used to get the value of the variable that the pointer is pointing to.
If a pointer in C is assigned to NULL, it means it is pointing to nothing.
Two pointers can be subtracted to know how many elements are available between these two pointers.
But, Pointer addition, multiplication, division are not allowed.
The size of any pointer is 2 byte (for 16 bit compiler).
Example:
#include <stdio.h>
Int main()
{
Int *ptr, q;
q = 50;
/* address of q is assigned to ptr */
Ptr = &q;
/* display q's value using ptr variable */
Printf("%d", *ptr);
Return 0;
}
Output:
1
2
3
4
5
6
7
8
9
10
11
Declaration
Pointers are declare with the help of operator ‘*’. ‘*’ is known as ‘value at address’. Pointers are the variables which are used to store the address of another variable As the address of variable is always whole numbers so pointer always contains whole numbers. The declaration of pointer are as follows.
Syntax: Data type * pointer Name.
Example: int *I;
Data type defines the type of value defined at the address of pointer variable. In the above example value at the address of ‘I’ is of type integer.
Consider the following program.
# include<stdio.h>
# include<conio.h>
Void main()
{
Int a,b,c;
Int *p,*q,*r;
p=&a;
q=&b;
r=&c;
Printf(“Enter two numbers”);
Scanf(“%d%d,&a,&b);
c=a + b;
Printf(“\n Address of variable C is %d”,&C);
Printf(“\n Address of variable C is %d,r);
Printf(“\n Address of variable r is %d”,&r);
Printf(“\n value of variable C is %d”,C);
Printf(“\n value of variable C is %d,*^);
Getch ();
}
In the above program variable ‘r’ is the integer pointer which holds the address of variable ‘C’
Case 1: In ‘printf’ statement whenever we used (“%d”,r) men me value of r is printed but ‘r’ is holding the address of variable ‘C’. So, address of variable C is copied to the value of ‘r’ and it is printed on output screen
Case 2: Whenever we used (“%d”,&r) in ‘printf’ function men the address of variable ‘r’ is pointed on o/p screen.
Case 3: When we used (“%d”,*r) in pointf function at mat time value which is stored at the address which holds by variable ‘r’ is printed.
Now me variable ‘r’ is holding the address of variable ‘C’. So, the value which is stored at the address of ‘C’ is printed on the output screen.
Consider the following example.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a=3;
Int *p;
p=&a;
Printf(“\n%d”,a);
Printf(“\n%d”,&a);
Printf(“\n%d”,P);
Printf(“\n%d”,&P);
Printf(“\n%d”,*P);
Printf(“\n%d”,*(&a));
}
Run the above program on the computer system so that you will familiar with the basic use of pointers. Following is the explanation O/p of above program.
● The first ‘printf’ statement prints the value of ‘C’ ie. 3
● The second ‘printf’ statement prints the address of ‘a’
● The third ‘printf’ statement prints me value of ‘p’ ie. The address of ‘a’
● The forth ‘printf’ statement prints the address of ‘p’
● The fifth ‘printf’ statement prints the value which is stored at the address holds in ‘p’ ie. 3
● The sixth ‘printf’ statement prints the value which is stored at the address of ‘a’ ie. 3
Data type of pointer variable can be anything. Such as char *C;
In the above instruction pointer ‘C’ is of type character so the variable ‘C’ can store the address of variable which contains character type of value. Consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int I,*ip;
Char C, *cp;
I = 3;
Ip = & I;
c=’M’;
Cp=&c;
Printf(“%d”,I);
Printf(“\n%d”,*ip);
Printf(“\n%C;,C);
Printf(“\n%c”, *cp);
Getch();
}
The output of above program is.
3
3
m
m
Defining pointers
One of the vital and heavily used features of ‘C’ is pointer. Most of the other programming languages also support pointers but only few of them use it freely. Support pointers but only few of them use it freely.
When we declare any variable in C language, there are three things associated with that variable.
- Data type of variable: Data type defines the type of data that variable can hold. Data type tells the compiler about the amount of memory allocated to the variable.
- Address of Variable: Address of variable represents the exact address of memory location which is allocated to variable.
- Value of variable: It is the value of variable which is stored at the address of memory location allocated to variable.
Example: int n = 5;
In the above example ‘int’ is the data type which tells the compiler to allocate 2 bytes of memory to variable ‘n’.
Once the variable is declared the compiler allocated two bytes of memory to variable ‘n’. Suppose the address of that memory location is 1020. At the address of memory location 1020 the value 5 is stored.
Memory map for the above declaration is as follows.
Use of &,/and ‘*’ operator
Consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a,b,c;
Printf(“Enter two numbers”);
Scanf(“%d%d”, &a,&b);
c = a+b;
Printf(“/n Addition is %d”, c);
Printf(“/n Addition of variable is %d”, &c);
Getch();
}
Above program is the program for addition of two numbers in ‘C’ language. In the seventh instruction of the above program we used operator ‘%’ and ‘&’ ‘%d’ is the access specifier which tells the compiler to take integer value as an input whereas. ‘&a’ tells the compiler to store the taken value at the address of variable ‘a’.
In the ninth instruction compiler will print me the value of ‘C’ so the output of the 9th instruction is as follows.
Addition is 5[Note: considering a = 2 and b = 3]
In the tenth instruction compiler will print me the address of variable C.
So the output of length instruction is as follows. Address of variable C is 1020.
Now consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a,b,c;
Printf(“Enter two numbers”);
Scanf(“%d%d”, &a,&b);
c = a+b;
Printf(“/n Addition is %d”, c);
Printf(“/n Addition of variable is %d”, &c);
Printf(“/n value of variable c is %d”, *(&c));
Getch();
}
Now, we all are clear about the output of instruction 9 and 10.
In the 11th instruction, operator *and & is used. ‘*’ operator tells compiler to pick up the value which is stored at the address of variable C. So the output of the 11th instruction is as follows. Value of variable C is 5 [considering a = 24 b = 3;]
Key takeaway:
One of the vital and heavily used features of ‘C’ is pointer.
Most of the other programming languages also support pointers but only few of them use it freely.
The process of assigning a variable's address to a pointer variable is known as pointer initialization. The address of a variable of the same data type can only be stored in a pointer variable. The address operator & is used to determine the address of a variable in the C programming language. The & (directly preceding a variable name) yields the variable's address.
#include<stdio.h>
Void main()
{
int a = 10;
int *ptr; //pointer declaration
ptr = &a; //pointer initialization
}
Variables of the same datatype are always pointed to by pointer variables. Let's look at an example to demonstrate this:
#include<stdio.h>
Void main()
{
float a;
int *ptr;
ptr = &a; // ERROR, type mismatch
}
If you're not sure which variable's address to assign to a pointer variable during declaration, it's best to leave it blank. A NULL pointer is a pointer that has been allocated the value NULL.
#include <stdio.h>
Int main()
{
int *ptr = NULL;
return 0;
}
Key takeaway
The process of assigning a variable's address to a pointer variable is known as pointer initialization. The address of a variable of the same data type can only be stored in a pointer variable.
Pointer arithmetic is slightly different from arithmetic we normally use in our daily life. The only valid arithmetic operations applicable on pointers are:
- Addition of integer to a pointer
- Subtraction of integer to a pointer
- Subtracting two pointers of the same type
The pointer arithmetic is performed relative to the base type of the pointer. For example, if we have an integer pointer ip which contains address 1000, then on incrementing it by 1, we will get 1004 (i.e 1000 + 1 * 4) instead of 1001 because the size of the int data type is 4 bytes. If we had been using a system where the size of int is 2 bytes then we would get 1002 ( i.e 1000 + 1 * 2 ).
Similarly, on decrementing it we will get 996 (i.e 1000 - 1 * 4) instead of 999.
So, the expression ip + 4 will point to the address 1016 (i.e 1000 + 4 * 4).
Let's take some more examples.
1
2
3
Int i = 12, *ip = &i;
Double d = 2.3, *dp = &d;
Char ch = 'a', *cp = &ch;
Suppose the address of i, d and ch are 1000, 2000, 3000 respectively, therefore ip, dp and cp are at 1000, 2000, 3000 initially.
Key takeaway
Pointer arithmetic is slightly different from arithmetic we normally use in our daily life.
The pointer arithmetic is performed relative to the base type of the pointer.
Consider the following example, which utilises an array of three integers to explain the notion of arrays of pointers.
#include <stdio.h>
const int MAX = 3;
Int main () {
int var[] = {10, 100, 200};
int i;
for (i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, var[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
There may be times when we need to keep an array that can store pointers to ints, chars, or any other possible data type. The declaration of an array of pointers to an integer is as follows:
Int *ptr[MAX];
It declares ptr as a MAX integer pointer array. As a result, each ptr element contains a pointer to an int value. The example below uses three integers that are stored in an array of pointers like follows:
#include <stdio.h>
Const int MAX = 3;
Int main () {
int var[] = {10, 100, 200};
int i, *ptr[MAX];
for ( i = 0; i < MAX; i++) {
ptr[i] = &var[i]; /* assign the address of integer. */
}
for ( i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, *ptr[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
You can also store a list of strings in an array of character pointers, as shown below:
#include <stdio.h>
Const int MAX = 4;
Int main () {
char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
int i = 0;
for ( i = 0; i < MAX; i++) {
printf("Value of names[%d] = %s\n", i, names[i] );
}
return 0;
}
When the preceding code is compiled and run, the following result is obtained:
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali
Pointers and one-dimensional array
● For every of the array's items, the compiler allocates Continuous memory addresses.
● The array's base address is equal to the array's first element address (index 0).
● For instance, int a [5] = 10, 20, 30, 40, 50;
Elements
The five items are saved in the following order:
If 'p' is declared as an integer pointer, the following assignment can be used to point to an array 'a'.
p = a;
(or) p = &a[0];
Using p++ to travel from one element to another, every value of 'a' is accessed. When a pointer is incremented, the size of the datatype it points to is multiplied by its value. The "scale factor" is the name given to this length.
Below is an explanation of the link between 'p' and 'a.'
P = &a[0] = 1000
P+1 = &a[1] = 1004
P+2 = &a[2] = 1008
P+3 = &a[3] = 1012
P+4 = &a[4] = 1016
The address of an element is determined by its index and the datatype's scale factor. Here's an example to help you understand.
Address of a[3] = base address + (3* scale factor of int)
= 1000 + (3*4)
= 1000 +12
= 1012
Instead of utilising array indexing, pointers can be used to access array entries.
The value of a[3] is given by *(p+3).
a[i] = *(p+i)
Example
The C programme for pointers and one-dimensional arrays is shown below.
#include<stdio.h>
Main ( ){
int a[5];
int *p,i;
printf ("Enter 5 elements");
for (i=0; i<5; i++)
scanf ("%d", &a[i]);
p = &a[0];
printf ("Elements of the array are");
for (i=0; i<5; i++)
printf("%d", *(p+i));
}
Output
When the aforementioned programme is run, the following result is obtained:
Enter 5 elements: 10 20 30 40 50
Elements of the array are: 10 20 30 40 50
Pointers and two dimensional arrays
The following is the memory allocation for a two-dimensional array:
Int a[3] [3] = {1,2,3,4,5,6,7,8,9};
a[1] [2] = *(1234 + 1*3+2)
= *(1234 + 3+2)
= *(1234 + 5*4) // 4 is Scale factor
= * (1234+20)
= *(1254)
a[1] [2] = 6
Example
The C programme for pointers and two-dimensional arrays is shown below.
#include<stdio.h>
Main ( ){
int a[3] [3], i,j;
int *p;
clrscr ( );
printf ("Enter elements of 2D array");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
scanf ("%d", &a[i] [j]);
}
}
p = &a[0] [0];
printf ("elements of 2d array are");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
printf ("%d \t", *(p+i*3+j));
}
printf ("\n");
}
getch ( );
}
Output
When the aforementioned programme is run, the following result is obtained:
Enter elements of 2D array
1 2 3 4 5 6 7 8 9
Elements of 2D array are
1 2 3
4 5 6
7 8 9
Parameter Passing by Value
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called call by value. In case of parameter passing by value, the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function.
This mechanism is used when programmer don't want to change the value of passed parameters. When parameters are passed by value then functions in C create copies of the passed in variables and do required processing on these copied variables.
Pass-by-value is implemented by actual data transfer so additional storage is required to maintain the copies of passed parameters.
Example:
#include <stdio.h>
#include<conio.h>
/* function declaration goes here.*/
Void swap( int p1, int p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( a, b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
Getch();
}
Void swap( int p1, int p2 )
{
Int t;
t = p2;
p2 = p1;
p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", p1, p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b (p2) = 10
After: Value of a = 10 and value of b = 20
Note: In the above example the values of “a” and “b” remain unchanged before calling swap function and after calling swap function.
Parameter Passing by Reference
This mechanism is used when programmers want a function to do the changes in passed parameters and reflect those changes back to the calling function. This mechanism is also called as call by reference. This is achieved by passing the address of variable to the function and function body can directly work over the addresses. Advantage of pass by reference is efficiency in both time and space. Whereas disadvantages are access to formal parameters is slow and inadvertent and erroneous changes may be made to the actual parameter.
Example:
#include <stdio.h>
#include<conio.h>
Void swap( int *p1, int *p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( &a, &b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
}
Void swap( int *p1, int *p2 )
{
Int t;
t = *p2;
*p2 = *p1;
*p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", *p1, *p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b(p2) = 10
After: Value of a = 20 and value of b = 10
Note: In the above example the values of “a” and “b” are changes after calling swap function.
Call by reference
Array is a data structure which stores the collection of similar types of element in consecutive memory locations. Indexing of array always start with ‘0’ where as non-graphical variable ‘\0’ indicates the end of array. Syntax for declaring array is
Data typearray name[Maximum size];
● Data types are used to define type of element in an array. Data types are also useful in finding the size of total memory locations allocated for the array.
● All the rules of defining name of variable are also applicable for the array name.
● Maximum size indicates the total number of maximum elements that array can hold.
● Total memory allocated for the array is equal to the memory required to store one element of the array multiply by the total element in the array.
● In array, memory allocation is done at the time of declaration of an array.
Example:
Sr. No. | Instructions | Description |
1. | #include<stdio.h> | Header file included |
2. | #include<conio.h> | Header file included |
3. | Void main() | Execution of program begins |
4. | { |
|
5. | Int i,n,a[10]; | Memory is allocated for variable i,n and array a |
6. | Clrscr(); | Clear the output of previous screen |
7. | Printf("enter a number"); | Print “enter a number” |
8. | Scanf("%d",&n); | Input value is stored at the addres of variable n |
9. | For(i=0;i<=10;i++) | For loop started from value of i=0 to i=10 |
10. | { | Compound statement(scope of for loop starts) |
11. | a[i]=n*i; | Result of multiplication of n and I is stored at the ith location of array ieas i=0 so it is stores at first location. |
12. | Printf("\n %d",a[i]); | Value of ith location of the array is printed |
13. | } | Compound statement(scope of for loop ends) |
14. | Printf("\n first element in array is %d",a[0]); | Value of first element of the array is printed |
15. | Printf("\n fifth element in array is %d",a[4]); | Value of fifth element of the array is printed |
16. | Printf("\n tenth element in array is %d",a[9]); | Value of tenth element of the array is printed |
17. | Getch(); | Used to hold the output screen |
18. | } | Indicates end of scope of main function |
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called as call by value. In case of parameter passing by value, the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function.
This mechanism is used when programmer don't want to change the value of passed parameters. When parameters are passed by value then functions in C create copies of the passed in variables and do required processing on these copied variables.
Pass-by-value is implemented by actual data transfer so additional storage is required to maintain the copies of passed parameters.
Example:
#include <stdio.h>
#include<conio.h>
/* function declaration goes here.*/
Void swap( int p1, int p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( a, b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
Getch();
}
Void swap( int p1, int p2 )
{
Int t;
t = p2;
p2 = p1;
p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", p1, p2 );
}
Output:
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b (p2) = 10
After: Value of a = 10 and value of b = 20
Note: In the above example the values of “a” and “b” remain unchanged before calling swap function and after calling swap function.
Key takeaway
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called call by value.
C malloc()
The name "malloc" stands for memory allocation.
The malloc() function reserves a block of memory of the specified number of bytes. And, it returns a pointer of void which can be casted into pointers of any form.
Syntax of malloc()
Ptr = (castType*) malloc(size);
Example
Ptr = (float*) malloc(100 * sizeof(float));
The above statement allocates 400 bytes of memory. It's because the size of float is 4 bytes. And, the pointer ptr holds the address of the first byte in the allocated memory.
The expression results in a NULL pointer if the memory cannot be allocated.
C calloc()
The name "calloc" stands for contiguous allocation.
The malloc() function allocates memory and leaves the memory uninitialized. Whereas, the calloc() function allocates memory and initializes all bits to zero.
Syntax of calloc()
Ptr = (castType*)calloc(n, size);
Example:
Ptr = (float*) calloc(25, sizeof(float));
The above statement allocates contiguous space in memory for 25 elements of type float.
C free()
Dynamically allocated memory created with either calloc() or malloc() doesn't get freed on their own. You must explicitly use free() to release the space.
Syntax of free()
Free(ptr);
This statement frees the space allocated in the memory pointed by ptr.
Example 1: malloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) malloc(n * sizeof(int));
// if memory cannot be allocated
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i < n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
// deallocating the memory
Free(ptr);
Return 0;
}
Here, we have dynamically allocated the memory for n number of int.
Example 2: calloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) calloc(n, sizeof(int));
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i < n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
Free(ptr);
Return 0;
}
C realloc()
If the dynamically allocated memory is insufficient or more than required, you can change the size of previously allocated memory using the realloc() function.
Syntax of realloc()
Ptr = realloc(ptr, x);
Here, ptr is reallocated with a new size x.
Example 3: realloc()
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int *ptr, i , n1, n2;
Printf("Enter size: ");
Scanf("%d", &n1);
Ptr = (int*) malloc(n1 * sizeof(int));
Printf("Addresses of previously allocated memory: ");
For(i = 0; i < n1; ++i)
Printf("%u\n",ptr + i);
Printf("\nEnter the new size: ");
Scanf("%d", &n2);
// rellocating the memory
Ptr = realloc(ptr, n2 * sizeof(int));
Printf("Addresses of newly allocated memory: ");
For(i = 0; i < n2; ++i)
Printf("%u\n", ptr + i);
Free(ptr);
Return 0;
}
When you run the program, the output will be:
Enter size: 2
Addresses of previously allocated memory:26855472
26855476
Enter the new size: 4
Addresses of newly allocated memory:26855472
26855476
26855480
26855484
References:
- The C- Programming Language - By Brian W Kernighan and Dennis Ritchie
- C- Programming in an open source paradigm: By R.K. Kamat, K .S. Oza, S.R. Patil
- The GNU C Programming Tutorial -By Mark Burgess
- Let us C- By Yashwant Kanetkar