You are on page 1of 24

Department of Computer Science and Engineering

RV College of Engineering®, Bangalore


Programming in C

1.RECURSION

1.1 Introduction:
Recursion means "defining a problem in terms of itself". This is a powerful tool in writing
algorithms. Recursion comes directly from Mathematics, where there are many examples of
expressions written in terms of themselves. For example, the Fibonacci sequence is defined as:
F(i) = F(i-1) + F(i-2).

Using recursive algorithm, certain problems can be solved quite easily. Examples of such
problems are Towers of Hanoi (TOH), Inorder/Preorder/Postorder Tree Traversals, DFS of
Graph.

1.2 How recursion works?

A function that calls itself is known as a recursive function. And, this technique is known as
recursion.
void recurse()
{
... .. ...
recurse();
... .. ...
}

int main()
{
... .. ...
recurse();
... .. ...
}

DEPT. OF CSE 1
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

The recursion continues until some condition is met to prevent it.To prevent infinite recursion,
if...else statement (or similar approach) can be used where one branch makes the recursive call
and other doesn't.

Base condition in recursion:

In recursive program, the solution to base case is provided and solution of bigger problem is
expressed in terms of smaller problems.

int fact(int n)
{
if (n < = 1) // base case
return 1;
else
return n*fact(n-1);
}

In the above example, base case for n < = 1 is defined and larger value of number can be solved
by converting to smaller one till base case is reached.

DEPT. OF CSE 2
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

1.3 Different ways of defining recursion

Some of the ways in which recursive functions are characterized. The characterizations are based
on:

1. whether the function calls itself or not (direct or indirect recursion).


2. whether there are pending operations at each recursive call (tail-recursive or not).
3. the shape of the calling pattern -- whether pending operations are also recursive (linear or
tree-recursive).

Direct Recursion:

A C function is directly recursive if it contains an explicit call to itself. For example, the function
int foo(int x) {

if (x <= 0) return x;

return foo(x - 1);


}
includes a call to itself, so it's directly recursive. The recursive call will occur for positive values
of x.

Indirect Recursion:

A C function foo is indirectly recursive if it contains a call to another function which ultimately
calls foo.

The following pair of functions is indirectly recursive. Since they call each other, they are also
known as mutually recursive functions.

int foo(int x) {

if (x <= 0) return x;

return bar(x);
}

DEPT. OF CSE 3
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

int bar(int y) {
return foo(y - 1);
}

Tail Recursion:

A recursive function is said to be tail recursive if there are no pending operations to be


performed on return from a recursive call.

Tail recursive functions are often said to "return the value of the last recursive call as the value of
the function." Tail recursion is very desirable because the amount of information which must be
stored during the computation is independent of the number of recursive calls. Some modern
computing systems will actually compute tail-recursive functions using an iterative process.

The "infamous" factorial function fact is usually written in a non-tail-recursive manner:

int fact (int n) { /* n >= 0 */

if (n == 0) return 1;

return n * fact(n - 1);


}

Notice that there is a "pending operation," namely multiplication, to be performed on return from
each recursive call. Whenever there is a pending operation, the function is non-tail-recursive.
Information about each pending operation must be stored, so the amount of information is not
independent of the number of calls.

The factorial function can be written in a tail-recursive way:

int fact_aux(int n, int result) {

if (n == 1) return result;

return fact_aux(n - 1, n * result)


}

int fact(n) {

DEPT. OF CSE 4
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

return fact_aux(n, 1);


}

The "auxiliary" function fact_aux is used to keep the syntax of fact(n) the same as before. The
recursive function is really fact_aux, not fact. Note that fact_aux has no pending operations on
return from recursive calls. The value computed by the recursive call is simply returned with no
modification. The amount of information which must be stored is constant (the value of n and the
value of result), independent of the number of recursive calls.

Linear and Tree Recursion:

Another way to characterize recursive functions is by the way in which the recursion grows. The
two basic ways are "linear" and "tree."

A recursive function is said to be linearly recursive when no pending operation involves another
recursive call to the function.

For example, the "infamous" fact function is linearly recursive. The pending operation is simply
multiplication by a scalar, it does not involve another call to fact.

A recursive function is said to be tree recursive (or non-linearly recursive) when the pending
operation does involve another recursive call to the function.

The Fibonacci function fib provides a classic example of tree recursion. The Fibonacci numbers
can be defined by the rule:

fib(n) = 0 if n is 0,
= 1 if n is 1,
= fib(n-1) + fib(n-2) otherwise

