7.9 ARRAYS AND THEIR INITIALIZATION IN C


7.9 ARRAYS AND THEIR INITIALIZATION IN C++

In C++ you can create an array with either of the following two kinds of declarations

      int d[10];      int* dp = new int[10]; 

for arrays of integers. Similar declarations can be constructed for other types. With either declaration you can use array indexing to access the individual elements. So you could access, say, the fourth element by

        d[3] 

in the first case, or by

        dp[3] 

in the second case.

While it is true that an array name can be treated as a pointer, it is strictly speaking not a pointer, in the sense you cannot do certain kinds of pointer arithmetic on an array name. For example, you could get the value of the fifth element of the array by either of the following dereferencing operations:

        *( d + 4 ) 

or

        *( dp + 4 ) 

But, since you cannot assign to an array name, what does NOT work for an array name are the incrementing and decrementing operators. Therefore, the following does not work:

        *d++                                // error 

while the following is a common operation with a pointer to an array:

        *dp++ 

And, for the same reasons, while a pointer variable can be made to point to any other entity as long it is of the same type, an array name cannot be made to point to some some other array in the memory.

An array declaration is also a definition, since it reserves a block of memory for the array. But whether or not the memory allocated for an array is also default-initialized depends on whether we are dealing with an array of primitive types or class types, and whether the array is local or global in scope. Here is a summary of how default initialization works for arrays in C++:

  • For arrays of primitive types, an array is default-initialized to a zero of the appropriate kind only if the array is in global scope. That means that a local array will not be default initialized.

  • For arrays of class types, array declarations are illegal if the class does not possess a no-arg constructor.

  • For arrays of class types, if the class is supplied with a programmer-defined no-arg constructor, both the local and the global arrays are default-initialized according to the no-arg constructor.

  • For arrays of class types, if the class has to use a system-supplied default no-arg constructor, only the global arrays are default-initialized according to the no-arg constructor. In other words, in this case any local arrays of the class type will not be default-initialized.

Consider the following example that shows the difference between the default initialization for global and local arrays:

 
//DefaultInitPrimArray.cc #include <iostream> using namespace std; int global[10]; int main() { int local[10]; cout << local[0] << endl; // GARBAGE cout << local[1] << endl; // GARBAGE cout << global[0] << endl; // 0 cout << global[1] << endl; // 0 return 0; }

Obviously, the global array global is getting zeroed out, while the local array local just has random bits in its memory.

If you wish to initialize the array at the same time you are declaring it, you can use the following syntax:

       int data[] = {3, 2, 4, 5, 9, 8, 7, 6, 1, 0}; 

When an array is initialized in this manner, it is common to omit the size from the declaration on the left; the compiler figures out the size from the initializer on the right. However, if you do include the size as in

       char ch[3] = {'a', 'c', 'b'}; 

then you'd better make sure that the number of element on the right dose not exceed the size declared on the left. However, the number of element in the initializer is allowed to be smaller than the declared size on the left. If the declared size is M and the number of element supplied in the initializer is N < M, the first N elements

of the array are set according to the initializer, and the rest to zeros of the appropriate kind. This is to allow the initialization of large arrays with simple statements like[9]

     int data[10] = {0}; 

Regarding arrays of class types in C++, the following code fragment shows that when a class does not possess a no-arg constructor (because it has been supplied with one or more other constructors), it is not possible to declare arrays of that class type.

      class User {      public:          string name;          int age;          User( string nam, int yy ) { name = nam; age = yy; }      };      User uList[10];                                        // ERROR             User* uptr[10];                                       //OK 

The following example shows the difference between the default initializations for local and global arrays of class type objects. Both classes in the example, User and Date, possess system-supplied no-arg constructors because they have not been explicitly provided with any constructors at all.

 
//DefaultInitClassArray.cc #include <iostream> using namespace std; class Date { public: int d, m, y; }; class User { public: int ID; int age; Date dateOfBirth; }; User uGlobal[10]; // global array int main() { User uLocal[10]; // local array cout << uLocal[1].ID << endl; // GARBAGE cout << uLocal[1].age << endl; // GARBAGE cout << uLocal[1].dateOfBirth.y << endl; // GARBAGE cout << uLocal[1].dateOfBirth.m << endl; // GARBAGE cout << uGlobal[1].ID << endl; // 0 cout << uGlobal[1].age << endl; // 0 cout << uGlobal[1].dateOfBirth.y << endl; // 0 cout << uGlobal[1].dateOfBirth.m << endl; // 0 return 0; }

Note that for dateOfBirth, the class type data member of theUser class, is getting default initialized according to the system-supplied no-arg constructor for the class.

The following example shows that local and global arrays are treated the same with respect to default initialization when a class type is provided with a programmer-supplied no-arg constructor:

 
//DefaultInitClassArray2.cc #include <iostream> #include <string> using namespace std; class Date { public: int d, m, y; Date() { d = 1; m = 1; y = 1970; } }; class User { public: string name; int age; Date dateOfBirth; User() { name = "Zaphod"; age = 10; } }; User uGlobal[10]; // global array int main() { User uLocal[10]; // local array cout << uLocal[1].name << endl; // Zaphod cout << uLocal[1].age << endl; // 10 cout << uLocal[1].dateOfBirth.y << endl; // 1970 cout << uLocal[1].dateOfBirth.m << endl; // 1 cout << uGlobal[1].name << endl; // Zaphod cout << uGlobal[1].age << endl; // 10 cout << uGlobal[1].dateOfBirth.y << endl; // 1970 cout << uGlobal[1].dateOfBirth.m << endl; //1 return 0; }

One final point concerning C++ arrays: Ascertaining the memory address of the fictitious element just past the end of an array is permitted[54]. Consider the declarations:

     int data[] = {3, 4, 6, 7};          int* p1 = data;     int* p2 = data[0];     int* p3 = &data[4]; 

Whereas the pointers p1 and p2 point to exactly the same place in the memory-the first element of the array data-the pointer p3 points to a fictitious element just beyond the array. Many algorithms in the C++ Standard Template Library rely on p3 returning a valid address; its calculation is guaranteed to work by the C++ standard.

[9]It is not uncommon for beginning programmers to assume that in the statement

       int data[10] = {2}; 

all ten elements are getting initialized to the integer 2. But, as mentioned, that is obviously not the case. This declaration will cause only the first element of the array to be initialized to the number 2, the other nine elements would be set to 0.




Programming With Objects[c] A Comparative Presentation of Object-Oriented Programming With C++ and Java
Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Java
ISBN: 0471268526
EAN: 2147483647
Year: 2005
Pages: 273
Authors: Avinash Kak

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net