C equivalent of C++ new()?

S

Steve555

Hi

I've been working with C++ and Objective-C and I've forgotten how to
allocate memory for an array of structs in C.

Given a struct:

typedef struct {
double a,b,c,d;
long e,f,g,h;
} MyStruct


I want to do the equivalent of :

MyStruct **myStructArray;
myStructArray = new MyStruct*[1024];
for(long i=0; i<1024; i++){
myStructArray = new MyStruct;
}
so that I can access them by index:

double a = myStructArray[1]->a;


I'm aware of malloc as a simple lump of memory, but don't understand
how it would be aware of the boundaries of each struct and each
element.

Thanks

Steve
 
S

Seebs

I'm aware of malloc as a simple lump of memory, but don't understand
how it would be aware of the boundaries of each struct and each
element.

It wouldn't, nor would it need to be.

The boundaries of the structures and elements come from the type of
the pointer you use to hold the address returned from malloc().

C++ needs constructors and thus allocators care about types. C doesn't
have constructors, so there's no type to allocation -- you just get
a block of memory.

-s
 
J

Jon

Seebs said:
It wouldn't, nor would it need to be.

The boundaries of the structures and elements come from the type of
the pointer you use to hold the address returned from malloc().

C++ needs constructors and thus allocators care about types. C
doesn't have constructors, so there's no type to allocation -- you
just get
a block of memory.

You tell him Seebs. (He's your "straight man", c'mon, lame comedy).
 
S

Steve555

It wouldn't, nor would it need to be.

The boundaries of the structures and elements come from the type of
the pointer you use to hold the address returned from malloc().

C++ needs constructors and thus allocators care about types.  C doesn't
have constructors, so there's no type to allocation -- you just get
a block of memory.

-s

Thanks, I wasn't sure if that was the case.
But I still can't get my head around the fact it's pointers of
pointers:

Would this be correct, based on what you said:

myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))
for(long i=0; i<1024; i++){
myStructArray = malloc(sizeof(MyStruct));
}
 
S

Steve555

 Steve555 said:
I've been working with C++ and Objective-C and I've forgotten how to
allocate memory for an array of structs in C.
MyStruct   **myStructArray;
myStructArray = new MyStruct*[1024];

This is an array of struct pointers, not an array of structs.
for(long i=0; i<1024; i++){
    myStructArray = new MyStruct;
}
so that I can access them by index:

double a = myStructArray[1]->a;

myStructArray = malloc(1024*sizeof(MyStruct));
...
    myStructArray = malloc(sizeof(MyStruct));
I'm aware of malloc as a simple lump of memory, but don't understand
how it would be aware of the boundaries of each struct and each
element.

It doesn't need to be aware. You allocate a separate block for each struct as a
pointer, and one block for the array of pointers. The address arithmetic picks
the correct pointer out of the array, assuming you don't lie about the array
size, and the pointer deref gets the struct value.

If you want to allocate an array of structs, that's just
    MyStruct  *myStructArray = malloc(1024*sizeof(MyStruct));
    ...
    double a = myStructArray[1].a;

--
Damn the living - It's a lovely life.           I'm whoever you want me to be.
Silver silverware - Where is the love?       At least I can stay in character.
Oval swimming pool - Where is the love?    Annoying Usenet one post at a time.
Damn the living - It's a lovely life.     May your creator bless and keep you.


double a = myStructArray[1].a;

Thanks, but in case I didn't explain well enough, the crucial point is
that I need pointers:

double a = myStructArray[1]->a;

I'm passing large structures by pointer to time-critical functions to
save the overhead of copying.
 
S

Steve555

 Steve555 said:
I've been working with C++ and Objective-C and I've forgotten how to
allocate memory for an array of structs in C.
MyStruct   **myStructArray;
myStructArray = new MyStruct*[1024];
This is an array of struct pointers, not an array of structs.
for(long i=0; i<1024; i++){
    myStructArray = new MyStruct;
}
so that I can access them by index:
double a = myStructArray[1]->a;

myStructArray = malloc(1024*sizeof(MyStruct));
...
    myStructArray = malloc(sizeof(MyStruct));
I'm aware of malloc as a simple lump of memory, but don't understand
how it would be aware of the boundaries of each struct and each
element.

It doesn't need to be aware. You allocate a separate block for each struct as a
pointer, and one block for the array of pointers. The address arithmetic picks
the correct pointer out of the array, assuming you don't lie about the array
size, and the pointer deref gets the struct value.
If you want to allocate an array of structs, that's just
    MyStruct  *myStructArray = malloc(1024*sizeof(MyStruct));
    ...
    double a = myStructArray[1].a;
