F.R.I.D.A.Y.

구조체(struct) part1. default 본문

DEV/C C++

구조체(struct) part1. default

F.R.I.D.A.Y. 2020. 1. 2. 23:25
반응형

 일상생활에서 우리는 비슷한 부류끼리 그룹을 지어 관리하곤 합니다. 프로그래밍에서도 예외는 아닌데요, 오늘은 구조체에 대해 배워봅니다.


성적 관리하기

 학생의 성적을 관리하는 프로그램을 만든다고 생각해봅니다. 국/영/수/사/과 다섯 가지 항목을 관리한다고 했을 때, 우리는 변수 다섯 개가 필요함을 느낄 것입니다.

#include <stdio.h>

int main(void){
    int korean, english, math, society, science;
    scanf("%d %d %d %d %d", &korean, &english, &math, &society, &science);
    printf("국어 : %d\n", korean);
    printf("영어 : %d\n", english);
    printf("수학 : %d\n", math);
    printf("사회 : %d\n", society);
    printf("과학 : %d\n", science);
    return 0;
}

 이 프로그램은 한 명의 성적을 입력받고 출력하는 프로그램입니다. 일반적으로 한 명의 성적을 관리하려고 프로그램을 사용하지는 않습니다. 따라서 우리는 다른 방법을 찾아야 합니다.

 

 배열을 사용해볼 수 있겠습니다. 최대 100명의 성적을 받을 수 있도록 고쳐보겠습니다.

#include <stdio.h>

int main(void){
    int korean[100], english[100], math[100], society[100], science[100];
    for(int i = 0 ; i < 100; ++i){
        scanf("%d %d %d %d %d", korean + i, english + i, math + i, society + i, science + i);
        printf("국어 : %d\n", korean[i]);
        printf("영어 : %d\n", english[i]);
        printf("수학 : %d\n", math[i]);
        printf("사회 : %d\n", society[i]);
        printf("과학 : %d\n", science[i]);
    }
    return 0;
}

 이렇게 하면 100명의 성적을 받을 수는 있습니다. 그러나 이렇게 각각의 데이터를 관리하게 되면 나중에 프로그램을 수정하려고 할 때 굉장히 많은 노력이 필요할 것입니다.


구조체 - 선언하기

 그래서 나온 문법이 바로 구조체입니다. 배열이 같은 종류의 데이터를 한데 뭉쳐 놓은 것과 마찬가지로, 구조체는 분류상 같은 조상으로 나온 데이터를 한데 뭉쳐 놓는 문법입니다.

그룹 학생1 학생2 학생3 학생4 학생5
국어 AA BA CA DA EA
영어 AB BB CB DB EB
수학 AC BC CC DC EC
사회 AD BD CD DD ED
과학 AE BE CE DE EE

 이런 표가 있을 때 가로축. 즉, 과목별로 묶은 것이 배열의 방식입니다. 세로축, 학생 별로 묶은 것은 지금 배우는 구조체의 방식입니다.

 

 구조체를 선언하는 기본 문법은 다음과 같습니다.

struct person{
    unsigned      char korean;
    unsigned      char english;
    unsigned     short math;
    unsigned       int society;
    unsigned long long science;
};

 

 맨 처음 struct를 선언한 후 구조체의 이름으로 작성할 단어를 뒤이어 작성합니다. 중괄호를 이용해 멤버 변수를 작성할 수 있습니다. 이때, 닫는 중괄호 다음에 세미콜론을 꼭 작성해주어야 합니다.

 멤버 변수는 선언만 가능하고 초기화는 불가능합니다.

더보기

# Q. 초기화 코드를 작성해도 오류가 발생하지 않아요

 파일 확장자가 cpp로 되어있는지 확인해보세요. C++에서는 C++의 문법 class와 struct가 혼용될 수 있습니다. 물론 차이점은 있지만요.

 C 언어의 확장자는 c이고 C++ 언어의 확장자는 cpp(c plus plus의 약자)입니다.

 

