web-dev-qa-db-fra.com

Utilisation de l'opérateur Arrow (->) en C

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?

234
Mohit Deshpande

foo->bar est équivalent à (*foo).bar, c'est-à-dire qu'il obtient le membre appelé bar à partir de la structure vers laquelle pointe foo.

426
sepp2k

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!

116
Jack

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()).

30
Peter Alexander

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.

21
Lukasz Matysiak

foo->bar n'est qu'un raccourci pour (*foo).bar. C'est tout ce qu'on peut en dire.

19
Matti Virkkunen
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".

10
Jayghosh Wankar
#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

1
prashanth

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
1
Rich Vogt
#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;
}
1
Gopal Rao

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?

1
smwikipedia

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

0
divya