Bx4002 Unit 4

Download as pdf or txt
Download as pdf or txt
You are on page 1of 69

PEC,Vaniyambadi

Department of MCA
BX4002 - Problem Solving and Programming in C

UNIT IV ARRAYS, STRINGS, FUNCTIONS AND POINTERS

Array

An array is a variable that can store multiple values. For example, if you want to store
100 integers, you can create an array for it.

int data[100];

How to declare an array?

dataType arrayName[arraySize];

For example,

float mark[5];

Here, we declared an array, mark, of floating-point type. And its size is 5. Meaning, it
can hold 5 floating-point values.

It's important to note that the size and type of an array cannot be changed once it is
declared.

Access Array Elements

You can access elements of an array by indices.

Suppose you declared an array mark as above. The first element is mark[0], the
second element is mark[1] and so on.

1
Declare an Array

Few keynotes:

• Arrays have 0 as the first index, not 1. In this example, mark[0] is the first
element.
• If the size of an array is n, to access the last element, the n-1 index is used. In
this example, mark[4]
• Suppose the starting address of mark[0] is 2120d. Then, the address of the
mark[1] will be 2124d. Similarly, the address of mark[2] will be 2128d and so
on.
This is because the size of a float is 4 bytes.

How to initialize an array?

It is possible to initialize an array during declaration. For example,

int mark[5] = {19, 10, 8, 17, 9};

You can also initialize an array like this.

int mark[] = {19, 10, 8, 17, 9};

Here, we haven't specified the size. However, the compiler knows its size is 5 as we
are initializing it with 5 elements.

Initialize an Array

Here,

mark[0] is equal to 19
mark[1] is equal to 10
mark[2] is equal to 8
mark[3] is equal to 17
mark[4] is equal to 9

Change Value of Array elements

int mark[5] = {19, 10, 8, 17, 9}


// make the value of the third element to -1
mark[2] = -1;

2
// make the value of the fifth element to 0
mark[4] = 0;

Input and Output Array Elements

Here's how you can take input from the user and store it in an array element.

// take input and store it in the 3rd element


scanf("%d", &mark[2]);
// take input and store it in the ith elementscanf("%d", &mark[i-1]);

Here's how you can print an individual element of an array.

// print the first element of the arrayprintf("%d", mark[0]);


// print the third element of the arrayprintf("%d", mark[2]);
// print ith element of the arrayprintf("%d", mark[i-1]);

Example 1: Array Input/Output

// Program to take 5 values from the user and store them in an array// Print the
elements stored in the array#include <stdio.h>
int main() {
int values[5];

printf("Enter 5 integers: ");

// taking input and storing it in an array


for(int i = 0; i < 5; ++i) {
scanf("%d", &values[i]);
}

printf("Displaying integers: ");

// printing elements of an array


for(int i = 0; i < 5; ++i) {
printf("%d\n", values[i]);
}
return 0;
}

Output

Enter 5 integers: 1
-3
34
0
3
Displaying integers: 1
-3
34

3
0
3

Here, we have used a for loop to take 5 inputs from the user and store them in an array.
Then, using another for loop, these elements are displayed on the screen.

Example 2: Calculate Average

// Program to find the average of n numbers using arrays


#include <stdio.h>int main() {

int marks[10], i, n, sum = 0, average;

printf("Enter number of elements: ");


scanf("%d", &n);

for(i=0; i < n; ++i) {


printf("Enter number%d: ",i+1);
scanf("%d", &marks[i]);

// adding integers entered by the user to the sum variable


sum += marks[i];
}

average = sum / n;
printf("Average = %d", average);

return 0;
}

Output

Enter n: 5
Enter number1: 45
Enter number2: 35
Enter number3: 38
Enter number4: 31
Enter number5: 49
Average = 39

Here, we have computed the average of n numbers entered by the user.

Access elements out of its bound!

Suppose you declared an array of 10 elements. Let's say,

int testArray[10];

You can access the array elements from testArray[0] to testArray[9].

4
Now let's say if you try to access testArray[12]. The element is not available. This
may cause unexpected output (undefined behavior). Sometimes you might get an error
and some other time your program may run correctly.

Hence, you should never access elements of an array outside of its bound.

One dimensional Character Arrays

String is a sequence of characters that are treated as a single data item and terminated
by a null character '\0'. Remember that the C language does not support strings as a
data type. A string is actually a one-dimensional array of characters in C language.
These are often used to create meaningful and readable programs.

For example: The string "home" contains 5 characters including the '\0' character
which is automatically added by the compiler at the end of the string.

Declaring and Initializing a string variables:

// validchar name[13] = "StudyTonight"; char name[10] = {'c','o','d','e','\0'};


// Illegalchar ch[3] = "hello"; char str[4];
str = "hello";

String Input and Output:

%s format specifier to read a string input from the terminal.

But scanf() function, terminates its input on the first white space it encounters.

5
edit set conversion code %[..] that can be used to read a line containing a
variety of characters, including white spaces.

The gets() function can also be used to read character string with white spaces

char str[20];printf("Enter a string");scanf("%[^\n]", &str); printf("%s", str);


char text[20];gets(text);printf("%s", text);

String Handling Functions:

C language supports a large number of string handling functions that can be used to
carry out many of the string manipulations. These functions are packaged in the
string.h library. Hence, you must include string.h header file in your programs to use
these functions.

The following are the most commonly used string handling functions.

Method Description

strcat() It is used to concatenate(combine) two strings

strlen() It is used to show the length of a string

strrev() It is used to show the reverse of a string

strcpy() Copies one string into another

strcmp() It is used to compare two string

strcat() function in C:

Syntax:

strcat("hello", "world");

6
strcat() will add the string "world" to "hello" i.e ouput = helloworld.

strlen() and strcmp() function:

strlen() will return the length of the string passed to it and strcmp() will return the
ASCII difference between first unmatching character of two strings.

int j = strlen("studytonight");
int i=strcmp("study ", "tonight");printf("%d %d",j,i);

12 -1

strcpy() function:

It copies the second string argument to the first string argument.

Example of strcpy() function:

#include<stdio.h>#include<string.h>
int main(){
char s1[50], s2[50];

strcpy(s1, "StudyTonight");
strcpy(s2, s1);

printf("%s\n", s2);

return(0);}

StudyTonight

strrev() function:

7
It is used to reverse the given string expression.

Code snippet for strrev():

#include <stdio.h>
int main(){
char s1[50];

printf("Enter your string: ");


gets(s1);
printf("\nYour reverse string is: %s",strrev(s1));
return(0); }

Enter your string: studytonight

Your reverse string is: thginotyduts

Multidimensional Arrays

In C programming, you can create an array of arrays. These arrays are known as
multidimensional arrays. For example,

float x[3][4];

Here, x is a two-dimensional (2d) array. The array can hold 12 elements. You can
think the array as a table with 3 rows and each row has 4 columns.

8
Two dimensional Array

Similarly, you can declare a three-dimensional (3d) array. For example,

float y[2][4][3];

Here, the array y can hold 24 elements.

Initializing a multidimensional array

Here is how you can initialize two-dimensional and three-dimensional arrays:

Initialization of a 2d array

// Different ways to initialize two-dimensional array


int c[2][3] = {{1, 3, 0}, {-1, 5, 9}};
int c[][3] = {{1, 3, 0}, {-1, 5, 9}};
int c[2][3] = {1, 3, 0, -1, 5, 9};

Initialization of a 3d array

You can initialize a three-dimensional array in a similar way like a two-dimensional


array. Here's an example,

int test[2][3][4] = {
{{3, 4, 2, 3}, {0, -3, 9, 11}, {23, 12, 23, 2}},
{{13, 4, 56, 3}, {5, 9, 3, 5}, {3, 1, 4, 9}}};

Example 1: Two-dimensional array to store and print values

// C program to store temperature of two cities of a week and display it.#include


<stdio.h>const int CITY = 2;const int WEEK = 7;int main(){
int temperature[CITY][WEEK];

// Using nested loop to store values in a 2d array


for (int i = 0; i < CITY; ++i)
{
for (int j = 0; j < WEEK; ++j)

9
{
printf("City %d, Day %d: ", i + 1, j + 1);
scanf("%d", &temperature[i][j]);
}
}
printf("\nDisplaying values: \n\n");

// Using nested loop to display vlues of a 2d array


for (int i = 0; i < CITY; ++i)
{
for (int j = 0; j < WEEK; ++j)
{
printf("City %d, Day %d = %d\n", i + 1, j + 1, temperature[i][j]);
}
}
return 0;
}

Output

City 1, Day 1: 33
City 1, Day 2: 34
City 1, Day 3: 35
City 1, Day 4: 33
City 1, Day 5: 32
City 1, Day 6: 31
City 1, Day 7: 30
City 2, Day 1: 23
City 2, Day 2: 22
City 2, Day 3: 21
City 2, Day 4: 24
City 2, Day 5: 22
City 2, Day 6: 25
City 2, Day 7: 26

