초보 해커를 위한 C언어와 동작 원리/Ch2. Programming

구조체

anonkorea4869 2025. 4. 23. 00:34

학습 목표

! 내용은 검토 포스트 입니다. 부정학한 내용이 있을 있으니 양해바랍니다.

  • 구조체의 사용 방법을 학습한다.

1. 구조체

구조체는 관련된 변수를 하나의 자료형으로 만들어 보관하는 것이다. 예를 들어 사람의 정보인 이름, 나이, 학과를 저장할 때 모두 다른 변수로 저장해도 되지만 묶어서 저장하면 더욱 효율적이다. 아래 코드는 구조체를 선언하는 방법이다. 구조체 명으로는 흔히 Pascal case로 맨앞글자만 대문자로 작성한다.

struct 구조체명 {
    자료형 변수명;
    ...
    자료형 변수명;
};
struct Info {
    char name[20];
    int age;
    char major[20];
};

2. 구조체 변수 선언

만들어진 구조체 사용하여 변수를 선언해보겠다. 아래 코드에서는 struct Info가 자료형이고 이에 해당하는 person 구조체 변수를 생성하였다. name, age, major 변수는 person 변수의 멤버(member)라고 한다.

#include <stdio.h>

struct Info {
    char name[20];
    int age;
    char major[20];
};

int main(void) {
    struct Info person;

    return 0;
}

구조체를 선언함과 동시에 전역 변수를 생성 할 수 있다. 구조체 아래에 원하는 변수명을 , 로 구분하여 작성해주면 된다.

#include <stdio.h>

struct Info {
    char name[20];
    int age;
    char major[20];
} person;
#include <stdio.h>

struct Info {
    char name[20];
    int age;
    char major[20];
} person1, person2;

2.1. 자료형 별칭

typedef는 기존의 자료형에 새로운 별칭을 붙여주는 것입니다. 아래 코드는 int 자료형을 INT로 별칭을 붙여주고 변수를 생성하는 코드입니다.

#include <stdio.h>

typedef int INT;

int main(void) {
    INT age = 25;

    printf("%d", age);

    return 0;
}

typedef를 활용해 긴 구조체 자료형을 줄일 수 도 있습니다. 보통 상수처럼 모든 문자를 대문자로 작성하고 단어와 단어 사이에는 언더바로 구분합니다.

#include <stdio.h>

struct Info {
    char name[20];
    int age;
    char major[20];
};

typedef struct Info INFO;

int main(void) {
    INFO person;

    return 0;
}

이를 더욱 줄여서 아래 코드와 같이 구조체 선언과 동시에 자료형을 축약할 수 있습니다. 구조체 하단의 INFO는 변수가 아닌 자료형입니다.

#include <stdio.h>

typedef struct {
    char name[20];
    int age;
    char major[20];
} INFO;

int main(void) {
    INFO person;

    return 0;
}

3. 구조체 변수 초기화

구조체 변수를 초기화 하는 방법에는 2가지가 있다. 변수 선언과 동시에 초기화 하는 것이고, 두번째는 변수 선언 후 초기화 하는 것이다.

3.1. 선언과 동시에 초기화

선언과 동시에 초기화 하는 방법은 아래 코드와 같이 중괄호 사이에 값을 차례 대로 넣어주면 된다.

#include <stdio.h>

typedef struct {
    char name[20];
    int age;
    char major[20];
} INFO;

int main(void) {
    INFO person = {"daehun", "25", "SW"};

    return 0;
}

만약 중괄호를 비워놓거나 일부 멤버의 값만 넣었을 경우 나머지 멤버에는 0이 들어가게 된다. 마찬가지로 배열의 모든 공간에도 0이 들어간다.

#include <stdio.h>

typedef struct {
    char name[20];
    int age;
    char major[20];
} INFO;

int main(void) {
    INFO person = {};

    return 0;
}

3.2. 선언 후 초기화

