What's the equivalent of new/delete of C++ in C?
Asked Answered
E

6

40

What's the equivalent of new/delete of C++ in C?

Or it's the same in C/C++?

Epanaphora answered 15/5, 2010 at 9:6 Comment(0)
P
65

There's no new/delete expression in C.

The closest equivalent are the malloc and free functions, if you ignore the constructors/destructors and type safety.

#include <stdlib.h>

int* p = malloc(sizeof(*p));   // int* p = new int;
...
free(p);                       // delete p;

int* a = malloc(12*sizeof(*a));  // int* a = new int[12];
...
free(a);                         // delete[] a;
Postmortem answered 15/5, 2010 at 9:7 Comment(7)
@KennyTM: Does sizeof(*p) actually dereference p, or is it fully equivalent to writing sizeof(int)? It seems that in the former case, this expression would potentially cause a segmentation fault (because p is not yet assigned at this point). In the latter case, I would probably still prefer writing sizeof(int) because there's less potential for misunderstanding what this statement does.Ezarras
@stakx: The sizeof operator is evaluated at compile time. There's no dereferencing. sizeof(*p) is preferred to sizeof(int) because if you change the type of p to double the compiler cannot warn you of size mismatch.Postmortem
@stakx The sizeof operator is a mapping from type to size_t. The value of its operand is not interesting at all. For example, in sizeof(1 + 2), there is absolutely no need to compute the result 3. The sizeof operator simply sees an expression of type int + int and infers that the result is also an int. Then it maps int to 4 (or 2 or 8, depending on the platform). It's the same thing with sizeof(*p). The type system knows that, on the type level, dereferencing an int* yields an int. sizeof is not interested in the value of *p at all, only the type matters.Rugg
@stakx For exactly the same reason, sizeof(1/0) does NOT crash horribly with an arithmetic exception, but instead yields sizeof(int), because 1 is of type int, 0 is of type int, and the division of two ints also yields an int on the type level. The division is never executed, neither at compile time nor at runtime!Rugg
Thanks to both of you for replying. I thought I'd ask because I haven't seen this usage of sizeof before. Good thing to know, though!Ezarras
@KennyTM Nice answer. Would like to ask: why is the following considered a more proper way when using sizeof: malloc(sizeof (*p)); note the single space between sizeof and (*p)? Thanks.Feeney
@Unheilig: sizeof (*p) and sizeof(*p) are just equivalent. You could also omit the parenthesis for expressions sizeof *p.Postmortem
R
11

Note that constructors might throw exceptions in C++. The equivalent of player* p = new player(); would be something like this in C.

struct player *p = malloc(sizeof *p);
if (!p) handle_out_of_memory();
int err = construct_player(p);
if (err)
{
    free(p);
    handle_constructor_error();
}

The equivalent of delete p is simpler, because destructors should never "throw".

destruct(p);
free(p);
Rugg answered 15/5, 2010 at 9:41 Comment(1)
What would construct_player look like?Maxinemaxiskirt
M
8

Use of new and delete in C++ combines two responsibility - allocating/releasing dynamic memory, and initialising/releasing an object.

As all the other answers say, the most common way to allocate and release dynamic memory is calling malloc and free. You also can use OS-specific functions to get a large chunk of memory and allocate your objects in that, but that is rarer - only if you have fairly specific requirements that malloc does not satisfy.

In C, most APIs will provide a pair of functions which fulfil the other roles of new and delete.

For example, the file api uses a pair of open and close functions:

// C++
fstream* fp = new fstream("c:\\test.txt", "r");
delete fp;

// C
FILE *fp=fopen("c:\\test.txt", "r"); 
fclose(fp);

It may be that fopen uses malloc to allocate the storage for the FILE struct, or it may statically allocate a table for the maximum number of file pointers on process start. The point is, the API doesn't require the client to use malloc and free.

Other APIs provide functions which just perform the initialisation and releasing part of the contract - equivalent to the constructor and destructor, which allows the client code to use either automatic , static or dynamic storage. One example is the pthreads API:

pthread_t thread;

pthread_create( &thread, NULL, thread_function, (void*) param); 

This allows the client more flexibility, but increases the coupling between the library and the client - the client needs to know the size of the pthread_t type, whereas if the library handles both allocation and initialisation the client does not need to know the size of the type, so the implementation can vary without changing the client at all. Neither introduces as much coupling between the client and the implementation as C++ does. (It's often better to think of C++ as a template metaprogramming language with vtables than an OO language)

Meshed answered 15/5, 2010 at 10:47 Comment(2)
Can you explain exactly what specific requirements malloc does not satisfy?Colleague
@Colleague malloc allocates memory. operator new (usually) allocates memory and initialises the memory to contain values supplied by the constructor of the class of object specified. ( there is a variable of operator new called 'placement new' which does not allocate memory, so you can use malloc for the first part, and new for the second if you so wish)Meshed
B
3

Not directly an exact replica but compatible equivalents are malloc and free.

<data-type>* variable = (<data-type> *) malloc(memory-size);
free(variable);

No constructors/destructors - C anyway doesn't have them :)

To get the memory-size, you can use sizeof operator.

If you want to work with multidimensional arrays, you will need to use it multiple times (like new):

int** ptr_to_ptr = (int **) malloc(12 * sizeof(int *)); //assuming an array with length 12.
ptr[0] = (int *) malloc(10 * sizeof(int));   //1st element is an array of 10 items
ptr[1] = (int *) malloc(5 * sizeof(int));    //2nd element an array of 5 elements etc
Bullard answered 15/5, 2010 at 9:13 Comment(5)
In C you don't need to cast from void* to other pointers. Its just int* p = malloc( sizeof(int) * cElements);Fraud
Chris: Are you sure? I haven't worked with C for quite some time now, but IIRC, I had to do it because the return type of malloc is void *.Bullard
In c void* automatically converts to other pointer types. Casting the return of malloc can cause errors if you haven't included stdlib.h, as the parameters will have been assumed to be int.Isobath
Explicitly casting from void* to other pointer types is necessary in C++ but not in C.Coaly
@Scott, @Jamesdlin: Thanks. It seems I've become rusty in C ;)Bullard
D
1

Use malloc / free functions.

Dufrene answered 15/5, 2010 at 9:20 Comment(0)
D
1

Late, but I really like this syntax, although I'm not sure if it fits ways of C

#include <stdlib.h>

#define new(type, length) malloc(sizeof(type)*(length))
#define delete(x) free(x)
int main()
{
    int *test = new(int, 30);
    delete(test);
}
Drye answered 29/11, 2019 at 10:41 Comment(3)
Not sure if I like it... At least you should enclose length in brackets.Sard
I'm not really sure how to achieve it with macros so I've done what I couldDrye
You should always put brackets around macro parameters. See my edit. You might think about the result of new(int,4+5) without the brackets around lengthSard

© 2022 - 2024 — McMap. All rights reserved.