Les fonctions sur les caractères sont dans ctype.h
Fonction de test, rendant 0 ou 1 :
Et fonctions de conversion minuscule/majuscule :
tolower et toupper
Conversion d’une chaîne en minuscules :
for (i = 0; ch[i] != '\0' ; i = i + 1)
ch[i] = tolower(ch[i]);
Les fonctions sur les chaînes sont dans string.h
Elles sont décrites dans le livre de Kernighan et Ritchie et dans le cours de Garreta (document PDF accessible sur developpez.com).
Attention,
char s1[80] = "bonjour" ;
effectue une déclaration et initialisation de s1
mais
char s1[80] ;
s1 = "bonjour" ;
ne fonctionne pas. C’est une affectation de tableau et ça n’existe pas en C.
Copie
L’affectation de chaînes est appelée copie de chaînes et se fait avec la fonction strcpy
strcpy(s2,s1);
copie s1 dans s2
strcpy(s1,"Bonjour");
copie "Bonjour" dans s2
Concaténation
char s1[40] = "Bonjour", s2[40] = "Madame";
strcat(s1,s2); /* copie s2 au bout de s1 */
printf("%s",s1);
affiche BonjourMadame
Comparaison
strcmp(s1,s2)
rend 0 si s1=s2
rend entier strictement négatif si s1<s2
rend entier strictement positif si s1>s2
rappel : majuscules, minuscules, lettre accentuées sont différentes ; l’ordre est lexicographique.
Longueur
strlen(s1)
rend la longueur de s1
char s1[40] = "Bonjour" ;
strlen(s1) rend 7
Ce sont des nombres décimaux appelés aussi nombres flottants ou flottants.
Se représentent avec mantisse et argument en base 2.
Trois types avec des champs de valeurs différents :
float simple précision : 4 octets sur PC intel
double double précision : 8 octets sur PC intel
long double quadruple précision : 16 octets sur PC intel
A chaque type est associé une taille maximale de la mantisse et un nombre de chiffres significatifs.
Représentation avec point décimal : 21.4 0.013 .41 3.
Représentation mentisse et argument : 2e4 pour 2*104 1.2e-2 pour 1.2*10-2
Cette représentation a le type double.
Pour indiquer le type float, on met f ou F ensuite. Pour indiquer le type long double, on met l ou L ensuite.
Il y a arrondi quand cela est nécessaire. Exemple : le nombre 0.1 en décimal a un développement binaire infini, il est arrondi et n’est donc pas représenté de façon exacte.
+ - * / même priorité que sur les entiers
Attention : 2. / 5. vaut 0.4 (division décimale) et 2 / 5 vaut 0 (division entière)
Combinaisons d’entiers et de réels pour les opérateurs binaires :
Deux entiers : opération entière
Deux réels : opération décimale
Un entier et un réel : conversion de l’entier en réel et opération décimale.
Les mêmes opérateurs de comparaison que les entiers, mais, du fait des erreurs de calcul, ne pas comparer les réels avec égal ou différent.
#define EPSILON 1e-5
/* au lieu de if (a == b) */
if (a > b - EPSILON && a < b + EPSILON)
Format avec virgule fixe « f » :
scanf("%f",&x);
printf("%f",x);
Format avec notation exponentielle « e » :
scanf("%e",&x);
printf("%e",x);
Mais pour scanf, « f » et « e » font la même chose.
Si on affecte un entier à une variable réelle ou un réel à une variable entière, il y a conversion (troncature dans le deuxième cas).
Exemple :
float u;
int i;
u = 12;
i = 1.3;
printf("u=%f i=%d",u,i);
affiche u=12.000000 i=1
Les calculs réels se font de façon approchée, avec des erreurs d’arrondi. Il vaut généralement mieux contrôler les boucles avec des entiers.
Exemple :
int main()
{
float u;
int i;
u = 0.;
i = 0;
while (u < 100.)
{
u = u + 0.1;
i = i + 1;
}
printf("Controle avec le decimal : u=%f i=%d\n\n",u,i);
u = 0.;
i = 0;
while (i < 1000)
{
u = u + 0.1;
i = i + 1;
}
printf("Controle avec l'entier : u=%f i=%d\n\n",u,i);
}
Ce programme affiche :
Controle avec le decimal : u=100.099045 i=1001
Controle avec l'entier : u=99.999046 i=1000
Donc on est passé une fois de trop dans la première boucle.
Ces fonctions sont dans math.h
Les arguments et le résultat sont des « double ». Il y a conversion si nécessaire.
Comparaison à epsilon près de a et b :
if ( fabs(a – b) < EPSILON )
Les tableaux sont des regroupements d’informations de mêmes types, les structures regroupements d’informations de types différents. Structure est le terme du langage C pour ce qui est habituellement appelé enregistrement. Un enregistrement est composé de champs. En C, on parle de membres.
Exemple :
struct personne
{
char nom[20] ;
char prenom[20] ;
int age ;
float taille ;
} ;
Déclaration de variables de ce type :
struct personne p1, p2 ;
Déclaration de variables en même temps que la déclaration de la structure :
struct personne
{
char nom[20] ;
char prenom[20] ;
int age ;
float taille ;
} p1, p2;
Manipulation des champs :
p1.nom
est le champ nom, un char[20] qui se manipule comme tout autre char[20]
p1.nom[2]
est le 3e caractère du champ nom
p1.age
est le champ age, un entier qui se manipule comme tout autre entier
strcpy(p1.nom, "Dupont") ;
p1.age = 34 ;
n = p1.age ;
Initialisation à la déclaration :
struct personne z = {"Dupont", "Jean", 34, 1.75} ;
Affectation :
p1 = p2
copie dans p1 la structure contenue dans p2.
Attention, ceci marche pour les structures et pas pour les tableaux. Ca marche même pour les structures contenant des tableaux, mais pas pour les tableaux (contrairement à d’autres langages).
Les comparaisons de structures avec == ou != ne marchent pas (contrairement à d’autres langages).
On peut composer structures et tableaux, exemple :
struct date
{
int jour, mois, an ;
} ;
struct personne
{
char nom[20] ;
char prenom[20] ;
struct date date_nais ;
} ;
struct personne LesPersonnes[100] ;
LesPersonnes[i].date_nais.jour = 30 ;
Exemple, comparaison de dates :
struct date
{
int jour, mois, an ;
} d1, d2 ;
if (d1.an < d2.an)
r = -1 ;
else if (d1.an > d2.an)
r = 1 ;
else if (d1.mois < d2.mois)
r = -1 ;
else if (d1. mois > d2. mois)
r = 1 ;
else if (d1.jour < d2. jour)
r = -1 ;
else if (d1. jour > d2. jour)
r = 1 ;
else r = 0 ;
typedef permet de déclarer des types.
On met derrière la même chose qu’une déclaration de variable, on déclare ainsi un type au lieu d’une variable.
Exemple :
typedef int TAB10[10] ;
déclare tab10 comme le type tableau de 10 entiers.
On peut ensuite déclarer des variables de ce type :
TAB10 ta, tb ;
Autre exemple :
typedef struct
{
char nom[20] ;
char prenom[20] ;
struct date date_nais ;
} PERSONNE ;
PERSONNE p1, p2 ;
++ et -- sont des opérateurs unaires qui s’appliquent de façon préfixée ou postfixée à une variable entière (y compris de type char). Priorité 14.
Préfixé : ++n augmente n de 1 et rend la valeur obtenue.
Postfixé : n++ augmente n de 1 et rend la valeur avant l’augmentation.
Préfixé : --n diminue n de 1 et rend la valeur obtenue.
Postfixé : n-- diminue n de 1 et rend la valeur avant la diminution.
Certains utilisent les termes incrémentation et décrémentation.
Afficher les éléments d’un tableau :
for (i = 0 ; i < NN ; i++) printf("%d ",tab[i]) ;
Calculer la longueur d’une chaîne :
for (lg = -1; a[++lg] != '\0';);
enum {AVANT, PENDANT, APRES}
Déclare 3 constantes de type int et leur donne les valeurs 0, 1 et 2.
On peut choisir les valeurs :
enum {AVANT = 15, PENDANT = 25, APRES = 35}
Exemple :
enum {AVANT, PENDANT, APRES} ;
switch(moment)
{
case AVANT : a = b + c ; break ;
case PENDANT : a = 2 * b + 2 * c ; break ;
case APRES : a = 3 * b + 3 * c ; break ;
}
Si moment vaut AVANT, on effectue a = b + c et, du fait du break qui suit, on quitte le switch.
Syntaxe :
switch(<expression>)
{
case <exp-const1> : <liste-d-instructions1>
...
case <exp-constN> : <liste-d-instructionsN>
default : <liste-d-instructionsD>
}
<exp-constx> est une expression constante (sans variable), exemple NN+4 dans laquelle NN est une constante.
default est facultatif.
On évalue <expression>, on cherche la première <exp-constx> égale à cette valeur. Si on trouve, on exécute les instructions qui suivent. Si on rencontre un break, on quitte le switch.
Si on ne trouve pas et qu’il y a un default, on exécute les instructions qui suivent le default.
Si on ne trouve pas et qu’il n’y a pas de default, on ne fait rien.
Attention, avec :
switch(i)
{
case 2 : a++ ;
case 4 : a++ ;
case 5 : a++ ;
}
Quand i vaut 2, a est augmenté de 3 car il n’y a pas de break. Quand i vaut 4, a est augmenté de 2.
Elle permet de sortir d’une instruction for, while, do, switch.
Au lieu de :
do
{
printf("Donner un nombre (999 quand fini) \n");
scanf("%d",&nb);
if (nb != 999) somme = somme + nb;
}
while (nb != 999);
on peut écrire :
while (1)
{
printf("Donner un nombre (999 quand fini) \n");
scanf("%d",&nb);
if (nb == 999) break ;
somme = somme + nb;
} ;
Dans les boucles imbriquées, cela concerne la boucle interne.
Elle arrête l’itération en cours d’une instruction for, while, do et passe à la suivante.
for (i = 1 ; i < 10 ; i++)
{
if (tab[i]<0) continue ;
…
…
}
Dans les boucles imbriquées, cela concerne la boucle interne.
Une ligne se terminant par « \ » indique que la ligne suivante est la suite.
printf("C’est une chaîne un peu longue qui est écrite \
sur deux lignes");
Avec de nombreux compilateurs (mais pas tous), // indique le début d’un commentaire se terminant à la fin de ligne, comme dans de nombreux langages.
while (1) // boucle infinie, sortie par break
{
…
}
C’est un si alors sinon qui est une expression, qui rend une valeur.
Syntaxe :
<expression1> ? <expression2> : <expression3>
Signifie :
Si <expression1> alors rendre la valeur de <expression2> sinon rendre la valeur de <expression3>
<expression1> est une expression entière prise pour une expression logique.
Exemple :
m = (a < b + c) ? x : y+3 ;