malloc
:
Reserves bytes of memory; returns the address or NULL
.
calloc
:
Reserves space for an array; returns the address or NULL
.
realloc
:
Re-sizes previously allocated memory;
returns the address or NULL
.
free
:
Releases memory previously reserved.
#include <stdlib.h>
void *malloc(size_t size)
NULL
malloc(12)
:
returns a pointer to 12 bytes of memory.
malloc(sizeof(int) * 100)
:
returns a pointer to memory that has enough space for
100 int
s, no matter how big an int
is.
size_t
is a typedef for an unsigned numeric type, often
unsigned long int
. It’s used as an argument to functions
like malloc
, when a number of bytes is required.
strlen
and sizeof
return a size_t
.
size_t
with %zu
, thus:
char god[] = "Thor of Asgard"; printf("%d\n", sizeof(god)); // not quite right printf("%ld\n", sizeof(god)); // not quite right printf("%zd\n", sizeof(god)); // not quite right printf("%zu\n", sizeof(god)); // correct
c.c: In function 'main': c.c:2: warning: format '%d' expects argument of type 'int', but argument 2 has type 'long unsigned int' 15 15 15 15
sizeof(int) == 4
(assume this, for the moment)
int i, a[10], *p;
sizeof(i) == 4
sizeof(a) == 40
sizeof(p) == 4
(assume, also, that pointers are 4 bytes)
sizeof
can be used with user-defined types as well.
void free(void *p)
p
to pool of available memory
p
must come from a previous call to malloc
or
realloc
or calloc
(can’t free from the stack)
If you forget to free p
,
eventually,
you run out of memory!
Do you C?
void *calloc(size_t how_many, size_t size_of_each);
how_many
× size_of_each
bytes.
int *p = calloc(10, sizeof(int)); for (int i=0; i<10; i++) printf(" %d", p[i]);
0 0 0 0 0 0 0 0 0 0
void *realloc(void *p, size_t size)
int *p = malloc(100*sizeof(int)); … p = realloc(p, 200*sizeof(int));
int *grades; int numgrades = 15; grades = malloc(numgrades * sizeof(int)); int size = 10; char *base = calloc(size, sizeof(char)); free(base); free(grades);
Dynamically create an array of grades, asking the user how many, then prompting the user for each grade.
int numgrades; int *grades; // ptr to array of grades printf("How many students? "); scanf("%d", &numgrades); // get memory for the entire array grades = malloc(numgrades * sizeof(int)); if (grades == NULL) { // snafu? printf("Failed to allocate grades array\n"); return 1; } for (int i=0; i<numgrades; i++) { printf("Enter a grade: "); scanf("%d", &grades[i]); } for (int i=0; i<numgrades; i++) printf("Value %d: %d\n", i, grades[i]); free(grades);
malloc
returns a void *
, so how
can we assign that to an int *
?
void *
is special.
void *
magically transforms to any other pointer type, as needed.
% c11 -o dym2 dynMem2.c % ./dym2 Array size: 4 a, b, c, d
Dynamically create a repeating array of the alphabet.
int size; printf("Array size: "); scanf("%d", &size); char *base = calloc(size, sizeof(char)); // calloc: handy for arrays /* Should check for failure here */ for (int i=0;i<size;i++) base[i] = 'a' + i%26; for (int i=0;i<size;i++) { if (i != 0) printf(", "); printf("%c", base[i]); } printf("\n"); free(base);
The dreaded Memory Leak
Memory is divided into two parts: the stack & the heap.
A stack is a common structure used in computers and in programming. The basics are the same, but here we are talking about memory management as opposed to programming it in our code.
Until now, we’ve mostly used the stack:
free
function allows us to give memory
back to the heap.
free
takes a pointer (which you got from a
previous call to malloc
/calloc
/realloc
)
and returns nothing.
malloc
does not initialize the memory it gives
you. Its contents are undefined. If you want
it initialized, that’s your job (or use calloc
).
malloc
is determined by the machine
and operating system.
malloc
without eventually calling free
.
valgrind
can be used to find problems with
dynamic memory usage.
valgrind
detects the use of uninitialized memory, read/write outside
allocated memory, and memory leaks (unfreed memory).
char str[8] = "spam\n" char *ptr;
┌───┐ ┌────┬────┬────┬────┬────┬────┬────┬────┐ ptr:│ ? │ str:│ s │ p │ a │ m │ \n │ \0 │ ?? │ ?? │ └───┘ └────┴────┴────┴────┴────┴────┴────┴────┘
char str[8] = "spam\n"; char *ptr; ptr = malloc(sizeof(char)*(strlen(str)+1));
┌───┐ ┌────┬────┬────┬────┬────┬────┬────┬────┐ ptr:│ │ str:│ s │ p │ a │ m │ \n │ \0 │ ?? │ ?? │ └─┼─┘ └────┴────┴────┴────┴────┴────┴────┴────┘ │ ∨ ┌────┬────┬────┬────┬────┬────┐ │ ?? │ ?? │ ?? │ ?? │ ?? │ ?? │ └────┴────┴────┴────┴────┴────┘
char str[8] = "spam\n"; char *ptr; ptr = malloc(sizeof(char)*(strlen(str)+1)); strcpy(ptr, str);
┌───┐ ┌────┬────┬────┬────┬────┬────┬────┬────┐ ptr:│ │ str:│ s │ p │ a │ m │ \n │ \0 │ ?? │ ?? │ └─┼─┘ └────┴────┴────┴────┴────┴────┴────┴────┘ │ ∨ ┌────┬────┬────┬────┬────┬────┐ │ s │ p │ a │ m │ \n │ \0 │ └────┴────┴────┴────┴────┴────┘
char str[8] = "spam\n"; char *ptr; ptr = malloc(sizeof(char)*(strlen(str)+1)); strcpy(ptr, str); free(ptr); // Assume that we’re done with it
┌───┐ ┌────┬────┬────┬────┬────┬────┬────┬────┐ ptr:│ │ str:│ s │ p │ a │ m │ \n │ \0 │ ?? │ ?? │ └─┼─┘ └────┴────┴────┴────┴────┴────┴────┴────┘ │ ∨ ┌────┬────┬────┬────┬────┬────┐ │ ?? │ ?? │ ?? │ ?? │ ?? │ ?? │ └────┴────┴────┴────┴────┴────┘
strdup
(non-standard, but available everywhere)
does exactly what we just did on the previous slides.
malloc
exactly enough space for a
string, and copy it into the new memory for
you. It’s still your job to free it.
char foo[] = "Hello"; char *bar = strdup(foo); bar[0] = 'J'; printf("%s %s\n", foo, bar); // Displays Hello Jello free(bar);
dst: destination
src: source
len: length
memcpy
(dst, src, len)
memmove
(dst, src, len)
memset
(dst,val,len)
memset(ptr,0,sizeof(int) * 100);