web-dev-qa-db-ja.com

Cでの矢印演算子( - >)の使用法

私は現在、 "21日で自分のCを教える"という良い初心者向けの本を読んでCを学んでいます(私はすでにJavaとC#を学んだので、私はずっと速いペースで動いています)。私はポインタの章を読んでいて、->(arrow)演算子が説明なしに出てきました。私はそれがメンバーと関数を呼び出すために使われると思います(.(dot)演算子の同等物のように、しかしメンバーの代わりにポインターのために)。しかし、私は完全にはわかりません。

説明とコードサンプルをもらえますか。

220
Mohit Deshpande

foo->bar(*foo).barと同等です。つまり、barが指す構造体からfooというメンバーを取得します。

409
sepp2k

はい、それで終わりです。

参照ではなくポインタであるstruct/classの要素にアクセスしたい場合は、単なるドットバージョンです。

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

それでおしまい!

113
Jack

a->bはあらゆる意味で(*a).bの略です(関数の場合も同様です。a->b()(*a).b()の略です)。

30
Peter Alexander

答えに「なぜ?」を追加するだけです。

.は、*ポインター演算子よりも優先順位が高い標準のメンバーアクセス演算子です。

構造体の内部にアクセスしようとして*foo.barとして記述した場合、コンパイラは 'foo'(メモリ内のアドレス)の 'bar'要素が必要だと考えます。明らかに、単なるアドレスにはメンバーがありません。

したがって、最初に(*foo)を逆参照し、次にメンバー要素にアクセスするようにコンパイラーに要求する必要があります:(*foo).bar、これは書くのが少し不器用なので、善人は簡単なバージョンを思い付きました:foo->barこれはポインター演算子によるメンバーアクセスの一種です。

21
Lukasz Matysiak

foo->bar(*foo).barの短縮形にすぎません。それだけです。

19
Matti Virkkunen
struct Node {
    int i;
    int j;
};
struct Node a, *p = &a;

ここで、ijの値にアクセスするには、変数aとポインタpを次のように使用します。a.i(*p).iおよびp->iはすべて同じです。

ここで.は "直接セレクタ"で、->は "間接セレクタ"です。

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);
}

出力は5 5 5

1
prashanth

私はそれを実行させるためにJackのプログラムを少し変更しなければなりませんでした。構造体ポインタpvarを宣言した後、それをvarのアドレスを指すようにしてください。この解決策は、Stephen KochanによるProgramming in Cの242ページにあります。

#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;
}

次のコマンドでこれをvimで実行します。

:!gcc -o var var.c && ./var

出力します:

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

->演算子は、状況によっては*演算子よりもコードを読みやすくします。

のような:( 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;

};

_EFI_BLOCK_IO_PROTOCOL構造体は4つの関数ポインタメンバを含みます。

変数struct _EFI_BLOCK_IO_PROTOCOL * pStructがあり、そのメンバー関数ポインタを呼び出すために古き*演算子を使用したいとします。あなたはこのようなコードで終わるでしょう:

(*pStruct).ReadBlocks(...arguments...)

しかし->演算子を使えば、次のように書くことができます。

pStruct->ReadBlocks(...arguments...)

どちらがよさそうですか?

1
smwikipedia

ドットは間接参照演算子であり、構造体の特定のレコードの構造体変数を接続するために使用されます。例:

struct student
    {
      int s.no;
      Char name [];
      int age;
    } s1,s2;

main()
    {
      s1.name;
      s2.name;
    }

このようにして、ドット演算子を使って構造体変数にアクセスすることができます。

0
divya