• Les types numériques les plus utiles :
Type de donnée Signification Taille
(en octets)
Plage de valeurs
char caractère 1 -128 à 127
int entier 4 −2147483648 à 2147483647
float flottant (réel) 4 3.4 ∗ 10−38 à 3.4 ∗ 1038
double flottant double 8 1.7 ∗ 10−4932 à 1.7 ∗ 104932
  • Binaire - Base 2 :

Binaire Décimal
0 0
1 1
10 2
11 3
100 4
101 5
110 6
111 7
1000 8
1001 9
1010 10
... ...
11111111 255
  • Hexadécimal - Base 16

Hexadécimal Décimal
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
A 10
B 11
C 12
D 13
E 14
F 15
  • Opérateurs bit à bit :
Opérateur Signification
& ET bit à bit
| OU inclusif bit à bit
^ OU exclusif bit à bit
<< Décalage à gauche
>> Décalage à droite
~ Complément à un (opérateur unaire)

Exemple :

N/A ~ 1 donne 0
N/A ~ 0 donne 1
1 & 1 donne 1
1 & 0 donne 0
0 & 1 donne 0
0 & 0 donne 0
1 | 1 donne 1
1 | 0 donne 1
0 | 1 donne 1
0 | 0 donne 0
1 ^ 1 donne 0
1 ^ 0 donne 1
0 ^ 1 donne 1
0 ^ 0 donne 0 

  • Conversions de base de printf :
 Caractère Type de l'argument ; Type d'impression
