도트연산자와 ( . ) 화살표연산자 ( -> ) 모두 접근이라는 의미로 사용된다.
처음부터 다루어보자.
구조체란 여러 자료형이 모여 하나의 큰 사용자 정의 자료형을 구성한 것이다.
여기서 우리가 구조체를 정의한다는 것은 어떤 의미일까?
바로 Stack 영역에 구조체의 크기만큼 공간을 할당받는 것이다.
그럼 여러 개의 구조체가 필요한 상황에서 구조체마다 각각 할당을 받아버리면? Stack 영역은 꽉 차버리는 상황이 발생한다. (그래서 우리는 malloc() 함수를 통해 임의로 메모리 공간을 Heap 영역에 할당받고, 우리가 다 사용하면 free() 함수로 메모리 해제를 시키는 게 좋은 최적화를 도모할 수 있는 방법이다.)
구조체 포인터를 생성할 때는 일반 포인터 변수를 생성할 때와 동일하게 * 참조 연산자를 생성 시에 변수명 앞에 위치시키면 된다.
그리고 우리는 Heap 영역에 우리가 필요한 만큼, 구조체의 크기만큼 생성을 할 것이니 malloc 으로 구조체 크기만큼 size를 지정해서 생성과 할당을 진행할 수 있다.
struct 구조체이름 * 포인터이름 = malloc(sizeof(struct 구조체이름));
위에서 생성과 할당을 했으니 실질적으로 구조체 포인터가 가리키는 주소에 데이터를 추가해야 한다.
구조체 포인터가 가리키는 주소에 데이터를 할당하기 위해 화살표 연산을 사용할 수 있다.
화살표 연산은 구조체 포인터 안의 변수에, 즉 멤버 변수에 쉽게 접근할 수 있도록 한다.
포인터이름->멤버변수이름 = 값
위와 같은 형태로 화살표 연산자를 사용해 값을 할당할 수 있다.
정리하자면,
그런데 여기서 만약 화살표 연산자를 이용하지 않을 경우에는 괄호와 역참조를 이용해서도 할당할 수 있다. 이는 아래와 같은 형태일 것이다.
(*포인터이름).멤버변수이름 = 값
그러니까 다시 정리하면,
아래 예시의 코드를 보자.
#include <stdio.h>
struct posTag {
int x;
int y;
};
int main()
{
struct posTag a = {1, 2};
struct posTag *pa = &a;
printf("pa->x = %d, (*pa).x = %d\n", pa->x, (*pa).x);
printf("pa->y = %d, (*pa).y = %d\n", pa->y, (*pa).y);
return 0;
}
위 코드에서 두 printf 함수가 반환하는 값은 동일하다.
고로, 우리는
- .(도트) 는 클래스의 멤버를 직접적으로 접근한다.
- ->(화살표) 는 포인터를 통해 멤버를 간접적으로 접근한다.
- 즉 a->b 는 (*a).b 와 동일하다.
ip[i].name == (*(lp+i)).name == (lp+i)->name
보통은 도트연산자 ( . )를 사용해서 맴버에 접근하지만,
구조체 포인터의 맴버에 접근할 때는 화살표로 접근해야 한다.
는 것을 알 수 있다.