<예시>
#include<stdio.h>
struct point
{
int xpos;
int ypos;
};
int main(void)
{
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;
}
point라는 이름의 구조체를 정의하였고, 이때 point라는 이름이 int나 double과 같은 자료형의 이름이 된다. 즉 사용자 정의 자료형이라 부를 수 있다.
int xpos; int ypos; 를 구조체의 멤버라고 부른다.
다수의 int형 변수를 선언할 때 int형 배열의 선언을 고려하듯이, 다수의 구조체 변수를 선언할 때 구조체의 배열의 선언을 고려해야 한다.
struct point arr[3]; point 형 구조체 배열 선언.
첫 번째 요소의 값은 arr [0]. xpos와 arr [0]. ypos이다.
<구조체 배열의 초기화 예시>
#include<stdio.h>
struct person
{
char name[20];
char phoneNum[20];
int age;
};
int main(void)
{
struct person arr[3] = {
{"이승기","010-8989-8899",21},
{"오메가","010-1111-1111",20},
{"비타민","010-2222-2222",33}
};
int i;
for (i = 0; i < 3; i++)
printf("%s %s %d\n", arr[i].name, arr[i].phoneNum, arr[i].age);
return 0;
}
<구조체 배열의 초기화는 다음과 같이 진행해준다>
struct person arr[3] = {
{"이승기","010-8989-8899",21},
{"오메가","010-1111-1111",20},
{"비타민","010-2222-2222",33}
};
문제 22-2
#include<stdio.h>
struct employee
{
char name[10];
char num[20];
int salary;
};
int main(void)
{
struct employee arr[3];
for (int i = 0; i < 3; i++)
{
scanf("%s %s %d", arr[i].name, arr[i].num, &arr[i].salary);
}
for (int j = 0; j < 3; j++)
{
printf("%s %s %d\n", arr[j].name, arr[j].num, arr[j].salary);
}
return 0;
}
문자열을 scanf 함수를 통해 입력받을 때는 앞에 &(주소 연산자)를 붙이지 않지만, 정수를 입력받을때는 &를 앞에 붙여줘야 한다.
scanf("%s %s %d", arr[i].name, arr[i].num, &arr[i].salary);
<Struct pointer 예제>
#include<stdio.h>
struct point
{
int xpos;
int ypos;
};
int main(void)
{
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;
}
struct point* pptr = &pos1; 포인터 변수 pptr이 구조체 변수 pos1을 가리킨다.
point는 자료형과 같은 것이다. &연산자로 주솟값을 반환하는 것은 구조체 변수인 pos1이 돼야 한다.
(*pptr). xpos += 4; 현재 pptr이 pos1을 가리키므로, 이 연산은 pos1을 대상으로 한다.
pptr = &pos2; 포인터 변수 pptr이 구조체 변수 pos2를 가리키게 된다.
pptr ->xpos += 1; 현재 pptr이 pos2를 가리키므로, 이 연산은 pos2를 대상으로 한다.
해석을 하자면, pptr이 가리키는 변수의 멤버 xpos의 값을 1 증가한다.
-> 연산자는 * 연산과. 연산을 대신한 것이다.
즉, (*pptr). xpos의 의미와 pptr ->xpos 의미는 동일하다. 그러므로 훨씬 더 간결한 -> 연산자를 사용할 수 있도록 해야 한다.
<포인터 변수를 구조체의 멤버로 선언하기>
#include<stdio.h>
struct point
{
int xpos;
int ypos;
};
struct circle
{
double radius;
struct point* center;
};
int main(void)
{
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;
}
struct point* center; 구조체 point의 포인터 변수 center인데, 포인터 변수도 구조체의 멤버가 될 수 있다.
struct point cen = { 2,7 }; point라는 이름의 구조체의 구조체 변수 cen을 선언과 동시에 초기화해주었다.
struct circle ring = { rad, &cen }; 구조체 변수 ring의 멤버 center가 구조체 변수 cen을 가리키는 형태가 되었다.
앞선 예제에서 공부했듯이 struct point * center = &cen; 와 같을 꼴이 된다.
(ring.center)->xpos ring의 멤버 center가 포인터 변수이므로 ring.center를 대상으로 -> 연산을 해서, 구조체 변수 cen의 멤버에 접근해야 한다. 그리고 연산자 우선순위로 인해 -> 연산자의 왼편에 있는 소괄호는 생략이 가능하다고 한다.
<p467 예제>
#include<stdio.h>
struct point
{
int xpos;
int ypos;
struct point* ptr;
};
int main(void)
{
struct point pos1 = { 1,1 };
struct point pos2 = { 2,2 };
struct point pos3 = { 3,3 };
pos1.ptr = &pos2;
pos2.ptr = &pos3;
pos3.ptr = &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;
}
pos1.ptr = &pos2; 구조체 변수 pos1의 멤버인 포인터 변수 ptr이 pos2를 가리킨다.
pos1.ptr->xpos : pos1의 멤버 ptr이 포인터 변수이므로 pos1.ptr을 대상으로 -> 연산을 해서, pos2의 멤버에 접근한다.
왜 pos2의 멤버에 접근할까? pos1의 멤버 ptr이 pos2를 가리키고 있기 때문이다.
<구조체 변수의 주소 값과 첫 번째 멤버의 주소 값>
#include<stdio.h>
struct point
{
int xpos;
int ypos;
};
int main(void)
{
struct point pos = { 10,20 };
printf("%p %p", &pos, &pos.xpos);
return 0;
}
구조체 변수의 주소 값은 구조체 변수의 첫 번째 멤버의 주소 값과 동일하다.