1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | typedef struct _Point { int x; int y; }Point; void main() { Point p1 = { 10, 20 }; printf("p1 : %d\n", p1); printf("p1.x : %d p1.y : %d\n", p1.x, p1.y); printf("\n"); printf("p1 : %p\n", &p1); printf("p1.x : %p p1.y : %p\n", &p1.x, &p1.y); printf("\n"); printf("p1+1 : %p\n", &p1+1); printf("p1.x+1 : %p p1.y+1 : %p\n", &p1.x+1, &p1.y+1); } | cs |
p1.x , p1.y와 같이 사용한 ' . ' (점) 연산자는
멤버(구조체 변수의 x와 y를 멤버라고 부르죠)를 접근하는 연산자입니다.
출력해보시면 아실터인데,
int형 변수 두개이기에 구조체 +1은 8바이트 증가되고,,
구조체 안의 멤버 변수에 +1을 하면 자료형의 크기인 4만큼 증가하게 됩니다.
2차원 배열 때도 설명드렸던 것 같은데,
아무리 p1와 p1.x의 주소가 같더라도 형식이 다르다는 것은 기억해주세요.
왜냐하면.... p1은 Point라는 사용자 정의형 형식이고요, p1.x는 int형이니까요...
주소는 같을지라도... 형태는 다르다!
다음 예시입니다... 구조체는 똑같으니 생략을 하도록 하겠습니다...
1 2 3 4 | Point p1 = { 10, 20 }; printf("p1.x : %d, p1.y : %d\n", p1.x, p1.y); printf("(&p1)->x : %d, (&p1)->y : %d\n", (&p1)->x, (&p1)->y); | cs |
둘은 똑같은 값이 출력됩니다.
하지만 차이점이 있죠. 위에서 언급해드린 ' . '(점) 연산자를 사용했고
하나는 '->'(화살표) 연산자를 사용했군요...
혹시나 눈치 채셨을 수도 있을텐데... 우선 각 연산자의 기능에 대해서 설명해드리자면,
.(점) 연산자 같은 경우에는 구조체의 이름으로 접근하느 방법입니다.
그렇다면, ->(화살표) 연산자는 구조체의 주소로 멤버에 접근하는 방법이라는 것이죠...
둘의 차이점을 아시겠습니까?
물론 지금 상태에서 .(점) 연산자와 -> 연산자
둘중에 하나 뭐쓸래 하면 점 연산자가 편하겠죠...
그런데말입니다... 주소 나온거보니까 뭔가 감 잡히시나요?
C언어의 꽃... 포인터... ㅋㅋㅋㅋㅋ
1 2 3 4 5 6 7 8 | Point p1 = { 10, 20 }; Point* ps = &p1; printf("p1.x : %d, p1.y : %d\n", p1.x, p1.y); printf("(&p1)->x : %d, (&p1)->y : %d\n", p1.x, p1.y); printf("ps->x : %d, ps->y : %d\n", ps->x, ps->y); printf("*(ps).x : %d, *(ps).y : %d\n", *(ps).x, *(ps).y); | cs |
결론부터 말씀드리자면... 다 같습니다...
포인터는 주소를 담는 것이죠.
p1의 주소를 담을 것인데 p1은 Point 형식이니까
그 주소를 담는 ps는 Pointer* 형이어야 한다는 것~!
그렇다면 크기는? 4 Byte죠... ps는 단지 주소를 담는 변수니까요 ㅎㅎ
구조체는 함수 블럭 안에다가 정의하더라도 전혀 문제가 되지 않습니다.
해당 구조체를 사용하기 직전에만 정의하면 되는 것이죠.
하지만 그런 경우는 없습니다. 구조체의 정의는 헤더에 만든다죠...
아무튼...
일반적으로 구조체는 지금과 같이 기초적으로 쪼금 담는 것이 아니라
데이터 형을 많이 구성해두기 때문에 크기가 어마어마합니다.
그렇기에 통째로 복사하는 경우는 별로 없습니다. 통째로 복사한다면 그것은 낭비죠...
하지만 우리는 주구장창 배운 것이 있죠.... 그거요 그거...
시작주소만 안다면 아무리 데이터가 커도 모든 데이터를 참조할 수 있는...
값을 복사하는데 비용을 줄일 수 있기에...
그래서 주소만을 보내면 됩니다. 역시 C언어의 꽃이야...
다음 코드입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | void PrintPointVal(Point pt) { printf("(%d, %d)\n", pt.x, pt.y); } void PrintPointRef(Point* ps)//참조 { printf("(%d, %d)\n", ps->x, ps->y); } void main() { Point p1 = { 10, 20 }; PrintPointVal(p1); PrintPointRef(&p1); printf("struct _Point size: %d\n", sizeof(struct _Point)); printf("Point size : %d\n", sizeof(Point)); printf("p1 size : %d\n", sizeof(p1)); printf("&p1 size : %d\n", sizeof(&p1)); } | cs |
주소를 보내는데 그렇다면 주소를 받는 함수측에서 매개변수는?
int 형을 인자로 보내면 매개변수는 int형 형식으로 받죠?
int* 형을 인자로 본내면 매개변수는 int* 형 형식으로 받죠?
그렇다면 Point 라는 사용자 정의형 형태의 인자를 보낸다면???
Point 형으로 받겠죠?!
PrintPointVal() 함수와 PrintPointRef() 함수는
각각 Point형 변수와 그 변수의 주소를 인자로 보내고 있습니다.
그리고 해당 하는 각 함수들은 Point 형 pt 매개변수와 Point*형 ps 매개변수로 받고 있습니다.
위의 설명을 이해하셨다면.... 패스하겠습니다...
다음으로 size를 구하고 있습니다.
위에서부터 차례대로 원 구조체의 이름, typedef된 구조체 그리고 구조체 변수...
모두 같은 형이죠? 그러니 모두 8바이트가 출력되게 됩니다.
하지만 &p1 즉 구조체 주소의 크기는 4 바이트가 출력된다는 거~
똑같은 구조체를 사용하고 있는 다른 예제도 살펴보도록 합시다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | PrintPoint(Point ps[]) { printf("(%d, %d)\n", ps->x, ps->y); } void PrintPointArray(Point arr[], int size) { int i; for (i = 0; i < size; ++i) PrintPoint(&arr[i]); } void main() { Point arr[3] = { { 1, 2 }, { 2, 2 }, { 3, 3 } }; Point p1 = { 10, 20 }; PrintPointArray(arr, 3); PrintPointArray(&p1, 1); } | cs |
Point arr[3]가 의미하는 것은 뭘까요?
다를 바 없습니다. Point 형 데이터를 연속적으로 3개 가지고 있군요.
arr이라는 배열 안에 Point 형 구조체가 3개 있어요!
별거 없습니다. int, char 와 같은 자료형이 구조체 Point 형으로 바뀐것이에요!
연산자 *와 []는 같은 기능을 하고 있다고 했죠...
Point arr[]는 Point* arr 로 바꿔서 사용할 수 있습니다.
아무튼... 자료형을 알고 있으니... 해석하는데는 무리가 없을듯 합니다...
arr은 배열의 이름으로 시작주소를 의미하니 매개변수의 형태와 맞구...
두번째 함수 호출때에는 변수의 주소값을 보내니 문제가 없습니다.
'삽질의 현장 > - C' 카테고리의 다른 글
곱씹어보자 C!_#023_삽잡이의 두서없이 막말하는 지금까지 응용 예제 (0) | 2015.06.30 |
---|---|
곱씹어보자 C!_#022_삽잡이의 두서없이 막말하는 구조체 예시_둘 (0) | 2015.06.28 |
곱씹어보자 C!_#020_삽잡이의 두서없이 막말하는 구조체를 사용해볼까 (0) | 2015.06.28 |
곱씹어보자 C!_#019_삽잡이의 두서없이 막말하는 구조체 사용 이유 (0) | 2015.06.28 |
곱씹어보자 C!_#018_삽잡이의 두서없이 막말하는 잡다한 것들... (0) | 2015.06.27 |