본문 바로가기
[ CODING STUDY ]/》C언어 공부

C언어 19장(구조체, 공용체, 열거형)

by MRG 2020. 5. 18.
728x90
반응형

▣ 안녕하세요^^ 
저번장까지 포인터와 메모리를 공부했습니다.
숙제랑 잘하고 계시죠??
꼭 하셔야 합니다. 
눈으로만 읽고 끝나면 아무것도 못하게 됩니다. -_-
저도 그랬습니다. ^^;;
직접 해보시고 많이 틀려봐야
코딩 실력이 늘어납니다. ^^
꼭 해보세요.


그리고 포인터와 함수, 배열에 활용은
계속 장 하나하나를 배우면서 익혀보도록 하겠습니다.


▣ 그럼 오늘은 구조체와 공용체 그리고 열거형을 공부해보겠습니다.


▣ 개념부터 공부해볼까요?
배열은 동일한 자료형을 모아서 만든 변수에 모임과 같았죠?
그럼 구조체는 무엇일까요?


▣ 구조체는 배열과 비슷하지만 다른 자료 형식들을 연속적으로 만들어서 사용할 수 있습니다.
공용체는 쉽게 이야기하면 구조체와 비슷하지만 메모리를 공유해서 사용한다고 생각해주세요.
그리고 열거형은 우리가 기호상수를 만들 때 기억하시죠?
#define과 const으로 만들었습니다.
기억이 안나시는분은 변수와 상수 부분을 다시 공부하고 와주세요.
상수를 배열과 구조체처럼 여러개 만들어서 사용하는 것이 열거형이라고 생각하시면 됩니다.


▣ 우선 이렇게 기억해주시고 구조체부터 코드로 공부해보겠습니다.


▣ 배열에서는 하나하나에 배열값을 요소, 인덱스라고 불렀습니다.
구조체에서는 멤버라고 부릅니다.
아이돌 멤버가 아닙니다. ^^
코드를 한번 볼까요?

 

 

▣ 구조체를 만들려면 struct라고 적어주고 그 옆에 구조체에 이름을 정해줍니다.
배열에 자료형을 먼저 쓰고 배열에 이름을 적는 구조랑 똑같습니다.



▣ 저는 구조체에 이름을 Player라고 정했습니다.
그리고 안에 멤버들을 구성했습니다. 
게임처럼 저는 playerName을 char형식으로 playerHp, playerPower를 int형식으로 정했습니다.
그리고 main함수에서 struct Player를 player라는 변수로 선언했습니다.
이렇게 하지 않으면 구조체를 사용할 수 없습니다.
쉽게 이야기하면 배열이라고 치면 안에 있는 구조들을 직접 만든다고 생각해주세요.



▣ 다시 이야기하면 우리가 배열에서도 변수에서도 선언을 하죠.
그것과 동일하게 구조체는 위에서 우리가 구조체에 틀만 만들었고
그걸 선언을 해줘서 그 틀이 main함수를 시작할때 
만들어지는 거라고 생각하시면 됩니다.
그럼 이제 만들어진 구조체 멤버 안에 하나하나 값을 대입해보겠습니다.

 

 

▣ 구조체에 멤버로 접근하려면 
우리가 선언해준 player변수에 . 점을 찍어줍니다.
 (.) 점 자체는 접근하는 기호다라고 생각하시면 됩니다.
점을 쓰면 이렇게 안에 있는 멤버들을 확인할 수 있죠?

 

 

▣ 먼저 playerName에 문자열을 넣어보겠습니다. 
하지만 오류가 나오게됩니다.
lvalue가 없다고 경고가 나오네요.
이건 왜 그런걸까요?
자 우리가 포인터까지 했다면 이게 왜 이러는지를 아실 수 있을 겁니다.



▣ 다시 설명하면 playerName이름 자체는 기준 주소를 의미합니다.
기준 주소는 playerName [0] 주소를 의미하죠.
우리가 배열과 포인터를 배웠을 때 공부했습니다.
한 글자를 넣을 때마다 playerName [0] = 'M'; 이렇게 요소마다 넣어줘야 합니다.
그렇기 때문에 당연히 저 위에 있는 식은 성립되지 않습니다.
그렇기 때문에 하나하나 넣어도 됩니다.   playerName[0] = 'M'; 이렇게 말이죠
아니면 초기식으로 넣어줘도 됩니다. 
그리고 포인터를 사용해도 됩니다.



