본문 바로가기
TIL/따배씨

구조체(2021-01-25~2021-01-29)

by Dev_Dank 2021. 1. 25.

(2021-01-27 생각보다 수강에 시간이 정말 많이 걸리고 있다.... 예상했던것보다 어려운 느낌이다. 아무래도 이번주 내내 구조체 챕터만 들을거 같은 느낌이다.)

 

4.1 구조체가 필요한 이유

C언어에서는 데이터가 메모리에 저장 되어있으면 추상화된 개념으로 오브젝트라고 부르기도함. 

자료형이 서로 다른것들을 모아놓는데 사용가능한 c의 문법이 구조체다. 서로 자료형이 다르더라도 하나로 묶어서 새로운 자료형처럼 사용할수 있게 도와주는게 구조체임. 

Dot(.)연산자를 통해 구조체의 멤버에 접근할 수 있다.

위의 그림에서 p1, p2, p3가 Struct Patient p1, p2, p3;로 선언되면 구조체의 형에 맞추어 메모리에 자리가 생기는것

14.2 구조체의 기본적인 사용법

기본적인 구조체 선언방법은 이하와 같다.

구조체 변수를 선언하는 방법은 이하와 같다. 

그리고 구조체의 특정 자료에 접근할때는 dot(.) membership opeator 를 사용한다. 

구조체 변수는 다른 변수와 마찬가지로 선언할때 초기화가 가능하다. 

포인터 또한 활용이 가능하다. 

구조체는 함수안에서 선언되면 해당 영역에서만 사용이 가능하고 
구조체 선언할때 태그를 물결괄호 뒤에 선언할 수도 있다. 

typedef를 사용하면 구조체 사용할떄 마다 번거롭게 Struct를 쓰지 않아도 된다. 

14.3 구조체의 메모리 할당

구조체가 메모리를 어떻게 사용하는지 알아보는 강의이다.

구조체는 자료형이 서로다른 멤버들이 나열되어있어서 내부적으로 효율을 높이기 위해 메모리 패딩이란걸 사용 함

메모리와 cpu가 데이터를 주고받을때 1바이트씩 주고받을것으로 생각할수 있다. 
그런데 그렇게 1바이트씩 주고받으면 느려서 데이터들을 한번에 묶어서 보내는게 효율적이다.
최소 얼마나 많은 양을 묶어서 보낼것인지를 정의한 용어가 word임 
따라서 최소로 묶어서 보낼 데이터크기를 맞추기 위해 패딩이 일어난다. 

char 가 1바이트지만 쉽게 데이터를 읽어오기 위해 3바이트가 패딩이 된 모습이다. 

구조체 안의 배여도 패딩이 일어난다. 

배열name의 크기가 구조체안에서 41로 선언됬지만 패딩이 일어나서 44인걸 볼 수 있다. 

위의 예제에서 구조체 변수를 배열로 선언하면 어떻게 구조가 짜이는지도 주목하자. 
(|f[0].name        | f[0].age | f[0].height | ... ... |f[3].name        | f[3].age | f[3].height |)

14.5 구조체를 다른 구조체의 멤버로 사용하기

이하의 예시와 같이 구조체를 중첩하여 사용할 수 있다. 

또한 printf를 이렇게도 사용할수 있다는점에 주목하자.

14.6 구조체와 포인터

이하와 같은 형태로 구조체에 대한 포인터를 사용할수도 있다. 

구조체는 복사가 가능하다. 

동적할당으로 할당받은 멤버를 복사하면 결국 포인터로 복사한거기 때문에 메모리 주소가 똑같게 나온다. 

14.7 구조체를 함수로 전달하는 방법

구조체를 함수로 전달할때 포인터로 전달하지 않으면 구조체가 통째로 복사되어서 자원낭비가 심하므로 이하와 같이 포인터를 사용해서 넘겨주는것이 좋다.

14.10 복합 리터럴

14.10 복합 리터럴

구조체선언과 동시에 초기화 한 후 대입할때 복합리터럴을 사용하면 쉽게 사용할 수 있다. 

14.11 신축성있는 배열 멤버

기존 GCC 컴파일러에서 struct hack 으로 쓰이던 기술이다. 

자세한 설명은 강의로 대채

14.12 익명 구조체

구조체 안에서 구조체를 선언할때 태그를 없이 사용할 수 있다.

14.13 구조체의 배열을 사용하는 함수

동적할당으로 메모리를 받아온뒤 구조체를 사용할수도 있다는 점에 주목하자. 

14.15 공용체의 원리

