tags:

views:

227

answers:

7

I'm just not getting any further with allocating memory for arrays in C and mainly C++. I've looked for examples but there aren't any useful ones for me out there, at least it seems so.

So if I have a typedef here like this:

typedef struct
{
int x;
int y;
} Coordinate;

Coordinate* myList;

And I have an array of the type Coordinate too, how do I append items to it dynamically. All I know is that I have to use malloc and later free in C and new / delete in C++. (Malloc scares the hell out of me)

So what I was aiming for is a function like this:

void AddSomething ( int x, int y )
{
// myList malloc/new magic here
}

My question is:

  • How does the line that allocates new memory for myList and then adds the new item to it have to look like? Could you please show me a working example for C and C++?

  • How exactly does malloc in C work? There are some things about it that I'm not familiar with (there is some sort of pointer before the function, and the variable that is allocated is set to mallocs return value)

+12  A: 

Use vector to do the job.

#include <vector>

typedef struct
{
int x;
int y;
} Coordinate;

std::vector<Coordinate> coordinates;

Coordinate newCoord;
newCoord.x = 1;
newCoord.y = 1;

coordinates.push_back(newCoord);

Additional Information: To understand malloc/free and new/delete you might read chapter

13: Dynamic Object Creation

in Bruce Eckels Thinking C++ Volume 1. Its a book that can be downloaded for free.

Totonga
+3  A: 

For any question like this, the first reply has to be another question. Specifically, is there some really good reason you can't use an std::vector? Unless you really, truly, absolutely can't, that's the right thing to do.

Otherwise, your only real choice is to write (yet another) imitation of std::vector. Though I don't know you personally, experience indicates that what you write probably won't be as good.

Jerry Coffin
A: 

C malloc simply allocates memory, but doesn't "construct" an object. In C++, you would typically use new, which does allocate and construct the object. The primary difference is new calls the constructor after allocating the RAM. malloc is just a 'dumb' memory manager, but may perform better for certain specific cases where you need non-typed raw memory.

Both new and malloc "return" a pointer. A pointer is an address. So this is the form of both, they are assignment expressions.

Coordinate * notObject = (Coordinate*)malloc(sizeof(Coordinate));
Coordinate * object = new Coordinate();

Note, malloc returns a void *, so you must cast it. new is typed, so there is no casting required.

mrjoltcola
A: 
  • How does the line that allocates new memory for myList and then adds the new item to it have to look like? Could you please show me a working example for C and C++?

There are actually two different options: You can either create an array of Coordinate objects using:

Coordinate *list = new Coordinate[ 42 ]; // list can hold at most 42 objects

Or, use a linked list, which of course will require you to change the definition of your Coordinate data-type:

typedef Coordinate_t {
    int x, y;
    Coordinate_t *next;
};

Inserting in a linked list is a bit more complicated.

Of course, if you are using C, you cannot use the new operator, but will instead have to use malloc:

Coordinate *list = malloc(*list * 42); /* list can hold at most 42 objects */
  • How exactly does malloc in C work? There are some things about it that I'm not familiar with (there is some sort of pointer before the function, and the variable that is allocated is set to mallocs return value)

The allocation function uses some OS specific API to request some memory from the free store (and hence this is therefore implementation dependent). E.g: On *nix, a system API called sbrk and friends are used.

dirkgently
+4  A: 

For C, the following will create a list containing a single Coordinate:

myList = malloc(sizeof(Coordinate));

If you want to allocate an array of size n, you do the following:

myList = malloc(n * sizeof(Coordinate));

In C++, the code for an array of size n looks like this:

myList = new Coordinate[n];

For the C++ case, your class must have a default constructor, which the Coordinate class has implicitly. However for C++ I'd strongly suggest using a std::vector<Coordinate> instead of a manually managed array.

As an aside, you can use malloc() to allocate memory in C++ as well, but it only allocates raw memory whereas using new will also trigger a call to the constructor(s). In the case of your struct, there is no difference as it's a POD structure and doesn't require a constructor. Also, keep in mind that if you allocate memory in C++ using malloc(), you have to use free() to free it; if you are using new you need to use delete - mixing the two can lead to very interesting results that are not amusing to debug. With new, you'll also have to ensure that you match the correct invocation type. Anything created using new needs to be cleaned up with delete and anything created with array new as in my example above needs to be deleted using delete[].

Timo Geusch
Don't forget to use `delete []`, not just `delete`!
Fred Larson
A `void *` is correctly converted to any object pointer type without a cast - in fact one should *not* cast the return value of `malloc` in C. I would write the above as `myList = malloc(sizeof *myList);`
Alok
@Fred Larson - thanks for the reminder, just updated the answer
Timo Geusch
@Alok, thanks for pointing this out, my C is a little rusty. Fixed examples accordingly.
Timo Geusch
+1  A: 

Malloc scares the hell out of me

Being wary of hand managed dynamic memory is a good idea---there are lots of chances to make mistakes doing that; hard to debug mistakes---but no need to be frightened.

What malloc does is asks the OS for a piece of memory at least THIS big. That's all. You have to use pointers to keep track of it because the compiler doesn't know what memory the OS will choose for you, and so can't connect a variable name to the place at compile time.

What free does is tell the OS, I'm done with THIS memory and won't be using it again. That's all

C++'s new and delete also call initialization and finalization routines in the form of the the appropriate constructor or destructor. I won't say "that's all" about that because there are some details in that business.

So, to use dynamic allocation successfully you should

  • Ask for the memory you need before you try to use it, and check that you actually got some (the OS could say "No, you can't have it." you know)
  • Insure that you initialize it (either write the right constructor in c++ or manage it yourself in c)
  • Don't lose track of it.
  • Insure that you manage any needed cleanup before giving it back (destructors in c++, by hand in c). This is probably the hardest part of the whole business.
  • Never use memory after you've given it back
dmckee
A: 
#include <stdlib.h>

struct
{
int x;
int y;
} Coordinate;

Coordinate* myList = 0;

int myListLength = 0;  // initialize myListLength to size of myList

void AddSomething ( int x, int y )
{
    int i;
    // malloc returns a void pointer, so we cast it to be a Coordinate *
    Coordinate* newList = (Coordinate*)malloc(sizeof(Coordinate)*(myListLength+1));
    for(i=0; i < myListLength; ++i) {
        newList[i] = myList[i];
    }
    newList[myListLength].x = x;
    newList[myListLength].y = y;
    if(myList)
        free(myList);
    myList = newList;
    ++myListLength;
 }

Note that it's a much better idea to use std::vector if you can.

Chris