728x90

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 함수로 메모리를 해제해 줘야 한다.



728x90
블로그 이미지

Link2Me

,