Deel I: Programmeertaal C 6. Arrays en Pointers Prof.Dr.Ir. Filip De Turck
Overzicht 1. Arrays (rijen) in 1 dimensie 2. Pointers (wijzers) 3. Call by reference 4. Dynamisch geheugenbeheer 5. Strings 6. Multidimensionele arrays 7. Functie-argumenten 8. Structs revisited Single Dimension Arrays, Two- and Multiple-Dimension Arrays, Strings, Arrays of Strings An array is a collection of variables of the same type which are referenced by a common name. A specific element in an array is referenced by an index. The most common array in C is the string, which is simply an array of characters terminated by a null. In C, arrays and pointers are closely related; a discussion of one usually refers to the other. C has no bounds checking on arrays. Vakgroep Informatietechnologie
1. Arrays: basisconcepten Array = reeks van variabelen van ZELFDE type (een array/rij is homogeen) Declaratie type naam[constante_gehele_uitdrukking]; #define MAANDEN 12 … double neerslag[MAANDEN]; double neerslag[12]; long postnummer[100]; Gebruik naam[gehele_uitdrukking]; Single Dimension Arrays The general form for declaring a single-dimension array is: type var_name[size]; In C, all arrays have zero as the index of their first element. Therefore a declaration of char p[10]; declares a ten-element array (p[0] through p[9]). kan overal gebruikt worden waar gewone variabele van zelfde type toegelaten is 0 index < constante_gehele_uitdrukking [ ] is een C-operator ! (zie boek Appendix E) Vakgroep Informatietechnologie
1. Arrays: basisconcepten (2) Initialisatie type naam[constante_gehele_uitdrukkingopt] = { constante_uitdrukking {, constante_uitdrukking}0+ }; elementen 4 … 11 geïnitialiseerd op 0 double neerslag[12] = {20.7,23.0,99.0,77.4}; geen automatische initialisatie ! indien bereik niet opgegeven -> compiler vult zelf aantal elementen in int a[4]={1,2,3,4}; ≈ int a[ ] = {1,2,3,4}; karakter - rijen char a[ ] = “Een tekst”; char a[ ] = {‘E’,’e’,’n’,’ ‘,’t’,’e’,’k’,’s’,’t’,’\0’}; Array Initialization Arrays may be initialized at the time of declaration. The following example initializes a ten-element integer array: int i[10] = { 1,2,3,4,5,6,7,8,9,10 }; Character arrays which hold strings allow a shorthand initialization, e.g.: char str[9] = "I like C"; which is the same as: char str[9] = { 'I',' ','l','i','k','e',' ','C','\0' }; When the string constant method is used, the compiler automatically supplies the null terminator. Vakgroep Informatietechnologie
1. Arrays: C-idioom voor toegang & behandeling Processing van rijen #define N 100 … int a[N]; int i; for(i=0;i<N;i++) /* bewerk element a[i] */ In this example space is allocated for the array elements: a[0], a[1], …, a[99]. a[100] does not exists. As such the loop condition needs to test on < N. Vakgroep Informatietechnologie
1. Arrays: functie-argumenten Formele parameter type naam[ ] Prototype parameter type [ ] Voorbeeld /* berekensom.c */ #include <stdio.h> int bereken_som(int[ ],int); int main(void) { int a[ ]={1,2,3,4,5}; printf("Som = %d\n",bereken_som(a,5)); return 0; } int bereken_som(int a[ ],int n) { int som=0; int i; for(i=0;i<n;i++) som+=a[i]; return som; Vakgroep Informatietechnologie
Overzicht 1. Arrays (rijen) in 1 dimensie 2. Pointers (wijzers) 3. Call by reference 4. Dynamisch geheugenbeheer 5. Strings 6. Multidimensionele arrays 7. Functie-argumenten 8. Structs revisited Vakgroep Informatietechnologie
2. Pointers: basisconcepten Een pointer (wijzer) is een variabele die een ADRES bevat Voorbeeld int a=7; int* p; p=&a; 7 1000 a p ???? 1000 Elk type heeft een geassocieerd wijzertype, namelijk type* Conversie-karakter (hexadecimale voorstelling): p printf(“Wijzer = %p”,p); Pointers, Pointer Operators, Pointer Expressions, Pointers and Arrays, Multiple Indirection, Pointer to Functions A pointer is a variable which holds a memory address, that address usually being the address of another variable. Pointers provide the means by which functions may modify their calling parameters. They also support C's dynamic allocation functions and improve the efficiency of certain routines. If a variable is going to hold a pointer, it must be declared as such. The general form of declaration is: type *name; where type is any valid C data type and name is the name of the pointer variable. The base type defines what type of variables the pointer can point to. All pointer arithmetic is done relative to the base type. Vakgroep Informatietechnologie
Dereferentie-operator: * 2. Pointers: operatoren Adresoperator: & Dereferentie-operator: * ENKEL op lvalue unaire operatoren precedentie identiek voor alle unaire operatoren associatie: R -> L : **&p *(*(&p)) Voorbeeld int a=7; int* p= NULL; int b; p=&a; a=9; *p=12; b = *p; 7 a 9 12 Pointer Operators 1) The & Operator The & operator is a unary operator (ie, an operator which requires only one operand) which returns the memory address of the operand. For example: m = &count; places the memory address of count into m. 2)The * Operator The * operator is the complement of & in that it returns the value of the variable at the address which follows. For example: q = *m; places the value of count into q. p 0xFF00 b ??? 12 Vakgroep Informatietechnologie
2. Pointers: operatoren (2) Relationele operatoren < <= > >= Interpretatie : vergelijken van numerieke adressen if(p < q) printf("p points to lower memory than q"); Pointer Comparisons Pointers may be compared in a relational expression, as in: if(p < q) printf("p points to lower memory than q"); Vakgroep Informatietechnologie
output ? 2. Pointers: voorbeeld /* wijzer.c */ #include <stdio.h> #define N 5 int main(void) { int a[N]={0}; int* p=0; int i; for(i=0;i<N;i++) { p=&a[i]; printf("wijzer naar a[%d] : 0x%p\n",i,p); *p=i; } for(i=0;i<N;i++) printf("a[%d]=%d\n",i,a[i]); return 0; output ? Pointer Demo 1. Array access . ====================== wijzer naar a[0] : 0x0012FF6C wijzer naar a[1] : 0x0012FF70 wijzer naar a[2] : 0x0012FF74 wijzer naar a[3] : 0x0012FF78 wijzer naar a[4] : 0x0012FF7C a[0]=0 a[1]=1 a[2]=2 a[3]=3 a[4]=4 Vakgroep Informatietechnologie
2. Pointers: bewerkingen dereferentie *pointer int a=7; int* p=&a; printf(“a= %d”,*p); void* kan niet gedefereerd worden ! adresbepaling &pointer int** q = &p; printf(“p= %p, a= %d”,*q,**q); Pointer Expressions Pointer Assignments As with any variable, a pointer may be used on the right side of an assignment operator to assign its value to another pointer. optelling en aftrekking “pointer arithmetic” Vakgroep Informatietechnologie
2. Pointers: bewerkingen (2) assignatie pointer = pointer_uitdrukking; p=&a; p=(int*)127888; CAVEAT “traditional C”: assignatie tussen verschillende wijzertypes mogelijk ANSI C: assignatie MOET tussen zelfde wijzertypes UITZONDERING: void* int *i; double *d; i=d; int *i; double *d; void* v; i=d; i=v=d; void* GENERIEK POINTERTYPE Vakgroep Informatietechnologie
2. Pointers: arithmetiek Rekenkundige bewerkingen op pointers + en - (en variaties) met gehele getallen ! int* p=(int*)1000; p++; p--; p+=2; p-=4; 1000+sizeof(int) 1000-sizeof(int) 1000+2*sizeof(int) 1000-4*sizeof(int) Pointer Arithmetic The only arithmetic operations which may be used on pointers are addition and subtraction. When, say, an int pointer is incremented (eg, p++;), the address held by the pointer will be incremented by four, not by 1, the reason being that integers are (normally) four bytes long. That is, pointers are incremented and decremented relative to the length of their base type. Arithmetic operations are not limited to the increment and decrement operators. Integers may be added to, or subtracted from, pointers, as in: p = p + 12; effect hangt af van lengte (sizeof) van het type ! Vakgroep Informatietechnologie
2. Pointers: arrays vs pointers int a[3]={1,2,3}; int *b=a; a 1 2 3 b a en b bevatten adres a is CONSTANT, b niet a++ b++ element i van de rij ? a[i] *(a+i) *(b+i) Pointers and Arrays C provides two methods for accessing array elements, namely, array indexing and pointer arithmetic. Pointer arithmetic can be faster than array indexing.In the following, p is set to point to the first element of str: char str[80], *p; p = str; Two ways to access the fifth element of str are as follows: str[4]; // Array indexing. *(p+4); // Pointer arithmetic. The following examples illustrate the two methods: void puts(char *s){ /* Index s as an Array */ register int t; for(t=0;s[t];t++) } putchar(s[t]); } void puts(char *s){ /* Access s as a Pointer */ while(*s) putchar(*s++); Most professional C programmers would find the second method easier to read and understand. Vakgroep Informatietechnologie
2. Pointers: arrays vs pointers voorbeeld /* verschil.c */ #include <stdio.h> int main(void) { float a[]={1.0,2.0,3.0,4.0,5.0}; float*start,*eind; int i=0; start=a; eind=&a[4]; for(i=0;i<5;i++) printf("a[%d]=%f\n",i,*(start+i)); printf("eind - start = %d\n",eind-start); printf("(int)eind-(int)start = %d\n",(int)eind-(int)start); return 0; } output ? Pointer Demo `3. arrays vs. pointers . ========================== a[0]=1.000000 a[1]=2.000000 a[2]=3.000000 a[3]=4.000000 a[4]=5.000000 eind - start = 4 (int)eind-(int)start = 16 Vakgroep Informatietechnologie
2. Pointers: pointers en arrays Gevraagd Is volgend programma OK ? #include <stdio.h> #define SIZE 10 int main(void) { int a[SIZE]; int *p; for(p=&a[0];p<&a[SIZE];) *++p=0; } Precedence: as with unary opertors Asociates from Right to left. *++p is equivalent to *(++p) Vakgroep Informatietechnologie
Oefening: array & pointer definities int a; int *a; int **a; int a[10]; int *a[10]; int (*a)[10]; int a; // An integer int *a; // A pointer to an integer int **a; // A pointer to a pointer to an integer int a[10]; // An array of integer int *a[10]; // An array of pointer to integers int (*a)[10]; // A pointer to an array of 10 integers Vakgroep Informatietechnologie
Overzicht 1. Arrays (rijen) in 1 dimensie 2. Pointers (wijzers) 3. Call by reference 4. Dynamisch geheugenbeheer 5. Strings 6. Multidimensionele arrays 7. Functie-argumenten 8. Structs revisited Vakgroep Informatietechnologie
3. Call by reference Algemene aanpak: Waarde doorgeven wijzigt waarde uit oproepende context NIET. Algemene aanpak: Geef de adressen van variabelen door De formele parameters zijn van wijzertype Gebruik dereferentie van parameters om waarde van variabelen uit oproepende context te wijzigen ... char a; opvolger(a); void opvolger(char a) { a++ ; } … char a; opvolger(&a); ... void opvolger(char* a) { (*a)++; } Call-by-Value The call-by-value method copies the value of an argument into the formal parameter of the function. Therefore, changes made by the function to the parameters have no effect on the variables used to call it. Call-by-Reference The call-by-reference method copies the address of an argument into the formal parameter. Inside the function, this address is used to access the argument used in the call. In this way, changes made to the parameter affect the variable used in the call to the function. Calls-by-reference are achieved by passing a pointer as the argument. Of course, in this case, the parameters must be declared as pointer types. Vakgroep Informatietechnologie
3. Call by reference: wisselen /* wisselnaief.c */ #include <stdio.h> void wissel(int,int); int main(void) { int a=1,b=2; printf("a=%d b=%d\n",a,b); wissel(a,b); return 0; } void wissel(int a,int b) { int t=a; a=b; b=t; output ? Vakgroep Informatietechnologie
3. Call by reference: wisselen (2) /* wisselints.c */ #include <stdio.h> void wissel(int*,int* ); int main(void) { int a=1,b=2; printf("a=%d b=%d\n",a,b); wissel(&a,&b); return 0; } void wissel(int *a,int *b) { int t=*a; *a=*b; *b=t; output ? The following demonstrates this: void swap(int *x, int *y); // function prototype void main(void) { int x,y; x = 10; y = 20; swap(&x,&y) // addresses passed } void swap(int *x, int *y) int temp; temp = *x; *x = *y; *y = temp; Vakgroep Informatietechnologie
ANSI C Sleutelwoorden Category Keyword Data Types char int float double void Data Type Modifiers long short signed unsigned Storage Class Specifiers auto extern register static Access Type Modifiers const volatile Vakgroep Informatietechnologie
const toegepast op variabele: verhindert wijziging ! const int i=7; initialisatie verplicht ! int main(void) { const int i=7; int* p=&i; *p=12; printf("i=%d\n",i); return 0; } Warning Access Type Modifiers The ANSI standard introduced two new type modifiers. These modifiers (const and volatile) control how variables may be accessed or modified. Usage is as follows: const Variables of type const may be given an initial value; however, that value cannot be changed by the program. Such a variable receives its value from explicit initialization or by some hardware-dependent means. Many functions in the C standard library use const in their parameter declaration. const pointers. As will be seen, functions can modify a variable pointed to by a pointer. However, if the pointer is specified as const in the formal parameter declaration, the function's code will not be able to modify what it points to. Vakgroep Informatietechnologie
const ERROR *p constant const int *p; int* const p; p constant int main(void) { const int i=7; const int* p=&i; *p=12; printf("i=%d\n",i); return 0; } ERROR const int *p; int* const p; *p constant p constant Vakgroep Informatietechnologie
const In functieprototype verhindert (onopzettelijke) wijziging van call-by-reference argumenten #include <stdlib.h> void opvolger(const char*); int main(void) { char a='a'; printf("a=%c\n",a); opvolger(&a); return 0; } void opvolger(const char*a) { (*a)++; “ERROR : const object” Vakgroep Informatietechnologie
Oefening: const data definities const int a; int const a; const int *a; int * const a; const int a; a is a constant integer int const a; const int *a; a is a pointer to a constant integer int * const a; a is a const pointer to an integer Vakgroep Informatietechnologie
volatile De variabele kan onverwacht van waarde veranderen. Voorbeelden Hardware registers: vb.: 8 bit status register op adres 0xFF00 char volatile * reg_ptr = (char volatile *) 0xFF00 ; while (*reg_ptr == 0);... Variabelen die vanuit een interrupt service routine gewijzigd worden Gedeelde variabelen in een multitasking applicatie volatile The value of variables of type volatile may be changed in ways not explicitly specified in the program (eg, a variable used to hold the real time of the system). The contents of the variable are altered without any explicit assignment statements. Such a variable should be declared volatile whenever its value could change unexpectedly. In practice, only three types of variables could change: Memory-mapped peripheral registers , global variables modified by an interrupt service routine or global variables within a multi-threaded application Peripheral registers Embedded systems contain real hardware, usually with sophisticated peripherals. These peripherals contain registers whose values may change asynchronously to the program flow. As a very simple example, consider an 8-bit status register at address 0x1234. It is required that you poll the status register until it becomes non-zero. int volatile * ptr = (int volatile *) 0x1234; The assembly language now looks like this: mov ptr, #0x1234 loop mov a, @ptr bz loop Vakgroep Informatietechnologie
Kan een parameter zowel const als volatile zijn ? Oefening: volatile Kan een parameter zowel const als volatile zijn ? Kan een pointer volatile zijn ? Wat is het probleem met volgende functie: int square (volatile int * ptr) { return *ptr * *ptr; } 1. Ja: een voorbeeld is een read-only status register. Het is volatile omdat het onverwacht kan veranderen maar het programma mag het statusregister niet wijzigen. 2. Ja: niet gebruikelijk maar komt soms voor: bijvoorbeeld een device driver wijzigt de waarde van een buffer pointer die aan de omgeving word teruggegeven. 3. Waarde van *ptr kan wijzigen a= *ptr; b= *ptr; return a*b; Correct: return a*a; Vakgroep Informatietechnologie
1D-rijen als functie-argument adres wordt meegegeven als argument in parameterlijst zijn rij- en pointernotatie equivalent verhinderen dat rij gewijzigd wordt -> gebruik const int grootste(int*,int); ... int grootste(int a[ ],int n) { int i=0; int m=*a++; for(i=1;i<n;i++) m=(*a++>m) ? *(a-1):m; return m; } int grootste(int*,int); ... int grootste(int* a,int n) { int i=0; int m=*a++; for(i=1;i<n;i++) m=(*a++>m) ? *(a-1):m; return m; } Calling Functions With Arrays Generally, the C convention is the call-by-value. An exception is where arrays are passed as arguments. In C, an entire array cannot be passed as an argument to a function. However, a pointer to an array may be passed by specifying the array's name without an index. If a function receives a single dimension array, the formal parameter may be declared as either a pointer, a sized array, or an unsized array. Examples are: function(int *x) // A pointer. function(int x[10]) // A sized array. function(int x[]) // An unsized array. Vakgroep Informatietechnologie
Overzicht 1. Arrays (rijen) in 1 dimensie 2. Pointers (wijzers) 3. Call by reference 4. Dynamisch geheugenbeheer 5. Strings 6. Multidimensionele arrays 7. Functie-argumenten 8. Structs revisited Vakgroep Informatietechnologie
4. Dynamisch geheugenbeheer : functies in stdlib.h Geheugen toewijzen tijdens uitvoering van programma Toewijzen malloc(aantal_bytes) calloc(aantal,aantal_bytes) Argumenten: type size_t (unsigned int) Resultaat: type void* (gebruik cast !) NULL indien mislukt ! Prototypes in stdlib.h malloc versus calloc ? calloc() initialiseert geheugen maak code systeemonafhankelijk ! C's Dynamic Allocation Functions Global variables are allocated storage at compile time and local variables use the stack. Neither can be added during program execution. Dynamic allocation is the means by which a program can obtain memory during execution. The core of the dynamic allocation system consists of the functions malloc() (allocates memory from the heap) and free() (frees that memory). malloc() returns a pointer to the first byte of the allocated memory. Pointers provide the necessary support for C's dynamic allocation system. The dynamic allocation system supports linked lists, binary trees and dynamically allocated arrays. malloc(n*N) calloc(n,N) malloc(n*sizeof(double)) Vakgroep Informatietechnologie
4. Dynamisch geheugenbeheer : functies in stdlib.h Vrijgeven free(toegewezen_pointer) fout indien argument al vrijgegeven argument geen toegewezen pointer geheugenlekken moeilijk op te sporen ! Hergebruik realloc(toegewezen_pointer,aantal_bytes) poogt geheugenblok te hergebruiken voor aantal_bytes inhoud begin van blok blijft behouden resultaat: cf. malloc/calloc Vakgroep Informatietechnologie
4. Dynamisch geheugenbeheer : fouten en problemen Dangling Pointer: Pointer nog gebruiken na een free() vb. meerdere pointers wijzen naar hetzelfde blok Memory Leak : geen pointers meer naar het geheugen maar ook geen free() Memory Fragmentatie: na veelvuldig alloceren en dealloceren kunnen bepaalde kleine stukjes geheugen niet meer gebruikt worden omdat ze te klein zijn Memory Leaks: A leak is always a bug in the application. More specifically, a leak is a block of memory that was allocated, but will never be freed. If all pointers to that block have gone out of scope or were assigned to point elsewhere, the application will never be able to free that piece of memory. A small leak may be acceptable in a desktop application that will exit at some point, since an exiting process returns all memory to the operating system. But in a long running dedicated or embedded system, it is often necessary to guarantee that absolutely no leaks exist-a non-trivial challenge. Fragmentation: The standard C library functions malloc() and free() allow blocks of arbitrary size to be allocated to an application for an arbitrary period of time. As blocks are used and freed, the area of storage dedicated to the heap becomes a jumble of used and free blocks mixed throughout that memory area. Any small patches of free space that remain might become unusable. For example, an application might request 30 bytes from the heap. If the heap has 20 small blocks of three bytes each-a total of 60 bytes-the heap still cannot satisfy the request, since the 30 bytes requested have to be contiguous. In a long-running program, fragmentation can cause a system to run out of memory even though the total amount of memory allocated does not exceed the total available. Geen probleem in Java: garbage collection Vakgroep Informatietechnologie
4. Dynamisch geheugenbeheer: wisselen (GENERIEK) /* wisselgeneriek */ #include <stdio.h> #include <stdlib.h> #include <string.h> void wissel(void*,void*,int); int main(void) { int a=1,b=2; double c=3.14,d=2.71828; printf("a=%d b=%d\n",a,b); wissel(&a,&b,sizeof(a)); printf("c=%f d=%f\n",c,d); wissel(&c,&d,sizeof(c)); return 0; } void wissel(void *a,void *b,int n){ void* temp= malloc(n); memcpy(temp,a,n); memcpy(a,b,n); memcpy(b,temp,n); free(temp); } Vakgroep Informatietechnologie
Overzicht 1. Arrays (rijen) in 1 dimensie 2. Pointers (wijzers) 3. Call by reference 4. Dynamisch geheugenbeheer 5. Strings 6. Multidimensionele arrays 7. Functie-argumenten 8. Structs revisited Vakgroep Informatietechnologie
printf(“t bevat = %s”,t); 5. Strings in C 1D-rij van char’s Start van de string = wijzeruitdrukking Eind van de string : karakter ‘\0’ (sentinel !) ASCII-conventie #define EOS ‘\0’ Geheugenruimte = (aantal_karakters+1)*sizeof(char) Constanten - tussen: “ “ - compiler voegt zelf ‘\0’ toe Conversiekarakter: s EOS char *t=“een tekst”; Strings A string is actually an array of characters. Because strings are terminated by a null ('\0'), character arrays must be declared with one extra element (to hold the null). Although C does not have a string data type, it allows string constants. For example, "hello there" is a string constant. printf(“t bevat = %s”,t); Vakgroep Informatietechnologie
5. Strings: string vs char[] char* s= “abc”; char a[ ] = {‘a’,’b’,’c’,’\0’}; a b c \0 #include <stdio.h> int main(void) { char a[ ]={'a','b','c','\0'}; char *s="abc"; printf("%c %c\n",a[0],s[0]); printf("%c %c\n",*(a+1),*(s+1)); /* a+=2; niet toegelaten !*/ s+=2; printf("%c %c\n",*(a+2),*s); return 0; } s a b c \0 Vakgroep Informatietechnologie
5. Strings: string functies Klassieke stringbewerkingen (prototypes in string.h) concatenatie char *strcat(char *s1, const char *s2); vergelijken int strcmp(const char *s1,const char *s2); kopiëren char *strcpy(char *s1,const char *s2); lengte bepalen size_t strlen(const char *s); /* exclusief EOS */ C supports a wide range of string manipulation functions, including: Function Description strcpy(s1,s2) Copies s2 into s1. strcat(s1,s2) Concatenates s2 to s1. strlen(s1) Returns the length of s1. strcmp(s1,s2) Returns 0 (false) if s1 and s2 are the same. Returns less than 0 if s1<s2 Returns greater than 0 if s1>s2 strchr(s1,ch) Returns pointer to first occurrence ch in s1. strstr(s1,s2) Returns pointer to first occurrence s2 in s1. Since strcmp() returns false if the strings are equal, it is best to use the ! operator to reverse the condition if the test is for equality. Deze functies alloceren GEEN geheugen !!! De gebruiker moet zorgen voor voldoende ruimte. Vakgroep Informatietechnologie
5. Strings: string functies Geformatteerde I/O van/naar string (prototypes in stdio.h) invoer int sscanf(const char* s, const char* ctrl, …); uitvoer int sprintf(char *s, const char* ctrl, …); allocatie van s niet binnen sscanf/sprintf !!! Vakgroep Informatietechnologie
5. Strings: vergelijken van strings /* compare.c */ #include <stdio.h> #include <string.h> int my_strcmp(const char*,const char*); int main(void) { printf("gelijk = %d\n",my_strcmp("abcd","abcd")); printf("niet gelijk = %d\n",my_strcmp("abcd","abcD")); return 0; } int my_strcmp(const char* s1,const char*s2) { int gelijk=1; if (strlen(s1)!=strlen(s2)) return 0; else while(*s1) if((*s1++)!=(*s2++)) return 0; return 1; Vakgroep Informatietechnologie
Overzicht 1. Arrays (rijen) in 1 dimensie 2. Pointers (wijzers) 3. Call by reference 4. Dynamisch geheugenbeheer 5. Strings 6. Multidimensionele arrays 7. Functie-argumenten 8. Structs revisited Vakgroep Informatietechnologie
6. Meerdimensionale rijen algemeen principe : meerdimensionele rij = rij van rijen elementen worden NA elkaar opgeslagen in geheugen 2D rijen 3D rijen declaratie type naam[P][Q]; type naam[P][Q][R]; initialisatie type naam[P][Q]={a00,…,a0Q-1,a10,…}; type naam[P][Q]={{a00,…a0Q-1},{a10…},…}; type naam[ ] [Q]={{a00,…a0Q-1},{a10…},…}; type naam[P][Q][R]={a000,…,a00R-1,a010,…}; type naam[P][Q][R]={{{a000,…a00R-1},{a010…}},…}; type naam[ ] [Q][R]={{{a000,…a00R-1},{a010…}},…}; Two-Dimensional Arrays In C, a two-dimensional array is declared as shown in the following example: int d[10][20]; Two-dimensional arrays are stored in a row-column matrix. The first index indicates the row. The row index can be thought of as a “pointer"to the correct row. When a two-dimensional array is used as an argument to a function, only a pointer to the first element is passed. However, the receiving function must define at least the length of the second dimension, e.g.: function(int x[][20]) Multi-Dimensional Arrays C allows arrays of more than two dimensions, the exact limit depending on the individual compiler. ontbrekende -> op 0 geplaatst Vakgroep Informatietechnologie
6. Meerdimensionale rijen 2D rij: a[P][Q] 3D rij: a[P][Q][R] Elementtoegang naam[i][j] *(naam[i]+j) *((*(naam+i))+j) *(naam+Q*i+j) naam[i][j][k] *(naam[i][j]+k) *(naam+(Q*R)*i+R*j+k) “storage mapping function” Vakgroep Informatietechnologie
6. Meerdimensionale rijen als functieparameters “storage mapping function” moet gekend zijn (voor statische rijen) ! 2D rijen 3D rijen formele parameter type naam [P][Q][R] type naam [ ][Q][R] type naam [P][Q] type naam [ ][Q] schaadt de algemeenheid van de functie ! gebruik dynamisch gealloceerde rijen ! Vakgroep Informatietechnologie
6. Meerdimensionale rijen: wijzerrijen ‘q’ a[0] ‘a’ ‘b’ ‘c’ ‘\0’ a a[1] ‘d’ ‘e’ ‘f’ ‘\0’ a[2] ‘g’ ‘h’ ‘i' ‘\0’ a[3] ‘j’ ‘k’ ‘l’ ‘\0’ char* a[4]={“abc”,”def”,”ghi”,”jkl”} uitdrukking waarde *(a[0]) ‘a’ *(a[1]+2) ‘f’ a[2][2] ‘i' a[2]=a[0]; a[2][2] ‘c’ a[2][2]=‘q’; a[0][2] ‘q’ Vakgroep Informatietechnologie
6. Voorbeeld: array van pointers void signal_runtime_error (int num){ static char *error[] = { "Ethernet chip not initialised. \n", "Device not ready. \n", "Input Buffer overflow detected. \n", "Transmission problem .\n" }; printf(”SYSTEM> %s.\n",error[num]); } Arrays of Strings Arrays of strings are created using a two-dimensional array. The left index determines the number of strings. Each string is accessed using only the left index (eg, gets(array[2] accesses the third string). Vakgroep Informatietechnologie
6. Meerdimensionale rijen : programma-argumenten /* argumenten.c */ #include <stdio.h> int main(int argc,char* argv[ ]) { int i=0; printf("Programma-argumenten : \n"); for(i=0;i<argc;i++) printf("%s\n",argv[i]); return 0; } argumenten abc def ghi argc = 4 ‘a’ ‘r’ ‘g’‘u’‘m’‘e’‘n’‘t’ ‘e’‘n’ \0 argv argc and argv - Arguments to main() Information may be passed into the program from the command line using the two special built-in arguments argc and argv. The former holds the number of arguments and the latter is a pointer to an array of character pointers. The value in argc is always at least 1 because the program name counts as the first argument. An example of usage is as follows: void main(int argc, char *argv[]) { if(argc != 2) { printf("You forgot to type your name\n"); exit(1); } printf("Hello %s", argv[1]); The names argc and argv are traditional but arbitrary, and may be changed to anything the programmer prefers. argv[0] argv[1] argv[2] argv[3] ‘a’ ‘b’ ‘c’ ‘\0’ ‘d’ ‘e’ ‘f’ ‘\0’ ‘g’ ‘h’ ‘i’ ‘\0’ Vakgroep Informatietechnologie
6. Meerdimensionale rijen: dynamische rijen 1D-rijen a[0] a a[1] a[2] int* a[3] a[4] int #define P 5 ... int* a; … a=(int*)calloc(P,sizeof(int)); allocatie vernietiging … free(a); ... Dynamically Allocated Arrays and Pointers Memory may be allocated using malloc() and operated on as if it were an array. Such “arrays"are known as dynamically allocated arrays . Since any pointer may be indexed as if it were a single-dimension array, the pointer returned by the malloc() function may be indexed in the normal way. Multi-dimensional arrays, however, pose a problem. Since the dimensions have not been defined in the program, a trick must be used: The pointer is passed as a parameter to a function, which allows the function to define the dimensions of the parameter receiving the pointer, e.g.: p = malloc(40*sizeof(int)); table(p); ... void table(int p[4][10]) /* now the compiler has an array to work with */ { } Vakgroep Informatietechnologie
6. Dynamische rijen (2) 2D-rijen a int** allocatie int* int #define P 5 #define Q 2 ... int** a; int i; … a=(int**)calloc(P,sizeof(int*)); for(i=0;i<P;i++) a[i]=(int*)calloc(Q,sizeof(int)); vernietiging … for(i=0;i<P;i++) free(a[i]); free(a) ... Vakgroep Informatietechnologie
Overzicht 1. Arrays (rijen) in 1 dimensie 2. Pointers (wijzers) 3. Call by reference 4. Dynamisch geheugenbeheer 5. Strings 6. Multidimensionele arrays 7. Functie-argumenten 8. Structs revisited Vakgroep Informatietechnologie
Functie als argument van andere functie 7. Functie-argumenten Functie als argument van andere functie Functie wijzer: type naam(proto_lijst) type (*naam)(proto_lijst) Interpretatie naam wijzer naar functie *naam functie zelf (*naam)(actuele_lijst) functie-oproep Pointers to Functions Even though a function is not a variable, it has a location in memory which may be assigned to a pointer. A variable which is a pointer to a function must be declared as such, as in: int (*p)(); The address of a function is assigned to this variable by using the function's name without parentheses or arguments, e.g.: p = function_name; dereferentie gebeurt automatisch in functie zelf dus : *naam(actuele_lijst) equivalent met naam(actuele_lijst) Vakgroep Informatietechnologie
7. Functie-argumenten: gebruik voor UNIT testen. void signal_runtime_error ( int ); void signal_memory_error ( int) ; ... int i =0; void (*f_ptr)(int); f_ptr= signal_runtime_error ; for(i=0;i<4;i++) f_ptr(i); f_ptr= signal_memory_error ; Vakgroep Informatietechnologie
7. Functie-argumenten oefening: generatie van tabel /* functiewijzer.c */ #include <stdio.h> #include <math.h> double kwadraat(double); void tabuleer(double f(double),double,double,double); int main(void) { printf("Tabel van sin(x)\n"); tabuleer(sin,0.0,1.57,0.2); printf("Tabel van x*x\n"); tabuleer(kwadraat,0.0,1.0,0.2); return 0; } void tabuleer(double f(double),double s,double e,double stap) { double x; printf("-----------------------------------\n"); for(x=s;x<e;x+=stap) printf("%f -> %f\n",x,f(x)); double kwadraat(double x) { return x*x; Vakgroep Informatietechnologie
7. Intermezzo: typedef Voorbeelden typedef int geheel; Legt verband tussen type en naam Declareert een naam alsof het een variabele van het type in kwestie was, voorafgegaan door typedef Een type kan vervangen worden door naam Dikwijls gedefinieerd in header file Voorbeelden typedef int geheel; typedef int* gehele_wijzer; typedef int (*f)(int,int); typedef double (*g)(double); typedef size_t unsigned; typedef typedef allows a new data type to be explicitly defined. Note that it does not actually create a new data class, but simply defines a new name for an existing type. This process helps in making machine-dependent code more portable, since only the typedef statements need be changed. It can also aid in self-documenting a program by allowing the use of more descriptive names for the standard data types. For example, a new name for float could be created as follows: typedef float balance; which would allow a new float variable to be created by: balance overdue; Vakgroep Informatietechnologie
7. Functie-argumenten: rijen van functiewijzers typedef functie_type_definitie; functietype naam[bereik]; Voorbeeld typedef int (*discretef)(int,int); discretef f[10]; Vakgroep Informatietechnologie
Generatie van tabel typedef double (*realf)(double); /* functierij.c */ #include <stdio.h> #include <math.h> double kwadraat(double); void tabuleer(double f(double),double,double,double); typedef double (*realf)(double); int main(void) { realf f[2]={sin,kwadraat}; int i; for(i=0;i<2;i++) tabuleer(f[i],0.0,1.0,0.2); return 0; } void tabuleer(double f(double),double s,double e,double stap) { double x; printf("-----------------------------------\n"); for(x=s;x<e;x+=stap) printf("%f -> %f\n",x,f(x)); double kwadraat(double x) { return x*x; Vakgroep Informatietechnologie
Overzicht 1. Arrays (rijen) in 1 dimensie 2. Pointers (wijzers) 3. Call by reference 4. Dynamisch geheugenbeheer 5. Strings 6. Multidimensionele arrays 7. Functie-argumenten 8. Structs revisited Vakgroep Informatietechnologie
8. Toekenning van strings p1.naam[0] p1.naam[29] typedef struct{ char naam[30]; short leeftijd; char code; } persoon; ... persoon p1,p2; p1 p1.naam p1.leeftijd p1.code p2 p1.naam p1.naam en p2.naam zijn beide STATISCHE rijen: geheugen wordt gealloceerd tijdens creatie van p1 en p2 p1.leeftijd p1.code Vakgroep Informatietechnologie
struct* 8. Structs & pointers w p toegang tot gegevens typedef struct{ char naam[30]; short leeftijd; char code; } persoon; ... persoon p; persoon* w; w=&p; p p.naam p.leeftijd p.code toegang tot gegevens Declaring Structure Pointers Assuming the previously defined structure addr, the following declares addr_pointer as a pointer to data of that type: struct addr *addr_pointer; Using Structure Pointers Structure pointers may be used to generate a call-by-reference to a function and to create linked lists and other dynamic data structures. Calls-by- reference should be used for all but the simplest structures so as to avoid overheads occasioned by the pushing and popping of all the structure elements onto and off the stack. To access the elements of a structure using a pointer, the -> operator is used, as in: ptr->postcode where ptr has been declared as a pointer to the type of structure and assigned the address of a variable of that type, and postcode is a structure element within that variable. p.naam (*w).naam w->naam (*w).leeftijd w->leeftijd p.leeftijd (*w).code w->code p.code p.naam[1] (*w).naam[1] w->naam[1] (*struct_wijzer).veldnaam struct_wijzer->veldnaam Vakgroep Informatietechnologie
8. Structs: initialisatie Cfr. syntax voor het initialiseren van een rij schrijf initialisatie-uitdrukkingen voor elk veld tussen { } bij expliciete initialisatie: alle niet gespecificeerde velden worden op 0 geplaatst Voorbeelden persoon p={“Jan Janssen”,30,’A’}; persoon q={“Piet Janssen”}; persoon r[5]={{“Mario Puzo”,55,’P’},{“Don Corleone”}}; persoon n[10]={0}; /* alles 0 ! */ Vakgroep Informatietechnologie
8. Structs: wijzervelden #define NAAML 30 typedef struct{ char naam[NAAML]; short leeftijd; char code; } persoon1; #define NAAML 30 typedef struct{ char *naam; short leeftijd; char code; } persoon2; sizeof(persoon1) 34 sizeof(persoon2) 8 Arrays and Structures Within Structures Structure elements may be arrays and structures. When a structure is an element of another structure, it is called a nested structure. reserveert WEL geheugen voor inhoud van naam ! reserveert GEEN geheugen voor inhoud van naam ! Vakgroep Informatietechnologie
8. Structs: wijzervelden (2) persoon1 p1={0}; persoon2 p2={0}; p1 p1.naam p1.leeftijd p1.code \0 p2 p2.naam p2.leeftijd p2.code \0 NULL p2.naam Dynamisch te alloceren rij Type persoon 2 vergt functies voor allocatie en vernietiging Vakgroep Informatietechnologie
8. Structs: initialisatie P2 type typedef struct{ char *naam; short leeftijd; char code; } persoon2; void init_persoon2(persoon2*); void free_persoon2(persoon2); int main(void) { persoon2 p2={0}; init_persoon2(&p2); free_persoon2(p2); return 0; } void init_persoon2(persoon2* p) { if(p->naam != NULL) free_persoon2(*p); p->naam=(char*)calloc(NAAML,sizeof(char)); if (p->naam != NULL) p->naam[0]='\0'; void free_persoon2(persoon2 p) { if (p.naam !=NULL) free(p.naam); \0 p2 p2.naam p2.leeftijd p2.code \0 NULL Vakgroep Informatietechnologie
8. Structs: soorten kopieën geen init_persoon2 nodig ! persoon1 a={“Jan Jansen”,30,’A’}; persoon1 b={0}; b=a; persoon2 a={“Jan Jansen”,30,’A’}; persoon2 b={0}; b=a; a a.naam a.leeftijd a.code J n \0 30 A a a.naam a.leeftijd a.code 30 A J n \0 DIEPE KOPIE ONDIEPE KOPIE 30 A b b.naam b.leeftijd b.code \0 b b.naam b.leeftijd b.code \0 NULL J a n \0 30 A Vakgroep Informatietechnologie
8.Structs: soorten kopieën (2) int main(void) { persoon2 a={0}; persoon2 b={0}; init_persoon2(&a,"Jan Jansen",30,'A'); init_persoon2(&b,"Piet Verlinden",35,'B'); print_persoon2(a);print_persoon2(b); b=a;b.code='N'; wijzig_naam(&b,”Mario Puzo"); free_persoon2(a);free_persoon2(b); return 0; } --- void print_persoon2(persoon2 p) { printf("Naam = %s\n",p.naam); printf("Leeftijd = %d\n",p.leeftijd); printf("Code = %c\n",p.code); void wijzig_naam(persoon2* p,const char* n) { p->naam=(char*)realloc(p->naam, strlen(n)*sizeof(char)); strcpy(p->naam,n); output ? (uitleg ?) Vakgroep Informatietechnologie
8. Diepe kopie (deep copy) Gevraagd ? Schrijf een functie die een diepe kopie maakt van een variabele van het type persoon2. void deep_copy ( persoon2 * toPersoon, const persoon2 * fromPersoon) { int naamlengte =0 ; naamlengte = strlen(fromPersoon->naam); toPersoon->naam= (char*)calloc(++naamlengte,sizeof(char)); strcpy(toPersoon->naam, fromPersoon->naam); toPersoon->leeftijd=fromPersoon->leeftijd; toPersoon->code=fromPersoon->code; }; Vakgroep Informatietechnologie
8. Diepe kopie: oplossing void deep_copy ( persoon2 * toPersoon, const persoon2 * fromPersoon) { int naamlengte =0 ; naamlengte = strlen(fromPersoon->name); toPersoon->name=(char*)calloc(++naamlengte,sizeof(char)); toPersoon->name=strcpy(toPersoon->name, fromPersoon->name); toPersoon->leeftijd=fromPersoon->leeftijd; toPersoon->code=fromPersoon->code; }; Vakgroep Informatietechnologie
8. Structs: structs en functies Als argument Wordt behandeld als elk ander type (pass-by-value) Er wordt een ONDIEPE kopie genomen (shallow copy) (dynamisch gealloceerde variabelen worden niet automatisch in een nieuwe geheugenruimte gekopieerd !) Als resultaat Passing Entire Structures to Functions When a structure is used as an argument to a function, the entire structure is passed using the standard call-by-value method. Of course, this means that changes made to the contents of the structure inside the function do not affect the structure used as the argument. Passing Structures to Functions When an element of a non-global structure is to be passed to a function, the value of that element is passed (unless that element is complex, such as an array of characters). For example, given: struct fred { char x; int y; char s[10]; } mike; each element would be passed like this: funct(mike.x); /* passes character value of x */ funct(mike.y); /* passes integer value of y */ funct(mike.s); /* passes address of string */ funct(mike.s[2]);/* passes character val of s[2] */ Wordt behandeld als elk ander type (m.a.w. rijen van structs niet als resultaat toegelaten! wel struct*) Vakgroep Informatietechnologie
8. Structs: structs en functies vb #include <stdio.h> #define PRINT2(x) (printf("el1=%d, el2=%d\n",x[0],x[1])) void wissel(int[ ]); void wissel_rij2(rij2); typedef struct { int r[2]; } rij2; int main(void) { int a[ ]={1,2}; rij2 b={{1,2}}; PRINT2(a); wissel(a); PRINT2(a); PRINT2(b.r); wissel_rij2(b); PRINT2(b.r); wissel(b.r); PRINT2(b.r); return 0; } void wissel(int a[ ]) { int t; t=a[0]; a[0]=a[1]; a[1]=t; } void wissel_rij2(rij2 s) { t=s.r[0]; s.r[0]=s.r[1]; s.r[1]=t; output ? (uitleg ?) Vakgroep Informatietechnologie
8. Structs: geneste structuren typedef struct { char* voor; char* fam; } naam; naam n; int leeftijd; char code; } persoon; persoon p; persoon *q; naam* r; … q=&p; r=&(p.n); printf(“Voornaam = %s”,p.n.voor); (*r).voor r->voor (*q).n.voor (q->n).voor p.n.voor Vakgroep Informatietechnologie