Displaying values:

City 1, Day 1 = 33
City 1, Day 2 = 34
City 1, Day 3 = 35
City 1, Day 4 = 33
City 1, Day 5 = 32
City 1, Day 6 = 31
City 1, Day 7 = 30
City 2, Day 1 = 23
City 2, Day 2 = 22
City 2, Day 3 = 21
City 2, Day 4 = 24
City 2, Day 5 = 22
City 2, Day 6 = 25

10
City 2, Day 7 = 26

Example 2: Sum of two matrices

// C program to find the sum of two matrices of order 2*2


#include <stdio.h>int main(){
float a[2][2], b[2][2], result[2][2];

// Taking input using nested for loop


printf("Enter elements of 1st matrix\n");
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
{
printf("Enter a%d%d: ", i + 1, j + 1);
scanf("%f", &a[i][j]);
}

// Taking input using nested for loop


printf("Enter elements of 2nd matrix\n");
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
{
printf("Enter b%d%d: ", i + 1, j + 1);
scanf("%f", &b[i][j]);
}

// adding corresponding elements of two arrays


for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
{
result[i][j] = a[i][j] + b[i][j];
}

// Displaying the sum


printf("\nSum Of Matrix:");

for (int i = 0; i < 2; ++i)


for (int j = 0; j < 2; ++j)
{
printf("%.1f\t", result[i][j]);

if (j == 1)
printf("\n");
}
return 0;
}

Output

Enter elements of 1st matrix

11
Enter a11: 2;
Enter a12: 0.5;
Enter a21: -1.1;
Enter a22: 2;
Enter elements of 2nd matrix
Enter b11: 0.2;
Enter b12: 0;
Enter b21: 0.23;
Enter b22: 23;

Sum Of Matrix:
2.2 0.5
-0.9 25.0

Example 3: Three-dimensional array

// C Program to store and print 12 values entered by the user


#include <stdio.h>int main(){
int test[2][3][2];

printf("Enter 12 values: \n");

for (int i = 0; i < 2; ++i)


{
for (int j = 0; j < 3; ++j)
{
for (int k = 0; k < 2; ++k)
{
scanf("%d", &test[i][j][k]);
}
}
}

// Printing values with proper index.

printf("\nDisplaying values:\n");
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < 3; ++j)
{
for (int k = 0; k < 2; ++k)
{
printf("test[%d][%d][%d] = %d\n", i, j, k, test[i][j][k]);
}
}
}

return 0;
}

12
Output

Enter 12 values:
1
2
3
4
5
6
7
8
9
10
11
12

Displaying Values:
test[0][0][0] = 1
test[0][0][1] = 2
test[0][1][0] = 3
test[0][1][1] = 4
test[0][2][0] = 5
test[0][2][1] = 6
test[1][0][0] = 7
test[1][0][1] = 8
test[1][1][0] = 9
test[1][1][1] = 10
test[1][2][0] = 11
test[1][2][1] = 12

Arrays of Strings

What is an Array of String?

The string is a collection of characters, an array of a string is an array of arrays of


characters. Each string is terminated with a null character. An array of a string is one
of the most common applications of two-dimensional arrays.

scanf( ) is the input function with %s format specifier to read a string as input from
the terminal. But the drawback is it terminates as soon as it encounters the space. To
avoid this gets( ) function which can read any number of strings including white
spaces.

Sting is an array of characters terminated with the special character known as the null
character (“\0”).

Syntax

The syntax for array of string is as follows:

13
Syntax

datatype name_of_the_array[size_of_elements_in_array];
char str_name[size];

Example

datatype name_of_the_array [ ] = { Elements of array };


char str_name[8] = “Strings”;

Str_name is the string name and the size defines the length of the string (number of
characters).

A String can be defined as a one-dimensional array of characters, so an array of


strings is two –dimensional array of characters.

Syntax

char str_name[size][max];

Syntax

char str_arr[2][6] = { {‘g’,’o’,’u’,’r’,’i’,’\0’}, {‘r’,’ a’,’ m’,’\0’}};

Alternatively, we can even declare it as

Syntax

char str_arr[2][6] ={“gouri”, ”ram”};

From the given syntax there are two subscripts first one is for how many strings to
declare and the second is to define the maximum length of characters that each string
can store including the null character. C concept already explains that each character
takes 1 byte of data while allocating memory, the above example of syntax occupies 2
* 6 =12 bytes of memory.

Example

char str_name[8] = {‘s’,’t’,’r’,’i’,’n’,’g’,’s’,’\0’};


By the rule of initialization of array, the above declaration can be written as
char str_name[] = “Strings”;

0 1 2 3 4 5 6 7 Index

Variables 2000 2001 2002 2003 2004 2005 2006 2007 Address

This is a representation of how strings are allocated in memory for the above-declared
string in C.

14
Each character in the string is having an index and address allocated to each character
in the string. In the above representation, the null character (“\0”) is automatically
placed by the C compiler at the end of every string when it initializes the
above-declared array. Usually, strings are declared using double quotes as per the
rules of strings initialization and when the compiler encounters double quotes it
automatically appends null character at the end of the string.

From the above example as we know that the name of the array points to the 0th index
and address 2000 as we already know the indexing of an array starts from 0.
Therefore,

str_name + 0 points to the character “s”


str_name + 1 points to the character “t”

As the above example is for one-dimensional array so the pointer points to each
character of the string.

Examples of Array String in C

Following are the examples:

Example:

#include <stdio.h>
int main()
{
char name[10];
printf("Enter the name: ");
fgets(name, sizeof(name), stdin);
printf("Name is : ");
puts(name);
return 0;
}

Output:

Now for two-dimensional arrays, we have the following syntax and memory
allocation. For this, we can take it as row and column representation (table format).

char str_name[size][max];

In this table representation, each row (first subscript) defines as the number of strings
to be stored and column (second subscript) defines the maximum length of the strings.

char str_arr[2][6] = { {‘g’,’o’,’u’,’r’,’i’,’\0’}, {‘r’,’ a’,’ m’,’\0’}};

15
Alternatively, we can even declare it as

Syntax:

char str_arr[2][8] ={“gouri”, ”ram”};

Index
0 1 2 3 4 5 6 7
Rows
0 g o u r i \0 \0 \0
1 r a m \0 \0 \0 \0 \0

From the above example as we know that the name of the array points to the 0th
string. Therefore,

str_name + 0 points to 0th string “gouri”

str_name + 1 points to 1st string “ram”

As the above example is for two-dimensional arrays so the pointer points to each
string of the array.

Example:

#include <stdio.h>
int main()
{
int i;
char name[2][8] = {
“gouri”,
“ram”
};
for (i = 0; i < 2; i++)
{
printf(“String = %s \n”, name + i, name + i);
}
return 0;
}

Output:

Functions of strings

strcpy(s1,s2); this function copies string s2 innto sting s1.


char s1[10] = “gouri”;

16
char s2 [10] = “ram”;
char s3 [10] ;
strcpy(s3,s2);
result => strcpy(s3,s2) : ram

strcat(s1,s2); this function concatenates strings s1 and s2 , string s2 is appended at the


end of the string s1.
char s1[10] = “gouri”;
char s2 [10] = “ram”;
strcat(s1,s2);
result => strcat(s1,s2) : gouriram

strlen(s1); this function returns the length of the string s1.


char s1[10] = “gouri”;
strlen(s1);
result => 5

strcmp(s1,s2); This function compares both strings s1 and s2.


style="list-style-type: none;">
style="list-style-type: none;">

strchr(s1, ch); these functions find the first occurrence of the given character ch in
the string s1 and the pointer points to this character in the string.

strstr(s1,s2); this finds the first occurrence of string s2 in the string s1 and the pointer
points to the string s2 in the string s1.

With some invalid operations are str_arr[0] = “gouri”; in this operation pointer of the
string is assigned to the constant pointer which is invalid and is not possible, because
the name of the array is a constant pointer.

To avoid this we can assign str_arr by using strcpy(str_arr[0],”gouri”).

Two dimensional character array

1. What is 2D character array in C?

We have successfully learned the basic concepts and different library functions that C
Programming offers. Another interesting concept is the use of 2D character arrays. In
the previous tutorial, we already saw that string is nothing but an array of characters
that ends with a ‘\0’.

2D character arrays are very similar to 2D integer arrays. We store the elements and
perform other operations in a similar manner. A 2D character array is more like a
String array. It allows us to store multiple strings under the same name.

17
2. How to Declaration and Initialization a 2D character array?

A 2D character array is declared in the following manner:

char name[5][10];

