Dynamically allocating array of structs

Started by
10 comments, last by Zahlman 15 years, 5 months ago
Could someone post an example of how this would be done in C++? And I'm not wanting to use vectors at the moment... I have this code so far to dynamically allocate arrays using examples I found, but how would I do it for a structure? I tried replacing new int with stuff like... new structname but no go and I can't find anything on google.

    int size = 1; // size of array
    int* a = new int[size];  // new array
    int n = 0;

    while(std::cin >> a[n])
    {
        n++;
        if (n >= size) {
            size += 1; // increase size of array.
            std::cout << "size: " << size << std::endl;
            int* temp = new int[size]; // create new bigger array.
            for (int j=0; j<n; j++) {
                temp[j] = a[j]; // copy values to new array.
            }
            delete [] a; // free memory
            a = temp; // points to new array.
        }
    }

Advertisement
Quote:Original post by Jaqen
I tried replacing new int with stuff like... new structname

That should work.

Quote:Original post by Jaqen
but no go

Be more verbose. What did the compiler exactly complain about? Show us the code that produces the error message. Are you sure the struct was defined?

Some test code that works for me:
struct example{    int a, b, c;};int main(){    example *test = new example[10];    test[0].a = 5;    test[3].c = 7;    test[7].b = 2;    delete[] test;}
Thanks, I got it working.
Quote:Original post by Jaqen
Could someone post an example of how this would be done in C++? And I'm not wanting to use vectors at the moment...


I'm confused; do you want to use C++ or not? :)
Of course! However, I'm trying to learn everything I can and get a lot of practice in. Still too much I don't know.
Quote:Original post by DevFred
struct example{    int a, b, c;};int main(){    example *test = new example[10];    test[0].a = 5;    test[3].c = 7;    test[7].b = 2;    delete[] test;}


Could someone clarify what's going on here (gimme the nitty gritty assembly level details)? I imagine you would have to increment the pointer to point to the next example rather than be able to index the array like test[3].
Quote:Original post by Shakedown
Could someone clarify what's going on here (gimme the nitty gritty assembly level details)? I imagine you would have to increment the pointer to point to the next example rather than be able to index the array like test[3].


The code asks the operating system for a block of memory which is at least sizeof(example) * 10 bytes long. Assuming this is successful, the operating system returns a memory address where this memory resides, after marking it internally as in use by that program. (This skips over a lot of details about virtual memory, alignment, paging etc.) The program records in an implementation-specific way that it has a block of memory of that size at the indicated location, and the returned address goes into either a register or a variable on the stack. (One possible scheme for doing the recording is to ask for one word more of memory from the OS, write the size - or perhaps the element count - into that word, and increment the returned pointer to point to the "real" allocation.) Then, the example constructor, if any is found, is run on each element of the array, initializing the memory "in place" and optionally running any additional "setup" code. Here, there is no explicitly provided constructor, and the struct is POD, so no initialization takes place.

Now, as long as each address involved is valid, you must understand that x[y] is equivalent to *(x + y). Although arrays and pointers are fundamentally different things, array names are used as pointers to the beginning element. When you index a local array (like 'example foo[10]'), you actually "decay" 'foo' to a pointer, increment the pointer (remember that pointer arithmetic automatically takes the sizeof() the pointed-at type into account, and reference the element at the resulting location. (In C++, the easiest way to think about it is that if X is of type Foo*, then the type of the expression '*X' is not Foo, but Foo& - you don't automatically copy things just by dereferencing a pointer!)

This, incidentally, has a lot to do with why you can't put a Derived instance into an array of Base and expect it to work properly: it "doesn't fit". Each element of the Base array is exactly sizeof(Base) bytes long (it must be, in order to guarantee that pointer arithmetic can work), and in general, sizeof(Derived) may be larger than that. (And special-casing for the situation where it's the same size would just make things even MORE confusing.)
And that is why Zahlman is godly epic.
Jack
Quote:Original post by Shakedown
Could someone clarify what's going on here (gimme the nitty gritty assembly level details)?

Sure, here's the relevant output of g++ -O1 -S:
example *test = new example[10];	movl	$120, (%esp)	call	__ZnajSince each example requires 12 bytes of memoryand we want 10 of them, we must allocate 12*10 = 120 bytes.So we store 120 on top of the stack and let the magical routine __Znaj do the work.When that routines returns, %eax points to the first of the 120 allocated bytes.test[0].a = 5;	movl	$5, (%eax)The a component of element 0 starts at the very beginning,that is at the address that %eax points to,so we store the value 5 there.test[3].c = 7;	movl	$7, 44(%eax)test[3] is 3*12 = 36 bytes beyond test[0],and the c component is 8 bytes beyond the a component,and 36 + 8 = 44.test[7].b = 2;	movl	$2, 88(%eax)7*12 + 4 = 88delete[] test;	testl	%eax, %eax	je	L3	movl	%eax, (%esp)	call	__ZdaPvL3:	movl	$0, %eaxOh how nice, deleting a null pointer is a no-op - in case you didn't know :-)

Quote:Original post by Shakedown
I imagine you would have to increment the pointer to point to the next example rather than be able to index the array like test[3].

a is just syntactic sugar for *(a+i), that is, [] always operates on a pointer and an integer. If a is the name of an array, it implicitly decays into a pointer to its first element before the actual indexing is done.

Note that in my code, no arrays are involved. (The size of arrays must be known at compile time.) new example[10] returns a pointer to one example. It just so happens that after that example, there is room for 9 more examples.

Google "array to pointer decay" or read the FAQ for more information.

Now comes the most important part: sane people don't want to handle these low level details, and that's why you will eventually switch to vector.
Quote:Original post by Zahlman
array names are used as pointers to the beginning element.

Not always though ;-)

sizeof array yields the size of the entire array, not the size of a pointer to its first element.

char a[] = "Hello"; copies the entire string into a, not a pointer to its first character 'H'.

&array yields a pointer to the entire array, not a pointer to its first element (the address is the same, but the type differs).

In all other contexts, the array name decays into a pointer to its first element. read more

This topic is closed to new replies.

Advertisement