NULL
?NULL
-pointer assignment » ?void *
et char *
?N
éléments consécutifs de même type.
Un pointeur est une zone mémoire qui contient l'adresse d'une
autre zone mémoire. Toutefois, dans un grand nombre de cas, tout
se passe comme si c'était la même chose.
À ce titre, il faut bien faire la différence entre a[i]
pour un tableau et ap[i]
pour un pointeur.
Voici un exemple :
char a[] = "Bonjour";
char *ap = "Au revoir";
L'expression a[3]
signifie que l'on accède aux quatrième
élément du tableau. ap[3]
signifie que l'on accède à la
zone mémoire pointée par (ap+3)
.
Autrement dit, a[3]
est l'objet situé 3 places après
a[0]
(a
est le tableau entier),
alors que ap[3]
est l'objet situé 3 places après l'objet
pointé par ap
. Dans l'exemple, a[3]
vaut
'j'
et ap[3]
vaut 'r'
.
Voir aussi la question 5.8.
N-1
dernières dimensions. Pour un tableau à deux
dimensions, la deuxième doit être connue, et la fonction doit être
déclarée ainsi :
int f1(int a[][NCOLUMNS]);
/* a est un tableau a deux dimensions (cf. remarque) */
int f2(int (*ap)[NCOLUMNS]);
/* ap est un pointeur sur un tableau */
Si elle n'est pas connue, il faut passer la taille du tableau en paramètre (ligne ET colonne) et un pointeur sur le tableau :
int f(int * a, int nrows, int ncolumns);
On accède aux éléments du tableau ainsi :
a[i * ncolumns + j] /* element de la ieme ligne
* et de la jeme colonne */
Une remarque : Dans une déclaration de paramètre
int f1(int a[][NCOLUMNS])
ou
int f1(int a[42][NCOLUMNS])
a
est un pointeur sur int[NCOLUMS]
malgré
l'écriture. La déclaration est interprétée comme
int (*a) [NCOLUMS]
Ainsi les déclarations de f1()
et f2()
dans
l'exemple initial sont exactement les mêmes.
#include <stdlib.h>
int ** a = malloc(nrows * sizeof *a );
for(i = 0; i < nrows; i++)
a[i] = malloc(ncolumns * sizeof *(a[i]));
Dans la vraie vie, le retour de malloc()
doit être
vérifié.
Une autre solution est de simuler un tableau multi-dimensions avec une seule allocation :
int *a = malloc(nrows * ncolumns * sizeof *a);
L'accès aux éléments se fait par :
a[i * ncolumns + j] /* element de la ieme ligne
* et de la jeme colonne */
typedef
, comme pour n'importe quel autre
type. Voici un exemple :
int f(char * sz); /* une fonction */
int (*pf)(char *);/* un pointeur sur une fonction */
typedef int (*pf_t)(char *);
/* un type pointeur sur fonction*/
Il est toutefois préférable de ne pas cacher le pointeur dans un
typedef
. La solution suivante est plus jolie :
typedef int (f_t)(char *); /* un type fonction */
f_t * pf; /* un pointeur sur ce type */
On l'utilise alors de cette façon :
pf = f;
int ret = pf("Merci pour cette reponse");
Voir aussi la question 5.7.
NULL
?NULL
est une macro qui représente une valeur spéciale
pour désigner un pointeur nul lorsque converti au type approprié.
Elle est définie dans <stddef.h>
ou dans
<stdio.h>
.
La valeur réelle de NULL
est dépendante de
l'implémentation, et n'est pas nécessairement un pointeur, ni de
type pointeur. Des valeurs possibles sont ((void *)0)
ou
0
.
NULL
permet de distinguer les pointeurs valides des
pointeurs invalides. Par exemple, malloc()
renvoie une
valeur comparable à NULL
quand elle échoue.
Voir aussi la question 12.3.
NULL
-pointer assignment » ?NULL
, ou oublié de tester la valeur retour d'une
fonction, avant de l'utiliser.
printf()
avec le
code de format %p
.
Le pointeur doit être d'abord casté en un pointeur
générique void *
.
char * p;
printf("Pointeur p avant initialisation: %p\n",
(void *)p);
void *
et char *
?
Avant la norme ANSI, le type void
n'existait pas. C'était
donc char *
qui était utilisé pour faire des pointeurs
génériques. Depuis la norme, ce n'est plus valide.
De nombreux programmeurs ont toutefois gardé cette habitude,
notamment dans le cast de fonctions comme
malloc()
(cf. 12.1).
faq-fclc 5/3/2002 (8h 59:04)