UNIT 3
Arrays
One dimensional Array
A one-dimensional array is a group of elements having the same datatype and same name. Individual elements are referred to using common name and unique index of the elements.
The simplest form of an array is one-dimensional-array. The array itself is given name and its elements are referred to by their subscripts. In , an array is denoted as follows:
Array_name[array_size]
Where size specifies the number of elements in the array and the subscript (also called index) value ranges from 0 through size-1.
Declare One Dimensional Array
Here is the general form to declare one dimensional array in
Data_type array_name[array_size];
Here, data_type is any valid data type, array_name is the name of the array, and array_size is the size of array. Here is an example, declaring an array named arr of int type, having maximum element size of 10 elements
Int arr[10];
Initialize One Dimensional Array
Here is the general form to initialize values to one dimensional array
Data_type array_name[array_size] = {comma_separated_element_list};
Here is an example, declaring and initializing values to the array name arr of type int, containing 10 elements
Int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
One Dimensional Array Example
Here are some example program, demonstrating one dimensional array
/*One Dimensional Array */
#include<iostream.h>
#include<conio.h>
Void main()
{
Clrscr();
Int arr[5] = {1, 2, 3, 4, 5};
Int i;
For(i=0; i<5; i++)
{
Cout<<"arr["<<i<<"] = "<<arr[i]<<"\n";
}
Getch();
}
Here is the sample output of this program:
Here is another example, also demonstrating one dimension array in
/* One Dimensional Array */
#include<iostream.h>
#include<conio.h>
Void main()
{
Clrscr();
Int arr[10];
Int i;
Int sum=0, avg=0;
Cout<<"Enter 10 array elements: ";
For(i=0; i<10; i++)
{
Cin>>arr[i];
Sum = sum + arr[i];
}
Cout<<"\nThe array elements are: \n";
For(i=0; i<10; i++)
{
Cout<<arr[i]<<" ";
}
Cout<<"\n\nSum of all elements is: "<<sum;
Avg = sum/10;
Cout<<"\nAnd average is: "<<avg;
Getch();
}
Here is the sample run of the above program:
Below is another program on one-dimensional array in
/* One Dimensional Array */
#include<iostream.h>
#include<conio.h>
Void main()
{
Clrscr();
Int arr[5];
Int i, position, index;
Cout<<"Enter 5 array elements: ";
For(i=0; i<5; i++)
{
Cin>>arr[i];
}
Cout<<"\nIndex\t\tPosition";
For(i=0; i<5; i++)
{
Cout<<"\n";
Cout<<i<<" = "<<arr[i]<<"\t\t"<<i+1<<" = "<<arr[i+1];
}
Cout<<" (Garbage value/not of array)";
Cout<<"\n\nImportant - Array element can only be accessed by indexing the array\n";
Cout<<"Note - Array index always starts from 0";
Getch();
}
Below is the sample run of this program:
Let's take one more program, on single or one dimensional array
/* One Dimensional Array */
#include<iostream.h>
#include<conio.h>
Void main()
{
Clrscr();
Int arr[10];
Int i, position, index;
Cout<<"Enter 10 array elements: ";
For(i=0; i<10; i++)
{
Cin>>arr[i];
}
Cout<<"Accessing element at position...Enter position...";
Cin>>position;
Cout<<"\nElement present at position "<<position<<" is "<<arr[position+1];
Cout<<"\n\nAccessing element at index..Enter index..";
Cin>>index;
Cout<<"\nElement present at index "<<index<<" is "<<arr[index];
Getch();
}
Here is the sample run of the above program:
Two Dimensional Array
The two-dimensional array can be defined as an array of arrays. The 2D array is organized as matrices which can be represented as the collection of rows and columns. However, 2D arrays are created to implement a relational database lookalike data structure. It provides ease of holding the bulk of data at once which can be passed to any number of functions wherever required.
Declaration of two dimensional Array in C
The syntax to declare the 2D array is given below.
- Data_type array_name[rows][columns];
Consider the following example.
- Int twodimen[4][3];
Here, 4 is the number of rows, and 3 is the number of columns.
Initialization of 2D Array in C
In the 1D array, we don't need to specify the size of the array if the declaration and initialization are being done simultaneously. However, this will not work with 2D arrays. We will have to define at least the second dimension of the array. The two-dimensional array can be declared and defined in the following way.
- Int arr[4][3]={{1,2,3},{2,3,4},{3,4,5},{4,5,6}};
Two-dimensional array example in C
- #include<stdio.h>
- Int main(){
- Int i=0,j=0;
- Int arr[4][3]={{1,2,3},{2,3,4},{3,4,5},{4,5,6}};
- //traversing 2D array
- For(i=0;i<4;i++){
- For(j=0;j<3;j++){
- Printf("arr[%d] [%d] = %d \n",i,j,arr[i][j]);
- }//end of j
- }//end of i
- Return 0;
- }
Output
Arr[0][0] = 1
Arr[0][1] = 2
Arr[0][2] = 3
Arr[1][0] = 2
Arr[1][1] = 3
Arr[1][2] = 4
Arr[2][0] = 3
Arr[2][1] = 4
Arr[2][2] = 5
Arr[3][0] = 4
Arr[3][1] = 5
Arr[3][2] = 6
C 2D array example: Storing elements in a matrix and printing it.
- #include <stdio.h>
- Void main ()
- {
- Int arr[3][3],i,j;
- For (i=0;i<3;i++)
- {
- For (j=0;j<3;j++)
- {
- Printf("Enter a[%d][%d]: ",i,j);
- Scanf("%d",&arr[i][j]);
- }
- }
- Printf("\n printing the elements ....\n");
- For(i=0;i<3;i++)
- {
- Printf("\n");
- For (j=0;j<3;j++)
- {
- Printf("%d\t",arr[i][j]);
- }
- }
- }
Output
Enter a[0][0]: 56
Enter a[0][1]: 10
Enter a[0][2]: 30
Enter a[1][0]: 34
Enter a[1][1]: 21
Enter a[1][2]: 34
Enter a[2][0]: 45
Enter a[2][1]: 56
Enter a[2][2]: 78
Printing the elements ....
56 10 30
34 21 34
45 56 78
The string can be defined as the one-dimensional array of characters terminated by a null ('\0'). The character array or the string is used to manipulate text such as word or sentences. Each character in the array occupies one byte of memory, and the last character must always be 0. The termination character ('\0') is important in a string since it is the only way to identify where the string ends. When we define a string as char s[10], the character s[10] is implicitly initialized with the null in the memory.
There are two ways to declare a string in c language.
- By char array
- By string literal
Let's see the example of declaring string by char array in C language.
- Char ch[10]={'j', 'a', 'v', 'a', 't', 'p', 'o', 'i', 'n', 't', '\0'};
As we know, array index starts from 0, so it will be represented as in the figure given below.
While declaring string, size is not mandatory. So we can write the above code as given below:
- Char ch[]={'j', 'a', 'v', 'a', 't', 'p', 'o', 'i', 'n', 't', '\0'};
We can also define the string by the string literal in C language. For example:
- Char ch[]="javatpoint";
In such case, '\0' will be appended at the end of the string by the compiler.
Difference between char array and string literal
There are two main differences between char array and literal.
- We need to add the null character '\0' at the end of the array by ourself whereas, it is appended internally by the compiler in the case of the character array.
- The string literal cannot be reassigned to another set of characters whereas, we can reassign the characters of the array.
String Example in C
Let's see a simple example where a string is declared and being printed. The '%s' is used as a format specifier for the string in c language.
- #include<stdio.h>
- #include <string.h>
- Int main(){
- Char ch[11]={'j', 'a', 'v', 'a', 't', 'p', 'o', 'i', 'n', 't', '\0'};
- Char ch2[11]="javatpoint";
- Printf("Char Array Value is: %s\n", ch);
- Printf("String Literal Value is: %s\n", ch2);
- Return 0;
- }
Output
Char Array Value is: javatpoint
String Literal Value is: javatpoint
Traversing String
Traversing the string is one of the most important aspects in any of the programming languages. We may need to manipulate a very large text which can be done by traversing the text. Traversing string is somewhat different from the traversing an integer array. We need to know the length of the array to traverse an integer array, whereas we may use the null character in the case of string to identify the end the string and terminate the loop.
Hence, there are two ways to traverse a string.
- By using the length of string
- By using the null character.
Let's discuss each one of them.
Using the length of string
Let's see an example of counting the number of vowels in a string.
- #include<stdio.h>
- Void main ()
- {
- Char s[11] = "javatpoint";
- Int i = 0;
- Int count = 0;
- While(i<11)
- {
- If(s[i]=='a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'u' || s[i] == 'o')
- {
- Count ++;
- }
- i++;
- }
- Printf("The number of vowels %d",count);
- }
Output
The number of vowels 4
Using the null character
Let's see the same example of counting the number of vowels by using the null character.
- #include<stdio.h>
- Void main ()
- {
- Char s[11] = "javatpoint";
- Int i = 0;
- Int count = 0;
- While(s[i] != NULL)
- {
- If(s[i]=='a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'u' || s[i] == 'o')
- {
- Count ++;
- }
- i++;
- }
- Printf("The number of vowels %d",count);
- }
Output
The number of vowels 4
Accepting string as the input
Till now, we have used scanf to accept the input from the user. However, it can also be used in the case of strings but with a different scenario. Consider the below code which stores the string while space is encountered.
- #include<stdio.h>
- Void main ()
- {
- Char s[20];
- Printf("Enter the string?");
- Scanf("%s",s);
- Printf("You entered %s",s);
- }
Output
Enter the string?javatpoint is the best
You entered javatpoint
It is clear from the output that, the above code will not work for space separated strings. To make this code working for the space separated strings, the minor changed required in the scanf function, i.e., instead of writing scanf("%s",s), we must write: scanf("%[^\n]s",s) which instructs the compiler to store the string s while the new line (\n) is encountered. Let's consider the following example to store the space-separated strings.
- #include<stdio.h>
- Void main ()
- {
- Char s[20];
- Printf("Enter the string?");
- Scanf("%[^\n]s",s);
- Printf("You entered %s",s);
- }
Output
Enter the string?javatpoint is the best
You entered javatpoint is the best
Here we must also notice that we do not need to use address of (&) operator in scanf to store a string since string s is an array of characters and the name of the array, i.e., s indicates the base address of the string (character array) therefore we need not use & with it.
Some important points
However, there are the following points which must be noticed while entering the strings by using scanf.
- The compiler doesn't perform bounds checking on the character array. Hence, there can be a case where the length of the string can exceed the dimension of the character array which may always overwrite some important data.
- Instead of using scanf, we may use gets() which is an inbuilt function defined in a header file string.h. The gets() is capable of receiving only one string at a time.
Pointers with strings
We have used pointers with the array, functions, and primitive data types so far. However, pointers can be used to point to the strings. There are various advantages of using pointers to point strings. Let us consider the following example to access the string via the pointer.
- #include<stdio.h>
- Void main ()
- {
- Char s[11] = "javatpoint";
- Char *p = s; // pointer p is pointing to string s.
- Printf("%s",p); // the string javatpoint is printed if we print p.
- }
Output
Javatpoint
As we know that string is an array of characters, the pointers can be used in the same way they were used with arrays. In the above example, p is declared as a pointer to the array of characters s. P affects similar to s since s is the base address of the string and treated as a pointer internally. However, we can not change the content of s or copy the content of s into another string directly. For this purpose, we need to use the pointers to store the strings. In the following example, we have shown the use of pointers to copy the content of a string into another.
- #include<stdio.h>
- Void main ()
- {
- Char *p = "hello javatpoint";
- Printf("String p: %s\n",p);
- Char *q;
- Printf("copying the content of p into q...\n");
- q = p;
- Printf("String q: %s\n",q);
- }
Output
String p: hello javatpoint
Copying the content of p into q...
String q: hello javatpoint
Once a string is defined, it cannot be reassigned to another set of characters. However, using pointers, we can assign the set of characters to the string. Consider the following example.
- #include<stdio.h>
- Void main ()
- {
- Char *p = "hello javatpoint";
- Printf("Before assigning: %s\n",p);
- p = "hello";
- Printf("After assigning: %s\n",p);
- }
Output
Before assigning: hello javatpoint
After assigning: hello
Handling strings as array of characters
Strings are actually one-dimensional array of characters terminated by a null character '\0'. Thus, a null-terminated string contains the characters that comprise the string followed by a null.
The following declaration and initialization create a string consisting of the word "Hello". To hold the null character at the end of the array, the size of the character array containing the string is one more than the number of characters in the word "Hello."
Char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
If you follow the rule of array initialization then you can write the above statement as follows −
Char greeting[] = "Hello";
Following is the memory presentation of the above defined string in C/C++ −
Actually, you do not place the null character at the end of a string constant. The C compiler automatically places the '\0' at the end of the string when it initializes the array. Let us try to print the above mentioned string −
#include <stdio.h>
Int main () {
Char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
Printf("Greeting message: %s\n", greeting );
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Greeting message: Hello
C supports a wide range of functions that manipulate null-terminated strings −
Sr.No. | Function & Purpose |
1 | Strcpy(s1, s2); Copies string s2 into string s1. |
2 | Strcat(s1, s2); Concatenates string s2 onto the end of string s1. |
3 | Strlen(s1); Returns the length of string s1. |
4 | Strcmp(s1, s2); Returns 0 if s1 and s2 are the same; less than 0 if s1<s2; greater than 0 if s1>s2. |
5 | Strchr(s1, ch); Returns a pointer to the first occurrence of character ch in string s1. |
6 | Strstr(s1, s2); Returns a pointer to the first occurrence of string s2 in string s1. |
The following example uses some of the above-mentioned functions −
#include <stdio.h>
#include <string.h>
Int main () {
Char str1[12] = "Hello";
Char str2[12] = "World";
Char str3[12];
Int len ;
/* copy str1 into str3 */
Strcpy(str3, str1);
Printf("strcpy( str3, str1) : %s\n", str3 );
/* concatenates str1 and str2 */
Strcat( str1, str2);
Printf("strcat( str1, str2): %s\n", str1 );
/* total lenghth of str1 after concatenation */
Len = strlen(str1);
Printf("strlen(str1) : %d\n", len );
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Strcpy( str3, str1) : Hello
Strcat( str1, str2): HelloWorld
Strlen(str1) : 10
Strings are actually one-dimensional array of characters terminated by a null character '\0'. Thus a null-terminated string contains the characters that comprise the string followed by a null.
The following declaration and initialization create a string consisting of the word "Hello". To hold the null character at the end of the array, the size of the character array containing the string is one more than the number of characters in the word "Hello."
Char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
If you follow the rule of array initialization then you can write the above statement as follows −
Char greeting[] = "Hello";
Following is the memory presentation of the above defined string in C/C++ −
Actually, you do not place the null character at the end of a string constant. The C compiler automatically places the '\0' at the end of the string when it initializes the array. Let us try to print the above mentioned string −
#include <stdio.h>
Int main () {
Char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
Printf("Greeting message: %s\n", greeting );
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Greeting message: Hello
C supports a wide range of functions that manipulate null-terminated strings −
Sr.No. | Function & Purpose |
1 | Strcpy(s1, s2); Copies string s2 into string s1. |
2 | Strcat(s1, s2); Concatenates string s2 onto the end of string s1. |
3 | Strlen(s1); Returns the length of string s1. |
4 | Strcmp(s1, s2); Returns 0 if s1 and s2 are the same; less than 0 if s1<s2; greater than 0 if s1>s2. |
5 | Strchr(s1, ch); Returns a pointer to the first occurrence of character ch in string s1. |
6 | Strstr(s1, s2); Returns a pointer to the first occurrence of string s2 in string s1. |
The following example uses some of the above-mentioned functions −
#include <stdio.h>
#include <string.h>
Int main () {
Char str1[12] = "Hello";
Char str2[12] = "World";
Char str3[12];
Int len ;
/* copy str1 into str3 */
Strcpy(str3, str1);
Printf("strcpy( str3, str1) : %s\n", str3 );
/* concatenates str1 and str2 */
Strcat( str1, str2);
Printf("strcat( str1, str2): %s\n", str1 );
/* total lenghth of str1 after concatenation */
Len = strlen(str1);
Printf("strlen(str1) : %d\n", len );
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Strcpy( str3, str1) : Hello
Strcat( str1, str2): HelloWorld
Strlen(str1) : 10
The string.h header defines one variable type, one macro, and various functions for manipulating arrays of characters.
Library Variables
Following is the variable type defined in the header string.h −
Sr.No. | Variable & Description |
1 | Size_t This is the unsigned integral type and is the result of the sizeof keyword. |
Library Macros
Following is the macro defined in the header string.h −
Sr.No. | Macro & Description |
1 | NULL This macro is the value of a null pointer constant. |
Library Functions
Following are the functions defined in the header string.h −
Sr.No. | Function & Description |
1 | Void *memchr(const void *str, int c, size_t n) Searches for the first occurrence of the character c (an unsigned char) in the first n bytes of the string pointed to, by the argument str. |
2 | Int memcmp(const void *str1, const void *str2, size_t n) Compares the first n bytes of str1 and str2. |
3 | Void *memcpy(void *dest, const void *src, size_t n) Copies n characters from src to dest. |
4 | Void *memmove(void *dest, const void *src, size_t n) Another function to copy n characters from str2 to str1. |
5 | Void *memset(void *str, int c, size_t n) Copies the character c (an unsigned char) to the first n characters of the string pointed to, by the argument str. |
6 | Char *strcat(char *dest, const char *src) Appends the string pointed to, by src to the end of the string pointed to by dest. |
7 | Char *strncat(char *dest, const char *src, size_t n) Appends the string pointed to, by src to the end of the string pointed to, by dest up to n characters long. |
8 | Char *strchr(const char *str, int c) Searches for the first occurrence of the character c (an unsigned char) in the string pointed to, by the argument str. |
9 | Int strcmp(const char *str1, const char *str2) Compares the string pointed to, by str1 to the string pointed to by str2. |
10 | Int strncmp(const char *str1, const char *str2, size_t n) Compares at most the first n bytes of str1 and str2. |
11 | Int strcoll(const char *str1, const char *str2) Compares string str1 to str2. The result is dependent on the LC_COLLATE setting of the location. |
12 | Char *strcpy(char *dest, const char *src) Copies the string pointed to, by src to dest. |
13 | Char *strncpy(char *dest, const char *src, size_t n) Copies up to n characters from the string pointed to, by src to dest. |
14 | Size_t strcspn(const char *str1, const char *str2) Calculates the length of the initial segment of str1 which consists entirely of characters not in str2. |
15 | Char *strerror(int errnum) Searches an internal array for the error number errnum and returns a pointer to an error message string. |
16 | Size_t strlen(const char *str) Computes the length of the string str up to but not including the terminating null character. |
17 | Char *strpbrk(const char *str1, const char *str2) Finds the first character in the string str1 that matches any character specified in str2. |
18 | Char *strrchr(const char *str, int c) Searches for the last occurrence of the character c (an unsigned char) in the string pointed to by the argument str. |
19 | Size_t strspn(const char *str1, const char *str2) Calculates the length of the initial segment of str1 which consists entirely of characters in str2. |
20 | Char *strstr(const char *haystack, const char *needle) Finds the first occurrence of the entire string needle (not including the terminating null character) which appears in the string haystack. |
21 | Char *strtok(char *str, const char *delim) Breaks string str into a series of tokens separated by delim. |
22 | Size_t strxfrm(char *dest, const char *src, size_t n) Transforms the first n characters of the string src into current locale and places them in the string dest. |
Array Input/Output
// Program to take 5 values from the user and store them in an array
// Print the elements stored in the array
Int main() {
Int values[5];
Printf("Enter 5 integers: ");
// taking input and storing it in an array
For(int i = 0; i < 5; ++i) {
Scanf("%d", &values[i]);
}
Printf("Displaying integers: ");
// printing elements of an array
For(int i = 0; i < 5; ++i) {
Printf("%d\n", values[i]);
}
Return 0;
}
Output
Enter 5 integers: 1
-3
34
0
3
Displaying integers: 1
-3
34
0
3
Calculate Average
// Program to find the average of n numbers using arrays
Int main()
{
Int marks[10], i, n, sum = 0, average;
Printf("Enter number of elements: ");
Scanf("%d", &n);
For(i=0; i<n; ++i)
{
Printf("Enter number%d: ",i+1);
Scanf("%d", &marks[i]);
// adding integers entered by the user to the sum variable
Sum += marks[i];
}
Average = sum/n;
Printf("Average = %d", average);
Return 0;
}
Output
Enter n: 5
Enter number1: 45
Enter number2: 35
Enter number3: 38
Enter number4: 31
Enter number5: 49
Average = 39
Gets() and puts()
Functions gets() and puts() are two string functions to take string input from the user and display it respectively
Int main()
{
Char name[30];
Printf("Enter name: ");
Gets(name); //Function to read string from user.
Printf("Name: ");
Puts(name); //Function to display string.
Return 0;
}
Note: Though, gets() and puts() function handle strings, both these functions are defined in "stdio.h" header file.
The pointer in C language is a variable which stores the address of another variable. This variable can be of type int, char, array, function, or any other pointer. The size of the pointer depends on the architecture. However, in 32-bit architecture the size of a pointer is 2 byte.
Consider the following example to define a pointer which stores the address of an integer.
- Int n = 10;
- Int* p = &n; // Variable p of type pointer is pointing to the address of the variable n of type integer.
Declaring a pointer
The pointer in c language can be declared using * (asterisk symbol). It is also known as indirection pointer used to dereference a pointer.
- Int *a;//pointer to int
- Char *c;//pointer to char
Pointer Example
An example of using pointers to print the address and value is given below.
As you can see in the above figure, pointer variable stores the address of number variable, i.e., fff4. The value of number variable is 50. But the address of pointer variable p is aaa3.
By the help of * (indirection operator), we can print the value of pointer variable p.
Let's see the pointer example as explained for the above figure.
- #include<stdio.h>
- Int main(){
- Int number=50;
- Int *p;
- p=&number;//stores the address of number variable
- Printf("Address of p variable is %x \n",p); // p contains the address of the number therefore printing p gives the address of number.
- Printf("Value of p variable is %d \n",*p); // As we know that * is used to dereference a pointer therefore if we print *p, we will get the value stored at the address contained by p.
- Return 0;
- }
Output
Address of number variable is fff4
Address of p variable is fff4
Value of p variable is 50
Pointer to array
- Int arr[10];
- Int *p[10]=&arr; // Variable p of type pointer is pointing to the address of an integer array arr.
Pointer to a function
- Void show (int);
- Void(*p)(int) = &display; // Pointer p is pointing to the address of a function
Pointer to structure
- Struct st {
- Int i;
- Float f;
- }ref;
- Struct st *p = &ref;
Advantage of pointer
1) Pointer reduces the code and improves the performance, it is used to retrieving strings, trees, etc. and used with arrays, structures, and functions.
2) We can return multiple values from a function using the pointer.
3) It makes you able to access any memory location in the computer's memory.
Usage of pointer
There are many applications of pointers in c language.
1) Dynamic memory allocation
In c language, we can dynamically allocate memory using malloc() and calloc() functions where the pointer is used.
2) Arrays, Functions, and Structures
Pointers in c language are widely used in arrays, functions, and structures. It reduces the code and improves the performance.
Address Of (&) Operator
The address of operator '&' returns the address of a variable. But, we need to use %u to display the address of a variable.
- #include<stdio.h>
- Int main(){
- Int number=50;
- Printf("value of number is %d, address of number is %u",number,&number);
- Return 0;
- }
Output
Value of number is 50, address of number is fff4
NULL Pointer
A pointer that is not assigned any value but NULL is known as the NULL pointer. If you don't have any address to be specified in the pointer at the time of declaration, you can assign NULL value. It will provide a better approach.
Int *p=NULL;
In the most libraries, the value of the pointer is 0 (zero).
Pointer Program to swap two numbers without using the 3rd variable.
- #include<stdio.h>
- Int main(){
- Int a=10,b=20,*p1=&a,*p2=&b;
- Printf("Before swap: *p1=%d *p2=%d",*p1,*p2);
- *p1=*p1+*p2;
- *p2=*p1-*p2;
- *p1=*p1-*p2;
- Printf("\nAfter swap: *p1=%d *p2=%d",*p1,*p2);
- Return 0;
- }
Output
Before swap: *p1=10 *p2=20
After swap: *p1=20 *p2=10
Reading complex pointers
There are several things which must be taken into the consideration while reading the complex pointers in C. Lets see the precedence and associativity of the operators which are used regarding pointers.
Operator | Precedence | Associativity |
(), [] | 1 | Left to right |
*, identifier | 2 | Right to left |
Data type | 3 | - |
Here, we must notice that,
- (): This operator is a bracket operator used to declare and define the function.
- []: This operator is an array subscript operator
- * : This operator is a pointer operator.
- Identifier: It is the name of the pointer. The priority will always be assigned to this.
- Data type: Data type is the type of the variable to which the pointer is intended to point. It also includes the modifier like signed int, long, etc).
How to read the pointer: int (*p)[10].
To read the pointer, we must see that () and [] have the equal precedence. Therefore, their associativity must be considered here. The associativity is left to right, so the priority goes to ().
Inside the bracket (), pointer operator * and pointer name (identifier) p have the same precedence. Therefore, their associativity must be considered here which is right to left, so the priority goes to p, and the second priority goes to *.
Assign the 3rd priority to [] since the data type has the last precedence. Therefore, the pointer will look like following.
- Char -> 4
- * -> 2
- p -> 1
- [10] -> 3
The pointer will be read as p is a pointer to an array of integers of size 10.
Example
How to read the following pointer?
- Int (*p)(int (*)[2], int (*)void))
Explanation
This pointer will be read as p is a pointer to such function which accepts the first parameter as the pointer to a one-dimensional array of integers of size two and the second parameter as the pointer to a function which parameter is void and return type is the integer.
Pointers are used to point to address the location of a variable. A pointer is declared by preceding the name of the pointer by an asterisk(*).
Syntax:
Datatype *pointer_name;
When we need to initialize a pointer with variable’s location, we use ampersand sign(&) before the variable name.
Example:
// Declaration of integer variable Int var=10;
// Initialization of pointer variable Int *pointer=&var; |
The ampersand (&) is used to get the address of a variable. We can directly find the location of any identifier by just preceding it with an ampersand(&) sign.
Example:
// This code prints the address of x #include <stdio.h>
Int main() { Int x = 10;
// Prints address of x Printf( "Address of variable x = %p", &x);
Return 0; } |
Output:
Address of variable x = 0x7fff3b690fd4
C supports a rich set of built-in operations like arithmetic, relational, assignment, conditional, etc. which can be performed on identifiers. Just like any other variable, these operations can be also performed on pointer variables.
Arithmetic Operators
We can perform arithmetic operations to pointer variables using arithmetic operators. We can add an integer or subtract an integer using a pointer pointing to that integer variable. The given table shows the arithmetic operators that can be performed on pointer variables:
Examples:
*ptr1 + *ptr2
*ptr1 * *ptr2
*ptr1 + *ptr2 - *ptr3
We can also directly perform arithmetic expression using integers. Lets look at the example given below where p1 and p2 are pointers.
p1+10, p2-5, p1-p2+10, p1/2
Below diagram represents how exactly the expression/operators work with pointers.
As seen in the diagram, pointer ‘pa’ and ‘pb’ points to integer variable ‘a’ and ‘b’ respectively. The addition is performed directly between integer variables and pointer variable and the results are stored in integer variable ‘c’ and ‘x’ respectively. Both the results are the same.
Let us understand pointer arithmetic expression better with given code:
// Program showing pointer expressions // during Arithmetic Operations #include <stdio.h>
Int main() { // Integer variables Int a = 20, b = 10;
// Variables for storing arithmetic // operations solution Int add, sub, div, mul, mod;
// Pointer variables for variables // a and b Int *ptr_a, *ptr_b;
// Initialization of pointers Ptr_a = &a; Ptr_b = &b;
// Performing arithmetic Operations // on pointers Add = *ptr_a + *ptr_b; Sub = *ptr_a - *ptr_b; Mul = *ptr_a * *ptr_b; Div = *ptr_a / *ptr_b; Mod = *ptr_a % *ptr_b;
// Printing values Printf("Addition = %d\n", add); Printf("Subtraction = %d\n", sub); Printf("Multiplication = %d\n", mul); Printf("Division = %d\n", div); Printf("Modulo = %d\n", mod); Return 0; } |
Output:
Addition = 30
Subtraction = 10
Multiplication = 200
Division = 2
Modulo = 0
Note: While performing division, make sure you put a blank space between ‘/’ and ‘*’ of the pointer as together it would make a multi-line comment(‘/*’).
Example:
Incorrect: *ptr_a/*ptr_b;
Correct: *ptr_a / *ptr_b;
Correct: (*ptr_a)/(*ptr_b);
Relational Operators
Relational operations are often used to compare the values of the variable based on which we can take decisions. The given table shows the relational operators that can be performed on pointer variables.
Example:
*ptr1 > *ptr2
*ptr1 < *ptr2
The value of the relational expression is either 0 or 1 that is false or true. The expression will return value 1 if the expression is true and it’ll return value 0 if false.
Let us understand relational expression on pointer better with the code given below:
// Program showing pointer expressions // during Relational Operations #include <stdio.h> Int main() { // Initializing integer variables Int a = 20, b = 10;
// Declaring pointer variables Int* ptr_a; Int* ptr_b;
// Initializing pointer variables Ptr_a = &a; Ptr_b = &b;
// Performing relational operations // less than operator If (*ptr_a < *ptr_b) { Printf( "%d is less than %d.", *ptr_a, *ptr_b); }
// Greater than operator If (*ptr_a > *ptr_b) { Printf( "%d is greater than %d.", *ptr_a, *ptr_b); }
// Equal to If (*ptr_a == *ptr_b) { Printf( "%d is equal to %d.", *ptr_a, *ptr_b); }
Return 0; } |
Output:
20 is greater than 10.
Output:
20 is greater than 10.
Assignment Operators
Assignment operators are used to assign values to the identifiers. There are multiple shorthand operations available. A table is given below showing the actual assignment statement with its shorthand statement.
Examples:
*a=10
*b+=20
*z=3.5
*s=4.56743
Let us understand assignment operator in better way with the help of code given below:
// Program showing pointer expressions // during Assignment Operations #include <stdio.h> Int main() { // Initializing integer variable Int a = 30;
// Declaring pointer variable Int* ptr_a;
// Initializing pointer using // assignment operator Ptr_a = &a;
// Changing the variable's value using // assignment operator *ptr_a = 50;
// Printing value of 'a' after // updating its value Printf("Value of variable a = %d", *ptr_a);
Return 0; } |
Output:
Value of variable a = 50
Conditional Operators
There is only one mostly used conditional operator in C known as Ternary operator. Ternary operator first checks the expression and depending on its return value returns true or false, which triggers/selects another expression.
Syntax:
Expression1 ? expression2 : expression3;
Example:
c = (*ptr1 > *ptr2) ? *ptr1 : *ptr2;
- As shown in example, assuming *ptr1=20 and *ptr2=10 then the condition here becomes true for the expression, so it’ll return value of true expression i.e. *ptr1, so variable ‘c’ will now contain value of 20.
- Considering same example, assume *ptr1=30 and *ptr2=50 then the condition is false for the expression, so it’ll return value of false expression i.e. *ptr2, so variable ‘c’ will now contain value 50.
Let us understand the concept through the given code:
// Program showing pointer expressions // during Conditional Operations #include <stdio.h> Int main() { // Initializing integer variables Int a = 15, b = 20, result = 0;
// Declaring pointer variables Int *ptr_a, *ptr_b;
// Initializing pointer variables Ptr_a = &a; Ptr_b = &b;
// Performing ternary operator Result = ((*ptr_a > *ptr_b) ? *ptr_a : *ptr_b);
// Printing result of ternary operator Printf("%d is the greatest.", result); Return 0; } |
Output:
20 is the greatest.
Unary Operators
There are mainly two operators which are given as follows.
Examples:
(*ptr1)++
(*ptr1)--
Let us understand the use of the unary operator through the given code:
// Program showing pointer expressions // during Unary Operations #include <stdio.h> Int main() { // Initializing integer variable Int a = 34;
// Declaring pointer variable Int* ptr_a;
// Initializing pointer variable Ptr_a = &a;
// Value of a before increment Printf("Increment:\n"); Printf( "Before increment a = %d\n", *ptr_a);
// Unary increment operation (*ptr_a)++;
// Value of a after increment Printf( "After increment a = %d", *ptr_a);
// Value before decrement Printf("\n\nDecrement:\n"); Printf( "Before decrement a = %d\n", *ptr_a);
// unary decrement operation (*ptr_a)--;
// Value after decrement Printf("After decrement a=%d", *ptr_a);
Return 0; } |
Output:
Increment:
Before increment a = 34
After increment a = 35
Decrement:
Before decrement a = 35
After decrement a=34
Bitwise Operators
Binary operators are also known as bitwise operators. It is used to manipulate data at bit level. Bitwise operators can’t be used for float and double datatype. A table is shown below with all bitwise operators:
Examples:
*ptr1 & *ptr2
*ptr1 | *ptr2
*ptr1 ^ *ptr2
Let us understand the concept through the given code:
// Program showing pointer expressions // during Bitwise Operations #include <stdio.h> Int main() { // Declaring integer variable for // storing result Int and, or, ex_or;
// Initializing integer variable Int a = 1, b = 2;
// Performing bitwise operations // AND operation And = a & b;
// OR operation Or = a | b;
// EX-OR operation Ex_or = a ^ b;
// Printing result of operations Printf("\na AND b = %d", and); Printf("\na OR b = %d", or); Printf("\na Exclusive-OR b = %d", ex_or); Return 0; } |
Output:
a AND b = 0
a OR b = 3
a Exclusive-OR b = 3
Till now, we have seen that in C programming, we can pass the variables as an argument to a function. We cannot pass the function as an argument to another function. But we can pass the reference of a function as a parameter by using a function pointer. This process is known as call by reference as the function parameter is passed as a pointer that holds the address of arguments. If any change made by the function using pointers, then it will also reflect the changes at the address of the passed variable.
Therefore, C programming allows you to create a pointer pointing to the function, which can be further passed as an argument to the function. We can create a function pointer as follows:
- (type) (*pointer_name)(parameter);
In the above syntax, the type is the variable type which is returned by the function, *pointer_name is the function pointer, and the parameter is the list of the argument passed to the function.
Let's consider an example:
- Float (*add)(); // this is a legal declaration for the function pointer
- Float *add(); // this is an illegal declaration for the function pointer
A function pointer can also point to another function, or we can say that it holds the address of another function.
- Float add (int a, int b); // function declaration
- Float (*a)(int, int); // declaration of a pointer to a function
- a=add; // assigning address of add() to 'a' pointer
In the above case, we have declared a function named as 'add'. We have also declared the function pointer (*a) which returns the floating-type value, and contains two parameters of integer type. Now, we can assign the address of add() function to the 'a' pointer as both are having the same return type(float), and the same type of arguments.
Now, 'a' is a pointer pointing to the add() function. We can call the add() function by using the pointer, i.e., 'a'. Let's see how we can do that:
- a(2, 3);
The above statement calls the add() function by using pointer 'a', and two parameters are passed in 'a', i.e., 2 and 3.
Let's see a simple example of how we can pass the function pointer as a parameter.
- Void display(void (*p)())
- {
- For(int i=1;i<=5;i++)
- {
- p(i);
- }
- }
- Void print_numbers(int num)
- {
- Cout<<num;
- }
- Int main()
- {
- Void (*p)(int); // void function pointer declaration
- Printf("The values are :");
- Display(print_numbers);
- Return 0;
- }
In the above code,
- We have defined two functions named 'display()' and print_numbers().
- Inside the main() method, we have declared a function pointer named as (*p), and we call the display() function in which we pass the print_numbers() function.
- When the control goes to the display() function, then pointer *p contains the address of print_numbers() function. It means that we can call the print_numbers() function using function pointer *p.
- In the definition of display() function, we have defined a 'for' loop, and inside the for loop, we call the print_numbers() function using statement p(i). Here, p(i) means that print_numbers() function will be called on each iteration of i, and the value of 'i' gets printed.
Output
Now, we will pass the function pointer as a argument in Quicksort function "qsort". It uses an algorithm that sorts an array.
- #include <stdio.h>
- #include <stdlib.h>
- #include<string.h>
- Int compare(const int *p, const int *q);
- Int (*f)(const void *a, const void *b);
- Int main()
- {
- Int a[]={4,7,6,1,3,2};
- Int num=sizeof(a)/sizeof(int);
- f=&compare;
- Qsort(a, num, sizeof(int), (*f));
- For(int i=0;i<num;i++)
- {
- Printf("%d ,",a[i]);
- }
- }
- Int compare(const int *p, const int *q)
- {
- If (*p == *q)
- Return 0;
- Else if (*p < *q)
- Return -1;
- Else
- Return 1;
- }
In the above code,
- We have defined an array of integer type. After creating an array, we have calculated the size of an array by using the sizeof() operator, and stores the size in the num
- We define a compare() function, which compares all the elements in an array and arranges them in ascending order.
- We also have declared the function pointer, i.e., (*f), and stores the address of compare() function in (*f) by using the statement f=&compare.
- We call qsort() function in which we pass the array, size of the array, size of the element, and the comparison function. The comparison function, i.e., compare() will compare the array elements until the elements in an array get sorted in ascending order.
Output
Before we understand the concept of arrays of pointers, let us consider the following example, which uses an array of 3 integers −
#include <stdio.h>
Const int MAX = 3;
Int main () {
Int var[] = {10, 100, 200};
Int i;
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>
Const int MAX = 3;
Int main () {
Int var[] = {10, 100, 200};
Int i, *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>
Const int MAX = 4;
Int main () {
Char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
Int i = 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
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;
Int i;
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.
We can perform arithmetic operations on the pointers like addition, subtraction, etc. However, as we know that pointer contains the address, the result of an arithmetic operation performed on the pointer will also be a pointer if the other operand is of type integer. In pointer-from-pointer subtraction, the result will be an integer value. Following arithmetic operations are possible on the pointer in C language:
- Increment
- Decrement
- Addition
- Subtraction
- Comparison
Incrementing Pointer in C
If we increment a pointer by 1, the pointer will start pointing to the immediate next location. This is somewhat different from the general arithmetic since the value of the pointer will get increased by the size of the data type to which the pointer is pointing.
We can traverse an array by using the increment operation on a pointer which will keep pointing to every element of the array, perform some operation on that, and update itself in a loop.
The Rule to increment the pointer is given below:
- New_address= current_address + i * size_of(data type)
Where i is the number by which the pointer get increased.
32-bit
For 32-bit int variable, it will be incremented by 2 bytes.
64-bit
For 64-bit int variable, it will be incremented by 4 bytes.
Let's see the example of incrementing pointer variable on 64-bit architecture.
- #include<stdio.h>
- Int main(){
- Int number=50;
- Int *p;//pointer to int
- p=&number;//stores the address of number variable
- Printf("Address of p variable is %u \n",p);
- p=p+1;
- Printf("After increment: Address of p variable is %u \n",p); // in our case, p will get incremented by 4 bytes.
- Return 0;
- }
Output
Address of p variable is 3214864300
After increment: Address of p variable is 3214864304
Traversing an array by using pointer
- #include<stdio.h>
- Void main ()
- {
- Int arr[5] = {1, 2, 3, 4, 5};
- Int *p = arr;
- Int i;
- Printf("printing array elements...\n");
- For(i = 0; i< 5; i++)
- {
- Printf("%d ",*(p+i));
- }
- }
Output
Printing array elements...
1 2 3 4 5
Decrementing Pointer in C
Like increment, we can decrement a pointer variable. If we decrement a pointer, it will start pointing to the previous location. The formula of decrementing the pointer is given below:
- New_address= current_address - i * size_of(data type)
32-bit
For 32-bit int variable, it will be decremented by 2 bytes.
64-bit
For 64-bit int variable, it will be decremented by 4 bytes.
Let's see the example of decrementing pointer variable on 64-bit OS.
- #include <stdio.h>
- Void main(){
- Int number=50;
- Int *p;//pointer to int
- p=&number;//stores the address of number variable
- Printf("Address of p variable is %u \n",p);
- p=p-1;
- Printf("After decrement: Address of p variable is %u \n",p); // P will now point to the immidiate previous location.
- }
Output
Address of p variable is 3214864300
After decrement: Address of p variable is 3214864296
C Pointer Addition
We can add a value to the pointer variable. The formula of adding value to pointer is given below:
- New_address= current_address + (number * size_of(data type))
32-bit
For 32-bit int variable, it will add 2 * number.
64-bit
For 64-bit int variable, it will add 4 * number.
Let's see the example of adding value to pointer variable on 64-bit architecture.
- #include<stdio.h>
- Int main(){
- Int number=50;
- Int *p;//pointer to int
- p=&number;//stores the address of number variable
- Printf("Address of p variable is %u \n",p);
- p=p+3; //adding 3 to pointer variable
- Printf("After adding 3: Address of p variable is %u \n",p);
- Return 0;
- }
Output
Address of p variable is 3214864300
After adding 3: Address of p variable is 3214864312
As you can see, the address of p is 3214864300. But after adding 3 with p variable, it is 3214864312, i.e., 4*3=12 increment. Since we are using 64-bit architecture, it increments 12. But if we were using 32-bit architecture, it was incrementing to 6 only, i.e., 2*3=6. As integer value occupies 2-byte memory in 32-bit OS.
C Pointer Subtraction
Like pointer addition, we can subtract a value from the pointer variable. Subtracting any number from a pointer will give an address. The formula of subtracting value from the pointer variable is given below:
- New_address= current_address - (number * size_of(data type))
32-bit
For 32-bit int variable, it will subtract 2 * number.
64-bit
For 64-bit int variable, it will subtract 4 * number.
Let's see the example of subtracting value from the pointer variable on 64-bit architecture.
- #include<stdio.h>
- Int main(){
- Int number=50;
- Int *p;//pointer to int
- p=&number;//stores the address of number variable
- Printf("Address of p variable is %u \n",p);
- p=p-3; //subtracting 3 from pointer variable
- Printf("After subtracting 3: Address of p variable is %u \n",p);
- Return 0;
- }
Output
Address of p variable is 3214864300
After subtracting 3: Address of p variable is 3214864288
You can see after subtracting 3 from the pointer variable, it is 12 (4*3) less than the previous address value.
However, instead of subtracting a number, we can also subtract an address from another address (pointer). This will result in a number. It will not be a simple arithmetic operation, but it will follow the following rule.
If two pointers are of the same type,
- Address2 - Address1 = (Subtraction of two addresses)/size of data type which pointer points
Consider the following example to subtract one pointer from an another.
- #include<stdio.h>
- Void main ()
- {
- Int i = 100;
- Int *p = &i;
- Int *temp;
- Temp = p;
- p = p + 3;
- Printf("Pointer Subtraction: %d - %d = %d",p, temp, p-temp);
- }
Output
Pointer Subtraction: 1030585080 - 1030585068 = 3
Illegal arithmetic with pointers
There are various operations which can not be performed on pointers. Since, pointer stores address hence we must ignore the operations which may lead to an illegal address, for example, addition, and multiplication. A list of such operations is given below.
- Address + Address = illegal
- Address * Address = illegal
- Address % Address = illegal
- Address / Address = illegal
- Address & Address = illegal
- Address ^ Address = illegal
- Address | Address = illegal
- ~Address = illegal
Pointer to function in C
As we discussed in the previous chapter, a pointer can point to a function in C. However, the declaration of the pointer variable must be the same as the function. Consider the following example to make a pointer pointing to the function.
- #include<stdio.h>
- Int addition ();
- Int main ()
- {
- Int result;
- Int (*ptr)();
- Ptr = &addition;
- Result = (*ptr)();
- Printf("The sum is %d",result);
- }
- Int addition()
- {
- Int a, b;
- Printf("Enter two numbers?");
- Scanf("%d %d",&a,&b);
- Return a+b;
- }
Output
Enter two numbers?10 15
The sum is 25
Pointer to Array of functions in C
To understand the concept of an array of functions, we must understand the array of function. Basically, an array of the function is an array which contains the addresses of functions. In other words, the pointer to an array of functions is a pointer pointing to an array which contains the pointers to the functions. Consider the following example.
- #include<stdio.h>
- Int show();
- Int showadd(int);
- Int (*arr[3])();
- Int (*(*ptr)[3])();
- Int main ()
- {
- Int result1;
- Arr[0] = show;
- Arr[1] = showadd;
- Ptr = &arr;
- Result1 = (**ptr)();
- Printf("printing the value returned by show : %d",result1);
- (*(*ptr+1))(result1);
- }
- Int show()
- {
- Int a = 65;
- Return a++;
- }
- Int showadd(int b)
- {
- Printf("\nAdding 90 to the value returned by show: %d",b+90);
- }
Output
Printing the value returned by show : 65
Adding 90 to the value returned by show: 155
Text Books:
1. Programming with C-Gottfried-Schaums Outline Series-TMH
2. C Programming – Anitha Goel/Ajay Mittal/E.Sreenivasa Reddy-Pearson India
References:
1. Problem Solving with C- Somasekharan-PHI.
2. C Programming- Behrouz A forouzan – CENGAGE Learning
3. Test your c skills-Yaswanth kanithker
4. Let us C- Yaswanth kanithker