하지만 우리는 다른 방법을 배워보겠습니다.
하나하나 하는 게 아닌
문자열 자체를 복사하고 기준 주소를 해서 그 배열에 안에 넣는 방법을 말이죠.
그럼 기준주소를 기준으로 문자열을 복사해서 넣고 싶으면 어떻게 해야 할까요?

 

 

▣ memcpy를 우리는 공부했습니다.
그건 메모리를 복사했었죠?
그것과 비슷한 형태에 함수가 있습니다.



▣ 먼저 string.h 헤더를 추가해주고
strcpy_s를 사용하시면 됩니다.
_s는 당연히 보안 결함 때문에 사용하겠죠?
scanf_s와 마찬가지로요.
이 부분이 기억이 안 나시면 입출력 장을 다시 공부하고 와주세요.
strcpy_s함수로 문자열을 복사해서 넣었습니다.
처음에는 넣을 주소, 사이즈, 넣을 문자열을 각각 넣어주시면 됩니다.
그리고 이렇게 위에서처럼 멤버에 숫자까지 각각 넣어보겠습니다.

 

 

▣ 그리고 디버깅해서 메모리에서 확인을 해보면
멤버 하나하나에 값이 들어간 걸 확인할 수 있습니다.



▣ 꼭 직접 구조체를 만들어주시고 메모리를 확인하는 것까지 꼭 실습해주세요.
숙제입니다.

 

 

▣ typedef 이건 형을 재 선언한 것입니다.
이게 무슨 말이냐.
우리가 main에서 struct를 선언할 때 매번 struct을 적어주고 Player 구조체에 이름을 적고 변수를 선언해야 하죠?
매번 번거롭습니다.
struct를 안 붙이고 Player만 넣어서 선언해주고 싶습니다.
그럴 때 사용합니다.
typedef을 넣어주고 struct와 Player을 넣는 다음에 
} 화살 괄호 마지막 부분에 다시 Player 구조체를 이름을 다시 넣어주면 
재 선언한 게 됩니다.
그럼 Player = struct Player 가 안에 선언이 되어 있는 겁니다.
Player만 넣고 이제 변수를 선언할 수 있습니다. 



▣ 이건 구조체, 공용체, 열거형 모두 동일하니 
꼭 숙지해주시고 직접 해보세요.
숙제입니다. 

 

▣ 자 이건 제가 구조체를 배열로 선언한 코드입니다.
아까는 Player player에 변수 하나로만 만들어서 값을 하나하나 정의해줬다면
이번에는 player [3] 배열로 만들어서 
player [0][0] = "MRG"를 하나하나 초기화를 주는 것처럼 만들었습니다.
꼭 2차원 배열과 비슷하죠?
네 비슷합니다. 이렇게 해서 직접 만들어보세요.
많이 사용합니다. 
왜 여기서는 그냥 문자열을 넣을 수 있는지 아시죠??
모르시면 배열 부분을 다시 공부하시면 좋을 거 같습니다.

 

▣ 자 이렇게 디버깅을 통해서 직접 메모리를 확인해보았습니다.
이것도 꼭 해보셔야 합니다. 
숙제입니다.

 

 

▣ 이번에는 저번장에 서 해던 메모리를 동적 할당해서 만들어보았습니다.
동적 할당을 하게 되면 스택 영역 메모리가 아닌 힙 영역 메모리를 사용하게 됩니다.
스택 와 힙 영역을 모르시면 저번장을 참고해주세요.



▣ 이렇게 Player구조체를 *pList 포인터로 선언을 해서 포인터를 통해 값을 대입했습니다.
하지만 다른 게 있죠?
. 점으로 접근하는 게 아닙니다.
포인터 멤버를 접근할 때에는 직접 포인터로 접근할 수도 있지만
->이 기호를 통해서 쉽게 접근해서 값을 포인터를 통해 대입할 수도 주소를 확인할 수도 있습니다.

 

 

▣ 자 이렇게 메모리를 확인해보면 cd fd 기억하시죠?
fd는 동적 할당한 메모리에 바리게이트라고 생각하시면 된다고 했습니다.
주소를 확인해보면 이렇게 동적할당한 부분에 우리가 넣은 값들이 들어있는 걸 확인할 수 있습니다.
c언어에 양날에 검이죠.
쉽게 주소를 통해 메모리를 조절할 수 있지만 
그 덕분에 쉽게 주소를 통해 메모리에 값을 잃을 수도 있다는 이야기입니다. ㅠ.ㅠ
조심히 써야 합니다. ^^