--
Damn the living - It's a lovely life.           I'm whoever you want me to be.
Silver silverware - Where is the love?       At least I can stay in character.
Oval swimming pool - Where is the love?    Annoying Usenet one post at a time.
Damn the living - It's a lovely life.     May your creator bless and keep you.

double a = myStructArray[1].a;

Thanks, but in case I didn't explain well enough, the crucial point is
that I need pointers:

double a = myStructArray[1]->a;

I'm passing large structures by pointer to time-critical functions to
save the overhead of copying.


MyStruct **myStructArray;
myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))
for(long i=0; i<1024; i++){
myStructArray = malloc(sizeof(MyStruct));
myStructArray->g = i;
}
printf("%d", myStructArray[123]->g);

OK, well that *seems* to work, but as with all memory problems, I
might just have got lucky.
If any kind soul spots a lurking catastrophe, I'd appreciate a heads-
up :)
 
I

Ian Collins

MyStruct **myStructArray;
myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))

Those two lines can be simplified to

MyStruct **myStructArray = malloc(1024 * sizeof(MyStruct*));
for(long i=0; i<1024; i++){
myStructArray = malloc(sizeof(MyStruct));
myStructArray->g = i;
}
printf("%d", myStructArray[123]->g);

OK, well that *seems* to work, but as with all memory problems, I
might just have got lucky.
If any kind soul spots a lurking catastrophe, I'd appreciate a heads-
up :)


Just don't forget to free them all when you are done.
 
S

Steve555

MyStruct   **myStructArray;
myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))

Those two lines can be simplified to

MyStruct **myStructArray = malloc(1024 * sizeof(MyStruct*));
for(long i=0; i<1024; i++){
     myStructArray = malloc(sizeof(MyStruct));
     myStructArray->g = i;
}
printf("%d", myStructArray[123]->g);

OK, well that *seems* to work, but as with all memory problems, I
might just have got lucky.
If any kind soul spots a lurking catastrophe, I'd appreciate a heads-
up :)

Just don't forget to free them all when you are done.


Many thanks Ian :)
 
A

Alexander Klauer

Steve555 said:
MyStruct **myStructArray;
myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))
for(long i=0; i<1024; i++){
myStructArray = malloc(sizeof(MyStruct));
myStructArray->g = i;
}
printf("%d", myStructArray[123]->g);

OK, well that *seems* to work, but as with all memory problems, I
might just have got lucky.
If any kind soul spots a lurking catastrophe, I'd appreciate a heads-
up :)


Please do not forget to check explicitly whether your malloc()s succeeded.
In your case, malloc() has failed if and only if it has returned a null
pointer (this is quite unlike C++, where "new" never yields a null
pointer).
 
L

lawrence.jones

Steve555 said:
MyStruct **myStructArray;
myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))
for(long i=0; i<1024; i++){
myStructArray = malloc(sizeof(MyStruct));
myStructArray->g = i;
}
printf("%d", myStructArray[123]->g);

OK, well that *seems* to work, but as with all memory problems, I
might just have got lucky.


That works, but it's rather inefficient. You can allocate all the
structs in a single block instead:

MyStruct *myStructArray = malloc(1024 * sizeof *myStructArray);
for (int i = 0; i < 1024; i++) {
myStructArray.g = i;
}
printf("%d\n", myStructArray[123].g;

If you need pointers, use the "&" operator:

myFunc(&myStructArray[42]);
 
B

Ben Bacarisse

Steve555 said:
Steve555 <[email protected]> writes:
Thanks, but in case I didn't explain well enough, the crucial point is
that I need pointers:

double a = myStructArray[1]->a;

I'm passing large structures by pointer to time-critical functions to
save the overhead of copying.

MyStruct **myStructArray;

If you are going to tag names with type info, it's wise to be clear.
This is an array of pointers not an array of structures.
myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))
for(long i=0; i<1024; i++){

long? If you might have very large arrays, the C type to use is
size_t. Note that it is an unsigned type.
myStructArray = malloc(sizeof(MyStruct));
myStructArray->g = i;
}
printf("%d", myStructArray[123]->g);


Do you need all the pointers to be "independent"? Another common patter
is to allocate a single array of structs and to point into that array.
You get two rather than 1025 malloc calls and only two pointers to free.