The order of the subscripts is important during declaration. The first subscript [5]
represents the number of Strings that we want our array to contain and the second
subscript [10] represents the length of each String. This is static memory allocation.
We are giving 5*10=50 memory locations for the array elements to be stored in the
array.

Initialization of the character array occurs in this manner:

char name[5][10]={
"tree",
"bowl",
"hat",
"mice",
"toon"
};

Let’s see the diagram below to understand how the elements are stored in the memory
location:

The areas marked in green show the memory locations that are reserved for the array
but are not used by the string. Each character occupies 1 byte of storage from the
memory.

3. How to take 2D array Data input from user?

In order to take string data input from the user we need to follow the following
syntax:

for(i=0 ;i<5 ;i++ )


scanf("%s",&name[i][0]);

18
Here we see that the second subscript remains [0]. This is because it shows the length
of the string and before entering any string the length of the string is 0.

4. Printing the array elements

The way a 2D character array is printed is not the same as a 2D integer array. This
is because we see that all the spaces in the array are not occupied by the string entered
by the user.

If we display it in the same way as a 2D integer array we will get unnecessary garbage
values in unoccupied spaces. Here is how we can display all the string elements:

for(i=0 ;i<5 ;i++)


printf("%s\n",name[i]);

This format will print only the string contained in the index numbers specified and
eliminate any garbage values after ‘\0’. All the string library functions that we have
come across in the previous tutorials can be used for the operations on strings
contained in the string array. Each string can be referred to in this form:

name[i][0];

where [i] is the index number of the string that needs to be accessed by library
functions.

5. Program to search for a string in the string array

Let’s implement a program to search for a string(a char array) entered by the user in
a 2D char array or a string array(also entered by the user):

#include <stdio.h>
#include <string.h>
int main() {
char name[5][10],
item[10]; // declaring the string array and the character
// array that will contain the string to be matched
int i, x, f = 0;
/*taking 5 string inputs*/
printf("Enter 5 strings:\n");
for (i = 0; i < 5; i++)
scanf("%s", &name[i][0]);
/*entering the item to be found in the string array*/
printf("Enter the string to be searched:\n");
scanf("%s", &item);
/*process for finding the item in the string array*/
for (i = 0; i < 5; i++) {
x = strcmp(&name[i][0],
item); // compares the string in the array with the item and if
// match is found returns 0 and stores it in variable x
if (x == 0)

19
f = i;
}
/*if match is not found*/
if (f == 0)
printf("the item does not match any name in the list");
/*If the match is found*/
else
printf("Item Found. Item in the array exists at index - %d", f);
return 0;
}
Output:-
Enter 5 strings:
tree
bowl
hat
mice
toon
Enter the string to be searched:
mice
Item Found. Item in the array exists at index - 3

Functions

A function is a block of code that performs a specific task.

Suppose, you need to create a program to create a circle and color it. You can create
two functions to solve this problem:

• create a circle function


• create a color function

Dividing a complex problem into smaller chunks makes our program easy to
understand and reuse.

Types of function

There are two types of function in C programming:

• Standard library functions


• User-defined functions

Standard library functions

The standard library functions are built-in functions in C programming.

These functions are defined in header files. For example,

• The printf() is a standard library function to send formatted output to the


screen (display output on the screen). This function is defined in

20
the stdio.h header file.
Hence, to use the printf() function, we need to include the stdio.h header file
using #include <stdio.h>.
• The sqrt() function calculates the square root of a number. The function is
defined in the math.h header file.

User-defined function

You can also create functions as per your need. Such functions created by the user are
known as user-defined functions.

How user-defined function works?

#include <stdio.h>
void functionName()
{
... .. ...
... .. ...
}

int main()
{
... .. ...
... .. ...

functionName();

... .. ...
... .. ...
}

The execution of a C program begins from the main() function.

When the compiler encounters functionName();, control of the program jumps to

void functionName()

And, the compiler starts executing the codes inside functionName().

The control of the program jumps back to the main() function once code inside the
function definition is executed.

21
Working of C Function

Note, function names are identifiers and should be unique.

This is just an overview of user-defined functions. Visit these pages to learn more on:

• User-defined Function in C programming


• Types of user-defined Functions

Advantages of user-defined function

1. The program will be easier to understand, maintain and debug.


2. Reusable codes that can be used in other programs
3. A large program can be divided into smaller modules. Hence, a large project
can be divided among many programmers.

22
Parameter passing mechanism scope

When a function gets executed in the program, the execution control is transferred
from calling-function to called function and executes function definition, and finally
comes back to the calling function. When the execution control is transferred from
calling-function to called-function it may carry one or number of data values. These
data values are called as parameters.

Parameters are the data values that are passed from calling function to called function.

In C, there are two types of parameters and they are as follows...

• Actual Parameters
• Formal Parameters

The actual parameters are the parameters that are speficified in calling function. The
formal parameters are the parameters that are declared at called function. When a
function gets executed, the copy of actual parameter values are copied into formal
parameters.

In C Programming Language, there are two methods to pass parameters from calling
function to called function and they are as follows...

• Call by Value
• Call by Reference

Call by Value

In call by value parameter passing method, the copy of actual parameter values are
copied to formal parameters and these formal parameters are used in called function.
The changes made on the formal parameters does not effect the values of actual
parameters. That means, after the execution control comes back to the calling
function, the actual parameter values remains same. For example consider the
following program...

Example Program

#include<stdio.h>
#include<conio.h>

void main(){
int num1, num2 ;
void swap(int,int) ; // function declaration
clrscr() ;
num1 = 10 ;
num2 = 20 ;

printf("\nBefore swap: num1 = %d, num2 = %d", num1, num2) ;

23
swap(num1, num2) ; // calling function

printf("\nAfter swap: num1 = %d\nnum2 = %d", num1, num2);


getch() ;
}void swap(int a, int b) // called function
{
int temp ;
temp = a ;
a=b;
b = temp ;
}

Output:

In the above example program, the variables num1 and num2 are called actual
parameters and the variables a and b are called formal parameters. The value of num1
is copied into a and the value of num2 is copied into b. The changes made on
variables a and b does not effect the values of num1 and num2.

Call by Reference

In Call by Reference parameter passing method, the memory location address of the
actual parameters is copied to formal parameters. This address is used to access the
memory locations of the actual parameters in called function. In this method of
parameter passing, the formal parameters must be pointer variables.

That means in call by reference parameter passing method, the address of the actual
parameters is passed to the called function and is recieved by the formal parameters
(pointers). Whenever we use these formal parameters in called function, they directly
access the memory locations of actual parameters. So the changes made on the
formal parameters effects the values of actual parameters. For example consider
the following program...

Example Program

#include<stdio.h>
#include<conio.h>

24
void main(){
int num1, num2 ;
void swap(int *,int *) ; // function declaration
clrscr() ;
num1 = 10 ;
num2 = 20 ;

printf("\nBefore swap: num1 = %d, num2 = %d", num1, num2) ;


swap(&num1, &num2) ; // calling function

printf("\nAfter swap: num1 = %d, num2 = %d", num1, num2);


getch() ;
}void swap(int *a, int *b) // called function
{
int temp ;
temp = *a ;
*a = *b ;
*b = temp ;
}

Output:

In the above example program, the addresses of variables num1 and num2 are copied
to pointer variables a and b. The changes made on the pointer variables a and b in
called function effects the values of actual parameters num1 and num2 in calling
function.

25
Storage classes

Storage Classes are used to describe the features of a variable/function. These features
basically include the scope, visibility and life-time which help us to trace the
existence of a particular variable during the runtime of a program.
C language uses 4 storage classes, namely:

1. auto: This is the default storage class for all the variables declared inside a
function or a block. Hence, the keyword auto is rarely used while writing
programs in C language. Auto variables can be only accessed within the
block/function they have been declared and not outside them (which defines
their scope). Of course, these can be accessed within nested blocks within the
parent block/function in which the auto variable was declared. However, they
can be accessed outside their scope as well using the concept of pointers given
here by pointing to the very exact memory location where the variables resides.
They are assigned a garbage value by default whenever they are declared.

2. extern: Extern storage class simply tells us that the variable is defined
elsewhere and not within the same block where it is used. Basically, the value
is assigned to it in a different block and this can be overwritten/changed in a
different block as well. So an extern variable is nothing but a global variable
initialized with a legal value where it is declared in order to be used elsewhere.
It can be accessed within any function/block. Also, a normal global variable
can be made extern as well by placing the ‘extern’ keyword before its
declaration/definition in any function/block. This basically signifies that we
are not initializing a new variable but instead we are using/accessing the
global variable only. The main purpose of using extern variables is that they
can be accessed between two different files which are part of a large
program.
3. static: This storage class is used to declare static variables which are popularly
used while writing programs in C language. Static variables have a property of
preserving their value even after they are out of their scope! Hence, static

