Unit 4
Function and Dynamic Memory Allocation
Functions:
Structured Programming Approach, as the word suggests, can be defined as a programming approach in which the program is made as a single structure. It means that the code will execute the instruction by instruction one after the other. It doesn’t support the possibility of jumping from one instruction to some other with the help of any statement like GOTO, etc. Therefore, the instructions in this approach will be executed in a serial and structured manner. The languages that support Structured programming approach are:
- C
- C++
- Java
- C#
..etc
On the contrary, in the Assembly languages like Microprocessor 8085, etc, the statements do not get executed in a structured manner. It allows jump statements like GOTO. So the program flow might be random.
The structured program mainly consists of three types of elements:
- Selection Statements
- Sequence Statements
- Iteration Statements
The structured program consists of well-structured and separated modules. But the entry and exit in a Structured program is a single-time event. It means that the program uses single-entry and single-exit elements. Therefore a structured program is well maintained, neat and clean program. This is the reason why the Structured Programming Approach is well accepted in the programming world.
Advantages of Structured Programming Approach:
- Easier to read and understand
- User Friendly
- Easier to Maintain
- Mainly problem based instead of being machine based
- Development is easier as it requires less effort and time
- Easier to Debug
- Machine-Independent, mostly.
Disadvantages of Structured Programming Approach:
- Since it is Machine-Independent, So it takes time to convert into machine code.
- The converted machine code is not the same as for assembly language.
- The program depends upon changeable factors like data-types. Therefore it needs to be updated with the need on the go.
- Usually the development in this approach takes longer time as it is language-dependent. Whereas in the case of assembly language, the development takes lesser time as it is fixed for the machine.
A function is a group of statements that together perform a task. Every C program has at least one function, which is main(), and all the most trivial programs can define additional functions.
You can divide up your code into separate functions. How you divide up your code among different functions is up to you, but logically the division is such that each function performs a specific task.
A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function.
The C standard library provides numerous built-in functions that your program can call. For example, strcat() to concatenate two strings, memcpy() to copy one memory location to another location, and many more functions.
A function can also be referred as a method or a sub-routine or a procedure, etc.
Defining a Function
The general form of a function definition in C programming language is as follows −
Return_type function_name(parameter list ) {
Body of the function
}
A function definition in C programming consists of a function header and a function body. Here are all the parts of a function −
- Return Type − A function may return a value. The return_type is the data type of the value the function returns. Some functions perform the desired operations without returning a value. In this case, the return_type is the keyword void.
- Function Name − This is the actual name of the function. The function name and the parameter list together constitute the function signature.
- Parameters − A parameter is like a placeholder. When a function is invoked, you pass a value to the parameter. This value is referred to as actual parameter or argument. The parameter list refers to the type, order, and number of the parameters of a function. Parameters are optional; that is, a function may contain no parameters.
- Function Body − The function body contains a collection of statements that define what the function does.
Example
Given below is the source code for a function called max(). This function takes two parameters num1 and num2 and returns the maximum value between the two −
/* function returning the max between two numbers */
Int max(int num1, int num2) {
/* local variable declaration */
Int result;
If (num1 > num2)
Result = num1;
Else
Result = num2;
Return result;
}
Function Declarations
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_type function_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 signature (or type signature, or method signature) defines input and output of functions or methods.
A signature can include:
- Parameters and their types
- a return value and type
- Exceptions that might be thrown or passed back
- Information about the availability of the method in an object-oriented program (such as the keywords public, static, or prototype).
So a function either can take some arguments, or nothing is taken. Similarly, a function can return something, otherwise does not return anything. So we can categorize them into four types.
- Function with No argument and No return type.
- Function with No argument and Return something.
- A function that takes argument but returns nothing.
- Functions that take an argument and also return something.
Example
#include <stdio.h>
Void my_function() {
Printf("This is a function that takes no argument, and returns nothing.");
}
Main() {
My_function();
}
Output
This is a function that takes no argument, and returns nothing.
Here this function is not taking any input argument, and also the return type is void. So this returns nothing.
Example
#include <stdio.h>
Int my_function() {
Printf("This function takes no argument, But returns 50\n");
Return 50;
}
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>
Void my_function(int x) {
Printf("This function is taking %d as argument, but returns nothing", x);
Return 50;
}
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>
Int my_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.
This is the default way of passing the parameters to the function. This is achieved by passing the copy of data to the function. This mechanism is also called as call by value. In case of parameter passing by value, the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function.
This mechanism is used when programmer don't want to change the value of passed parameters. When parameters are passed by value then functions in C create copies of the passed in variables and do required processing on these copied variables.
Pass-by-value is implemented by actual data transfer so additional storage is required to maintain the copies of passed parameters.
Example:
#include <stdio.h>
#include<conio.h>
/* function declaration goes here.*/
Void swap( int p1, int p2 );
Int main()
{
Int a = 10;
Int b = 20;
Printf("Before: Value of a = %d and value of b = %d\n", a, b );
Swap( a, b );
Printf("After: Value of a = %d and value of b = %d\n", a, b );
Getch();
}
Void swap( int p1, int p2 )
{
Int t;
t = p2;
p2 = p1;
p1 = t;
Printf("Value of a (p1) = %d and value of b(p2) = %d\n", p1, p2 );
}
Output :
Before: Value of a = 10 and value of b = 20
Value of a (p1) = 20 and value of b (p2) = 10
After: Value of a = 10 and value of b = 20
Note: In the above example the values of “a” and “b” remain unchanged before calling swap function and after calling swap function.
The function called at program startup is named main . The main function can be defined with no parameters or with two parameters (for passing command-line arguments to a program when it begins executing). The two parameters are referred to here as argc and argv, though any names can be used because they are local to the function in which they are declared.
A main function has the following syntax:
Int main(void) { . . . }
Int main(int argc, char *argv[ ]) { . . . })
Argc
The number of arguments in the command line that invoked the program. The value of argc is nonnegative.
Argv
Pointer to an array of character strings that contain the arguments, one per string. The value argv[argc] is a null pointer.
If the value of argc is greater than zero, the array members argv[0] through argv[argc - 1] inclusive contain pointers to strings, which are given implementation-defined values by the host environment before program startup. The intent is to supply the program with information determined before program startup from elsewhere in the host environment.
If the host environment cannot supply strings with letters in both uppercase and lowercase, the host environment ensures that the strings are received in lowercase.
If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; argv[0][0] is the null character if the program name is not available from the host environment.
If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc –
1] represent the program parameters.
The parameters argc and argv, and the strings pointed to by the argv array, can be modified by the program and keep their last-stored values between program startup and program termination.
In the main function definition, parameters are optional. However, only the parameters that are defined can be accessed.
Call by value | Call by reference |
While calling a function we pass values of variables to it. Such functions are known as call by value. | While calling a function instead of passing the values of variables we pass the address of the variable. This is known as call by reference |
In this method the value of each variable in calling function is copied into corresponding dummy variables of the called function. | In this method the value of actual variable in the calling function are copied into dummy variables of the called function. |
With this method the changes made to the dummy variable in the called function have no effect on the values of actual variables in the calling function. | With this method using addresses we would have access to the actual variables and hence we would be able to manipulate them. |
In C, there are various general problems which requires passing more than one variable of the same type to a function. For example, consider a function which sorts the 10 elements in ascending order. Such a function requires 10 numbers to be passed as the actual parameters from the main function. Here, instead of declaring 10 different numbers and then passing into the function, we can declare and initialize an array and pass that into the function. This will resolve all the complexity since the function will now work for any number of values.
As we know that the array_name contains the address of the first element. Here, we must notice that we need to pass only the name of the array in the function which is intended to accept an array. The array defined as the formal parameter will automatically refer to the array specified by the array name defined as an actual parameter.
Consider the following syntax to pass an array to the function.
- Functionname(arrayname);//passing array
Methods to declare a function that receives an array as an argument
There are 3 ways to declare the function which is intended to receive an array as an argument.
First way:
- Return_type function(type arrayname[])
Declaring blank subscript notation [] is the widely used technique.
Second way:
- Return_type function(type arrayname[SIZE])
Optionally, we can define size in subscript notation [].
Third way:
- Return_type function(type *arrayname)
You can also use the concept of a pointer. In pointer chapter, we will learn about it.
C language passing an array to function example
- #include<stdio.h>
- Int minarray(int arr[],int size){
- Int min=arr[0];
- Int i=0;
- For(i=1;i<size;i++){
- If(min>arr[i]){
- Min=arr[i];
- }
- }//end of for
- Return min;
- }//end of function
- Int main(){
- Int i=0,min=0;
- Int numbers[]={4,5,7,3,8,9};//declaration of array
- Min=minarray(numbers,6);//passing array with size
- Printf("minimum number is %d \n",min);
- Return 0;
- }
Output
Minimum number is 3
C function to sort the array
- #include<stdio.h>
- Void Bubble_Sort(int[]);
- Void main ()
- {
- Int arr[10] = { 10, 9, 7, 101, 23, 44, 12, 78, 34, 23};
- Bubble_Sort(arr);
- }
- Void Bubble_Sort(int a[]) //array a[] points to arr.
- {
- Int i, j,temp;
- For(i = 0; i<10; i++)
- {
- For(j = i+1; j<10; j++)
- {
- If(a[j] < a[i])
- {
- Temp = a[i];
- a[i] = a[j];
- a[j] = temp;
- }
- }
- }
- Printf("Printing Sorted Element List ...\n");
- For(i = 0; i<10; i++)
- {
- Printf("%d\n",a[i]);
- }
- }
Output
Printing Sorted Element List ...
7
9
10
12
23
23
34
44
78
101
Returning array from the function
As we know that, a function can not return more than one value. However, if we try to write the return statement as return a, b, c; to return three values (a,b,c), the function will return the last mentioned value which is c in our case. In some problems, we may need to return multiple values from a function. In such cases, an array is returned from the function.
Returning an array is similar to passing the array into the function. The name of the array is returned from the function. To make a function returning an array, the following syntax is used.
- Int * Function_name() {
- //some statements;
- Return array_type;
- }
To store the array returned from the function, we can define a pointer which points to that array. We can traverse the array by increasing that pointer since pointer initially points to the base address of the array. Consider the following example that contains a function returning the sorted array.
- #include<stdio.h>
- Int* Bubble_Sort(int[]);
- Void main ()
- {
- Int arr[10] = { 10, 9, 7, 101, 23, 44, 12, 78, 34, 23};
- Int *p = Bubble_Sort(arr), i;
- Printf("printing sorted elements ...\n");
- For(i=0;i<10;i++)
- {
- Printf("%d\n",*(p+i));
- }
- }
- Int* Bubble_Sort(int a[]) //array a[] points to arr.
- {
- Int i, j,temp;
- For(i = 0; i<10; i++)
- {
- For(j = i+1; j<10; j++)
- {
- If(a[j] < a[i])
- {
- Temp = a[i];
- a[i] = a[j];
- a[j] = temp;
- }
- }
- }
- Return a;
- }
Output
Printing Sorted Element List ...
7
9
10
12
23
23
34
44
78
101
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>
Void getSeconds(unsigned long *par);
Int main () {
Unsigned long sec;
GetSeconds( &sec );
/* print the actual value */
Printf("Number of seconds: %ld\n", sec );
Return 0;
}
Void getSeconds(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 */
Double getAverage(int *arr, int size);
Int main () {
/* an int array with 5 elements */
Int balance[5] = {1000, 2, 3, 17, 50};
Double avg;
/* 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;
}
Double getAverage(int *arr, int size) {
Int i, sum = 0;
Double avg;
For (i = 0; i < size; ++i) {
Sum += arr[i];
}
Avg = (double)sum / size;
Return avg;
}
When the above code is compiled together and executed, it produces the following result −
Average value is: 214.40000
The call by reference method of passing arguments to a function copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call. It means the changes made to the parameter affect the passed argument.
To pass a value by reference, argument pointers are passed to the functions just like any other value. So accordingly you need to declare the function parameters as pointer types as in the following function swap(), which exchanges the values of the two integer variables pointed to, by their arguments.
/* function definition to swap the values */
Void swap(int *x, int *y) {
Int temp;
Temp = *x; /* save the value at address x */
*x = *y; /* put y into x */
*y = temp; /* put temp into y */
Return;
}
Let us now call the function swap() by passing values by reference as in the following example −
#include <stdio.h>
/* function declaration */
Void swap(int *x, int *y);
Int main () {
/* local variable definition */
Int a = 100;
Int b = 200;
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.
* &a indicates pointer to a ie. Address of variable a and
* &b indicates pointer to b ie. Address of variable b.
*/
Swap(&a, &b);
Printf("After swap, value of a : %d\n", a );
Printf("After swap, value of b : %d\n", b );
Return 0;
}
Let us put the above code in a single C file, compile and execute it, to produce the following result −
Before swap, value of a :100
Before swap, value of b :200
After swap, value of a :200
After swap, value of b :100
It shows that the change has reflected outside the function as well, unlike call by value where the changes do not reflect outside the function.
C Standard library functions or simply C Library functions are inbuilt functions in C programming.
The prototype and data definitions of these functions are present in their respective header files. To use these functions we need to include the header file in our program. For example,
If you want to use the printf() function, the header file <stdio.h> should be included.
#include <stdio.h>
Int main()
{
Printf("Catch me if you can.");
}
If you try to use printf() without including the stdio.h header file, you will get an error.
Advantages of Using C library functions
1. They work
One of the most important reasons you should use library functions is simply because they work. These functions have gone through multiple rigorous testing and are easy to use.
2. The functions are optimized for performance
Since, the functions are "standard library" functions, a dedicated group of developers constantly make them better. In the process, they are able to create the most efficient code optimized for maximum performance.
3. It saves considerable development time
Since the general functions like printing to a screen, calculating the square root, and many more are already written. You shouldn't worry about creating them once again.
4. The functions are portable
With ever-changing real-world needs, your application is expected to work every time, everywhere. And, these library functions help you in that they do the same thing on every computer.
Example: Square root using sqrt() function
Suppose, you want to find the square root of a number.
To can compute the square root of a number, you can use the sqrt() library function. The function is defined in the math.h header file.
#include <stdio.h>
#include <math.h>
Int main()
{
Float num, root;
Printf("Enter a number: ");
Scanf("%f", &num);
// Computes the square root of num and stores in root.
Root = sqrt(num);
Printf("Square root of %.2f = %.2f", num, root);
Return 0;
}
When you run the program, the output will be:
Enter a number: 12
Square root of 12.00 = 3.46
Library Functions in Different Header Files
C Header Files | |
<assert.h> | Program assertion functions |
<ctype.h> | Character type functions |
<locale.h> | Localization functions |
<math.h> | Mathematics functions |
<setjmp.h> | Jump functions |
<signal.h> | Signal handling functions |
<stdarg.h> | Variable arguments handling functions |
<stdio.h> | Standard Input/Output functions |
<stdlib.h> | Standard Utility functions |
<string.h> | String handling functions |
<time.h> | Date time functions |
Recursion:
#include <stdio.h>
Int fact (int);
Int main()
{
Int n,f;
Printf("Enter the number whose factorial you want to calculate?");
Scanf("%d",&n);
f = fact(n);
Printf("factorial = %d",f);
}
Int fact(int n)
{
If (n==0)
{
Return 0;
}
Else if ( n == 1)
{
Return 1;
}
Else
{
Return n*fact(n-1);
}
}
Output
Enter the number whose factorial you want to calculate?5
Factorial = 120
We can understand the above program of the recursive method call by the figure given below:
#include<stdio.h>
Int fibonacci(int);
Void main ()
{
Int n,f;
Printf("Enter the value of n?");
Scanf("%d",&n);
f = fibonacci(n);
Printf("%d",f);
}
Int fibonacci (int n)
{
If (n==0)
{
Return 0;
}
Else if (n == 1)
{
Return 1;
}
Else
{
Return fibonacci(n-1)+fibonacci(n-2);
}
}
Output
Enter the value of n?12
144
Recursion in C
When a function calls itself from its body is called Recursion.
Advantages
- Reduce unnecessary calling of function.
- Through Recursion one can Solve problems in easy way while its iterative solution is very big and complex.
Disdvantages
- Recursive solution is always logical and it is very difficult to trace.(debug and understand).
- In recursive we must have an if statement somewhere to force the function to return without the recursive call being executed, otherwise the function will never return.
- Recursion takes a lot of stack space, usually not considerable when the program is small and running on a PC.
- Recursion uses more processor time.
Example : C program to calculate factorial using recursion
#include<stdio.h>
Long Factorial(int);
Void main()
{
Int num;
Long fact;
Printf("\n\tEnter any positive number : ");
Scanf("%d",&num);
Fact = Factorial(num);
Printf("\n\tThe Factorial of %d is %ld",num,fact);
}
Long Factorial(int num)
{
If (num == 1)
Return 1;
Else
Return num*Factorial(num-1);
}
Output :
Enter any positive number :
The Factorial of 10 is 3628800
Each recursive call creates a new copy of that method in the memory. Once some data is returned by the method, the copy is removed from the memory. Since all the variables and other stuff declared inside function get stored in the stack, therefore a separate stack is maintained at each recursive call. Once the value is returned from the corresponding function, the stack gets destroyed. Recursion involves so much complexity in resolving and tracking the values at each recursive call. Therefore we need to maintain the stack and track the values of the variables defined in the stack.
Let us consider the following example to understand the memory allocation of the recursive functions.
Int display (int n)
{
If(n == 0)
Return 0; // terminating condition
Else
{
Printf("%d",n);
Return display(n-1); // recursive call
}
}
Explanation
Let us examine this recursive function for n = 4. First, all the stacks are maintained which prints the corresponding value of n until n becomes 0, Once the termination condition is reached, the stacks get destroyed one by one by returning 0 to its calling stack. Consider the following image for more information regarding the stack trace for the recursive functions.
The concept of dynamic memory allocation in c language enables the C programmer to allocate memory at runtime. Dynamic memory allocation in c language is possible by 4 functions of stdlib.h header file.
- Malloc()
- Calloc()
- Realloc()
- Free()
Before learning above functions, let's understand the difference between static memory allocation and dynamic memory allocation.
Static memory allocation | Dynamic memory allocation |
Memory is allocated at compile time. | Memory is allocated at run time. |
Memory can't be increased while executing program. | Memory can be increased while executing program. |
Used in array. | Used in linked list. |
Now let's have a quick look at the methods used for dynamic memory allocation.
Malloc() | Allocates single block of requested memory. |
Calloc() | Allocates multiple block of requested memory. |
Realloc() | Reallocates the memory occupied by malloc() or calloc() functions. |
Free() | Frees the dynamically allocated memory. |
Malloc() function in C
The malloc() function allocates single block of requested memory.
It doesn't initialize memory at execution time, so it has garbage value initially.
It returns NULL if memory is not sufficient.
The syntax of malloc() function is given below:
- Ptr=(cast-type*)malloc(byte-size)
Let's see the example of malloc() function.
- #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)); //memory allocated using malloc
- If(ptr==NULL)
- {
- Printf("Sorry! unable to allocate memory");
- Exit(0);
- }
- Printf("Enter elements of array: ");
- For(i=0;i<n;++i)
- {
- Scanf("%d",ptr+i);
- Sum+=*(ptr+i);
- }
- Printf("Sum=%d",sum);
- Free(ptr);
- Return 0;
- }
Output
Enter elements of array: 3
Enter elements of array: 10
10
10
Sum=30
Calloc() function in C
The calloc() function allocates multiple block of requested memory.
It initially initialize all bytes to zero.
It returns NULL if memory is not sufficient.
The syntax of calloc() function is given below:
- Ptr=(cast-type*)calloc(number, byte-size)
Let's see the example of calloc() function.
- #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)); //memory allocated using calloc
- If(ptr==NULL)
- {
- Printf("Sorry! unable to allocate memory");
- Exit(0);
- }
- Printf("Enter elements of array: ");
- For(i=0;i<n;++i)
- {
- Scanf("%d",ptr+i);
- Sum+=*(ptr+i);
- }
- Printf("Sum=%d",sum);
- Free(ptr);
- Return 0;
- }
Output
Enter elements of array: 3
Enter elements of array: 10
10
10
Sum=30
Realloc() function in C
If memory is not sufficient for malloc() or calloc(), you can reallocate the memory by realloc() function. In short, it changes the memory size.
Let's see the syntax of realloc() function.
- Ptr=realloc(ptr, new-size)
Free() function in C
The memory occupied by malloc() or calloc() functions must be released by calling free() function. Otherwise, it will consume memory until program exit.
Let's see the syntax of free() function.
- Free(ptr)
In the following examples, we have considered ‘r‘ as number of rows, ‘c‘ as number of columns and we created a 2D array with r = 3, c = 4 and following values
1 2 3 4
5 6 7 8
9 10 11 12
1) Using a single pointer:
A simple way is to allocate memory block of size r*c and access elements using simple pointer arithmetic.
#include <stdio.h> #include <stdlib.h>
Int main() { Int r = 3, c = 4; Int *arr = (int *)malloc(r * c * sizeof(int));
Int i, j, count = 0; For (i = 0; i < r; i++) For (j = 0; j < c; j++) *(arr + i*c + j) = ++count;
For (i = 0; i < r; i++) For (j = 0; j < c; j++) Printf("%d ", *(arr + i*c + j));
/* Code for further processing and free the Dynamically allocated memory */
Return 0; } |
Output:
1 2 3 4 5 6 7 8 9 10 11 12
2) Using an array of pointers
We can create an array of pointers of size r. Note that from C99, C language allows variable sized arrays. After creating an array of pointers, we can dynamically allocate memory for every row.
#include <stdio.h> #include <stdlib.h>
Int main() { Int r = 3, c = 4, i, j, count;
Int *arr[r]; For (i=0; i<r; i++) Arr[i] = (int *)malloc(c * sizeof(int));
// Note that arr[i][j] is same as *(*(arr+i)+j) Count = 0; For (i = 0; i < r; i++) For (j = 0; j < c; j++) Arr[i][j] = ++count; // Or *(*(arr+i)+j) = ++count
For (i = 0; i < r; i++) For (j = 0; j < c; j++) Printf("%d ", arr[i][j]);
/* Code for further processing and free the Dynamically allocated memory */
Return 0; } |
Output:
1 2 3 4 5 6 7 8 9 10 11 12
3) Using pointer to a pointer
We can create an array of pointers also dynamically using a double pointer. Once we have an array pointers allocated dynamically, we can dynamically allocate memory and for every row like method 2.
#include <stdio.h> #include <stdlib.h>
Int main() { Int r = 3, c = 4, i, j, count;
Int **arr = (int **)malloc(r * sizeof(int *)); For (i=0; i<r; i++) Arr[i] = (int *)malloc(c * sizeof(int));
// Note that arr[i][j] is same as *(*(arr+i)+j) Count = 0; For (i = 0; i < r; i++) For (j = 0; j < c; j++) Arr[i][j] = ++count; // OR *(*(arr+i)+j) = ++count
For (i = 0; i < r; i++) For (j = 0; j < c; j++) Printf("%d ", arr[i][j]);
/* Code for further processing and free the Dynamically allocated memory */
Return 0; } |
Output:
1 2 3 4 5 6 7 8 9 10 11 12
4) Using double pointer and one malloc call
#include<stdio.h> #include<stdlib.h>
Int main() { Int r=3, c=4, len=0; Int *ptr, **arr; Int count = 0,i,j;
Len = sizeof(int *) * r + sizeof(int) * c * r; Arr = (int **)malloc(len);
// ptr is now pointing to the first element in of 2D array Ptr = (int *)(arr + r);
// for loop to point rows pointer to appropriate location in 2D array For(i = 0; i < r; i++) Arr[i] = (ptr + c * i);
For (i = 0; i < r; i++) For (j = 0; j < c; j++) Arr[i][j] = ++count; // OR *(*(arr+i)+j) = ++count
For (i = 0; i < r; i++) For (j = 0; j < c; j++) Printf("%d ", arr[i][j]);
Return 0; } |
Output:
1 2 3 4 5 6 7 8 9 10 11 12