이번에는 구조체 자료형으로도 배열을 만들 수 있다는 사실과 구조체 변수의 주소값을 포인터변수에 저장할 수 있다는 사실을 보여드리겠습니다.
먼저 우리가 구조체를 정의하고 거기에 따라 여러사람의 정보를 담는다고 해봅시다. 10명의 정보를 저장하려면 구조체변수를 10개, 100명의 정보를 저장하려면 구조체변수를 100개 선언해야하겠죠. 하지만 그 수가 커질수록 이는 번거로운 작업이 될 것입니다. 이 때에 간단하게 길이가 10이나 100인 구조체 자료형의 배열을 선언하고 거기에 구조체변수를 저장하면 됩니다.
#include <stdio.h>
void clear(void) //입력버퍼에서 "\n" 비우기 함수
{
while(getchar()!="\n")
{
}
}
struct person
{
char name[10];
int age;
char blood_type;
}
int main(void)
{
struct person arr[3];
int i=0;
// 입력 받기
for(int i=0; i<3; i++)
{
printf("arr[%d] age : ", i);
scanf("%d", &(arr[i].age));
clear();
printf("arr[%d] blood_type : ", i);
scanf("%c", &(arr[i].blood_type));
clear();
}
printf("\n");
// 배열 정보 출력
for(int i=0; i<3; i++)
{
printf("arr[%d] name : %2s, age : %2d, blood_type : %2c\n", i, arr[i].name, arr[i].age, arr[i].blood_type);
}
return 0;
}
실행결과
arr[0] name : John
arr[0] age : 20
arr[0] blood_type : A
arr[1] name : Harry
arr[1] age : 40
arr[1] blood_type : B
arr[2] name : Victor
arr[2] age : 50
arr[2] blood_type : O
arr[0] name : John, age : 20, blood_type : A
arr[1] name : Harry, age : 40, blood_type : B
arr[2] name : Victor, age : 50, blood_type : O
계속하려면 아무 키나 누르십시오 . . .
구조체 타입의 배열을 선언하고 데이터를 저장해봤습니다. int형 배열이 원소로 int형 변수들을 가지는것처럼 구조체로 정의한 person타입의 배열은 person타입의 변수들을 원소로 가집니다.
초기화 역시 배열의 선언과 동시에 할 수 있습니다.
#include <stdio.h>
struct person
{
char name[10];
int age;
char blood_type;
}
int main(void)
{
struct person arr[3] = {\{"John", 20, 'A'}, {"Harry", 41, 'B'}, {"Keynn", 32, 'O'}\};
int i=0;
for(int i=0; i<3; i++)
{
printf("arr[%d] name : %2s, age : %2d, blood_type : %2c\n", i, arr[i].name, arr[i].age, arr[i].blood_type);
}
return 0;
}
실행결과
arr[0] name : John, age : 20, blood_type : A
arr[1] name : Harry, age : 41, blood_type : B
arr[2] name : Keynn, age : 32, blood_type : O
계속하려면 아무 키나 누르십시오 . . .
구조체 타입의 배열도 기본자료형의 배열들과 별반 다르지 않습니다.
그리고 우리는 포인터를 선언할 때 int형, double형처럼 포인터형을 지정해주었고 이 포인터형이라는것은 포인터가 가르키는 변수의 자료형이고 포인터연산을 할 때 참조할 메모리공간의 크기를 알려주는 역할을 한다 했습니다. 구조체형의 포인터 역시 같습니다.
#include <stdio.h>
struct person
{
char name[10];
int age;
char blood_type;
}
int main(void)
{
struct person per1 = {"John", 20, 'B'};
struct person per2 = {"Kelly", 41, 'A'};
struct person *ptr1 = &per1;
struct person *ptr2 = &per2;
printf("%s %d %c\n", (*ptr1).name, (*ptr1).age, (*ptr1).blood_type);
printf("%s %d %c\n", (*ptr2).name, (*ptr2).age, (*ptr2).blood_type);
return 0;
}
실행결과
John 20 B
Kelly 41 A
계속하려면 아무 키나 누르십시오…
구조체의 멤버 역시 일반 변수처럼 포인터의 * 연산자를 사용해서 접근도 가능하고 데이터의 저장도 가능하다는 사실을 확인했습니다. 그리고 구조체형의 포인터변수를 다룰때에는 * 연산자와 . 연산자를 합쳐서 -> 연산자로 바꿔쓸 수 있습니다.
#include <stdio.h>
struct person
{
char name[10];
int age;
char blood_type;
}
int main(void)
{
struct person per1 = {"John", 20, 'B'};
struct person per2 = {"Kelly", 41, 'A'};
struct person *ptr1 = &per1;
struct person *ptr2 = &per2;
printf("%s %d %c\n", ptr1->name, ptr1->age, ptr1->blood_type);
printf("%s %d %c\n", ptr2->name, ptr2->age, ptr2->blood_type);
return 0;
}
실행결과
John 20 B
Kelly 41 A
계속하려면 아무 키나 누르십시오…
실행결과는 같습니다.
포인터변수가 구조체의 멤버로 선언될 수도 있습니다.
#include <stdio.h>
struct nums
{
int * a;
int * b;
};
int main(void)
{
int num1 = 10;
int num2 = 20;
struct nums myNums = {&num1, &num2};
printf("%d %d\n", *(myNums.a), *(myNums.b));
return 0;
}
실행결과
계속하려면 아무 키나 누르십시오…
구조체의 멤버인 포인터 변수에 num1과 num2의 주소값을 저장하고 *와 . 연산자를 사용해서 데이터에 접근했습니다. 이정도쯤 되면 구조체가 기본 자료형과 별반 다르지 않은 하나의 자료형이라는 것을 알 수 있습니다.
한 가지 중요한 사실이 하나 더 있습니다. 배열의 주소는 배열의 첫 번째 원소의 주소와 동일한 것 처럼, 구조체 변수의 주소값은 구조체 변수의 첫 번째 멤버의 주소와 동일하다는 사실입니다. 이를 확인하기 위해 다음 코드를 봅시다.
#include <stdio.h>
struct nums
{
int a;
int b;
struct nums * c;
}
int main(void)
{
struct nums myNums;
myNums.a = 10;
myNums.b = 20;
myNums.c = &myNums;
printf("%d %d %d\n", myNums.a, myNums.b, *(myNums.c));
return 0;
}
실행결과
10 20 10
계속하려면 아무 키나 누르십시오…
구조체를 가르키는 포인터 변수로 메모리에서 데이터를 읽었는데 10이 나왔습니다. 즉, 구조체를 가르키는 포인터 변수가 a를 가르킨다는 겁니다.
결론 : 구조체 변수의 주소값은 구조체 변수의 첫 번째 멤버의 주소값이다.
'프로그래밍 언어 > C' 카테고리의 다른 글
(C언어) 41 - 구조체의 함수 전달 (0) | 2020.05.14 |
---|---|
(C언어) 40 - typedef 선언 (0) | 2020.05.14 |
(C언어) 38 - 구조체(1) (0) | 2020.05.14 |
(C언어) 37 - 버퍼(Buffer) (0) | 2020.05.14 |
(C언어) 36 - string (0) | 2020.05.14 |