26
variables preserve the value of their last use in their scope. So we can say that
they are initialized only once and exist till the termination of the program.
Thus, no new memory is allocated because they are not re-declared. Their
scope is local to the function to which they were defined. Global static
variables can be accessed anywhere in the program. By default, they are
assigned the value 0 by the compiler.

4. register: This storage class declares register variables which have the same
functionality as that of the auto variables. The only difference is that the
compiler tries to store these variables in the register of the microprocessor if a
free register is available. This makes the use of register variables to be much
faster than that of the variables stored in the memory during the runtime of the
program. If a free register is not available, these are then stored in the memory
only. Usually few variables which are to be accessed very frequently in a
program are declared with the register keyword which improves the running
time of the program. An important and interesting point to be noted here is
that we cannot obtain the address of a register variable using pointers.

To specify the storage class for a variable, the following syntax is to be followed:
Syntax:

storage_class var_data_type var_name;

Functions follow the same syntax as given above for variables. Have a look at the
following C example for further clarification :

// A C program to demonstrate different storage


// classes
#include <stdio.h>
// declaring the variable which is to be made extern
// an initial value can also be initialized to x
int x;
void autoStorageClass()
{
printf("\nDemonstrating auto class\n\n");
// declaring an auto variable (simply
// writing "int a=32;" works as well)
auto int a = 32;
// printing the auto variable 'a'
printf("Value of the variable 'a'"
" declared as auto: %d\n",
a);

27
printf("--------------------------------");
}
void registerStorageClass()
{
printf("\nDemonstrating register class\n\n");
// declaring a register variable
register char b = 'G';
// printing the register variable 'b'
printf("Value of the variable 'b'"
" declared as register: %d\n",
b);
printf("--------------------------------");
}
void externStorageClass()
{
printf("\nDemonstrating extern class\n\n");
// telling the compiler that the variable
// x is an extern variable and has been
// defined elsewhere (above the main
// function)
extern int x;
// printing the extern variables 'x'
printf("Value of the variable 'x'"
" declared as extern: %d\n",
x);
// value of extern variable x modified
x = 2;
// printing the modified values of
// extern variables 'x'
printf("Modified value of the variable 'x'"
" declared as extern: %d\n",
x);
printf("--------------------------------");
}

28
void staticStorageClass()
{
int i = 0;
printf("\nDemonstrating static class\n\n");
// using a static variable 'y'
printf("Declaring 'y' as static inside the loop.\n"
"But this declaration will occur only"
" once as 'y' is static.\n"
"If not, then every time the value of 'y' "
"will be the declared value 5"
" as in the case of variable 'p'\n");
printf("\nLoop started:\n");
for (i = 1; i < 5; i++) {
// Declaring the static variable 'y'
static int y = 5;
// Declare a non-static variable 'p'
int p = 10;
// Incrementing the value of y and p by 1
y++;
p++;
// printing value of y at each iteration
printf("\nThe value of 'y', "
"declared as static, in %d "
"iteration is %d\n",
i, y);
// printing value of p at each iteration
printf("The value of non-static variable 'p', "
"in %d iteration is %d\n",
i, p);
}
printf("\nLoop ended:\n");
printf("--------------------------------");
}

29
int main()
{
printf("A program to demonstrate"
" Storage Classes in C\n\n");
// To demonstrate auto Storage Class
autoStorageClass();
// To demonstrate register Storage Class
registerStorageClass();
// To demonstrate extern Storage Class
externStorageClass();
// To demonstrate static Storage Class
staticStorageClass();
// exiting
printf("\n\nStorage Classes demonstrated");
return 0;
}
Output:

A program to demonstrate Storage Classes in C


Demonstrating auto class
Value of the variable ‘a’ declared as auto: 32
——————————–
Demonstrating register class
Value of the variable ‘b’ declared as register: 71
——————————–
Demonstrating extern class
Value of the variable ‘x’ declared as extern: 0
Modified value of the variable ‘x’ declared as extern: 2
——————————–
Demonstrating static class
Declaring ‘y’ as static inside the loop.
But this declaration will occur only once as ‘y’ is static.
If not, then every time the value of ‘y’ will be the declared value 5 as in the case of
variable ‘p’
Loop started:
The value of ‘y’, declared as static, in 1 iteration is 6
The value of non-static variable ‘p’, in 1 iteration is 11
The value of ‘y’, declared as static, in 2 iteration is 7
The value of non-static variable ‘p’, in 2 iteration is 11
The value of ‘y’, declared as static, in 3 iteration is 8
The value of non-static variable ‘p’, in 3 iteration is 11
The value of ‘y’, declared as static, in 4 iteration is 9

30
The value of non-static variable ‘p’, in 4 iteration is 11
Loop ended:
——————————–
Storage Classes demonstrated

Recursion

The C programming language offers various features which help the programmers in
making their code efficient and simple. In C, Recursion is one of the most complex
and useful concepts.

With the help of recursion, you can solve complex mathematical problems such as
factorial of a number and generating fibonacci series etc.

Let us see what is Recursion in C?

Recursion in C

In C, When a function calls a copy of itself then the process is known as Recursion.
To put it short, when a function calls itself then this technique is known as Recursion.
And the function is known as a recursive function.

You have to be more careful when you are using recursion in your program. You just
cannot use recursion in all your problems because it will make your program more
complex and difficult.

Recursion can be used in case of similar subtasks like sorting, searching, and traversal
problems. While using recursion, you will have to define an exit condition on that
function, if not then it will go into an infinite loop.

NOTE:- Problems that can be solved recursively, can also be solved iteratively.

Syntax of recursive function in C:-

void do_recursion()
{
... .. ...
do_recursion();
... .. ...
}
int main()
{
... .. ...
do_recursion();
... .. ...
}

31
Working of recursion in C:-

Below is a flowchart of how recursion works:-

The recursion will go in an infinite loop until some condition is met. So, to prevent it
from going into an infinite loop, you can make use of the if…else statement or define
an exit condition in the recursive function.

Example:- Infinite loop through recursive function

#include<stdio.h>
int main()
{
printf("TechVidvan Tutorial: Infinite loop through Recursive Function!\n");
main();
return 0;
}

32
The above example will result in an infinite loop. In the above program, we are doing
recursion by calling main() from main(). And also we have not provided any
condition for the program to exit. That’s why it will print the output infinitely.

Types of recursion in C

There are two types of recursion present in the C programming language.

• Direct Recursion
• Indirect Recursion

1. Direct Recursion in C

If a function calls itself directly then the function is known as direct recursive
function.

Example:- Direct Recursive function in C

int fib(int num)


{
if (num==1 || num==2)
return 1;
else
return (fib(num-1)+fib(num-2));
}

In the above example, fib() function is direct recursive. Because the statements inside
the fib() function calls the fib() function directly.

2. Indirect Recursion in C

A function that does not call itself directly then function is known as an indirect
recursive function.

Example:- Indirect Recursive function in C

int first_function(int num)


{
if (num<=2)
return 2;
else
return new_function(num);
}
int new_function(int num)
{
return first_function(num);
}

33
In the above example, first_function() calls the new_function(), which is indeed a new
function. Then this new_function() calls the first_function(). So, it is an indirect
recursive function.

Example:- Finding factorial of a given number

#include <stdio.h>
int factorial(int);
int main()
{
int num=5,fact;
printf("TechVidvan Tutorial: Factorial of a number using recursion!\n\n");
fact = factorial(num);
printf("Factorial of %d is: %d\n",num,fact);
}
int factorial(int num)
{
if (num==0)
{
return 0;
}
else if (num==1)
{
return 1;
}
else
{
return num*factorial(num-1);
}
}

Output:-

TechVidvan Tutorial: Factorial of a number using recursion!

Factorial of 5 is: 120

Recursive Function in C

A recursive function always performs tasks by dividing it into subtasks. In a recursive


function, there has to be an exit() condition and when it is satisfied then the recursion
stops and the final result is returned from the function.

For Example:-

if (condition1)
{
return value1;
}
else if (condition2)

34
{
return value2;
}
else
{
// Statements;
recursive call;
}

Example:- Recursive Function

#include<stdio.h>
int fib(int);
void main ()
{
int num=15,fibo;
printf("TechVidvan Tutorial: Fibonacci series using recursive function!\n\n");
fibo = fib(num);
printf("Result is: %d",fibo);
}
int fib(int num)
{
if (num==0)
{
return 0;
}
else if (num == 1)
{
return 1;
}
else
{
return fib(num-1)+fib(num-2);
}
}

Output:-

TechVidvan Tutorial: Fibonacci series using recursive function!

Result is: 610

Memory allocation of recursive method:-

In C, each recursive function call creates a copy of it in memory. When some data is
returned from the recursive call then the memory releases the copy.

As we all know that all variables, arguments and other things of function get stored in
the stack. And for each recursive call, a separate stack is maintained.

