C and C++ array :myths and conception


C++ array and array assignment

With variables we are allowed to manipulate a single value or storage of a given type.Say a variable of int type can only manipulate the value present in the memory allocated for that variable.This means a variable is bound to a single memory in it’s lifetime.In our program it is not a far fetch conception that a case may arise when we will be needing more than one data of a specific kind,for instance we may need 20 variables of int type to keep track of the information for 20 different students .In such scenario we can declare 20 variables and solve the given problem. But don’t you think declaring 20 variables with different names is a bit overdo and exhausting and also to organize 20 different names properly will not be an easy task.C++ is aware that programmer will face such situation while writing programs so,it provides them with a feature known as array-inherited from C- to help them manage many datas of a particular type efficiently.You will see that declaring an array is much more efficient and easier then declaring 20 variables or so in your program.In this post we will see some ways to manipulate an array and also explore some of the myths surrounding an array.

what is an array?

By array we simply mean a collection of data of particular type and by collection we mean holding many values.Note an array is also a variable so it is declare in the same way as the normal variables are declared.But to distinguish an array from the normal variables we will add the opening and closing square bracket ‘[]’ after the variable name and the number of values the array should hold is mentioned inside the square bracket;this value is known as index value.An example of array declaration is shown below.

int ivalue; //normal variable

int iarr[2] ; ///an array declaration

The difference between ivalue and iarr[2] is that ‘ivalue’ can hold only one integer value but ‘iarr[2]’ can hold two integer values since the index value mentioned inside the square bracket is 2.But if say,iarr[5] is written then it can hold five integers value due to index value being 5.So the number of data an array can hold depend on the value mentioned inside the square bracket.





Initializing an array

We have seen that declaring an array is pretty simple.And before we start using an array we have to initialize them.There are two ways to initialize an array.

i)Explicit initialization and
ii)Using loop-for or while- statement.

The second method will be discussed later.

Explicit initialization of array

int iarr[5]={ 2 , 4 , 5 , 5 , 67 } ; ///integer array initialization

char carr[3]={‘G’ , ‘O’ , ‘D’ } ; ///char array initialization

string sarr[2] ={ “New shoes”
  “New games” }; ///string array initialization

double darr[4]={ 3.45 , 4e10 , 5.6 , .0098 } ;   ///double array initialization

In the code above for each array of the specific type the number of initializers -values inside the braces- provided is equal to the index value.And it should be because an array can only hold as many values as the mentioned index value.This can give rise to some cases when initializing an array.What if the number of initializers provided is less than or greater then the index value? In such cases we will get varying outcome depending on whether the elements provided is less or more.Consider the program below.

/***
if the initializers provided is less then the array index value
***/

int iarr[5]={2,3,4 } ;/// the 4th and 5th array is assigned 0

char carr[3]={‘G’ , ‘O’ } ; ///the 3rd array is assigned ” (empty character)

string sarr[4] ={ “New shoes”
    “New games”}; ///the 3rd and 4th array is assigned “” (empty string)

double darr[4]={ 3.45 , 4e10 , 5.6 } ; ///the 3rd array is assigned 0

 
/***
if the elements is more then the array index value
***/

int ir[3]={ 2,3,45,5} ; ///error ‘too many initializers’

string sr[2]={“New era” , ” of ” , “C++!” } ; ///error ‘too many initializers’

When the initializers provided is lesser than the index value the compiler will assign 0 for the remaining array if the type is integral or floating point.And if the type is char or string the compiler assign an empty string or an empty char;integer value of the empty char assigned is 0.However,if more initializers is provided then required the compiler throws an error.And it should because there is no extra storage to accommodate the extra values.


In C string index value should be 1 greater than the characters in string

If you are coming from C or have a back ground in C you will often see a string usually written as,

char str[4]=”low” ; ///work fine

The above way of initializing a char array also work fine in C++,but more important thing to note when using such method is the number of characters provided inside the “”(double quotation) should be 1 less then the index value.If not you get an error.Consider the case below.

char str[3]=”low” ; ///error

The reason for this is mainly due to C way of treating a string differently.According to C each string is appended with ‘\0’ character at the end of the string.So the above “low” string is actually interpreted as “low\0”-which is a 4 characters string.So this means the str index should be 4 not 3 and so like the normal rule that is followed when the initializers provided is more than the index value we get an error;C++ has a different way of treating a string,we will discuss that in Chapter 7.

To solve the problem that arises when more initializers is provided then the index value another way of initializing an array is introduced.To make the array variable more robust in this method we will not be mentioning the index value.

int ar[]={ 4,4,5,6} ;

string star[]={ “C++” , “C++11” , “C++14” , “C++17 coming soon” };

char car[]=”C type array string” ; ///work fine

Here we have not provided the index value so we are letting the compiler to deduce the index value.The advantage with this method is since the compiler has to figure out the index value it cannot throw an error message stating that “the initializers provided is too many” even when we have provided initializers more than we required.

The disadvantage with this method is we do not know the index value before hand if the necessity arises.But this problem can be solved by performing simple operation:sizeof(your_array)/sizeof(data type),which evaluate the total number of elements in an array.The sizeof() functions return the size of the whole array and to get the number of elements in array we divide it by the size of the array type.

