Author: saqibkhan

  • Static Variables

    By default, a C variable is classified as an auto storage type. A static variable is useful when you want to preserve a certain value between calls to different functions. Static variables are also used to store data that should be shared between multiple functions.

    Static Variables

    The static variables belong to the static storage class, they are initialized only once and preserve the values till the end of the program, The static keyword is used to declare the static variables.

    Features of Static Variables

    The following are some of the features of static variables in C programming language −

    • The compiler allocates space to a static variable in the computers main memory.
    • Unlike auto, a static variable is initialized to zero and not garbage.
    • A static variable is not re-initialized on every function call, if it is declared inside a function.
    • A static variable has local scope.

    Declare a Static Variable

    To declare a static variable in C language, use the static keyword and assign the initial value. Following is the syntax to declare a static variable:

    static datatype var = value;

    Here,

    • datatype represents the type of variable like int, char, float, etc.
    • var is the name of variable given by user.
    • value is any value given to initialize the variable. By default, it is zero.

    Examples of Static Variables in C

    Example: Using Static Variable

    Here is an example of how you can use a static variable in C language −

    #include <stdio.h>intmain(){autoint a =-28;staticint b =8;printf("The value of auto variable: %d\n", a);printf("The value of static variable b: %d\n",b);if(a !=0)printf("The sum of static variable and auto variable: %d\n",(b+a));return0;}

    Output

    When you run this code, it will produce the following output −

    The value of auto variable: -28
    The value of static variable b: 8
    The sum of static variable and auto variable: -20
    

    Example: Create Counter Function W/O Using Static Variable

    In this example, x is an auto variable by default and initialized to 0 every time when the counter() function is called. On each subsequent call, it gets re-initialized.

    #include <stdio.h>intcounter();intmain(){counter();counter();counter();return0;}intcounter(){int x;printf("Value of x as it enters the function: %d\n", x);
       x++;printf("Incremented value of x: %d\n", x);}

    Output

    Run the code and check its output −

    Value of x as it enters the function: 0
    Incremented value of x: 1
    Value of x as it enters the function: 0
    Incremented value of x: 1
    Value of x as it enters the function: 0
    Incremented value of x: 1
    

    However, when the variable x in the counter() function is declared as static, it is initialized to “0” when the counter() function is called for the first time. On each subsequent call, it is not re-initialized. Instead, it retains the earlier value.

    Example: Create Counter Using Static Variable

    Change the declaration of “x” to “static int x = 0;” and run the program again −

    #include <stdio.h>intcounter();intmain(){counter();counter();counter();return0;}intcounter(){staticint x =0;printf("Value of x as it enters the function: %d\n", x);
       x++;printf("Incremented value of x: %d\n", x);}

    Output

    Now, when you run this code, it will produce the following output −

    Value of x as it enters the function: 0
    Incremented value of x: 1
    Value of x as it enters the function: 1
    Incremented value of x: 2
    Value of x as it enters the function: 2
    Incremented value of x: 3
    

    Passing Static Variable to Function

    You can pass a static variable to a function. However, a formal parameter cannot be declared as static, as C uses the function parameters as local auto variables inside a function.

    Example

    In this code, we pass a static variable to a function. However, the change in its value is not reflected in the calling function.

    #include <stdio.h>intmyfunction(int x);intmain(){staticint x =5;myfunction(x);printf("in main - x:%d\n", x);return0;}intmyfunction(int x){
       x++;printf("Incremented value of x: %d\n", x);}

    Output

    Run the coce and check its output −

    Incremented value of x: 6
    in main - x:5
    

    Similarities Between Static and Global Variables

    A static variable has certain similarities with a global variable. Both of them, if not explicitly initialized, both are initialized to “0” (for numeric types) or “null pointers” (for pointers).

    The scope of a static variable is restricted to the function or the block in which it is declared. This is unlike a global variable, which is accessible throughout the program. Also, a static variable can be imported in another code file, as we do by using the extern keyword.

    Example

    You can declare a global variable as static too. Take a look at the following example −

    #include <stdio.h>intmyfunction();staticint x =5;intmain(){myfunction(x);printf("Inside the main function, x: %d\n", x);return0;}intmyfunction(){
       x++;printf("Incremented value of x: %d\n", x);}

    Output

    When you run this code, it will produce the following output −

    Incremented value of x: 6
    Inside the main function, x: 6
    

    It is better to use static variables to be accessible only within a file. On the other hand, use global (with extern) variables to be accessible from anywhere in a program (if declared extern in other files).

  • Scope Rules

    A scope in any programming is a region of the program where a defined variable can have its existence and beyond that variable it cannot be accessed. There are three places where variables can be declared in C programming language −

    • Inside a function or a block which is called local variables.
    • Outside of all functions which is called global variables.
    • In the definition of function parameters which are called formal parameters.

    Let us understand what are local and global variables, and formal parameters.

    Local Variables

    Variables that are declared inside a function or block are called local variables. They can be used only by statements that are inside that function or block of code. Local variables are not known to functions outside their own.

    Example

    The following example shows how local variables are used. Here all the variables a, b, and c are local to main() function.

    #include <stdio.h>intmain(){/* local variable declaration */int a, b;int c;/* actual initialization */
      a =10;
      b =20;
      c = a + b;printf("value of a = %d, b = %d and c = %d\n", a, b, c);return0;}

    Global Variables

    Global variables are defined outside a function, usually on top of the program. Global variables hold their values throughout the lifetime of your program and they can be accessed inside any of the functions defined for the program.

    A global variable can be accessed by any function. That is, a global variable is available for use throughout your entire program after its declaration.

    Example

    The following program show how global variables are used in a program.

    #include <stdio.h>/* global variable declaration */int g;intmain(){/* local variable declaration */int a, b;/* actual initialization */
      a =10;
      b =20;
      g = a + b;printf("value of a = %d, b = %d and g = %d\n", a, b, g);return0;}

    A program can have same name for local and global variables but the value of local variable inside a function will take preference. Here is an example −

    Example

    #include <stdio.h>/* global variable declaration */int g =20;intmain(){/* local variable declaration */int g =10;printf("value of g = %d\n",  g);return0;}

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

    value of g = 10
    

    Formal Parameters

    Formal parameters, are treated as local variables with-in a function and they take precedence over global variables. Following is an example −

    Example

    #include <stdio.h>/* global variable declaration */int a =20;intmain(){/* local variable declaration in main function */int a =10;int b =20;int c =0;printf("value of a in main() = %d\n",  a);
      c =sum( a, b);printf("value of c in main() = %d\n",  c);return0;}/* function to add two integers */intsum(int a,int b){printf("value of a in sum() = %d\n",  a);printf("value of b in sum() = %d\n",  b);return a + b;}

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

    value of a in main() = 10
    value of a in sum() = 10
    value of b in sum() = 20
    value of c in main() = 30
    

    Initializing Local and Global Variables

    When a local variable is defined, it is not initialized by the system, you must initialize it yourself. Global variables are initialized automatically by the system when you define them as follows −

    Data TypeInitial Default Value
    int0
    char‘\0’
    float0
    double0
    pointerNULL

    It is a good programming practice to initialize variables properly, otherwise your program may produce unexpected results, because uninitialized variables will take some garbage value already available at their memory location.

  • Predefined Identifier __func__

    The predefined identifier __func__ in C programming is a special identifier introduced in the C99 standard. It provides the name of the current function as a string literal, making error tracking and debugging more convenient.

    Debugging and logging frequently require identifying where an issue occurs in the code. To simplify the process, the C99 standard introduced the predefined identifier __func__.

    A Simple Example of Using __func__ in a C Program

    Before we start discussing __func__ in detail, let us write a sample program and predict its output. The following C program to shows a glimpse of how the Predefined Identifier __func__ works −

    #include <stdio.h>intmain(){// %s read the stringprintf("%s",__func__);return0;}

    When you run this code, it will produce the following output −

    main
    

    The predefined identifier “__func__” represents the name of the current function as a string. Inside main(), it expands to “main“, so the program prints the function’s name.

    What is __func__ ?

    __func__ is a predefined identifier which is automatically available inside every function. It expands to a const char[] containing the name of the current function.

    staticconstchar__func__[]="function-name";

    Unlike other predefined macros such as __FILE__ or __LINE__, __func__ is not a macro, but rather a predefined identifier.

    Here is its syntax. It can be used directly inside any function to gets its name as a string.

    __func__

    Example: Basic Usages

    In this example, we use the __func__ identifier to display the function name −

    #include <stdio.h>voidgreet(){printf("Currently in function: %s\n",__func__);}intmain(){printf("Currently in function: %s\n",__func__);greet();return0;}

    Following is the output of the above code −

    Currently in function: main
    Currently in function: greet
    

    Error Logging with __func__

    Error logging is the process of recording information about error, warning, or unusual behavior that occurs while a program is running.

    Rather than terminating execution or displaying a general error message, programs log the details of the error in a file, console, or logging system. This information helps developers in determining what and where the error occurred.

    Example: Error Logging with __func__

    In this example, we use __func__ to log error details on the console −

    #include <stdio.h>#define LOG_ERROR(msg) \
       printf("Error in function %s: %s\n", __func__, msg)voiddisplayData(int x){if(x <0){LOG_ERROR("Negative value not allowed");return;}printf("Processing value: %d\n", x);}intmain(){displayData(10);displayData(-5);return0;}

    Here is its output −

    Processing value: 10
    Error in function displayData: Negative value not allowed
    

    Key Features of __func__

    Given below are some of the key features of __func__ −

    • Automatic Availability − It is built into the language. There is no need to include the header file for it.
    • Function Scope − Available only inside the function in which it appears.
    • String Literal − Represents the function name as a const char[].
    • Debugging Friendly − Often used in logging systems to report the exact function where an error occurs.

    Conclusion

    The predefined identifier __func__, introduced in the C99 standard, provides the name of the current function as a string literal. It is a basic but effective feature that improves debugging, error logging, and program monitoring by allowing developers to quickly identify the code where an error occurred.

  • Recursion

    Recursion is the process by which a function calls itself. C language allows writing of such functions which call itself to solve complicated problems by breaking them down into simple and easy problems. These functions are known as recursive functions.

    What is a Recursive Function in C?

    A recursive function in C is a function that calls itself. A recursive function is used when a certain problem is defined in terms of itself. Although it involves iteration, using iterative approach to solve such problems can be tedious. Recursive approach provides a very concise solution to seemingly complex problems.

    Syntax

    This is how a general recursive function looks like −

    voidrecursive_function(){recursion();// function calls itself}intmain(){recursive_function();}

    While using recursion, programmers need to be careful to define an exit condition from the function, otherwise it will go into an infinite loop.

    Why Recursion is Used in C?

    Recursion is used to perform complex tasks such as tree and graph structure traversals. Popular recursive programming solutions include factorial, binary search, tree traversal, tower of Hanoi, eight queens problem in chess, etc.

    A recursive program becomes concise, it is not easily comprehendible. Even if the size of the code may reduce, it needs more resources of the processor, as it involves multiple IO calls to the function.

    Factorial Using Recursion

    Recursive functions are very useful to solve many mathematical problems such as calculating the factorial of a number, generating Fibonacci series, etc.

    The most popular example of recursion is calculation of factorial. Mathematically, a factorial is defined as −

     
    n!= n X(n-1)!

    It can be seen that we use factorial itself to define factorial. Hence this is a fit case to write a recursive function. Let us expand the above definition for calculating the factorial value of 5.

    5!=5 X 4!5 X 4 X 3!5 X 4 X 3 X 2!5 X 4 X 3 X  2 X 1!5 X 4 X 3 X  2 X 1=120

    While we can perform this calculation using a loop, its recursive function involves successively calling it by decrementing the number till it reaches 1.

    Example: Non-Recursive Factorial Function

    The following program shows how you can use a non-recursive function to calculate the factorial of a number −

    #include <stdio.h>#include <math.h>// function declarationintfactorial(int);intmain(){int a =5;int f =factorial(a);printf("a: %d \n", a);printf("Factorial of a: %d", f);}intfactorial(int x){int i;int f =1;for(i =5; i >=1; i--){
    
      f *= i;}return f;}</code></pre>

    Output

    When you run this code, it will produce the following output −

    a: 5 
    Factorial of a: 120
    

    Example: Recursive Factorial Function

    Let us now write a recursive function for calculating the factorial of a given number.

    The following example calculates the factorial of a given number using a recursive function −

    #include <stdio.h>#include <math.h>/* function declaration */intfactorial(int i){if(i <=1){return1;}return i *factorial(i -1);}intmain(){int a =5;int f =factorial(a);printf("a: %d \n", a);printf("Factorial of a: %d", f);return0;}

    Output

    Run the code and check its output −

    a: 5 
    Factorial of a: 120
    

    When the main() function calls the factorial() function by passing the variable "a", its value is stored in "i". The factorial() function successively calls itself.

    In each call, the value of "i" is multiplied by its earlier value after reducing it by 1, till it reaches 1. As it reaches 1, the product of all the values between the initial value of the argument and 1 is returned to the main() function.

    Binary Search Using Recursion

    Let us have a look at another example to understand how recursion works. The problem at hand is to check whether a given number is present in an array.

    While we can perform a sequential search for a certain number in the list using a for loop and comparing each number, the sequential search is not efficient, especially if the list is too long.

    The binary search algorithm checks if the index "start" is greater than the index "end". Based on the value present at the variable "mid", the function is called again to search for the element.

    We have a list of numbers arranged in ascending order. Then we find the midpoint of the list and restrict the checking to either left or right of the midpoint, depending on whether the desired number is less than or greater than the number at the midpoint.

    Example: Recursive Binary Search

    The following code implements the recursive binary searching technique −

    #include <stdio.h>intbSearch(int array[],int start,int end,int element){if(end >= start){int mid = start +(end - start )/2;if(array[mid]== element)return mid;if(array[mid]> element)returnbSearch(array, start, mid-1, element);returnbSearch(array, mid+1, end, element);}return-1;}intmain(void){int array[]={5,12,23,45,49,67,71,77,82};int n =9;int element =67;int index =bSearch(array,0, n-1, element);if(index ==-1){printf("Element not found in the array ");}else{printf("Element found at index: %d", index);}return0;}

    Output

    Run the code and check its output −

    Element found at index: 5
    

    Fibonacci Series Using Recursion

    In Fibonacci series, a number is the sum of its previous two numbers. To generate Fibonacci series, the ith number is the addition of i−1 and i−2.

    Example

    The following example generates the first 10 numbers in the Fibonacci series for a given number using a recursive function −

    #include <stdio.h>intfibonacci(int i){if(i ==0){return0;}if(i ==1){return1;}returnfibonacci(i-1)+fibonacci(i-2);}intmain(){int i;for(i =0; i <10; i++){printf("%d\t\n",fibonacci(i));}return0;}

    Output

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

    0	
    1	
    1	
    2	
    3	
    5	
    8	
    13	
    21	
    34
    

    Implementing recursion in a program is difficult for beginners. While any iterative process can be converted in a recursive process, not all cases of recursion can be easily expressed iteratively.

  • Return Statement

    The return statement terminates the execution of a function and returns control to the calling function. Every function should have a return statement as its last statement. While using the returns statement, the return type and returned value (expression) must be the same.

    Syntax of return Statement

    Here is the syntax of the return statement:

    return value_or_expression;

    The following main() function shows return as its last statement −

    intmain(){// function body;return0;}

    The main() function returning 0 indicates the successful completion of the function. To indicate failure of the function, a non−zero expression is returned.

    The void return statement

    A function’s return type can be void. In such a case, return statement is optional. It may be omitted, or return without any expression is used.

    Example

    #include <stdio.h>/* function declaration */voidtest(){return;}intmain(){test();printf("end");return0;}

    Return type mismatch in return statement

    Each function in the program must have a forward declaration of its prototype. By default, each function returns an integer. However, function of other return types without prototype is not accepted.

    Example

    intmain(){test(5);printf("end");return0;}floattest(int a){return1.1;}

    Output

    Error: C:\Users\mlath\test.c|12|error: conflicting types for 'test'
    

    This is because, function without prototype is assumed as of int type, which conflicts with the definition.

    The same error occurs if the return type of a function in the prototype doesn’t match with the type of return expression, an error is reported as below −

    floattest(int);intmain(){test(5);printf("end");return0;}floattest(float a){return1.1;}

    Multiple return values with return statement

    A function can be defined with more than one arguments, but can return only one value. You can however use multiple conditional return statements as shown below −

    Example

    inttest(int);intmain(){test(5);printf("end");return0;}inttest(int a){if(a<3)return1;elsereturn0;}

    Function returning an array

    It is not possible to return an entire array as an argument to a function. However, you can return a pointer to an array by specifying the array’s name without an index.

    Example

    The following program shows how to pass an array to a function that returns an array after performing a certain process.

    #include <stdio.h>int*test(int*);intmain(){int a[]={1,2,3,4};int i;int*b =test(a);for(i=0; i<4; i++){printf("%d\n", b[i]);}return0;}int*test(int*a){int i;for(i=0; i<4; i++){
    
      a&#91;i]=2*a&#91;i];}return a;}</code></pre>

    Output

    2
    4
    6
    8
    

    function can only return a single value using return statement. To return multiple values, we use pointers or structures

    exit() instead of return statement

    Unlike the return statement, the exit() function is also used to terminate the execution of the program without transferring the control back to the calling function. It is used inside a function when the program has finished its execution or when an unrecoverable error occurs. It is a standard way of handling exception errors in C. When exit() is called, the program control does not return to the point where exit() was invoked. Instead, the control is handed back to the operating system.

    The exit() function is library function defined in stdlib.h header file.

    Syntax

    voidexit(int status);

    exit() is typically called from the main() function or any other function to terminate the entire program.

    It is included in the <stdlib.h> header file.

    Since it results in termination of the program, exit() does not return a value directly to the caller function. Instead, it terminates the program and returns a status code. It is an integer that represents the exit status of the program, indicating success or failure.

  • Callback Function

    Callback functions are extremely versatile, particularly in event-driven programming. When a specific event is triggered, a callback function mapped to it is executed in response to these events. This is typically used in GUI applications, an action like a button click can initiate a series of predefined actions.

    Callback Function

    The callback function is basically any executable code that is passed as an argument to other code, that is expected to call back or execute the argument at a given time. We can define it in other words like this: If the reference of a function is passed to another function argument for calling, then it is called a callback function.

    The mechanism of callbacks depends on function pointers. A function pointer is a variable that stores the memory address of a function.

    Here is a simple hello() function in C −

    voidhello(){printf("Hello World.");}

    We declare a pointer to this function as follows −

    void(*ptr)()=&hello;

    We can now call the function with the help of this function pointer, (*ptr)();

    Example of Callback Function in C

    In this example, the hello() function is defined as an argument to myfunction().

    #include <stdio.h>voidhello(){printf("Hello World\n");}voidcallback(void(*ptr)()){printf("Calling a function with its pointer\n");(*ptr)();// calling the callback function}main(){void(*ptr)()= hello;callback(ptr);}

    Output

    Calling a function with its pointer
    Hello World
    

    Callback Function With Arguments

    In the example given below, we have also declared two functions with identical prototypes − square() and root().

    intsquare(int val){return val*val;}introot(int val){returnpow(val,0.5);}

    The callback function is defined to receive an argument as well as a function pointer with an integer argument that matches with the above functions.

    intcallback(int a,int(*ptr)(int)){int ret =(*ptr)(a);return ret;}

    In the main() function, we place a call to the callback by passing an integer and the name of the function (square / root) which becomes the function pointer in callbacks definition.

    Example of Callback Function With Arguments

    The complete code is as follows −

    #include <stdio.h>#include <math.h>intcallback(int a,int(*print_callback)(int));intsquare(int value);introot(int value);intmain(){int x =4;printf("Square of x: %d is %d\n", x,callback(x, square));printf("Square root of x: %d is %d\n", x,callback(x, root));return0;}intcallback(int a,int(*ptr)(int)){int ret =(*ptr)(a);return ret;}intsquare(int val){return val*val;}introot(int val){returnpow(val,0.5);}

    Output

    Square of x: 4 is 16
    Square root of x: 4 is 2
    

    Types of Callbacks in C

    There are two types of callbacks −

    Synchronous Callback

    A callback is synchronous when it is given to another function, which executes it as part of its process. The calling function waits for the callback to complete before proceeding. This is useful when you need immediate results or want to ensure a task is finished before moving on.

    Asynchronous Callback

    In this case, the calling function triggers the callback but doesnt wait for it to finish. Instead, it continues its execution. It results in non-blocking operations. Its commonly used in event-driven programming.

    Generic callback functions help developers write C programs that are versatile and better adaptable.

    In this chapter, we explained how you can use function pointers so that we can enhance the flexibility of our C programs. Additionally, we showed how you can create generic callback functions that are not limited to a specific function pointer type.

  • User-defined Functions

    A function in C is a block of organized, reusable code that is used to perform a single related action. In any C program, there are one or more functions − classified as library functions and user-defined functions.

    There are two types of functions in C −

    • Library functions
    • User-defined functions

    Any C compiler (e.g. GCC compiler, Clang, MSVC compiler, etc.) is distributed with a number precompiled header files (stdio.h, math.h, etc.), each consisting of one or more predefined library functions such as printf(), scanf(), pow(), sqrt(), etc. To be able to use the library function, the corresponding header file must be made available with the #include directive.

    However, if you dont find a suitable library function to serve your purpose, then you can define a customized function for the program. Normally, we find a C program with a main() function. Obviously, the main() function is a user-defined function, as it contains the instructions provided by the user. It can of course call the other library or user-defined functions.

    What is User-Defined Function in C?

    User-defined function is defined by the user to perform specific task to achieve the code reusability and modularity. To create and use the user-defined function, you do not need use any built-in library. These functions can be created either in the same program or in user-defined header file.

    Creating a User-defined Function

    For creating a user-defined function, first you need to understand the purpose of the function, that is, what do you want the function to do?

    To create a user-defined function, you need to know about the following three parts of a function:

    • Function declaration
    • Function definition
    • Function calling

    Declaration of User-defined Function

    In C language, it is necessary to provide the declaration of the prototype of any function. The prototype of a library function is present in the corresponding header file.

    For a user-defined function, its prototype is present in the current program. The definition of a function and its prototype declaration should match.

    Syntax

    If you wish to define a function called add() that performs the addition of two integer arguments and returns the value as an integer, then the function declaration would be as follows −

    intadd(int,int);

    Definition of User-defined Function

    The definition of a function and its prototype declaration should match. The definition consists of a function header that matches the declaration and a function body.

    Syntax

    return_type function_name(arg1, arg2,...){// Function body;return val;}

    Example

    Using this template, you can write the user-defined function add() as follows −

    intadd(int a,int b){int c;
       c = a + b;return c;}

    Note that the order of definition of user-defined functions is not important in a C program. However, its prototype must be declared before calling the function.

    In a program, the main() function is always the entry point, irrespective of whether it is the first function or not. We needn’t provide the prototype declaration of the main() function.

    Calling a User-defined Function

    To call a function, you should use a statement that complies with the declaration of the function prototype. If the function is defined to receive a certain number of arguments, then the same number and type of arguments must be passed to call that function.

    Example

    The following statement calls the add() function that we defined above −

    int result =add(10,20);

    Example of User-Defined Function

    In this example, we are create two user-defined functions add() and sub() to find the addition and subtraction of the given numbers.

    // C program to demonstrate an example of// user-defined function#include <stdio.h>// Function declarationsintadd(int,int);intsub(int,int);// Function definitionsintadd(int a,int b){return(a + b);}intsub(int a,int b){return(a - b);}intmain(){// Declaring two integer variables to// store the numbers// and resultant variables to store the resultint num1 =36, num2 =24;int res_add, res_sub;// Calling the functions
      res_add =add(num1, num2);
      res_sub =sub(num1, num2);// Printing the resultsprintf("Addition is : %d\n", res_add);printf("Subtraction is : %d\n", res_sub);return0;}
    Addition is : 60
    Subtraction is : 12
    

    Formal and Actual Arguments in User-Defined Function

    When a function is defined with arguments, the arguments in the parenthesis in front of the function name are called formal arguments. In the above example, the function is defined with “int a” and “int b” arguments; they are formal arguments.

    When the function is called, the arguments passed to it are called the actual arguments. In the example below, the variables “x” and “y” are the actual arguments.

    int x =10, y =20;int result =add(x, y);

    A user-defined function may be defined to have any type of variables as formal arguments. It includes primary types (int, float, char), array, pointer, or struct/union type variables.

    A function should return a value to the calling environment. By default, the return type of a function is int type. However, it can return any data type − primary type, array, pointer, or a struct as well as a pointer. You can even define a function that returns a void type.

    Example

    If either the number or the type of actual and formal arguments or the return type as in the forward declaration of a function and its definition dont match, then the compiler reports an error.

    Look at the example below −

    #include <stdio.h>floatdivide(int,int);intmain(){int x =15, y =5;float z =divide(x, y);printf("%f", z);return0;}intdivide(int a,int b){int c = a/b;return c;}

    Output

    In the code above, the declaration of the divide() function doesnt match with its definition, hence the compiler shows the following error −

    error: conflicting types for 'divide'
    

    In C, any function can call any other function, any number of times. A function can call itself too. Such a self-calling function is called a recursive function.

    The following program calls the main() function from inside main() itself −

    #include <stdio.h>intmain(){printf("Hello");main();return0;}

    When executed, the program goes into an infinite loop. In practice, recursion has to be used so that the program eventually terminates.

  • Variadic Functions in C

    Variadic Function in C

    A function that can take a variable number of arguments is called a variadic function. One fixed argument is required to define a variadic function.

    The most frequently used library functions in C, i.e., printf() and scanf() are in fact the best-known examples of variadic functions, as we can put a variable number of arguments after the format specifier string.

    printf("format specifier",arg1, arg2, arg3,...);

    Syntax of Variadic Functions

    In C, a variadic function is defined to have at least one fixed argument, and then followed by an ellipsis symbol (…) that enables the compiler to parse the variable number of arguments.

    return_type function_name(type arg1,...);

    You need to include the stdarg.h header file at the top of the code to handle the variable arguments. This header file provides the following macros to work with the arguments received by the ellipsis symbol.

    MethodsDescription
    va_start(va_list ap, arg)Arguments after the last fixed argument are stored in the va_list.
    va_arg(va_list ap, type)Each time, the next argument in the variable list va_list and coverts it to the given type, till it reaches the end of list.
    va_copy(va_list dest, va_list src)This creates a copy of the arguments in va_list
    va_end(va_list ap)This ends the traversal of the variadic function arguments. As the end of va_list is reached, the list object is cleaned up.

    Examples of Variadic Functions in C

    Example: Sum of Numbers Using a Variadic Function

    The following code uses the concept of a variadic function to return the sum of a variable number of numeric arguments passed to such a function. The first argument to the addition() function is the count of the remaining arguments.

    Inside the addition() function, we initialize the va_list variable as follows −

    va_list args;va_start(args, n);

    Since there are “n” number of arguments that follow, fetch the next argument with “va_arg()” macro for “n” number of times and perform cumulative addition −

    for(i =0; i < n; i++){    
       sum +=va_arg(args,int);}

    Finally, clean up the va_list variable −

    va_end(args);

    The function ends by returning the sum of all the arguments.

    The complete code is given below −

    #include <stdio.h>#include <stdarg.h>// Variadic function to add numbersintaddition(int n,...){
    
       va_list args;int i, sum =0;va_start(args, n);for(i =0; i < n; i++){    
    
      sum +=va_arg(args,int);}va_end(args);return sum;}intmain(){printf("Sum = %d ",addition(5,1,2,3,4,5));return0;}</code></pre>

    Output

    Run the code and check its output −

    Sum = 15
    

    You can try providing a different set of numbers as the variadic arguments to the addition() function.

    Example: Finding the Largest Number Using a Variadic Function

    We can extend the concept of variadic function to find the largest number in a given list of variable number of values.

    #include <stdio.h>#include <stdarg.h>// Variadic function to add numbersintlargest(int n,...){
       va_list args;int i, max =0;va_start(args, n);for(i =0; i < n; i++){int x =va_arg(args,int);if(x >= max)
    
            max = x;}va_end(args);return max;}intmain(){printf("Largest number in the list = %d ",largest(5,12,34,21,45,32));return0;}</code></pre>

    Output

    When you run this code, it will produce the following output −

    Largest number in the list = 45
    

    Example: Concatenation of Multiple Strings Using Variadic Function

    In the following code, we pass multiple strings to a variadic function that returns a concatenated string.

    #include <stdio.h>#include <string.h>#include <stdarg.h>char*concat(int n,...){
       va_list args;int i;staticchar string[100],*word;va_start(args, n);strcpy(string,"");for(i =0; i < n; i++){
    
      word=va_arg(args,char*);strcat(string, word);strcat(string," ");}va_end(args);return string;}intmain(){char* string1 =concat(2,"Hello","World");printf("%s\n", string1);char* string2 =concat(3,"How","are","you?");printf("%s\n", string2);return0;}</code></pre>

    Output

    Run the code and check its output −

    Hello World
    How are you?
    
  • Nested Functions

    The term nesting, in programming context refers to enclosing a particular programming element inside another similar element. Just like nested loops, nested structures, etc., a nested function is a term used to describe the use of one or more functions inside another function.

    What is Lexical Scoping?

    In C language, defining a function inside another one is not possible. In short, nested functions are not supported in C. A function may only be declared (not defined) within another function.

    When a function is declared inside another function, it is called lexical scoping. Lexical scoping is not valid in C because the compiler cannot reach the correct memory location of inner function.

    Nested Functions Have Limited Use

    Nested function definitions cannot access local variables of surrounding blocks. They can access only global variables. In C, there are two nested scopes: local and global. So, nested functions have limited use.

    Example: Nested Function

    If you want to create a nested function like the one shown below, then it will generate an error −

    #include <stdio.h>intmain(void){printf("Main Function");intmy_fun(){printf("my_fun function");// Nested Functionintnested(){printf("This is a nested function.");}}nested();}

    Output

    On running this code, you will get an error −

    main.c:(.text+0x3d): undefined reference to `nested'
    collect2: error: ld returned 1 exit status
    

    Trampolines for Nested Functions

    Nested functions are supported as an extension in “GNU C”. GCC implements taking the address of a nested function using a technique called trampolines.

    A trampoline is a piece of code created at runtime when the address of a nested function is taken. It requires the function to be prefixed with the keyword auto in the declaration.

    Example 1

    Take a look at the following example −

    #include <stdio.h>intmain(){autointnested();nested();printf("In Main Function now\n");intnested(){printf("In the nested function now\n");}printf("End of the program");}

    Output

    When you run this code, it will produce the following output −

    In the nested function now
    In Main Function now
    End of the program
    

    Example 2

    In thi program, a function square() is nested inside another function myfunction(). The nested function is declared with the auto keyword.

    #include <stdio.h>#include <math.h>doublemyfunction(double a,double b);intmain(){double x =4, y =5;printf("Addition of squares of %f and %f = %f", x, y,myfunction(x, y));return0;}doublemyfunction(double a,double b){autodoublesquare(double c){returnpow(c,2);}returnsquare(a)+square(b);}

    Output

    Run the code and check its output −

    Addition of squares of 4.000000 and 5.000000 = 41.000000
    

    Nested Functions: Points to Note

    One needs to be aware of the following points while using nested functions −

    • A nested function can access all the identifiers of the containing function that precede its definition.
    • A nested function must not be called before the containing function exits.
    • A nested function cannot use a goto statement to jump to a label in the containing function.
    • Nested function definitions are permitted within functions in any block, mixed with the other declarations and statements in the block.
    • If you try to call a nested function through its address after the containing function exits, it throws an error.
    • A nested function always has no linkage. Declaring one with “extern” or “static” always produces errors.
  • Function Call by Reference in C

    There are two ways in which a function can be called: (a) Call by Value and (b) Call by Reference. In this chapter, we will explain the mechanism of calling a function by reference.

    Let us start this chapter with a brief overview on “pointers” and the “address operator (&)”. It is important that you learn these two concepts in order to fully understand the mechanism of Call by Reference.

    The Address Operator (&) in C

    In C language, a variable is a named memory location. When a variable declared, the compiler allocates a random location in the memory and internally identifies the location with the user-defined name.

    To fetch the address at which the variable has been created, we use the address (&) operator.

    Example

    Take a look at the following example −

    #include <stdio.h>intmain(){int x =10;printf("x: %d Address of x: %d", x,&x);}

    Output

    This will print the value of x and its address −

    x: 10 Address of x: -1990957196
    

    What is a Pointer in C?

    A pointer is a variable that stores the address of another variable. To declare a pointer variable, its name is prefixed with the * symbol. The type of the pointer variable and its host variable must be same.

    The address is assigned with the & operator. The dereference operator (*) is used with the pointer. It fetches the value of a variable whose address is assigned to the pointer.

    Example

    The following example demonstrates how referening and dereferencing work in C −

    #include <stdio.h>intmain(){int x =10;int*y =&x;printf("x: %d Address of x: %d\n", x,&x);printf("Address of y: %d \n",&y);printf("Value at address in y: %d\n",*y);}

    Output

    Run the code and check its output −

    x: 10 Address of x: -1742755108
    Address of y: -1742755104 
    Value at address in y: 10
    

    How Does Call by Reference Work in C?

    When a function is called by reference, the address of the actual argument variables passed, instead of their values.

    Let us define the add() function that receives the references of two variables −

    intadd(int*x,int*y){int z =*x +*y;return z;}

    When such a function is called, we pass the address of the actual argument.

    Example

    Let us call the add() function by reference from inside the main() function −

    #include <stdio.h>/* function declaration */intadd(int*,int*);intmain(){int a =10, b =20;int c =add(&a,&b);printf("Addition: %d", c);}intadd(int*x,int*y){int z =*x +*y;return z;}

    Output

    When you run this code, it will produce the following output −

    Addition: 30
    

    Now let’s understand how this code actually works. The main() function passes the address of a and b to the add() function. The addresses of a and b are assigned to the pointer variables x and y.

    Now focus on the statement “z = *x + *y;” inside the add() function. Remember that x stores the address of a. The dereference operator in *x and *y fetches the values of a and b respectively, hence z is the addition of a and b in the main() function.

    Example: Swap Values with Call by Reference

    Let us understand in more detail how the Call by Reference mechanism works, with the help of the following example that interchanges value of two variables.

    #include <stdio.h>/* Function definition to swap the values *//* It receives the reference of two variables whose values are to be swapped */intswap(int*x,int*y){int z;
    
       z =*x;/* save the value at address x */*x =*y;/* put y into x */*y = z;/* put z into y */return0;}/* The main() function has two variables "a" and "b" *//* Their addresses are passed as arguments to the swap() function. */intmain(){/* local variable definition */int a =10;int b =20;printf("Before swap, value of a: %d\n", a );printf("Before swap, value of b: %d\n", b );/* calling a function to swap the values */swap(&a,&b);printf("After swap, value of a: %d\n", a);printf("After swap, value of b: %d\n", b);return0;}

    Output

    When you run this code, it will produce the following output −

    Before swap, value of a: 10
    Before swap, value of b: 20
    After swap, value of a: 20
    After swap, value of b: 10
    

    Explanation

    Assume that the variables a and b in the main() function are allotted locations with the memory address 100 and 200 respectively. As their addresses are passed to x and y (remember that they are pointers), the variables xy and z in the swap() function are created at addresses 1000, 2000 and 3000 respectively.

    Inside the swap in C

    Since “x” and “y” store the address of “a” and “b”, “x” becomes 100 and “y” becomes 200, as the above figure shows.

    Inside the swap() function, the first statement “z = *x” causes the value at address in “x” to be stored in “x” (which is 10). Similarly, in the statement “*x = *y;“, the value at the address in “y” (which is 20) is stored in the location whose pointer is “x”.

    Finally, the statement “*y = z;” assigns the “z” to the variable pointed to by “y”, which is “b” in the main() function. The values of “a” and “b” now get swapped.

    The following figure visually demonstrates how it works −

    Understand Visually how this works in C

    Mixing Call by Value and Call by Reference

    You can use a function calling mechanism that is a combination of Call by Value and Call by Reference. It can be termed as “mixed calling mechanism”, where some of the arguments are passed by value and others by reference.

    A function in C can have more than one arguments, but can return only one value. The Call by Reference mechanism is a good solution to overcome this restriction.

    Example

    In this example, the calculate() function receives an integer argument by value, and two pointers where its square and cube are stored.

    #include <stdio.h>#include <math.h>/* function declaration */intcalculate(int,int*,int*);intmain(){int a =10;int b, c;calculate(a,&b,&c);printf("a: %d \nSquare of a: %d \nCube of a: %d", a, b, c);}intcalculate(int x,int*y,int*z){*y  =pow(x,2);*z =pow(x,3);return0;}

    Output

    When you run this code, it will produce the following output −

    a: 10 
    Square of a: 100 
    Cube of a: 1000
    

    The Call by Reference mechanism is widely used when a function needs to perform memory-level manipulations such as controlling the peripheral devices, performing dynamic allocation, etc.