C // 구조체와 사용자 정의 자료형 1
구조체 ?
구조체는 하나 이상의 변수를 묶어서 새로운 자료형을 정의하는 도구, 즉 구조체를 기반으로 우리는 새로운 자료형을 정의할 수 있다.
int xpos; // 마우스의 x 좌표
int ypos; // 마우스의 y 좌표
위의 문장들은 마우스의 위치 정보를 표현하기 때문에, 언제든 항상 함께해야한다. 그래서 이 둘을 묶어버리는 방법이 있는데 그것이 구조체이다.
struct point // point라는 이름의 구조체 정의
{
int xpos; // point 구조체를 구성하는 멤버 xpos
int ypos; // point 구조체를 구성하는 멤버 ypos
};
위의 코드가 구조체를 정의하는 코드인데 point라는 이름이 int나 double과 같은 자료형의 이름이 되는 것이다. 이는 기본 자료형이 아닌 사용자가 정의하여 만든 ' 사용자 정의 자료형 ' 이다.
ex) 사람의 이름과 나이와 전화번호
struct person // person이라는 이름의 구조체 정의
{
char name[20]; // 이름 저장을 위한 멤버
char phoneNum[20]; // 전화번호 저장을 위한 멤버
int age; // 나이 저장을 위한 멤버
};
구조체 변수의 선언방법
struct point pos; // 구조체 변수선언의 기본 형태
struct person man; // 구조체 변수선언의 기본 형태
맨 앞에 struct 선언을 추가해야 하고, 이어서 구조체의 이름과 구조체 변수의 이름을 선언해야 한다.
위처럼 구조체 변수가 선언되면, 이 둘은 각각 다음의 형태로 존재한다.
구조체에 존재하는 멤버에 접근하는 방법
구조체 변수의 이름 . 구조체 멤버의 이름
pos.xpos = 20;
구조체 변수의 멤버에 접근할 때에는 . 연산자를 사용한다.
ex) 두 점 사이의 거리 계산
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include<stdio.h> #include<math.h> struct point { int xpos; int ypos; }; int main() { struct point pos1, pos2; double distance; fputs("point1 pos: ",stdout); scanf("%d %d",&pos1.xpos, &pos1.ypos); fputs("point2 pos: ",stdout); scanf("%d %d",&pos2.xpos, &pos2.ypos); /* 두 점간의 거리 계산 공식 */ distance = sqrt((double)((pos1.xpos - pos2.xpos) * (pos1.xpos - pos1.xpos) + (pos1.ypos - pos2.ypos) * (pos1.ypos - pos2.ypos))); printf("두 점의 거리는 %g 입니다. \n",distance); return 0; } |
출력결과
point1 pos: 1 3
point2 pos: 4 5
두 점의 거리는 3.60555 입니다.
ex) person구조체
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include<stdio.h> #include<string.h> struct person { char name[20]; char phoneNum[20]; int age; }; int main() { struct person man1, man2; strcpy(man1.name, "김태현"); strcpy(man1.phoneNum, "010-1234-1234"); man1.age = 26; printf("이름 입력: "); scanf("%s", man2.name); printf("번호 입력: "); scanf("%s", man2.phoneNum); printf("나이 입력: "); scanf("%d", &man2.age); printf("이름: %s \n", man1.name); printf("번호: %s \n", man1.phoneNum); printf("나이: %d \n", man1.age); printf("이름: %s \n", man2.name); printf("번호: %s \n", man2.phoneNum); printf("나이: %d \n", man2.age); return 0; } |
출력결과
이름 입력: gorapaduk
번호 입력: 0107942-5295
나이 입력: 23
이름: 김태현
번호: 010-1234-1234
나이: 26
이름: gorapaduk
번호: 0107942-5295
나이: 23
14,15행 : name과 phoneNum은 배열이기 때문에 문자열 저장을 위해서는 strcpy함수를 호출해야 한다.
- 구조체의 멤버로 배열이 선언되면 배열의 접근방식을, 포인터 변수가 선언되면 포인터 변수의 접근방식을 취하면 된다. -
구조체를 정의함과 동시에 변수를 선언할 수도 있다.
ex)
struct point
{
int xpos;
int ypos;
} pos1, pos2, pos3; // 구조체 정의함과 동시에 변수 선언
구조체 변수를 선언과 동시에 초기화 할 수 있다.
ex)
struct point
{
int xpos;
int ypos;
}
struct person
{
char name[20];
int age;
}
int main()
{
struct point pos = {10, 20};
struct person man = {"강동원", 39};
. . . .
}
초기화 과정에서는 문자열 저장을 위해 strcpy함수를 호출하지 않아도 된다.
구조체와 배열
전화번호부를 구현하기 위해서는 여러 사람의 정보를 저장할 수 있어야 하며, 이를 위해 다수의 구조체 변수를 선언해야 한다.
다수의 구조체 변수를 선언할 때에는 구조체 배열을 선언한다.
int형 변수의 선언과 int형 배열선언의 관계
int형 변수 : int num -> int형 배열 : int arr[10]
point형 변수의 선언과 point형 배열선언의 관계
point형 변수 : struct point pos -> point형 배열 : struct point arr[10]
따라서 다음과 같이 poiint형 구조체 배열을 선언하면
struct point arr[4];
다음의 구조로 배열이 할당된다.
ex)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include<stdio.h> struct point { int xpos; int ypos; }; int main() { struct point arr[3]; int i; for(i=0;i<3;i++) { printf("점의 좌표 입력:"); scanf("%d %d",&arr[i].xpos, &arr[i].ypos); } for(i=0;i<3;i++) { printf("[%d, %d]",arr[i].xpos, arr[i].ypos); } return 0; } |
출력결과
점의 좌표 입력:3 5
점의 좌표 입력:2 4
점의 좌표 입력:1 3
[3, 5][2, 4][1, 3]
구조체 변수를 선언과 동시에 초기화할 수 있는데 중괄호를 통해 하면 가능하다.(2차원배열처럼)
struct point arr[3]={
{1, 5},
{2, 6},
{3, 7}
}
구조체 변수와 포인터
point형 구조체의 포인터 변수 선언과 초기화
struct point pos = {10, 20}; // xpos, ypos를 각각 11,12로 초기화
struct point * pptr = &pos; // 포인터 변수 pptr이 구조체 변수 pos를 가리킴
point형 포인터 변수를 이용해 구조체 변수에 접근할 때에는
(*pptr).xpos = 10; // pptr이 가리키는 구조체 변수의 멤버 xpos에 10 저장
(*pptr).ypos = 20; // pptr이 가리키는 구조체 변수의 멤버 ypos에 20 저장
위의 문장은 다음과 같이 쓸 수 있다.
pptr -> xpos = 10;
pptr -> ypos = 20;
완전 동일한 문장!
ex)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include<stdio.h> struct point { int xpos; int ypos; }; int main() { struct point pos1={1,2}; struct point pos2={100,200}; struct point * pptr=&pos1; (*pptr).xpos += 4; (*pptr).ypos += 5; printf("[%d, %d] \n", pptr->xpos,pptr->ypos); pptr=&pos2; pptr->xpos += 1; pptr->ypos += 2; printf("[%d, %d] \n", (*pptr).xpos, (*pptr).ypos); return 0; } |
출력결과
[5, 7]
[101, 202]
1. ex) 포인터 변수를 구조체의 멤버로 선언하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include<stdio.h> struct point { int xpos; int ypos; }; struct circle { double radius; struct point * center; }; int main() { struct point cen={2,7}; double rad=5.5; struct circle ring={rad,&cen}; printf("원의 반지름: %g \n",ring.radius); printf("원의 중심 [%d, %d] \n", (ring.center)->xpos, (ring.center)->ypos); return 0; } |
출력결과
원의 반지름: 5.5
원의 중심 [2, 7]
위 예제에서 선언한 구조체 변수 ring과 cen의 관계
type형 구조체 멤버로 type형 포인터 변수를 둘 수 있다.
다음과 같은 선언이 가능하다.
struct point
{
int xpos;
int ypos;
struct point * ptr; // 구조체 point의 포인터 변수 선언
}
2. ex) type형 구조체 멤버로 type형 포인터 변수를 둘 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include<stdio.h> struct point { int xpos; int ypos; struct point *ptr; }; int main() { struct point pos1 = {1, 1}; struct point pos2 = {2, 2}; struct point pos3 = {3, 3}; pos1.ptr = &pos2; // pos1과 pos2를 연결 pos2.ptr = &pos3; // pos2와 pos3을 연결 pos3.ptr = &pos1; // pos3과 pos1을 연결 printf("점의 연결관계 . . . \n"); printf("[%d, %d]와 [%d, %d] 연결 \n",pos1.xpos, pos1.ypos, pos1.ptr->xpos, pos1.ptr->ypos); printf("[%d, %d]와 [%d, %d] 연결 \n",pos2.xpos, pos2.ypos, pos2.ptr->xpos, pos2.ptr->ypos); printf("[%d, %d]와 [%d, %d] 연결 \n",pos3.xpos, pos3.ypos, pos3.ptr->xpos, pos3.ptr->ypos); return 0; } |
점의 연결관계 . . .
[1, 1]와 [2, 2] 연결
[2, 2]와 [3, 3] 연결
[3, 3]와 [1, 1] 연결
3. ex) 구조체 변수의 주소 값은 구조체 변수의 첫 번째 멤버의 주소 값과 동일하다.
struct point
{
int xpos;
int ypos;
};
int main()
{
struct point pos1 = {10, 20};
. . . .
}
위의 코드에서 &pos1과 &pos1.xpos는 동일하다. ( 구조체 변수의 주소값과 구조체 변수의 첫 번째 멤버의 주소 값은 동일하다.)