int ia[]={ 5 , 5 , 6 , 7 } ;

cout<< sizeof(ia) ; ///gives 4

 


 


Accessing an array

We have discussed how to store values in an array now then let us see how to access them.To access the array element we will till use the array syntax that means we will attach the subscript ‘[]‘ after the array name.And to access a specific element we will mentioned the the index value.The index value will depend on the position of the value which it is written when it was used for initialization.Consider the array arr below.

int arr[4]={ 303 , 404 , 405 , 505 } ;

If you want to access the value ‘404’ from the array then we will use the expression arr[1].Note the index here is 1 not 2 although the value 404 was written in the second position during initialization.This is due to the standard way of counting in C++ which starts from 0.So to access the first element the index will be 0 and the correct expression is arr[0].

cout<< arr[1] << endl  ///prints 404
  << arr[0] << endl  ///prints 303
   << arr[2] ;  ///prints 405

 
More example is given below.
 

int ia[4]={ 121 , 3 , 80 } ;

cout<< ia[2] << endl ///prints 80
 << ia[3] << endl; ///prints 0

double darr[]={ 3.45 , 6.78 , 0.958 , 3 } ;

cout<< darr[3] << endl ///prints 3
 << darr[1] << endl; ///prints 6.78

string sarr[]={ “Happy” ,
   “Sad” ,
   “Lively ” };

cout<< sarr[2] << endl ///prints “Lively”
   << sarr[0] << endl; ///prints “happy”

 
If you want to access all the elements of an array you can use the for() statement.Consider the program below.
 

char carr[]={ ‘Y’ , ‘e’ , ‘s’ , ‘/’ , ‘N’ , ‘o’ };

for (size_t i=0 , size=sizeof(carr)/sizeof(char) ; i<size ; i++ )
{
cout<< carr[i] ;
}

Accessing the array element using the consecutive index value 0,1,2 … and so on is possible because the elements in an array are stored in a consecutive manner.The element lies next to each other in a storage.


Fig Array elements lying in a consecutive manner

There is another way to access the array element using for( ) statement, this method is known as range-based for loop and it is introduced in C++11.The method is shown below.

char carr[]={ ‘Y’ , ‘e’ , ‘s’ , ‘/’ , ‘N’ , ‘o’ } ;

for (auto ele:carr )
{
cout<< ele ;
}

The output is still,

Yes/No

If you don’t know what is auto visit this link C++11 using auto keyword.





Assigning an array to another array

C and C++ does not allow an array to be assigned to another array.In other words it does not allow copying of array.Consider the code below.

int i[]={ 2,345 ,47} ;

int ia[]=i ; ///error

ia=i ;///error

If you want to copy the values of one array to another then you can use the for() or while() statement to copy the value one by one.

for(int i=0; i<3;i++ ) { ia[i]=i[i] ; }

 


Exchanging the array name and index value when accessing the array element

Another intriguing case when accessing an array element is exchanging the array name and index value in the syntax will still yield the correct value.Consider the code below.

int iar[]={ 00, 10, 100 , 1000 }

cout<< 1[iar] << endl ///work fine prints 10
 << 3[iar] ; ///work fine prints 1000

for( size_t i=0 , size=sizeof(iar)/sizeof(int) ; i++)
{
cout<< i[iar] << endl; ///work fine
}

Why does the above syntax: i[arr] work? To understand why this form is valid we will need to look deeper into the Compiler way of executing an array.First thing to note is the compiler does not know what is array ,the whole array syntax form is only accustom to us:the C++ programmer.When we ask the compiler to print the third element by providing the expression:iarr[2],the compiler won’t understand.For the Compiler to actually evaluate the expression it will turn the expression into an understandable form.So what it does is it will turn it into a pointer expression.And the expression will look something like this *(iarr+2).The meaning of this expression is “give the value present in the second position from the address of ‘iarr'” or it can be interpreted as “give the value present at the address ‘iarr+2*(sizeof(int))‘ “;the size of the data type is also required to calculate the address.Consider the code below.

cout<< iarr[2] << ” ” << *(iarr +2 ) << endl ;///the output is the same
<< iarr[3] << ” ” << *(iarr+3) << endl ;///the output is the same

cout<< (int)iarr << ” ” << (int)(iarr+2) ;  ///The difference is 8 bytes

iarr is in 0 position , (iarr+1) in 1st position and (iarr+2) in second so the value at (iarr+2) is printed out, simple isn’t?.If you want to read more about the relation between a pointer and an array a link is given here Relation between array and pointers..

Now going back to the discussion why exchanging the index and the array name will still yield the same value? In providing the expression 2[iarr],the compiler is liable to convert it into a pointer form.Obviously the compiler will now be viewing the expression 2[iarr] as *( 2 + iarr ) .This in turn can be written as *(iarr + 2 ),which is in fact the form obtain when the array is accessed using the standard form – iarr[2].So in this case also the compiler will yield the third element of the array.Although the expression used may be different in the interface level but underneath if the interpretation is the same the compiler will certainly comply;this is also why they say, “Looks does not matter,beauty is what lies underneath!”.I bet we can’t say no to that saying ,can we?


Related Link

->Relation between array and pointers.