구조체 - 사용하기

 선언을 했으면 이제 사용을 할 차례입니다. 바로 전 단락에서 선언했던 구조체는 아래와 같이 이용할 수 있습니다.

struct person p; // 변수 선언

p.korean = 50;   // 구조체 멤버 변수 사용
p.englsih = 48;
p.math = 50;
p.society = 48;
p.science = 33;

// EASTEREGG

 변수 선언 라인을 보면 세 단어로 나누어져 있습니다. 변수 선언은 [ type name; ] 형식이 되어야 하는데요. 여기에선 타입과 변수명이 이렇게 나누어집니다.

타입 변수명
struct person p

 타입이 정말 귀찮게 깁니다. 이런 경우에는 typedef 키워드를 이용해볼 수 있습니다. typedef 키워드는 다음 시간에 알아보겠습니다.

 

 다음으로, 선언을 마친 구조체 변수 아래로 연달아 멤버 변수를 초기화하는 코드가 담겨 있습니다. 이 코드들은 다음과 같이 선언과 동시에 초기화할 수 있습니다.

struct person p = {50, 48, 50, 48, 33};
// 선언과 동시에 초기화

 중괄호를 이용하면 처음 선언한 멤버 변수부터 순서대로 값을 입력해 초기화를 진행할 수 있습니다. 이 중괄호를 이용한 초기화는 선언과 동시에서만 가능하고 이후엔 불가능합니다. 배열과 같은 논리로 동작하네요.


포인터로 접근하기

# 포인터를 선행으로 알아야 합니다.

 

 우리는 종종 포인터로 구조체를 가리켜야 할 필요가 있습니다. 그럴 때는 아래처럼 작성하면 됩니다.

struct person  p;
struct person* p1 = &p;

 일반 변수를 가리키는 포인터처럼 결국 구조체의 포인터도 구조체를 가리키는 포인터에 불과합니다. 주소 연산자인 &를 추가해 대입하면 구조체 포인터 p1은 구조체 변수 p를 가리키게 됩니다.

 

 포인터를 사용하는 이유는 결국 해당 변수에 접근하기 위함입니다. 가리키기만 하고 가리킨 곳의 값을 자유자재로 이용할 수 없다면 배우지 않느니만 못합니다. 그래서 아래처럼 작성해 접근해 봤습니다.

printf("사회 점수는 %d점입니다.\n", *p1.society);

// 서식 지정자와 관련된 내용은 https://pang2h.tistory.com/200#tmlTitle-tagIndexor-3를 참고하세요.
// scanf 서식 지정자와 비슷하다고 보면 됩니다.

 포인터에서 간접 참조를 통해 본연의 값을 알아내던 것과 마찬가지로, 구조체 포인터에서도 간접 참조 연산자(*)를 이용해 접근하도록 했습니다. 그런데 컴파일이 진행되지 않습니다.

goorm ide. 다른 연산자를 권장한다

 

'연산자 우선순위에 따른 문제'

 

 이 문제가 발생한 것입니다. 잠시 연산자 우선순위 표를 보겠습니다.

 

https://docs.microsoft.com/ko-kr/cpp/c-language/precedence-and-order-of-evaluation?view=vs-2019

 노란색으로 표시된 두 연산자는 각각 *p1.society에서 (*)(.)을 담당하고 있습니다. 표에서 위에 있을수록 우선순위가 높습니다. 간접 참조 연산자(*)가 구조체 연산자(.)보다 우선순위가 낮음을 알 수 있습니다. 따라서 작성했던 코드를 우선순위를 기준으로 괄호로 묶어보면 아래와 같습니다.

 

*(p1.society)

 

 그래서 문제가 발생하는 것입니다. 아시다시피 간접 참조 연산자는 포인터 변수에서만 사용이 가능한데, int 타입의 변수(society)에 이용하려고 했으니 문제가 생기는 것입니다. 그래서 제대로 사용하기 위해서는 아래와 같이 코드를 수정해주어야 합니다.

