TD C1 (2425v1)
Objectifs :Les types fournis par C sont proches des types primitifs Java (historiquement, c'est plutôt l'inverse). Mais les différences sont suffisantes pour nous poser problème si on ne les connaît pas.
1) int
est bien le type entier (signé), mais alors qu'il est toujours sur 32 bits en Java, son empreinte mémoire peut varier d'une machine à l'autre en C.
De même pour long. Par contre
byte et short devraient bien occuper respectivement 8 et 16 bits.
2) float et double sont comme en Java (les fonctions mathématiques calculent aussi en double, donc les réels simple précision float sont peu utilisés).
3) char (pour stocker un seul caractère) n'occupe que 8 bits et est signé (-128 à +127), alors qu'il en occupe 16 en Java et n'est pas signé (0 à 65535).
4) Le type booléen n'existe pas en standard, même si des versions récentes fournissent le bool du C++.
On a coutume d'utiliser le type int (32 fois trop coûteux !) en prenant comme conventions :
- à la lecture, =0 vaut FAUX, et ≠0 vaut VRAI (dans les if et les while, par exemple)
- à l'écriture, 0 pour FAUX, et 1 pour VRAI
5) Il est possible d'utiliser des types plus exotiques tels que long int (équivalent de long), long long (dépendant de la machine), long double (sur 80 bits).
6) Il est également possible
d'ajouter unsigned devant
un type pour obtenir un type non signé.
Exemple : int
correspond à 'entier relatif' (allant pour n bits de -2n-1 à +2n-1-1), alors que
unsigned int
correspond à 'entier naturel' (allant pour n bits de 0 à 2n-1).
II. La définition de type
Si vous trouvez fastidieux de répéter unsigned int à chaque fois que vous avez besoin d'une variable du type entier naturel, il est possible de définir un nouveau type par l'instruction
:
typedef unsigned int
Naturel;
Ensuite, il suffira d'écrire Naturel n; pour déclarer une variable de ce type.
Cette possibilité bien plus générale
typedef definition_de_type nouveau_nom
;
nous servira énormément lors du prochain TP.
Exception à la règle ci-dessus :
pour définir un type tableau par exemple d'entiers,
il faut écrire : typedef int TableauI[];
(donc avec les crochets à la fin),
puis pour l'utiliser : TableauI vTab; par exemple.
III. Manipulations de tableaux
Lors du TP C1, vous avez remarqué qu'on ne pouvait pas obtenir le nombre de cases d'un tableau (sauf dans le bloc dans lequel il est créé).
Cela explique pourquoi on est presque toujours obligé d'ajouter un paramètre supplémentaire aux fonctions de manipulation
des tableaux pour leur passer sa taille.
Attention ! Ne pas confondre le nombre de cases, par exemple 10, et le nombre d'éléments utiles dans le tableau, par exemple 7. Dans ce cas, les 3 dernières valeurs seraient ignorées.
1) Écrire un programme C comportant une fonction vmin retournant la valeur minimale d'un tableau de réels (passé en paramètre, ainsi que le nombre de valeurs à examiner) et un
main comportant :
- la déclaration/initialisation d'un tableau de réels (d'au moins 7 valeurs)
- l'affichage du résultat de vmin avec en 2ème paramètre la taille du tableau (préalablement calculée)
- l'affichage du résultat de vmin avec en 2ème paramètre 3 ou 4 (de telle sorte que le résultat soit différent)
2) Écrire un programme C comportant une fonction imin (n'appelant pas la fonction vmin) retournant l'indice du minimum d'un tableau de réels (passé en paramètre, ainsi que le
nombre de valeurs à examiner) et un main comportant :
- la déclaration/initialisation d'un tableau de réels (d'au moins 7 valeurs, avec au moins 2 fois la valeur minimale)
- l'affichage du résultat de imin avec en 2ème paramètre la taille du tableau (préalablement calculée)
Contrainte : Si la valeur minimale apparaît plusieurs fois dans le tableau, imin doit retourner le plus grand indice, tout en n'affectant pas la variable contenant la
valeur minimale courante si celle-ci ne change pas !
3) Ceux qui n'ont pas terminé le TP C1 doivent le faire maintenant.
Pour les autres, écrire un programme C comportant une procédure
affiche2
qui devra afficher dans l'ordre croissant des valeurs provenant de 2 tableaux de réels
(de taille différente) triés par ordre croissant.
affiche2 aura donc 4 paramètres : 2 x (un tableau + son nombre d'éléments).
Contrainte : Définir le type tableau et l'utiliser aux 4 endroits où il peut être utilisé.
Conseils :
Comme cet algorithme n'est pas simple, il est conseillé (dans la boucle) de séparer la partie où l'on choisit dans quel tableau on va prendre la prochaine valeur, de la partie où l'on prend la valeur et fait évoluer les indices. D'autre part, la boucle
'Faire ... Tantque' semble bien adaptée ici :
do { instructions } while (condition);
Exemple pour tester : { -5.0, -5.0, -4.44, -2.2, 1.1, 3.0, 6.6, 7.77 } et { -11.1, -3.0, -2.2, 5.5, 8.8, 9.9 }
Rappels : double vTab[] = En C, il n'y a pas d'attribut length comme en Java ; on doit donc presque toujours passer la taille du tableau en paramètre supplémentaire de la fonction que l'on est en train d'écrire. Seul cas où l'on peut calculer la taille d'un tableau : dans le même bloc, juste après la déclaration ci-dessus,
on peut utiliser la formule : int vNbEle = printf( "rationnel=%d/%d\n", vN, vD ); pour afficher les entiers vN et vD. Pour un nombre réel, le format est %lf. On peut inclure autant de formats %qqch dans la chaîne de caractères en premier paramètre de printf à condition qu'il y ait ensuite le bon nombre de variables (séparées par des virgules) et dans le bon ordre ! Donc, printf a un nombre variable de paramètres, le premier étant toujours une chaîne de caractères (n+1 paramètres s'il y a n caractères % dans le format en premier paramètre). Bon à savoir : Il est même possible de spécifier pour chaque variable réelle combien de chiffres on veut afficher après la virgule ; il suffit d'ajouter .2 entre % et lf pour imposer seulement 2 chiffres après la virgule par exemple. |
Attention, en C :
La ligne #include <stdio.h> n'est pas une instruction C, mais une directive à l'intention du pré-processeur. Le pré-processeur est un programme qui est lancé par la commande gcc juste avant de lancer le compilateur C proprement dit, c'est-à-dire que le compilateur ne compile pas directement notre fichier prog.c, mais un fichier prog.i, résultat de la transformation de prog.c par le pré-processeur. En quoi consistent principalement ces transformations :1) inclure des fichiers .h (qui contiennent des déclarations) tels que stdio.h, math.h, ou bien d'autres 2) remplacer toutes les occurrences d'un mot par une suite de caractères que l'on choisit : - #define TAILLE 10 permet de définir une constante Attention ! #define TAILLE 10; (voyez-vous la différence ?) provoquerait une erreur de compilation dans une instruction telle que int max = TAILLE / 2; - #define TAB { 11, -22, 33 } permet de définir un tableau dont on aurait besoin plusieurs fois dans la suite du programme Attention ! Cette ligne ne déclare aucun tableau pour le compilateur ... |