35
Let’s take an example to understand the memory allocation of recursive method.

int print(int num)


{
if(num == 0)
return 0;
else
{
printf("Value is: %d",num);
return print(num-1); // recursive call
}
}

Let’s analyze the above example for num=4. At first, all stacks are maintained. We
have used the if condition in the above example. If the value of num reaches 0 then
the stacks will be deleted one by one by returning 0 to its calling stack.

Advantages of Recursion in C

• Makes the program elegant.


• It adds clarity to the program code and also reduces the time to write the code.
• Reduces time complexity.
• It is best for solving problems based on tree structures.

Disadvantages of Recursion in C

• It is slower than non recursive programs due to the overhead of maintaining


the stack.
• It requires more memory for the stack.
• For better performance, use loops instead of recursion. Because recursion is
slower.

36
Significance of Recursion in C

In C, programmers use recursion many times on their programs due to its ability to
keep the code short and simple. It also enhances the code readability.

Recursion also helps in reducing the run-time of the program code. But you can also
use iteration, it provides much faster functionality than recursion.

You can solve several problems using the recursion in C. Problems like factorial of a
number, fibonacci series in a given range, tree algorithm problems etc. can be solved
easily with recursion.

Why stack overflow occurs in recursion:-

In recursion, if you don’t specify or define the base case then you can face stack
overflow problems.

Example:-

int factorial(int num)


{
// wrong base case
if (num == 10)
return 1;
else
return num*factorial(num-1);
}

In the above example, if you provide factorial(5) then first it will call factorial(4),
factorial(3) and so on but the number will never reach 10. So, here the base case is not
reached then the memory will get exhausted by the factorial() functions on the stack
and it will cause a stack overflow error.

Difference between tailed and non-tailed recursion in C

In a recursive function, if the recursive call is the last thing executed by the recursive
function then the recursive function is known as tail-recursive. And if it is not then it
is called a non-tailed recursive.

Comparing iteration and recursion

Now, let's see the comparison between iteration and recursion. We are comparing
both terms based on some characteristics.

On the basis
Recursion Iteration
of
Basic Recursion is the process of In iteration, there is a repeated

37
calling a function itself within execution of the set of instructions. In
its own code. Iteration, loops are used to execute the
set of instructions repetitively until the
condition is false.
The format of iteration includes
There is a termination
Syntax initialization, condition, and
condition is specified.
increment/decrement of a variable.
The termination condition is
Here, the termination condition is
Termination defined within the recursive
defined in the definition of the loop.
function.
The code size in recursion is
The code size in iteration is larger than
Code size smaller than the code size in
the code size in recursion.
iteration.
If the recursive function does
not meet to a termination Iteration will be infinite, if the control
condition, it leads to an condition of the iteration statement
Infinite
infinite recursion. There is a never becomes false. On infinite loop, it
chance of system crash in repeatedly used CPU cycles.
infinite recursion.
It is always applied to
Applied It is applied to loops.
functions.
Speed It is slower than iteration. It is faster than recursion.
Recursion is generally used
It is used when we have to balance the
where there is no issue of time
Usage time complexity against a large code
complexity, and code size
size.
requires being small.
The time complexity in iteration is
Time relatively lower. We can calculate its
It has high time complexity.
complexity time complexity by finding the no. of
cycles being repeated in a loop.
It has to update and maintain
Stack There is no utilization of stack.
the stack.
It uses more memory as It uses less memory as compared to
Memory
compared to iteration. recursion.
There is an extensive
Overhead overhead due to updating and There is no overhead in iteration.
maintaining the stack.

Pointers

The pointer in C language is a variable which stores the address of another variable.
This variable can be of type int, char, array, function, or any other pointer. The size of
the pointer depends on the architecture. However, in 32-bit architecture the size of a
pointer is 2 byte.

38
Consider the following example to define a pointer which stores the address of an
integer.

1. int n = 10;
2. int* p = &n; // Variable p of type pointer is pointing to the address of the varia
ble n of type integer.

Declaring a pointer

The pointer in c language can be declared using * (asterisk symbol). It is also known
as indirection pointer used to dereference a pointer.

1. int *a;//pointer to int


2. char *c;//pointer to char

Pointer Example

An example of using pointers to print the address and value is given below.

As you can see in the above figure, pointer variable stores the address of number
variable, i.e., fff4. The value of number variable is 50. But the address of pointer
variable p is aaa3.

By the help of * (indirection operator), we can print the value of pointer variable p.

Let's see the pointer example as explained for the above figure.

1. #include<stdio.h>
2. int main(){
3. int number=50;
4. int *p;
5. p=&number;//stores the address of number variable
6. printf("Address of p variable is %x \n",p); // p contains the address of the num
ber therefore printing p gives the address of number.
7. printf("Value of p variable is %d \n",*p); // As we know that * is used to deref
erence a pointer therefore if we print *p, we will get the value stored at the add
ress contained by p.

39
8. return 0;
9. }

Output

Address of number variable is fff4


Address of p variable is fff4
Value of p variable is 50

Pointer to array

1. int arr[10];
2. int *p[10]=&arr; // Variable p of type pointer is pointing to the address of an i
nteger array arr.

Pointer to a function

1. void show (int);


2. void(*p)(int) = &display; // Pointer p is pointing to the address of a function

Pointer to structure

1. struct st {
2. int i;
3. float f;
4. }ref;
5. struct st *p = &ref;

Advantage of pointer

1) Pointer reduces the code and improves the performance, it is used to retrieving
strings, trees, etc. and used with arrays, structures, and functions.

2) We can return multiple values from a function using the pointer.

3) It makes you able to access any memory location in the computer's memory.

Usage of pointer

There are many applications of pointers in c language.

40
1) Dynamic memory allocation

In c language, we can dynamically allocate memory using malloc() and calloc()


functions where the pointer is used.

2) Arrays, Functions, and Structures

Pointers in c language are widely used in arrays, functions, and structures. It reduces
the code and improves the performance.

Address Of (&) Operator

The address of operator '&' returns the address of a variable. But, we need to use %u
to display the address of a variable.

1. #include<stdio.h>
2. int main(){
3. int number=50;
4. printf("value of number is %d, address of number is %u",number,&number);

5. return 0;
6. }

Output

value of number is 50, address of number is fff4

NULL Pointer

A pointer that is not assigned any value but NULL is known as the NULL pointer. If
you don't have any address to be specified in the pointer at the time of declaration,
you can assign NULL value. It will provide a better approach.

int *p=NULL;

In the most libraries, the value of the pointer is 0 (zero).

Pointer Program to swap two numbers without using the 3rd variable.

1. #include<stdio.h>
2. int main(){
3. int a=10,b=20,*p1=&a,*p2=&b;
4.
5. printf("Before swap: *p1=%d *p2=%d",*p1,*p2);
6. *p1=*p1+*p2;
7. *p2=*p1-*p2;
8. *p1=*p1-*p2;
9. printf("\nAfter swap: *p1=%d *p2=%d",*p1,*p2);
10.
11. return 0;

41
12. }

Output

Before swap: *p1=10 *p2=20


After swap: *p1=20 *p2=10

Reading complex pointers

There are several things which must be taken into the consideration while reading the
complex pointers in C. Lets see the precedence and associativity of the operators
which are used regarding pointers.

Operator Precedence Associativity


(), [] 1 Left to right
*, identifier 2 Right to left
Data type 3 -

Here,we must notice that,

• (): This operator is a bracket operator used to declare and define the function.
• []: This operator is an array subscript operator
• * : This operator is a pointer operator.
• Identifier: It is the name of the pointer. The priority will always be assigned to
this.
• Data type: Data type is the type of the variable to which the pointer is intended
to point. It also includes the modifier like signed int, long, etc).

How to read the pointer: int (*p)[10].

To read the pointer, we must see that () and [] have the equal precedence. Therefore,
their associativity must be considered here. The associativity is left to right, so the
priority goes to ().

Inside the bracket (), pointer operator * and pointer name (identifier) p have the same
precedence. Therefore, their associativity must be considered here which is right to
left, so the priority goes to p, and the second priority goes to *.

Assign the 3rd priority to [] since the data type has the last precedence. Therefore the
pointer will look like following.

• char -> 4
• * -> 2
• p -> 1
• [10] -> 3

The pointer will be read as p is a pointer to an array of integers of size 10.

42
Example

How to read the following pointer?

1. int (*p)(int (*)[2], int (*)void))

Explanation

This pointer will be read as p is a pointer to such function which accepts the first
parameter as the pointer to a one-dimensional array of integers of size two and the
second parameter as the pointer to a function which parameter is void and return type
is the integer.