구조체와 비슷하게 서로다른 자료형을 한곳에 모아서 사용하지만 같은 메모리 공간을 사용한다는 점이 다르다. 

공용체 uni의 사이즈는 my_union에서 가장 큰 자료형인 double d (8바이트)가 배정이 되었으며 uni.i, uni.d, uni.c 모두 같은 주소에서 시작하는것을 볼 수있다. 

이외의 사용법은 이하의 스샷을 참고하자. 

14.16 공용체와 구조체를 함께 사용하기

아래의 예시처럼 구조체와 공용체를 같이 사용할 수 있다. 

만약 주황색으로 동그라미 친부분을 union이 아닌 struct로 선언했다면 메모리공간을 더 차지 했어서 비효율 적이었을 것이다. 

 

14.17 익명 공용체

공용체는 이름없이 이하와 같이도 사용이 가능하다. 

16강에서의 공용체를 이름이 없는형태로 더 간결하게 사용하고 있다. 
이렇게도 사용이 가능하기 때문에 이름없는 공용체와 구조체를 같이 사용하면 편하다.

14.18 열거형

정수형 상수가 마치 이름이 있는 것 처럼 사용하게 해주는 방법. 

14.19 열거형

scanf의 %[^\n]%*c 에 대한 설명은 14.8강 3분 40초경에 나옴. 

그리고 이하의 링크를 참조가능

stackoverflow.com/questions/11542010/c-in-scanf-what-does-it-mean

www.geeksforgeeks.org/scansets-in-c/

www.quora.com/What-is-meaning-of-*-n-*c-while-using-scanf-in-c

14.20 이름공간 공유하기

namespace란 프로그램에서 이름이 인식될수있는 범위를 의미한다.

14.21 함수 포인터의 원리

함수가 메모리 어디에 저장되어있는지를 가리키는 함수 포인터에 대한 강의이다.

기본적인 함수포인터의 사용방법은 이하와 같다. 

1. 내부적으로는 함수의 이름자체가 사실상 함수코드가 담긴 주소라서 문법적으로 함수포인터 선언할때 함수 이름앞에 &붙이지 않아도 괜찮다. 

2. 그리고 함수의 포인터를 통해서 함수를 실행 시킬때도 함수의 이름자체가 주소(포인터)니까 문법적으로 indirection operator(*)쓰지 않고 그냥 괄호만 붙여서 실행 하는것도 가능

"Banana" 문자열 리터럴, f_ptr이 가리키는 함수 func가저장 된 주소, main이라는 함수가 저장된 곳은 전부 text segment이다. 

프로그래머는 함수의 이름을 이용해서 프로그램을 작성하지만 컴파일러는 이름(식별자)들을 메모리에서의 주소로 번역한다. 즉, 함수를 실행시킨다는 것은 메모리에서 함수의 주소위치에 저장되어있는 명령어들을 순차적으로 수행한다는 의미이다. 

14.22 함수 포인터의 사용 방법

이하와 같은 방식으로 함수의 포인터를 사용할 수 있다. 

그런데 위의 예시에서 ToUpper와 ToLower의 내용이 거의 같기 때문에 아래와 같은 형태로 사용 하는것이 더 효율 적이다. 

ToUpper와 ToLower는 UpdateString 형태로 바꾼 후 

 

요렇게 사용할 수 있다.

참고로 UpdateString 에서 int(*pf)(int) 를 쓰는 이유는 toupper와 tolower의 매개변수와 리턴값을 맞추기 위함이다. (ToLower와 tolower는 같은 함수가 아님!)

14.23 자료형에게 별명을 붙여주는 typedef

typedef는 이름을 바꿔서 사용이 가능한것 뿐이지 새로운 자료형을 컴파일러에 추가하는것은 아님.

기본적인 사용방법은 이하와 같다. 

typedef도 스코프를 지녔기 때문에 byte를 중괄호 밖에서 사용하면 에러가 발생한다.

한가지 더 주목할점은 typedef는 이식성이 높다는 점이다. size_t도 우클릭해서 Go To definition을 누르면 이하와 같은 방식으로 선언이 되어있기때문에 x64일때랑 x86일때 자료형이 자동으로 바껴서 편하다. (강의 3:30)

define으로 하는 것과 typedef의 차이는 이하와 같다. 

지난번강의에서 보았듯 typedef로 구조체에도 사용이 가능하다. 이하의 예시 참조, 

14.24 복잡한 선언을 해석하는 요령

기본적인 해석방법은 이하와 같다.

이하의 주의점이있다. 

 

댓글