Unit 3
Functions and Pointers
Similar to other languages C language also provides the facility of function. Function is the block of code which is used to perform a specific task. In c language the complete program is composed of function.
Functions are useful to divide c programs into smaller modules. Programmer can invoked these modules anywhere inside c program for any number of times.
Functions are used to increase readability of the code. Size of program can be reduce by using functions. By using function, programmer can divide complex tasks into smaller manageable tasks and test them independently before using them together.
Functions of C language are defined with the type of function. The type of functions indicates the data type of value which will return by function. In order to use function in the program, initially programmer have to inform compiler about the function. This is also called as defining a function.
In C program all the function definition present outside the main function. All function need to be declared and defined before use. Function declaration requires function name, argument list, and return type.
1. Library Functions
A function which is predefined in c language is called library function. Library function is also called as built in function of C language. The definition of library function is stored in respective header file. Library functions are used to perform dedicated operation like taking input from user, displaying output, string handling operation, etc. Library functions are readily available and programmer can directly use it without writing any extra code. For example, printf () and scanf () are library function and their definition is stored in stdio header file.
2. User Defined Functions
User define function is the block of code written by programmer to perform a particular task. As compiler doesn’t have any idea about the user define function so programmer has to define and declare these functions inside the program body. Programmer can define these function outside the main function but declaration of user define function should present in main function only. Whenever compiler executes function call (function declaration) then compiler shift the flow of program execution to the definition part of user define function.
Example
#include <stdio.h>
#include<conio.h>
Int add (int x, int y)
{
Int sum;
Sum = x + y;
Return (sum);
}
Main ()
{
Inta,b,c;
a = 15;
b = 25;
c = add(a,b);
Printf ("\n Addition is %d ", c);
}
Output:
Addition is 40
There are two ways to pass the parameters to the function
- Parameter Passing by value
In this mechanism, the value of the parameter is passed while calling the function.
2. Parameter Passing by reference
In this mechanism, the address of the parameter is passed while calling the function.
There are two methods to pass the data into the function in C language, i.e., call by value and call by reference.
Let's understand call by value and call by reference in c language one by one.
Call by value in C
- In call by value method, the value of the actual parameters is copied into the formal parameters. In other words, we can say that the value of the variable is used in the function call in the call by value method.
- In call by value method, we can not modify the value of the actual parameter by the formal parameter.
- In call by value, different memory is allocated for actual and formal parameters since the value of the actual parameter is copied into the formal parameter.
- The actual parameter is the argument which is used in the function call whereas formal parameter is the argument which is used in the function definition.
Let's try to understand the concept of call by value in c language by the example given below:
- #include<stdio.h>
- Void change(int num) {
- Printf("Before adding value inside function num=%d \n",num);
- Num=num+100;
- Printf("After adding value inside function num=%d \n", num);
- }
- Int main() {
- Int x=100;
- Printf("Before function call x=%d \n", x);
- Change(x);//passing value in function
- Printf("After function call x=%d \n", x);
- Return 0;
- }
Output
Before function call x=100
Before adding value inside function num=100
After adding value inside function num=200
After function call x=100
Call by Value Example: Swapping the values of the two variables
- #include <stdio.h>
- Void swap(int , int); //prototype of the function
- Int main()
- {
- Int a = 10;
- Int b = 20;
- Printf("Before swapping the values in main a = %d, b = %d\n",a,b); // printing the value of a and b in main
- Swap(a,b);
- Printf("After swapping values in main a = %d, b = %d\n",a,b); // The value of actual parameters do not change by changing the formal parameters in call by value, a = 10, b = 20
- }
- Void swap (int a, int b)
- {
- Int temp;
- Temp = a;
- a=b;
- b=temp;
- Printf("After swapping values in function a = %d, b = %d\n",a,b); // Formal parameters, a = 20, b = 10
- }
Output
Before swapping the values in main a = 10, b = 20
After swapping values in function a = 20, b = 10
After swapping values in main a = 10, b = 20
Call by reference in C
- In call by reference, the address of the variable is passed into the function call as the actual parameter.
- The value of the actual parameters can be modified by changing the formal parameters since the address of the actual parameters is passed.
- In call by reference, the memory allocation is similar for both formal parameters and actual parameters. All the operations in the function are performed on the value stored at the address of the actual parameters, and the modified value gets stored at the same address.
Consider the following example for the call by reference.
- #include<stdio.h>
- Void change(int *num) {
- Printf("Before adding value inside function num=%d \n",*num);
- (*num) += 100;
- Printf("After adding value inside function num=%d \n", *num);
- }
- Int main() {
- Int x=100;
- Printf("Before function call x=%d \n", x);
- Change(&x);//passing reference in function
- Printf("After function call x=%d \n", x);
- Return 0;
- }
Output
Before function call x=100
Before adding value inside function num=100
After adding value inside function num=200
After function call x=200
Call by reference Example: Swapping the values of the two variables
- #include <stdio.h>
- Void swap(int *, int *); //prototype of the function
- Int main()
- {
- Int a = 10;
- Int b = 20;
- Printf("Before swapping the values in main a = %d, b = %d\n",a,b); // printing the value of a and b in main
- Swap(&a,&b);
- Printf("After swapping values in main a = %d, b = %d\n",a,b); // The values of actual parameters do change in call by reference, a = 10, b = 20
- }
- Void swap (int *a, int *b)
- {
- Int temp;
- Temp = *a;
- *a=*b;
- *b=temp;
- Printf("After swapping values in function a = %d, b = %d\n",*a,*b); // Formal parameters, a = 20, b = 10
- }
Output
Before swapping the values in main a = 10, b = 20
After swapping values in function a = 20, b = 10
After swapping values in main a = 20, b = 10
Difference between call by value and call by reference in c
No. | Call by value | Call by reference |
1 | A copy of the value is passed into the function | An address of value is passed into the function |
2 | Changes made inside the function is limited to the function only. The values of the actual parameters do not change by changing the formal parameters. | Changes made inside the function validate outside of the function also. The values of the actual parameters do change by changing the formal parameters. |
3 | Actual and formal arguments are created at the different memory location | Actual and formal arguments are created at the same memory location |
A function declaration tells the compiler about a function name and how to call the function. The actual body of the function can be defined separately.
A function declaration has the following parts −
Return_typefunction_name( parameter list );
For the above defined function max(), the function declaration is as follows −
Int max(int num1, int num2);
Parameter names are not important in function declaration only their type is required, so the following is also a valid declaration −
Int max(int, int);
Function declaration is required when you define a function in one source file and you call that function in another file. In such case, you should declare the function at the top of the file calling the function.
A function depending an whether the arguments are present or not and whether a value is returned or not, may belong to one of following categories
- Function with no return values, no arguments
- Functions with arguments, no return values
- Functions with arguments and return values
- Functions with no arguments and return values.
1.).In this category, the function has no arguments. It does not receive any data from the calling function. Similarly, it doesn’t return any value. The calling function doesn’t receive any data from the called function. So, there is no communication between calling and called functions.
2.)In this category, function has some arguments . It receives data from the calling function, but it doesn’t return a value to the calling function. The calling function doesn’t receive any data from the called function. So, it is one way data communication between called and calling functions.
Eg: Printing n Natural numbers
01 | #include<stdio.h> |
02 | #include<conio.h> |
03 | Voidnat( int); | |
04 | Voidmain() | |
05 | { | |
06 | Intn; | |
07 | Clrscr(); | |
08 | Printf("\n Enter n value:"); | |
09 | Scanf("%d",&n); | |
10 | Nat(n); | |
11 | Getch(); | |
12 | } | |
13 |
| |
14 | Voidnat(intn) | |
15 | { | |
16 | Inti; | |
17 | For(i=1;i<=n;i++) |
18 | Printf("%d\t",i); |
19 | } |
Output:
Enter n value: 5
1 2 3 4 5
Note:
In the main() function, n value is passed to the nat() function. The n value is now stored in the formal argument n, declared in the function definition and subsequently, the natural numbers upto n are obtained.
3.)In this category, functions has some arguments and it receives data from the calling function. Simillarly, it returns a value to the calling function. The calling function receives data from the called function. So, it is two-way data communication between calling and called functions.
Eg:
01 | #include<stdio.h> | |
02 | #include<conio.h> | |
03 | Intfact(int); | |
04 | Voidmain() | |
05 | { | |
06 | Intn; | |
07 | Clrscr(); | |
08 | Printf("\n Enter n:"); | |
09 | Scanf("%d",&n); | |
10 | Printf("\n Factorial of the number : %d", fact(n)); | |
11 | Getch(); | |
12 | } | |
13 |
| |
14 | Intfact(intn) | |
15 | { | |
16 | Inti,f; | |
17 | For(i=1,f=1;i<=n;i++) | |
18 | f=f*i; | |
19 | Return(f); | |
20 | } | |
Output:
Enter n: 5
Factorial of the number : 120
4.)In this category, the functions has no arguments and it doesn’t receive any data from the calling function, but it returns a value to the calling function. The calling function receives data from the called function. So, it is one way data communication between calling and called functions.
Eg:
01 | #include<stdio.h> |
02 | #include<conio.h> |
03 | Intsum(); | |
04 | Voidmain() | |
05 | { | |
06 | Ints; | |
07 | Clrscr(); | |
08 | Printf("\n Enter number of elements to be added :"); | |
09 | s=sum(); | |
10 | Printf("\n Sum of the elements :%d",p); | |
11 | Getch(); | |
12 | } | |
13 |
| |
14 | Intsum() | |
15 | { | |
16 | Inta[20], i, s=0,n; | |
17 | Scanf("%d",&n); | |
18 | Printf("\n Enter the elements:"); | |
19 | For(i=0;i< n; i++) | |
20 | Scanf("%d",& a[i]); | |
21 | For(i=0;i< n; i++) | |
22 | s=s+a[i]; | |
23 | Returns; | |
24 | } | |
Many a times, we need to repeat the same process in a program multiple times. It is difficult for us to define functions for every function call of the same process.Based on the calling of the functions by the user in a program, functions are classified as
- Recursive functions
- Non-Recursive functions
Example
#include<stdio.h>
Intmy_function(){
Printf("This function takes no argument, But returns 50\n");
Return50;
}
Main(){
Int x;
x =my_function();
Printf("Returned Value: %d", x);
}
Output
This function takes no argument, But returns 50
Returned Value: 50
Here this function is not taking any input argument, but its return type is int. So this returns a value.
Example
#include<stdio.h>
Voidmy_function(int x){
Printf("This function is taking %d as argument, but returns nothing", x);
Return50;
}
Main(){
Int x;
x =10;
My_function(x);
}
Output
This function is taking 10 as argument, but returns nothing
Here this function is taking an input argument, but its return type is void. So this returns nothing.
Example
#include<stdio.h>
Intmy_function(int x){
Printf("This will take an argument, and will return its squared value\n");
Return x * x;
}
Main(){
Int x, res;
x =12;
Res=my_function(12);
Printf("Returned Value: %d", res);
}
Output
This function is taking 10 as argument, but returns nothing
Here this function is taking any input argument, and also returns value.
Example
#include<stdio.h>
Intmy_function(){
Printf("This function takes no argument, But returns 50\n");
Return50;
}
Main(){
Int x;
x =my_function();
Printf("Returned Value: %d", x);
}
Output
This function takes no argument, But returns 50
Returned Value: 50
Here this function is not taking any input argument, but its return type is int. So this returns a value.
We can return more than one values from a function by using the method called “call by address”, or “call by reference”. In the invoker function, we will use two variables to store the results, and the function will take pointer type data. So we have to pass the address of the data.
In this example, we will see how to define a function that can return quotient and remainder after dividing two numbers from one single function.
Example Code
#include<stdio.h>
Void div(int a,int b,int*quotient,int*remainder){
*quotient = a / b;
*remainder = a % b;
}
Main(){
Int a =76, b =10;
Int q, r;
Div(a, b,&q,&r);
Printf("Quotient is: %d\nRemainder is: %d\n", q, r);
}
Output
Quotient is: 7
Remainder is: 6
In some applications, we have seen that some functions are declared inside another function. This is sometimes known as nested function, but actually this is not the nested function. This is called the lexical scoping. Lexical scoping is not valid in C because the compiler is unable to reach correct memory location of inner function.
Nested function definitions cannot access local variables of surrounding blocks. They can access only global variables. In C there are two nested scopes the local and the global. So nested function has some limited use. If we want to create nested function like below, it will generate error.
Example
#include<stdio.h>
Main(void){
Printf("Main Function");
Intmy_fun(){
Printf("my_fun function");
// defining another function inside the first function.
Int my_fun2(){
Printf("my_fun2 is inner function");
}
}
My_fun2();
}
Output
Text.c:(.text+0x1a): undefined reference to my_fun2'
But an extension of GNU C compiler allows declaration of the nested function. For this we have to add auto keyword before the declaration of nested function.
Example
#include<stdio.h>
Main(void){
Autointmy_fun();
My_fun();
Printf("Main Function\n");
Intmy_fun(){
Printf("my_fun function\n");
}
Printf("Done");
}
Output
My_fun function
Main Function
Done
In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.
Void recursion() {
Recursion(); /* function calls itself */
}
Int main() {
Recursion();
}
The C programming language supports recursion, i.e., a function to call itself. But while using recursion, programmers has to be careful to define an exit condition from the function, otherwise it will go into an infinite loop.
Recursive functions are useful to solve many mathematical problems, such as calculating the factorial of a number, generating Fibonacci series, etc.
The following example calculates the factorial of a given number using a recursive function −
#include <stdio.h>
Unsigned long longint factorial(unsigned inti) {
If(i<= 1) {
Return 1;
}
Returni * factorial(i - 1);
}
Int main() {
Inti = 12;
Printf("Factorial of %d is %d\n", i, factorial(i));
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Factorial of 12 is 479001600
The following example generates the Fibonacci series for a given number using a recursive function −
#include <stdio.h>
Intfibonacci(inti) {
If(i == 0) {
Return 0;
}
If(i == 1) {
Return 1;
}
Returnfibonacci(i-1) + fibonacci(i-2);
}
Int main() {
Inti;
For (i = 0; i< 10; i++) {
Printf("%d\t\n", fibonacci(i));
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
0
1
1
2
3
5
8
13
21
34
Passing array to function using call by value method
As we already know in this type of function call, the actual parameter is copied to the formal parameters.
#include <stdio.h>
Voiddisp( char ch)
{
Printf("%c ", ch);
}
Int main()
{
Char arr[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
For (int x=0; x<10; x++)
{
/* I’m passing each element one by one using subscript*/
Disp (arr[x]);
}
Return 0;
}
Output:
a b c d e f g h i j
Passing array to function using call by reference
When we pass the address of an array while calling a function then this is called function call by reference. When we pass an address as an argument, the function declaration should have a pointer as a parameter to receive the passed address.
#include <stdio.h>
Voiddisp( int *num)
{
Printf("%d ", *num);
}
Int main()
{
Intarr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
For (inti=0; i<10; i++)
{
/* Passing addresses of array elements*/
Disp (&arr[i]);
}
Return 0;
}
Output:
1 2 3 4 5 6 7 8 9 0
In C programming, a string is a sequence of characters terminated with a null character \0. For example:
Char c[] = "c string";
When the compiler encounters a sequence of characters enclosed in the double quotation marks, it appends a null character \0 at the end by default.
How to declare a string?
Here's how you can declare strings:
Char s[5];
Here, we have declared a string of 5 characters.
How to initialize strings?
You can initialize strings in a number of ways.
Char c[] = "abcd";
Char c[50] = "abcd";
Char c[] = {'a', 'b', 'c', 'd', '\0'};
Char c[5] = {'a', 'b', 'c', 'd', '\0'};
Let's take another example:
Char c[5] = "abcde";
Here, we are trying to assign 6 characters (the last character is '\0') to a char array having 5 characters. This is bad and you should never do this.
Assigning Values to Strings
Arrays and strings are second-class citizens in C; they do not support the assignment operator once it is declared. For example,
Char c[100];
c = "C programming"; // Error! array type is not assignable.
Note: Use the strcpy() function to copy the string instead.
Read String from the user
You can use the scanf() function to read a string.
The scanf() function reads the sequence of characters until it encounters whitespace (space, newline, tab, etc.).
Example 1: scanf() to read a string
Intmain()
{
Char name[20];
Printf("Enter name: ");
Scanf("%s", name);
Printf("Your name is %s.", name);
Return0;
}
Output
Enter name: Dennis Ritchie
Your name is Dennis.
Even though Dennis Ritchie was entered in the above program, only "Dennis" was stored in the name string. It's because there was a space after Dennis.
How to read a line of text?
You can use the fgets() function to read a line of string. And, you can use puts() to display the string.
Example 2: fgets() and puts()
Intmain()
{
Char name[30];
Printf("Enter name: ");
Fgets(name, sizeof(name), stdin); // read string
Printf("Name: ");
Puts(name); // display string
Return0;
}
Output
Enter name: Tom Hanks
Name: Tom Hanks
Here, we have used fgets() function to read a string from the user.
Fgets(name, sizeof(name), stdlin); // read string
The sizeof(name) results to 30. Hence, we can take a maximum of 30 characters as input which is the size of the name string.
To print the string, we have used puts(name);.
Note: The gets() function can also be to take input from the user. However, it is removed from the C standard.
It's because gets() allows you to input any length of characters. Hence, there might be a buffer overflow.
Passing Strings to Functions
Strings can be passed to a function in a similar way as arrays.
Example 3: Passing string to a Function
VoiddisplayString(charstr[]);
Intmain()
{
Charstr[50];
Printf("Enter string: ");
Fgets(str, sizeof(str), stdin);
DisplayString(str); // Passing string to a function.
Return0;
}
VoiddisplayString(charstr[])
{
Printf("String Output: ");
Puts(str);
}
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. The following example shows how local variables are used. Here all the variables a, b, and c are local to main() function.
#include <stdio.h>
Int main () {
/* local variable declaration */
Int a, b;
Int c;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
Printf ("value of a = %d, b = %d and c = %d\n", a, b, c);
Return 0;
}
Global Variables
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. The following program show how global variables are used in a program.
#include <stdio.h>
/* global variable declaration */
Int g;
Int main () {
/* local variable declaration */
Int a, b;
/* actual initialization */
a = 10;
b = 20;
g = a + b;
Printf ("value of a = %d, b = %d and g = %d\n", a, b, g);
Return 0;
}
A program can have same name for local and global variables but the value of local variable inside a function will take preference. Here is an example −
#include <stdio.h>
/* global variable declaration */
Int g = 20;
Int main () {
/* local variable declaration */
Int g = 10;
Printf ("value of g = %d\n", g);
Return 0;
}
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 −
#include <stdio.h>
/* global variable declaration */
Int a = 20;
Int main () {
/* 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);
Return 0;
}
/* function to add two integers */
Int sum(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 Type | Initial Default Value |
Int | 0 |
Char | '\0' |
Float | 0 |
Double | 0 |
Pointer | NULL |
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.
We haven't said so explicitly, but variables are channels of communication within a program. You set a variable to a value at one point in a program, and at another point (or points) you read the value out again. The two points may be in adjoining statements, or they may be in widely separated parts of the program.
How long does a variable last? How widely separated can the setting and fetching parts of the program be, and how long after a variable is set does it persist? Depending on the variable and how you're using it, you might want different answers to these questions.
The visibility of a variable determines how much of the rest of the program can access that variable. You can arrange that a variable is visible only within one part of one function, or in one function, or in one source file, or anywhere in the program. (We haven't really talked about source files yet; we'll be exploring them soon.)
Why would you want to limit the visibility of a variable? For maximum flexibility, wouldn't it be handy if all variables were potentially visible everywhere? As it happens, that arrangement would be too flexible: everywhere in the program, you would have to keep track of the names of all the variables declared anywhere else in the program, so that you didn't accidentally re-use one. Whenever a variable had the wrong value by mistake, you'd have to search the entire program for the bug, because any statement in the entire program could potentially have modified that variable. You would constantly be stepping all over yourself by using a common variable name like i in two parts of your program, and having one snippet of code accidentally overwrite the values being used by another part of the code. The communication would be sort of like an old party line--you'd always be accidentally interrupting other conversations, or having your conversations interrupted.
To avoid this confusion, we generally give variables the narrowest or smallest visibility they need. A variable declared within the braces {} of a function is visible only within that function; variables declared within functions are called local variables. If another function somewhere else declares a local variable with the same name, it's a different variable entirely, and the two don't clash with each other.
On the other hand, a variable declared outside of any function is a global variable, and it is potentially visible anywhere within the program. You use global variables when you do want the communications path to be able to travel to any part of the program. When you declare a global variable, you will usually give it a longer, more descriptive name (not something generic like i) so that whenever you use it you will remember that it's the same variable everywhere.
Another word for the visibility of variables is scope.
How long do variables last? By default, local variables (those declared within a function) have automatic duration: they spring into existence when the function is called, and they (and their values) disappear when the function returns. Global variables, on the other hand, have static duration: they last, and the values stored in them persist, for as long as the program does. (Of course, the values can in general still be overwritten, so they don't necessarily persist forever.)
Finally, it is possible to split a function up into several source files, for easier maintenance. When several source files are combined into one program (we'll be seeing how in the next chapter) the compiler must have a way of correlating the global variables which might be used to communicate between the several source files. Furthermore, if a global variable is going to be useful for communication, there must be exactly one of it: you wouldn't want one function in one source file to store a value in one global variable named globalvar, and then have another function in another source file read from a different global variable named globalvar. Therefore, a global variable should have exactly one defining instance, in one place in one source file. If the same variable is to be used anywhere else (i.e. in some other source file or files), the variable is declared in those other file(s) with an external declaration, which is not a defining instance. The external declaration says, hey, compiler, here's the name and type of a global variable I'm going to use, but don't define it here, don't allocate space for it; it's one that's defined somewhere else, and I'm just referring to it here.'' If you accidentally have two distinct defining instances for a variable of the same name, the compiler (or the linker) will complain that it is multiply defined.''
It is also possible to have a variable which is global in the sense that it is declared outside of any function, but private to the one source file it's defined in. Such a variable is visible to the functions in that source file but not to any functions in any other source files, even if they try to issue a matching declaration.
You get any extra control you might need over visibility and lifetime, and you distinguish between defining instances and external declarations, by using storage classes. A storage class is an extra keyword at the beginning of a declaration which modifies the declaration in some way. Generally, the storage class (if any) is the first word in the declaration, preceding the type name. (Strictly speaking, this ordering has not traditionally been necessary, and you may see some code with the storage class, type name, and other parts of a declaration in an unusual order.)
We said that, by default, local variables had automatic duration. To give them static duration (so that, instead of coming and going as the function is called, they persist for as long as the function does), you precede their declaration with the static keyword:
Staticinti;
By default, a declaration of a global variable (especially if it specifies an initial value) is the defining instance. To make it an external declaration, of a variable which is defined somewhere else, you precede it with the keyword extern:
Externint j;
Finally, to arrange that a global variable is visible only within its containing source file, you precede it with the static keyword:
Staticint k;
Notice that the static keyword can do two different things: it adjusts the duration of a local variable from automatic to static, or it adjusts the visibility of a global variable from truly global to private-to-the-file.
To summarize, we've talked about two different attributes of a variable: visibility and duration. These are orthogonal, as shown in this table:
| Duration: | |
Visibility: | Automatic | Static |
Local | Normal local variables | Static local variables |
Global | N/A | Normal global variables |
We can also distinguish between file-scope global variables and truly global variables, based on the presence or absence of the static keyword.
We can also distinguish between external declarations and defining instances of global variables, based on the presence or absence of the extern keyword.
Pointers in C language is a variable that stores/points the address of another variable. A Pointer in C is used to allocate memory dynamically i.e. at run time. The pointer variable might be belonging to any of the data type such as int, float, char, double, short etc.
Pointer Syntax :data_type *var_name; Example : int *p; char *p;
Where, * is used to denote that “p” is pointer variable and not a normal variable.
Normal variable stores the value whereas pointer variable stores the address of the variable.
The content of the C pointer always be a whole number i.e. address.
Always C pointer is initialized to null, i.e. int *p = null.
The value of null pointer is 0.
& symbol is used to get the address of the variable.
* symbol is used to get the value of the variable that the pointer is pointing to.
If a pointer in C is assigned to NULL, it means it is pointing to nothing.
Two pointers can be subtracted to know how many elements are available between these two pointers.
But, Pointer addition, multiplication, division are not allowed.
The size of any pointer is 2 byte (for 16 bit compiler).
Example:
#include <stdio.h>
Int main()
{
Int *ptr, q;
q = 50;
/* address of q is assigned to ptr */
Ptr = &q;
/* display q's value using ptr variable */
Printf("%d", *ptr);
Return 0;
}
1
2
3
4
5
6
7
8
9
10
11
A pointer is a variable whose value is the address of another variable, i.e., direct address of the memory location. Like any variable or constant, you must declare a pointer before using it to store any variable address. The general form of a pointer variable declaration is −
Type *var-name;
Here, type is the pointer's base type; it must be a valid C data type and var-name is the name of the pointer variable. The asterisk * used to declare a pointer is the same asterisk used for multiplication. However, in this statement the asterisk is being used to designate a variable as a pointer. Take a look at some of the valid pointer declarations −
Int *ip; /* pointer to an integer */
Double *dp; /* pointer to a double */
Float *fp; /* pointer to a float */
Char *ch /* pointer to a character */
The actual data type of the value of all pointers, whether integer, float, character, or otherwise, is the same, a long hexadecimal number that represents a memory address. The only difference between pointers of different data types is the data type of the variable or constant that the pointer points to.
How to Use Pointers?
There are a few important operations, which we will do with the help of pointers very frequently. (a) We define a pointer variable, (b) assign the address of a variable to a pointer and (c) finally access the value at the address available in the pointer variable. This is done by using unary operator * that returns the value of the variable located at the address specified by its operand. The following example makes use of these operations −
#include<stdio.h>
Int main (){
Intvar=20;/* actual variable declaration */
Int*ip;/* pointer variable declaration */
Ip=&var;/* store address of var in pointer variable*/
Printf("Address of var variable: %x\n",&var);
/* address stored in pointer variable */
Printf("Address stored in ip variable: %x\n",ip);
/* access the value using the pointer */
Printf("Value of *ip variable: %d\n",*ip);
Return0;
}
When the above code is compiled and executed, it produces the following result −
Address of var variable: bffd8b3c
Address stored in ip variable: bffd8b3c
Value of *ip variable: 20
NULL Pointers
It is always a good practice to assign a NULL value to a pointer variable in case you do not have an exact address to be assigned. This is done at the time of variable declaration. A pointer that is assigned NULL is called a null pointer.
The NULL pointer is a constant with a value of zero defined in several standard libraries. Consider the following program −
#include<stdio.h>
Int main (){
Int*ptr= NULL;
Printf("The value of ptr is : %x\n",ptr);
Return0;
}
When the above code is compiled and executed, it produces the following result −
The value of ptr is 0
In most of the operating systems, programs are not permitted to access memory at address 0 because that memory is reserved by the operating system. However, the memory address 0 has special significance; it signals that the pointer is not intended to point to an accessible memory location. But by convention, if a pointer contains the null (zero) value, it is assumed to point to nothing.
To check for a null pointer, you can use an 'if' statement as follows −
If(ptr) /* succeeds if p is not null */
If(!ptr) /* succeeds if p is null */
Pointers are declare with the help of operator ‘*’. ‘*’ is known as ‘value at address’. Pointers are the variables which are used to store the address of another variable As the address of variable is always whole numbers so pointer always contains whole numbers. The declaration of pointer are as follows.
Syntax : Data type * pointer Name.
Example: int *I;
Data type defines the type of value defined at the address of pointer variable. In the above example value at the address of ‘I’ is of type integer.
Consider the following program.
# include<stdio.h>
# include<conio.h>
Void main()
{
Inta,b,c;
Int *p,*q,*r;
p=&a;
q=&b;
r=&c;
Printf(“Enter two numbers”);
Scanf(“%d%d,&a,&b);
c=a + b;
Printf(“\n Address of variable C is %d”,&C);
Printf(“\n Address of variable C is %d,r);
Printf(“\n Address of variable r is %d”,&r);
Printf(“\n value of variable C is %d”,C);
Printf(“\n value of variable C is %d,*^);
Getch ();
}
In the above program variable ‘r’ is the integer pointer which holds the address of variable ‘C’
Case 1: In ‘printf’ statement whenever we used (“%d”,r) men me value of r is printed but ‘r’ is holding the address of variable ‘C’. So, address of variable C is copied to the value of ‘r’ and it is printed on output screen
Case 2: Whenever we used (“%d”,&r) in ‘printf’ function men the address of variable ‘r’ is pointed on o/p screen.
Case 3: When we used (“%d”,*r) in pointf function at mat time value which is stored at the address which holds by variable ‘r’ is printed.
Now me variable ‘r’ is holding the address of variable ‘C’. So, the value which is stored at the address of ‘C’ is printed on the output screen.
Consider the following example.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int a=3;
Int *p;
p=&a;
Printf(“\n%d”,a);
Printf(“\n%d”,&a);
Printf(“\n%d”,P);
Printf(“\n%d”,&P);
Printf(“\n%d”,*P);
Printf(“\n%d”,*(&a));
}
Run the above program on the computer system so that you will familiar with the basic use of pointers. Following is the explanation O/p of above program.
- The first ‘printf’ statement prints the value of ‘C’ ie. 3
- The second ‘printf’ statement prints the address of ‘a’
- The third ‘printf’ statement prints me value of ‘p’ ie. The address of ‘a’
- The forth ‘printf’ statement prints the address of ‘p’
- The fifth ‘printf’ statement prints the value which is stored at the address holds in ‘p’ ie. 3
- The sixth ‘printf’ statement prints the value which is stored at the address of ‘a’ ie. 3
Data type of pointer variable can be anything. Such as char *C;
In the above instruction pointer ‘C’ is of type character so the variable ‘C’ can store the address of variable which contains character type of value. Consider the following program.
#include<stdio.h>
#include<conio.h>
Void main()
{
Int I,*ip;
Char C, *cp;
I = 3;
Ip = & I;
c=’M’;
Cp=&c;
Printf(“%d”,I);
Printf(“\n%d”,*ip);
Printf(“\n%C;,C);
Printf(“\n%c”, *cp);
Getch();
}
The output of above program is.
3
3
m
m
Declaring a pointer
Like variables, pointers have to be declared before they can be used in your program. Pointers can be named anything you want as long as they obey C's naming rules. A pointer declaration has the following form.
Data_type * pointer_variable_name;
Here,
- Data_typeis the pointer's base type of C's variable types and indicates the type of the variable that the pointer points to.
- The asterisk (*: the same asterisk used for multiplication) which is indirection operator, declares a pointer.
Let's see some valid pointer declarations
Int *ptr_thing; /* pointer to an integer */
Int *ptr1,thing;/* ptr1 is a pointer to type integer and thing is an integer variable */
Double *ptr2; /* pointer to a double */
Float *ptr3; /* pointer to a float */
Char *ch1 ; /* pointer to a character */
Float *ptr, variable;/*ptr is a pointer to type float and variable is an ordinary float variable */
Initialize a pointer
After declaring a pointer, we initialize it like standard variables with a variable address. If pointers are not uninitialized and used in the program, the results are unpredictable and potentially disastrous.
To get the address of a variable, we use the ampersand (&)operator, placed before the name of a variable whose address we need. Pointer initialization is done with the following syntax.
Pointer = &variable;
A simple program for pointer illustration is given below:
#include <stdio.h>
Int main()
{
Int a=10; //variable declaration
Int *p; //pointer variable declaration
p=&a; //store address of variable a in pointer p
Printf("Address stored in a variable p is:%x\n",p); //accessing the address
Printf("Value stored in a variable p is:%d\n",*p); //accessing the value
Return 0;
}
Output:
Address stored in a variable p is:60ff08
Value stored in a variable p is:10
- Declare a normal variable, assign the value
- Declare a pointer variable with the same type as the normal variable
- Initialize the pointer variable with the address of normal variable
- Access the value of the variable by using asterisk (*) - it is known as dereference operator
Example:
Here, we have declared a normal integer variable num and pointer variable ptr,ptr is being initialized with the address of num and finally getting the value of num using pointer variable ptr.
#include <stdio.h>
Int main(void)
{
//normal variable
Intnum = 100;
//pointer variable
Int *ptr;
//pointer initialization
Ptr = #
//pritning the value
Printf("value of num = %d\n", *ptr);
Return 0;
}
Output
Value of num = 100
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 () {
Intvar;
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
Like other variables pointer variables can be used in expressions.
1) If p1 and p2 are properly declared and initialized pointers, then the following statements are valid:
Y=*p1**p2;
Sum=sum+*p1;
Z=5*-*p2/ *p1;
*p2=*p2+10;
*p1=*p1+*p2;
*p1=*p2-*p1;
NOTE: in the third statement there is a blank space between ‘/’ and * because the symbol /*is considered as beginning of the comment and therefore the statement fails.
2) if p1 and p2 are properly declared and initialized pointers then, ‘C’ allows adding integers to a pointer variable.
EX:
int a=5, b=10;
int *p1,*p2;
p1=&a;
p2=&b;
Now,
P1=p1+1=1000+2=1002;
P1=p1+2=1000+ (2*2) =1004;
P1=p1+4=1000+ (2*4) =1008;
P2=p2+2=3000+ (2*2) =3004;
P2=p2+6=3000+ (2*6) =3012;
Here addition means bytes that pointer data type hold are subtracted number of times that is subtracted to the pointer variable.
3) If p1 & p2 are properly declared and initialized, pointers then
‘C’ allows to subtract integers from pointers. From the above example,
P1=p1-1=1000-2=998;
P1=p1-2=1000-4=996;
P1=p1-4=1000-8=992;
P2=p2-2=3000-4=2996;
P2=p2-6=3000-12=2988;
Here the subtraction means byte that pointer data type hold are subtracted number of times that is subtracted to the pointer variable.
4) If p1 & p2 are properly declared and initialize pointers, and both points to the elements of same type. “Subtraction of one pointer from another pointer is also possible".
NOTE: this operation is done when the both pointer variable points to the elements of the same array.
EX:
P2- P1 (It gives the number of elements between p1 and p2)
5) Pointer can also be used with increment and decrement operators.
Ex:
int a=10;
int *b;
b=&a;
EXAMPLE PROGRAM:
Write a function to calculate the roots. The function must use two pointer parameters, one to receive the coefficients a, b and c and the other to send roots to calling function.
01 | #include<stdio.h> | |
02 | #include<math.h> | |
03 | Roots (p, q) | |
04 | Float*p,*q; | |
05 | { | |
06 | *q= (–(*(p+1) +sqrt((*(p+1))*(*(p+1))–4*(*p)*(*(p+2))))/ | |
07 | (2*(*p)); | |
08 | *(q+1) = (–(*(p+1)-sqrt((*(p+1))*(*(p+1))–4*(*p)*(*(p+2))))/ | |
09 | (2*(*p)); | |
10 | } | |
11 | Voidmain () | |
12 | { | |
13 | FloatA [3], R [2]; | |
14 | Inti; | |
15 | Printf(‘‘Enter values fora, b, c’’); | |
16 | For(i=0; i< = 2; i++) | |
17 | Scanf(‘‘%f’’, A+i); | |
18 | Roots (A, R); | |
19 | Printf(‘‘root1 = %f’’, *(R+0)); | |
20 | Printf(‘‘root2=%f’’, *(R+1)); | |
21 | } | |
22 |
| |
Write a ‘C’ program to compute the sum of all elements stored in an array Using pointers.
01 | /*program to compute sum of all elements stored in an | |
02 | Array */ | |
03 | #include<stdio.h> |
04 | #include<conio.h> |
05 | Main () | |
06 | { | |
07 | Inta [10], I, sum=0,*p; | |
08 | Printf(“enter 10 elements \n”); | |
09 | For(i=0; i<10; i++) | |
10 | Scanf(“%d”, & a[i]); | |
11 | p = a; | |
12 | For(i = 0; i<10; i++) | |
13 | { | |
14 | Sum = sum*p; | |
15 | p++; | |
16 | } | |
17 | Printf(“the sum is % d”, sum); | |
18 | Getch (); | |
19 | } |
Write a ‘C’ program using pointers to determine the length of a character String.
01 | /*program to find the length of a char string */ | |
02 | #include<stdio.h> | |
03 | #include<conio.h> | |
04 | #include<string.h> | |
05 | Main () | |
06 | { | |
07 | Char str [20].*p; | |
08 | Int l=0; | |
09 | Printf(“enter a string \n”); | |
10 | Scanf(“ % s”, str); | |
11 | p=str; | |
12 | While(*p!=’\0’) | |
13 | { | |
14 | l++; | |
15 | p++; | |
16 | } | |
17 | Printf(“the length of the given string is %d”, l); | |
18 | Getch (); | |
19 | } |
It is most likely that you would not understand this section until you are through with the chapter 'Pointers'.
Assuming you have some understanding of pointers in C, let us start: An array name is a constant pointer to the first element of the array. Therefore, in the declaration −
Double balance[50];
Balance is a pointer to &balance[0], which is the address of the first element of the array balance. Thus, the following program fragment assigns p as the address of the first element of balance−
Double *p;
Double balance[10];
p = balance;
It is legal to use array names as constant pointers, and vice versa. Therefore, *(balance + 4) is a legitimate way of accessing the data at balance[4].
Once you store the address of the first element in 'p', you can access the array elements using *p, *(p+1), *(p+2) and so on. Given below is the example to show all the concepts discussed above −
#include <stdio.h>
Int main () {
/* an array with 5 elements */
Double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
Double *p;
Inti;
p = balance;
/* output each array element's value */
Printf( "Array values using pointer\n");
For ( i = 0; i< 5; i++ ) {
Printf("*(p + %d) : %f\n", i, *(p + i) );
}
Printf( "Array values using balance as address\n");
For ( i = 0; i< 5; i++ ) {
Printf("*(balance + %d) : %f\n", i, *(balance + i) );
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Array values using pointer
*(p + 0) : 1000.000000
*(p + 1) : 2.000000
*(p + 2) : 3.400000
*(p + 3) : 17.000000
*(p + 4) : 50.000000
Array values using balance as address
*(balance + 0) : 1000.000000
*(balance + 1) : 2.000000
*(balance + 2) : 3.400000
*(balance + 3) : 17.000000
*(balance + 4) : 50.000000
In the above example, p is a pointer to double, which means it can store the address of a variable of double type. Once we have the address in p, *p will give us the value available at the address stored in p, as we have shown in the above example.
Let us consider the following example, which uses an array of 3 integers −
#include <stdio.h>
Constint MAX = 3;
Int main () {
Intvar[] = {10, 100, 200};
Inti;
For (i = 0; i< MAX; i++) {
Printf("Value of var[%d] = %d\n", i, var[i] );
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
There may be a situation when we want to maintain an array, which can store pointers to an int or char or any other data type available. Following is the declaration of an array of pointers to an integer −
Int *ptr[MAX];
It declares ptr as an array of MAX integer pointers. Thus, each element in ptr, holds a pointer to an int value. The following example uses three integers, which are stored in an array of pointers, as follows −
#include <stdio.h>
Constint MAX = 3;
Int main () {
Intvar[] = {10, 100, 200};
Inti, *ptr[MAX];
For ( i = 0; i< MAX; i++) {
Ptr[i] = &var[i]; /* assign the address of integer. */
}
For ( i = 0; i< MAX; i++) {
Printf("Value of var[%d] = %d\n", i, *ptr[i] );
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
You can also use an array of pointers to character to store a list of strings as follows −
#include <stdio.h>
Constint MAX = 4;
Int main () {
Char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
Inti = 0;
For ( i = 0; i< MAX; i++) {
Printf("Value of names[%d] = %s\n", i, names[i] );
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali
A String is a sequence of characters stored in an array. A string always ends with null ('\0') character. Simply a group of characters forms a string and a group of strings form a sentence. A pointer to array of characters or string can be looks like the following:
C Program - Pointers To Strings 1
Pointer-strings-1.c
#include <stdio.h>
Int main()
{
Char *cities[] = {"Iran", "Iraq"};
Inti;
For(i = 0; i< 2; i++)
Printf("%s\n", cities[i]);
Return 0;
}
- Iran
- Iraq
Note:
In the above pointer to string program, we declared a pointer array of character datatypes and then few strings like "Iran", "Iraq" where initialized to the pointer array (*cities[]). Note that we have not declared the size of the array as it is of character pointer type. Coming to the explanation, cities[] is an array which has its own address and it holds the address of first element (I (Iran) ) in it as a value. This address is then executed by the pointer, i.e) pointer start reading the value from the address stored in the array cities[0] and ends with '\0' by default. Next cities[1] holds the address of (I (Iraq).This address is then executed by the pointer, i.e) pointer start reading the value from the address stored in the array cities[1] and ends with '\0' by default. As a result Iran and Iraq is outputted.
C Program - Pointers To Strings 2
Pointer-strings-2.c
#include <stdio.h>
#include <string.h>
Void function(char**);
Int main()
{
Char *str = "Pointer-to-string";
Inti, j = strlen(str);
For(i = 0; i< j; i++)
Printf("%c", *str++);
Return 0;
}
- Pointer-to-string
Note:
*str is a char pointer variable which is initialized by a string "Pointer-to-String". Then strlen() is used to find the length of the string to do iteration using for loop is done to print the complete characters store with the variable name *str.
Let us consider the following example, which uses an array of 3 integers −
#include <stdio.h>
Constint MAX = 3;
Int main () {
Intvar[] = {10, 100, 200};
Inti;
For (i = 0; i< MAX; i++) {
Printf("Value of var[%d] = %d\n", i, var[i] );
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
There may be a situation when we want to maintain an array, which can store pointers to an int or char or any other data type available. Following is the declaration of an array of pointers to an integer −
Int *ptr[MAX];
It declares ptr as an array of MAX integer pointers. Thus, each element in ptr, holds a pointer to an int value. The following example uses three integers, which are stored in an array of pointers, as follows −
#include <stdio.h>
Constint MAX = 3;
Int main () {
Intvar[] = {10, 100, 200};
Inti, *ptr[MAX];
For ( i = 0; i< MAX; i++) {
Ptr[i] = &var[i]; /* assign the address of integer. */
}
For ( i = 0; i< MAX; i++) {
Printf("Value of var[%d] = %d\n", i, *ptr[i] );
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
You can also use an array of pointers to character to store a list of strings as follows −
#include <stdio.h>
Constint MAX = 4;
Int main () {
Char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
Inti = 0;
For ( i = 0; i< MAX; i++) {
Printf("Value of names[%d] = %s\n", i, names[i] );
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali
C programming allows passing a pointer to a function. To do so, simply declare the function parameter as a pointer type.
Following is a simple example where we pass an unsigned long pointer to a function and change the value inside the function which reflects back in the calling function −
#include <stdio.h>
#include <time.h>
VoidgetSeconds(unsigned long *par);
Int main () {
Unsigned long sec;
GetSeconds(&sec );
/* print the actual value */
Printf("Number of seconds: %ld\n", sec );
Return 0;
}
VoidgetSeconds(unsigned long *par) {
/* get the current number of seconds */
*par = time( NULL );
Return;
}
When the above code is compiled and executed, it produces the following result −
Number of seconds :1294450468
The function, which can accept a pointer, can also accept an array as shown in the following example −
#include <stdio.h>
/* function declaration */
DoublegetAverage(int *arr, int size);
Int main () {
/* an int array with 5 elements */
Int balance[5] = {1000, 2, 3, 17, 50};
Doubleavg;
/* pass pointer to the array as an argument */
Avg = getAverage( balance, 5 ) ;
/* output the returned value */
Printf("Average value is: %f\n", avg );
Return 0;
}
DoublegetAverage(int *arr, int size) {
Inti, sum = 0;
Doubleavg;
For (i = 0; i< size; ++i) {
Sum += arr[i];
}
Avg = (double)sum / size;
Returnavg;
}
When the above code is compiled together and executed, it produces the following result −
Average value is: 214.40000
Similarly, C also allows to return a pointer from a function. To do so, you would have to declare a function returning a pointer as in the following example −
Int * myFunction() {
.
.
.
}
Second point to remember is that, it is not a good idea to return the address of a local variable outside the function, so you would have to define the local variable as static variable.
Now, consider the following function which will generate 10 random numbers and return them using an array name which represents a pointer, i.e., address of first array element.
#include <stdio.h>
#include <time.h>
/* function to generate and return random numbers. */
Int * getRandom( ) {
Staticint r[10];
Inti;
/* set the seed */
Srand( (unsigned)time( NULL ) );
For ( i = 0; i< 10; ++i) {
r[i] = rand();
Printf("%d\n", r[i] );
}
Return r;
}
/* main function to call above defined function */
Int main () {
/* a pointer to an int */
Int *p;
Inti;
p = getRandom();
For ( i = 0; i< 10; i++ ) {
Printf("*(p + [%d]) : %d\n", i, *(p + i) );
}
Return 0;
}
When the above code is compiled together and executed, it produces the following result −
1523198053
1187214107
1108300978
430494959
1421301276
930971084
123250484
106932140
1604461820
149169022
*(p + [0]) : 1523198053
*(p + [1]) : 1187214107
*(p + [2]) : 1108300978
*(p + [3]) : 430494959
*(p + [4]) : 1421301276
*(p + [5]) : 930971084
*(p + [6]) : 123250484
*(p + [7]) : 106932140
*(p + [8]) : 1604461820
*(p + [9]) : 149169022
Functions Pointers Example
For example, the next program swaps two values of two:
Void swap (int *a, int *b);
Int main() {
Int m = 25;
Int n = 100;
Printf("m is %d, n is %d\n", m, n);
Swap(&m, &n);
Printf("m is %d, n is %d\n", m, n);
Return 0;}
Void swap (int *a, int *b) {
Int temp;
Temp = *a;
*a = *b;
*b = temp;}
}
Output:
m is 25, n is 100
m is 100, n is 25
The program swaps the actual variables values because the function accesses them by address using pointers. Here we will discuss the program process:
- We declare the function responsible for swapping the two variable values, which takes two integer pointers as parameters and returns any value when it is called.
- In the main function, we declare and initialize two integer variables ('m' and 'n') then we print their values respectively.
- We call the swap() function by passing the address of the two variables as arguments using the ampersand symbol. After that, we print the new swapped values of variables.
- Here we define the swap() function content which takes two integer variable addresses as parameters and declare a temporary integer variable used as a third storage box to save one of the value variables which will be put to the second variable.
- Save the content of the first variable pointed by 'a' in the temporary variable.
- Store the second variable pointed by b in the first variable pointed by a.
- Update the second variable (pointed by b) by the value of the first variable saved in the temporary variable.
Functions with Array Parameters
In C, we cannot pass an array by value to a function. Whereas, an array name is a pointer (address), so we just pass an array name to a function which means to pass a pointer to the array.
For example, we consider the following program:
Intadd_array (int *a, intnum_elements);
Int main() {
Int Tab[5] = {100, 220, 37, 16, 98};
Printf("Total summation is %d\n", add_array(Tab, 5));
Return 0;}
Intadd_array (int *p, int size) {
Int total = 0;
Int k;
For (k = 0; k < size; k++) {
Total += p[k]; /* it is equivalent to total +=*p ;p++; */}
Return (total);}
Output:
Total summation is 471
Here, we will explain the program code with its details
- We declare and define add_array() function which takes an array address( pointer) with its elements number as parameters and returns the total accumulated summation of these elements. The pointer is used to iterate the array elements (using the p[k] notation), and we accumulate the summation in a local variable which will be returned after iterating the entire element array.
- We declare and initialize an integer array with five integer elements. We print the total summation by passing the array name (which acts as address) and array size to the add_array()called function as arguments.
Functions that Return an Array
In C, we can return a pointer to an array, as in the following program:
#include <stdio.h>
Int * build_array();
Int main() {
Int *a;
a = build_array(); /* get first 5 even numbers */
For (k = 0; k < 5; k++)
Printf("%d\n", a[k]);
Return 0;}
Int * build_array() {
Staticint Tab[5]={1,2,3,4,5};
Return (Tab);}
Output:
1
2
3
4
5
And here, we will discuss the program details
- We define and declare a function which returns an array address containing an integer value and didn't take any arguments.
- We declare an integer pointer which receives the complete array built after the function is called and we print its contents by iterating the entire five element array.
Notice that a pointer, not an array, is defined to store the array address returned by the function. Also notice that when a local variable is being returned from a function, we have to declare it as static in the function.
Function Pointers
As we know by definition that pointers point to an address in any memory location, they can also point to at the beginning of executable code as functions in memory.
A pointer to function is declared with the * ,the general statement of its declaration is:
Return_type (*function_name)(arguments)
You have to remember that the parentheses around (*function_name) are important because without them, the compiler will think the function_name is returning a pointer of return_type.
After defining the function pointer, we have to assign it to a function. For example, the next program declares an ordinary function, defines a function pointer, assigns the function pointer to the ordinary function and after that calls the function through the pointer:
#include <stdio.h>
VoidHi_function (int times); /* function */
Int main() {
Void (*function_ptr)(int); /* function pointer Declaration */
Function_ptr = Hi_function; /* pointer assignment */
Function_ptr (3); /* function call */
Return 0;}
VoidHi_function (int times) {
Int k;
For (k = 0; k < times; k++) printf("Hi\n");}
Output:
Hi
Hi
Hi
- We define and declare a standard function which prints a Hi text k times indicated by the parameter times when the function is called
- We define a pointer function (with its special declaration) which takes an integer parameter and doesn't return anything.
- We initialize our pointer function with the Hi_function which means that the pointer points to the Hi_function().
- Rather than the standard function calling by taping the function name with arguments, we call only the pointer function by passing the number 3 as arguments, and that's it!
Keep in mind that the function name points to the beginning address of the executable code like an array name which points to its first element. Therefore, instructions like function_ptr = &Hi_function and (*funptr)(3) are correct.
NOTE: It is not important to insert the address operator & and the indirection operator * during the function assignment and function call.
Array of Function Pointers
An array of function pointers can play a switch or an if statement role for making a decision, as in the next program:
#include <stdio.h>
Int sum(int num1, int num2);
Int sub(int num1, int num2);
Intmult(int num1, int num2);
Int div(int num1, int num2);
Int main()
{ int x, y, choice, result;
Int (*ope[4])(int, int);
Ope[0] = sum;
Ope[1] = sub;
Ope[2] = mult;
Ope[3] = div;
Printf("Enter two integer numbers: ");
Scanf("%d%d", &x, &y);
Printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: ");
Scanf("%d", &choice);
Result = ope[choice](x, y);
Printf("%d", result);
Return 0;}
Int sum(int x, int y) {return(x + y);}
Int sub(int x, int y) {return(x - y);}
Intmult(int x, int y) {return(x * y);}
Int div(int x, int y) {if (y != 0) return (x / y); else return 0;}
Enter two integer numbers: 13 48
Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2
624
Here, we discuss the program details:
- We declare and define four functions which take two integer arguments and return an integer value. These functions add, subtract, multiply and divide the two arguments regarding which function is being called by the user.
- We declare 4 integers to handle operands, operation type, and result respectively. Also, we declare an array of four function pointer. Each function pointer of array element takes two integers parameters and returns an integer value.
- We assign and initialize each array element with the function already declared. For example, the third element which is the third function pointer will point to multiplication operation function.
- We seek operands and type of operation from the user typed with the keyboard.
- We called the appropriate array element (Function pointer) with arguments, and we store the result generated by the appropriate function.
The instruction int (*ope[4])(int, int); defines the array of function pointers. Each array element must have the same parameters and return type.
The statement result = ope[choice](x, y); runs the appropriate function according to the choice made by the user The two entered integers are the arguments passed to the function.
Functions Using void Pointers
Void pointers are used during function declarations. We use a void * return type permits to return any type. If we assume that our parameters do not change when passing to a function, we declare it as const.
For example:
Void * cube (const void *);
Consider the following program:
#include <stdio.h>
Void* cube (const void* num);
Int main() {
Int x, cube_int;
x = 4;
Cube_int = cube (&x);
Printf("%d cubed is %d\n", x, cube_int);
Return 0;}
Void* cube (const void *num) {
Int result;
Result = (*(int *)num) * (*(int *)num) * (*(int *)num);
Return result;}
Result:
4 cubed is 64
Here, we will discuss the program details:
- We define and declare a function that returns an integer value and takes an address of unchangeable variable without a specific data type. We calculate the cube value of the content variable (x) pointed by the num pointer, and as it is a void pointer, we have to type cast it to an integer data type using a specific notation (* datatype) pointer, and we return the cube value.
- We declare the operand and the result variable. Also, we initialize our operand with value "4."
- We call the cube function by passing the operand address, and we handle the returning value in the result variable
Function Pointers as Arguments
Another way to exploit a function pointer by passing it as an argument to another function sometimes called "callback function" because the receiving function "calls it back."
In the stdlib.h header file, the Quicksort "qsort()" function uses this technique which is an algorithm dedicated to sort an array.
Voidqsort(void *base, size_tnum, size_t width, int (*compare)(const void *, const void *))
- Void *base : void pointer to the array.
- Size_tnum : The array element number.
- Size_t width The element size.
- Int (*compare (const void *, const void *) : function pointer composed of two arguments and returns 0 when the arguments have the same value, <0 when arg1 comes before arg2, and >0 when arg1 comes after arg2.
The following program sorts an integers array from small to big number using qsort() function:
#include <stdio.h>
#include <stdlib.h>
Int compare (const void *, const void *);
Int main() {
Intarr[5] = {52, 14, 50, 48, 13};
Intnum, width, i;
Num = sizeof(arr)/sizeof(arr[0]);
Width = sizeof(arr[0]);
Qsort((void *)arr, num, width, compare);
For (i = 0; i< 5; i++)
Printf("%d ", arr[ i ]);
Return 0;}
Int compare (const void *elem1, const void *elem2) {
If ((*(int *)elem1) == (*(int *)elem2)) return 0;
Else if ((*(int *)elem1) < (*(int *)elem2)) return -1;
Else return 1;}
Result:
13 14 48 50 52
Here, we will discuss the program details:
- We define compare function composed of two arguments and returns 0 when the arguments have the same value, <0 when arg1 comes before arg2, and >0 when arg1 comes after arg2.The parameters are a void pointers type casted to the appropriate array data type (integer)
- We define and initialize an integer array The array size is stored in the num variable and the size of each array element is stored in width variable using sizeof() predefined C operator.
- We call the qsortfunction and pass the array name, size, width, and comparison function defined previously by the user in order to sort our array in ascending order.The comparison will be performed by taking in each iteration two array elements until the entire array will be sorted.
- We print the array elements to be sure that our array is well sorted by iterating the entire array using for loop.
You can define pointers to structures in the same way as you define pointer to any other variable −
Struct Books *struct_pointer;
Now, you can store the address of a structure variable in the above defined pointer variable. To find the address of a structure variable, place the '&'; operator before the structure's name as follows −
Struct_pointer = &Book1;
To access the members of a structure using a pointer to that structure, you must use the → operator as follows −
Struct_pointer->title;
Let us re-write the above example using structure pointer.
#include <stdio.h>
#include <string.h>
Struct Books {
Char title[50];
Char author[50];
Char subject[100];
Intbook_id;
};
/* function declaration */
VoidprintBook( struct Books *book );
Int main( ) {
Struct Books Book1; /* Declare Book1 of type Book */
Struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
Strcpy( Book1.title, "C Programming");
Strcpy( Book1.author, "Nuha Ali");
Strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* book 2 specification */
Strcpy( Book2.title, "Telecom Billing");
Strcpy( Book2.author, "Zara Ali");
Strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/* print Book1 info by passing address of Book1 */
PrintBook(&Book1 );
/* print Book2 info by passing address of Book2 */
PrintBook(&Book2 );
Return 0;
}
VoidprintBook( struct Books *book ) {
Printf( "Book title : %s\n", book->title);
Printf( "Book author : %s\n", book->author);
Printf( "Book subject : %s\n", book->subject);
Printf( "Book book_id : %d\n", book->book_id);
}
When the above code is compiled and executed, it produces the following result −
Book title : C Programming
Book author :Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700
Bit Fields
Bit Fields allow the packing of data in a structure. This is especially useful when memory or data storage is at a premium. Typical examples include −
- Packing several objects into a machine word. e.g. 1 bit flags can be compacted.
- Reading external file formats -- non-standard file formats could be read in, e.g., 9-bit integers.
C allows us to do this in a structure definition by putting :bit length after the variable. For example −
Structpacked_struct {
Unsignedint f1:1;
Unsignedint f2:1;
Unsignedint f3:1;
Unsignedint f4:1;
Unsignedint type:4;
Unsignedint my_int:9;
} pack;
Here, the packed_struct contains 6 members: Four 1 bit flags f1..f3, a 4-bit type and a 9-bit my_int.
C automatically packs the above bit fields as compactly as possible, provided that the maximum length of the field is less than or equal to the integer word length of the computer. If this is not the case, then some compilers may allow memory overlap for the fields while others would store the next field in the next word.
C malloc()
The name "malloc" stands for memory allocation.
The malloc() function reserves a block of memory of the specified number of bytes. And, it returns a pointer of void which can be casted into pointers of any form.
Syntax of malloc()
Ptr = (castType*) malloc(size);
Example
Ptr = (float*) malloc(100 * sizeof(float));
The above statement allocates 400 bytes of memory. It's because the size of float is 4 bytes. And, the pointer ptr holds the address of the first byte in the allocated memory.
The expression results in a NULL pointer if the memory cannot be allocated.
C calloc()
The name "calloc" stands for contiguous allocation.
The malloc() function allocates memory and leaves the memory uninitialized. Whereas, the calloc() function allocates memory and initializes all bits to zero.
Syntax of calloc()
Ptr = (castType*)calloc(n, size);
Example:
Ptr = (float*) calloc(25, sizeof(float));
The above statement allocates contiguous space in memory for 25 elements of type float.
C free()
Dynamically allocated memory created with either calloc() or malloc() doesn't get freed on their own. You must explicitly use free() to release the space.
Syntax of free()
Free(ptr);
This statement frees the space allocated in the memory pointed by ptr.
Example 1: malloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) malloc(n * sizeof(int));
// if memory cannot be allocated
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i< n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
// deallocating the memory
Free(ptr);
Return 0;
}
Here, we have dynamically allocated the memory for n number of int.
Example 2: calloc() and free()
// Program to calculate the sum of n numbers entered by the user
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int n, i, *ptr, sum = 0;
Printf("Enter number of elements: ");
Scanf("%d", &n);
Ptr = (int*) calloc(n, sizeof(int));
If(ptr == NULL)
{
Printf("Error! memory not allocated.");
Exit(0);
}
Printf("Enter elements: ");
For(i = 0; i< n; ++i)
{
Scanf("%d", ptr + i);
Sum += *(ptr + i);
}
Printf("Sum = %d", sum);
Free(ptr);
Return 0;
}
C realloc()
If the dynamically allocated memory is insufficient or more than required, you can change the size of previously allocated memory using the realloc() function.
Syntax of realloc()
Ptr = realloc(ptr, x);
Here, ptr is reallocated with a new size x.
Example 3: realloc()
#include <stdio.h>
#include <stdlib.h>
Int main()
{
Int *ptr, i , n1, n2;
Printf("Enter size: ");
Scanf("%d", &n1);
Ptr = (int*) malloc(n1 * sizeof(int));
Printf("Addresses of previously allocated memory: ");
For (i = 0; i< n1; ++i)
Printf("%u\n",ptr + i);
Printf("\nEnter the new size: ");
Scanf("%d", &n2);
// rellocating the memory
Ptr = realloc(ptr, n2 * size of(int));
Printf("Addresses of newly allocated memory: ");
For(i = 0; i< n2; ++i)
Printf("%u\n", ptr + i);
Free(ptr);
Return 0;
}
When you run the program, the output will be:
Enter size: 2
Addresses of previously allocated memory:26855472
26855476
Enter the new size: 4
Addresses of newly allocated memory:26855472
26855476
26855480
26855484
TEXT BOOKS:
C & Data Structures (A practical approach) – by G.S. Baluja and G.K. Baluja, Dhanapatrai & Co publishers.