J'apprends actuellement le C en lisant un livre pour débutant intitulé "Apprenez-vous le C en 21 jours" (j'ai déjà appris Java et le C #, donc je vais beaucoup plus vite). Je lisais le chapitre sur les pointeurs et le ->
(flèche) opérateur est apparu sans explication. Je pense qu'il est utilisé pour appeler des membres et des fonctions (comme l'équivalent de l'opérateur .
(point), mais pour les pointeurs au lieu des membres). Mais je ne suis pas tout à fait sûr.
Puis-je obtenir une explication et un exemple de code?
foo->bar
est équivalent à (*foo).bar
, c'est-à-dire qu'il obtient le membre appelé bar
à partir de la structure vers laquelle pointe foo
.
Oui c'est ça.
C'est juste la version avec points lorsque vous voulez accéder aux éléments d'une structure/classe qui est un pointeur au lieu d'une référence.
struct foo
{
int x; // 5
float y;
};
struct foo var;
struct foo* pvar;
pvar = malloc(sizeof(pvar));
var.x = 5; // var.x is 5
(&var)->y = 14.3;
pvar->y = 22.4;
(*pvar).x = 6; // (*pvar).x is 5
C'est ça!
a->b
est simplement l'abréviation de (*a).b
dans tous les sens (de même pour les fonctions: a->b()
est l'abréviation de (*a).b()
).
Je voudrais juste ajouter aux réponses le "pourquoi?".
.
est un opérateur d'accès membre standard dont la priorité est supérieure à celle de *
opérateur de pointeur.
Lorsque vous essayez d'accéder aux éléments internes d'une structure et que vous l'écrivez sous la forme *foo.bar
, le compilateur pense alors qu'il doit vouloir un élément 'bar' de 'foo' (qui est une adresse en mémoire) et, évidemment, cette simple adresse ne avoir des membres.
Ainsi, vous devez demander au compilateur de déréférencer d’abord avec (*foo)
puis d’accéder à l’élément member: (*foo).bar
, ce qui est un peu maladroit à écrire pour que les plus expérimentés en aient une version abrégée: foo->bar
qui est une sorte d'accès membre par opérateur de pointeur.
foo->bar
n'est qu'un raccourci pour (*foo).bar
. C'est tout ce qu'on peut en dire.
struct Node {
int i;
int j;
};
struct Node a, *p = &a;
Ici, pour accéder aux valeurs de i
et j
, nous pouvons utiliser la variable a
et le pointeur p
comme suit: a.i
, (*p).i
et p->i
sont tous identiques.
Ici .
est un "sélecteur direct" et ->
est un "sélecteur indirect".
#include<stdio.h>
struct examp{
int number;
};
struct examp a,*b=&a;`enter code here`
main()
{
a.number=5;
/* a.number,b->number,(*b).number produces same output. b->number is mostly used in linked list*/
printf("%d \n %d \n %d",a.number,b->number,(*b).number);
}
la sortie est 5 5 5
Je devais apporter un petit changement au programme de Jack pour le faire fonctionner. Après avoir déclaré le pointeur struct pvar, pointez-le sur l'adresse de var. J'ai trouvé cette solution à la page 242 de la Programmation de Stephen Kochan en C.
#include <stdio.h>
int main()
{
struct foo
{
int x;
float y;
};
struct foo var;
struct foo* pvar;
pvar = &var;
var.x = 5;
(&var)->y = 14.3;
printf("%i - %.02f\n", var.x, (&var)->y);
pvar->x = 6;
pvar->y = 22.4;
printf("%i - %.02f\n", pvar->x, pvar->y);
return 0;
}
Exécutez ceci dans vim avec la commande suivante:
:!gcc -o var var.c && ./var
Est-ce que la sortie:
5 - 14.30
6 - 22.40
#include<stdio.h>
int main()
{
struct foo
{
int x;
float y;
} var1;
struct foo var;
struct foo* pvar;
pvar = &var1;
/* if pvar = &var; it directly
takes values stored in var, and if give
new > values like pvar->x = 6; pvar->y = 22.4;
it modifies the values of var
object..so better to give new reference. */
var.x = 5;
(&var)->y = 14.3;
printf("%i - %.02f\n", var.x, (&var)->y);
pvar->x = 6;
pvar->y = 22.4;
printf("%i - %.02f\n", pvar->x, pvar->y);
return 0;
}
L'opérateur ->
rend le code plus lisible que l'opérateur *
dans certaines situations.
Tels que: (cité d'après le projet EDK II )
typedef
EFI_STATUS
(EFIAPI *EFI_BLOCK_READ)(
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
);
struct _EFI_BLOCK_IO_PROTOCOL {
///
/// The revision to which the block IO interface adheres. All future
/// revisions must be backwards compatible. If a future version is not
/// back wards compatible, it is not the same GUID.
///
UINT64 Revision;
///
/// Pointer to the EFI_BLOCK_IO_MEDIA data for this device.
///
EFI_BLOCK_IO_MEDIA *Media;
EFI_BLOCK_RESET Reset;
EFI_BLOCK_READ ReadBlocks;
EFI_BLOCK_WRITE WriteBlocks;
EFI_BLOCK_FLUSH FlushBlocks;
};
La structure _EFI_BLOCK_IO_PROTOCOL
contient 4 membres de pointeur de fonction.
Supposons que vous ayez une variable struct _EFI_BLOCK_IO_PROTOCOL * pStruct
et que vous souhaitiez utiliser le bon vieil opérateur *
pour appeler le pointeur de sa fonction membre. Vous allez vous retrouver avec un code comme celui-ci:
(*pStruct).ReadBlocks(...arguments...)
Mais avec l'opérateur ->
, vous pouvez écrire comme ceci:
pStruct->ReadBlocks(...arguments...)
.
Qui a l'air mieux?
Dot est un opérateur de déréférence utilisé pour connecter la variable de structure à un enregistrement de structure particulier. Par exemple :
struct student
{
int s.no;
Char name [];
int age;
} s1,s2;
main()
{
s1.name;
s2.name;
}
De cette manière, nous pouvons utiliser un opérateur de point pour accéder à la variable de structure