2.2 Introduction aux variables, aux types simples et aux instructions
2.2.1 Identificateurs en C
Exercice 2.2 --- Identificateurs.
Le programme suivant tente de définir des variables locales de
type entier :
int main(void){
int
nom1, 1nom, nom_2, nom.2, _nom_3, -nom-3, Nom_de_variable,
Nom de variable, deuxieme_choix, deuxième_choix, mot_francais,
mot_français, fonction-1, _MOYENNE_du_MOIS_, 3e_jour, limite_inf.,
lim_supérieure, __A_, _, a, 3 ;
}
Malheureusement, certains identificateurs ne sont pas licites.
Corriger ce programme en modifiant les identificateurs qui ne
devraient pas être utilisés (expliciter à chaque fois l'erreur
commise).
2.2.2 Variables et types des variables
Schématiquement, une variable correspond à un emplacement en
mémoire contenant une information. Dans le code source, cette
information est manipulée par l'entremise du nom de la variable.
Le C est un langage typé. Toute variable, constante ou
fonction doit être d'un type précis. Le type d'un objet définit
la façon dont il est représenté en mémoire et les
manipulations qu'on peut faire avec lui.
La norme ANSI spécifie les types et les opérations sur les
variables suivants :
-
les spécificateurs de type
| char |
double |
enum |
float |
int |
long |
| short |
signed |
struct |
union |
unsigned |
void |
- les qualificateurs de type
const volatile
- les opérateurs
| ( ) |
[ ] |
-> |
! |
~ |
++ |
-- |
- |
(type) |
*() |
| &() |
sizeof |
, |
* |
/ |
% |
+ |
- |
>> |
<< |
| > |
< |
<= |
>= |
== |
<<= |
& |
^ |
| |
&& |
| || |
?: |
+= |
-= |
*= |
/= |
%= |
^= |
|= |
>>= |
Ainsi, on définit un caractère par l'instruction : char
nom; et on peut lui affecter le caractère A par
l'instruction nom='A';.
On peut définir une variable foo stockant la chaîne de
caractères bar par l'instruction char *foo="bar";.
De même, on définit un entier et un flottant grâce aux
instructions int
nom=666; et
float nom=3.14;.
Le programme --- erroné --- suivant devrait afficher le résultat
de la multiplication de 1500 par 6,55957.
#include "stdio.h"
int main(void) {
int A ;
int B ;
float R ;
A = 1500 ;
B = 6.55957 ;
R = A*B ;
// pour l'affichage
printf("Le resultat de la multiplication est %f\n",R) ;
return 1 ;
}
Ce programme compile mais le résultat est erroné. En effet,
l'affectation effectue une conversion de type implicite : quand c'est
possible l'expression de droite est convertie dans le type du terme de
gauche.
Exercice 2.3 --- Correction d'un programme.
Corriger le programme.
Indication :
pensez à afficher le contenu des variables. Comment expliquez vous
la valeur de la variable r.
Remarque
Il n'est pas pertinent d'inclure dans des programmes des nombres
comme 1500 sans préciser leurs significations et sans fournir un
mécanisme pour les modifier au besoin.
En utilisant la commande du préprocesseur #define en
début de fichier, on peut définir un nom symbolique
(#define Somme 1500) et le réutiliser par la suite
(A = Somme). Le préprocesseur remplacera le nom
Somme par 1500 chaque fois qu'il le rencontrera dans
le programme.
Exercice 2.4 --- Typage implicite.
Expliquer pourquoi le programme suivant :
int main(void){
int a = 10;
float b ;
b = 1/(a/100) ;
return 0 ;
}
compile mais provoque une erreur d'exécution.
2.2.3 Le type char
En C, le type char correspond aux entiers signés codables
sur 1 octet. Un bit étant réservé pour le signe, il s'agit des
entiers compris entre 27-1(=127) et -127. Le type
unsigned char désigne les entiers non signés codables
sur 1 octet (de 0 à 255).
Puisque les variables de types char codent des entiers, on
peut les convertir en ce type par la commande :
char foo ='a' ;
int bar = (int) foo ; /* (int) est un op\'erateur de convertion de type */
Par le biais d'une table, ces entiers sont associés à des
caractères ; le standard American Standard Code for Information
Interchange est consultable dans le manuel (man ascii).
La norme ISO 8859-1 complète cette table afin de coder les
lettres accentuées utilisées en Europe de l'ouest
(man iso_8859_1 pour plus de détails).
Exercice 2.5 --- Les fonctions putchar et getchar.
La fonction int putchar (int c); prend en entrée un entier
représentant le code ascii d'en caractère et affiche ce
caractère sur la sortie standard.
La fonction int getchar (void); récupère un caractère
dans l'entrée standard et le retourne.
L'usage de ces fonctions nécessite l'ajout de la directive
#include <stdio.h> à votre code.
Construisez un programme qui permette à l'utilisateur de saisir
une lettre minuscule au clavier et affiche la majuscule
correspondante à l'écran (ne vous occupez pas de la gestion
d'erreur).
Même exercice mais la lettre est supposée être stockée dans
un fichier et la majuscule doit être stockée dans un autre
(utilisez les redirections du shell).
Exercice 2.6 --- Séquence d'échappement.
Les caractères ASCII reçèlent quelques suprises.
Déternimez ce que provoque l'affichage des caractères suivants :
'
'\n' '\t' '\b' '\r' '\"' '\\' '\0' '\a' '\?' '\'' '\v'
Exercice 2.7 --- Étude du type char.
En utilisant les tables de codages des caractères et en gardant
à l'esprit le codage d'un entier sur un octet, prévoyez le
résultat du programme suivant :
#include <stdio.h>
int main(void){
unsigned char bar = 'a' + 127 ;
char foo = bar+256 ;
printf("Le charact\\`ere %c correspond \\`a l'entier %d.\n",bar,(int) bar) ;
printf("Le charact\\`ere %c correspond \\`a l'entier %d.\n",foo,(int) foo) ;
return 0 ;
}
Exercice 2.8 --- Choix de typage.
Traduisez les déclarations suivantes en C, sachant que les
variables sont destinées à continir les ensembles de nombres
indiqués. Choisissez les types les plus économiques en terme
d'espace mémnoir, sans perdre en précision.
entier COMPTEUR {0 ,..., 300}
entier X,Y {-120 ,..., 100}
entier MESURE {-10 ,..., 104}
r\'eel SURFACE1 {0.5 ,..., 150075}
r\'eel SURFACE2 {-12 ,..., 1500750.5}
entier N1 {0 ,..., 210}
entier N2 {-47 ,..., 47}
entier N3 {0 ,..., 326}
entier N4 {-1280 ,..., 1285}
bool\'een TROUVE {vrai, faux}
Exercice 2.9 --- Les constantes.
Quel(s) type(s) numérique(s) pouvez-vous utiliser pour les groupes
de nombres suivants ?
1 12 4 0 -125
1 12 -4 0 250
1 12 4 0 250
1 12 -4 0.5 125
-220 32000 0
-3000005.000000001
410 50000 2
410 50000 -2
3.14159265 1015
2*107 10000001
2*10-7 10000001
-1.05*1050 0.0001
305.122212 0 -12
12332 23.4 345LU 34.5L -1.0
0xeba 0123l '\n' 1.23ul -1.0e-1
0xFE0 40000 40000u 70000u 1e1f
'0' ' \0' 0 'O'
67e0 '\r' 01001 0.0l 0XEUL
2.2.4 Expressions
En C, les expressions peuvent être difficile à comprendre. Il est
donc vivement conseillé de ne pas abuser de la flexibilité du
langage au début de votre apprentissage.
Exercice 2.10 --- Affectation.
Quel est le résultat des instructions suivantes :
#include <stdio.h>
int main(void){
int a,b =0 ;
a+=b-=20 ;
return 0 ;
}
Exercice 2.11 --- Suite d'expressions.
L'opérateur virgule permet de définir une suite d'expressions ;
ces dernières sont évaluées de la gauche vers la droite et la
valeur de retour de la suite d'expressions est la dernière
expression évaluée.
Que retourne le programme suivant. Testez votre réponse.
int main(void){
/* une premi\`ere suite
d'expressions */
int a = 2, b = a ;
/* une seconde */
return a+=b, b+=3 ;
}
Pour tout commentaire : Alexandre Sedoglavic.