Pointer operators
There are two pointer operators :
1. value at address operator ( * )
2. address of operator ( & )
Value at address operator ( * )
The * is a unary operator. It gives the value stored at a particular address. The ‘value
at address’ operator is also called ‘indirection’ operator.
q = *m;
if m contains the memory address of the variable count, then preceding assignment
statement can places the value of count into q.
Address of operator ( & )
The & is a unary operator that returns the memory address of its operand.
m = & count;
The preceding assignment statement can be “The memory address of the variable
count is places into m”.

The following program that demonstrates the relationships between operators :

\* Pointer to initialize and print the value and address of variable. *\

# include < stdio.h >


int main( )
{

int a = 25 ;
int *b ;
b = &a ;
printf("\n Address of a = %u ", & a) ;

43
printf("\n Address of a = %u ", b) ;
printf("\n Address of b = %u ", & b) ;
printf("\n Value of b = %u ", b) ;
printf("\n Value of a = %d ", a) ;
printf("\n Value of a = %d ", *( &a ) )) ;
printf("\n Value of a = %d ", *b) ;
return ( 0 );

Output of the program :

Address of a = 12345
Address of a = 12345
Address of b = 12345
Value of b = 12345
Value of a = 5
Value of a = 5
Value of a = 5

Uses of pointers

Features of Pointers:

1. Pointers save memory space.


2. Execution time with pointers is faster because data are manipulated with the
address, that is, direct access to
memory location.
3. Memory is accessed efficiently with the pointers. The pointer assigns and
releases the memory as well. Hence it can be said the Memory of pointers is
dynamically allocated.
4. Pointers are used with data structures. They are useful for representing
two-dimensional and multi-dimensional
arrays.
5. An array, of any type can be accessed with the help of pointers, without
considering its subscript range.
6. Pointers are used for file handling.
7. Pointers are used to allocate memory dynamically.
8. In C++, a pointer declared to a base class could access the object of a derived
class. However, a pointer to a derived class cannot access the object of a base
class.

Uses of pointers:

1. To pass arguments by reference


2. For accessing array elements
3. To return multiple values
4. Dynamic memory allocation

44
5. To implement data structures
6. To do system level programming where memory addresses are useful

Arrays and pointers

Relationship Between Arrays and Pointers

An array is a block of sequential data. Let's write a program to print addresses of array
elements.

#include <stdio.h>int main() {


int x[4];
int i;

for(i = 0; i < 4; ++i) {


printf("&x[%d] = %p\n", i, &x[i]);
}

printf("Address of array x: %p", x);

return 0;
}

Output

&x[0] = 1450734448
&x[1] = 1450734452
&x[2] = 1450734456
&x[3] = 1450734460
Address of array x: 1450734448

There is a difference of 4 bytes between two consecutive elements of array x. It is


because the size of int is 4 bytes (on our compiler).

Notice that, the address of &x[0] and x is the same. It's because the variable name x
points to the first element of the array.

Relation between Arrays and Pointers

From the above example, it is clear that &x[0] is equivalent to x. And, x[0] is
equivalent to *x.

Similarly,

45
• &x[1] is equivalent to x+1 and x[1] is equivalent to *(x+1).
• &x[2] is equivalent to x+2 and x[2] is equivalent to *(x+2).
• ...
• Basically, &x[i] is equivalent to x+i and x[i] is equivalent to *(x+i).

Example 1: Pointers and Arrays

#include <stdio.h>int main() {

int i, x[6], sum = 0;

printf("Enter 6 numbers: ");

for(i = 0; i < 6; ++i) {


// Equivalent to scanf("%d", &x[i]);
scanf("%d", x+i);

// Equivalent to sum += x[i]


sum += *(x+i);
}

printf("Sum = %d", sum);

return 0;
}

When you run the program, the output will be:

Enter 6 numbers: 2
3
4
4
12
4
Sum = 29

Here, we have declared an array x of 6 elements. To access elements of the array, we


have used pointers.

In most contexts, array names decay to pointers. In simple words, array names are
converted to pointers. That's the reason why you can use pointers to access elements
of arrays. However, you should remember that pointers and arrays are not the
same.

There are a few cases where array names don't decay to pointers.

46
Example 2: Arrays and Pointers

#include <stdio.h>int main() {

int x[5] = {1, 2, 3, 4, 5};


int* ptr;

// ptr is assigned the address of the third element


ptr = &x[2];

printf("*ptr = %d \n", *ptr); // 3


printf("*(ptr+1) = %d \n", *(ptr+1)); // 4
printf("*(ptr-1) = %d", *(ptr-1)); // 2

return 0;
}

When you run the program, the output will be:

*ptr = 3
*(ptr+1) = 4
*(ptr-1) = 2

In this example, &x[2], the address of the third element, is assigned to the ptr pointer.
Hence, 3 was displayed when we printed *ptr.

And, printing *(ptr+1) gives us the fourth element. Similarly, printing *(ptr-1) gives
us the second element.

Pointers and strings

We know that a string is a sequence of characters which we save in an array. And in C


programming language the \0 null character marks the end of a string.

Creating a string

In the following example we are creating a string str using char character array of size
6.

char str[6] = "Hello";

The above string can be represented in memory as follows.

47
Each character in the string str takes 1 byte of memory space.

Creating a pointer for the string

The variable name of the string str holds the address of the first element of the array
i.e., it points at the starting memory address.

So, we can create a character pointer ptr and store the address of the string str variable
in it. This way, ptr will point at the string str.

In the following code we are assigning the address of the string str to the pointer ptr.

char *ptr = str;

We can represent the character pointer variable ptr as follows.

The pointer variable ptr is allocated memory address 8000 and it holds the address of
the string variable str i.e., 1000.

48
Accessing string via pointer

To access and print the elements of the string we can use a loop and check for the \0
null character.

In the following example we are using while loop to print the characters of the string
variable str.

#include <stdio.h>

int main(void) {

// string variable
char str[6] = "Hello";

// pointer variable
char *ptr = str;

// print the string


while(*ptr != '\0') {
printf("%c", *ptr);

// move the ptr pointer to the next memory location


ptr++;
}

return 0;
}

Using pointer to store string

We can achieve the same result by creating a character pointer that points at a string
value stored at some memory location.

In the following example we are using character pointer variable strPtr to store string
value.

#include <stdio.h>

int main(void) {

// pointer variable to store string


char *strPtr = "Hello";

// temporary pointer variable


char *t = strPtr;

// print the string


while(*t != '\0') {
printf("%c", *t);

49
// move the t pointer to the next memory location
t++;
}

return 0;
}

Note! In the above code we are using another character pointer t to print the
characters of the string as because we don't want to lose the starting address of the
string "Hello" which is saved in pointer variable strPtr.

In the above image the string "Hello" is saved in the memory location 5000 to 5005.

The pointer variable strPtr is at memory location 8000 and is pointing at the string
address 5000.

The temporary variable is also assigned the address of the string so, it too holds the
value 5000 and points at the starting memory location of the string "Hello".

Array of strings

We can create a two dimensional array and save multiple strings in it.

For example, in the given code we are storing 4 cities name in a string array city.

char city[4][12] = {
"Chennai",
"Kolkata",
"Mumbai",
"New Delhi"
};

50
We can represent the city array as follows.

The problem with this approach is that we are allocating 4x12 = 48 bytes memory to
the city array and we are only using 33 bytes.

We can save those unused memory spaces by using pointers as shown below.

char *cityPtr[4] = {
"Chennai",
"Kolkata",
"Mumbai",
"New Delhi"
};

In the above code we are creating an array of character pointer cityPtr of size 4 to
store the name of the four cities.

We can represent the array of pointers as follows.

51
The above array of pointers can be represented in memory as follows.

The cityPtr pointer variable is allocated the memory address 8000 to 8007. Assuming
integer address value takes 2 bytes space. So, each pointer gets 2 bytes.

Name of the cities are saved in locations 1000, 2000, 3000 and 4000.

Accessing values pointed by array of pointers

To access and print the values pointed by the array of pointers we take help of loop as
shown in the following example.

52
#include <stdio.h>

int main(void) {

// array of pointers
char *cityPtr[4] = {
"Chennai",
"Kolkata",
"Mumbai",
"New Delhi"
};

// temporary variable
int r, c;

// print cities
for (r = 0; r < 4; r++) {
c = 0;
while(*(cityPtr[r] + c) != '\0') {
printf("%c", *(cityPtr[r] + c));
c++;
}
printf("\n");
}

return 0;
}

Output:

Chennai
Kolkata
Mumbai
New Delhi

In the above code we are using the r variable to access each row of the pointer. And
we are using the c variable to access each character in a selected row.

Pointer indirection pointers to functions

Pointers have two uses. The first is to store a memory address. The second is to use
the stored memory address to access that points using an indirection.

An indirection in C is denoted by the operand * followed by the name of a pointer


variable. Its meaning is “access the content the pointer points to”. Unfortunately, this
operator is the same as the one to denote pointer data types when declaring pointer
variables. It is very important to have a clear distinction between these two uses of the
operator. When translating a program, the compiler does not check neither that the

