私は現在、 "21日で自分のCを教える"という良い初心者向けの本を読んでCを学んでいます(私はすでにJavaとC#を学んだので、私はずっと速いペースで動いています)。私はポインタの章を読んでいて、->
(arrow)演算子が説明なしに出てきました。私はそれがメンバーと関数を呼び出すために使われると思います(.
(dot)演算子の同等物のように、しかしメンバーの代わりにポインターのために)。しかし、私は完全にはわかりません。
説明とコードサンプルをもらえますか。
foo->bar
は(*foo).bar
と同等です。つまり、bar
が指す構造体からfoo
というメンバーを取得します。
はい、それで終わりです。
参照ではなくポインタである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
それでおしまい!
a->b
はあらゆる意味で(*a).b
の略です(関数の場合も同様です。a->b()
は(*a).b()
の略です)。
答えに「なぜ?」を追加するだけです。
.
は、*
ポインター演算子よりも優先順位が高い標準のメンバーアクセス演算子です。
構造体の内部にアクセスしようとして*foo.bar
として記述した場合、コンパイラは 'foo'(メモリ内のアドレス)の 'bar'要素が必要だと考えます。明らかに、単なるアドレスにはメンバーがありません。
したがって、最初に(*foo)
を逆参照し、次にメンバー要素にアクセスするようにコンパイラーに要求する必要があります:(*foo).bar
、これは書くのが少し不器用なので、善人は簡単なバージョンを思い付きました:foo->bar
これはポインター演算子によるメンバーアクセスの一種です。
foo->bar
は(*foo).bar
の短縮形にすぎません。それだけです。
struct Node {
int i;
int j;
};
struct Node a, *p = &a;
ここで、i
とj
の値にアクセスするには、変数a
とポインタp
を次のように使用します。a.i
、(*p).i
およびp->i
はすべて同じです。
ここで.
は "直接セレクタ"で、->
は "間接セレクタ"です。
#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
私はそれを実行させるために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
#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;
}
->
演算子は、状況によっては*
演算子よりもコードを読みやすくします。
のような:( 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...)
。
どちらがよさそうですか?
ドットは間接参照演算子であり、構造体の特定のレコードの構造体変数を接続するために使用されます。例:
struct student
{
int s.no;
Char name [];
int age;
} s1,s2;
main()
{
s1.name;
s2.name;
}
このようにして、ドット演算子を使って構造体変数にアクセスすることができます。