선언 후 초기화는 변수명.맴버명 에 대입연산을 하여 초기화 한다. 다만 문자열의 경우 strcpy 같은 문자열 함수를 사용하여 초기화하여야한다. 대입연산을 통해 초기화하지 않은 변수들은 쓰레기 값이 들어간다.

#include <stdio.h>
#include <string.h>

typedef struct {
    char name[20];
    int age;
    char major[20];
} INFO;

int main(void) {
    INFO person;

    strcpy(person.name, "daehun");
    person.age = 25;
    strcpy(person.major, "SW");

    return 0;
}

4. 멤버 사용

멤버 출력등 사용하는 방법은 어렵지 않다. 초기화 때 처럼 변수명.멤버명으로 출력할 수 있다.

#include <stdio.h>

typedef struct {
    char name[20];
    int age;
    char major[20];
} INFO;

int main(void) {
    INFO person = {"daehun", 25, "SW"};

    printf("%s %d %s", person.name, person.age, person.major); // daehun 25 SW

    return 0;
}

5. Call-by-reference

구조체를 변수를 Call-by-reference하여 사용해야할 경우가 있다. 당연하지만 아래 코드는 Call-by-value로 main 함수의 person 변수의 age 변수는 바뀌지 않는다.

#include <stdio.h>

typedef struct {
    char name[20];
    int age;
    char major[20];
} INFO;

void changeInfo(INFO person) {
    person.age = 10;

    printf("changeInfo : %s %d %s\n", person.name, person.age, person.major);
    // changeInfo : daehun 10 SW
}

int main(void) {
    INFO person = {"daehun", 25, "SW"};

    changeInfo(person);

    printf("main : %s %d %s\n", person.name, person.age, person.major);
    // main : daehun 25 SW

    return 0;
}

아래 코드 처럼 Call-by-reference 기법을 활용하여 (*변수명).멤버명으로 값을 바꿀 수 있다.

#include <stdio

typedef struct {
    char name[20];
    int age;
    char major[20];
} INFO;

void changeInfo(INFO *person) {
    (*person).age = 10;

    printf("changeInfo : %s %d %s\n", (*person).name, (*person).age, (*person).major);
        // main : daehun 10 SW
}

int main(void) {
    INFO person = {"daehun", 25, "SW"};

    changeInfo(&person);

    printf("main : %s %d %s\n", person.name, person.age, person.major);
        // main : daehun 10 SW
    return 0;
}

(*변수명).멤버명을 다르게 표현하여 변수명 → 멤버명으로도 값을 바꿀수 있다. 보통 → 를 많이 사용한다.

#include <stdio.

typedef struct {
    char name[20];
    int age;
    char major[20];
} INFO;

void changeInfo(INFO *person) {
    person->age = 10;

    printf("changeInfo : %s %d %s\n", person->name, person->age, person->major);
}

int main(void) {
    INFO person = {"daehun", 25, "SW"};

    changeInfo(&person);

    printf("main : %s %d %s\n", person.name, person.age, person.major);

    return 0;
}

6. PE 구조

Window OS의 실행파일은 PE(Portable Executable) 구조를 가진다. PE 구조에는 실행파일의 실행코드와 실행코드를 실행하기위한 환경등이 기술되어있다. PE구조는 구조체로 멤버들을 관리하고 있는데, 헤더와 섹션의 하위 변수들은 모두 구조체로 구조체안에 구조체 등 복잡한 구조를 가지고 있습니다. 아래 사진 중 색깔로 하이라이트 된 부분은 모두 멤버입니다.

출처 : https://onlyf8.com/pe-format

참고할 만한 사이트

아래 사이트는 매우 유명한 reversecore 작가의 ‘리버싱 핵심원리’의 참고 사이트이다.

PE(Portable Executable) File Format (1) - PE Header

'초보 해커를 위한 C언어와 동작 원리 > Ch2. Programming' 카테고리의 다른 글

동적 할당  (0) 2025.04.23
문자열 함수  (0) 2025.04.23
함수  (0) 2025.04.23
배열과 포인터  (2) 2025.04.22
포인터  (0) 2025.04.22