C(++) malloc confusion
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
malloc
s 开发者_如何学编程return value)
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.
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[]
.
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.
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
- 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.
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.
#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.
精彩评论