For example, the first seven Fibonacci numbers are


Fib(0) = 0
Fib(1) = 1
Fib(2) = Fib(1) + Fib(0) = 1
Fib(3) = Fib(2) + Fib(1) = 2
Fib(4) = Fib(3) + Fib(2) = 3
Fib(5) = Fib(4) + Fib(3) = 5
Fib(6) = Fib(5) + Fib(4) = 8

DEPT. OF CSE 5
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

This leads to the following implementation in C:


int fib(int n) { /* n >= 0 */

if (n == 0) return 0;

if (n == 1) return 1;

return fib(n - 1) + fib(n - 2);


}

Notice that the pending operation for the recursive call is another call to fib. Therefore fib is tree-
recursive.

9.4. Advantages and Disadvantages of Recursion

Recursion provides a clean and simple way to write code. Some problems are inherently
recursive like tree traversals, Tower of Hanoi, etc.
Recursive program has greater space requirements than iterative program as all functions will
remain in stack until base case is reached. It also has greater time requirements because of
function calls and return overhead.

9.5. Example programs


Factorial of a number

#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;

DEPT. OF CSE 6
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

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


return 0;
}

Fibonacci Series

#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;
}

Sum of Natural Numbers

#include <stdio.h>
int sum(int n);

int main()
{
int number, result;

printf("Enter a positive integer: ");

DEPT. OF CSE 7
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

scanf("%d", &number);

result = sum(number);

printf("sum=%d", result);
}

int sum(int num)


{
if (num!=0)
return num + sum(num-1); // sum() function calls itself
else
return num;
}

Initially, the sum() is called from the main() function with number passed as an argument.

Suppose, the value of num is 3 initially. During next function call, 2 is passed to the sum()
function. This process continues until num is equal to 0.

When num is equal to 0, the if condition fails and the else part is executed returning the sum of
integers to the main() function.

DEPT. OF CSE 8
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

Ackerman Function

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

DEPT. OF CSE 9
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

int ack_recursive(int m, int n) {


if (m == 0) {
return n + 1;
}

if (n == 0) {
return ack_recursive(m - 1, 1);
}

return ack_recursive(m - 1, ack_recursive(m, n - 1));


}