▣ 이것도 꼭 직접 해보셔야 합니다.
저만 따라 하는 것에서 끝난 게 아니라 값을 바꿔서
만들어보시고 메모리를 확인해주세요.
숙제입니다.

 

▣ 이건 함수와 구조체를 활용한 것입니다.
어려워하실 거 없습니다.
하나하나 천천히 해석해보면 됩니다.
구조체는 아까와 동일합니다.
하지만 사용자 함수(playerData)에서 구조체를 player로 똑같이 선언했습니다.
그리고 사용자 함수에서 멤버 안에 값을 입력을 통해 값을 넣고 그 넣은 값들을 return player 구조체로 반환했습니다.
그리고 반환한 값을 main함수에서 출력을 했습니다.
간단하죠. 



▣ 직접 해보세요!!
숙제입니다. 



자 여기서 우리가 고민해볼게 있습니다.
하지만 Player구조체는 하나인데 main함수 한번 사용자함 수한 번 두 번을 선언하여 
스택 메모리에 불필요하게 두 번을 사용하게 되었습니다.
그럼 이걸 어떻게 고칠 수 있을까요?

 

 

▣ 이건 정답은 아니지만 그냥 제가 고쳐보았습니다.
멥버를 관리하는 메모리는 하나만 있으면 됩니다.
그렇기 때문에 지금 위에서 구조체를 포인터로 받아왔습니다.
그럼 사용자 함수(playerData)에서는 따로 또 구조체 변수를 선언하지 않아도 되고 
main함수에서만 선언해서 주소만 보내주고 
사용자 함수에서 포인터 변수에 입력한 값을 넣어주고
main함수에서 구조체에 값을 출력했습니다.
스택 영역에 선언하고 넣어진 메모리는 하나가 되겠죠?
포인터로 관리하고 사용한 것뿐입니다.
그럼 메모리와 최적 화적인 부분에서 절약이 되었네요.
이럴 때 포인터를 사용합니다. 



▣다른 방법도 있을 수 있습니다.
이건 저에 생각이니^^ 
다른 좋은 분들 자료들도 참고하시면 함께 공부해주세요.
코딩은 정답이 없습니다.



▣ 직접 위에 있는 것도 다르게 만들어보셔서 해보셔야 합니다.
숙제입니다.
그리고 메모리를 확인하는 것도 꼭 해보세요. 

 

▣ 이 코드는 player구조체 안에 또 다른 구조체를 넣어 보았습니다. 
아주 간단합니다.
위에 구조체를 만들고 
player구조체 안에 선언을 해줍니다.
그리고 main함수에서 player변수로 구조체를 선언해주고 
. 점으로 접근 또. 접근을 하게 되면 구조체 안에 구조체에 접근할 수 있게 됩니다.
그곳에 값을 대입할 수도 있습니다.



▣ 직접 만들어보시고 출력해보시고 메모리 구조도 확인해주세요.
숙제입니다.

 

 

▣ 이건 구조체 안에 포인터를 하나를 선언해서,
자기 자신 안에 자신을 참조하는 포인터를 만들어보았습니다.
조금 헷갈릴 수 있는 코드지만, 
포인터를 이용해서 
구조체 하나를 가지고 자기 자신을 계속 참조하여 
짧은 코드로 많은 정보들을 만들 수 있겠죠?
하지만 저는 추천하지는 않습니다.
코딩이 복잡한 게 좋은 건 아니라고 생각하기 때문이죠.



▣ 그래도 저 위에 있는 코드도 꼭 직접 해보세요.
그래야 포인터를 좀 더 이해하는데 도움이 되실 거라 생각합니다.
꼭 해보세요 숙제입니다.

 

▣ 자 이번에는 공용체입니다. 
맨 처음에 이야기한 것처럼, 구조체와 동일한 구조이지만
메모리를 공유해서 사용하는 게 다릅니다. 
공용체를 만들려면 union을 해주고 구조체와 동일하게 만들어줍니다.



▣ 그리고 main에서 공용체를 메모리에 크기를 확인해보면 
short, int, char [8]를 더한 메모리가 아닌 
가장 큰 char [8]로 메모리가 정해져 있는 걸 볼 수 있습니다.
네 맞습니다. 
union 공용체는 가장 큰 메모리를 기준으로 공유해서 사용합니다. 



