Complex data structures Cedric Saule cedric.saule@uni-bielefeld.de
Arrays in language C In language C, arrays are contiguous spaces in memory. We make the difference between two kinds of arrays : Static arrays : their size is defined during the compilation. Dynamic arrays : their size will be known during the execution. 2
Arrays in memory C Contiguous memory space of exactly same type +1 +1 adress 1 adress 2 adress 3 Size of Type Size of Type Size of Type adress2 adress1 = ((unsigned long) adress1 (unsigned long) adress2) / sizeof(type) adress1 + n = (Type *) ((unsigned long) adress1 + n * sizeof(type)) To acces to the next case in memory : *(adress1 + n) == adress1[n] Like for functions, the array's name identifies the adress of the first cell. 3
Static arrays declaration Declaration of a static array type name[number of elements]; Number of elements as to be known during compilation. Numbers : 1, 5, 10, 100, 12569 Constant : global integers : #define size 10 Constant types are not considered in ANSI. 4
Static arrays declaration Because of the previous considerations, these expressions are equivalent : int t[10]; *t and t[0] (Because the basic pointer is the first cell, the first index is 0.) t and &t[0] *(t + i) and t[i] I neglect here the pointer size conversion, but be careful! 5
Operations on pointers Arrays are contiguous cells in memory, so increasing a pointer by one is pointing the next cell. But : int t[5] ; /* t is a constant pointer. */ int* p; /* p is a variable pointer. */ p = t; p++; /* This operation is legal. */ t = p; t++; /* This operation is illegal because t is a constant */ 6
Operations on pointers C char t[] = ''Hello''; char *p = ''Hello''; 0 1 2 3 4 5 H e l l o \0 char t[] = ''Hello''; ''t'' is a true array. 125 126 127 0 1 2 3 4 5 0 t h \0 H e l l o \0 W char *p = ''Hello''; ''p'' contains the adress of the string beginning among other constants in memory. 7
Static arrays in multidimensions int t[4][3] = { { 1, 2, 3, { 4, 5, 6, { 7, 8, 9, { 10, 11, 12 ; In memory : 1 2 3 4 5 6 7 8 9 10 11 12 According to the previous definition, we have : t[i][j] = *(int*)(t[i] + j) = *(int*)(*(t + i) + j) = *(int*)(*(t + ( i * 3 + j)); Number of cells in the second dimension t [0][0] [0][1] [0][2] [1][0] [1][1] [1][2] [2][0] [2][1] [2][2] [3][0] [3][1] [3][2] 8
Static arrays in multidimensions Another way : int t[4][3], *u[4]; u is a 4 cells array of integers pointers. [0] [1] [2] [3] u Of course, u[2][1] is a valid expression! Initialisation : int i = 0; for(i = 0; i < 4; i++) { u[i] = t[i]; Value : u[i][j] = *(int*)(*( u + i ) + j ) t [0][0] [0][1] [0][2] [1][0] [1][1] [1][2] [2][0] [2][1] [2][2] [3][0] [3][1] [3][2] 9
Static arrays in multidimensions initialisation : int t[4][3] = { { 1, 2, 3, { 4, 5, 6, { 7, 8, 9, { 10, 11, 12 ; 1 2 3 4 5 6 7 8 9 10 11 12 int t[4][3] = { { 1, 2, 3, { 4, 5, 6, { 7, 8, 9 ; 1 2 3 4 5 6 7 8 9 0 0 0 int t[4][3] = { { 1, 2, { 4, 5, { 7, 8, { 10, 11 ; 1 2 0 4 5 0 7 8 0 10 11 0 int t[4][3] = { { 1, 2, 3, 4, 5, 6, 7, 8 ; 1 2 3 4 5 6 7 8 0 0 0 0 10
Dynamic arrays In dynamic arrays, the number of cells is known during the execution. It is impossible to use the basic declaration of arrays since the number of cells and is ignored and so, the memory occupancy. But arrays are also pointers, so we can use this definition! 11
Dynamic arrays We reserve memory and store the adress in a pointer. For multidimension, we do the same! But the memory will contain adresses int size1 = 4, size2 = 3, i = 0; float** t; t = malloc(size1 * sizeof(float*)); for( i = 0; i < size1; i++ ) { t[i] = malloc(size2 * sizeof(float)); for(i = 0; i < size1; i++) { free(t); free(t[i]); Free the memory of the array of float* Reservation of size1 cells of memory with the size of a float*. Reservation of size2 cells of memory with the size of a float. Each pointer of size1 cells points to the adress of a pointer of size2 cells. Free the memory of each array of float 12
Dynamic arrays Arrays creation Declaration of float** t 13
Dynamic arrays Arrays creation t Memory allocation of size1 cells of size float* 14
Dynamic arrays Arrays creation t float float float t[0] Memory allocation of size2 cells of float. Allocation to the cell0 of the previous array. 15
Dynamic arrays Arrays creation t float float float float float float float float float t[0] t[1] t[2] float float float t[3] We repeat the operation for each cell of the array of float*. 16
Dynamic arrays Arrays destruction t The memory of each array of size2 cells is freed. Be careful, the pointers point now on nothing! 17
Dynamic arrays Arrays destruction t The size1 memory spaces are freed. t points on nothing. 18
Dynamic arrays Arrays creation t float float float If we free t before each of the size1 array of float. We loose acces to their adress. float float float float float float Anonymous reserved memory float float float 19
Dynamic arrays We can define non homogenous arrays. t float float float t[0] float float float float float float float float float t[1] t[2] float float float t[3] We have just to keep in memory the number of cells for each. 20
Arrays and functions To use an array as a parameter, the pointer on the first adress is enough. Better is float sumarray(float* myarray, int nb1 ) { int i; float sum = 0; for(i = 0; i < nb1; i++) { sum += myarray[i]; return sum; float sumarray(const float* myarray, int nb1 ) { int i; float sum = 0; for(i = 0; i < nb1; i++) { sum += myarray[i]; return sum; We cannot modify the arrays by ''mistake'' 21
Arrays and functions We can also write : float sumarray(const float myarray[], int nb1 ) { int i; float sum = 0; for(i = 0; i < nb1; i++) { sum += myarray[i]; return sum; Or, equivalently : float sumarray(const float myarray[15], int nb1 ) { int i; float sum = 0; for(i = 0; i < nb1; i++) { sum += myarray[i]; return sum; The compiler does not check the bounds! 22
Arrays and functions In two dimensions (or more...) : float sumarray(const float myarray[][nb2], int nb1 ) { int i, j; float sum = 0; for(i = 0; i < nb1; i++) { for(j = 0; j < nb2; j++) { sum += myarray[i][j]; return sum; Or : t Because we have to knoe the dimensions sizes after the first one. Remember : t[i][j] = *(float*)(*(t + ( i * 3 + j)) [0][0] [0][1] [0][2] [1][0] [1][1] [1][2] [2][0] [2][1] [2][2] [3][0] [3][1] [3][2] float sumarray(const * myarray, int nb1, int nb2 ) { int i, j; float sum = 0; for(i = 0; i < nb1; i++) { for(j = 0; j < nb2; j++) { sum += *(float*)(*(myarray + i * nb2 + j)); return sum; 23
Convenient functions calloc : initialise the value to ''0'' or ''NULL'' : int* myarray = calloc(nb, sizeof(int)); realloc : resize dynamically the memory space. myarray = realloc(myarray, (nb+1) * sizeof(int)); These two functions returns NULL in case of mistake. We have to be careful (temporary variables, test of right allocation...) 24
Another way to enumerate We want to use ''strings'' as identifyers. Exemples : Days of the week. Months Each name is associated with an integer : enum day {monday, tuesday, wednesday, thursday, friday, satursday, sunday; Monday is equal to 0, tuesday to 1... enum somemonth {january = 1, february, march, april, september = 9, october, november; 10 11 25
Quick preview How to make a copy of an array in fonction? How to create new data types? What about trees? Graphs? Lists? Stacks? We can define structures which contain several types and recursive definitions. 26