What are Arrays?
An array is a collection of similar data types in which each element is located in unique memory locations. These similar elements could be all ints, or all floats, or all chars, etc. usually, the array of characters is called a ‘string’.
We can use arrays to represent not only a simple list of values but also tables of data in two, three or more dimension. These are can be,
- One-dimensional arrays.
- Two-dimensional arrays.
- Multidimensional arrays.
Characteristics of Array
let us take the example int a[5]={1,2,3,4,5};
- The declaration int a[5] is nothing but a creation of 5 variables of integer types in the memory. Instead of declaring five variables for five values, the programmer can define them in an array.
- All the elements of an array share the same name, and they are distinguished from one another with the help of an element number.
- The element number in an array plays a major role in calling each element.
- Any particular element of an array can be modified separately without disturbing other elements. If a programmer needs to replace 8 with 10, he/she need not require to change all other numbers except 8. To carry out this task the statement a[4]=10 can be used. Here the other three elements are not disturbed.
- Any element of an array a[] can be assigned/equated to another ordinary variable or array variable of its type.
[quote]
Ex: b=a[2];
a[2] = a[3];
[/quote]
- In the statement b=a[2] or vice versa, the value of a[2] is assigned to ‘b’, where ‘b’ is an integer. In the statement a[2]=a[3] or vice versa, the value of a[2] is assigned to a[3], where both the elements are of the same array. The array elements are stored in continues memory locations. The amount of storage required for holding elements of the array depends on its type and size. The total size in bytes for a single dimensional array is computed as:
total bytes=sizeof (data types) * size of array.
One Dimensional array
Array Declaration
a simple example of an array declaration.
int marks[30];
Here, int specifies the type of the variable, just as it does with ordinary variables and the word marks specifies the name of the variable. The number 30 tells how many elements of the type int will be in our array. This number is often called the ‘dimension’ or ‘subscript’ of the array. The bracket ( [] ) tells the compiler that we are dealing with an array.
Subscript
subscript of an array is an integer expression, integer constant or integer variables like ‘i’, ‘n’ etc., that refers to different elements in the array. In the above example, array subscripts start at zero. Therefore the elements are from marks[0] to marks[29]. Subscripts have a range, starting from ‘0’ to the “size of the array – 1”. Subscripts can also be reflected in loops that print the array elements.
Array Initialization
Following are a few examples that demonstrate this.
- int number[6]={ 2,4,6,8,10,12};
- int n[]={ 1,11,21,31,41,51};
- float pass[]={ 12.3, 22.3, 33.3, 44.3};
- int bit[5]={ 5,15,25,35,45,55,65};
Note:
[quote]
- Till the array elements are not given any specific values, they are supposed to contain garbage values.
- If the array is initialized where it is declared, mentioning the dimension of the array is optional as in the 2nd and 3rd example above.
- If the array is initialized more than the size of the array that is an error.
[/quote]
Accessing array elements
The elements of an array can be accessed using an index known as the array index. The smallest possible value of the array index is known as a lower bound. The largest value is known as the upper bound. In “C” lower bound is always 0 and the upper bound is N-1, where N is the size of an array.
Entering Data at Run Time
Here is the example to understand easily here is the section of code that places data into an array at run time.
for(i = 0 ; i <=29 ; i++ )
{
printf ("\nEnter marks");
scanf ("%d", &marks[i] );
}
The for loop causes the process of asking for and receiving a student’s marks from the user to be repeated 30 times. The first time through the loop, i have a value 0, so the scanf() function will cause the value typed to be stored in the array element marks[0], the first element of the array. This process will be repeated until becoming 29. This is the last time through the loop, which is a good thing because there is no array element like marks[30].
In scanf() function, we have used the “address of” operator (&) on the element marks[i] of the array, just as we have used it earlier on another variable. In so doing, we are passing the address of this particular array element to the scanf() function, rather than its value; which is what scanf() requires.
Reading Data from an Array
The balance of the program reads the data back out of the array and used it to calculate the average. The for loop in much the same, but now the body of the loop causes each student’s marks to be added to a running total stored in a variable called sum. When all the marks have been added up, the result is divided by 30, the number of students, to get average.
for ( i= 0 ; i <= 29; i++ )
sum=sum+marks[i];
avg=sum/30;
printf( "\nAverage marks = %d" ,avg);
Memory allocations for an array
Consider the following array declaration
int arr[5];
What happens in memory when we make this declaration? 10 bytes get immediately reserved in memory, 2 bytes each for the 5 integers. And since the array is not being initialized, all five values present in it would be garbage values. This so happens because the storage class of this array is assumed to be auto. If the storage class is declared to be static, then all the array elements would have a default initial value as zero. Whatever be the initial values, all the array elements would always be present in contiguous memory locations. This arrangement of an array element in memory is shown in bellow.
Boundary Checking In Array
In C and C++ there is no check to see if the subscript used for an array exceeds the size of the array. Data entered with a subscript exceed the size of the array. Data entered with a subscript exceeds the array size will simply be placed in memory outside the array; probably on top of other data, or on the program itself. This will lead to unpredictable results, to say the least, and there will be no error message to warn you that you are going beyond the array size. In some cases, the computer may just hang. Thus, the following program may turn out to be suicidal.
#include <stdio.h>
int main ()
{
int num[10],i;
for ( i=0 ; i<= 20 ; i++ )
num[i]=i;
return 0;
}
Thus, to see to it that we do not reach beyond the array size is entirely the programmer’s botheration and not the compiler’s.
Two-Dimensional Array
The two-dimensional array is also called a matrix. Two-dimension arrays are declared as follows:
[quote]Type array_name [row_size][column_size];[/quote]
Ex: int arr[4][3];
Initialization
When we are going to initializing the values we need to maintain row and columns by using curly braces and when the row is compiled close the braces if you are using more rows and use separator (,) between.
int arr[4][3] = {
{1,11,21},
{2,12,22},
{3,13,33},
{4,14,44}
};
Once an array is declared or initialized, let us see how individual elements in the array can be referred. This is done by using two subscripts, the number in fist subscript referred the row address and the second one for column following the array name. This number specifies the element’s position in the array. All the array elements are numbered, starting with 0 and 0.Thus, arr[0][0] is the first element, arr[1][0] is fourth element and arr[3][2] is the last element.
It is important to remember that, while initializing a 2-D array, it is necessary to mention the second dimension (column), whereas the first dimension is optional (row).Thus the declarations,
- int arr[2][2]={2,12,22,32};
- int arr[ ][2] ={3,13,23,33}; are perfectly acceptable. Whereas
- int arr[2][]={4,14,24,34};
- int arr[ ][ ]={5,15,25,35}; are not acceptable.
Entering Data at Run Time
Here is the section of code that places data into an array at run time.
for( int i = 0 ; i <=3 ; i++ )
{
for( int j = 0 ; j <=2 ; j++ )
{
scanf ( “%d”, &arr[i][j] );
}
}
The outer for loop to be repeated 4 times that is equal to the number of rows and inner for loop repeated 3 times that is equal to the number of column in each row. The first time through the loop, i and j have a value 0, so the scanf() function will cause the value typed to be stored in the array element arr[0][0], the first element of the array. This process will be repeated until j value become 2. Than outer for loop variable will be increment with one again inner loop repeated 3 times. This process repeated until the outer loop becomes false.
Memory allocations for 2-D array
Let us reiterate the arrangement of an array element in a two-dimensional array of students, which contains roll no’s: in one column and the marks in other.
The array arrangement shown in the below figure is only conceptually true. This is because memory contains rows and columns. In memory, whether it is a 1-D or 2-D array, the array elements are stored in one continues the chain. The arrangement of an array element of a 2-D array in memory is shown below:
int arr[3][2]={1,11,21,31,41,51};
We can easily refer to the marks obtained by the second student using the subscript notation as shown below:
printf("Marks of second student=%d",arr[1][1]);
Three or Multi-dimensional arrays
We aren’t going to show a programming example that uses a 3-D array. This is because, in practice, one rarely uses this array. However, an example of initializing a 3-D array will consolidate your understanding of subscripts:
int arr[3][3][2] = {
{
{1,11},
{2,22},
{3,33}
},
{
{4,44},
{5,55},
{6,66}
},
{
{7,77},
{8,88},
{9,99}
}
};
A 3-D array can be thought of as an array of arrays of arrays. The outer array has three elements; each of witches is a 2-D array of three one-dimensional arrays, each of which contains two integers. In other words, a one-dimensional array 0f two elements are constructed first. Then four such one-dimensional array are placed one below the other to give a two-dimensional array are placed one behind the other to yield a three-dimensional array containing three 2-D arrays. In the array declaration, note how the commas have been given.
How would you refer to the array element 99 in the above array? The first subscript should be [2] since the element is in the third 2-D array. The second subscript should be [2] since the element is in the third row of the two-dimensional array, and the third subscript should be [1] since the element is in the second position in the one-dimensional array. We can, therefore, say that the element 1 can referred to as arr[2][2][1]. It may be noted here that the counting of array element even for a 3-D array begins with zero. Can we not refer to this element using pointer notation? Of course, yes. For example, the following two expressions refer to the same element in the 3-D array. arr[2][2][1] *(*(*(arr+2)+2)+1)
C allows 3-D or more dimensions. The exact limit is determined by the compiler. The general form of a multi-dimensional array is
type array_name[s1][s2][s3]……[si];
Where si is the size of the ith dimension.
Arrays with functions
An array element can be passed to a function by calling the function by value, or by reference. In the call by value, we pass values of array elements to the function, whereas, in the call by reference, we pass the address of array element to the function. These two calls are illustrated below:
Call By Value
/* Demonstrated of call by value */
#include <stdio.h>
void baluTutorial(int);
void main()
{
int i;
int marks[6]={55,66,77,88,99,100};
for(i = 0 ;i <= 5 ; i++ )
baluTutorial( marks[i] );
return 0;
}
void baluTutorial(int r)
{
printf("%d ",r);
}
Output: [quote]55 66 77 88 99 100[/quote]
Here, we are passing an individual element at a time to the function baluTutorial() and getting it printed in the function baluTutorial(). Note that, since at a time only one element is being passed, this element is collected in an ordinary integer variable r, in the function baluTutorial().
Call By Address
/* Demonstrated of call by address */
#include <stdio.h>
void display(int* );
int main()
{
int i;
int marks[6]={55,66,77,88,99,100};
for ( i = 0 ;i <= 5 ; i++ )
display( &marks[i] );
return 0;
}
void display( int *r)
{
printf("%d ",*r);
}
Output:[quote]55 66 77 88 99 100[/quote]
Here, we are passing the address of an individual array element to the function display(). Hence, the variable in which this address is collected r is declared as a pointer a variable. And since n contains the address of array element, to print out the array element, we are using the ‘value at address’ operator *.
Passing an Entire Array to a Function
As the value of simple variables, it is also possible to pass the values of an array to a function. To pass an array to a called function, it is sufficient to list the name of the array, without any subscripts, and the size of the array as arguments. For example, the call largest(arr,n); will pass all the elements contained in the array arr of size n. the called function expecting this call must be appropriately defined. The largest function header might look like:
int largest(int array[],int size);
The function largest is defined to take two arguments, the array name and the size of the array to specify the number of elements in the array. The declaration of the formal argument array is made as int array[ ]; the pair of bracket informs the compiler that the argument array is an array of numbers. It is not necessary to specify the size of the array here.
Let us consider a problem of finding the largest value in an array of elements. The program is as follows:
#include <stdio.h>
float largest(float*, int);
int main()
{
float arr[5]={2.5,-8.2,4.4,5.8,8.2};
printf("\n%d",largest(arr,5));
return 0;
}
float largest(float a[ ], int size)
{
int i;
float max;
max=a[0];
for( i = 1 ; i <size ; i++ )
{
if(max < a[i])
max= a[i];
}
return (max);
}
Output:[quote]8.200000 [/quote]
When the function call largest (arr,5) is made, the values of all elements of the arr are passed to the corresponding element a in the called function. The largest function finds the largest value in the array and returns the result to main.
Arrays with pointers
When we array is declared, the compiler allocates a base address and sufficient amount of storage to contain all the elements of the array in contiguous memory locations. The base address is the location of the first element (index 0) of the array. The compiler also defines the array names as a constant pointer to the first element. Suppose we declare an array x as follows:
int x[5]={1,2,3,4,5};
Suppose the base address of x is 500 and assuming that each integer requires two bytes, the five elements will be stored as follows:
The name x is defined as a constant pointer pointing to the first element, x[0] and therefore the value of x is 1000, the location where x[0] is stored. That is,
x=&x[0]=500
If we declare p as a pointer of type integer, then we can make the pointer p to point to the array x by the following assignment: p=x;
this is equivalent to p=&x[0];
Now, we can access every value of x using p++ to move from one element to another. The relationship between p and x is shown below:
- p =&x[0]=500
- p+1 =&x[1]=502
- p+2 =&x[2]=504
- p+3 =&x[3]=506
- p+4 =&z[4]=508
You may notice that the address of an element is calculated using its index and the scale factor of the data type. For instance,
[quote]
Address of x[3] = base address + (3 * scale factor of int )
=500 + (3 * 2)
=506
[/quote]
When handling arrays, instead of using array indexing, we can use pointers to access array elements. Note that *(p+3) gives the value of x[3]. The pointer accessing method is much faster than array indexing.
A pointer can be used for 2-D, 3-D, and multi-dimensional arrays as well. We know that in a one-dimensional array x, the expression *(x+i) or *(p+i)
represents the element x[i]. Similarly, an element in a 2-D array can be represented by the pointer expression as follows:
*(*(a+i)+j) or *(*(p+i)+j)
The below figure illustrates how this expression represents the element a[i][j]. The base address of the array a is &a[0]0]and starting at the address, the compiler allocates contiguous space for all the elements, row-wise. That is, the first element of the second row is placed immediately after the last element of the first row, and so on. Suppose we declare an array an as follows.
int a[3][4]={
{1,11,21,31},
{2,12,22,32},
{3,13,23,33}
};
The element of a will be stored as shown below
If we declare p as an int pointer with the initial address of &a[0][0], than a[i][j] is equivalent to *(p+4 * i+j).
You may notice that, if we increment i by 1, the p is incremented by 4, the size of each row, making p element a[2][3] is given by *(p+4 * 2+3) = *(p +11).
This is the reason why, when a 2-D array is declared, we must specify the size of each row so that the compiler can determine the correct storage mapping.