d,i int ; nombre décimal
o int ; nombre octal non signé (non précédé d'un zéro)
x, X int ; nombre hexadécimal non signé (non précédé de 0x ou 0X, en utilisant abcdef ou ABCDEF pour 10, .... 15
u int ; nombre décimal non signé
c int ; caractère isolé
s char * ; imprime les caractères d'une chaîne jusqu'à rencontrer un '\0' ou jusqu'à avoir imprimé le nombre de caractères indiqué par la précision
f double ; notation décimale de la forme [-]m.dddddd où le nombre de d est donné par la précision (par défaut 6)
e, E double ; [-]m.dddddde±xx ou [-]m.ddddddE±xx, où le nombre de d est donné par la précision (par défaut 6)
g, G double ; équivaut à %e ou %E si l'exposant est inférieur à -4 ou supérieur ou égal à la précision ; sinon équivaut à %f. Les zéros ou u le point décimal de terminaison ne sont pas imprimés
p void * ; pointeur (représentation dépendant de l'implémentation)
% aucun argument n'est converti ; imprime un %
  • Conversions de base de scanf:
 Caractère Données en entrée ; Type de l'arguement
d entier sous forme décimale ; int *
i entier ; int *. L'entier peut être sous forme octale (précédé par un 0) ou héxadécimale (précédé par 0x ou 0X).
o entier sous forme octale (précédé ou non par un zéro) ; int *
x entier sous forme hexadécimale (précédé ou non par 0x ou 0X) ; int *.
u entier non signé sous forme décimale ; unsigned int *
c

Caractère ; char *. Les caractères suivants en entrée (par défaut un seul) sont placés dans le tableau indiqué, sans sauter les caractères d'espacement ne sont pas sautés

pour lire le prochain caractère différent d'un caractère d'espacement, il faut utiliser %1s

s chaîne de caractères (sans guillemet) ; char *, pointant sur un tableau de caractères assez grand pour contenir la chaîne et le caractère '\0' final qui lui sera ajouté.
e, f, g nombre en virgule flottante comportant éventuellement un signe, un point décimal et un exposant ; float *
% le caractère % ; ne réalise aucune affectation.
  • Pointeur générique et arithmétique de pointeur

Un pointeur générique est représenté par void *. Tout pointeur peut être converti en void * et être reconverti en son type d'origine sans perte d'informations.

Vous pouvez retrouver dans les exemples un exemple d'utilisation de pointeur générique au travers de l'implémentation du tri rapide (quick sort) avec pointeur de fonctions, proposant deux fonctions de tris distinctes : une lexicographique et l'autre numérique.

Comme les pointeurs jouent un rôle si important, le langage C soutient une série d'opérations arithmétiques sur les pointeurs que l'on ne rencontre en général que dans les langages machines. Le confort de ces opérations en C est basé sur le principe suivant:

Toutes les opérations avec les pointeurs tiennent compte automatiquement du type et de la grandeur des objets pointés.

- Affectation par un pointeur sur le même type

Soient P1 et P2 deux pointeurs sur le même type de données, alors l'instruction

P1 = P2;

fait pointer P1 sur le même objet que P2

- Addition et soustraction d'un nombre entier

Si P pointe sur l'élément A[i] d'un tableau, alors

 

P+n

pointe sur A[i+n]
  P-n pointe sur A[i-n]

- Incrémentation et décrémentation d'un pointeur

Si P pointe sur l'élément A[i] d'un tableau, alors après l'instruction

 

P++;

P pointe sur A[i+1]
  P+=n; P pointe sur A[i+n]
  P--; P pointe sur A[i-1]
  P-=n; P pointe sur A[i-n]

Domaine des opérations

L'addition, la soustraction, l'incrémentation et la décrémentation sur les pointeurs sont seulement définies à l'intérieur d'un tableau. Si l'adresse formée par le pointeur et l'indice sort du domaine du tableau, alors le résultat n'est pas défini.

Seule exception: Il est permis de 'pointer' sur le premier octet derrière un tableau (à condition que cet octet se trouve dans le même segment de mémoire que le tableau). Cette règle, introduite avec le standard ANSI-C, légalise la définition de boucles qui incrémentent le pointeur avant l'évaluation de la condition d'arrêt.

Exemples

int A[10];

 
int *P;  
P = A+9; /* dernier élément -> légal */
P = A+10; /* dernier élément + 1 -> légal */
P = A+11; /* dernier élément + 2 -> illégal */
P = A-1; /* premier élément - 1 -> illégal */

- Soustraction de deux pointeurs

Soient P1 et P2 deux pointeurs qui pointent dans le même tableau:

P1-P2

fournit le nombre de composantes comprises entre P1 et P2.

Le résultat de la soustraction P1-P2 est

 

- négatif,

si P1 précède P2
  - zéro, si P1 = P2
  - positif, si P2 precède P1
  - indéfini, si P1 et P2 ne pointent pas dans le même tableau

Plus généralement, la soustraction de deux pointeurs qui pointent dans le même tableau est équivalente à la soustraction des indices correspondants.

- Comparaison de deux pointeurs

 

On peut comparer deux pointeurs par <, >, <=, >=, ==, !=.

La comparaison de deux pointeurs qui pointent dans le même tableau est équivalente à la comparaison des indices correspondants. (Si les pointeurs ne pointent pas dans le même tableau, alors le résultat est donné par leurs positions relatives dans la mémoire).

 

  • Les structures

 

Une structure rassemble une ou plusieurs variables, qui peuvent être de types différents, que l'on regroupe sous un seul nom pour les manipuler facilement. Les structures servent à organiser des données compliquées, en particulier dans de long programmes, parce qu'elles permettent de traiter un groupe de variable liées entre elles comme un tout et non comme des entités séparées.


Exemple : Créons quelques structures appropriées au graphisme. L'objet de base est le point que nous supposerons représenté par les coordonnées x et y entières.

struct point {
    int x;
    int y;
};

Le mot-clé struct indique une déclaration de structure constituée d'une liste de déclarations entre accolades.

On peut ajouter éventuellement un nom baptisé étiquette de structure (structure tag) juste derrière le mot struct (comme point dans notre exemple). L'étiquette donne un nom à ce genre de structure et peut servir ensuite de notation abrégée pour représenter la partie de la déclaration entre accolades.

Les variables mentionnées dans une structure s'appellent des membres.

On peut initialiser une structure en faisant suivre sa définition par une liste de valeurs initiales, chacune étant une expression constante correspondant à chaque membre :

struct point maxpt = { 320, 200 };

On peut également initialiser une structure automatique par affectation ou appel à une fonction retournant une structure de type approprié.

On peut faire référence dans une expression à un membre d'une structure donnée en utilisant une construction de la forme

nom-de-structure.membre


L'opérateur "." associe le nom de la structure et le nom du membre. Par exemple, pour afficher les coordonnées du point pt, on écrira :

printf("%d,%d", pt.x, pt.y);

On peut imbriquer les structures. On peut par exemple représenter un rectangle par une paire de points désignant deux de ses coins diamétralement opposés :

 

struct rectangle {
    struct point p1;
    struct point p2;
};

La structure rectangle contient deux structures point. Si l'on déclare écran ainsi :

 

struct rectangle ecran;

alors 

ecran.pt1.x

désigne la coordonnée x du membre pt1 de ecran.

Les structures sont passées en arguments par valeur (et non par référence) comme les variables d'autres types.

Si l'on doit passer une structure de taille important en argument à une fonction, il est généralement plus efficace de lui passer un pointeur plutôt que de copier la structure entière.

Les pointeurs de structures sont semblables aux pointeurs de variables ordinaires. La déclaration :

struct point *pp;

signifie que pp est un pointeur sur une structure de type struct point. Si pp pointe sur une structure point, *pp désigne cette structure et (*pp).x et (*pp).y ses membres.

Pour utiliser pp nous pourrions écrire, par exemple,

struct point origine, *pp;

pp = &origine;
printf("l'origine est (%d,%d)\n", (*pp).x, (*pp).y);

 

Les parenthèses sont nécessaires dans (*pp).x parce que la priorité de l'opérateur "." est supérieure à celle de "*".

L'expression *pp.x est équivalente à *(pp).x, ce qui n'est pas correct ici car x n'est pas un pointeur.

Les pointeurs de structures sont si fréquemment utilisés qu'il existe une notation abrégé. Si p est un pointeur sur structure, alors : 

p->membre-de-structure


désigne le membre en question. Ainsi, nous pourrions écrire de manière équivalente

printf("l'origine est (%d,%d)\n", pp->x, pp->y);

 

Vous pouvez retrouver un exemple utilisant le type struct dans la bibliothèque thématique de programme en C. Cet exemple propose à l'aide des structures autoréférentielles une implémentation d'arbre binaire permettant de compter le nombre d'occurrences de tous les mots lus en entrée et de les trier simultanément.