GEF 243B Programmation informatique appliquée Les pointeurs rencontrent les fonctions Pointeurs à pointeurs §9.2 – 9.3
Revue Comment est-ce que les deux variables suivantes sont représentées en mémoire? char character = 'a' ; char string [] = "a"; Est-ce que mon ami le compilateur va se pleindre avec ceci? Que va-t-il se passer?: char temp [] = ""; char text [] = "Some text"; int i; for (i = 0, strlen(text), i++) temp[i] = text[i]; character only has 0x61 (97) in memory; string[] has {0x61, 0x0} in memory No complaint, but temp was declared zero-sized; it will not be big enough to accept the values from text[] JGA Beaulieu
Synopsis Pointeurs et fonctions Pointeurs à pointeurs Passage d’un pointeur à une fonction Retourner un pointeur à partir d’une fonction Sommaire de la communication avec les fonctions Pointeurs à pointeurs Pointeurs de type void Utilisations Déclaration Casting des pointeurs . JGA Beaulieu
Pointeurs rencontrent les fonctions Une des plus grandes utilités des pointeurs est de passer des paramètres par adresses aux fonctions Comme nous l’avons vue pour les tableaux, il est parfois plus efficace de passer l’information par référence au lieu de par valeur Le passage des données par référence n’est pas seulement efficace, mais parfois c’est nécessaire pour que certaines fonctions soient possibles Passing by address or by reference is often used interchangeably. For the most part, both terms mean the same thing, passing the address of some piece of information to some function. We say necessary, because if we want to develop/use some functions such as sorting, finding maximum, minimum values, dynamic memory helper functions and so on. JGA Beaulieu
Pointeurs rencontrent les fonctions Tout comme pour les tableaux, quand vous passez des paramètres par référence, tout changement qui est fait dedans la fonctions est appliqué directement à la variable actuelle Une fonction simple qui utilise les pointeurs comme paramètres est la fonction pour échanger deux valeurs entre deux variables Une telle fonction peut être utilisée dans un algorithme de triage This is a good place to explain why pointers are required. Without pointers, all of the values to be sorted would have to passed by value. Copies of every value would be copied (in a time consuming fashion) and passed. Changes would be made, and a new list passed back, again by value, only to have to be copied to the destination! JGA Beaulieu
Passé par valeur ne fonctionne pas… Code is from Forouzan p. 440. Make them notice the way the function is declared in the prototype. Two pointers to int are declared. The variable name could have been used in the prototype. The function declaration says that it will accept two pointers to int (two addresses that store integers). Make them notice the function call that passes two addresses as actual parameters. They also should understand how the dereferencing of the variables works. The drawing beside the code is good, because it shows spatially that the pointers are in the function and that they point to variables outside because they hold the addresses of the variables. Note that writing this function would not be possible without the use of pointers. So pointers are necessary if we want to factor some functions. The only other way we could have implemented this function without pointers would have been to use global variables, which is not a good option. JGA Beaulieu
Passé par référence fonctionne … Code is from Forouzan p. 440. Make them notice the way the function is declared in the prototype. Two pointers to int are declared. The variable name could have been used in the prototype. The function declaration says that it will accept two pointers to int (two addresses that store integers). Make them notice the function call that passes two addresses as actual parameters. They also should understand how the dereferencing of the variables works. The drawing beside the code is good, because it shows spatially that the pointers are in the function and that they point to variables outside because they hold the addresses of the variables. Note that writing this function would not be possible without the use of pointers. So pointers are necessary if we want to factor some functions. The only other way we could have implemented this function without pointers would have been to use global variables, which is not a good option. JGA Beaulieu
Pointeurs comme paramètres Passez des pointeurs seulement si il est nécessaire que vous ayez accès à la variable directement quand vous voulez changer la valeur du paramètre actuel Si vous n’avez pas un besoin de changer la valeur de la variable externe, passer le paramètre actuel par valeur vous allez alors protéger le paramètre actuel contre tout changement non voulu JGA Beaulieu
Retourner les pointeurs des fonctions Les fonctions ne font pas que d’accepter les pointeurs, elles peuvent aussi les retourner!!! Cela peut être utile quand on veut retourner une référence à un des paramètres passés à la fonction Le prochain exemple nous montre une fonction qui retourne un pointeur à une des deux variables qui lui ont été passé; au retour, le pointeur pointe à la variable ayant la plus petite valeur Le pointeur (adresse) est ensuite stocké dans une variable pointeur dans la fonction qui a fait l’appel The use of pointer and address here is done on purpose so that the students understand that a pointer is an address. A pointer is stored in a pointer variable. JGA Beaulieu
Pointeurs rencontrent les fonctions Again, this code is from Forouzan p.441: This slide shows even more clearly the location of the pointers. What is very important to note here is the type of the function. It returns a pointer to int, so the function must be declared with that type. The second thing we should note for the students is the power of the C language expressions such as the one in the return statement in the smaller function. The function returns px or py which ever points to the smaller of the two integers that was passed by reference. The last thing to point out is that the variable p in main is a pointer to int. JGA Beaulieu
Sommaire de la communication avec fonctions JGA Beaulieu
Pointeurs à pointeurs Donc si un pointeur tient l’adresse d’une autre variable, est-ce qu’il peut contenir l’adresse d’un autre pointeur? Oui il le peut. Un pointeur à un pointeur représente deux niveaux d’indirection En fait, il n’y a aucune limite au nombre d’indirections que l’on peut utiliser en C En pratique, cependant, vous allez rarement passer deux niveaux d’indirection JGA Beaulieu
Pointeurs à pointeurs Voici comment on déclare un pointeur à un pointeur à int int** p; //un pointeur à un pointeur à un int Chaque fois que vous voulez accéder à la valeur pointé par un pointeur à un pointeur, il faut le déréférencer deux fois : int** p; int* r; int a = 0; r = &a; //r pointe à a p = &r; //p pointe à r qui pointe à a **p = 5; //La valeur de a change à 5 Pointers to pointers are useful to process 2-D arrays or in numerical methods. The use of pointers to pointers is especially useful when you want to create an array in a function and that you do not know before compile time how many elements are going to be in the array. JGA Beaulieu
Pointeurs de type void Tout comme indiqué lors du dernier cours, C ne permet pas de faire des comparaisons ou de mélanger les types des pointeurs Il y a une exception à cette règle: Le pointeur void En C le pointeur void est un pointeur générique ou universel qui peut être utilisé là où le type des données auxquelles ont veut pointer n’est pas connu avant la compilation et l’exécution du programme JGA Beaulieu
Pointeurs de type void Nous allons bientôt voir l’allocation dynamique de la mémoire. Quand on demande de la mémoire, C nous retourne un pointeur qui pointe vers la mémoire demandée. Ce pointeur est void Parce que la fonction qui nous donne la mémoire (malloc) n’a aucune idée de quelle type de données on va mettre dedans Si nous voulons une fonction générique capable de trier toutes sortes d’information (int, char, float, ou types dérivés), nous pouvons accepter un pointeur void qui pointe à l’information qui doit être triée You use a void pointer when you do not know the type for the data that your function will handle. There are many uses for void pointers, here we give two. One that is inherent in the C language and one reason that we would use to create a generic function. The reason that malloc returns a void pointer is that the function was written without a type. For the second example, the only thing I would need to do when using a generic sorting function is to define which comparison function to use. The sorting algorithm (say a bubble sort) is the same regardless of the data, the only thing that changes is the expression of what is bigger. Such an example can be found at: http://pweb.netcom.com/~tjensen/ptr/pointers.pdf in code example bubble6.c JGA Beaulieu
Pointeurs de type void Vous déclarez un pointeur à void de cette façon: void* pointerAVoid; Parce que le pointeur ne pointe à aucun type de variable, on ne peut pas le déréférencer dans un énoncé int maVar; maVar = *pointerAVoid; //erreur! *pointerAVoid = maVar; //erreur! We remember that a variable cannot be of void type. JGA Beaulieu
Pointeurs de type void - casting Nous pouvons utiliser un « cast » avec les types de pointeurs int* pInt; char* pChar; void* pVoid; … pInt = pChar; //Erreur de compilateur (warning) pInt = (int *) pVoid; //bon pChar = (char *) pVoid; //bon pInt = (int *) pChar; //valide mais pas logique! There should never be a reason to do the last of these statements. JGA Beaulieu
Pointeurs de type void - casting Vous devez « caster » une fonction si elle retourne un pointeur à void. Voici un exemple avec la fonction malloc: //malloc retourne une adresse à un bloc de mémoire void* malloc(int size); //comme définit en C int* iPtr; … iPtr = (int *)malloc(10 * sizeof(int)); //casting We do not give more detail on malloc here, just enough so that they understand the void pointer return. Show them the declaration of malloc and the use of void * Show them the declaration of the int pointer and the casting during the call. JGA Beaulieu
Quiz Time char anotherChar, myChar = 'a'; int *pNum; char *pChar, **ppChar; void *pNothing; void main(void) { ppChar = &pNum; //1. Est-ce légal? pChar = &myChar; //2. Est-ce légal? pNothing = pChar; //3. Est-ce légal? ppChar = &pChar; //4. Est-ce légal? *pChar = 'z'; //5. Est-ce bon? Ca fait quoi? **ppChar = 'y'; //6. Est-ce bon? Ca fait quoi? anotherChar = *pNothing; //7. Est-ce que je peut faire ça? pChar = pNothing; //8. Est-ce légal? } 1 is not not legal…a pointer to pointer to char cannot be assigned the address of a pointer to an integer. It seems like it might work, and it would if it were cast. 2 is legal as a pointer to char can be assigned a char address 3 is legal…as far as C is concerned any pointer may be assigned to a void pointer. No harm there. 4 is OK as pointer to pointer to char can be assigned the address of pointer to char. 5 is good and the value of myChar is now 'z' 6 is good, and the value of myChar is now 'y' 7 is illegal as you cannot dereference a void pointer without casting. You could have anotherChar=*(char*)pNothing; 8 isn't legal …need pChar=(char*)pNothing; NOTE: BECAUSE POINTERS ARE ALL JUST INTS YOU CAN CAST ALMOST ANYTHING AS ANYTHING ELSE. CAUTION AND DIAGRAMS ARE ADVISED!!!! Yes it is legal…as far as C is concerned any pointer may be assigned to a void pointer. No harm there. But you must be explicit in the other direction, hence the "extra" question below. The fourth statement is OK as pointer to pointer to char can be assigned the address of pointer to char. Yes it is good and the value of myChar is now 'z' Yes it is good, and the value of myChar is now 'y' No you cannot dereference a void pointer without casting. You could have anotherChar=*(char*)pNothing; Finally, ask if pChar=pNothing is legal (it isn't…need pChar=(char*)pNothing; JGA Beaulieu