int ack_nonrecursive(int m, int n, int *status) {


int value[n];
size_t size = 0;

for (;;) {
if (m == 0) {
n++;
if (size-- == 0) {
*status = EXIT_SUCCESS;
break;
}
m = value[size];
continue;
}

if (n == 0) {
m--;
n = 1;
continue;

DEPT. OF CSE 10
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

size_t index = size++;


value[index] = m - 1;
n--;
}

return n;
}

int main(void) {
for (int m = 0; m < 2; m++) {
for (int n = 0; n < 2; n++) {
int status;
assert(ack_recursive(m, n) == ack_nonrecursive(m, n, &status) && status == EXIT_SUCCESS);
}
}
}

Merge Sort
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void merge(int a[],int l,int m,int h)
{
int i,j,k,c[10000];
i=k=l;
j=m+1;
while(i<=m&&j<=h)
{
if(a[i]<a[j])
c[k++]=a[i++];
else
c[k++]=a[j++];
}

DEPT. OF CSE 11
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

while(i<=m)
c[k++]=a[i++];
while(j<=h)
c[k++]=a[j++];
for(i=l;i<k;i++)
a[i]=c[i];
}
void mergesort(int a[],int l,int h)
{
int m;
if(l<h)
{
m=(l+h)/2;
mergesort(a,l,m);
mergesort(a,m+1,h);
merge(a,l,m,h);
}
}

main()
{
int a[600],i,j,n;
printf("MERGE SORT\n");
printf("\nenter the size of array:");
scanf("%d",&n);
printf("\nenter the elements one by one\n");
for(i=0;i<n;i++)
scanf("%d",&a[i]);
count=0;
mergesort(a,0,n-1);
printf("\narray after sorting:");
for(i=0;i<n;i++)
printf("\t%d",a[i]);
}

Quick Sort
#include<stdio.h>

DEPT. OF CSE 12
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

#include<math.h>
int partition(int a[],int l,int h)
{
int i,j,temp,key;
key=a[l];
i=l+1;
j=h;
while(1)
{
count++;
while(i<h&&key>=a[i])
i++;
while(key<a[j])

j--;

if(i<j)
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
else
{
temp=a[l];
a[l]=a[j];
a[j]=temp;
return j;
}
}
}
void quicksort(int a[],int l,int h)
{
int p;
if(l<h)
{
p=partition(a,l,h);
quicksort(a,l,p-1);

DEPT. OF CSE 13
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

quicksort(a,p+1,h);
}
}
main()
{
int a[600],i,j,n;
printf("QUICK SORT\n");
printf("\nenter the size of arry: ");
scanf("%d",&n);
printf("\nenter the elements one by one\n");
for(i=0;i<n;i++)
scanf("%d",&a[i]);
count=0;
quicksort(a,0,n-1);
printf("\narrau after sorting: ");
for(i=0;i<n;i++)
printf("\t%d",a[i]);
}

DEPT. OF CSE 14
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

2. POINTERS
2.1 Introduction:
Pointer is a derived data type in C language. The variables that holds memory addresses are
called pointer variables. Pointers are used in C program to access the memory and
manipulate the address.

The pointer operators are & (Address operator) and *(Dereferencing operator or
Indirection operator).

2.2 Accessing the address of a variable:

The actual location of a variable in memory is system dependent. A programmer cannot know
the address of a variable immediately. We can retrieve the address of a variable by using the
address of (&) operator. Let’s look at the following example:

1 int a = 10;
2 int *p;
3 p = &a;

In the above example, let the variable a is stored at memory address 5000. This can be retrieved
by using the address of operator as &a. So the value stored in variable p is 5000 which is the
memory address of variable a. So, both the variable a, and p point to the same memory location.

2.3 Declaring and initializing of pointer variables:

Declaration of Pointer Variables:

DEPT. OF CSE 15
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

Since pointer variables contain addresses that belong to a separate data type, they must be
declared as pointers before we use them. The declaration of a pointer variable has the following
form:
General Form:
datatype *pt_name;
This tells the compiler three things about the variable pt_name.

1. The asterisk(*) tells that the variable pt_name is a pointer variable.


2. pt_name needs a memory location.
3. pt_name points to variable of type data type.

Different forms of declaring integer pointer variables:


Ex: int *p;
int* p;
int * p;
Declaration of float pointer variable
Ex: float *p;
Declaration of char pointer variable
Ex: char *p;
Declaration of double pointer variable
Ex: double *p;

Initialization of Pointer Variables:


int i, *p1=&i; //Address of variable i is stored in pointer variable p1

Variable Name Address Contents


i 5600 35

p1 6000 5600

int *p1=&i,i; ----------> Wrong

DEPT. OF CSE 16
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

Pointer variables can be initialized with the values NULL and 0.


Ex: int *p=NULL;
int *p=0;
Same Pointer can point to different data variables in different statements.
Ex: int x, y, z,*p;
p=&x; p=&y; p=&z;

Different pointers can be used to point to same data variable.


Ex: int x;
int *p1=&x;
int *p2=&x;
int *p3=&x;

2.4 Accessing a variable using pointer


Once a pointer has been assigned the address of a variable, the question remains as to
how to access the value of the variable using the pointer. This is done by using *(asterisk),
usually known as the indirection operator.
int i,*p,n; // p is a pointer variable and i is a integer variable
i=10;
p=&i; // p holds the address of variable i
n=*p; // Returns the value of variable i
This is equivalent to n=*&i; or n=i.

2.5 Chain of Pointers


Pointer can point to another pointer.
Ex:

main()
{
int x, *p1,**p2;

DEPT. OF CSE 17
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

x=100;
p1=&x;
p2=&p1;
printf(“%d”,**p2); //Output is 100
}

In this example, pointer variable p2 contains the address of the pointer variable p1, which
points to the location that contains the desired value. This is known as multiple indirections.

2.6 Pointer Expressions


1) Pointer variables can be used in expressions.
Ex: int *p1,*p2;
y=*p1 * *p2;
Sum=Sum+ *p1;
Z=5* -*p2/ *p1;
2) Short hand operators can be used with pointers.
Ex: int *p1,*p2;
p1++;
-p2; sum += *p2;
3) Pointers can be compared using relational operators.
Ex: p1>p2, p1==p2, p1!=p2

2.7 Pointer Increments and Scale Factor


When a pointer is incremented, its value is increased by the length of the datatype it
points to. This length is called scale factor.
Ex:
int *p; i=10;
p=&i;
p=p+1;

DEPT. OF CSE 18
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

