04B Right Left Rule 2D Arrays
04B Right Left Rule 2D Arrays
2D arrays
3
The Right-Left rule
int x; // an int
int (*x)[5]; // ?
int *x[5]; // ?
int *const x[5]; // ??
const int *x[5]; // ??
int *(*x[5])[10][13]; // ???
4
The Right-Left rule
int (*x)[5]
https://cdecl.org/
6
The Right-Left rule
int x; // an int
8
Types of 2D-arrays
9
Similarities & Differences
I. Fixed size (”static”) Similarities
double arr[M][N]; // M x N
Uniform access to elements
II. Semi-dynamic regardless of 2D-array type:
double *arr[M]; // M x n
double (*arr)[N]; // m x N
arr[i][j]
III. Fully-dynamic
double **arr; // m x n Differences
Storage:
• continuous vs. fragmented
• stack vs. heap
Access efficiency:
• single vs. multiple operations
Variable type:
• pointer/array/both
10
I. Fixed-size (“static”) arrays:
int arr[M][N]
• Continuous memory
sizeof(arr) = M * N * sizeof(*arr)
I. Fixed-size arrays: int arr[4][8]
STACK
arr[1][0]
int A[M][N];
A[i][j] = 5; // equivalent to *(*(A+i)+j) = 5, or in other
row
words, go to memory address [&A[0] + (i*N + j) * sizeof(int)]
(in bytes) and write 5 into it
12
II-a. Semi-dynamic arrays: int *arr[M]
An array of M pointers to int
STACK arr[0][0]
HEAP
0X557
arr
0X557 arr[1][0]
0X28f
0X28f
0X462
0X462
0X71c
0X71c
14
II-a. Semi-dynamic arrays: int *arr[M]
An array of M pointers to int
• Flexibility
size of each row might be different
• Complexity
row sizes must be traced correctly
• Less efficiency
Two memory operations to access an entry
• ~Practicality
Number of rows must be known at compile time
Don’t forget to free
One free() per m/calloc()
int *arr[M] = {0};
for (int i = 0; i < M; i++)
{
arr[i] = malloc (n * sizeof (int));
if (!arr[i]) { <… handle it …> }
}
…
for (int i = 0; i < 4; i++)
{
free (arr[i]);
}
16
Do not return M x n arrays!
We cannot pass ownership of a static array!
17
II-b. Semi-dynamic arrays: int (*arr)[N]
A pointer to an array of N ints
• Flexibility
size of each column might be different
• Complexity
column sizes must be traced correctly
• Less efficiency (vs. fixed-size array)
Two memory operations to access an entry
• ~Practicality
Number of columns must be known at compile time
III. A fully-dynamic array: int **arr
How do we allocate an m x n fully-dynamic array?
int **arr;
STACK
arr
.
.
.
.
.
.
20
III. A fully-dynamic array: int **arr
How do we allocate an m x n fully-dynamic array?
int **arr;
arr = malloc (m * sizeof(int*)); // eg, m=4
)
STACK
0X32f
HEAP
0X32f
.
.
.
.
.
.
21
III. A fully-dynamic array: int **arr
How do we allocate an m x n fully-dynamic array?
int **arr;
arr = malloc (m * sizeof(int*)); // m x sizeof(int*)
if (!arr) {… handle error …}
for (i = 0; i < m; i++)
{
arr[i] = malloc (n * sizeof (int)); // e.g. n=8
if (!arr[i]) {… handle error …}
}
STACK
0X32f
HEAP
0X557
.
. 0X28f
.
. 0X462
.
. 0X71c
22
III. A fully-dynamic array: int **arr
STACK HEAP
arr[0][0]
arr 0X32f 0X557
0X32f
0X557
arr[1][0]
. 0X28f
. 0X28f
.
0X462
.
0X462
.
.
. 0X71c
0X71c
23
III. A fully-dynamic array: int **arr
25
III. fully-dynamic arrays: int **arr;
int** arr;
arr = malloc(m*sizeof(*arr)); // m=4
if (!arr == NULL) {… handle error …}
for (i = 0; i < m; i++)
{
arr[i] = calloc(n, sizeof(**arr)); // n=8
if (!arr[i]) {… handle error …}
}
STACK
0X32f
HEAP
0X32f
0X557
0 0 0 0 0 0 0 0
.
0 0 0 0 0 0 0 0
. 0X28f
.
. 0X462 0 0 0 0 0 0 0 0
.
. 0X71c 0 0 0 0 0 0 0 0
26
Free!
• Don’t forget to free all the memory –
one free call per m/calloc call
27
Revisiting argc/argv –
a special 2D-array
30
Passing arguments to a program with argc and argv – an array of arrays
argc
• stands for “argument count”
• contains the number of arguments passed
to the program
argv
• stands for “argument vector”
• array of strings
myprog 1 2 3 >
33
Reminder – a 1D-array argument is always
converted to a pointer
34
The first dimension in a 2D-array
argument is always converted to a pointer
Just use the right-left rule:
• If an argument is an array of <something>, it is converted to a pointer to
<something>.
• For example, int a[4][N] is an array of N-sized arrays
it is passed as a pointer to N-sized arrays
37
A 2D array
memory leak example
38
Example: a 3 x 2 fully-dynamic 2D-array
void create_memory_leak () {
int i, j;
int **m = malloc (sizeof (int*) * 3);
for (i = 0; i < 3; i++) {
m[i] = malloc (sizeof (int) * 2);
for (j = 0; j < 2; j++)
{
m[i][j] = i + j;
}
}
}
In the following example we will assume
sizeof (int) == sizeof (void*) == 4
39
Another memory leak example
stack heap int i, j;
int **m = malloc
999
20 24 28 32 36 (sizeof (int*)*3);
i 0 for (i = 0; i < 3; i++)
995 {
40 44 48 52 56
j 0 x x
m[i] = malloc
(sizeof (int)*2);
991
60 64 68 72 76 for (j = 0; j < 2; j++)
m x x x x x {
m[i][j] = i + j;
987
80 84 88 92 96 }
x }
983
40
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2] int **m = malloc
999
20 24 28 32 36 (sizeof (int*)*3);
i 0 for (i = 0; i < 3; i++)
995 {
40 44 48 52 56
j 0 x x
m[i] = malloc
(sizeof (int)*2);
991
60 64 68 72 76 for (j = 0; j < 2; j++)
m 20 x x x x x {
m[i][j] = i + j;
987
80 84 88 92 96 }
x }
983
41
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2] int **m = malloc
999
20 24 28 32 36 (sizeof (int*)*3);
i 0 32 for (i = 0; i < 3; i++)
995 {
40 44 48 52 56
j 0 x x
m[i] = malloc
(sizeof (int)*2);
991
60 64 68 72 76 for (j = 0; j < 2; j++)
m 20 x x x x x {
m[i][j] = i + j;
987
80 84 88 92 96 }
x }
983
42
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2]
999
20 24 28 32 36
int **m = (int**)
i 0 32 0 malloc(sizeof(int*)*3);
995
40 44 48 52 56 for (i=0; i<3; i++) {
j 0 x x
m[i] = (int*)
991
60 64 68 72 76 malloc(sizeof(int)*2);
m 20 x x x x x
for (j=0; j<2; j++) {
987
80 84 88 92 96
x m[i][j] = i + j;
983 }
}
43
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2]
999
20 24 28 32 36
int **m = (int**)
i 0 32 0 1 malloc(sizeof(int*)*3);
995
40 44 48 52 56 for (i=0; i<3; i++) {
j 1 x x
m[i] = (int*)
991
60 64 68 72 76 malloc(sizeof(int)*2);
m 20 x x x x x
for (j=0; j<2; j++) {
987
80 84 88 92 96
x m[i][j] = i + j;
983 }
}
44
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2]
999
20 24 28 32 36
int **m = (int**)
i 1 32 48 0 1 malloc(sizeof(int*)*3);
995
40 44 48 52 56 for (i=0; i<3; i++) {
j 1 x x
m[i] = (int*)
991
60 64 68 72 76 malloc(sizeof(int)*2);
m 20 x x x x x
for (j=0; j<2; j++) {
987
80 84 88 92 96
x m[i][j] = i + j;
983 }
}
45
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2]
999
20 24 28 32 36
int **m = (int**)
i 1 32 48 0 1 malloc(sizeof(int*)*3);
995
40 44 48 52 56 for (i=0; i<3; i++) {
j 0 x 1 x
m[i] = (int*)
991
60 64 68 72 76 malloc(sizeof(int)*2);
m 20 x x x x x
for (j=0; j<2; j++) {
987
80 84 88 92 96
x m[i][j] = i + j;
983 }
}
46
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2]
999
20 24 28 32 36
int **m = (int**)
i 1 32 48 0 1 malloc(sizeof(int*)*3);
995
40 44 48 52 56 for (i=0; i<3; i++) {
j 1 x 1 2 x
m[i] = (int*)
991
60 64 68 72 76 malloc(sizeof(int)*2);
m 20 x x x x x
for (j=0; j<2; j++) {
987
80 84 88 92 96
x m[i][j] = i + j;
983 }
}
47
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2] int **m = malloc
999
20 24 28 32 36 (sizeof (int*)*3);
i 2 32 48 84 0 1 for (i = 0; i < 3; i++)
995 {
40 44 48 52 56
j 1 x 1 2 x
m[i] = malloc
(sizeof(int)*2);
991
60 64 68 72 76 for (j = 0; j < 2; j++)
m 20 x x x x x {
m[i][j] = i + j;
987
80 84 88 92 96 }
x }
983
48
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2] int **m = malloc
999
20 24 28 32 36 (sizeof (int*)*3);
i 2 32 48 84 0 1 for (i = 0; i < 3; i++)
995 {
40 44 48 52 56
j 0 x 1 2 x
m[i] = malloc
(sizeof(int)*2);
991
60 64 68 72 76 for (j = 0; j < 2; j++)
m 20 x x x x x {
m[i][j] = i + j;
987
80 84 88 92 96 }
x 2 }
983
49
Another memory leak example
stack heap int i, j;
m[0] m[1] m[2] int **m = malloc
999
20 24 28 32 36 (sizeof (int*)*3);
i 2 32 48 84 0 1 for (i = 0; i < 3; i++)
995 {
40 44 48 52 56
j 1 x 1 2 x
m[i] = malloc
(sizeof(int)*2);
991
60 64 68 72 76 for (j = 0; j < 2; j++)
m 20 x x x x x {
m[i][j] = i + j;
987
80 84 88 92 96 }
x 2 3 }
983
50
Function ends with memory leak
stack heap int i, j;
m[0] m[1] m[2] int **m = malloc
999
20 24 28 32 36 (sizeof (int*)*3);
32 48 84 0 1 for (i = 0; i < 3; i++)
995 {
40 44 48 52 56
m[i] = malloc
x 1 2 x (sizeof(int)*2);
991
60 64 68 72 76 for (j = 0; j < 2; j++)
x x x x x {
m[i][j] = i + j;
987
80 84 88 92 96 }
x 2 3 }
983
51
Trying to fix using free (attempt 1)
stack heap …
m[0] m[1] m[2]
999
20 24 28 32 36
free(m);
i 2 32 48 84 0 1 m = NULL;
995
40 44 48 52 56
j 1 x 1 2 x
991
60 64 68 72 76
m 20 x x x x x
987
80 84 88 92 96
x 2 3
983
52
Trying to fix using free (attempt 1)
stack heap …
999
20 24 28 32 36
free(m);
i 2 0 1 m = NULL;
995
40 44 48 52 56
j 1 x 1 2 x
991
60 64 68 72 76
m x x x x x
987
80 84 88 92 96
x 2 3
983
53
Function still ends with memory leak
stack heap …
999
20 24 28 32 36
free(m);
i 0 1 m = NULL;
995
40 44 48 52 56
j x 1 2 x
991
60 64 68 72 76
m x x x x x
987
80 84 88 92 96
x 2 3
983
54
Correct: freeing all allocated memory
stack heap …
999
20 24 28 32 36
for (i=0; i<3; i++)
i 2 32 48 84 0 1 {
free(m[i]);
995
40 44 48 52 56 m = NULL;
j 1 x 1 2 x }
free(m);
991
60 64 68 72 76 M = NULL;
m 20 x x x x x
987
80 84 88 92 96
x 2 3
983
55
Freeing all allocated memory
stack heap …
999
20 24 28 32 36
for (i=0; i<3; i++)
i 0 0 48 84 {
free(m[i]);
995
40 44 48 52 56 m = NULL;
j 1 x 1 2 x }
free(m);
991
60 64 68 72 76 m = NULL;
m 20 x x x x x
987
80 84 88 92 96
x 2 3
983
56
Freeing all allocated memory
stack heap …
999
20 24 28 32 36
for (i=0; i<3; i++)
i 1 0 0 84 {
free(m[i]);
995
40 44 48 52 56 m = NULL
j 1 x x }
free(m);
991
60 64 68 72 76 m = NULL;
m 20 x x x x x
987
80 84 88 92 96
x 2 3
983
57
Freeing all allocated memory
stack heap …
999
20 24 28 32 36
for (i=0; i<3; i++)
i 2 0 0 0 {
free(m[i]);
995
40 44 48 52 56 m = NULL
j 1 x x }
free(m);
991
60 64 68 72 76 m = NULL;
m 20 x x x x x
987
80 84 88 92 96
x
983
58
Freeing all allocated memory
stack heap …
999
20 24 28 32 36
for (i=0; i<3; i++)
i 2 {
free(m[i]);
995
40 44 48 52 56 m = NULL;
j 1 x x }
free(m);
991
60 64 68 72 76 M = NULL;
m 20 x x x x x
987
80 84 88 92 96
x
983
59
function ends with no memory leak
stack heap …
999
20 24 28 32 36
for (i=0; i<3; i++)
i {
free(m[i]);
995
40 44 48 52 56 m = NULL;
j x x }
free(m);
991
60 64 68 72 76 M = NULL;
m x x x x x …
return …;
987
80 84 88 92 96
x
983
60