printf("사회 점수는 %d점입니다.\n", (*p1).society);

// result : 사회 점수는 37점입니다.

 괄호는 우선순위를 무시하고 안쪽에 있는 식부터 계산하도록 하므로 우선순위가 헷갈릴 때는 정말 좋은 친구입니다. 그러나 이 경우에는 굉장히 불편한 존재가 아닐 수 없습니다. 구조체는 프로그래밍을 하다 보면 정말 많이 사용하는 문법이고, 포인터와 겸하여 사용하는 경우도 많습니다. 계속 이렇게 작성해야 할까요?

 

 아닙니다. 처음 컴파일을 진행했을 때 다른 연산자를 권유하는 메시지가 있었는데, 이 연산자를 이용하면 가능합니다.

'->' 연산자를 이용할 것을 권유하고 있다.

'->'

 

 화살표 연산자(Arrow operator)라 불리는 이 연산자는 구조체 포인터에서 접근을 용이하도록 만들어진 연산자입니다.

printf("사회 점수는 %d점입니다.\n", (*p1).society); // 간접 참조와 구조체 연산자 사용

printf("사회 점수는 %d점입니다.\n", p1->society); // 화살표 연산자 사용

 이 두 코드는 동일한 작업을 진행합니다. 괄호를 묶지 않아도 손쉽게 이게 무엇을 뜻함을 알 수 있습니다. 화살표 연산자는 구조체 포인터의 간접 참조를 돕기 위해 태어난 연산자인 만큼, 포인터가 아닌 경우에는 사용이 불가능합니다.


구조체로 성적 관리하기

#include <stdio.h>

int main(void){
    int korean[100], english[100], math[100], society[100], science[100];
    for(int i = 0 ; i < 100; ++i){
        scanf("%d %d %d %d %d", korean + i, english + i, math + i, society + i, science + i);
        printf("국어 : %d\n", korean[i]);
        printf("영어 : %d\n", english[i]);
        printf("수학 : %d\n", math[i]);
        printf("사회 : %d\n", society[i]);
        printf("과학 : %d\n", science[i]);
    }
    return 0;
}

 기존에 배열을 이용해 작성했던 코드는 이제 아래와 같이 변모할 수 있습니다.

#include <stdio.h>

struct student{
    int korean;
    int english;
    int math;
    int society;
    int science;
};

int main(void){
    struct student arr[100];
    for(int i = 0 ; i < 100; ++i){
        scanf("%d %d %d %d %d", 
            &arr[i].korean, &arr[i].englsih, &arr[i].math, &arr[i].society, &arr[i].science);
        printf("국어 : %d\n", arr[i].korean);
        printf("영어 : %d\n", arr[i].english);
        printf("수학 : %d\n", arr[i].math);
        printf("사회 : %d\n", arr[i].society);
        printf("과학 : %d\n", arr[i].science);
    }
    return 0;
}

더 읽어보기

 

구조체(struct) part2. 비트 필드

이번 시간에는 구조체에서 사용하는 비트 필드에 대해 알아봅니다. 원래 구조체를 설명하고 곧바로 시작할 생각이었는데 공용체 문법에서 먼저 나오게 되었네요 :| # 비트 필드 연산자는 공용체에서도 사용할 수..

pang2h.tistory.com

 구조체 정렬

 

[TIPS 19TH] 09 : 2018.07.24. (월)

1. 구조체 정렬 구조체를 간단히 설명하면 변수들의 집합으로 보면 된다. 그렇다면 구조체의 크기는 어떻게 될까? 구조체 안에 선언된 변수 크기의 합일까? 반은 맞고 반은 틀리다고 볼 수 있다. 시대가 발전하면..

pang2h.tistory.com

# index

728x90
반응형
Comments