In this example, if the address value of i is 2800, then pointer variable p holds the address
of i, i.e. 2800. If the pointer variable is incremented by 1, it becomes 2802.

2.8 Pointers and Arrays


When an array is declared, the compiler allocates the base address and sufficient amount
of memory to contain all the elements in contiguous memory location. The base address is the
location of the first element (index 0) of the array.
Ex: int *p;
p=&a[0];
p+1=&a[1];
p+2=&a[2];
The address of an element is calculated using its index and scale factor of the data type.
Ex: Address of a[3]= Base Address+(3*ScaleFactor of int)
Pointers can be used to access array elements instead of using array indexing.
Ex: *(p+3) ----> It is similar to a[3].

2.9 Pointers And Character Strings

A pointer may be defined as pointing to a character string. A pointer which pointing to an array
which content is string, is known as pointer to array of strings.

#include <stdio.h>

main()
{
char *text_pointer = "Good morning!";

for( ; *text_pointer != '\0'; ++text_pointer)


printf("%c", *text_pointer);

DEPT. OF CSE 19
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

Program Print the Address of the Character Array

#include<stdio.h>

int main()
{
int i;

char *arr[4] = {"C","C++","Java","VBA"};


char *(*ptr)[4] = &arr;

for(i=0;i<4;i++)
printf("Address of String %d : %u\n",i+1,(*ptr)[i]);

return 0;
}
Output:
Address of String 1 = 178
Address of String 2 = 180
Address of String 3 = 184
Address of String 4 = 189

Program to Print Contents of character array


#include<stdio.h>

int main()
{
int i;

char *arr[4] = {"C","C++","Java","VBA"};


char *(*ptr)[4] = &arr;

for(i=0;i<4;i++)
printf("String %d : %s\n",i+1,(*ptr)[i]);

return 0;
}

DEPT. OF CSE 20
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

Output :

String 1 = C
String 2 = C++
String 3 = Java
String 4 = VBA

Pointer to String and Pre-increment Operator

#include<stdio.h>

int main()
{
int i;

char *arr[4] = {"C","C++","Java","VBA"};


char *(*ptr)[4] = &arr;

printf("%s",++(*ptr)[2]);

return 0;
}

Output:

Ava

Advantages of Pointers:

1. Pointers can be used to return multiple values from User Defined Function.
2. It allows C language to support dynamic memory management.
3. It increases the execution speed and reduce the program execution time.
4. It provides an efficient tool for manipulating dynamic data structures such as structures,
linked lists, queues, stacks and trees.

DEPT. OF CSE 21
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

Example Questions:
1) Write a program to find the sum of all elements stored in an array using pointers?

main( )
{
int *p,sum,i;
int a[5]={10,20,30,40,50};
i=0;
p=a;
while(a<5)
{
printf(“%d%d%u”, i,*p,p);
sum=sum+*p;
i++; p++;
}
printf(“%d”, sum);
}

2) Find the output of the following program: Assume the address values of m, ptr and y are
2000, 3000 and 4500 respectively.
main()
{
int m;
int *ptr;

m=15;
ptr=&m;
y=*ptr;
printf(“Value of m is %d\n\n”, m);
printf(“%d is stored at address %u \n”, m,&m);
printf(“%u%u \n”, ptr, &ptr);
printf(“%d is stored at address %u \n”, y, &y);
*ptr=30;
printf(“\n Now m=%d\n”,x);
}

DEPT. OF CSE 22
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

Output:
15
15 is stored at address 2000
2000 3000
15 is stored at address 4500
Now m=30

3) Write a program to perform the arithmetic operations using pointers

main( )
{
int a, b,*p1,*p2;
int sum,diff,prod,div;
a=200, b=10;
p1=&a;p2=&b;

sum=*p1 + *p2;
diff=*p1 - *p2;
prod=*p1 * *p2;
div=*p1 / *p2;
printf(“%d%d%d%d”, sum,diff,prod,div);
}

Output:
210
190
2000
20

4) Evaluate the expressions in the following program:


main()
{
int a, b,*p3,*p4,i,j,k;
a=31,b=10,p3=&a,p4=&b;
i=*p3 * *p4-6;
j=6 * - *p3/ *p4+20;
a=*p4+34; b=*p4-6; k=*p3 * *p4-8;
}

DEPT. OF CSE 23
Department of Computer Science and Engineering
RV College of Engineering®, Bangalore
Programming in C

Output:

i=304
j=2
a=44
b=4
k=302

DEPT. OF CSE 24

You might also like