"21 일 안에 C를 가르치십시오"라는 책을 읽고 있습니다 (이미 Java와 C #을 배웠으므로 훨씬 빠른 속도로 움직이고 있습니다). 나는 포인터에 관한 장을 읽고 있었고 ->
(화살표) 연산자 는 설명없이 나타났습니다. 멤버와 함수를 호출하는 데 사용된다고 생각합니다 .
(점 연산자와 동일하지만 멤버 대신 포인터). 그러나 나는 완전히 확신하지 못한다.
설명과 코드 샘플을 얻을 수 있습니까?
"21 일 안에 C를 가르치십시오"라는 책을 읽고 있습니다 (이미 Java와 C #을 배웠으므로 훨씬 빠른 속도로 움직이고 있습니다). 나는 포인터에 관한 장을 읽고 있었고 ->
(화살표) 연산자 는 설명없이 나타났습니다. 멤버와 함수를 호출하는 데 사용된다고 생각합니다 .
(점 연산자와 동일하지만 멤버 대신 포인터). 그러나 나는 완전히 확신하지 못한다.
설명과 코드 샘플을 얻을 수 있습니까?
답변:
foo->bar
와 같습니다 (*foo).bar
, 그것은라는 멤버 얻을 즉 bar
그 구조체에서 foo
포인트를.
->
으면 훨씬 더 읽기 쉬운 연산자가 필요하지 않았을 것 foo*.bar
입니다. 모든 추가 괄호가있는 타입 정의 함수의 혼란은 피할 수있었습니다.
foo*.bar
과 (*foo).bar
동등 모두 foo->bar
? 무엇에 대해 Foo myFoo = *foo; myFoo.bar
?
그래 그거야.
참조 대신 포인터 인 구조체 / 클래스의 요소에 액세스하려는 경우 도트 버전 일뿐입니다.
struct foo
{
int x;
float y;
};
struct foo var;
struct foo* pvar;
pvar = malloc(sizeof(pvar));
var.x = 5;
(&var)->y = 14.3;
pvar->y = 22.4;
(*pvar).x = 6;
그게 다야!
pvar = &var
합니까?
나는 왜 "왜?"라는 답에 덧붙일 것입니다.
.
보다 높은 우선 순위를 갖는 표준 멤버 액세스 연산자입니다. *
포인터 연산자 .
구조체의 내부에 액세스하려고 할 때 *foo.bar
컴파일러는 foo의 'bar'요소 (메모리의 주소)를 원한다고 생각하며 분명히 주소에는 멤버가 없습니다.
따라서 당신은 아 파크 첫번째 역 참조로 컴파일러 요청해야 (*foo)
: 다음 멤버 요소에 액세스 (*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>
typedef struct{
int km;
int kph;
int kg;
} car;
int main(void){
car audi = {12000, 230, 760};
car *ptr = &audi;
}
여기서 포인터 는 구조 변수 ptr
의 주소 ( ! )를 가리 키지 audi
만 주소 구조 옆에도 데이터 덩어리 ( ! )가 있습니다! 데이터 청크의 첫 번째 멤버는 구조 자체와 주소가 동일하며 이와 같은 포인터 만 참조하여 데이터를 가져올 수 있습니다 *ptr
(중괄호 없음) .
첫 번째보다 다른 멤버를 ACESS하려면, 당신은 같은 부호를 추가 할 필요가 .km
, .kph
, .kg
더의 기본 주소에 오프셋보다 더 아무것도없는 데이터의 덩어리 ...
그러나의 때문에 preceedence 당신은 쓸 수 없습니다 *ptr.kg
액세스 연산자 .
참조 연산자 전에 평가 *
하고 당신은 얻을 것 *(ptr.kg)
포인터가 회원이 없습니다으로 불가능하다! 그리고 컴파일러는 이것을 알고 있으므로 다음과 같은 오류를 발생시킵니다.
error: ‘ptr’ is a pointer; did you mean to use ‘->’?
printf("%d\n", *ptr.km);
대신 당신이 이것을 사용 (*ptr).kg
하면에 컴파일러를 강제로 1 포인터 역 참조와에 ACESS 수 있도록 데이터의 덩어리 와 2 멤버를 선택하면 오프셋 (지정자)를 추가합니다.
내가 만든이 이미지를 확인하십시오.
중첩 된 멤버있을 것입니다하지만이 구문은 읽을 수 있으므로 될 것입니다 ->
도입되었다. 나는 가독성이 ptr->kg
쓰기보다 훨씬 쉽기 때문에 그것을 사용할 수있는 유일한 이유라고 생각 (*ptr).kg
합니다.
이제 연결을보다 명확하게 볼 수 있도록 다르게 작성하겠습니다. (*ptr).kg
⟹ (*&audi).kg
⟹ audi.kg
. 여기에 내가 먼저 실제로 사용 ptr
이다 "주소 audi
" , 즉 &audi
것을 사실 "참조" &
및 "역 참조" *
사업자가 서로 아웃을 취소합니다.
Jack의 프로그램을 실행하려면 약간 변경해야했습니다. 구조체 포인터 pvar을 선언 한 후 var의 주소를 가리 킵니다. C에서 Stephen Kochan 's Programming의 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
%
현재 파일 이름을 나타내는 데 사용 하십시오. 그래서처럼!gcc % && ./a.out
#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 명 함수 포인터 멤버가 포함되어 있습니다.
variable이 struct _EFI_BLOCK_IO_PROTOCOL * pStruct
있고 좋은 이전 *
연산자를 사용하여 멤버 함수 포인터를 호출 한다고 가정하십시오 . 다음과 같은 코드로 끝납니다.
(*pStruct).ReadBlocks(...arguments...)
그러나 ->
연산자를 사용하면 다음과 같이 작성할 수 있습니다.
pStruct->ReadBlocks(...arguments...)
.
어느 것이 더 좋아 보입니까?