MyStruct *tmp_array = malloc(1024 * sizeof *tmp_array);
MyStruct **myStructPtrArray = malloc(1024 * sizeof *myStructPtrArray);
for (size_t i = 0; i < 1024; i++)
myStructPtrArray = &tmp_array;

Of course, this only works in some situations. If the pointers get
handed off to other functions and data structures that might want to
free them individually you can't use this structure.
 
J

John Bode

Hi

I've been working with C++ and Objective-C and I've forgotten how to
allocate memory for an array of structs in C.

Given a struct:

typedef struct {
    double   a,b,c,d;
    long       e,f,g,h;

} MyStruct

I want to do the equivalent of :

MyStruct   **myStructArray;
myStructArray = new MyStruct*[1024];
for(long i=0; i<1024; i++){
    myStructArray = new MyStruct;}


Since you're doing a two-step allocation and deallocation, it might be
best to create separate allocation and deallocation functions; that
will help keep everything organized.

MyStruct **createArray(size_t arraySize)
{
// sizeof *theArray == sizeof (MyStruct *)
MyStruct **theArray = malloc(sizeof *theArray * arraySize);
if (theArray)
{
size_t i;
for (i = 0; i < arraySize; i++)
{
// sizeof *theArray == sizeof (MyStruct)
theArray = malloc(sizeof *theArray);
if (!theArray)
break;

/* initialize theArray here */
}

if (i < arraySize)
{
/**
* One of the allocations failed; release everything
* allocated so far.
*/
size_t j;
for (j = 0; j < i; j++)
free(theArray[j]);

free(theArray);
theArray = NULL;
}
}
return theArray;
}

void destroyArray(MyStruct ***theArray, size_t arraySize)
{
size_t i;
for (i = 0; i < arraySize; i++)
free((*theArray);
free(*theArray);
*theArray = NULL;
}

int main(void)
{
MyStruct **myArray = createArray(1024);
/**
* do stuff with myArray
*/
destroyArray(&myArray);
...
}
 
F

Fred

Steve555 said:
MyStruct   **myStructArray;
myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))
for(long i=0; i<1024; i++){
    myStructArray = malloc(sizeof(MyStruct));
    myStructArray->g = i;
}
printf("%d", myStructArray[123]->g);

OK, well that *seems* to work, but as with all memory problems, I
might just have got lucky.

That works, but it's rather inefficient.  You can allocate all the
structs in a single block instead:

        MyStruct *myStructArray = malloc(1024 * sizeof *myStructArray);
        for (int i = 0; i < 1024; i++) {
           myStructArray.g = i;
        }
        printf("%d\n", myStructArray[123].g;

If you need pointers, use the "&" operator:

        myFunc(&myStructArray[42]);


Better to use sizeof(*myStructArray). That is,
Type *instance;
instance = malloc( n * sizeof(*instance) );

that way if you ever change Type, you don't need to find
and change all of the malloc/calloc/realloc lines.

And don't forget to #include <stdlib.h>
 
S

Seebs

myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))
for(long i=0; i<1024; i++){
myStructArray = malloc(sizeof(MyStruct));
}


This can't be correct. Not seeing the declaration of myStructArray, I
can't be sure what's wrong with it, but it should be either:
myStruct *myStructArray;
myStruct init_values = { 0, 3, 21 }; /* or whatever */
myStructArray = malloc(1024 * sizeof(MyStruct));
for (int i = 0; i < 1024; ++i) {
myStructArray = init_values;
}
or
myStruct **myStructArray;
myStruct init_values = { 0, 3, 21 }; /* or whatever */
myStructArray = malloc(1024 * sizeof(MyStruct *));
for (int i = 0; i < 1024; ++i) {
myStructArray = malloc(sizeof(MyStruct));
*myStructArray = init_values;
}

Usually, in C, you'd do the first. You're thinking like a C++ programmer,
and that's led you to two mistakes:

1. You're trying to allocate all the items separately, because you're
thinking of allocation/new as where the constructor happens. There's
no constructor! Just populate the items directly. Each element of
the array should, usually, be a myStruct, not a pointer.
2. You're casting the return from malloc. Don't do that; it's bad style
in C. (In C++, there are perhaps sound reasons for void * not to
automatically convert; in C, there aren't, so it converts automatically.
Casting pointer conversions like this just hides bugs.)

-s
 
S

Seebs

Thanks, but in case I didn't explain well enough, the crucial point is
that I need pointers:
double a = myStructArray[1]->a;
I'm passing large structures by pointer to time-critical functions to
save the overhead of copying.

