typedef는 C언어에서 타입의 새로운 별칭을 정의하는 키워드이다.
C언어는 자료를 체계적으로 관리하기 위해 구조체라는 문법을 제공한다.
구조체는 관련 정보를 하나의 의미로 묶을 때 사용하며, struct 키워드로 정의한다.
다음은 인적 정보를 표현한 구조체인데 struct Person은 Person 구조체를 정의한다는 뜻이다.
struct Person {
char name[20]; // 이름
int age; // 나이
char address[100]; // 주소
};
아래 예제를 통해서 구조체 개념을 이해한다.
#define _CRT_SECURE_NO_WARNINGS // strcpy 보안 경고로 인한 컴파일 에러 방지 #include <stdio.h> #include <string.h> // strcpy 함수가 선언된 헤더 파일
// 구조체 선언 //typedef struct { int x, y; } Point; struct Point { int x, y; };
typedef struct _Person { // _Person 은 생략 가능(익명 구조체) char name[20]; int age; char address[100]; } Person; // 구조체 별칭을 Person으로 정의
int main() {
Point p;
p.x = 3; p.y = 4;
printf("\n (%d, %d)\n", p.x, p.y); printf(" sizeof(p) = %d\n", sizeof(p));
Person p1; // 구조체 별칭 Person으로 변수 선언 strcpy(p1.name, "홍길동"); p1.age = 30; strcpy(p1.address, "서울시 관악구 조원중앙로");
printf("\n 이름 : %s\n", p1.name); printf(" 나이 : %d\n", p1.age); printf(" 주소 : %s\n", p1.address);
// 메모리에 어떻게 저장이 되는지 확인 printf("\n sizeof(p1) = %d\n", sizeof(p1)); printf(" 이름 : %d\n", p1.name); printf(" 나이 : %d\n", &p1.age); printf(" 주소 : %d\n\n", p1.address);
return 0; }
|
위 그림에서 보면 메모리 크기는 20 bytes + 4 bytes + 100 bytes = 124 bytes
주소 표시를 %d 로 하여 메모리 공간이 연속적으로 할당되어 있음을 확인할 수 있다.
구조체 포인터
포인터가 어떤 변수의 주소를 담아서 가리키는 변수라는 것은 배웠다.
구조체를 가리키는 포인터를 구조체 포인터라고 한다.
포인터를 선언할 때 int *ptr 형식으로 선언했다. 구조체는 struct 구조체 이름 이 자료형이나 마찬가지이다.
따라서 struct Person *p1 과 같이 구조체 포인터를 선언해야 한다.
구조체 별칭을 사용하면 Person *ptr 과 같이 선언할 수 있다.
#define _CRT_SECURE_NO_WARNINGS // strcpy 보안 경고로 인한 컴파일 에러 방지 #include <stdio.h> #include <string.h> // strcpy 함수가 선언된 헤더 파일
typedef struct { char name[20]; int age; char address[100]; } Person; // 구조체 별칭
void PersonSwap(Person* a, Person* b) { Person tmp = *a; *a = *b; *b = tmp; }
int main() {
Person p1; // 구조체 별칭 Person으로 변수 선언 strcpy(p1.name, "홍길동"); p1.age = 34; strcpy(p1.address, "서울시 관악구 조원중앙로");
printf("\n 이름 : %s\n", p1.name); printf(" 나이 : %d\n", p1.age); printf(" 주소 : %s\n", p1.address);
Person *ptr1 = &p1; // 구조체 포인터 선언
printf("\n 이름 : %s\n", (*ptr1).name); // 구조체 포인터를 이용해서 값을 대입 printf(" 나이 : %d\n", (*ptr1).age); // 구조체 포인터를 사용하기 위해서는 항상 괄호를 사용해야 한다. printf(" 주소 : %s\n", (*ptr1).address);
printf("\n 이름 : %s\n", ptr1->name); // ptr1->name은 (*ptr1).name 과 동일 printf(" 나이 : %d\n", ptr1->age); printf(" 주소 : %s\n", ptr1->address);
Person p2 = {"이순신",40,"서울시 서초구 양재동"};
PersonSwap(&p1, &p2);
// swap 결과의 p1 출력 printf("\n 이름 : %s\n", ptr1->name); printf(" 나이 : %d\n", ptr1->age); printf(" 주소 : %s\n", ptr1->address);
return 0; }
|
C++ 에서는 헤더 파일이 다르고, printf 출력문을 std::cout 로 하는 것이 다르지만 기본 개념은 동일하다.
C++에서는 변수의 실제 이름 대신 사용할 수 있는 참조자(reference)라는 새로운 기능이 추가되었다.
참조자는 크기가 큰 구조체와 같은 데이터를 함수의 인수로 전달해야 할 경우에 사용할 수 있다.
또한, C++의 클래스(class)를 설계할 때에도 자주 사용된다.
int 변수이름; // 변수의 선언
int& 참조자이름 = 변수이름; // 참조자 선언, int&는 int형 변수에 대한 참조를 의미
C++ 참조변수 : https://link2me.tistory.com/1746
C++ 구조체 예제
#include <iostream> using namespace std;
struct Person { int age; double weight; char name[20]; };
int main() { cout << endl; Person p; // 구조체 변수 선언
p.age = 25; p.weight = 60; strcpy_s(p.name, "홍길동");
cout << " age : " << p.age << ", 몸무게 : " << p.weight << ", 이름 : " << p.name << endl;
Person& ref = p; // 참조변수 선언, 참조변수는 선언과 동시에 초기화되어야 한다. ref.age = 35; strcpy_s(ref.name, "이순신"); // ref.name = "이순신"; // 에러 발생 ref.weight = 75;
cout << " age : " << ref.age << ", 몸무게 : " << ref.weight << ", 이름 : " << ref.name << endl;
Person* ptr = &p; // 구조체 포인터 변수 선언 ptr->age = 20;
cout << " age : " << ptr->age << ", 몸무게 : " << ptr->weight << ", 이름 : " << ptr->name << endl;
cout << " address : " << (uintptr_t)&p << endl; cout << " address : " << (uintptr_t)&ref << endl; cout << " address : " << (uintptr_t)&ptr << endl;
return 0; } |
구조체 포인터 선언 및 동적 메모리 할당
구조체 포인터에 메모리를 할당하는 방법을 알아보자.
#define _CRT_SECURE_NO_WARNINGS // strcpy 보안 경고로 인한 컴파일 에러 방지 #include <stdio.h> #include <string.h> // strcpy 함수가 선언된 헤더 파일 #include <stdlib.h> // malloc, free, exit 함수가 선언된 헤더 파일
typedef struct { char name[20]; int age; char address[100]; } Person;
int main() {
Person* ptr = (Person*)malloc(sizeof(Person)); // 구조체 포인터 선언, 메모리 할당
// 화살표 연산자로 구조체 멤버에 접근하여 값 할당 if (ptr != NULL) { strcpy(ptr->name, "홍길동"); ptr->age = 34; strcpy(ptr->address, "서울시 관악구 조원중앙로"); } else { exit(1); // 에러시 강제 종료, exit(0) : 정상 종료 // NULL Pointer 역참조 : 일반적으로 객체가 NULL이 될 수 없다는 가정을 위반했을 때 // 발생하는 보안 취약점이다. }
// 화살표 연산자로 구조체 멤버에 접근하여 값 출력 printf("이름: %s\n", ptr->name); printf("나이: %d\n", ptr->age); printf("주소: %s\n", ptr->address);
free(ptr); // 동적 메모리 해제
return 0; }
|
마지막으로 구조체를 다 사용했다면 반드시 free 함수로 메모리를 해제해 줘야 한다.