53
memory address contained in a pointer is correct, nor that the pointed data is correct.
This feature makes the design of programs using pointer a complex task.

The following program shows the use of the indirection operator (file
pointer_example_2.c):

#include <stdio.h>
int main(int argc, char** argv)
{
int num1, num2;
int *ptr1, *ptr2;

ptr1 = &num1;
ptr2 = &num2;

num1 = 10;
num2 = 20;

*ptr1 = 30;
*ptr2 = 40;

*ptr2 = *ptr1;

return 0;
}

Line 13 assigns the value 30 to the memory location stored in ptr1 through an
indirection. The pointer has the address of num1, thus it is equivalent to assign the
value 30 directly to num1. Analogously, line 14 assigns the value 40 to the address
pointed by ptr2. This assignment is equivalent to assign the value 40 to num2. Line 16
contains two indirections. The right hand side of the assignment obtains the data from
the memory address stored in ptr1 (the address of num1), and this data is assigned to
the memory address stored in ptr2 (the address of num2). Upon program termination,
variable num2 contains the value 30 although it has not been directly assigned.

The following figure shows the evolution of these four variables throughout the
program execution. Again, the memory addresses where they are stored are arbitrary.

54
The coincidence between the indirection operator and the definition of the pointer
type “*” may pose a difficulty when understanding code. For example, the following
line

int *r = *p;

contains two “*” operands. The first defines the type “pointer to integer” and is
followed by a declaration of variable “r”. The second is an indirection and is applied
to the address stored in pointer “p”.

Indirect access to the fields of a structure

Let us suppose that a data structure with name “struct s” has been defined. Applying
the rule to define the pointer types, a pointer to this structure has type “struct s *”. In
the following code fragment a structure is defined and declared, and a pointer is then
declared containing its address.

struct s
{
int x;
char c;
}

struct s element;
struct s *pointer;

pointer = &element;

An indirection with pointer is used only to access the structure fields. This operation
require two operators, the indirection (operator “*”) and the access to the structure
fields (operator “.”). The syntax is then:

(*pointer).x = 10;
(*pointer).c = 'l';

These two operations in C are grouped by the operator “->” that is placed between the
pointer and the name of the field structure. The equivalent notation is then:

pointer->x = 10;
pointer->c = 'l';

The operator “->” is always written next to a pointer pointing to a structure, and
precedes the name of one of the fields of that structure. The following program shows
the use of this operator to copy the content from one structure to another.

/* Definition of the structure */


struct coordinates
{
float x;
float y;

55
float z;
};

int main()
{
/* Declaring two structures */
struct coordinates location1, location2;
/* Declaring two pointers */
struct coordinates *ptr1, *ptr2;

/* Assigning the addresses to the pointers */


ptr1 = &location1;
ptr2 = &location2;

/* Assigning values to the first structure */


ptr1->x = 3.5;
ptr1->y = 5.5;
ptr1->z = 10.5;

/* Copy the values to the second structure */


ptr2->x = ptr1->x;
ptr2->y = ptr1->y;
ptr2->z = ptr1->z;

return 0;
}

A pointer to a pointer is a form of multiple indirection, or a chain of pointers.


Normally, a pointer contains the address of a variable. When we define a pointer to a
pointer, the first pointer contains the address of the second pointer, which points to the
location that contains the actual value as shown below.

A variable that is a pointer to a pointer must be declared as such. This is done by


placing an additional asterisk in front of its name. For example, the following
declaration declares a pointer to a pointer of type int −

int **var;

When a target value is indirectly pointed to by a pointer to a pointer, accessing that


value requires that the asterisk operator be applied twice, as is shown below in the
example −

#include <stdio.h>
int main () {

56
int var;
int *ptr;
int **pptr;

var = 3000;

/* take the address of var */


ptr = &var;

/* take the address of ptr using address of operator & */


pptr = &ptr;

/* take the value using pptr */


printf("Value of var = %d\n", var );
printf("Value available at *ptr = %d\n", *ptr );
printf("Value available at **pptr = %d\n", **pptr);

return 0;}

When the above code is compiled and executed, it produces the following result −

Value of var = 3000


Value available at *ptr = 3000
Value available at **pptr = 3000

Pointers to functions

A pointer to a function points to the address of the executable code of the function.
You can use pointers to call functions and to pass functions as arguments to other
functions. You cannot perform pointer arithmetic on pointers to functions.

For z/OS® XL C/C++, use the __cdecl keyword to declare a pointer to a function as a
C linkage.

The type of a pointer to a function is based on both the return type and parameter
types of the function.

A declaration of a pointer to a function must have the pointer name in parentheses.


Function parameters have precedence over pointers in declarations, so parentheses are
required to alter the precedence and declare a pointer to a function. Without them, the
compiler interprets the declaration as a function that returns a pointer to a specified
return type. For example:
int *f(int a); /* function f returning an int* */
int (*g)(int a); /* pointer g to a function returning an int */
In the first declaration, f is interpreted as a function that takes an int as argument, and
returns a pointer to an int. In the second declaration, g is interpreted as a pointer to a
function that takes an int argument and that returns an int.
You can use a trailing return type in the declaration or definition of a pointer to a
function. For example:
auto(*fp)()->int;

57
In this example, fp is a pointer to a function that returns int. You can rewrite the
declaration of fp without using a trailing return type as int (*fp)(void).

Under z/OS XL C/C++, if you pass a function pointer to a function, or the function
returns a function pointer, the declared or implied linkages must be the same. Use the
extern keyword with declarations in order to specify different linkages.

The following example illustrates the correct and incorrect uses of function pointers
under z/OS XL C/C++ :
#include <stdlib.h>

extern "C" int cf();


extern "C++" int cxxf(); // C++ is included here for clarity;
// it is not required; if it is
// omitted, cxxf() will still have
// C++ linkage.
extern "C" int (*c_fp)();
extern "C++" int (*cxx_fp)();
typedef int (*dft_fp_T)();
typedef int (dft_f_T)();

extern "C" {
typedef void (*cfp_T)();
typedef int (*cf_pT)();
void cfn();
void (*cfp)();
}

extern "C++" {
typedef int (*cxxf_pT)();
void cxxfn();
void (*cxxfp)();
}

