Sign in to follow this  
Jaqen

Dynamically allocating array of structs

Recommended Posts

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.
        }
    }

Share this post


Link to post
Share on other sites
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;
}

Share this post


Link to post
Share on other sites
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? :)

Share this post


Link to post
Share on other sites
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].

Share this post


Link to post
Share on other sites
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.)

Share this post


Link to post
Share on other sites
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 __Znaj
Since each example requires 12 bytes of memory
and 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 = 88

delete[] test;
testl %eax, %eax
je L3
movl %eax, (%esp)
call __ZdaPv
L3:
movl $0, %eax
Oh 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[i] 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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
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


I didn't want to risk trying and failing to make an exhaustive list :)

(Pointers-to-array are weird entities, but sometimes the easiest way to make sense out of working with multi-dimensional arrays.)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this