▣ 구조체와 동일하게. 점으로 멤버에 접근하여 값을 대입해주고 하나하나 
출력해주면 잘 나옵니다. 
하지만

 

▣ 이렇게 한꺼번에 대입해주고 한꺼번에 출력을 해주면 
값이 이상하게 나옵니다.
왜 그런 걸까요?
네 쉽게 이야 하면 
덮어진 것입니다. 같이 메모리를 사용하기 때문이죠.
MRG를 넣어주면 공용체 메모리에 MRG 글자가 들어가고
100을 넣으면 거기에 또 100이 넣어져 MRG가 덮어져 버립니다.
또 10을 넣으면 10을 출력하게 되는 것입니다. 
그래서 값이 저렇게 나옵니다.  

 

 

▣ 이렇게 말이죠. 
메모리를 따라가면 그 값이 덮어지는 걸 볼 수 있습니다.
직접 확인해보세요.

 

 

▣ 자 구조체와 동일하게 
typedef으로 재선언을 할 수도 있고,
포인터를 만들어서 직접 메모리를 동적 할당할 수 도 있습니다.
이걸 이용하면 메모리를 공유한다는 점에서 위험할 수도 있지만,
불필요한 메모리를 사용하지 않고
내가 정한 메모리만 사용할 때 최적 화적인 면에 좋겠지만
많이 선호하지 않습니다. ^^
양날에 검이죠 ^^;;
이건 제 생각일 뿐입니다.



▣ 공용 체도 위에서부터 하나하나 
직접 실습해주시고 만들어보세요.
숙제입니다.

 

 

 

▣ 열거형은 간단합니다. 
쉽게 여러 기호 상수를 한꺼번에 만들 수 있다라고 생각하시면 편할꺼 같습니다. 
구조체는 struct, 공용체는 union, 열거형은 enum으로 만들수 있습니다.
구조체와 공용체와 동일하게 
typedef으로 재 선언할 수도 있습니다. 
하지만 조금 다른 점이 있습니다.
player로 main함수에서 재선 언하였고 
그 변수에 도적이라는 문자열을 넣었더니 
2라는 값을 출력한 걸 볼 수 있습니다.
결론적으로 멤버에 숫자 값이 있는 겁니다.
배열처럼요.
그래서 이런 식으로 게임을 만들 때 사용할 수 있습니다.

 

▣ 저도 많이 사용하는데, 이렇게 switch문을 활용하여 만들어 보았습니다.
player값 안에 법사라는 문자열을 넣고
그 직업들을 switch 조건문으로 검사하겠죠?
그럼 법사라는 상수와 조건이 같다면 
맞은 조건에 값이 출력이 되겠죠?
재미있죠? ㅎㅎ
당연히 열거형은 문자뿐만 아니라 숫자로도 할 수 있습니다.
switch문을 잘 모르시겠다면
조건문 부분을 다시 공부해주세요.



▣ 이 열거형도 꼭 직접 만들어보시고 
출력해보시고 메모리도 따라가 보세요.
숙제입니다.!!!



▣ 자 벌써 구조체와 공용체 그리고 열거형까지 배웠습니다.
그렇게 어려운 부분은 아니지만
활용함에 있어서 어떻게 해야 할지 많이 고민이 되시죠?



▣ 이것도 우리가 장을 계속 배우면서
아니면 나중에 게임을 만들면서 
제가 활용하는걸 같이 공부해보도록 하겠습니다.



▣ 그리고 저라고 해서 모든 코드를 쓰는 건 아닙니다.
모든 코드를 다 써야 한다라는 부담은 버려주세요.
코딩을 하는 것도 사람마다 다르고 취향이 다릅니다.



▣ 그래서 제가 매번 말씀드리는 말이지만,
공부하실 때
제 블로그뿐만 아니라 
여러 좋은 강사님들과 선생님들에 자료와 영상들
그리고 코드를 보시면서 함께 공부해주세요.
그래야 실력이 늘어납니다.



▣ 그리고 숙제 꼭 하셔야 합니다.
그럼 다음장에서 뵙겠습니다.
질문 있으시면 댓글 남겨주세요.
여러분들에 공감과 댓글, 방명록 정말 많은 힘이 됩니다.


▣ 포기하지 마세요!!! 저도 했습니다!!! 파이팅!!!

 

728x90
반응형

댓글