Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Java

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++:

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.

Категории