Langage C |
Equivalent Pascal |
Déclarations / affectations
|
|
#define NOMBRE 1 #define CHAINE "ALPHA" |
CONST NOMBRE = 1; CONST CHAINE = 'ALPHA'; |
|
|
int i,j; int k,l=0; char c; float r; |
VAR i,j:INTEGER; VAR k,l:INTEGER; ...l:=0; VAR c:CHAR; VAR r:REAL; |
Les caractères se notent entre apostrophes : 'a'
Les chaînes de caractères se notent entre guillemets : "abcd ef"
Les commentaires se notent entre /* et */
Les blocs se notent entre { et }
Nom | Type | Taille du codage |
char | caractère | 8 bits |
int | entier | 1 mot mémoire (16/32 bits) |
long | entier long | 16/32 bits |
short | entier court | 16 bits |
float | réel | 32 bits |
double | réel | + de 4 octets |
Remarque :
Il est possible de redéfinir un type en utilisant la commande typedef
L'affectation d'une variable se fait à l'aide de l'opérateur =
Exemples :
char a;
int b,c = 0;
a = 'A';
L'affectation d'une valeur V à une variable x se décompose en deux
phases :
Certaines variables, définies "en global" dans un fichier, ne doivent pas être référencées dans d'autres fichiers pour ne pas être confondues avec les déclarations de variables globales dans d'autres fichiers. Pour exprimer le fait que ces variables sont confidentielles à un fichier (c'est-à-dire visibles uniquement dans ce fichier), on fait précéder leur déclaration du mot-clé static
Remarque :
Il est possible de définir, de la même manière, des fonctions confidentielles à un
fichier.
Les variables locales à un sous-programme peuvent être de diverses classes :
Lorsque la classe d'une variable locale n'est pas spécifiée, la classe "automatique" lui est alors attribuée par défaut.
Une variable "statique" locale à une fonction, constitue une mémoire du passé pour cette fonction. Une fois initialisée, cette variable conserve son ancienne valeur à chaque nouvel appel de la fonction.
Une variable déclarée de classe "registre" est allouée dans un registre (s'il en existe un de disponible). La manipulation de données effectuée directement dans les registres peut permettre de réduire les temps de calculs.
typedef est une instruction qui permet de créer de nouveaux noms de types
pour la déclaration des variables. La syntaxe de cette instruction est :
typedef [type] [nom du type];
Après l'utilisation de cette instruction, [nom du type] devient le synonyme de [type]
Le mot-clé const devant la déclaration d'une variable indique que la
valeur de cette variable ne doit absolument pas être modifiée dans le bloc courant (on
parle de "type contraint").
La conversion d'un type vers un autre s'effectue en faisant précéder la valeur à
convertir du nouveau type entre parenthèses :
char c='a';
int i=0;
float j;
...
j = (float)i;
i = (int)c; /* i reçoit le code ASCII de 'a' */
Attention, certaines conversions peuvent générer des "warnings" à la
compilation et des erreurs à l'exécution.
Exemple :
char c;
int i = 257; /* un entier est codé sur 16 ou 32 bits */
c = (char)i; /* un caractère est codé sur 8 bits (1 octet), la conversion risque de
produire une perte d'information */
En C, la division (/) de deux entiers produit le quotient de la division entière.
Exemple :
int a;
a = 2 / 4;
printf("%d\n",a);
retourne à l'écran la valeur 0. En revanche :
float a;
a = 2.0 / 4.0;
printf("%f\n",a);
retourne à l'écran la valeur 0.5
La syntaxe pour la déclaration d'un tableau est :
type_des_données identificateur[nombre_de_données]
On rajoute autant de [ ] que le tableau a de dimensions.
Exemple :
Langage C |
Equivalent Pascal |
int tab1[50]; int tab2[50][10]; Exemple : ...tab2[i][j]=6; |
VAR tab1:ARRAY [0..49] OF INTEGER; VAR tab2:ARRAY [0..49,0..9] OF INTEGER; Exemple : ...tab2[i,j]:=6; |
Un tableau peut être initialisé au moment de sa déclaration en indiquant la liste de ses valeurs.
Exemples :
+, -, *, /, % (modulo),
<< décalage de bits à gauche,
>> décalage de bits à droite,
& (ET logique entre chaînes de bits),
| (OU logique inclusif entre chaînes de bits),
^ (OU logique exclusif entre chaînes de bits).
Les quatre commandes suivantes produisent le même résultat après leur exécution :
La post-incrémentation est effective dès que la variable a été évaluée.
== test d'égalité,
!= test de différence.
>, <, >=, <= tests de supériorité ou
d'infériorité.
! négation,
&& ET logique,
|| OU logique.
Les opérateurs de comparaison (>, <, >=, <=), d'égalité (==, !=) et logiques (&&, ||) renvoient 0 si le résultat est faux et 1 s'il est juste. L'opérateur de négation logique (!) renvoie 0 pour toute valeur non nulle et 1 pour la valeur 0 :
!0 --> 1
!8 --> 0
Remarque :
Pour sortir d'une action sans exécuter toutes les actions suivantes dans un switch,
il faut qu'elle se termine par l'instruction break;
La commande :
for (expr1;expr2;expr3) action;
est équivalente à :
expr1;
while(expr2)
{ action; expr3;
}
while(1) et for(;;) sont des boucles infinies.
Un sous-programme en C renvoie toujours une valeur. Lorsque cette valeur est indéfinie, le sous programme est déclaré de type void. En général, les fonctions du langage C renvoient une valeur non nulle lorsque la commande a pu être correctement exécutée et 0 sinon.
La structure d'un sous-programme est généralement :
type_du_résultat nom_fonction(liste_et_types_des_paramètres)
{
corps_du_sous-programme
return(resultat);
}
Le passage des paramètres se fait toujours par valeur. Pour modifier la valeur d'une variable, il faut en transmettre l'adresse par pointeur.
Une chaîne de caractères est représentée sous la forme d'un tableau de caractères. Le dernier caractère indique la fin de la chaîne et sa valeur est \0
Les deux exemples suivants permettent de déclarer un tableau de 20 caractères :
La taille maximale de la chaîne déclarée ci-dessus (par la première ou la deuxième méthode) est de 19 caractères (+ le caractère \0).
Remarques :
Exemples d'initialisation d'une chaîne de caractères :
chaine[i-1]='\0';
/* Attention, la chaîne ne doit contenir ni espace, ni retour-chariot */
/* scanf place automatiquement un caractère \0 en fin de chaîne */
Remarque :
Pour afficher une chaîne de caractères, il est possible d'utiliser la commande printf de la manière suivante :
printf("%s",chaine);
oł chaine est un pointeur vers une zone mémoire contenant la chaîne à
afficher.
Pour la manipulation des chaînes de caractères, il est possible d'utiliser les fonctions
accessibles par l'inclusion de "string.h" en début de programme. Parmi
celles-ci, on retiendra en particulier :
Pour convertir une chaîne de caractères contenant des chiffres sous la forme d'entiers, on peut utiliser la fonction atoi (alphanumérique to integer) de la bibliothèque standard, dont l'en-tête est le suivant :
int atoi(const char *s)
Un pointeur contient l'adresse d'un objet (i.e. d'une variable, d'une structure, ...). Lorsqu'on déclare :
int a;
le système réserve un espace suffisant dans la mémoire pour ranger un entier. L'adresse
de cet espace réservé est : &a
Le passage d'un tableau en paramètre se fait toujours à partir de son adresse. Un
tableau déclaré de la manière suivante :
int tab[100];
a pour adresse tab ou encore &tab[0]
& donne l'adresse d'un objet donné.
* donne la valeur d'un objet à une adresse donnée.
NULL est une valeur de pointeur ayant le plus souvent la signification
d'inexistence.
Un pointeur incrémenté pointe sur l'objet adjacent suivant dans la mémoire.
Un tableau du type int TAB[10]; a pour adresse, l'adresse de son premier
élément, à savoir TAB, ou &TAB[0]. Les éléments d'un tableau
ont des adresses d'objets consécutifs.
void *malloc(size_t taille) : cette fonction renvoie un pointeur vers un
espace mémoire dont la taille en octets est précisée en paramètre (renvoie NULL
si la demande ne peut être satisfaite).
Le type size_t est défini dans la bibliothèque standard et équivaut à un unsigned
int ("entier non-signé").
Au moment de l'affectation de la valeur retournée par malloc à un pointeur, il
est nécessaire de forcer la conversion vers le type de l'information pointée. Dans
l'exemple suivant :
char *p;
...
p = (char *)malloc(4);
on force le type du pointeur retourné par malloc à être char *
void *calloc(size_t nbobjets,size_t taille) : cette fonction renvoie un
pointeur vers un espace mémoire pour le stockage d'un tableau de nbobjets objets
dont chacun prend une place mémoire correspondant à taille octets. Les bits de
la zone mémoire réservée sont tous initialisés à 0.
void free(void *pointeur) : cette fonction libère la zone mémoire
accessible par un pointeur donné en paramètre, dans le cas oł cette zone
mémoire a été allouée dynamiquement lors d'un appel à la fonction malloc.
Attention : ne jamais libérer une zone mémoire déjà libérée. Le
système pourrait alors générer des erreurs de nature imprévisible.
Pour connaître la taille d'un objet afin de réserver l'espace mémoire nécessaire à son stockage, on utilise la commande sizeof(), avec l'objet en paramètre, ou son type.
L'identificateur d'un tableau est un pointeur sur une zone en mémoire contenant (ou susceptible de contenir) les informations du tableau de manière connexe.
La taille de la zone mémoire pointée est donnée par le type du pointeur. Par exemple, si on a la déclaration suivante :
char *c;
c est un pointeur vers une zone de 8 bits en mémoire. Dès lors, l'adresse de
l'octet situé immédiatement après est c+1. En incrémentant c, il est
ainsi possible de parcourir la mémoire d'octet en octet.
Un pointeur du type short *a; pointe sur une zone pouvant contenir un entier court (codé sur 16 bits). En incrémentant a, on balaye la mémoire de 16 bits en 16 bits.
On a donc les équivalences suivantes :
Une structure se déclare de la manière suivante :
struct nom_structure
{
liste_des_champs
}
Exemple :
struct date
{
int jour;
int mois;
int an;
}
On accède aux champs d'une structure par l'opérateur : .
struct date d; /* déclaration d'une variable de type "struct date" */
d.jour=1; /* initialisation du champ "jour" de la variable "d" */
La notation pdate->jour est équivalente à (*pdate).jour (champ jour
de l'objet pointé par pdate).
Il est possible d'initialiser une structure au moment de sa déclaration, en donnant la
liste des valeurs de ses champs, de la même manière que pour un tableau. En reprenant
l'exemple précédent, au moment de déclarer la variable d, on peut écrire :
struct date d={30,02,1998};
: ce type d'initialisation n'est correct
qu'au moment de la déclaration d'une variable. Il ne peut pas être utilisé ailleurs
dans un programme.
Afin de donner une représentation de la manière dont les structures sont liées les unes aux autres dans la mémoire centrale d'un ordinateur lors de l'exécution d'un programme, on produit un graphique respectant les conventions suivantes :
Exemples :
stdin, stdout, stderr : entrée standard (clavier), sortie standard (écran) et sortie standard des erreurs (écran).
Pour forcer un affichage sur la sortie standard :
printf("affichage"); ou fprintf(stdout,"affichage");
Pour forcer une lecture sur l'entrée standard :
scanf("%d",&v); ou fscanf(stdin,"%d",&v);
Pour forcer les affichages, il peut être nécessaire de vider le buffer de sortie :
fflush(stdout);
Pour vider le buffer d'entrée et éviter la lecture d'une valeur obsolète, il peut
être nécessaire de vider le buffer d'entrée :
fflush(stdin);
Les spécificateurs de formats pour les instructions printf et scanf sont :
Attention : fseek renvoie une valeur non nulle en cas d'erreur (c'est-à-dire si on déborde du fichier).
Le préprocesseur permet entre autres :
Exemples :
#define A 1
#define max(A,B) ((A) > (B) ? (A) : (B))
...
x = max(a+b,c+d);
y = A;
...
Attention : x = max(i++,j++); incrémente deux fois i et j...
L 'opérateur # permet, dans une macro, de substituer un paramètre par sa valeur convertie en chaîne de caractères.
L'opérateur ## effectue la concaténation de deux symboles.
Il existe un ensemble de symboles prédéfinis permettant de récupérer dans un programme C des valeurs renvoyées par des "appels système" :
Pour transmettre de programme à programme l'adresse d'un sous-programme gérant une tâche particulière, on peut utiliser un pointeur de fonction. Un sous-programme n'est alors plus appelé à travers son nom, mais à travers l'adresse du code de la tâche qu'il effectue...
Exemple :
int f(...)
{
...
}
main()
{
int (*p)(...);
int i;
p=f; /* ou p=&f; */
i=f(...);
i=p(...);
i=(*p)(...);
}
L'arrêt de l'exécution d'un programme s'effectue à l'aide de l'instruction :
exit(valeur);
Par convention (avec UNIX), il est conseillé de retourner la valeur 0 lorsque
tout s'est bien passé, et une valeur non nulle lorsqu'il y a eu un problème.
La fonction exit provoque l'arrêt du programme. Il ne faut pas confondre cette
fonction ni avec break (qui sort d'un bloc), ni avec return (qui sort
d'un sous-programme en renvoyant une valeur, sans arrêt de l'exécution).
La fonction perror, d'en-tête :
void perror(const char *s)
a pour rôle de faire afficher, sur le fichier standard d'erreurs (qui est l'écran, par défaut), un message décrivant la dernière erreur rencontrée. Si le paramètre s pointe sur une chaîne de caractères non vide, alors cette chaîne est affichée juste avant le message décrivant le type de l'erreur. Sinon, le message d'erreur est affiché directement. Dans les deux cas, l'affichage est terminé par un retour à la ligne.
Le langage C permet de lancer des commandes système grâce à l'utilisation de la fonction system. Cette fonction doit être appelée avec un seul paramètre effectif, qui est une chaîne de caractères représentant la commande système requise.
Pour récupérer les paramètres passés au moment de l'appel à un programme en C, il
faut déclarer le programme principal avec deux arguments :
main(int argc,char **argv)
ou encore :
main(int argc,char *argv[])
argc sera automatiquement initialisé par le système au moment de l'appel au
nombre de termes apparaissant sur la ligne d'appel du programme (i.e. le nombre
de paramètres + 1 pour le nom du programme exécutable).
argv désignera un tableau de pointeurs vers des chaînes de caractères. Chaque chaîne contient un des termes (dans l'ordre) apparaissant sur la ligne d'appel du programme.
Ces pages ont été adaptées à partir de celles réalisées par J.D. Durou et Ph. Joly avec leur aimable autorisation.