In C++, you had keywords like
new
and delete (as well as their [] variants) to help you create dynamic arrays or just allocate a bit of data on-the-spot.
These had the benefit of also calling class constructors/destructors, and they can be operator overloaded (if you really needed that...).
Well, in C, you don't have these keywords.
You don't need them either since there's no such thing as a class.
Instead, C uses
malloc and
free, which are functions to allocate bytes of memory.
Here's the man page entry for malloc.
It includes the entire "family" of functions.
Man page for "malloc"
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
void *reallocarray(void *ptr, size_t nmemb, size_t size);
To aid in showing how these functions work, let's start with something familiar.
Here's some C++ code that you're probably familiar with:
File (new_delete.cpp)
#include <iostream>
#include <string>
using namespace std;
int main() {
int* a = new int[10];
int i;
for (i = 0; i < 10; i++)
a[i] = i;
//Print out the values in the array
for (i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
//Free memory
delete[] a;
}
And it prints out the following:
Output
0 1 2 3 4 5 6 7 8 9
Now let's look at it in C.
File (malloc_free.c)
#include <stdio.h>
#include <stdlib.h>
int main() {
int* a = (int *) malloc(sizeof(int) * 10);
int i;
for (i = 0; i < 10; i++)
a[i] = i;
//Print out the values in the array
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
//Free memory
free(a);
}
Structurally, it looks the same.
Other than the output statements being changed to
printf
, though, what else has changed?
The lines where
new
and
delete
were called were changed to
malloc(...)
and
free(...)
respectively.
Confused? Let's break it down.
Breaking down malloc
malloc
is very easy to mess up.
The man page gives the following definition:
Man Page for "malloc"
void *malloc(size_t size);
So it takes an integer
size
which is the
number of bytes we want to allocate in memory.
It will return a
void *
pointer to that allocated memory.
This pointer should be casted to the target type afterwards (hence the
(int *)
cast in the code above).
Simple enough.
So if we want an array of 10 ints, we will call the following:
int* a = (int *) malloc(sizeof(int) * 10);
sizeof
is typically used to get the size of a data type
in bytes. Assume
int
is 4 bytes. Thus,
sizeof(int) = 4
. Since we want 10 of these integers (40 bytes) we have to perform the multiplication above.
Lastly,
malloc
(like new
) can fail.
You can check this by checking the pointer returned.
If it's
NULL
, it failed.
Breaking down free
The man page gives the following definition:
Man Page for "free"
void free(void *ptr);
It just takes a pointer.
Pass in the pointer that was returned by
malloc
earlier and your memory is freed.
It really is that simple.
In the code above, it's called in the following fashion:
File (malloc_free.c)
int* a = (int *) malloc(sizeof(int) * 10);
/* do stuff */
free(a);
"Why should I care about free
? Computers these days have gigabytes of RAM!"
And yet they can still be brought to their knees.
In C++, the heavy-lifting memory management is handled for you by data structures like
vector
,
map
, etc.
In C though, you will be handling it all yourself.
All it takes is allocation of strings, and duplicating them a few million times in an infinite loop or something and you're out of memory.
All the higher RAM means is that it'll just take a tad bit more effort to run out of memory.
It doesn't mean you
won't run out of memory.
Plus, assuming your CS360 TA isn't lazy, usually they are instructed to use a tool like
valgrind
to check if your program leaks memory or not.
I know my TA was instructed to do that. And they deducted points if they saw a memory leak.