TITLE: initializing built-in arrays (Private mailing, 16 Jun 98) [ This is part of a previous tip titled "array initialization with and without STL". -adc ] >TITLE: array initialization with and without STL >(Newsgroups: comp.lang.c++, 5 Jun 98) > >SOMEONE: c9707010@alinga.newcastle.edu.au > >> I just read a post where someone asked how to create an array in C++, >> and how to initialize it using a for-loop, and then how to output it. >> Fair enough request... > >KUEHL: dietmar.kuehl@claas-solutions.de > >The answer to the question is non-trivial at all! If you really want to >*initialize* a built-in array with value opposed to assigning values after >initialization, things are quite messy and even beyond most experts. Here is >how this roughly looks like for an array of ints initialized with increasing >values: [code snipped] >I hope I haven't messed up this example... I'm more used to do this with STL: [code snipped, which uses STL iterators] >Anyway: Once you know how to write an iterator, it is much easier to use the >STL than to initialize an array manually. ... and it is occasionally necessary >to initialize an array, eg. because the type stored in the array does not have >a default constructor. TRIBBLE: david.tribble@central.beasys.com Maybe I missed the beginning of the discussion, but declaring and initializing arrays is simply not that complicated. The concept of "creating" an array is bit confusing; you can create an array at program startup by declaring a static (non-dynamic) array object, or you can create one during program execution by allocating a dynamic (non-static) array object. I will discuss initializing static arrays first. The simplest case is initializing arrays of built-in types or POD types. For example: // 1. Array of ints int intArr[10] = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, // Statically initialized ints }; // 2. Array of PODs struct Pod { int num; const char * name; }; static const struct Pod podArr[] = { { 0, "zero" }, // Statically initialized POD struct { 1, "one" }, { 2, "two" }, { 3, "three" }, { -1, NULL }, }; Initializing more complicated built-in types, such as pointers, is still fairly straightforward. For example, initializing an array of pointers to pre-existing objects: class Foo { ... }; class Foobar { public: static Foo foo1; static Foo foo2; static Foo foo3; }; static Foo * otherInts[] = { &Foobar::foo1, // Points to a static object &Foobar::foo2, &Foobar::foo3, }; Initializing arrays of non-POD types is a little more complicated because each element is an object which must be constructed. But this is not very difficult: class Bob { public: Bob(int i); // Constuctor }; static Bob myBobs[] = { Bob(3), // Constructed object of type 'Bob' Bob(2), Bob(1), }; These kinds of initializers are executed at program startup if they have file scope, or the first time the containing block is entered if they have block scope. Of course in practice, I don't like to use free (non-member) variables, so I usually declare these kinds of arrays as a static members of some class (effectively making the class names act like namespaces): class Foo { public: // Shared constants static const Pod podArr[]; public: // Shared variables static int intArr[10]; ... }; Now to discuss dynamically allocated arrays. Kuehl's (dietmar.kuehl@claas-solutions.de) code demonstrated how to dynamically allocate and initialize an array of ints: > int *array = static_cast(operator new[] (sizeof(int) * size)); > for (int i = 0; i < size; ++i) > new(array + i) int(i); While this is certainly correct, it is overly complicated because built-in types like 'int' don't need explicit constructors (and certainly don't need explicit destructors). It is also flawed by the fact that it does not 'new' an array of ints but rather an array of bytes which is then typecast into an int array. A much simpler version is this: int * array = static_cast(new int[size]); for (int i = 0; i < size; i++) array[i] = i; Allocating an array of non-built-in, non-POD types is more complicated because each element is an object that must be constructed. Example: Employee emps[30]; This causes an array of 30 'Employee' objects to be allocated. After the space has been allocated, each of the 30 members are then constructed by calling the default Employee::Employee() constructor function for each one. While this is a valid use of object arrays, in practice it's usually better to allocate an array of object pointers instead. This allows you to manage the elements one at a time. For example: Employee * empP[30]; for (int i = 0; i < 30; i++) empP[i] = new Employee; This also means that all 30 objects must be deleted eventually: for (int i = 0; i < 30; i++) delete empP[i], empP[i] = NULL; >From these fundamentals of array initialization, more complex arrays, and >thus more complex initializers, can be written. I'll leave the discussion >of STL iterators for those more capable than me.