본문 바로가기
C/코딩도장

[코딩도장] Unit 49. 구조체 포인터 사용하기

by 단월໒꒱ 2021. 8. 15.

1. 구조체 포인터 사용하기

구조체는 멤버 변수가 여러 개 들어있어서 크기가 큰 편이다.

따라서 구조체 변수를 하나하나 선언해서 사용하는 것보다 포인터에 메모리를 할당해서 사용하는 것이 더 효율적이다.

함수를 만들어서 구조체를 사용할 때 포인터를 자주 활용한다.

 

2. 구조체 포인터를 선언하고 메모리 할당하기

다른 자료형과 마찬가지로 구조체도 포인터를 선언할 수 있다.

구조체 포인터에서도 동적 메모리를 할당할 때 malloc 함수를 사용한다.

구조체 포인터 선언 형식은 아래와 같다.

 

struct 구조체이름 *포인터이름 = malloc(sizeof(struct 구조체이름));

 

 

 

구조체 포인터를 선언할 때 struct 키워드와 구조체 이름을 사용하고 포인터 변수이므로 *를 꼭 붙여준다.

메모리 할당 시 sizeof(struct 구조체이름)의 형식으로 할당할 메모리의 크기를 구해준다.

위의 상황처럼 일반적인 상황에서 구조체 이름 앞에는 반드시 struct를 붙여준다.

 

이전에 구조체의 멤버에 접근하는 방법과 달리, 구조체 포인터의 멤버에 접근할 때는 화살표 연산자(->)를 사용한다.

마찬가지로 구조체 포인터의 멤버에 값을 할당할 때, 문자열의 경우 strcpy 함수를 이용해준다.

 

3. 구조체 포인터에서 .으로 멤버에 접근하기

위에서 구조체 포인터에서 멤버에 접근하려면 화살표 연산자를 사용한다고 했다.

그 외에 괄호와 역참조를 사용하면 점(.)을 이용해서도 멤버에 접근할 수 있다.

 

p1->age;

(*p1).age;

 

위의 두 줄은 같은 내용을 뜻하는데, 이처럼 구조체를 역참조하면 점으로 멤버에 접근 할 수 있다.

 

4. 구조체의 멤버가 포인터일 때 역참조하기

구조체의 멤버가 포인터일 때 역참조하려면 맨 앞에 *를 붙이면 된다.

이때, 구조체 변수 앞에 *가 붙어있더라도 이것은 멤버의 역참조이지 구조체 변수의 역참조가 아니다.

 

*구조체변수.멤버

*구조체포인터->멤버

 

위의 내용을 그림으로 표현하면 아래와 같다.

 

 

다르게 표현할 수도 있다.

역참조한 것을 괄호로 묶는 것은 구조체 변수를 역참조한 뒤 멤버에 접근한다는 뜻이다.

 

(*구조체포인터).멤버

*(*구조체포인터).멤버

 

위의 내용을 그림으로 표현하면 아래와 같다.

 

 

구조체 포인터를 역참조한 뒤 괄호로 묶으면 -> 연산자에서 . 연산자를 사용하게 되므로 포인터가 일반 변수로 바뀐다.

 

5. 구조체 별칭으로 포인터를 선언하고 메모리 할당하기

typedef로 정의한 구조체 별칭으로 포인터를 선언하고 메모리를 할당할 수 있다.

구조체 별칭으로 포인터를 선언하는 형식은 아래와 같다.

 

구조체별칭 *포인터이름 = malloc(sizeof(구조체별칭));

 

 

 

이처럼 구조체 별칭을 사용하면 struct 키워드가 생략되었을 뿐인데도 포인터를 선언하고 메모리를 할당하는 방법이 더 간단해진다.

구조체 별칭 사용시 malloc 함수로 메모리를 할당할 때, 할당할 메모리 크기는 sizeof(구조체별칭)으로 구해준다.

구조체 별칭으로 선언한 포인터도 구조체 멤버에 접근할 때 화살표 연산자를 사용한다.

 

6. 익명 구조체 사용하고 메모리 할당하기

typedef struct 뒤에 구조체 이름을 삭제하면 익명 구조체가 되는데, 익명 구조체도 실제로 사용하려면 별칭을 지정해줘야 하니까 메모리 할당 방법은 5번에서 설명한 내용과 같다.

 

7. 구조체 포인터에 구조체 변수의 주소 할당하기

구조체 변수에 주소 연산자(&)를 사용하면 동적 메모리를 할당하지 않고 구조체 포인터를 사용할 수 있다.

구조체 변수의 주소를 구하여 구조체 포인터에 할당하는 형식은 아래와 같다.

 

구조체포인터 = &구조체변수;

 

 

 

위의 코드처럼 구조체 변수는 주소 연산자 &를 이용해서 메모리 주소를 구할 수 있고, 이렇게 구한 메모리 주소는 구조체 포인터에 할당할 수 있다.