That doesn't mean you need separately-allocated objects.

function(&myStructArray[1]);

You can take the address of the objects in the array regardless, and
if you're worried about time-critical, extra allocations are probably
bad.

-s
 
S

Seebs

MyStruct **myStructArray;
myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))

This cast is obviously wrong, but also unnecessary.
for(long i=0; i<1024; i++){
myStructArray = malloc(sizeof(MyStruct));
myStructArray->g = i;
}
printf("%d", myStructArray[123]->g);


This is otherwise correct.

-s
 
P

Paul N

Thanks, I wasn't sure if that was the case.
But I still can't get my head around the fact it's pointers of
pointers:

Would this be correct, based on what you said:

myStructArray = (MyStruct*)malloc(1024 * sizeof(MyStruct*))
for(long i=0; i<1024; i++){
    myStructArray = malloc(sizeof(MyStruct));
}


That looks right, though there are useful comments elsewhere in the
thread, including checking the return value of malloc and using a
size_t for i.

If it's any consolation, I found the C syntax odd when I first used
it. You reserve space for a MyStruct and then you pretend you have one
there. It seemed a bit like building a tiger cage and then expecting a
tiger to magically appear in it. But, if you think about it, there is
nothing further you need to do to summon a MyStruct into existence.
Possibly you need to initialise the space in some way, just like a
constructor in C++ except that you need to call it yourself.

The C++ syntax seems more intuitive - you want a new MyStruct, so you
ask for one and you get one.

Hope that helps, or at least reassures!
Paul.
 
N

Nick Keighley

This can't be correct.  Not seeing the declaration of myStructArray, I
can't be sure what's wrong with it, but it should be either:
myStruct *myStructArray;
myStruct init_values = { 0, 3, 21 }; /* or whatever */
myStructArray = malloc(1024 * sizeof(MyStruct));
for (int i = 0; i < 1024; ++i) {
myStructArray = init_values;
}
or
myStruct **myStructArray;
myStruct init_values = { 0, 3, 21 }; /* or whatever */
myStructArray = malloc(1024 * sizeof(MyStruct *));
for (int i = 0; i < 1024; ++i) {
myStructArray = malloc(sizeof(MyStruct));
*myStructArray = init_values;
}

Usually, in C, you'd do the first.  You're thinking like a C++ programmer,
and that's led you to two mistakes:
1.  You're trying to allocate all the items separately, because you're
thinking of allocation/new as where the constructor happens.  There's
no constructor!  Just populate the items directly.  Each element of
the array should, usually, be a myStruct, not a pointer.
2.  You're casting the return from malloc.  Don't do that; it's bad style
in C.  (In C++, there are perhaps sound reasons for void * not to
automatically convert; in C, there aren't, so it converts automatically..
Casting pointer conversions like this just hides bugs.)

They do that though, don't they?


why do you keep saying that?
is it funny?
 
N

Nick Keighley

Nick Keighley said:
This can't be correct.  Not seeing the declaration of myStructArray, I
can't be sure what's wrong with it, but it should be either:
myStruct *myStructArray;
myStruct init_values = { 0, 3, 21 }; /* or whatever */
myStructArray = malloc(1024 * sizeof(MyStruct));
for (int i = 0; i < 1024; ++i) {
myStructArray = init_values;
}
or
myStruct **myStructArray;
myStruct init_values = { 0, 3, 21 }; /* or whatever */
myStructArray = malloc(1024 * sizeof(MyStruct *));
for (int i = 0; i < 1024; ++i) {
myStructArray = malloc(sizeof(MyStruct));
*myStructArray = init_values;
}
Usually, in C, you'd do the first.  You're thinking like a C++ programmer,
and that's led you to two mistakes:
1.  You're trying to allocate all the items separately, because you're
thinking of allocation/new as where the constructor happens.  There's
no constructor!  Just populate the items directly.  Each element of
the array should, usually, be a myStruct, not a pointer.
2.  You're casting the return from malloc.  Don't do that; it's bad style
in C.  (In C++, there are perhaps sound reasons for void * not to
automatically convert; in C, there aren't, so it converts automatically.
Casting pointer conversions like this just hides bugs.)
They do that though, don't they?

why do you keep saying that?
is it funny?

Strange. I had always thought you were British. I guess not.


I am. Obviously something passed me by. I'm beginning to think
"Scouser" is a short BASIC program.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top