extern "C" void f_cprm(int (*f)()) {


int (*s)() = cxxf; // error, incompatible linkages-cxxf has
// C++ linkage, s has C linkage as it
// is included in the extern "C" wrapper
cxxf_pT j = cxxf; // valid, both have C++ linkage
int (*i)() = cf; // valid, both have C linkage

extern "C++" void f_cxprm(int (*f)()) {


int (*s)() = cf; // error, incompatible linkages-cf has C
// linkage, s has C++ linkage as it is
// included in the extern "C++" wrapper
int (*i)() = cxxf; // valid, both have C++ linkage
cf_pT j = cf; // valid, both have C linkage
}

58
main() {

c_fp = cxxf; // error - c_fp has C linkage and cxxf has


// C++ linkage
cxx_fp = cf; // error - cxx_fp has C++ linkage and
// cf has C linkage
dft_fp_T dftfpT1 = cf; // error - dftfpT1 has C++ linkage and
// cf has C linkage
dft_f_T *dftfT3 = cf; // error - dftfT3 has C++ linkage and
// cf has C linkage
dft_fp_T dftfpT5 = cxxf; // valid
dft_f_T *dftfT6 = cxxf; // valid

c_fp = cf; // valid


cxx_fp = cxxf; // valid
f_cprm(cf); // valid
f_cxprm(cxxf); // valid

// The following errors are due to incompatible linkage of function


// arguments, type conversion not possible
f_cprm(cxxf); // error - f_cprm expects a parameter with
// C linkage, but cxxf has C++ linkage
f_cxprm(cf); // error - f_cxprm expects a parameter
// with C++ linkage, but cf has C linkage
}

For z/OS, linkage compatibility affects all C library functions that accept a function
pointer as a parameter.

References to functions

A reference to a function is an alias or an alternative name for a function. You must


initialize all references to functions after they are defined. Once defined, a reference
to a function cannot be reassigned. You can use references to call functions and to
pass functions as arguments to other functions. For example:
int g();

// f is a reference to a function that has no parameters and returns int.


int bar(int(&f)()){

// call function f that is passed as an argument.


return f();
}

int x = bar(g);
You can also use a trailing return type in the declaration or definition of a reference to
a function. In the following example, fp is a reference to a function that returns int.
auto(&fp)()->int;

59
Dynamic memory allocation

Since C is a structured language, it has some fixed rules for programming. One of
them includes changing the size of an array. An array is a collection of items stored at
contiguous memory locations.

As it can be seen that the length (size) of the array above made is 9. But what if there
is a requirement to change this length (size). For Example,

• If there is a situation where only 5 elements are needed to be entered in this


array. In this case, the remaining 4 indices are just wasting memory in this
array. So there is a requirement to lessen the length (size) of the array from 9
to 5.
• Take another situation. In this, there is an array of 9 elements with all 9
indices filled. But there is a need to enter 3 more elements in this array. In this
case, 3 indices more are required. So the length (size) of the array needs to be
changed from 9 to 12.

This procedure is referred to as Dynamic Memory Allocation in C.


Therefore, C Dynamic Memory Allocation can be defined as a procedure in which
the size of a data structure (like Array) is changed during the runtime.
C provides some functions to achieve these tasks. There are 4 library functions
provided by C defined under <stdlib.h> header file to facilitate dynamic memory
allocation in C programming. They are:

1. malloc()
2. calloc()
3. free()
4. realloc()

Let’s look at each of them in greater detail.

C malloc() method

The “malloc” or “memory allocation” method in C is used to dynamically allocate a


single large block of memory with the specified size. It returns a pointer of type void
which can be cast into a pointer of any form. It doesn’t Initialize memory at execution
time so that it has initialized each block with the default garbage value initially.

60
Syntax:

ptr = (cast-type*) malloc(byte-size)For Example:

ptr = (int*) malloc(100 * sizeof(int));


Since the size of int is 4 bytes, this statement will allocate 400 bytes of
memory. And, the pointer ptr holds the address of the first byte in the
allocated memory.

If space is insufficient, allocation fails and returns a NULL pointer.

Example:

#include <stdio.h>
#include <stdlib.h>

int main()
{
// This pointer will hold the
// base address of the block created
int* ptr;
int n, i;
// Get the number of elements for the array
printf("Enter number of elements:");
scanf("%d",&n);
printf("Entered number of elements: %d\n", n);
// Dynamically allocate memory using malloc()
ptr = (int*)malloc(n * sizeof(int));
// Check if the memory has been successfully

61
// allocated by malloc or not
if (ptr == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {
// Memory has been successfully allocated
printf("Memory successfully allocated using malloc.\n");
// Get the elements of the array
for (i = 0; i < n; ++i) {
ptr[i] = i + 1;
}
// Print the elements of the array
printf("The elements of the array are: ");
for (i = 0; i < n; ++i) {
printf("%d, ", ptr[i]);
}
}
return 0;
}
Output:

Enter number of elements: 5


Memory successfully allocated using malloc.
The elements of the array are: 1, 2, 3, 4, 5,

C calloc() method

“calloc” or “contiguous allocation” method in C is used to dynamically allocate


the specified number of blocks of memory of the specified type. it is very much
similar to malloc() but has two different points and these are:
It initializes each block with a default value ‘0’.
It has two parameters or arguments as compare to malloc().

Syntax:

ptr = (cast-type*)calloc(n, element-size);


here, n is the no. of elements and element-size is the size of each element.

62
For Example:

ptr = (float*) calloc(25, sizeof(float));


This statement allocates contiguous space in memory for 25 elements each with
the size of the float.

If space is insufficient, allocation fails and returns a NULL pointer.

Example:

#include <stdio.h>
#include <stdlib.h>

int main()
{

// This pointer will hold the


// base address of the block created
int* ptr;
int n, i;

// Get the number of elements for the array


n = 5;
printf("Enter number of elements: %d\n", n);

// Dynamically allocate memory using calloc()


ptr = (int*)calloc(n, sizeof(int));

// Check if the memory has been successfully


// allocated by calloc or not
if (ptr == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {

// Memory has been successfully allocated


printf("Memory successfully allocated using calloc.\n");

63
// Get the elements of the array
for (i = 0; i < n; ++i) {
ptr[i] = i + 1;
}

// Print the elements of the array


printf("The elements of the array are: ");
for (i = 0; i < n; ++i) {
printf("%d, ", ptr[i]);
}
}

return 0;
}
Output:
Enter number of elements: 5
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,

C free() method

“free” method in C is used to dynamically de-allocate the memory. The memory


allocated using functions malloc() and calloc() is not de-allocated on their own. Hence
the free() method is used, whenever the dynamic memory allocation takes place. It
helps to reduce wastage of memory by freeing it.

Syntax:

free(ptr);

64
Example:

#include <stdio.h>
#include <stdlib.h>

int main()
{

// This pointer will hold the


// base address of the block created
int *ptr, *ptr1;
int n, i;

// Get the number of elements for the array


n = 5;
printf("Enter number of elements: %d\n", n);

// Dynamically allocate memory using malloc()


ptr = (int*)malloc(n * sizeof(int));

// Dynamically allocate memory using calloc()


ptr1 = (int*)calloc(n, sizeof(int));

// Check if the memory has been successfully


// allocated by malloc or not
if (ptr == NULL || ptr1 == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {

// Memory has been successfully allocated


printf("Memory successfully allocated using malloc.\n");

// Free the memory


free(ptr);
printf("Malloc Memory successfully freed.\n");

// Memory has been successfully allocated


printf("\nMemory successfully allocated using calloc.\n");

// Free the memory


free(ptr1);
printf("Calloc Memory successfully freed.\n");
}

return 0;
}

65
Output:
Enter number of elements: 5
Memory successfully allocated using malloc.
Malloc Memory successfully freed.

Memory successfully allocated using calloc.


Calloc Memory successfully freed.

C realloc() method

“realloc” or “re-allocation” method in C is used to dynamically change the memory


allocation of a previously allocated memory. In other words, if the memory previously
allocated with the help of malloc or calloc is insufficient, realloc can be used to
dynamically re-allocate memory. re-allocation of memory maintains the already
present value and new blocks will be initialized with the default garbage value.

Syntax:

ptr = realloc(ptr, newSize);

where ptr is reallocated with new size 'newSize'.

If space is insufficient, allocation fails and returns a NULL pointer.

Example:

#include <stdio.h>
#include <stdlib.h>

int main()
{

// This pointer will hold the

66
// base address of the block created
int* ptr;
int n, i;

// Get the number of elements for the array


n = 5;
printf("Enter number of elements: %d\n", n);

// Dynamically allocate memory using calloc()


ptr = (int*)calloc(n, sizeof(int));

// Check if the memory has been successfully


// allocated by malloc or not
if (ptr == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {

// Memory has been successfully allocated


printf("Memory successfully allocated using calloc.\n");

// Get the elements of the array


for (i = 0; i < n; ++i) {
ptr[i] = i + 1;
}

// Print the elements of the array


printf("The elements of the array are: ");
for (i = 0; i < n; ++i) {
printf("%d, ", ptr[i]);
}

// Get the new size for the array


n = 10;
printf("\n\nEnter the new size of the array: %d\n", n);

// Dynamically re-allocate memory using realloc()


ptr = realloc(ptr, n * sizeof(int));

// Memory has been successfully allocated


printf("Memory successfully re-allocated using realloc.\n");

// Get the new elements of the array


for (i = 5; i < n; ++i) {
ptr[i] = i + 1;
}

// Print the elements of the array


printf("The elements of the array are: ");

67
for (i = 0; i < n; ++i) {
printf("%d, ", ptr[i]);
}

free(ptr);
}

return 0;
}
Output:
Enter number of elements: 5
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,

Enter the new size of the array: 10


Memory successfully re-allocated using realloc.
The elements of the array are: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,

One another example for realloc() method is:

#include <stdio.h>
#include <stdlib.h>
int main()
{
int index = 0, i = 0, n,
*marks; // this marks pointer hold the base address
// of the block created
int ans;
marks = (int*)malloc(sizeof(
int)); // dynamically allocate memory using malloc
// check if the memory is successfully allocated by
// malloc or not?
if (marks == NULL) {
printf("memory cannot be allocated");
}
else {
// memory has successfully allocated
printf("Memory has been successfully allocated by "
"using malloc\n");
printf("\n marks = %pc\n",
marks); // print the base or beginning
// address of allocated memory
do {
printf("\n Enter Marks\n");
scanf("%d", &marks[index]); // Get the marks
printf("would you like to add more(1/0): ");
scanf("%d", &ans);

if (ans == 1) {
index++;

68
marks = (int*)realloc(
marks,
(index + 1)
* sizeof(
int)); // Dynamically reallocate
// memory by using realloc
// check if the memory is successfully
// allocated by realloc or not?
if (marks == NULL) {
printf("memory cannot be allocated");
}
else {
printf("Memory has been successfully "
"reallocated using realloc:\n");
printf(
"\n base address of marks are:%pc",
marks); ////print the base or
///beginning address of
///allocated memory
}
}
} while (ans == 1);
// print the marks of the students
for (i = 0; i <= index; i++) {
printf("marks of students %d are: %d\n ", i,
marks[i]);
}
free(marks);
}
return 0;
}

Output:

69

You might also like