Professional Documents
Culture Documents
Pointers To Pointers & Multi-Dimensional Arrays
Pointers To Pointers & Multi-Dimensional Arrays
dimensional arrays
Dynamic Allocation - Recap
• malloc( ),calloc( ) and free( ) library
functions
2
Library Functions for Dynamic Memory Allocation
Both malloc and calloc return NULL if there is insufficient memory on the heap.
Library Function free()
void free(void *ptr);
free() frees the block of memory that was allocated with malloc( ) or
calloc( ).
Question :
The following code is legal. Is it a smart code ?…
int *ptr = (int*)malloc(8 * sizeof(int));
ptr++;
Pointers to pointers
int i=3;
int j=4;
i: 3 j: 4 k: 5
int k=5;
7
Pointers to pointers
int i=3;
int j=4;
i: 3 j: 4 k: 5
int k=5;
8
Pointers to pointers
int i=3;
int j=4;
i: 3 j: 4 k: 5
int k=5;
11
Pointers to pointers: example
// copy a string using "allocString"
void main()
{
char *s = "example";
char *copy;
allocString( strlen(s), © );
strcpy( copy, s);
free (copy);
}
12
Array of pointers
13
Example: grades.c
1 /* grades.c
2 This program calculates the average grade of a class. The
3 programmer doesn’t know the number of students in the class, so
4 he can’t declare an array.
5 Dynamic allocation is used instead */
6
7 #include <stdio.h>
8 #include <stdlib.h> /* for the prototypes of malloc, free and
9 exit */
10 #define EXIT_FAIL 42
11
12 void main(void)
13 {
14 float *grades = NULL; /* the grades are of type float */
15 int num_students; /* will be entered by the user */
16 float sum = 0; /* will help calculating the average. */
17 int ctr;
Example: grades.c – cont’d
18 do
19 { /* loop until a legal number of students is entered */
20 printf("How many students are there in class?=> ");
21 scanf("%d", &num_students);
22 } while(num_students <= 0);
23 /* now we know the number of students, so we can dynamically
24 allocate an array for holding their grades (floats) */
25 grades = (float*)malloc(num_students * sizeof(float));
26 /* if there isn’t enough consecutive memory,malloc() returns
27 NULL */
28 if(! grades)
29 {
30 puts("There is not enough memory. Sorry.\n");
31 exit (EXIT_FAIL); /* exit the program */
32 }
Example: grades.c – cont’d
34 for (ctr = 0; ctr < num_students ; ++ctr) /* get the
35 grades */
36 {
37 printf("Enter grade #%d: ", ctr + 1);
38 scanf("%f", &grades[ctr]);
39 sum += grades[ctr]; /* for calculating the average
40 later */
41 }
42
43 printf("The average of the grades is : %f\n",
44 sum/num_students);
45 /* memory that was allocated by malloc/calloc must be freed!*/
46 free(grades); /* free the allocated memory */
47 }
Array of Pointers
The problem:
We have to read, for example, a list of 10 names.
The names differ in length.
The maximum length is, in our case, 23.
First Solution:
char arr[10][23];
A list of names is an array of strings. since a string is an
array of char, we have an array of arrays of char - a two-
dimensional array of char. Look at the waste of memory !
S n o w w h i t e \0
L i t t l e r e d r i d i n g h o o d \0
C i n d e r e l l a \0
Array of Pointers
Second Solution:
char *arr[10];
0 . S n o w w h i t e \0
1 L i t t l e r e d r i d i n g h o o d \0
.
2 C i n d e r e l l a \0
.
Example: names1.c
1 /*names1.c Creates an array of strings, each of an unknown length*/
2 #include <stdio.h>
3 #include <stdlib.h> /* prototypes of malloc(), free(), exit() */
4 #include <string.h>
5 #define EXIT_FAIL 42
6 void free_names(char * names[], int num); /* prototype */
7
8 int get_names(char *names[], int num)
9 {
10 int i = 0;
11 char str[128];
12 do {
13 puts("Enter a name (press CTRL/Z ENTER to stop) "
14 " => ");
15 if (gets(str) == NULL)
16 break;
17
Example: names1.c – cont’d
18 if( (names[i] = (char*) malloc(strlen(str)+1))
19 == NULL)
20 {
21 puts ("Not enough memory. Sorry.\n");
22 free_names(names, i); /* some memory has
23 been allocated ! */
24 exit(EXIT_FAIL);
25 }
26 strcpy(names[i], str); /* copy the name into the
27 memory */
28 }while (++i < num);
29 return i;/* return the actual number of names in the array */
30 }
31
32 void print_names(const char *names[], int num)
33 {
34 int i;
35 for (i = 0 ; i < num ; i++)
36 printf("%2d) %s\n", i + 1, names[i]);
37 }
Example: names1.c – cont’d
37 void free_names(char * names[], int num)
38 {
39 int i;
40 for( i = 0 ; i < num ; ++i )
41 free(names[i]);
42 }
43
44 void main(void)
45 {
46 char *names[10]; /* an array of 10 pointers to char */
47 int final_num;/*in case the user enters less than 10 names*/
48 final_num = get_names(names, 10);/* get names into the
49 array */
50 print_names(names, final_num);/*print the array of names*/
51 free_names(names, final_num);/* free all the allocated
52 memory */
53 }
Dynamic Allocation
The previous program allocated memory for the names according to their lengths.
No memory was wasted in the case of short names, and no memory was missing
in the case of long names.
BUT it is good only as long as the user doesn’t have more than 10 friends’ names
to keep. If the user has 11 friends, he must give up one name. How can he choose
who to insult ?…
The next program will not only allocate memory for the names according to their
lengths, but it will also allocate the array itself according to the number of names
that the user wants to keep !
names
char** char* char char char char
char* char char
char*
char char char char char char
Example: bad-alloc.c
1 /* bad_alloc.c
2 This program does not work well and is dangerous. Why ? */
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 void get_memory(char *arr, int length)
7 {
8 if((arr=(char*)malloc(length * sizeof(char))) == NULL)
9 {
10 puts("Not enough memory. Sorry.\n");
11 exit(-1);
12 }
13 }
14 void main(void)
15 {
16 char *str = NULL;
17 get_memory(str, 128);
18 strcpy(str,"Program illegally runs over memory !\n");
19 puts(str);
20 free(str);
21 }
Example: good-alloc.c
1 /* good_alloc.c This is the fixed version of bad_alloc.c */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 void get_memory(char **arr, int length)
6 {
7 if( (*arr = (char*)malloc(length * sizeof(char))) ==
8 NULL)
9 {
10 puts("Not enough memory. Sorry.\n");
11 exit(-1);
12 }
13 }
14 void main(void)
15 {
16 char *str = NULL;
17 get_memory(&str, 128);
18 strcpy(str, "This program works fine !\n");
19 puts(str);
20 free(str);
21 }
Multi-dimensional arrays
31
Multi-dimensional arrays
Can be created in few ways:
1. Automatically:
int m[2][3]; // 2 rows, 3 columns
continuous memory (divided to 2 blocks)
access: m[row][col] = 0;
32
Automatic multi-dimensional arrays
#define R 2
#define C 3
int m[R][C];
int* m_ptr;
for (m_ptr= &(m[0][0]);
m_ptr<=&(m[R-1][C-1]);
++m_ptr) {
printf(“%d\n”, *m_ptr );
34 }
Automatic multi-dimensional arrays
int A[R][C];
A[0][0] A[0][1] … A[0][c-1]
… … … …
Like a matrix à A[i][0] A[i][1] … A[i][c-1]
… … … …
A[R-1][0] A[R-1][1] … A[R-1][C-1]
Row-major ordering à
A[0] A[i] A[R-1]
A A A A A A
[0] • • • [0] • • • [i] • • • [i] • • •[R-1] • • • [R-1]
[0] [C-1] [0] [C-1] [0] [C-1]
A A+i*C*4 A+(R-1)*C*4
36
Dynamic multi-dimensional arrays
3. Dynamically:
int ** m;
m = (int**) malloc( 5*sizeof(int*) );
for (i=0; i<5; ++i)
{
m[i] = (int*)malloc( 7*sizeof(int) );
}
m
37
Semi/Dynamic multi-dimensional arrays
38
Dynamic arrays – more efficient way
int* A= (int*) malloc(R*C*sizeof(int));
1-D array R=3 C=2 à
0,0 0,1 0,2 1,0 1,1 1,2
39
much better, inline functions)
Pointers to pointers to …
We also have pointers to pointers to pointers,
etc.:
40
Automatic multi-dimensional arrays as
arguments to functions
int x[5][7]; // 5 rows, 7 columns
41
Why ?
42
Pointers to arrays (of size X):
int foo (char m[][20]);
43
Pointers to arrays (of size X):
Explicit declaration:
char (*arr_2d)[20];
// arr_2d is a pointer
// not initialized
Using typedef:
typdef char arr_2d_20[20];
arr_2d_20 *p_arr_2d;
But:
typdef char arr_2d[][]; // comp. error
44
Pointers to arrays (of size X):
45
Pointers to arrays (of size X):
m After initialization:
char arr[5];
m= &arr;
arr
46
Pointers to arrays (of size X):
47
Multi-dimensional arrays as arguments
to functions
48
Multi-dimensional arrays as arguments
to functions
void foo( int matrix[ROWS_NUM][COLS_NUM] ) {
49
Multi-dimensional arrays as arguments
to functions
void foo( int matrix[ROWS_NUM][COLS_NUM] ) {
50
Multi-dimensional arrays as arguments
to functions
void foo( int (*matrix)[COLS_NUM] ) {
pointer to an array of
COLS_NUM ints!
51
Multi-dimensional arrays as arguments
to functions
void foo( int (*matrix)[COLS_NUM] ) {
...
... matrix[r][c]
52
Multi-dimensional arrays as arguments
to functions
void foo( int (*matrix)[COLS_NUM] ) {
...
... matrix[r][c]
... (*(matrix+r))[c]
53
Multi-dimensional arrays as arguments
to functions
void foo( int (*matrix)[COLS_NUM] ) {
...
... matrix[r][c]
... (*(matrix+r))[c]
...
... matrix[r][c]
... (*(matrix+r))[c]
... *((*(matrix+r)) + c)
55
Multi-dimensional arrays as arguments
to functions
void foo( int (*matrix)[COLS_NUM] ) {
...
... matrix[r][c]
... (*(matrix+r))[c]
... *((*(matrix+r)) + c) == *(matrix+r*COLS_NUM+c)
56
Example of dynamic multidimensional
array: argv, argc
57
argv, argc
! To pass command line arguments to our program we
should use the following main declaration:
main(int argc, char* argv[]) { ...
ü char** argv
r char argv[][]
argc == 5
argv[0] == “prog1”
argv[1] == “-u”
...
argv[4] == “1234”
60
Array reallocation – wrong solution
61
Array reallocation
Allocate array on the heap and assign a pointer to it
arr
1 2 3
62
Array reallocation
Use temporary pointer to point to the old array.
arr temp
1 2 3
63
Array reallocation
Use temporary pointer to point to the old array.
Reallocate new array.
arr temp
1 2 3
? ? ? ? ?
64
Array reallocation
Use temporary pointer to point to the old array.
Reallocate new array.
Copy values from the old array to the new one.
arr temp
1 2 3
1 2 3 ? ?
65
Array reallocation
Use temporary pointer to point to the old array.
Reallocate new array.
Copy values from the old array to the new one.
Free the old array.
arr temp
1 2 3
1 2 3 ? ?
66
Array reallocation – version 1
void reallocateMemory(int **parr,
size_t oldSize, size_t newSize) {
assert(newSize>oldSize);
}
67
Array reallocation – version 1
int main() {
free(arr)
68
Array reallocation – version 2
int* reallocateMemory(int *arr,
size_t oldSize, size_t newSize) {
assert(newSize>oldSize);
...
arr = reallocateMemory(arr,arrSize,newSize);
free(arr);
70
Array reallocation – using realloc
int * arr = (int*)malloc(sizeof(int)*oldSize);
arr = (int*)realloc(arr,sizeof(int)*newSize);
71