여기서 구조체 변수의 멤버와 구조체 포인터의 멤버를 출력했더니 같은 값이 나오는데, 이는 둘이 접근 방식만 다를 뿐 같은 곳의 내용을 가리키기 때문이다.

 

구조체 변수의 메모리 주소를 구조체 포인터에 할당하는 방법을 그림으로 나타내면 아래와 같다.

 

 

예를 들어, 위의 그림대로 구조체 변수 p1의 주소가 0x0029FC08이라면 주소 연산자로 메모리 주소를 구해서 ptr에 저장하면 ptr이 p1을 가리키게 된다.

그래서 ptr로 age에 접근하면 p1의 age가 바뀌게 된다.

 

 

# 퀴즈

1. Person 구조체 포인터 p1에 메모리를 할당하려고 합니다. 올바른 코드를 고르세요.

   답  ->  4. struct Person *p1 = malloc(sizeof(struct Person));

 

2. 다음 중 구조체 포인터 p1의 멤버 x에 접근하는 방법으로 올바른 것을 고르세요.

   답  ->  d. p1->x

 

3. 다음 중 구조체 포인터 ptr에 구조체 변수 p1의 주소를 할당하는 방법으로 올바른 것을 고르세요.

   답  ->  d. struct Person *ptr = &p1;

 

 

# 연습문제 1 : 학생 구조체 포인터에 메모리 할당하기

[문제]

 

[코드 및 결과]

 

 

[설명]

s1 앞에 *가 붙어있으므로 s1은 구조체 포인터이다.

따라서 구조체 크기만큼 메모리를 할당해야하므로 sizeof 함수를 통해 구조체 크기를 구하고 malloc 함수를 사용하여 메모리를 할당한다.

나머지는 학생 정보에 대한 내용이므로 화살표 연산자를 통해 각 구조체 멤버에 접근하여 값을 넣어준다.

 

 

# 연습문제 2 : 3차원 좌표 구조체 포인터에 메모리 할당하기

[문제]

 

[코드 및 결과]

 

 

[설명]

struct 앞에 typedef가 있고 Point3D라는 구조체 별칭이 있으므로 메모리를 할당할 때에도 sizeof 함수 안에서 struct를 떼고 구조체 별칭만을 넣어서 그 크기만큼 메모리를 할당해준다.

실행 결과처럼 나와야하고 각 구조체 멤버들의 자료형이 float이므로 각 멤버들에 실수형으로 10.0f, 20.0f, 30.0f이란 값을 저장한다.

 

 

# 연습문제 3 : 구조체 포인터에 구조체 주소 할당하기

[문제]

 

[코드 및 결과]

 

 

[설명]

ptr에 화살표 연산자를 이용해서 구조체 멤버 limited에 접근하고 있으므로 ptr은 구조체 포인터임을 알 수 있다.

따라서 struct Item *ptr; 형식으로 구조체 포인터를 선언해준다.

코드를 보면 item1에 false의 값이 주어져있는데, 실행 결과대로 한정판을 출력하려면 true라는 값이 들어가야 한다.

17번째 줄에서 ptr->limited = true;를 통해서 true의 값을 저장했고 한정판을 출력하는 결과가 나왔으므로 17번째 줄을 통해 false란 값이 true라는 값으로 변했음을 알 수 있다.

그러므로 ptr을 통해 item1에 저장된 값도 바꾸기 위해서는 & 연산자를 이용해서 ptr에 item1의 주소를 할당해야 한다.

 

 

# 심사문제 1 : 사람과 자동차 구조체 포인터에 메모리 할당하기

[문제]

 

[코드 및 결과]

 

 

[설명]

아래의 printf 함수를 보면 p1과 c1 모두 ->를 통해 접근하고 있으므로 p1과 c1은 구조체 포인터임을 알 수 있다.

Person은 일반적인 구조체이고 Car은 구조체 별칭을 사용하고 있는 상태이다.

따라서 p1은 struct를 사용해서 포인터를 선언하고 메모리를 할당해주고, c1은 구조체 별칭으로 포인터를 선언하고 메모리를 할당해준다.

남은 내용들은 출력 결과를 참고하여 각각에 맞는 값들을 저장해주고 문자열의 경우 strcpy 함수를 통해 내용을 저장해준다.

 

 

# 심사문제 2 : 구조체 포인터에 구조체 변수의 주소 할당하기

[문제]

 

[코드 및 결과]

 

 

[설명]

주어진 코드를 보면 p1에만 값이 입력되어 있는데, 아래의 printf 함수에서는 ->를 통해 ptr로 구조체 멤버의 값을 출력하고 있다.

구조체 포인터로 선언된 ptr로 구조체 변수 p1의 값을 출력하기 위해서는 ptr에 p1의 주소를 할당해줘야 한다.

따라서 & 연산자를 이용해서 주소를 할당하도록 해준다.

 

 

 

댓글