FAQ CConsultez toutes les FAQ
Nombre d'auteurs : 35, nombre de questions : 194, dernière mise à jour : 18 février 2018 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de www.developpez.com et de l'expérience personnelle des auteurs.
Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci .
Sur ce, je vous souhaite une bonne lecture.
- Qu'est-ce qu'un prototype ?
- Est-il possible de définir une fonction sans fournir le prototype ?
- Comment passer "une variable" à une fonction ?
- Comment créer une fonction qui retourne plus d'une valeur ?
- Comment créer une fonction qui retourne une chaîne de caractères ?
- Comment retourner un pointeur de fonction ?
- Comment définir une fonction acceptant un nombre d'arguments variable, comme printf() ?
- Combiner plusieurs options en un seul paramètre ?
Un prototype est la partie qui, dans la définition d'une fonction, définit les relations entre la fonction et le monde extérieur. Par exemple dans :
Code C : | Sélectionner tout |
1 2 3 4 | double f(double x, int n) { ... } |
- le nom de la fonction : f ;
- le type de la valeur retournée : double ;
- le nombre de paramètres requis : 2 dont le premier de type double (x) et le deuxième de type int (n).
Une fonction avant d'être utilisée doit être déclarée. La déclaration permet au compilateur de s'assurer que la fonction sera toujours correctement utilisée dans le programme. Pour déclarer une fonction, il suffit de prendre son prototype puis d'ajouter un point-virgule à la fin.
Oui, et c'était d'ailleurs le seul moyen de définir une fonction avant la normalisation du langage C, c'est-à-dire dans le C originel (K & R C). Voici un exemple de définition d'une fonction selon cette méthode :
Code C : | Sélectionner tout |
1 2 3 4 5 | double f(x, n) double x; int n; { ... } |
Code C : | Sélectionner tout |
1 2 | double f(); /* Les parenthèses, toujours vides, qui suivent f servent à indiquer que f est une fonction. */ /* Sans elles, la ligne définirait plutôt une variable globale de type double nommée f. */ |
Supposons que l'on veut écrire une fonction, reset, qui permette de mettre à 0 une variable de type int. Faisons donc :
Code c : | Sélectionner tout |
1 2 3 4 | void reset(int n) { n = 0; } |
Code c : | Sélectionner tout |
1 2 | int a = 10; reset(a); |
Pour que la fonction reset puisse modifier la valeur de « la variable » qu'on lui a transmise, ce n'est pas la valeur de la variable qu'il faut lui fournir, mais plutôt son adresse. Connaissant l'adresse de la variable, la fonction peut aussi bien lire que modifier sa valeur. Le bon code est donc :
Code c : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdio.h> void reset(int * adr); int main(void) { int a = 10; reset(&a); printf("a = %d\n", a); /* affiche "a = 0" */ return 0; } void reset(int * adr) { *adr = 0; } |
Une fonction ne peut retourner au plus qu'une valeur, mais il est possible de créer une fonction qui retourne d'autres valeurs via un ou plusieurs paramètres. Par exemple :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include <stdio.h> #include <math.h> void decomposer_nombre(double x, double * ptr1, double * ptr2); int main(void) { double x, e, d; printf("x = "); scanf("%lf", &x); /* Supposons que l'utilisateur tape 2.5 */ decomposer_nombre(x, &e, &d); /* On donne une entrée (x), on obtient deux sorties (e et d) */ printf("e = %f\n", e); /* Pour x = 2.5, affiche e = 2.000000 */ printf("d = %f\n", d); /* Pour x = 2.5, affiche d = 0.500000 */ return 0; } void decomposer_nombre(double x, double * ptr1, double * ptr2) { /* Nous allons mettre dans *ptr1 la partie entière de x */ /* et dans *ptr2 sa partie décimale */ *ptr1 = floor(x); *ptr2 = x - *ptr1; } |
Une première méthode consiste à passer à la fonction un pointeur vers la zone mémoire destinée à contenir la chaîne à retourner. Par exemple :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <stdio.h> #include <string.h> void get_string(char * Buffer, size_t BufferLen) { /* On ne peut pas utiliser strcpy car cette fonction ne permet pas d'indiquer le nombre max de caractères qu'on veut copier */ strncpy(Buffer, "MaChaine", BufferLen); /* Il est possible que Buffer n'ait pas pu contenir toute la chaine ... */ Buffer[BufferLen - 1] = '\0'; } int main(void) { char Buffer[100]; get_string(Buffer, sizeof(Buffer)); printf("%s\n", Buffer); return 0; } |
Une autre façon de faire est de retourner un pointeur vers des caractères situés en mémoire globale. Par exemple :
- à l'aide d'une chaîne statique :
Code C : Sélectionner tout 1
2
3
4
5
6
7
8
9
10
11
12
13#include <stdio.h> const char * get_string(void) { return "MaChaine"; } int main(void) { printf("%s\n", get_string()); return 0; }
- à l'aide d'une chaîne allouée dynamiquement :
Code C : Sélectionner tout 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#include <stdio.h> #include <stdlib.h> #include <string.h> char * alloc_string(void) { char * Buffer, s[] = "MaChaine"; Buffer = malloc(strlen(s) + 1); if (Buffer != NULL) strcpy(Buffer, s); return Buffer; } int main(void) { char * Buffer = alloc_string(); if (Buffer != NULL) { printf("%s\n", Buffer); free(Buffer); } return 0; }
Voici un exemple de fonction, func, ne prenant aucun argument et qui retourne un pointeur sur une fonction de type int f(const char * s) (par exemple puts) :
Code c : | Sélectionner tout |
1 2 3 4 | int (*func(void))(const char *) { return puts; } |
Bien entendu, ici encore un typedef allège énormément l'écriture.
Code c : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h> typedef int F(const char *); F * func(void); int main(void) { func()("Bonjour."); /* <=> puts("Bonjour."); */ return 0; } F * func(void) { return puts; } |
Les ... dans la liste des paramètres d'une fonction indiquent que la fonction peut accepter 0, un ou plusieurs paramètres à la place. Parmi les paramètres de la fonction, il doit cependant y en avoir au moins un qui est explicite (fixé). Les macros va_start(), va_arg() et va_end() définies dans stdarg.h permettent de parcourir les paramètres. Dans l'exemple ci-dessous, on parcourt les paramètres jusqu'à en rencontrer un qui vaut 0.
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include <stdio.h> #include <stdarg.h> void printf_total(const char * format, ...); int main(void) { print_total("Le total est : %d\n", 1, 2, 3, 4, 0); return 0; } /* Fonction print_total : affiche la somme des arguments */ void printf_total(const char * format, ...) { int total = 0; va_list ap; int arg; va_start(ap, format); while ((arg = va_arg(ap, int)) != 0) total += arg; printf(format, total); va_end(ap); } |
Le système présenté ici permet de fournir à une fonction une valeur qui regroupe un ensemble de flags (drapeaux) souvent utilisés pour permettre à l'utilisateur de fournir un nombre variable d'options sans utiliser le système de fonction à nombre variable d'arguments (va_list). Pour cela, il faut commencer par définir les différentes options possibles :
Code C : | Sélectionner tout |
1 2 3 4 | enum { OPTION1 = 1 << 0, OPTION2 = 1 << 1 }; |
Code C : | Sélectionner tout |
void foo(int options)
Code C : | Sélectionner tout |
foo(OPTION1 | OPTION2)
Code C : | Sélectionner tout |
options & OPTION1
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <stdio.h> enum { OPTION1 = 1 << 0, OPTION2 = 1 << 1 }; void foo(int); int main(void) { foo(OPTION1 | OPTION2); return 0; } void foo(int options) { if (options & OPTION1) printf("OPTION1 trouve\n"); if (options & OPTION2) printf("OPTION2 trouve\n"); } |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.