home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 17 / CD_ASCQ_17_101194.iso / dos / prg / alb_c10 / chap_06 / chap_06.txt < prev   
Encoding:
Text File  |  1994-10-03  |  28.4 KB  |  647 lines

  1.       
  2. ==========================================================================
  3.                  APPRENTISSAGE du C             version ALB_10                
  4.                  
  5.             CHAPITRE 6: DES FONCTIONS.                   
  6. ==========================================================================
  7.  
  8.  
  9.  
  10.       Pourquoi avoir inventé les fonctions?
  11.       Pour des raisons pragmatiques: elles sont utiles au programmeur!   
  12.       
  13.  
  14.    1° Nous avons déjà plusieurs fois utilisé des fonctions dans le chapitre
  15.    précédent pour éviter la répétition d'une même séquence de code. 
  16.    
  17.    2° Reprenez maintenant, dans le même chapitre, le menu du programme de 
  18.    calcul de diverses lois de distribution de probabilités: CH05_06.C. 
  19.    Chaque possibilité du switch renvoie: " Lancement de la fonction ..."
  20.    Dans le programme complet, les lettres N, S, K, F, renvoient chacune à un
  21.    sous-programme de calcul, contenu dans une fonction. L'intérêt est que
  22.    chaque fonction est parfaitement isolée. Si un jour il faut en modifier 
  23.    une seule, nous pourrons le faire sans risque pour les autres. 
  24.    Cela renforce la sécurité du code.
  25.  
  26.    3° Cela permet de rendre aussi beaucoup plus claire la structure d'un 
  27.    programme et sa lisibilité.
  28.  
  29.    4° Pour résumer: c'est la possibilité de fractionner les grosses choses 
  30.    complexes en petits trucs simples qu'ont peut résoudre et gérer un par un. 
  31.    Nous restons dans la tradition de la méthode scientifique.
  32.  
  33.  
  34.             Ce langage s'est développé en fonction 
  35.             des besoins de ceux qui l'utilisaient.
  36.   Chapitre 6: Des fonctions                                         page 1
  37.  
  38.  
  39.  
  40.  
  41.              1. REGLES D'UTILISATION.
  42.             ===========================
  43.  
  44.  
  45.    1.1 Premier exemple ( passage par "valeur").
  46.    --------------------------------------------
  47.  
  48.                                 ************
  49.                  Examinez le programme:           CH06_01.C
  50.                                 ************
  51.       Ce programme permet de faire deux fois la saisie d'un caractère, sa 
  52.    conversion en majuscule s'il ne l'est déjà, puis son affichage. Il y a 
  53.    trois actions auxquelles correspondent trois fonctions.
  54.  
  55.    1° Les trois fonctions sont déclarées dans l'en tête, au même titre que la 
  56.    bibliothèque utilisée. Ce sont les "prototypes" des trois fonctions:
  57.  
  58.    char LitChar( void);
  59.    char Min_Maj( char);
  60.    void EcritChar( char);
  61.  
  62.    Nous déclarons au compilateur les éléments indispensables pour identifier 
  63.    la fonction au moment où le programme l'appellera. La définition de la
  64.    fonction, sa structure interne, nous l'écrirons après le corps de main() 
  65.    la fonction principale.
  66.  
  67.       Quels sont les éléments nécessaires à la déclaration de la fonction?
  68.  
  69.       *  Son type, char pour les deux premières, c'est le type de la valeur 
  70.      de retour. Il est unique. La troisième ne renvoie rien, son type 
  71.      est donc void.
  72.       *  Son nom.
  73.       *  La liste des types des arguments qu'on passe à la fonction pour 
  74.      qu'elle puisse travailler. Si on ne passe rien on écrit void.
  75.       *  Un point-virgule clôt la déclaration.
  76.  
  77.     => Deux fonctions qui ne diffèrent que par le type de la valeur de retour
  78.       sont considérées comme identiques par le compilateur qui renverra alors 
  79.       un message d'erreur. Il ne fera pas de différence entre:
  80.  
  81.     char LitChar( void) et void LitChar( void). Il vous dira en général
  82.     que vous avez fait une erreur de type dans la déclaration.
  83.     Il ne se sert du type de la fonction que pour contrôler si dans le 
  84.     main() vous demandez bien le même type en retour.
  85.  
  86.     car1= LitChar();  la fonction renvoie t'elle bien une variable du 
  87.               type de car1 ou d'un type équivalent?
  88.       
  89.     => Notez qu'il est parfois utile pour des raisons de clarté d'ajouter à 
  90.       la déclaration le nom des arguments qui sont passés. On peut déclarer
  91.       bien que le compilateur n'en ait pas besoin:
  92.    
  93.      char Min_Maj( char c1);  au lieu de: 
  94.      char Min_Maj( char); 
  95.   Chapitre 6: Des fonctions                                         page 2
  96.  
  97.  
  98.      
  99.    2° Les fonctions sont définies plus loin, après le corps de main().
  100.    Il est permis, mais pas conseillé, de le faire dans l'en-tête:
  101.  
  102.    char Min_Maj( char c1)               // pas de point-virgule
  103.    {    
  104.     le corps de la fonction 
  105.    }                                    // une accolade clôt la définition.
  106.  
  107.    3° Le compilateur lit ensuite le corps de la fonction main(). Il contrôle 
  108.    au passage la conformité au type de l'appel à la fonction. 
  109.    
  110.    4° car2= Min_Maj( car2);     Que se passe t'il en réalité?
  111.    
  112.       On dit que le C passe la VALEUR de la variable car2 à la fonction 
  113.    Min_Maj(). En réalité, le programme copie la VALEUR de la variable car2 
  114.    et l'affecte à la variable c1 qui figure dans la définition de la fonction 
  115.    entre les parenthèses et qui est générée à chaque appel de la fonction 
  116.    sans que nous ayons besoin de la déclarer formellement. 
  117.    La variable car2 n'est pas utilisée. La fonction accomplit son travail 
  118.    avec c1 et retourne une VALEUR qui est alors affectée à car2.
  119.    La variable intermédiaire c1 est alors détruite. En gros:
  120.  
  121.       car2 existe  
  122.       appel à la fonction  Min_Maj( char c1)
  123.       création automatique de c1
  124.       affectation à c1 de la VALEUR de car2
  125.       exécution de la fonction avec c1
  126.       retour d'une VALEUR 
  127.       affectation de cette valeur à car2 qui est alors modifiée
  128.       destruction de c1
  129.  
  130.    On dit qu'on a fait un passage par "valeur" à la fonction. Quand il n'y
  131.    a pas d'argument à passer, on met entre les parenthèses le mot void.
  132.  
  133.    5° Return( évaluation d'une expression); 
  134.    
  135.    Dans la première fonction LitChar(), le programme retourne la VALEUR de 
  136.    l'expression c0 qui est entre parenthèses ( elles ne sont pas obligatoires 
  137.    mais rendent souvent le programme plus facile à lire). Il ne faut pas 
  138.    oublier le point-virgule.
  139.    L'exécution de la fonction est arrêtée après le renvoie de la valeur.
  140.    Notez que les while(...); n'ont pas de corps.
  141.  
  142.    6° Notez qu'on peut toujours appeler une fonction à partir d'une autre
  143.    ( la fonction principale main() est aussi une fonction).
  144.    Elle peut se placer n'importe où dans la fonction mais ne renvoie qu'une
  145.    seule valeur qui est nécessairement du type de la fonction.
  146.    La fonction Min_Maj() utilise return à deux endroits. L'instruction 
  147.    if-else est interrompue, la fonction est arrêtée et la valeur d'une des 
  148.    deux expressions est renvoyée.
  149.  
  150.    Dans EcritChar(), la fonction ne renvoie rien. On peut ne pas utiliser 
  151.    return. L'accolade fermante suffit pour indiquer la condition de fin du
  152.    bloc. Le contrôle est alors rendu au point d'appel de la fonction sans
  153.    qu'il y ait un retour d'information. On conseille parfois d'utiliser une
  154.    instruction return sans argument pour rendre le code plus clair et 
  155.    faciliter des modifications futures. Ce n'est pas indispensable car de 
  156.    toutes façons, le compilateur ajoute systématiquement un return à la fin 
  157.    d'une fonction.
  158.   Chapitre 6: Des fonctions                                         page 3
  159.  
  160.  
  161.  
  162.    1.2 Passage par "pointeur".
  163.    ---------------------------
  164.       La technique du passage par valeur ne permet de modifier, de manipuler,                                                            
  165.    qu'une seule variable extérieure à la fonction en utilisant l'instruction 
  166.    return. 
  167.       Or, les programmeurs avaient besoin de manipuler, par une même fonction, 
  168.    plusieurs variables extérieures à la fonction.
  169.       La solution fut trouvée par un rapprochement avec une application des 
  170.    opérateurs unaires de référencement qui permettent d'obtenir l'adresse 
  171.    d'une variable et les opérateurs de déréférencement qui permettent d'agir 
  172.    sur une variable à partir de son adresse ( chapitre 3: 5.5).
  173.       La variable déréférencée est appelée un pointeur.
  174.  
  175.       A titre d'exercice et pour voir le mécanisme de l'utilisation des
  176.    pointeurs nous allons reprendre le programme précédent, en ne touchant pas
  177.    les fonctions que nous venons d'utiliser pour manipuler la variable car1, 
  178.    mais en créant 3 nouvelles fonctions qui manipuleront car2 avec le même 
  179.    résultat, mais en utilisant le passage par pointeur. 
  180.       Puis nous étudieront un programme moins simple qui permet de manipuler
  181.    plusieurs variables dans la même fonction.
  182.                                 
  183.                                 ************
  184.                1.2.1. Analyse du programme:           CH06_02.C
  185.                                 ************
  186.  
  187.    1° Examinons la déclaration, le prototype de la fonction LitChar2:
  188.  
  189.         void LitChar0( char*);
  190.  
  191.       => void signifie qu'elle ne renvoie rien.
  192.       => entre les parenthèses, char* signifie qu'elle utilise un pointeur 
  193.      sur une variable caractère. Le passage de l'information du programme
  194.      principal à la fonction se fera par un pointeur.
  195.  
  196.     2° Examinons maintenant la définition de la fonction LitChar0. 
  197.     
  198.         void LitChar0( char *c0)  {  ...  }
  199.  
  200.       => tout se passe comme si la fonction créait une variable c0, pour 
  201.      recevoir l'ADRESSE de la variable car0 du programme principal, 
  202.      celle qu'il faudra manipuler.
  203.      La valeur déréférencée *c0 sera celle de la variable car0. 
  204.      Toute modification de *c0 modifiera car0. 
  205.      On dit que le pointeur *c0 pointe car0.
  206.  
  207.      Souvenez vous ( chapitre 3: 5.5):      
  208.      
  209.       ================================================================= 
  210.       |               si:   b= &a;     alors:   *b= a;                |
  211.       =================================================================
  212.                c0= &car0;  alors:  *c0= car0;
  213.  
  214.     3° Nous n'avons plus besoin de l'instruction return. L'acquisition  et 
  215.        l'affectation du caractère se sont fait à l'intérieur du premier while
  216.        avec l'instruction, c0= getchar().
  217.   Chapitre 6: Des fonctions                                         page 4
  218.  
  219.  
  220.     
  221.     4° Revenons dans la fonction principale pour examiner l'appel de la 
  222.        fonction:
  223.             LitChar( &car0);
  224.        
  225.        La fonction utilise un pointeur, elle attend donc une adresse: &car0.
  226.  
  227.     5° Examinez aussi les changements dans les deux autres fonctions. Elles
  228.        s'analysent suivant les mêmes principes.
  229.                                 
  230.                                 ************
  231.                1.2.2. Analyse du programme:           CH06_03.C
  232.                                 ************
  233.  
  234.       Nous reprenons ici le code de Thad Smith pour calculer des combinaisons
  235.    avec des nombres réels doubles. La fonction utilise à la fois le passage 
  236.    par valeur pour initialiser la variable "test" et le passage par pointeur
  237.    pour initialiser la variable cnm0. 
  238.       Dans cet exemple on ne manipule par pointeur qu'une seule variable, mais
  239.    pour une application qui nécessiterait la manipulation de plusieurs autres
  240.    variables, la technique resterait la même.
  241.  
  242.    1° Nous utilisons la directive #define pour définir une constante égale 
  243.       au maximun du domaine des doubles.
  244.  
  245.    2° Le prototype de la fonction nous indique qu'elle renvoie un int, 
  246.       qu'elle demande deux int passés par valeur et utilise une fois le 
  247.       passage par un pointeur.
  248.  
  249.    3° Vous reconnaîtrez le coeur du code de Thad. Nous avons seulement ajouté
  250.       trois possibilités de sortie de la fonction en utilisant chaque fois 
  251.       l'instruction return:
  252.         return -1; quand les paramètres n et m ne sont pas conformes;
  253.         return 1;  quand le calcul va sortir du domaine des doubles;
  254.         return 0;  quand tout s'est bien passé.
  255.       La fonction renvoie donc une information qui nous renseigne sur la 
  256.       manière dont elle a fonctionné. 
  257.       
  258.       Cette information est renvoyée dans notre programme à la variable test,
  259.       Ce qui explique que dans main() nous trouvions: 
  260.         test= Combinaisons(...);
  261.  
  262.    4° Examinons dans le programme principal l'appel de la fonction:                                                            
  263.    
  264.         test= Combinaisons( n0, m0, &cnm0);
  265.  
  266.       Pour des raisons de clarté, nous avons choisi pour les variables de la 
  267.       fonction principale des noms proches de ceux qui sont utilisés dans la 
  268.       fonction Combinaisons(). 
  269.       La fonction crée au moment de l'appel les variables n et m et leur
  270.       affecte les valeurs de n0 et m0. L'adresse de cnm0 est affectée à la 
  271.       variable c qui sera manipulée par le pointeur *c qui pointe alors sur
  272.       cnm0.
  273.       Tout se passe comme si:  c= &cnm0;   donc:  *c identique à cnm0;
  274.   Chapitre 6: Des fonctions                                         page 5
  275.  
  276.  
  277.  
  278.  
  279.       A la clôture de la fonction: 
  280.     les variables n, m, c, cnm, i, f sont détruites.
  281.     n0, m0, n'ont pas été modifiées car elles sont passées par valeur 
  282.     et que le return ne les concerne pas.
  283.     test a été modifiée par le return.
  284.     cnm0 a été passée par pointeur et a donc pu être modifiée.
  285.  
  286.  
  287.    1.3 Comparaison des vitesses d'exécution entre les deux méthodes.
  288.    -----------------------------------------------------------------
  289.  
  290.       Plutôt que d'affirmer que l'une des méthodes est plus rapide que 
  291.    l'autre, nous vous proposons de faire un test que vous pourrez utiliser
  292.    pour évaluer chaque cas en particulier.
  293.  
  294.                                 ************
  295.                   Analyse du programme:           CH06_04.C
  296.                                 ************
  297.    1° Nous avons écrit la fonction de calcul des combinaisons de deux 
  298.       manières. La première version utilise le passage par valeurs et 
  299.       retourne le nombre de combinaisons. La seconde passe ce nombre par un 
  300.       pointeur. Les fonctions vont être appelées ( d- k) fois pour calculer 
  301.       C( i, j), i diminuant de d à k avec j= i- k. Le cumul des valeurs se 
  302.       fait dans des variables somme0 et somme1. Nous avons simplifié le code 
  303.       des fonctions et pris d= 800, k= 100, soit 700 cycles.
  304.  
  305.    2° Nous appelons la bibliothèque <time.h> pour pouvoir utiliser la 
  306.       fonction clock(). Cette fonction accepte pour arguments un type 
  307.       particulier de donnée clock_t. Elle nous renvoie la durée d'exécution 
  308.       depuis le début du programme en nombre de tops de l'horloge interne de 
  309.       votre machine. Le symbole utilisé par printf() est %f. CLK_TCK est une 
  310.       constante qui donne le nombre de tops de l'horloge interne par seconde.
  311.       
  312.    3° Ne laissez fonctionner QUE CE PROGRAMME sur votre machine pour ne pas 
  313.       avoir à partager le processeur avec d'autres applications. 
  314.       Exécutez plusieurs fois ce programme. Qu'en pensez vous?
  315.  
  316.       J'ai essayé sur plusieurs machines, je dois avouer que les résultats 
  317.       n'ont pas été très concluants. Mais ma méthode est peut être à 
  318.       remettre en question!
  319.  
  320.    Vous pourrez noter que dans les FAQ, les développeurs américains se 
  321.    montrent très sceptiques dès qu'il s'agit d'optimiser du code.
  322.  
  323.    Les "auteurs" disent que:
  324.  
  325.    => Si le type de l'argument à passer est d'une taille plus grande que 
  326.       celle des entiers, on le passe par pointeur.   (pourquoi pas!)
  327.  
  328.    => Si la valeur de la variable doit être modifiée par la fonction 
  329.       appelée on passe l'argument par pointeur.
  330.       ( si nous devons modifier plusieurs variables, on ne peut pas faire 
  331.       autrement).
  332.   Chapitre 6: Des fonctions                                         page 6
  333.  
  334.  
  335.  
  336.  
  337.     2. CLASSIFICATION DES VARIABLES EN FONCTION DE LEUR PORTEE.
  338.     ===========================================================
  339.  
  340.       Nous avons déjà l'habitude de classer les variables en fonction de leur 
  341.    type, char, int, double, etc.
  342.       Nous pouvons aussi les classer en fonction de leur portée, c'est à dire
  343.    de l'étendue du programme dans laquelle une variable est reconnue et peut
  344.    être utilisée.
  345.    Nous distinguerons deux catégories:
  346.  
  347.         les variables locales ( ou automatiques);
  348.         les variables globales ( ou externes);
  349.  
  350.    2.1. Les variables locales.
  351.    ----------------------------
  352.       Ce sont celles que nous avons utilisées jusqu'à présent. Elles sont 
  353.    déclarées à l'intérieur d'un bloc. Un bloc est défini par ce que l'on 
  354.    trouve entre une paire d'accolades. Leur portée est limitée à ce bloc.
  355.    Le corps d'une fonction, principale ou non, est un bloc.
  356.  
  357.       Les variables locales sont stockées dans la mémoire de pile (stack)
  358.    affectée à un programme. A l'appel d'une fonction, une zone mémoire lui 
  359.    est allouée où on trouvera l'adresse de départ du programme, la mémoire 
  360.    nécessaire à une valeur de retour, les valeurs des arguments et les 
  361.    variables locales. Au retour tout sera détruit et la zone mémoire libérée. 
  362.    Ces informations stockées dans la pile sont donc volatiles.
  363.  
  364.       Il faut noter que juste après leur déclaration, les variables locales 
  365.    contiennent n'importe quoi. C'est à l'initialisation qu'elles prennent la 
  366.    valeur que vous leur attribuez. 
  367.       Dans le programme précédent, n0, m0, cnm0 sont reconnues dans main()
  368.    mais ne le sont pas dans la fonction Combinaisons(). Placez un zéro
  369.    à la suite d'un m de cette dernière fonction et vous aurez un message
  370.    d'erreur à la compilation.
  371.       A la sortie de la fonction Combinaisons() ses variables locales, n, m, 
  372.    cnm, i, f, sont détruites.
  373.       C'est aussi le cas à la fin de main() où les variables n0, m0, cnm0, 
  374.    test, sont détruites.
  375.  
  376.       Si on déclare des variables à l'intérieur du bloc délimité par les 
  377.    accolades d'un do {...} while(); les variables déclarées sont locales 
  378.    pour le bloc et ne sont pas reconnues à l'extérieur.
  379.  
  380.       Chacun chez soi. L'avantage est de garder entre les fonctions des 
  381.    barrières  étanches qui évitent des mélanges aux conséquences toujours
  382.    imprévisibles.
  383.  
  384.     ---------------------------------------------------------------------  
  385.    |   Toujours cette préoccupation de sécurité. Il faut travailler avec |
  386.    |   des modules indépendants de façon à pouvoir modifier, maintenir   |
  387.    |   les programmes sans trop de difficultés.                          |
  388.     ---------------------------------------------------------------------
  389.  
  390.    Cette préoccupation est l'une de celles qui ont amené les développeurs à
  391.    imaginer la "programmation orienté objet".
  392.   Chapitre 6: Des fonctions                                         page 7
  393.  
  394.  
  395.  
  396.       L'idéal était d'en rester là. Mais les développeurs du C avaient lu 
  397.    Ciceron et médité ses commentaires sur l'ancienne maxime du droit romain, 
  398.    "summum jus summa injuria", l'application extrême du droit est aussi 
  399.    l'extrême injustice. Il est parfois indispensable de transgresser les 
  400.    meilleurs principes.
  401.  
  402.    2.2. Les variables globales.
  403.    ----------------------------
  404.  
  405.       Une variable doit parfois être utilisées par plusieurs fonctions. Elle
  406.    doit donc être définie en dehors de tout bloc, dans l'en tête du programme.
  407.  
  408.       Elle n'est pas stockée dans la mémoire de pile du programme mais dans 
  409.    sa mémoire statique. Nous reviendrons à la fin de ce manuel sur ces 
  410.    questions de mémoire.
  411.  
  412.       Les variables globales sont automatiquement initialisées à zéro au 
  413.    moment de leur déclaration quand il n'y a pas d'initialisation explicite.
  414.       La valeur initiale doit être une constante, par exemple 4 ou 5.67e3, et 
  415.    non une expression comme ( 3* x- y).
  416.       Elles conservent les valeurs qu'on leur affecte successivement au cours 
  417.    du programme. C'est un avantage et en même temps un danger.
  418.                                 
  419.                                 ************
  420.                   Examinez le programme:          CH06_05.C
  421.                                 ************
  422.  
  423.    Compilez le programme. 
  424.    Le compilateur vous renverra 5 messages d'erreur du genre "le symbole k 
  425.    n'est pas défini". Nous sommes en effet en dehors du bloc où la variable 
  426.    k a été définie. Replacez correctement les symboles /* et */ pour les 
  427.    lignes 24, 34 et 45 du code. Le programme fonctionnera normalement.
  428.    
  429.       Par contre la variable globale somme est accessible à partir d'un point 
  430.    quelconque du programme. Vérifiez le en plaçant des printf().
  431.  
  432.       Remarquez aussi que la qualification "globale" de la variable "somme"
  433.    nous a évité des passages par valeur ou par pointeur aux fonctions.
  434.  
  435.  
  436.       Quel est le danger d'utiliser des variables globales? 
  437.       -----------------------------------------------------
  438.  
  439.    On peut en modifier la valeur en tout point du code. Si le programme est 
  440.    complexe, la variable globale a été manipulée dans le programme principal
  441.    et dans une série de fonctions. On ne sait plus très bien au bout d'un 
  442.    moment ce qu'elle contient. Il se produit alors des "effets de bords".
  443.       Imaginez que vous soyez obligés de modifier le programme six mois plus 
  444.    tard! Il faudra analyser le code en détail pour s'y retrouver.
  445.  
  446.       Autant que possible, il faut éviter des constructions dangereuses qui
  447.    peuvent faire apparaître des bugs latents.
  448.   Chapitre 6: Des fonctions                                         page 8
  449.  
  450.  
  451.  
  452.  
  453.          3. STATUT D'UNE VARIABLE OU D'UNE FONCTION.
  454.         ============================================
  455.  
  456.       3.1. Statut "const".
  457.       --------------------
  458.  
  459.       Si on désire empêcher toute modification d'une variable, on peut lui  
  460.    donner le statut "const", que la variable soit locale ou globale. Cette 
  461.    norme est maintenant acceptée par le C ANSI.
  462.  
  463.       En déclarant "const" un argument passé à une fonction, on interdit de 
  464.    la même manière la modification de la VALEUR passée à la fonction. La
  465.    variable dans la fonction principale n'est de toutes façons pas touchée.
  466.    C'est la nouvelle variable à l'intérieur de la fonction qui ne peut plus
  467.    être modifiée.
  468.  
  469.    int Calcule( const int, const int);
  470.  
  471.    void main(void)
  472.    {
  473.     int a, b, c;
  474.     c= Calcule( a, b);
  475.     printf(" c= %d", c);
  476.    }
  477.    int Calcule( const int x, const int y)  { return( x* y); }
  478.  
  479.      Les variables a et b ne peuvent être modifiées par la fonction Calcule().
  480.    Ce sont les VALEURS de a et de b qui ont été passées aux variables x et y.
  481.    Le passage par valeur rend donc toute modification des variables a et b 
  482.    impossible. Si leurs valeurs ne doivent pas non plus être modifiées dans 
  483.    la fonction appelée, on donne à x et y à qui sont affectées ces valeurs, 
  484.    le statut de constantes.
  485.  
  486.       3.2. Statut "extern".
  487.       --------------------
  488.       Nous verrons qu'une application informatique utilise plusieurs fichiers. 
  489.    On définit comme externes des variables ou des fonctions qui sont également
  490.    définies dans un autre fichier que celui qui contient le programme. Cela 
  491.    évite de faire des doubles déclarations. Elles ne sont stockées qu'une
  492.    seule fois en mémoire, bien que connues et manipulées par plusieurs 
  493.    fichiers. Les variables externes sont toujours globales.
  494.    
  495.  Les dangers évoqués au sujet des variables globales sont encore multipliés!
  496.  
  497.       Dans une en-tête on peut donc trouver:
  498.         extern void Combinaisons( int, int, double *);
  499.         extern int somme;
  500.       Cette fonction et cette variable sont déclarés dans un autre fichier.
  501.  
  502.       Si l'éditeur de liens entre les fichiers objets détecte une confusion
  503.    de nom ou de prototype entre des fonctions externes, si elle manque ou si 
  504.    elle est définie plusieurs fois, vous aurez un message d'erreur.
  505.       Mais pour les variables externes, certains compilateurs ne s'assurent 
  506.    que de la présence d'une déclaration de la variable globale dans l'un des 
  507.    fichiers qu'ils compilent. Une confusion sur le type de cette variable ne 
  508.    sera pas détecté. Vous devrez vérifier chaque fois, que le type de la 
  509.    variable globale externe que vous utilisez est bien celui attendu dans 
  510.    votre code.
  511.   Chapitre 6: Des fonctions                                         page 9
  512.  
  513.  
  514.       
  515.       3.3. Statut "static".
  516.       ---------------------
  517.  
  518.              3.3.1. Pour une variable.
  519.  
  520.       Quand on veut qu'une variable locale puisse être reconnue dans tout un
  521.    fichier, on lui donne le statut de "static".
  522.       Elles ne sont plus stockées dans la pile du programme mais dans la 
  523.    mémoire statique comme les variables globales.
  524.  
  525.                                 ************
  526.     Calcul des termes de la série de Léonard de Pise:         CH06_06.C
  527.                                 ************
  528.  
  529.       Les variables s_moins1 et s_moins2 sont des variables locales de la 
  530.    fonction CalcTerme. Normalement elles seraient détruites à chaque 
  531.    clôture de la fonction et réinitialisées à 1 à chaque appel.  
  532.    
  533.       Quand elles sont déclarées comme variables statiques, elles sont 
  534.    initialisées à 1 au premier appel de la fonction, elles ne sont pas 
  535.    détruites à la clôture et gardent leur valeur à l'appel suivant. Elles 
  536.    ne sont pas réinitialisées à 1, puisqu'elles se comportent désormais 
  537.    comme des variables globales à l'intérieur du fichier! 
  538.  
  539.         Les dangers évoqués au sujet des variables 
  540.         globales sont encore multipliés!
  541.  
  542.  
  543.              3.3.2. Pour une fonction.
  544.  
  545.       Contrairement aux variables globales, les fonctions sont en quelque 
  546.    sorte externes par nature car on peut y accéder à partir d'autres 
  547.    fichiers. On les déclare "static" pour réduire leur accessibilité au 
  548.    fichier où elles sont déclarées.
  549.   Chapitre 6: Des fonctions                                         page 10
  550.  
  551.  
  552.  
  553.  
  554.   4. PROPRIETE DE RECURRENCE DES FONCTIONS.
  555.  ==========================================
  556.  
  557.       On dit que les fonctions possèdent la propriété de récurrence car elles
  558.    peuvent s'appeler elles mêmes. Il faut prévoir une condition d'arrêt pour 
  559.    ne pas déclencher de boucles infinies.
  560.  
  561.         C'est parfois très élégant.
  562.  
  563.       A chaque appel de la fonction, un jeu de variables locales se crée. 
  564.    Elles sont ajoutées sur la pile. Lorsque la condition d'arrêt s'exécute,
  565.    les jeux de variables sont retirés successivement de la pile et utilisés 
  566.    par la fonction.
  567.  
  568.         Ce processus est donc gourmand en termes de temps 
  569.         d'exécution et d'occupation de mémoire.
  570.  
  571.                                 ************
  572.                Calcul d'une série par récurrence:         CH06_07.C
  573.                                 ************
  574.  
  575.    1° Nous avons contrôlé la saisie de n en empêchant l'introduction d'une
  576.      valeur négative ou nulle. Une valeur réelle, 2.58 sera tronquée à 2.
  577.  
  578.    2° La fonction SommeSerie() s'appelle elle même et la condition d'arrêt
  579.       est que n< 0.
  580.  
  581.    3° Cela fonctionne bien pour des valeurs faibles de n. 
  582.       Augmentez progressivement cette valeur. Vous aurez bientôt un message 
  583.       d'erreur: "Stack overflow" vous avez dépassé les capacités de la pile.
  584.       La limite dépend de la taille que vous donnez à la pile sur votre 
  585.       machine. La mienne bloque à n= 327.
  586.  
  587.                 C'est gênant.
  588.  
  589.                                 ************
  590.           Comparez la lisibilité des 2 fonctions:         CH06_08.C
  591.                                 ************
  592.  
  593.    1° La série qui permet de calculer directement l'arc de cercle dont la 
  594.       tangente est x s'écrit:
  595.  
  596.         Arc tg x= x- x^3/ 3+ x^5/ 5-...+ terme général +...
  597.  
  598.         Le symbole (^) signifie puissance: x^n => x à la puissance n.
  599.  
  600.       Le terme général est celui qui permet de représenter tous les autres, 
  601.       ici:
  602.         terme général: X(n)= (-1)^n* x^(2*n+ 1)/( 2* n+ 1)
  603.  
  604.         en faisant n= 0     terme de rang 0:   X(0)=   x               
  605.                n= 1     terme de rang 1:   X(1)= - x^3/ 3                        
  606.                n= 2     terme de rang 2:   X(2)=   x^5/ 5 ,etc.                  
  607.  
  608.       Cette série converge très lentement. C'est à dire qu'il faut calculer 
  609.       et additionner beaucoup de termes pour avoir une précision acceptable.
  610.   Chapitre 6: Des fonctions                                         page 11
  611.  
  612.  
  613.  
  614.    2° Ce n'est pas particulièrement facile mais essayez avant d'analyser 
  615.       le programme d'écrire la fonction de calcul sous deux formes: 
  616.       
  617.        La première avec une boucle classique, 
  618.                 de i= 0 à i= n j'additionne les X(i);
  619.        La seconde en utilisant la récurrence comme précédemment.
  620.  
  621.       Il faut inclure la bibliothèque <math.h> car elle possède une fonction,
  622.       pow( x, n) qui renvoie un réel double égal à x^n.
  623.  
  624.       A titre de contrôle sachez que Arc tg 1= 0.787873 pour 100 termes.
  625.  
  626.    3° Analysons le programme. Une saisie contrôlée classique de n puis celle
  627.       de x. 
  628.  
  629.    4° Dans ArcTangente1() nous avons passé arctg1 par pointeur. Il n'y a pas
  630.       de difficultés insurmontables dans le code des fonctions. 
  631.       Que cela ne vous empêche pas de vous planter! Je vous rappelle un des 
  632.       mots favoris de Petrus Albulus," On ne progresse que par l'erreur".
  633.  
  634.    5° La machine nous renvoie un message d'erreur dès que n est trop grand.
  635.       La mienne bloque à n= 138: "Stack overflow". 
  636.       D'autre part il est peut être plus facile d'écrire ou de lire une 
  637.       fonction classique avec une boucle for. 
  638.       
  639.       Qu'en pensez vous? 
  640.       Avez vous vraiment envie d'utiliser des fonctions récurrentes?
  641.  
  642.    6° Notez qu'il existe dans math.h une fonction atan(x) qui calcule très 
  643.       bien Arctg x en utilisant une méthode beaucoup plus rapide.
  644.   Fin du chapitre 6: Des fonctions                                  page 12
  645.  
  646.  
  647.