Lecture 22 Malloc and Free
Joseph Haugh
University of New Mexico
Review Quiz Question 1
void main(void) {
int x = 2, y = 3;
int *px;
px = &x;
printf("%d\n", *px + y);
}
The output is:
- 0
- 2
- 5
- 7
- 92
Review Quiz Question 1
void main(void) {
int x = 2, y = 3;
int *px;
px = &x;
printf("%d\n", *px + y);
}
Review Quiz Question 2
void main(void) {
int a[] = {22, 33, 44};
int *x = a;
printf("sizeof(int)=%lu ", sizeof(int));
printf("x=%p, x[0]=%d\n", x, x[0]);
x = x + 2;
printf("x=%p, x[0]=%d\n", x, x[0]);
}
sizeof(int) = 4 x = 0x7fff29af6530, x[0] = 22 is the output from lines 4 and 5.
Output from line 7 is:
- x=0x7fff29af6532, x[0]=23
- x=0x7fff29af6532, x[0]=33
- x=0x7fff29af6534, x[0]=33
- x=0x7fff29af6538, x[0]=44
Review Quiz Question 2
void main(void) {
int a[] = {22, 33, 44};
int *x = a;
printf("sizeof(int)=%lu ", sizeof(int));
printf("x=%p, x[0]=%d\n", x, x[0]);
x = x + 2;
printf("x=%p, x[0]=%d\n", x, x[0]);
}
sizeof(int) = 4 x = 0x7fff29af6530, x[0] = 22 is the output from lines 4 and 5.
Output from line 7 is:
- x=0x7fff29af6538, x[0]=44
Review Quiz Question 3
void main(int argc, char *argv[]) {
if (argc == 2) {
int n = 0;
char *c_pt = argv[1];
while (*c_pt) {
if (*c_pt < '0' || *c_pt > '1') break;
n = n*2 + *c_pt-'0';
c_pt++;
}
printf("%d\n", n);
}
}
./a.out 0011023
- 00110
- 110
- 6
- 3
- 010
Review Quiz Question 3
void main(int argc, char *argv[]) {
if (argc == 2) {
int n = 0;
char *c_pt = argv[1];
while (*c_pt) {
if (*c_pt < '0' || *c_pt > '1') break;
n = n*2 + *c_pt-'0';
c_pt++;
}
printf("%d\n", n);
}
}
Review Quiz Question 4
char *findSubstring(char *str, char *needle) {
int len = strlen(needle);
int n = 0;
while (*str) {
printf("%c%c ",*str, *needle);
if ( *(needle+n) == *str) {
n++;
if (n == len) return (str-len)+1;
}
else {
str -= n;
n = 0;
}
str++;
}
return NULL;
}
What is the output of: findSubstring(“ABCDE”,“CD”)?
- AC BC CC DD
- AC BC CC DC
- AC BC CC DC EC
- AC BC CC DC ED
- AC BC CC
Review Quiz Question 4
char *findSubstring(char *str, char *needle) {
int len = strlen(needle);
int n = 0;
while (*str) {
printf("%c%c ",*str, *needle);
if ( *(needle+n) == *str) {
n++;
if (n == len) return (str-len)+1;
}
else {
str -= n;
n = 0;
}
str++;
}
return NULL;
}
What is the output of: findSubstring(“ABCDE”,“CD”)?
- AC BC CC DC
Review Quiz Question 5
char *findSubstring(char *str, char *needle) {
int len = strlen(needle);
int n = 0;
while (*str) {
printf("%c%c ",*str, *(needle+n));
if ( *(needle+n) == *str) {
n++;
if (n == len) return (str-len)+1;
}
else {
str -= n;
n = 0;
}
str++;
}
return NULL;
}
What is the output of: findSubstring(“ABCDEF”,“CDE”)?
- AC CC DC CC DC CC DC EC
- AC CC DC CC DC CC DD EE
- AC CC DD CE DE CE DE EE
- AC CC DD CE DC CC DD EC
- AC BC CC DD EE
Review Quiz Question 5
char *findSubstring(char *str, char *needle) {
int len = strlen(needle);
int n = 0;
while (*str) {
printf("%c%c ",*str, *(needle+n));
if ( *(needle+n) == *str) {
n++;
if (n == len) return (str-len)+1;
}
else {
str -= n;
n = 0;
}
str++;
}
return NULL;
}
What is the output of: findSubstring(“ABCDEF”,“CDE”)?
- AC BC CC DD EE
Review Quiz Question 6
void main(void) {
long a[] = {7, 13, 17};
long *x = a;
printf("sizeof(long)=%lu ", sizeof(long));
printf("x=%p, x[0]=%ld\n", x, x[0]);
x = x + 2;
printf("x=%p, x[0]=%ld\n", x, x[0]);
}
sizeof(long)=8 x=0x7fff04794670, x[0]=7, is the output from lines 4 and 5.
Output from line 7 is:
- x=0x7fff04794680, x[0]=17
- x=0x7fff04794678, x[0]=17
- x=0x7fff04794672, x[0]=13
- x=0x7fff04794678, x[0]=7
- x=0x7fff04794672, x[0]=7
Review Quiz Question 6
void main(void) {
long a[] = {7, 13, 17};
long *x = a;
printf("sizeof(long)=%lu ", sizeof(long));
printf("x=%p, x[0]=%ld\n", x, x[0]);
x = x + 2;
printf("x=%p, x[0]=%ld\n", x, x[0]);
}
sizeof(long)=8 x=0x7fff04794670, x[0]=7, is the output from lines 4 and 5.
Output from line 7 is:
- x=0x7fff04794680, x[0]=17
<stdlib.h>: malloc()
void *malloc(size_t byteSize)
- The malloc function allocates unused space for an object whose size in bytes is specified by byteSize.
- The order and contiguity of storage allocated by successive calls to malloc is unspecified.
- The return value is a void pointer (not void). A void pointer is aligned so that it may be assigned to a pointer of any object type.
- For example, on some machines int x can only start on addresses where x % 4 == 0.
- The pointer returned points to the start (lowest byte address) of the allocated space.
- If the requested space cannot be allocated, a NULL pointer is returned.
<stdlib.h>: calloc()
void *calloc(size_t numObj, size_t objSize)
- Allocates a continuous block of memory large enough to hold numObj items each of objSize byes.
- Also initializes all elements to zero.
- Compare with malloc
int n = 50;
int *a = malloc(n * sizeof(int));
int *b = calloc(n, sizeof(int));
<stdlib.h>: free()
void free (void *ptr)
- The free function deallocates the a block of memory previously allocated using a call to malloc, calloc, or realloc.
- After being deallocated, the memory is available for further allocations.
- Always call free when done with every pointer returned by malloc.
- Never use a pointer after it has been freed.
- Never call free with any value other than one returned by malloc.
Dynamic Array Allocation: main()
#include
#include
#include
#define END_CODE INT_MIN
int main(void) {
int *num = atoiArray("42 427 3 1234 88");
int i = 0;
while (num[i] != END_CODE) {
printf("num[%d]=%d\n", i, num[i]);
i++;
}
free(num);
return 0;
}
int *num only allocates memory for a pointer to an int.
atoiArray must allocate memory for the actual array.
Dynamic Array Allocation: atoiArray()
int* atoiArray(char *line)
Given: line is "42 427 3 1234 88"
- Find n, the number of numbers are in line.
- Allocate memory for an array of int of size n+1 (add one for the terminating symbol).
- Convert the characters in the string to numbers in the array.
- Add the terminating symbol.
- Return a pointer to the allocated int array.
Dynamic Array Allocation: atoiArray()
int *atoiArray(char *line) {
/* Find out how many numbers in line */
int n = 1;
char *charPt = line;
while (*charPt) {
if (*charPt == ' ') n++;
charPt++;
}
printf("%d numbers in string.\n", n);
/* Allocate memory of for array of int */
int *num = malloc(sizeof(int) * (n+1));
Dynamic Array Allocation: atoiArray()
/* Convert string to numbers in the array */
int *intPt = num;
*intPt = 0;
charPt = line; /* reset to line start */
int startedNewNumber = 0;
while (*charPt) {
if (*charPt == ' ') {
printf("Done with: %d\n", *intPt);
intPt++;
*intPt = 0;
startedNewNumber = 0;
}
else {
*intPt = *intPt * 10 + (*charPt - '0');
startedNewNumber = 1;
}
charPt++;
}
Dynamic Array Allocation: atoiArray()
/* Add terminating symbol */
if (startedNewNumber) intPt++;
*intPt = END_CODE;
/* Return a pointer the allocated int array */
return num;
}
Valgrind
Valgrind is an open source programming tool for detection of memory leaks, invalid memory usage, and profiling.
The name valgrind comes from the main entrance to Valhalla in Norse mythology.
valgrind a.out, runs a.out in a virtual machine.
Valgrind Example
#include
void f() {
int* x = malloc(10 * sizeof(int));
x[10] = 0;
}
int main(void) {
f();
return 0;
}
Valgrind Output
...
==17092== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==17092== at 0x4845784: malloc (in ...)
==17092== by 0x401157: f (valgrind-example.c:4)
==17092== by 0x401175: main (valgrind-example.c:9)
...
==17092== Invalid write of size 4
==17092== at 0x401164: f (valgrind-example.c:5)
==17092== by 0x401175: main (valgrind-example.c:9)
...
Dynamically Sized, 2D Array with malloc
#include
#include
void print2DArray(int **array, int rows, int cols) {
/* Body on separate slide */
}
void set2DArray(int **array, int rows, int cols) {
/* Body on separate slide */
}
void main(void) {
/* Body on separate slide */
}
Dynamically Sized, 2D Array: main()
void main(void) {
int columns = 3;
int rows = 4;
int **array;
array = malloc(columns * sizeof(*array));
int col;
for (col = 0; col < columns; col++) {
array[col] = malloc(rows * sizeof(int));
}
set2DArray(array, columns, rows);
print2DArray(array, columns, rows);
}
What do you notice is a bit strange about the order we are doing things?
Each sub-array represents a column instead of a row.
Dynamically Sized, 2D Array: set2DArray()
void set2DArray(int **array, int cols, int rows) {
int r, c;
int data = 0;
for (c = 0; c < cols; c++) {
for (r = 0; r < rows; r++) {
array[c][r] = data;
data++;
}
}
}
Incrementing data so each cell gets a different value in this example.
Dynamically Sized, 2D Array: print2DArray()
void print2DArray(int **array, int cols, int rows) {
int r, c;
for (r = 0; r < rows; r++) {
printf("r=%d [", r);
for (c = 0; c < cols; c++) {
printf("%3d ", array[c][r]);
}
printf("]\n");
}
}
Let’s Run It!
gcc two-d-alloc.c
./a.out
r=0 [ 0 4 8 ]
r=1 [ 1 5 9 ]
r=2 [ 2 6 10 ]
r=3 [ 3 7 11 ]
Awesome! Did I forget something?
I forgot to free() the memory I allocated!
Let’s see what valgrind says about it…
Valgrind Output
...
==19009== 48 bytes in 3 blocks are indirectly lost in loss record 1 of 2
==19009== at 0x4845784: malloc (in ...)
==19009== by 0x4012C6: main (two-d-alloc.c:34)
==19009==
==19009== 72 (24 direct, 48 indirect) bytes in 1 blocks are definitely
lost in loss record 2 of 2
==19009== at 0x4845784: malloc (in ...)
==19009== by 0x401292: main (two-d-alloc.c:30)
...
So how do we fix it?
Main Fixed
void main(void) {
int columns = 3;
int rows = 4;
int **array;
array = malloc(columns * sizeof(*array));
int col;
for (col = 0; col < columns; col++) {
array[col] = malloc(rows * sizeof(int));
}
set2DArray(array, columns, rows);
print2DArray(array, columns, rows);
free(array);
}
Does this fix it?
Not quite since we didn’t free the memory for each column.
Main Fixed
void main(void) {
int columns = 3;
int rows = 4;
int **array;
array = malloc(columns * sizeof(*array));
int col;
for (col = 0; col < columns; col++) {
array[col] = malloc(rows * sizeof(int));
}
set2DArray(array, columns, rows);
print2DArray(array, columns, rows);
for (col = 0; col < columns; col++) {
free(array[col]);
}
free(array);
}
Done!