<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>kiwi_100.log</title>
        <link>https://velog.io/</link>
        <description>Emotional realizer</description>
        <lastBuildDate>Tue, 08 Aug 2023 02:02:26 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>kiwi_100.log</title>
            <url>https://velog.velcdn.com/images/kiwi_100/profile/c491287f-f9ff-404a-b08a-966804479601/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. kiwi_100.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/kiwi_100" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[자료구조(4)]]></title>
            <link>https://velog.io/@kiwi_100/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B04</link>
            <guid>https://velog.io/@kiwi_100/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B04</guid>
            <pubDate>Tue, 08 Aug 2023 02:02:26 GMT</pubDate>
            <description><![CDATA[<h1 id="queue-재학습-및-동적배열로-queue-구현하기">Queue 재학습 및 동적배열로 Queue 구현하기</h1>
<p>큐를 구현하는 코드들에 대해 이해가 아직은 부족한 것 같아 다른 유튜버의 큐에 대한 개념을 재학습하고 동적할당을 이용해서 c언어로 구현해봤다.</p>
<blockquote>
<p>가정 상황
int a[5]라는 배열이 있다고 가정해보자.
a[0]부터 a[4]까지 데이터가 1부터 5까지 들어갈 것이다.</p>
</blockquote>
<blockquote>
<p>1.기존 배열에서 직접 데이터를 삭제하는 방식</p>
</blockquote>
<ul>
<li>데이터로 메모리가 다 포화되어있다고 가정했을 때 FIFO하기 위해서 a[0]의 데이터 즉 첫번째 데이터를 빼야된다.(뺀다=끄집어내다=삭제한다)</li>
<li>우린 기존에 이 데이터를 끄집어내면 두번째부터 있는 뒤의 데이터들도 앞에서 빠진 자리때문에 한 칸씩 이동해야되는 비효율적인 방식을 썼다.(배열안에 많은 데이터들이 하나씩 이동하는데 시간과 비용이 듬)</li>
</ul>
<ol start="2">
<li>큐</li>
</ol>
<ul>
<li>큐는 이런 문제를 해결하기위해 데이터를 꺼낼 때 실제 데이터를 저장해서 이동시키는 방식이 아닌 <strong>실제로 넣고(입력) 꺼낼(삭제) 위치가 어딘지만 알아서 이동하도록 하는 방식이다.</strong>
== 내 눈에 보이는 부분만 활성화 시키는 것</li>
</ul>
<p>큐는 데이터를 뒤에서 들어와서 앞으로 나가는 형태로 구현이 된다.
이때 여기에서 front와 rear이라는게 등장하는데 </p>
<blockquote>
<p>front 변수 : 어느 위치에서 데이터를 꺼낼 것인지 가리킨다.
            데이터는 앞에서 빠져나간다.
rear 변수 : 어느 위치에 데이터를 저장할 것인지 가리킨다.
            = 데이터가 있는 요소 다음 요소를 가리킴
           데이터는 뒤에서 들어온다.</p>
</blockquote>
<p>이걸 가지고 우리는 위치를 파악하는 것이다.
큐는 일반적인 배열로 쓰면 크기가 한정되어있고 에러가 날 수 있어서 순환해서 계속 쓸 수 있는 애초부터 원형큐로 활용한다.(아래에서 왜 원형을 쓰는지 이유가 나온다.)
(마지막 요소(a[4])에 데이터가 들어가면 rear는 원래는 a[5]를 가리켜야되는데 5번째 공간은 MAX size에 존재하지 않음 그래서 에러남)</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/eee3d8f0-2fa7-4cbb-8b41-7ce3e3c6801f/image.jpg" alt=""></p>
<p>3.큐의 시뮬레이션 </p>
<blockquote>
<p>ㄱ.데이터를 넣어주는 경우(Enqueue)
처음에 큐가 비어있는 상태에선 front와 rear가 a[0]에서부터 시작한다.
즉,1번 데이터가 들어갈 위치도, 꺼낼 위치도 rear와front로 잡는다.</p>
</blockquote>
<ul>
<li>데이터 &#39;1&#39;을 a[0]에 넣으면 rear가 증가되어 a[1]을 가리킨다.이런식으로 데이터를 넣을때마다 rear는 증가된다.
(다음번엔 a[+1]에 넣을 차례라는걸 알려줌)</li>
</ul>
<blockquote>
<p>ㄴ.데이터를 꺼내는 경우(Dequeue)
꺼내다 = 큐에서 삭제하다로 보면됨
맨 처음 a[0]에 있던 데이터 &#39;1&#39;을 꺼내면 front가 증가되어 a[1]을 가리킨다.이런식으로 데이터를 꺼낼때마다 front는 증가된다.</p>
</blockquote>
<ul>
<li><p>데이터위치를 가리키고 있는 범위는 front부터 rear 전까지의 범위로 봐야되며,이렇게 인큐, 디큐가 일어날때마다 데이터의 범위 또한 실시간으로 변하는 것이다.</p>
</li>
<li><p>여기서 실제로 꺼내진 데이터가 삭제된 것은 X 그저 가리키는 데이터의 범위가 위처럼 정해져있는것이다. = 활성화된 범위에 따라 큐가 가지고있는 데이터들이 변하는것임
ex)앞 책상엔 여러 물건이 있는데 내 손은 2개라 몇 개만 들 수 있는것</p>
</li>
</ul>
<blockquote>
<p>ㄷ.위처럼 첫번째 데이터를 빼낸 상태에서 원형큐의 마지막 요소에 인큐를 하는 경우
rear는 다시 a[0]을 가리킨다.이때 데이터의 범위는 front가 가리키는 a[1]부터 rear 전인 a[4]까지다.</p>
</blockquote>
<p>4.우리는 왜 큐를 원형큐로 쓰는 것인가?
위와 같이 일반적인 큐는 계속 데이터가 삽입되면 어느순간 MAX SIZE를 넘어가 에러가 난다.그래서 배열의 MAX SIZE와 rear의 값이 같다면 다시 rear의 값을 a[0]로 바꿔주는 작업이 필요하다.그러면 다시 순환하는 원형의 구조를 가지게된다.</p>
<p>원형의 구조에 위의 예시를 적용해서 MAX SIZE인 a[5]까지 데이터가 가득찬 상태에서 rear는 a[0]를 가리키고 추가로 &#39;6&#39;을 넣는다 가정하면 rear는 증가돼서 a[1]을 가리킨다.이때 활성화된 데이터의 범위는 front인 a[2]부터 rear전인 a[0]까지다.이게 무슨소리냐면 이렇게 기존에 a[0]에 들어있던 &#39;1&#39;이란 데이터는 다른 데이터 값 &#39;6&#39;이 들어가면서 활성화된 데이터 범위에서 제외된다.(그럼 이 데이터는 삭제되냐? 아니다.그리고 이 데이터의 삭제유무가 중요한건 아님)</p>
<p>근데 여기서 또 데이터 값 &#39;7&#39;을 넣으면 일어나는 현상이 있다 .
rear인 a[2]를 가리키면서 front와 같은곳을 가리킨다.</p>
<p>5.rear와 front가 같은곳을 가리키는 경우는 두 가지 상황에서 나타나게된다.</p>
<p>바로 큐의 모든 메모리가 꽉 찬 경우와 비어있는 경우다.</p>
<p>여기에선 문제점이 발생한다.</p>
<p>문제점</p>
<p>처음에 front와 rear을 a[0]으로 가리키도록하는데 이 말은 즉 컴퓨터가 데이터가 꽉 찼는지 아예 비어있는지 판단을 하기힘들다는것이다.</p>
<p>해결방법</p>
<p>프로그래머가 이 큐가 찼는지의 유무를 알기위한 하나의 장치를 추가적으로 해주면된다.바로 count변수(이름은 자유)라는 데이터의 갯수를 세주는 역할의 변수를 만들어주는것!!</p>
<p>데이터가 추가로 삽입돼서 rear가 증가하면 이 변수의값도 같이 증가하도록 count를 ++해준다.</p>
<p>반대로 데이터를 꺼낼때마다 front가 이동하게되는데 그때는 count가 --하게 한다.</p>
<p>이렇게하면 count변수의 값은 데이터의 저장 갯수인 front부터 rear 전까지의 데이터 갯수와 비례하게된다.</p>
<p>※ 큐 구현 코드의 구조체 부분 복습 
Typedef Struct Queue<br>Queue;</p>
<p>Typedef -&gt; 구조체를 대표하는 새로운 자료형을 Typedef로 정의한것
           기존 데이터 유형에 대해서 새 이름을 만드는데 사용된다.
           코드 가독성이 높아지고, 오류 가능성이 낮아진다.</p>
<p>Struct -&gt; 구조체를 의미</p>
<p>Queue -&gt; 구조체의 이름</p>
<p>Queue; -&gt; 밑에 쓰인 Queue는 Struct Queue의 별칭이다.(변수가 아님)이 별칭을 가지고도 변수를 선언하거나 자료형을 함수 매개변수로 전달할 수 있다.
그리고 이렇게 쓸 수 있는 이유는 Typedef 덕분</p>
<p>typedef를 사용하면 struct를 안써주고 Queue만으로 Queue testfunc; 이렇게 변수를 생성할 수 있고 </p>
<p>사용하지않으면 Struct Queue testfunc;를 써줘서 변수를 생성해줘야된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자료구조(3)]]></title>
            <link>https://velog.io/@kiwi_100/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B03</link>
            <guid>https://velog.io/@kiwi_100/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B03</guid>
            <pubDate>Thu, 03 Aug 2023 02:51:56 GMT</pubDate>
            <description><![CDATA[<h1 id="큐는-무엇인가">큐는 무엇인가?</h1>
<p>1.큐의 정의</p>
<blockquote>
<ul>
<li>자료구조의 규칙 중 하나로 메모리 안 데이터들을 더욱 효율적으로 다루기 위해 만들어진 데이터 참조 방식</li>
</ul>
</blockquote>
<ul>
<li>FIFO(First In First Out)
파이포는 양 쪽 끝에서만 데이터를 넣거나 뺄 수 있는 선형구조로 제일 처음에 들어온 데이터가 제일 빨리 처리되어 나가는 방식
 예시) 카페에서는 줄을 서서 먼저 온 사람의 주문을 처리하고 그 사람이 나간다. + 이메일 다중 전달, 게임 대기창, 알림, 푸시기능,티켓팅 사이트 등</li>
<li>큐에 새로운 요소가 들어올 시 
맨 뒤에 데이터가 들어가게되며,읽거나 삭제할 수 있는 행위는 큐의 맨 앞에 있는 요소에 의해 제한된다.</li>
</ul>
<p>2.큐를 대표적으로 구현하는 방법</p>
<ul>
<li><p>대표적으로는 정적인 어레이(Fixed Array)와 동적인 어레이(Linked List)가 있다. </p>
<blockquote>
<p> ㄱ.정적인 어레이(Fixed Array)를 이용해 큐를 구현하는 경우
장점 : 구현이 쉽다
단점 : 큐의 크기가 고정되어있다.(넘치면 오버플로우)
또한 이 경우는 큐의 맨앞 인덱스나 위치를 담는  first라는 변수, 새 요소를 추가할 수 있는 정적 배열에서 다음으로 사용 가능한 슬롯의 인덱스나 위치를 담는 next라는 변수를 사용한다. </p>
</blockquote>
<blockquote>
<p>ㄴ.동적인 어레이(Linked List)를 이용해 큐를 구현하는 경우
장점 : 구현이 전자에 비해 더 어려움
단점 : 큐의 크기를 자동으로 조절할 수 있다.
이 경우는 큐의 맨앞 인덱스나 위치를 head, 새 요소를 추가할 수 있는 동적 배열 마지막 인덱스 또는 위치를 나타내는 tail이라는 변수를 사용한다.</p>
</blockquote>
</li>
</ul>
<p>3.큐의 대표적인 함수들</p>
<blockquote>
<ul>
<li>Enqueue(인큐) : 큐에 값을 집어넣은 함수 </li>
</ul>
</blockquote>
<ul>
<li>Dequeue(데큐) : 큐에서 값을 빼내는 함수 </li>
<li>Size : 큐의 크기를 확인하는 함수</li>
<li>Empty : 큐가 비어있는지 확인하는 함수  </li>
</ul>
<p>4.큐의 동작 시뮬레이션</p>
<blockquote>
<p>ㄱ.스탠다드한 정적배열시 기준
    a.데이터가 없을때 : first와 next가 같은 곳을 가리킴(첫번째)
   b.enqueue(queue에 A를 넣음)로 데이터가 하나 들어왔을때 : first가 맨 앞 데이터 A가 있는곳을 가리키고 next는 다음에 데이터가 들어올 위치를 가리키게됨
  c.enqueue(queue에 B를 넣음)로 데이터가 추가로 들어왔을때 : 큐는 맨 처음에 있는애를 기억해야되기때문에 first가 맨 앞 데이터 A가 있는곳을 가리키고 next는 B를 쓰고 다음에 데이터가 들어올 위치를 가리키게됨
   d.dequeue로 데이터를 뺄 때 : 삭제는 맨앞부터 되는거니깐 A가 삭제됨 그러면서 first는 한 칸 이동하면서 B를 가리키게되고 next는 그 자리를 유지한다.</p>
</blockquote>
<p>5.큐의 다른 형식</p>
<blockquote>
<ul>
<li>Circular Queue(환형 큐)
정적인 어레이가 원형띠 모양이라고 생각하면된다.데이터의 입출력이 원형의 행동양식으로 이루어짐</li>
</ul>
</blockquote>
<ul>
<li><p>Priority Queue(우선순위 큐)
큐의 규칙인 FIFO가 적용되지않아 맨 앞이 먼저 처리되는게 아닌 중요성이 있는 데이터 우선순위순으로 배열이 재배치되어 처리하게된다.</p>
<pre><code>       출처 : 유튜브 Gunny&#39;s Algorithm Together</code></pre></li>
</ul>
<p>6.코딩해서 큐 구현해보기</p>
<pre><code class="language-c">#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;

#define MAX 5

typedef struct Queue {
    int front; //앞 쪽 index
    int rear;  //뒤 쪽 index
    int data[MAX];
} Queue;

void init(Queue* q)
{
    q-&gt;front = q-&gt;rear = -1;
}

int is_full(Queue *q){
    if (q-&gt;rear == MAX - 1)
        return 1;
    return 0;
}

int is_empty(Queue *q){
    if (q-&gt;front == q-&gt;rear)
        return 1;
    return 0;
}

void enqueue(Queue* q, int item)
{
    if(is_full(q))
    {
        printf(&quot;Error Queue is full&quot;);
        exit(1);
    }
    q-&gt;data[++(q-&gt;rear)] = item;
}

int dequeue(Queue* q) {
    if (is_empty(q))
    {
        printf(&quot;Error Queue is empty&quot;);
        exit(1);
    }
    return q-&gt;data[++(q-&gt;front)];     
}

int main()
{
    Queue q;
    init(&amp;q);

    enqueue(&amp;q, 3);
    enqueue(&amp;q, 2);
    enqueue(&amp;q, 1);

    printf(&quot;%d\n&quot;, dequeue(&amp;q));
    printf(&quot;%d\n&quot;, dequeue(&amp;q));
    printf(&quot;%d\n&quot;, dequeue(&amp;q));


    return 0;
}</code></pre>
<ul>
<li><p>메인함수에서 호출문에 들어가는 인자 중 포인터로 받는건 반드시 인자에 &amp;를 붙여 주소값을 보내주게 만들어야된다!</p>
</li>
<li><p>이해 안된 부분 공부</p>
<blockquote>
<p>return q-&gt;data[++(q-&gt;front)]</p>
</blockquote>
</li>
</ul>
<p>chat GPT를 활용하여 내가 이해안되는 부분에 대해 질문했다.</p>
<blockquote>
<p>1.이 코드를 자세히 설명해줘.
답변
&quot;이 코드는 앞 요소의 값을 반환한 다음 앞 인덱스를 대기열의 다음 요소로 이동하여 대기열에서 요소를 제거합니다. 대기열에서 첫 번째 요소를 효과적으로 제거하고 해당 값을 반환합니다.</p>
</blockquote>
<ul>
<li>내가 이해한 결과</li>
<li><blockquote>
<p>즉 dequeue를 첫번째 호출했을 때 인덱스는 -1인 상태였으니 0으로 이동하고 front도 0을 가리킨다.그리고 이때 front가 가리키는 데이터 &#39;3&#39;이 반환된다.</p>
</blockquote>
</li>
<li>두번째 호출 시 인덱스와 front는 0에서 1을 향하게되고 데이터 &#39;2&#39;를 반환한다.</li>
<li>세번째 호출 시 인덱스와 front는 1에서 2를 향하게되고 데이터 &#39;1&#39;을 반환한다.</li>
</ul>
<blockquote>
<p>2.사전증가연산으로 다음 인덱스로 이동하면 이전 인덱스와 그 안의 요소가 자동으로 삭제되는거야?
답변
&quot;아닙니다.주어진 dequeue 코드에서 queue의 다음 요소로 이동하기 위해 앞 인덱스가 증가할 때 이전 요소는 자동으로 삭제되지 않습니다.대기열을 나타내는 배열의 데이터는 대기열에서 빼기 작업 중에 수정되지 않습니다. 앞 인덱스는 단순히 다음 요소를 가리키도록 이동되어 대기열의 논리적 보기에서 앞 요소를 효과적으로 &quot;제거&quot;하지만 배열의 실제 데이터는 변경되지 않은 상태로 유지됩니다.
dequeue 연산은 큐의 앞에 요소를 제거합니다. 대기열에서 빼낸 요소의 데이터는 여전히 배열에 존재하지만 전면 인덱스가 앞으로 이동했기 때문에 더 이상 활성 대기열의 일부로 간주되지 않습니다.</p>
</blockquote>
<ul>
<li>내가 이해한 결과 
데이터가 사라지는게 아니라 배열에 남아있긴하지만 요소가 활성화되지않는거구나 </li>
</ul>
<blockquote>
<p>3.그렇다면 dequeue로 앞 요소가 사라졌을때 앞 요소의 데이터는 사라지는게 아니라 배열에 존재하지만 전면 인덱스가 앞으로 이동했기 때문에 더 이상 활성 대기열의 일부로 간주되지 않는다고하면 그럼 dequeue라는 함수는 queue의 앞 요소만 제거하는 함수가 맞아?</p>
</blockquote>
<ul>
<li>답변
맞습니다. dequeue 함수는 큐의 앞 요소만을 제거하는 함수입니다. 큐에서 데이터를 dequeue하면, 해당 데이터는 배열에 여전히 존재하지만, 논리적으로 큐의 일부로 간주되지 않게 됩니다. 즉, dequeue 연산은 배열의 데이터를 삭제하는 것이 아니라, 큐의 front 인덱스를 증가시켜서 큐에서 논리적으로 더 이상 해당 데이터를 포함하지 않도록 만드는 것입니다.</li>
</ul>
<blockquote>
<p>4.queue는 배열을 가지고 있는 구조체 변수의 주소와 front와 rear 를이용해서 배열의 일부분만 활성화를 해서 데이터를 다루는  자료구조인게 맞아?</p>
</blockquote>
<ul>
<li>답변
일반적으로 큐는 배열로 구현되며, front와 rear 변수는 배열에서 데이터를 추가하거나 제거할 위치를 가리킵니다. front는 큐의 가장 앞을 가리키고, rear는 큐의 가장 뒤를 가리킵니다. 큐의 데이터는 front와 rear 사이에 위치하며, front와 rear 사이에 있는 부분만이 활성화된 큐의 요소들입니다. 새로운 데이터가 enqueue되면 rear가 증가하고, dequeue되면 front가 증가하여 활성화된 큐의 범위를 조절합니다. 이를 통해 큐는 FIFO(First-In-First-Out) 원칙을 따르는 데이터 구조로 동작합니다.</li>
<li><blockquote>
<p>그래서 front가 증가되는 코드를 썼었구나</p>
</blockquote>
</li>
</ul>
<p>7.큐의 문제점
위 예제와 같이 데이터를 계속 넣고 빼게되면 결국 배열의 인덱스가 초과하게된다.그래서 예제에서 5개를 넣고 모두 dequeue를 하게된다면 그 큐는 더이상 사용할 수 없다.-&gt; 그래서 원형큐가 나오게된다.</p>
<p>해결방법 : 원형큐를 쓰기</p>
<pre><code>                                       출처 : 유튜브(Hard Code 하드코드)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[자료구조(2)]]></title>
            <link>https://velog.io/@kiwi_100/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B02</link>
            <guid>https://velog.io/@kiwi_100/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B02</guid>
            <pubDate>Wed, 02 Aug 2023 00:36:57 GMT</pubDate>
            <description><![CDATA[<h1 id="스택의-함수들">스택의 함수들</h1>
<p>B.is_full
is_full 함수는 매개변수를 스택으로 받으며, 스택이 가득차있는지 확인하는 함수이다.</p>
<pre><code class="language-c">#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;


typedef struct stacktype {                //stacktype이라는 구조체를 정의 
    int arr[100];                        //stacktype 구조체 내에서 크기 100의 정수 배열 arr을 선언. 이 배열은 스택의 요소를 저장하는 데 사용한다.
    int top;                            //stacktype 구조체 내에서 정수 변수 top을 선언. top은 배열의 스택에 푸시된 마지막 요소의 인덱스를 추적한다.

}


void init(stacktype* s)                  //스택을 초기화하는 데 사용되는 init 함수 정의문.stacktype 구조체에 대한 포인터를 인수로 사용함
                                         //s는 stackType 구조에 대한 포인터를 나타내는 데 사용되는 매개변수 이름
{
    s-&gt;top=-1;                          //스택이 가리키는값을 -1로 초기화.배열은 인덱스가 0부터 시작하니깐 -1로 해놓고 인덱스의 합이 0이면 데이터가 하나 있는거고,-1이면 인덱스의 증가가 없는것이니 비어있는것                          
}


int is_full(stacktype *s)               //함수 정의(매개변수는 구조체의 포인터 즉 주소값)
{
    if(s-&gt;top==SIZE-1)                  //데이터를 계속 푸시하면 top이 -1에서 배열의 임의의 크기 SIZE에서 -1을 한 것(0을 빼줌)까지 갈 것이고 거길 가리키면 배열이 꽉차있는것을 의미한다.(더넣으면 오버플로우)
        return 1;                       //꽉 차있으면 1을 반환
    return 0;                           //차지않았으면 0을 반환      
}

int main()
{
    stacktype s;                         //stacktype 유형의 s 변수를 선언하여 스택의 인스턴스를 생성
    init(&amp;s);

    is_full(s);

    printf(&quot;%d&quot;, is_full(s));            //1과0을 실시간에 따라 반환

    return 0;
}</code></pre>
<p>C.push 함수 
push함수는 스택의 상단에 데이터를 삽입(push)해주는 함수다.</p>
<pre><code class="language-c">#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;


typedef struct stacktype {                //stacktype이라는 구조체를 정의 
    int arr[100];                        //stacktype 구조체 내에서 크기 100의 정수 배열 arr을 선언. 이 배열은 스택의 요소를 저장하는 데 사용한다.
    int top;                            //stacktype 구조체 내에서 정수 변수 top을 선언. top은 배열의 스택에 푸시된 마지막 요소의 인덱스를 추적한다.

}


void init(stacktype* s)                  //스택을 초기화하는 데 사용되는 init 함수 정의문.stacktype 구조체에 대한 포인터를 인수로 사용함
                                         //s는 stackType 구조에 대한 포인터를 나타내는 데 사용되는 매개변수 이름
{
    s-&gt;top=-1;                          //스택이 가리키는값을 -1로 초기화.배열은 인덱스가 0부터 시작하니깐 -1로 해놓고 인덱스의 합이 0이면 데이터가 하나 있는거고,-1이면 인덱스의 증가가 없는것이니 비어있는것                          
}


void push(stacktype *s, int value)      //push함수는 매개변수로 구조체에 대한 포인터와 넣을 데이터를 받는다.
{
    if(is_full(s))                     //데이터를 넣기전에 스택이 차있는 상태로 푸시를 하면 스택오버플로우가 나기때문에 full 유무를 확인해야된다.이때 참이면 찼다는 문구를 출력하고 종료한다.
    {
        printf(&quot;stack is full&quot;);
        exit(1);
    }

    printf(&quot;pushed:%d&quot;, value);       //넣은 값을 출력
    s-&gt;arr[++(s-&gt;top)]=value;         //꽉 찬 경우가 아닐시 먼저 s가 주소값을 넘겨준 배열 즉 스택의 맨 위에 메모리 공간을 하나 더 만들어주고, 그 곳을 top이 가리키게해서 거기에 value를 대입해주기. ex)top이 -1인 상태에서 데이터를 넣어주면 인덱스0번째의 메모리공간이 먼저 생기고,거기에 해당 value가 들어간다.

}

int main()
{
    stacktype s;                         //stacktype 유형의 s 변수를 선언하여 스택의 인스턴스를 생성
    init(&amp;s);

    push(&amp;s, 4);

    return 0;
}</code></pre>
<p>D.pop
pop함수는 스택에서 데이터를 뺄 때 쓰는 함수이다.(매개변수 스텍)
push와 다르게 데이터를 제거하고 메모리를 제거하는 배열 안에 들어있는 값을 반환하는 코드가 존재해서 삭제되는 값을 출력할 수 있다.</p>
<pre><code class="language-c">#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;


typedef struct stacktype {                //stacktype이라는 구조체를 정의 
    int arr[100];                        //stacktype 구조체 내에서 크기 100의 정수 배열 arr을 선언. 이 배열은 스택의 요소를 저장하는 데 사용한다.
    int top;                            //stacktype 구조체 내에서 정수 변수 top을 선언. top은 배열의 스택에 푸시된 마지막 요소의 인덱스를 추적한다.

}


void init(stacktype* s)                  //스택을 초기화하는 데 사용되는 init 함수 정의문.stacktype 구조체에 대한 포인터를 인수로 사용함
                                         //s는 stackType 구조에 대한 포인터를 나타내는 데 사용되는 매개변수 이름
{
    s-&gt;top=-1;                          //스택이 가리키는값을 -1로 초기화.배열은 인덱스가 0부터 시작하니깐 -1로 해놓고 인덱스의 합이 0이면 데이터가 하나 있는거고,-1이면 인덱스의 증가가 없는것이니 비어있는것                          
}


int pop(stacktype *s)                 //매개변수에 별도의 데이터가 필요없다.그냥 스택 자체를 제거함
{
    if(is_empty(s))                   //스택이 비어있으면 오류나서 엠티유무를 확인해야된다.
    {
        printf(&quot;stack is empty&quot;);     
        exit(1);
    }
    return s-&gt;arr[(s-&gt;top)--];        //비어있지않으면 리턴을 하는데 스택 변수 s가 arr 배열의 값을 가리키고,이때 top의 데이터를 리턴시켜준다.그리고 메모리 하나를 감소시킨다.(크기가 하나 감소)
}

int main()
{
    stacktype s;                         //stacktype 유형의 s 변수를 선언하여 스택의 인스턴스를 생성
    init(&amp;s);

    push(&amp;s, 3);                        //푸시했다고 가정(정의문생략)

    printf(&quot;\n pop:%d \n&quot;, pop(&amp;s));    //pop한 데이터 출력 및 크기 감소

    return 0;
}</code></pre>
<ul>
<li>증감 연산자가 앞에 있으면 먼저 실행되고,뒤에 있으면 그 후에 실행된다.</li>
</ul>
<p>E.peek 
peek함수는 스택 상단에 있는 데이터를 단지 무엇인지만 알 수 있게해주는 반환만 해주는 함수다.pop과 구조가 유사하다.</p>
<pre><code class="language-c">#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;


typedef struct stacktype {                //stacktype이라는 구조체를 정의 
    int arr[100];                        //stacktype 구조체 내에서 크기 100의 정수 배열 arr을 선언. 이 배열은 스택의 요소를 저장하는 데 사용한다.
    int top;                            //stacktype 구조체 내에서 정수 변수 top을 선언. top은 배열의 스택에 푸시된 마지막 요소의 인덱스를 추적한다.

}


void init(stacktype* s)                  //스택을 초기화하는 데 사용되는 init 함수 정의문.stacktype 구조체에 대한 포인터를 인수로 사용함
                                         //s는 stackType 구조에 대한 포인터를 나타내는 데 사용되는 매개변수 이름
{
    s-&gt;top=-1;                          //스택이 가리키는값을 -1로 초기화.배열은 인덱스가 0부터 시작하니깐 -1로 해놓고 인덱스의 합이 0이면 데이터가 하나 있는거고,-1이면 인덱스의 증가가 없는것이니 비어있는것                          
}


int peek(stacktype* s)
{
    if(is_empty(s))                     //스택이 비어있는지 확인
    {
        printf(&quot;stack is empty&quot;);     
        exit(1);
    }
    return s -&gt; arr[(s-&gt;top)];         //구조체가 가리키는 배열의 top을 추적해 안에 있는 데이터를 반환한다.
}


int main()
{
    stacktype s;                         //stacktype 유형의 s 변수를 선언하여 스택의 인스턴스를 생성
    init(&amp;s);

    push(&amp;s, 3);                        //푸시했다고 가정(정의문생략)

    printf(&quot;\n peek:%d \n&quot;, peek(&amp;s)); 

    printf(&quot;\n pop:%d \n&quot;, pop(&amp;s));    //pop한 데이터 출력했다고 가정(정의문생략)



    return 0;
}</code></pre>
<p>F.함수들 출력해보기</p>
<pre><code class="language-c">#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;

typedef struct stacktype {
    int arr[100];
    int top;

}

stacktype;

void init(stacktype* s)
{

    s-&gt;top = -1;

}

int is_empty(stacktype* s)
{
    if (s-&gt;top == -1)

        return 1;

    return 0;
}

int is_full(stacktype* s)
{
    if (s-&gt;top == 100 - 1)
        return 1;
    return 0;
}


void push(stacktype* s, int value)
{
    if (is_full(s))
    {
        printf(&quot;stack is full&quot;);
        exit(1);
    }

    printf(&quot;pushed:%d&quot;, value);
    s-&gt;arr[++(s-&gt;top)] = value;
}

int pop(stacktype* s)
{
    if (is_empty(s))
    {
        printf(&quot;stack is empty&quot;);
        exit(1);
    }
    return s-&gt;arr[(s-&gt;top)--];

}

int peek(stacktype* s)
{
    if (is_empty(s))
    {
        printf(&quot;stack is empty&quot;);
        exit(1);
    }
    return s-&gt;arr[(s-&gt;top)];
}



int main()
{
    stacktype s;
    init(&amp;s);

    push(&amp;s, 3);
    push(&amp;s, 2);
    push(&amp;s, 1);

    printf(&quot;\npeek:%d\n&quot;, peek(&amp;s));

    printf(&quot;\n pop:%d \n&quot;, pop(&amp;s));
    printf(&quot;\n pop:%d \n&quot;, pop(&amp;s));
    printf(&quot;\n pop:%d \n&quot;, pop(&amp;s));

    return 0;
}</code></pre>
<blockquote>
<p>실행 결과
pushed:3
pushed:2
pushed:1
peek:1
pop:1
pop:2
pop:3</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[자료구조(1)]]></title>
            <link>https://velog.io/@kiwi_100/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B01</link>
            <guid>https://velog.io/@kiwi_100/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B01</guid>
            <pubDate>Tue, 01 Aug 2023 00:20:13 GMT</pubDate>
            <description><![CDATA[<h1 id="스택이란-무엇인가">스택이란 무엇인가?</h1>
<ol>
<li>스택은 추상적 자료구조(ADT,Abstract Data Type)의 한 종류로서, 스택이라는 코드 문법이 있는게 아니라 자료구조의 규칙 양상 중 하나다.</li>
</ol>
<blockquote>
<p>스택의 규칙</p>
</blockquote>
<ul>
<li>보통 배열을 가지고 구현하며 가로의 배열이 수직으로 쌓여있는것을 스택으로 생각하면된다.</li>
<li>스택의 맨 위에서만 요소를 읽거나 삭제할 수 있다.(LIFO)</li>
<li>더 나아가 요소를 추가나 삭제할때는, 맨 위에서부터 차례로 할 수 있다.</li>
</ul>
<blockquote>
<p>스택의 예시</p>
</blockquote>
<ul>
<li>웹사이트 뒤로가기(웹페이지 히스토리 링크들이 담긴 배열의 맨위를 컨트롤)</li>
<li>방탈출 게임 이전 방으로</li>
<li>쇼핑몰 장바구니</li>
<li>컴퓨터가 쓰는 후위표기법(우리가 쓰는건 전위표기법)</li>
</ul>
<blockquote>
<p>스택을 활용한 함수의 유형
1.스택이 비어있는지 확인해주는 함수 : is_empty
2.스택이 찼는지 확인해주는 함수 : is_full
3.스택에 데이터를 넣어주는 함수 :  push
4.스택에 데이터를 빼주는 함수 : pop</p>
</blockquote>
<blockquote>
<p>자료구조로서의 스택은?
<strong>ㄱ. 자료구조 안의 데이터들의 순서가 보장되는지?</strong>
   -&gt; 후입선출,LIFO(Last-In-First-Out) 원칙에 따라 데이터의 순서를         보장하는 선형데이터구조다.(맨 위에서만 푸시,팝이 일어남)
<strong>ㄴ. 중복된 데이터가 들어갈 수 있는지?</strong>
   -&gt; 스택에 푸시되는 값에는 제한이 없으므로 중복 값이 스택에 추가될 수 있다.
<strong>ㄷ. 검색할 때 얼마나 효율적인지?</strong>
   -&gt; 푸시하거나 팝할때는 구현 모두에 대한 일정한 시간이 걸린다.(o(1))
   그러나 배열에서 푸시작업시 크기를 조정해야 하는 경우 O(n)의 시간 복잡도를 가질 수 있다.
<strong>ㄹ. 우리가 원하는 기능에 따라서 수정할 때 얼마나 효율적인지?</strong>
  -&gt;스택을 사용하여 함수를 수정하는 효율성은 함수 호출 및 재귀에 특히 유용하며,함수 호출은 각 함수 호출이 스택에 저장된 활성화 레코드로 표시되는 호출 스택을 사용하여 관리할 수 있다. 함수가 호출되면 활성화 레코드가 스택으로 푸시되고 반환되면 활성화 레코드가 스택에서 팝되는데 이런 과정으로 프로그램은 함수 호출 순서를 추적하고 실행을 효율적으로 관리할 수 있다.</p>
</blockquote>
<p>다음은 스택의 함수들에 대해 정리해보겠다.</p>
<p>2.함수 유형별 코드 
A.is_empty</p>
<pre><code class="language-c++">#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;


typedef struct stacktype {                //stacktype이라는 구조체를 정의 
    int arr[100];                        //stacktype 구조체 내에서 크기 100의 정수 배열 arr을 선언. 이 배열은 스택의 요소를 저장하는 데 사용한다.
    int top;                            //stacktype 구조체 내에서 정수 변수 top을 선언. top은 배열의 스택에 푸시된 마지막 요소의 인덱스를 추적한다.

}


void init(stacktype* s)                  //스택을 초기화하는 데 사용되는 init 함수 정의문.stacktype 구조체에 대한 포인터를 인수로 사용함
                                         //s는 stackType 구조에 대한 포인터를 나타내는 데 사용되는 매개변수 이름
{
    s-&gt;top=-1;                          //스택이 가리키는값을 -1로 초기화.배열은 인덱스가 0부터 시작하니깐 -1로 해놓고 인덱스의 합이 0이면 데이터가 하나 있는거고,-1이면 인덱스의 증가가 없는것이니 비어있는것                          
}



int is_empty(stacktype* s)               //스택이 비어 있는지 확인하는 is_empty 함수 정의문. stacktype 구조체에 대한 포인터를 인수로 사용함
{
    if (s-&gt;top == -1)                    //top 값을 - 1로 설정합니다.-1은 비어 있거나 잘못된 상태를 나타내는 데 자주 사용된다.즉 빈 스택을 나타냄.

        return 1;                        //스택이 비어 있으면 1을 반환
    return 0;                            //스택이 비어 있지 않으면 0을 반환
}
                                         //만약 비어있는곳에 데이터가 들어가면 마지막 요소의 인덱스를 추적하는 top이 0이 된다.또 데이터가 푸시되면 top은 1이 된다.

int main()
{
    stacktype s;                         //stacktype 유형의 s 변수를 선언하여 스택의 인스턴스를 생성
    init(&amp;s);

    is_empty(s);

    printf(&quot;%d&quot;, is_empty(s));

    return 0;
}</code></pre>
<p>a.top의 역할 
top 변수의 사용은 스택의 LIFO(Last-In-First-Out) 속성을 유지하면서 스택을 효과적으로 관리할 수 있게 한다. 요소가 push되거나 pop될 때마다, top 변수는 스택의 현재 상태를 추적하도록 그에 따라 조정된다.즉 스택 조작을 위한 필수적인 존재이다.</p>
<p>요소가 스택에 푸시되는 경우
-&gt; top 변수로 지정된 인덱스에서 배열의 인덱스가 추가되고 
top은 최상위 요소의 새 위치를 반영하여 증가한다.</p>
<p>요소가 스택에 팝되는 경우
-&gt; top 변수에 추적한 인덱스 요소가 배열에서 제거되고 
top가 감소하여 최상위 요소의 새 위치를 업데이트한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[STL(3)]]></title>
            <link>https://velog.io/@kiwi_100/STL3</link>
            <guid>https://velog.io/@kiwi_100/STL3</guid>
            <pubDate>Fri, 28 Jul 2023 08:26:01 GMT</pubDate>
            <description><![CDATA[<h1 id="set이란-무엇인가">set이란 무엇인가?</h1>
<p>1.set
집합이란 개념을 코드로 구현한게 set이다.
수학에서의 집합처럼 얘도 데이터(값,변수)를 넣으면 뭘 넣던 자동으로 정렬해서 집합을 만들어준다. </p>
<p>a.첫번째 특징
백터같은 경우는 푸시백을 쓰면 넣은 값들이 넣은순서대로 그대로 출력되는데
셋은 값들을 넣으면 그걸 다시 어떤 기준으로 정렬시켜준다.</p>
<ul>
<li>정렬이 돼서 좋은점 : 탐색이 빨라진다.
백터에서는 원소가 정렬이 안되어있으니 특정 숫자를 찾으면 배열을 다 뒤져야된다.
근데 셋은 정중앙의 원소부터 왼쪽 오른쪽 중 왼쪽부터 보고 또 그 왼쪽의 왼쪽이 있다면 그 왼쪽부터 오른쪽순으로 본다.오른쪽에 값이 없을때 끝난다. 
(자료구조의 트리 공부하기)</li>
</ul>
<p>내가 특정값을 찾으면 반을 나눠 나보다 작으면 왼쪽 크면 오른쪽하는식으로 효율적으로 하는것</p>
<p>b.두번째 특징
중복되는 값을 허용하지않는다.(넣으면 생략해버림)
== Key값과 Value값이라는 개념이 있어야 이해 가능
Key값 : 중복되지않는 값
Key값이 존재한다 == 원소들이 다 key값이다.</p>
<ul>
<li>백터는 값이 중복될 수 있다.</li>
</ul>
<p>c. set의 단점
트리구조로 데이터를 넣어서 관리하다보니 데이터 하나 넣을때 시간이 걸린다.
또한 삭제할때도 시간이 걸린다.
(깊게 이게 어떻게 구현된것까지는 알필요없고 사용법과 이런 이슈가 있단것만 기억하자)</p>
<p>2.set의 사용법
백터처럼 선언하고 클래스 템플릿안에 있는 set 멤버함수 갖다가 사용하면된다.</p>
<p>set <int> s;   //기본 선언방법</p>
<ul>
<li>set은 푸시백이 없다.(뒤에 넣어줄 필요가 없는게 넣을때마다 정렬해버리니깐)</li>
</ul>
<p>3.set의 멤버함수들
insert
erase
begin, end
rbegin, rend</p>
<h2 id="map이란-무엇인가">map이란 무엇인가?</h2>
<p>set하고 거의 동일한데 차이점이 아래와 같이 하나있다.
map도 key값이 있고, 자동정렬되며 사용법도 동일하다.
셋은 키값과 밸류값을 따로 저장하는데 맵은 키값과 밸류값을 묶어서 저장한다.
(==키에 해당하는 밸류값을 추가로 저장할 수 있다.)
예로 들어 주민번호라는 키값을 두고 우리가 그 외 정보가 필요할때 그 외 정보를 밸류값으로 두면 그 부가정보들을 밸류값들로 잡아 중복안되는 키값과 묶어줄 수 있음</p>
<p>민원 정보 조회시 주민번호 치면 다나오는것이 map이다.다만 인서트할때 추가로 밸류값을 넣어줘야된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[STL(2)]]></title>
            <link>https://velog.io/@kiwi_100/STL2</link>
            <guid>https://velog.io/@kiwi_100/STL2</guid>
            <pubDate>Thu, 27 Jul 2023 02:20:12 GMT</pubDate>
            <description><![CDATA[<p>3-1.vector
배열의 붙어있는 형태,사용법과 유사하긴한데 차이점으로 백터는 크기가 정해져있지않은 &quot;무한대 배열&quot;이란것.</p>
<p>내가 만약 10개인데 11개를 넣었으면 백터는 크기를 자동으로 늘려준다.
다만 아쉬운점은 배열에 비해 속도가 좀 느리다.(배열을 보강하고자 만듬)</p>
<p>배열은 이름과 인덱스로 관리했었는데, 백터는 클래스(백터라는 클래스)로 백터객체가 요소들(객체)을 관리한다.백터객체는 아래와 같다.</p>
<p>Ex)
vector<int>MyVector
//백터(배열)긴 한데 int형 백터(배열)이다.이렇게 백터 객체를 만듬</p>
<p>우리가 클래스 객체를 선언하면 눈에 보이진않지만 숨겨져있는 멤버변수와 멤버함수가 있는데 이 두개를 정의하는것은 클래스를 따라간다.(클래스:붕어빵틀,객체:붕어빵,객체 만들때마다 똑같은게 계속 생겨남)</p>
<ul>
<li>백터의구조 -&gt; 피피티 참고</li>
</ul>
<p>이 백터란 클래스에 대해 알아보자면 </p>
<ul>
<li><p>push_back함수
== 배열 뒤에다가 값을 붙여준다.
배열이 없는 상태에서 푸시백을 해서 하나의 값이 들어가는 상황에서 함수가 실행하게되면 메모리공간(네모칸)이 없으니 동적할당을 받아 한 칸을 만들고 그 값이 한 칸에 들어가게된다.for문으로 푸시백이 반복 실행돼서 또 들어가는 경우는 한 칸을 동적할당으로 받아 기존 한 칸에 붙여 두 칸을 만드는게 아니라 기존에 있던 한 칸을 딜리트하고 안에 있던 값은 복사해놓은다음 동적할당으로 두칸의 메모리공간을 새로 받고 복사했던 값은 첫째칸에 그리고 새로 푸시백한 값은 두번째 칸에 넣는다.이런식으로 반복</p>
</li>
<li><blockquote>
<p>부족하면 새로 크게 받아오고 값들은 복사해서 붙이고 푸시백해서 넣고</p>
</blockquote>
</li>
<li><blockquote>
<p>백터가 메모리가 많다보니 이런 경우는 동적할당을 많이함</p>
</blockquote>
</li>
<li><p>size()
vector<int> v1;이라고 백터 객체를 선언하고 객체 v1의 멤버함수인 size를 쓰기위해서는 v1.size()라고 쓴다.이것은 v1 안에 들어있는 원소의 갯수를 리턴해준다.(이것이 어떻게 만들어졌는지는 신경x 뭔지만 알자)</p>
</li>
</ul>
<p>백터를 선언할때 for문으로 푸시백해서 배열에 값을 넣어주는걸 5번 돌렸다고 치면 size 했을때는 5를 반환해준다.</p>
<p>*벡터는 배열의 문법을 그대로 쓸 수 있어 v1[i] 이런식으로 접근할 수 있다.
이유는 얘도 동적할당 받으면서 통째로 붙어있는 메모리를 빌려오니깐 접근이 가능함</p>
<p>*메인에 있는 백터 객체는 스택영역에, 백터 객체 안의 멤버변수와 멤버함수는 힙영역에 </p>
<p>3-2. vector의 멤버변수
a. 백터는 무조건 12바이트(백터 자체가 12바이트고, 무한대란건 백터가 가리키는 공간이 무한이란것이다.)</p>
<p>우리가 동적할당할때 주소값을 받아오기때문에 포인터로 받아오는데 이때 int형 1개를 받아오든 100개를 받아오든 포인터의 크기는 변하지않는다.그거랑 같음</p>
<p>b.백터는 Size, Data, Capacity라는 멤버변수 3개를 가지고있다.</p>
<p>Size : 백터가 저장하고 있는 현재 원소의 갯수</p>
<p>Data : 동적할당받은 배열의 메모리 시작 주소,얘를 포인터변수의 이름으로 보면된다.
얘를 가지고 배열이 필요할때마다 동적할당받아 가져오는것.배열 2개짜리를 받든 추가로 늘리든할때마다 동적할당으로 주소값을 계속 받아서 이 포인터 변수인 Data가 들고 있는것이다.</p>
<p>Capacity : 백터가 담을 수 있는 최대 원소의 갯수</p>
<p>3-3.또다른 백터의 활용법(반복자를 이용했을때)</p>
<p>vector<int> v1;</p>
<p>for(int i =1; i &lt;= 5; i++ )
v1.push_back(i);</p>
<p>for(auto i = v1.begin(); i != v1.end(); i++)
  cout &lt;&lt; *i &lt;&lt; &quot; &quot;;</p>
<p>이게 이터레이터(반복자)라는건데 </p>
<ul>
<li>auto : i의 자료형을 알아서 써주는 자료형이라고 생각하면된다.맞춰주는 기준은 i 오른쪽의 v1.begin()이 기준이 된다.이 자리에 int형 변수를 쓰면 int로 바뀐다.)</li>
</ul>
<p> -&gt; auto i = v1.begin();부터 i != v1.end();까지 i++하면서 돌려라
-&gt; 첫번째 구문은 백터의 첫번째 원소를 가리키는애가 i라는 표현한 것이고 
-&gt; 두번째 구문은 백터의 마지막 원소가 아닐때까지 돌려라
  (여기서 end()는 끝에 위치한 메모리가 아니라 그 다음에 있는 외의 지점을   말한다.마지막 다음이여서 end함수를 리턴하면 그곳의 값이 나옴
  즉,++하면서 베열의 end 나오기 전까지 메모리들을 돈다.</p>
<p>*i는 i가 가리키는 곳의 원소을 의미함 거길 가서 그 원소를 찍어준다.
 즉 배열의 원소를 계속 가리키는것</p>
<p>즉 v1안에 Data라는 포인터가 있다고하면 그 Data가 가리키는 배열이 있을것이고 v1.begin과 v1.end로 반복자(i가 반복자다.Iterator의 I)를 뜯어온다.그리고 그 반복자가지고 값에 접근할 수 있다.</p>
<p>반복자는 포인터 문법과 비슷하며, 객체의 멤버변수와 멤버함수에 접근할 수 있다.</p>
<p>3-4.vecter의 멤버함수들(인터넷 참고)
ㄱ.Iterator 관련 멤버함수
begin
첫 번째 원소를 가리키는 반복자를 리턴한다. 
end
마지막 원소를 가리키는 반복자를 리턴한다. </p>
<p>등등</p>
<p>ㄴ.Capacity 관련 멤버함수 
empty
원소 존재 유무를 체크한다.아무것도 없으면 true, 있으면 false를 리턴한다.
resize
백터의 크기를 변경하고 default값이나 임의의값으로 초기화한다.</p>
<p>등등</p>
<p>ㄷ.Modifiers 관련 멤버함수
clear
백터의 모든 함수를 제거한다.
Push_back
벡터의 끝에 원소를 추가한다.</p>
<p>3-4.백터의 사용법 
-&gt; 강의에선 인터넷의 함수들을 보면서 쓰면된다해서 이건 강의 정리가 끝난후 새로 STL을 정리할때 정리하겠다.(이론으로 x,경험으로 터득)</p>
<p>4.블루프린트에서 쓰는 동적배열과 백터의 차이
ㄱ.동적배열
동적 메모리 할당을 이용한 생성한 배열
c++ 공부하면서 new 연산자로 힙영역으로부터 메모리를 빌려오고 거기에 데이터를 넣으며  Delete로 반납했던 문법이 동적 배열을 쓰는 방식이다.</p>
<p>문법에 있던  포인터 변수(배열)로 원소들을 for문 돌면서 초기화 시키고 for문 돌면서 원소를 인자로 하는 원하는 함수를 실행시키고 마지막에 delete하는식</p>
<p>ㄴ.백터 
c++에서 동적 배열 대신에 쓰는 크기가 변하는 컨테이너(자료구조)</p>
<ul>
<li>이전에 동적할당은 초기화 과정에서 크기를 정해줬는데 크기 정해줄 필요없다.</li>
<li>동적배열과 비슷하게 동적할당을 하며 크기를 확장할 수 있다. </li>
<li>백터라는 클래스 탬플릿이기에 자료형에 구애받지않고 클래스 안 여러 멤버함수를 이용할 수 있다.</li>
</ul>
<p>5.언리얼엔진에선 백터보다 TArray라는 컨테이너 클래스를 써서 이 배열을 위주로 학습할 예정이다.</p>
<p>참고사이트<br>언리얼엔진 공식사이트(TArray: 언리얼 엔진의 배열) <a href="https://docs.unrealengine.com/4.26/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/TArrays/">https://docs.unrealengine.com/4.26/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/TArrays/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[STL(1)]]></title>
            <link>https://velog.io/@kiwi_100/STL1</link>
            <guid>https://velog.io/@kiwi_100/STL1</guid>
            <pubDate>Wed, 26 Jul 2023 01:43:30 GMT</pubDate>
            <description><![CDATA[<p>#STL이란?
Standard : 표준 -&gt; c++을 개발하는 곳에서 만든것
Template : 자료형의 구애받지 않고 함수가 동작하는것
Library : 언리얼엔진으로 치면 플러그인같은것(==로드해서 쓸 수 있는 코드 집합채)</p>
<p>c++에서 프로그램에 필요한 자료구조와 알고리즘을 Template(자료형에 구애받지않는 형틀)로 제공하는 가져다쓰는 코드 집합채를 STL이라고 한다.</p>
<p>좀 더 쉽게 말하자면 c++의 자료구조와 알고리즘을 자료형에 관계없이 편하게 쓰게끔 나온 플러그인이 STL이다.</p>
<p>템플릿에 대한 개념 추가 이해를 위해 유튜브 강의(탬플릿은 무엇인가)를 듣고 아래와 같이 학습하였다.</p>
<p>1.Template의 개념</p>
<ul>
<li><p>STL은 다 템플릿으로 구현되어있다.</p>
</li>
<li><p>템플릿의 종류 : 1.함수 템플릿 2.클래스 템플릿</p>
</li>
<li><p>함수 템플릿이란?
오버로딩(같은 기능의 함수들을 이름을 하나로 중복하여 쓰이는 함수며,차이점은 들어가는 매개변수의 타입 즉 자료형이 다른 것)된 함수가 있는 경우 이걸 자료형의 차이만 있는것이니 자료형에 대한 타입을 나누지말고 하나로 묶어주자한 것</p>
</li>
<li><blockquote>
<p>함수를 만드는 형틀(Template)을 만들자!(!= 함수)</p>
</blockquote>
</li>
<li><p>함수 템플릿 만드는 방법 
1) 아래와 같이 템플릿을 선언하고 꺽쇠 안에 typename이라고 쓰고 그 뒤에 앞으로 너가 어떤 이름으로 자료형을 쓸건지의 목적으로 이름을 써준다.예로 들어 t라는 자료형을 부를거면 타입네임 뒤에 t라고 쓰면된다.(이름은 자유)</p>
</li>
</ul>
<p>template <typename      ></p>
<p>이제 기존 함수에 매개변수 자리에 있던 자료형들을 일일히 써줄 필요없이 내가 붙여준 자료형명만 써주고 뒤에 마저 인수만 들어가면된다.</p>
<p>함수 템플릿 적용 전 
void testfunc(int a, int b, int c)
{
  cout &lt;&lt; a &lt;&lt; b &lt;&lt; c;
}
void testfunc(float a, float b, float c)
{
  cout &lt;&lt; a &lt;&lt; b &lt;&lt; c;
}</p>
<p>함수 템플릿 적용 후</p>
<p>template <typename t>  </p>
<p>void testfunc(ㅊ a, t b, t c)
{
  cout &lt;&lt; a &lt;&lt; b &lt;&lt; c;
}
void testfunc(t a, t b, t c)
{
  cout &lt;&lt; a &lt;&lt; b &lt;&lt; c;
}</p>
<p>이렇게 하면 어떤 타입의 인수를 보내든 다 처리해주는 만능 함수가 되게끔해줌</p>
<p>2) 여기서 중요한건 탬플릿은 함수가 아니라 형틀이다. 이 형틀이 있으면 컴파일러가 함수 템플릿을 선언한 코드를 실행할 때는 컴파일러가 탬플릿 자료형이 속에 인자가 int였으면 그게 int형을 받는 함수라고 인지하고 int형 함수를 하나 만든다.다름 오버로딩된 함수의 매개변수를 보고 또 다른 자료형의 함수를 생성한다.(공장처럼 형틀이 찍어냄)</p>
<p>즉 최종적으로는 컴파일러가 호출문을 보고 탬플릿을 가지고 실제 함수들을 만든다는것이다.이때 만들어진 함수를 &quot;템플릿 함수&quot;라 한다.여기서 형틀이 아닌 실제 함수가 만들어진 것임.(<strong>위에는 함수가 아닌 형틀이다</strong>)</p>
<p>3) 템플릿 함수가 만들어지는 만큼 실제로 호출될 때마다 메모리는 다 할당된다.</p>
<p>4) 호출 시 이렇게 써주기 </p>
<p>int main()
{
    testfunc(3,5,8);
      testfunc(2.1,9.5,4.3);</p>
<pre><code>  return 0; </code></pre><p>}</p>
<p>호출할때 &#39;t&#39;한테 무슨 자료형으로 넘겨줄것인지를 함수이름과 인수 사이에 꺽쇠 안에 해당 자료형을 써줘야한다.</p>
<p>testfunc(3,5,8); -&gt; testfunc<int>(3,5,8);
testfunc(2.1,9.5,4.3); -&gt; testfunc<float>(2.1,9.5,4.3);</p>
<p>이렇게 안적어주면 컴파일러는 인수의 타입을 보고 그 인수의 자료형이라고 판단한다.만약 꺽쇠의 자료형과 인수의 자료형이 일치하는 경우는 &lt;자료형&gt;을 생략해도된다.그래도 정확한 방법으로 쓰자.</p>
<p>5) 탬플릿이 만드는 탬플릿 함수는 호출구문수와 비례한다.</p>
<pre><code>               출처 : 유튜브 허니C / C++ template 1 | 템플릿이 뭐예요??? | STL</code></pre><p>2-1. STL의 구성요소 6가지
a. Container(컨테이너)
b. Iterator(이터레이터)</p>
<ul>
<li><p>이터레이터는 포인터와 비슷한 개념으로 컨테이너의 원소를 가리키고,가리키는 원소에 접근하여 다음 원소를 가리키는 기능을 말한다.순회
c. Algorithm
d. Function Object
e. Container Adaptor
f. Allocator</p>
</li>
<li><p>d,e,f</p>
</li>
<li><blockquote>
<p>잘 안쓰이고 이론상에서 설명을 위해 쓰이는 정도여서 수업에선 skip됨</p>
</blockquote>
</li>
</ul>
<p>2-2. Container(컨테이너)
a. 객체를 저장하는 객체, 자료구조 라고도 한다.클래스 탬플릿으로 구현되어있다.컨테이너는 같은 타입의 여러 객체를 저장하는 객체로 일종의 객체들의 집합이다.  </p>
<p>-&gt; 배열처럼 한 객체(클래스 변수)로 여러 객체(클래스 변수)가 그 예다.이 배열같은 것이 바로 자료구조(==효율성을 위해 변수,숫자 등의 데이터들의 구조를 설계해서 저장하는 것)다. </p>
<p>ex) int형 변수(객체)를 어떻게 보관할 것인가?</p>
<p>-&gt; 컨테이너는 클래스 탬플릿으로 작성되어 있어 컨테이너 변수를 생성할 때 탬플릿 인자로 요소의 타입을 명시해야 한다.따라서 대입할 수 있는 타입의 객체만을 저장해야하며 복사 생성 또한 가능하다.또한 요소 추가 및 제거를 포함해 다양한 기능을 수행하는 멤버 함수가 존재한다.</p>
<p>b. 자료구조의 종류 : 배열 외 5가지</p>
<ul>
<li>자료구조학에 자세히 설명이 되어있는데 이건 이론에 중점이 맞춰져있고 STL은 이 이론을 구현해놓은것이여서 이걸 보면서 나올때마다 자료구조 이론을 찾는식으로 학습하기 </li>
</ul>
<p>ㄱ. 배열</p>
<ul>
<li>장점 : 빠른 데이터 접근.
물리적으로 배열은 객체들이 붙어있기에 인덱스와 주소값으로 접근이 쉽다.</li>
<li>단점 : 크기가 정해져있음.
(크기를 적게잡아도 성공시 손해,크게 잡아도 메모리 낭비니 손해)
이런 자료구조의 단점 때문에 다른 자료구조가 나온다.</li>
</ul>
<p>c. 컨테이너의 종류<br>  ㄱ.시퀀스 컨테이너(Sequence Container) 
    - array(c++11), vector, list, deque
  ㄴ.어소시에이티브 컨테이너(연관,Associative Container)
    - set, multiset, map, multimap</p>
<p>2-3. Algorithm(알고리즘)
a. 알고리즘의목적
자료구조에 저장된 데이터들이 어떻게 효율적으로 활용될 수 있는가를 정리해놓것</p>
<ul>
<li>활용을 한다 ==  데이터를 어딘가로 옮기거나 or 정렬을 해주거나 or 중에 검색을 한다던가 or 삭제한다던가 </li>
</ul>
<p>b. 정렬, 삭제, 검색, 연산 등을 해결하는 일반화된 방법을 제공하는 
  함수 템플릿</p>
<p>c. 멤버함수로 자료구조를 컨트롤한다.</p>
<p>2-4. Iterator(반복자)
a. 이터레이터의 목적
이터레이터는 포인터와 비슷한 개념으로 컨테이너의 원소를 가리키고,가리키는 원소에 접근하여 다음 원소를 가리키는 기능을 말한다.순회</p>
<p>이터레이터라는 클래스의 객체가 있다고 가정해보자.이 객체가 컨테이너에 접근할 때 이 포인터가 생긴 반복자(이터레이터)가지고 원소 하나하나를 가리키게 된다.포인터는 그냥 변수지만 이건 이터레이터라는 클래스의 객체란 걸 기억</p>
<p>기본적으로 클래스의 멤버 변수로 가지고 있다.</p>
<p>2-5.STL 안에도 여러 클래스가 존재함
클래스 하나당 컨테이너,이터레이터,알고리즘이 무조건 들어간다.</p>
<p>컨테이너   </p>
<ul>
<li><p>시퀀스 컨테이너에서는 vector를 우선적으로 배우면 나머지는 비슷한 문법들이여서 보다 잘 학습할 수 있다.</p>
</li>
<li><p>시퀀스 컨테이너는 특별한 규칙이 없는 일반적인 자료구조로 순서가 있는 선형구조다.백터,데큐,리스트,단방향 리스트로 존재함</p>
</li>
<li><p>시퀀스는 요소가 언제 삽입되는지에 따라 배열안에서의 요소 순서가 결정된다.즉 연속되게 저장하는 배열같은 구조이다.하지만 특이하게 list는 다음 요소의 주소를 가리키는 노드 구조를 가지고있다.</p>
</li>
<li><p>연관 컨테이너는 set이 map 안에 들어있어 map을 배우면 나머지를 상대적으로 잘 이해할 수 있다.</p>
</li>
<li><p>특정 규칙에 의해서 자동으로 정렬,저장,관리하는 컨테이너,순서가 없는 비선형구조다.세트,멀티세트,맵,멀티맵으로 존재함</p>
</li>
<li><p>요소가 작으면 왼쪽을 가리키고 크면 오른쪽을 가리키는 등 어떤 기준에 따라 정렬된다.따라서 순서가 없고 기준에 따라 다음 요소의 메모리 주소를 가리키는 노드구조이다.</p>
</li>
<li><p>컨테이너 어댑터는 간결함과 명료성을 위해 인터페이스를 제한한 시퀀스나 연관컨테이너의 변형이다.반복자를 지원하지 않아 STL 알고리즘에서는 사용할 수 없다.</p>
</li>
</ul>
<p>이터레이터
실습을 하면서 반복자를 공부하되 반복자의 종류는 상관없으니 종류별 공부는 skip하기</p>
<p>알고리즘
STL의 목적이 일반적인 알고리즘에 대한 효율적인 구현을 제공하는 것이다.
따라서 알고리즘에서는 컨테이너를 알고리즘을 통해 동작시키는데 필요한 많은 함수을 제공한다.따라서 컨테이너는 STL알고리즘 함수와 함께 사용되며 반복자를 통해 컨테이너에 적용시킨다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C ++ 이론(8)]]></title>
            <link>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A08</link>
            <guid>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A08</guid>
            <pubDate>Thu, 20 Jul 2023 09:27:50 GMT</pubDate>
            <description><![CDATA[<h1 id="rtti">RTTI</h1>
<p>== 런타임의 자료형이 정해지는 타입.다형성과 STL이 여기에 속한다.
== 자료형이 일정하게 정해져있지않고 런타임의 어떤 객체냐에 따라서 그 타입으로 변환시켜주는 존재
== 실행 전에는 어떤 함수가 호출될지 모르는데 실행됐을때의 객체에 따라서 자료형이 자유자재로 변하는게 RTTI란 개념이다.
==virtual 클래스로부터 상속이 하나라도 존재하면 RTTI를 사용하고있다고 보면 된다.</p>
<ul>
<li>가상함수 테이블이 RTTI를 도와준다.</li>
</ul>
<p>dynamic_cast가 가상함수테이블이 필요없는 경우에는 static_cast를 사용하게끔 되어있고 실행이 되고나서 자료형이 정해지는 경우는 가상함수테이블이 필요해서 dynamic_cast로 RTTI를 적용하여 작동하는 구조로 설계되어있다.</p>
<ul>
<li>reinterpret_cast는 위험하고 쓰지도않아서 스킵</li>
</ul>
<h2 id="template">Template</h2>
<p>== 자료형에 구애받지않는
== 자료형에 관계없이 실행 가능하게해주는 존재</p>
<ol>
<li>오버로드 </li>
</ol>
<p>기존에 우리는 함수를 짤때 자료형 하나로만 입력값을 받고 반환했었는데 다른 자료형에 대한 함수를 만들어달라하면 함수정의문과 호출문을 그때마다 추가해야된다.</p>
<p>ex)
int addNum(int a, int b)
{
    return a+b;
}
float addNum(float a, float b)               //오버로드 된 함수
{
    return a+b;
}</p>
<p>그렇게 오버로드 된 함수는( 오버로드 == 함수정의문의 이름과 내용은 같은데 매개변수의형태 즉 자료형이 다른것 ) 아래처럼 얼마든지 더 만들어도 문제가 되지않는다.(이걸 오버로드 된 상태라고 한다.)</p>
<p>float addNum(float a)
{
    return a;
}</p>
<p>char addNum(char a)
{
    return a;
}</p>
<p>이렇게 4개의 함수 정의문이 있는데 메인함수에선 호출문에 들어가는 인자의 형태에 따라 함수이름이 동일한데도 불구하고 인자 형태(자료형,인자 갯수)에 맞는 함수가 호출이된다.</p>
<ul>
<li>flaot은 인자 끝에 f 써주는것 잊지말기</li>
<li>함수를 치고 괄호를 열면 조금한 창이 뜨는데 동일 함수 갯수와 형태가 뜸</li>
</ul>
<p>2.오버로드의 조건 두 가지
 ㄱ. 함수 이름이 동일해야된다.
 ㄴ. 함수의 매개변수 갯수나 자료형이 달라야한다.(갯수만 다른것도 가능)</p>
<p>3.오버로드의 한계
추가되는 요구에 대응하기위해서 나온 개념이 오버로드인데 이 오버로드도 동일함수명이 무수히 많아지기때문에 한계가 있다.그래서 문법적으로 다 통일해서 하나로 만든 탬플릿이 나오게 된다.</p>
<ul>
<li>오버라이드 함수는 부모의 메서드만 재정의한것을 말함(필드는 재정의할 수 없음 주의!).오버라이딩 된 함수는 부모의 함수 이름, 반환값, 매개변수 등이 완벽하게 부모와 동일하다는게 특징이다.(부모의것을 그대로 가져와서 메서드만 바꿔준거니깐)</li>
</ul>
<p>4-0.Template</p>
<p>4-1.탬플릿의 구조 </p>
<p>Template&lt; class T &gt;
T addNum(T a, T b)
{
    return a+b;
}</p>
<p>구조는 우리가 만들었던 클래스,구조체와 비슷하다.왜냐하면 이것 또한 사용자에 의해 창조되는 자료형이기때문이다.그리고 매개변수 자료형 자리엔 T가 위치함</p>
<p>4-2. 특징 
T가 인자가 들어오면 인자의 자료형에 따라 동일하게 변경돼서 맞춰준다.
그게 언제냐면 런타임때(=함수 호출로 실행시)
뭐가 들어오던지 다 커버가 가능.
앞에 오버로드와 기능은 동일하지만 훨씬 더 효율성 있게함.
클래스를 넣는것도 가능하지만 그건 계산 용도로는 불가</p>
<h3 id="stl">STL</h3>
<p>탬플릿을 표준적으로 어떻게 쓰는가를 뜻함</p>
<p>기존에는 함수에다가 적용했다고하면 이번엔 변수에다가 탬플릿을 적용한다.
변수는 자료형이 정해진건데 STL은 이 변수의 자료형을 좀 더 유연하게 쓸 수 있게끔해준다.</p>
<p>배열도 우리가 여러 자료형으로 다 만들었던것 생각하면 배열도 탬플릿이다.
이런 배열 같은 애들의 종류가 몇 개 존재한다.
그리고 이런걸 자료구조라고 한다.</p>
<p>자료 == 데이터 == 변수들, 상수들, 어떤값들처럼 컴퓨터에 저장이 되는 존재
-&gt; 이런 자료들을 어떤 방식으로 구조를 짜서 저장할거냐라는게 &#39;자료구조&#39;라는 학문이다.</p>
<p>배열은 자료구조 중 하나로 데이터 하나하나가 일렬로 붙여서 유지한다는 특징이 있는데 이걸로 사용자는 인덱스가 있어서 배열이름(주소값)에 자료형만큼의 크기 곱하기 원소 갯수를 해서 배열의 원소에 접근할 수 있다.</p>
<p>하지만 배열의 단점이 있는데 선언하면서 정한 크기는 바꿀 수 없다.또한 그 크기를 넘어가면 오류가 난다.이런 단점들이 있어 나온게 다른 자료들이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C ++ 이론 (7)]]></title>
            <link>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A0-7</link>
            <guid>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A0-7</guid>
            <pubDate>Tue, 18 Jul 2023 11:45:07 GMT</pubDate>
            <description><![CDATA[<h1 id="형변환">형변환</h1>
<p>== 기본자료형, 클래스, 구조체 등등 자료형을 바꿔준다.</p>
<p>자료형을 변환해줄 수 있는게 가능한 케이스가 3가지로 존재한다.</p>
<p>1-1.const_cast는 무엇인가?</p>
<p>const는 우리가 변수를 상수처럼 만드는것을 의미함
cast는 변환해준다는 뜻으로 즉 &quot;상수를 변환해준다&quot;와 같다.</p>
<p>우리가 코드를 짤 때 안전상으로 절대 안바뀔 변수에 const를 붙여 상수화를 시켜주는데 항상 계획은 변동사항이 있다보니 추가 기능을 요구하는 경우에 상수화 시킨 것들 중에 하나만 상수화를 시키지말자는 요구 사항이 생길때가 있다.그때 <strong>const를 빼주는 함수가 const_cast 함수다.</strong></p>
<p>-&gt; const라는게 애초에 절대 안건드린다는 취지로 쓰다보니 이 상황과 모순이여서 회사마다 다르지만 거의 사용하진않는다고한다.(문법적 차원에서 숙지)
이런 경우가 생긴다면 오히려 코드 설계를 바꾸는게 더 효율적이라고 한다.</p>
<p>1-2.const_cast 예제</p>
<p>void main()
{
   char str[]=&quot;string&quot;;<br>   const char * c1 = str;
   char * c2;</p>
<p>   c2 = const_cast&lt;char * &gt;(c1);
   c2[0] = &#39;a&#39;;
   printf(&quot;%s\n&quot;,c2);
}</p>
<p>한 줄씩 해석하자면 </p>
<p>a.char str[]=&quot;string&quot;;<br>-&gt; 배열 str을 선언하면서 문자열을 넣어줘 초기화시킴
  (대괄호가 공란일 경우 문자의크기에 맞춰 크기가 넣어짐)</p>
<p>b.const char * c1 = str;
-&gt; c1은 포인터 변수여서 주소값이 들어가야한다.str은 배열의이름이다보니 주소값을 지니고 있고 c1은 str이라는 배열을 가리키게된다.</p>
<p>-&gt; 상수화가 된 케릭터형 포인터 변수 c1 을 str배열을 가리켜 초기화시킴
c1은 변하지않는 상수화된 변수여서 값이 정해져있어야만 상수화가 된다.그 말은 const도 레퍼런스 변수이기에 생성과 초기화가 동시에 되어야한다.
(const는 붙여짐과 동시에 바로 옆에 =으로 초기화시켜줘야된다.아랫줄에 초기화를 하면 안된다.)</p>
<ul>
<li>레퍼런스 변수는 생성자에서 이니셜라이저(초기화)를 못한다.왜냐면 초기화를 동시에 해줘야되니깐</li>
</ul>
<p>c.char * c2;<br>-&gt; 케릭터 포인터 변수 c2를 선언</p>
<p>d.c2 = const_cast&lt;char * &gt;(c1);
-&gt; 여기서 const_cast 함수가 나오는데 </p>
<p>구조는 const_cast&lt; 원하는 자료형 &gt;(바꿔줄 인자);
괄호 안에 인자(해당 바꿀 변수)를 넣어 꺽쇠 안에 있는 자료형으로 바꿔주는것</p>
<p>인자로 c1을 넣어주면 c1의 자료형인 const char * 가 const를 제거한 char * 로 바뀌는것이다.</p>
<p>그런고로 char * c1 = str;이 되고 c1이 가리키는 str이 c2에 넣어진다.
그래서 c2도 str을 가리키게된다.</p>
<p>e.c2[0] = &#39;a&#39;;
-&gt; c2는 애초에 상수도 아니였고 const도 없기에 값이 변경이 가능하다.그래서 str에 넣어준 문자열에 접근해서 값을 변경하는게 가능하다.</p>
<p>string의 0번째 원소 값인 &#39;s&#39;를 &#39;a&#39;로 바꿔준다.</p>
<p>f. printf(&quot;%s\n&quot;,c2);
-&gt; atring이 출력된다.
-&gt; 바로 이렇게 const를 제거 혹은 상수화를 해제하고싶을때 컨스트 케스트란 함수를 쓴다.</p>
<hr>
<p>2-1. static_cast 함수란 무엇인가?</p>
<p>명시적 형 변환을 위한 캐스트 연산자
== 강제적으로 자료형을 바꿔줄때</p>
<p>2-2. 예시</p>
<p>class super
{
};
class sub : public super          //부모로부터 자식이 상속
{
};</p>
<p>int main()
{
    sub * ss = static_cast&lt;sub * &gt;(new super());
}</p>
<p>//자식 포인터 변수에다가 new super(부모 객체를 동적할당 해온것)의 자료형을 sub * 로 static_cast해서 넣어주겠다.</p>
<p>인자 자리에 들어가는 new super()는 현제 변수의 이름이 아니라 힙영역의 이름없는 메모리며 접근할 수 있는 방법은 주소값 밖에 없기에 주소값 가지고 컨트롤해야된다.그런고로 그 주소값을 가리키는 자료형 포인터 변수가 인자에 들어가는 것 </p>
<p>동적할당하면 리턴값으로 주소값이 나온다.그리고 주소값을 받아온다는 것은 곧 포인터 변수(암기)</p>
<p>이 super라는 부모객체의 포인터 변수가 되는것이다.이걸 강제로 자식클래스인 sub * 로 자료형을 바꿔주겠다는것이다.</p>
<p>슈퍼라는 부모객체를 생성했기 때문에 원래는  super 포인터인데 이 포인터가 sub 포인터로 강제로 바뀌게된다.그리고 그 포인터변수가 가리키는 값이 즉 sub 포인터가 가리키는 주소값이 ss에 들어가게된다.</p>
<p>2-3.부모객체의 주소값을 자식객체에다가 바로 넣어주면안되는건가?
-&gt; 직접 그렇게 하면 에러가 난다.
-&gt; 이유는 포인터변수는 자료형을 맞춰줘야하는데 이때 예외사항으로 부모 포인터가 자식 객체를 가리킬때는 자료형이 달라도 가능했었다.근데 위같은 경우는 반대로 자식 포인터가 부모 포인터를 가리키는 형태다 보니깐 안돼서 (어려우면 이렇게 생각  sub * ss = new super() ) static_cast을 써줌으로서 자식과 똑같은 자료형으로 맞춰준것이다.자식 포인터가 자식 객체 가리키는건 가능 </p>
<p>2-4.이런식으로 사용하는 경우는 드물고 보통은 일반적인 자료형을 바꿀때 static_cast 함수를 쓴다.</p>
<p>예시)</p>
<p>float f라는 실수형 변수가 있는데 
float f = 5.6f라고 초기화 함
(5.6에 f를 붙여준 이유는 float라는걸 표시해주기위해서다. f를 안붙히면 double형으로 들어가버린다.)</p>
<p>내가 만약 int num에 변수 f를 넣어주면 출력했을땐 정수형이기때문에 5만 나온다.
이때 이건 c언어 특성상 0.6을 버리고 5만 나오게끔 하는거고 원래 정석 코드는 </p>
<p>int num = static_cast<num>(f);이다.</p>
<p>2-5.이처럼 static_cast는 강제로 자료형을 바꿔줄때 쓰인다.</p>
<hr>
<p>3-1.dynamic_cast 함수는 무엇인가?
(다형성과 상속의 완벽한 이해가 전재되야 활용가능)</p>
<p>-&gt; static_cast의 연한맛(강제여서 에러 안남)
-&gt; casting 할 수 있으면하게하고 못하면 에러방지차 리턴값으로 null 값을 반환한다.
   (빌드 오류,런타임 오류 등 에러나면 프로그램이 꺼지는데 그걸 방지)
-&gt; 상속받은 클래스인 경우에만 사용가능하다.</p>
<p>3-2
예시)</p>
<p>class super
{
};
class sub : public super          //부모로부터 자식이 상속
{
};</p>
<p>int main()
{
    sub * ss = dynamic_cast&lt;sub * &gt;(new super());
}</p>
<p>아까처럼 함수명만 다르고 자식의 포인터로 부모의객체를 가리킬려고하는데 그걸 자식으로 바꿔줘하는 상태다.
-&gt; 이것은 실행이 불가능하다.왜냐면 부모가 자식한테 물려주는건 되지만 자식이 부모한테 물려주는건 불가능해서다.
이게 무슨말이냐면 상속을 받는것에선 부모가 자식한테 물려주는건 가능하다.왜냐? 부모는 자기가 가지고 있는걸 그대로 물려주면되니깐 근데 자식이 부모로 변한다는것은 문제가 있다.</p>
<p>자식은 자식것을 나름대로 가지고있고,거기에 추가로 부모것을 가지고 있는 상태다.근데 자식 포인터 변수가 부모 객체를 가리킨다거나 부모 객체로 변하고싶으면 부모객체와 동일시되기위해 자식객체가 가지고 있던것(맴버변수 + 맴버함수)을 내려놔야한다.
코드란건 한번 정해놓으면 빌드까지 변화없이 가야되는데 중간에 코드를 버린다는것은 뭔가 잘못된것이다.곧 문법적으로 가능하지않은 상황이다.</p>
<p>근데 STATIC_CAST는 부모를 자식으로 바꿨었는데 그건 되냐? -&gt; 문법적으로 잘못된것임에도 불구하고 강제로 바꾼것
(필드와 매서드가 진짜 사라진게 아니라 사라진 척 하는 것)</p>
<p>DYNAMIC_CAST는 부모 객체를 자식으로 바꾼다.부모객체가 자식객체로 변할려고하면 자식객체에 있는 그 멤버변수, 멤버함수가 추가되어야하는데 그것도 불가능하다.코드가 없기때문이다.만약에 상속 관계였으면 물려받은 코드가 있을탠데 이 역순의 경우는 부모가 자식으로 변한기위해 자식과 같은 코드를 가지고있지않기에 말이 안된다.</p>
<p>그래서 DYNAMIC_CAST의 경우 부모 객체의 주소값이 있지만 그것을 자식 객체 포인터 변수로 캐스팅하는 과정에서 에러가 나는 상황이면 NULL을 리턴한다.그러면 자식클래스 포인터 SS는 NULL을 가리킨다.</p>
<ul>
<li>포인터변수를 항상 NULL 체크 해야된다는게 이것과도 관련이 있음</li>
</ul>
<p>STATIC_CAST의 경우는 NULL이 안나오는데 이게 문제가 되는게 뭐냐면 포인터변수에는 주소값이 들어있다.근데 이 포인터변수가 바뀐척만 하고 내용물은 그대로여서 프로그램 테스트 때는 통과가 되지만(NULL이 아니니깐) 나중에 프로그램을 실행했을때 에러가 나게된다.</p>
<p>반면에 DYNAMIC_CAST는 캐스팅 할 수 없는 상황에서는 NulL로 바꿔준다.-&gt; NULL이 띄어짐으로 인해 캐스팅이 제대로 안됐구나하고 인지가 가능</p>
<hr>
<p>4.STATIC와DYNAMIC의 차이
-&gt; 성능과 안전성이다.</p>
<p>STATIC 같은 경우는 정상적인 포인터인지 확인이 불가
단순변환이여서 속도가 빠름</p>
<p>용도 : 코드상으로 무조건 A가 B로 변하는 경우</p>
<p>DYNAMIC 같은 경우는 내가 NULL 체크만하면 정상적 캐스팅인지 확인 가능
단,단점 두 가지가 있음</p>
<p>ㄱ.상속받은 클래스 밖에 못쓴다.
ㄴ.느리다.
케스팅이 되는지의 판단을 Virtual 테이블(가상함수테이블)을 가지고 판단하는데 바꿀 수 있는 타입이면 바꾸고, 못바꾸면 NULL로 처리한다.이걸 참조하게되면서 속도가 느려지는 이슈가 있다.</p>
<p>*부모의 Virtual 함수가 하나라도 존재시 가상함수테이블이 생김</p>
<p>용도 : A가 뭘로 변할지 확신할 수 없는 경우
ex) 자식객체가 100개 있을때</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C ++ 이론 (6)]]></title>
            <link>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A0-6</link>
            <guid>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A0-6</guid>
            <pubDate>Mon, 17 Jul 2023 06:24:37 GMT</pubDate>
            <description><![CDATA[<h1 id="상속-심화">상속 심화</h1>
<p>1.상속 관계에서의 동적할당 주의점
 a.보통 동적할당 문법을 쓸 때 생성하고자하는 변수의 자료형과 포인터 변수의 자료형과    같아야한다.
 ( A * b = new A (o) / A * b = new B (x)? )
 b.꼭 다시 반납을 해야된다.</p>
<p> a에 대하여
 결국 이 두 자료형이 다르면 동적할당시 오류가 나는데 이때 c++에선 예외적으로 가능한 경우가 있는데 바로 **&quot;부모 클래스의 포인터가 자식 객체를 가리키는 경우에는 서로의 자료형이 달라도된다.&quot; **</p>
<p>포인터 자체가 가리키는 애의 자료형이 자신의 자료형과 동일해야된다.근데 예외적으로 상속관계일때 부모 클래스의 포인터변수가 자식의 객체를 가리킬때는 가능하단것이다. </p>
<ul>
<li>반대로 자식 포인터 변수가 부모의객체를 가리키는건 안된다. </li>
</ul>
<p>포인터변수는 자료형이 뭐든 다 4바이트다.이건 포인터변수가 하는일이 오로지 주소값을 저장하는 역할 밖에 없기때문이다.부모 포인터 변수도 역시 4바이트 하지만 이렇게 자료형을 서로 맞춰줬던 이유는 자료형을 혼용하고싶지않아서다.(혼동x) </p>
<p>근데 상속(부모의 필드, 메서드를 재사용하기 위함)이란 개념이 등장하면서 이 경우에 예외사항이 생긴것! 우리가 클래스를 관리하기위해 등장한 개념인 상속의 목적 즉 재사용하는 이유를 생각해보면 자식객체들이 부모의 것들을 공통적으로 가지고있으면해서인데 이러다보니 부모는 껍데기처럼 동작하는 느낌이다.(=부모한테서는 가져오기만 하고 껍데기로 놔두고 실제로 쓰는건 자식객체들)</p>
<p>ex)동물게임에서 동물(부모클래스)은 직접적으로 등장X, 동물의 구체적 이름들(자식클래스)이 등장o</p>
<ol start="2">
<li>오버라이드(부모로부터 물려받은걸 쓰지않는다고하고 자식 클래스에서 새로 재정의한것)된 경우에서 가능해진게 있는데 오버라이드 유무를 떠나서 자식이 부모것을 쓰든 안쓰든 공통적으로 가지고 있는 함수는 존재한다.바로 이점을 이용해서 내가 다가지고 있는 함수를 가지고 부모의 포인터를 이용해서 자식객체를 가리켜서 컨트롤해보자</li>
</ol>
<p>일반적인 상속 코드문이 있을때 메인함수에서 동적할당을 A * b = new B로 받고
b -&gt; 함수이름1(); 
b -&gt; 함수이름2();
이런식으로 호출한다고 가정해보자. (근데 이때 함수이름1이란게 부모, 자식 둘다 있음)</p>
<p>그러면 이때 이 함수이름 1이나2는 부모가 아닌 자식객체의 함수를 의미한다.포인터변수는 껍데기일뿐이고 생성한 실객체의 함수를 따라간다.이제 자식클래스가 여러개일때 어느 자식인지 구분이 안될탠데 그럴때 동적할당한 실객체에 의해서 결정이 나는것이다.</p>
<p>근데 이건 우리가 위에 있는 동적할당식을 봐서 아는거고 만약 호출문만 본다면 이 함수가 어느 자식 클래스의 함수인지 모른다.그래서 다형성(같은 형태지만 결과는 다르다)이라는게 필요한것이다.함수를 호출하는데 그 함수가 있는 클래스들이 A와 B였다면 A * b = new B에서는 B라는 자식클래스 속 함수를 호출했을것이고 new A였다면 A의 함수를 사용했을것이다.근데 이건 지금 동적할당식이 하나여서 우리가 구별한것이다.</p>
<p>3.만약 동적할당식이 여러개고 각 객체의 동일 함수 호출식을 써놓는다면 그건 어느 클래스의 함수를 말하는걸까?</p>
<p>위에서 말한 다형성의 특성 덕분에 자식객체들을 효율성있게 관리할 수 있다.
부모 포인터 변수로 여러 종류의 자식 객체들을 일괄적으로 컨트롤할 수 있다는것인데
한번에 관리할 수 있다는 것이 무슨뜻이냐면 예로 들어 동물 프로그램에서 부모 속 무브라는 움직이는 함수가 있지만 종류가 다른 자식 객체들에서 무브는 각자의 맞는식으로 재정의해서 쓰이는 함수가 될 것이다.객체를 여러개 생성한다했을때 여러 종류의 객체를 가리키는 동적할당식을 여러번 쓴다고하면(포인터 하나당 객체 하나) 내가 무브라는 함수를 호출했다고했을때, 그 무브가 어떤 자식의 함수인지 몰라 컨트롤 못하지않냐인데 우리는 그냥 부모 포인터(b)한테 무브라는 함수 호출(b-&gt;move)만 해주면 알아서 객체의 타입에 따라서 그 속의 무브가 자동으로 실행된다.</p>
<p>4.근데 다형성에 동적할당은 세트로 가는 형태인가?</p>
<p>별개다. 내가 동적할당을 쓰는 이유는 지역변수나 전역변수의 메모리의 한계가 있을때 혹은 유동적으로 메모리 크기를 조절할 수 있다는 메리트 때문에 쓰는거여서 직접적으로 다형성 때문에 쓰는건아니다.근데 다형성을 구현할려면 동적할당을 써야되는건 맞다.</p>
<p>ㄱ.첫번째 이유
<strong>이 동적할당이 포인터를 이용하기 때문이다.</strong></p>
<p>다형성은 포인터를 이용하기로한 개념이기 때문에 동적할당이 구문에 들어간 것이다.
동적할당 식을 보면 우리는 이름없는 메모리를 포인터로 받아온다.
근데 보통은 포인터변수와 가리키는 객체의 자료형이 일치하는데 예외적으로 다형성에선 자료형이 다른 경우가 앞의 내용인 것.</p>
<p>ㄴ.두번째 이유(자식 객체를 가리키는 건 왜 사용하냐?)
부모 포인터로 자식객체를 가리키는 이유는
부모는 자식이 내것을 가져다썼으면 좋겠고, 형태는 비슷해도 다르게 썼으면 좋겠다는게 상속이였다.그러면 <strong>이 자식이 무조건 부모의것을 가지는 성질을 이용해보자</strong>라는것이다.</p>
<p>함수를 호출하는 구조는 일반적이든 무슨 구문이든 쓰는 방식은 다 똑같다.
(메인함수내에서 함수이름();이라고 입력)
그리고 이걸 포인터와 연계해서 호출하곤 한다.포인터는 가리키는애의 값을 읽거나 변경할 수 있고 안에 있는 함수를 호출할 수 있다.( temp-&gt;b();이런식으로 )</p>
<p>ㄷ.그렇다면 이걸 쓰는 이유를 다시 정리해보면 다음과 같다.</p>
<p>예시)
동물(=부모클래스)이 있고 그 밑에 각 동물의 종류 100마리(=자식클래스)가 있는데 그중에 물고기3마리, 인간 50명, 새 21마리 나머진 기타 등등이 있는데 만약 부모클래스에 move라는 함수가 있다고 가정하면 이걸 한번에 호출해서 컨트롤하는게 효율적이지 각각 무브하라고 호출하는건 비효율적이다.(지금 대량의 객체를 컨트롤하는게 기준이며, 하나만 움직이고싶다 이런 생각은 배제하기) 한번에 호출하면 컴퓨터가 자동으로 각 함수의 맞는 자식클래스와 매칭시켜줘서 작동시킨다.</p>
<p>다시말해 효율성을 위해서 자식클래스들이 어차피 move란 함수를 똑같이 다 가지고있단 성질을 알고, 내가 부모 포인터로 자식 객체를 가리킬수 있는 성질을 알고있다면 이 두 성질을 이용해 객체들을 효율적으로 컨트롤 해보자는것이다.(move 호출시 그게 형태가 무엇이든 각자 재정의했으면 재정의한 move를 쓰고 안했으면 부모가 가지고있는 move를 작동한다.)</p>
<p>우리가 프로그램 실행 전엔 객체의 형태(갯수나,함수들)를 모르기때문에 객체들을 직접 갯수를 파악해서 따로따로 저장해서 관리하는것보다는 자식 객체들을 부모 포인터로 다 받아와서 부모 클래스의 함수를 작동시켜주면 간단한 문제인것이다.</p>
<p>여기서 각자 따로 관리해준다는건 자식 포인터로 자식 객체를 가리킨다는것인데 이럴 경우는 공통된 함수를 가지고있는게 아녀서 따로따로 컨트롤해줘야된다.
우리가 뭔가 총괄적으로 관리할때는 배열로 묶어줘야되고, 배열로 묶을려면 타입이 하나여야된다.그래서 부모 포인터 배열을 만들어줘서 자식객체들을 다 넣어준것이다.이렇게 만든 배열을 가지고 for문을 써줘서 반복돌면서 원하는 함수를 일괄호출 시켜주는것이다.그리고 바로 그게 다형성이다.</p>
<p>5.객체지향(객체를 컨트롤해서 뭔가를 구현하는것)이란게 여기서 실현되는건데 이 다형성 덕분에 컨트롤을 하는게 굉장히 편해졌다는것에 큰 의의가 있다. 
(다형성이 c++에서 가장 중요하다)</p>
<p>6.근데 하나만 상속된 자식을 가리켜 동적할당을 받아와서 다형성을 구현하는 코드를 짤 경우, 메인함수에서 호출하는데 오버라이드된 자식클래스 안 재정의된 함수를 호출한게 아니라 자식클래스에 재정의되지않은 함수가 호출될때 부모의 해당 함수를 복사해서 가져와서 호출하는것이냐? 그렇다면 그 함수는 엄연히 다른 자식 객체만의 함수가 호출된걸로 봐야되냐?</p>
<p>---&gt; 정확히 말하면 복사한게 아닌 똑같은 함수다.함수도 주소값이 존재하는데(코드들이 저장되는 영역이 코드영역인데 이 말은 곧 이것들도 다 메모리란 소리) 함수도 주소값을 가지고있는 이유는 함수의 메모리에 접근할려면 이름과 주소값을 가지고 접근하는데 우리가 호출문에서 함수이름을 써주고 호출하면 운영체제가 함수의 주소값을 돌려준다.(절차지향언어에서 위에서 아래로 코드가 실행되는데 가다가 호출문이 있으면 다시 코드가 함수정의문으로 가는 이유)그렇기 때문에 함수의 메모리는 다른게 아니라 동일해서 같은 함수다.</p>
<p>7.동적할당할때 자식 객체를 생성하는데 이것도 객체니깐 생성자 함수가 불린다.또한 소멸될때 소멸자 함수도 불린다.근데 이런 상속관계에서 부모 객체와 자식 객체가 생성된 경우에는 자식 객체의 소멸자가 안불리는 상황이 발생하는 문제가 발생할 수 있는데,그 이유는 컴퓨터는 우리가 생각한 것 만큼 똑똑하지않는다. 즉 프로그래머를 전적으로 신뢰한다.
그래서 프로그래머가 애매하게 정보를 알려주면 그 정보를 처리하지않는다.
예로 들면</p>
<p> A * b = new B
 delete b
가 있다고 가정하면 B객체를 생성한건 명확하니 생성자A와 B가 불리는건 맞다.근데 delete b 같은 경우는 b의 타입은 부모의 포인터 타입이다.그럼 컴파일러가 이걸 어떻게 받아들이냐면 b를 삭제시키는데 b가 가르키는애를 삭제시키면서 객체 삭제시켰으니깐 소멸자 불러야지하고 불러야되는데 어떤 소멸자를 부를지몰라서 자기의 타입이 부모의 포인터 타입이니깐 부모 소멸자만 부르면되겠구나 하고 부르고 객체 삭제하고 끝내버린다.(어떤 객체인지는 우리는 코드를 보면 알지만 컴퓨터 입장에선 모름)</p>
<ul>
<li>소멸자는 객체 삭제 직전에 불림</li>
</ul>
<p>여튼 보통은 부모 생성자 -&gt; 자식 생성자 -&gt; 자식 소멸자 -&gt; 부모 소멸자 이렇게 소멸이 되어야되는데 위와 같은 자식 객체 소멸자가 안불리는 이슈가 생긴다.</p>
<p>이럴 경우 우리가 직접 컴퓨터에게 알려줘야한다. 바로 소멸자를 가상화해주는 방법이다.
= 소멸자 앞에 virtual을 붙여줘서 가상함수로 만들어버린다.</p>
<p>ex) virtual ~A( );</p>
<p>vitual 즉 가상함수는 함수를 오버라이드를 사용할 가능성이 있다고 하겠다고 컴파일러한테 알려주는것이 목적인 것이다.여기서 무조건 가상함수화된다고 오버라이드를 반드시 해야된다는것은 아니며 이걸 해놓고 오버라이드를 사용하는 여부는 자유다.대신 오버라이드를 할려면 무조건 virtual을 붙여야된다.</p>
<p>즉 부모의 소멸자에다가 가상화를 시켜주면 컴파일러에게 소멸자가 오버라이드 되어있다는걸 확인해보라는 계기를 제공하는것 그렇게 되면 컴파일러가 오버라이드 된 자식 소멸자가 있는지 확인해본다.여기서 주의할 점은 virtual을 붙여준게 동적할당 구문의 자식 객체의 소멸자가 아니라 부모 객체란 것이다.그래야 밑에서 딜리트할때 부모만 소멸해줘야겠다하고 부모 소멸자 코드로 올라가서 보는데 virtual을 그제서야보고 자식 객체 소멸을 확인한다.자식 객체를 찾으면 그제서야 부모 객체 소멸자 전에 자식 객체의 소멸자를 먼저 부른다.</p>
<p>8-1.그렇다면 여기서 컴파일러가 자식 객체가 존재하는지의 유무를 어떻게 찾냐?</p>
<p>멍청한데 단순히 virtual만 붙혀서 어떻게 찾는지 궁금할 수도 있는데 이 키워드를 썼을때 컴파일러가 어떻게 작동하냐면 가상함수 테이블을 이용한다.</p>
<p>클래스 내에 한 개 이상의 가상함수가 존재한다면 즉 컴파일러는 virtual란 키워드를 쓴 클래스를 발견했을때 가상함수 테이블란것에 함수이름과 함수주소를 적어놓는다.
이 가상함수 테이블은 쉽게말해 우리가 자식 객체가 있는지 눈여겨 보라고 붙여준것이니깐 컴퓨터가 그걸 기억하고 관리하기위해 가지고 현황시켜놓는 액셀파일이라고 생각하면된다.</p>
<p>8-2.가상함수 테이블
Key와 Value로 이뤄져있는데 Key당 하나의 Value로 짝지어져있다.</p>
<p>Key값</p>
<ul>
<li>호출하고자 하는 함수를 구분지어주는 식별자</li>
<li>중복되지않고 유니크하다.</li>
<li>함수의형태로 들어간다. 
ex) void A::Func1( )        </li>
</ul>
<p>Value값</p>
<ul>
<li>구분자(Key)에 해당하는 함수의주소</li>
<li>함수의 주소값(변수와 차이는 주소에 해당하는 메모리가 다른 영역인 코드영역에 생기는것)</li>
<li>virtual되면 이 함수를 가상함수테이블에서 적어놓고 유지한다.</li>
</ul>
<p>만약 클래스 A내에 가상함수가 있다면 그 클래스 안 함수들을 가상함수 테이블에 적는다.
(가상함수뿐만 아니라 다른 함수도)</p>
<p>8-3.만약 A 객체를 생성하면 객체에 A 클래스의 가상 함수 테이블의 주소 값이 저장된다.
그러면 A 객체의 임의의 함수를 호출하면 다음과 같은 참조 과정을 가진다.</p>
<p>ㄱ. A 객체의 원하는 함수를 호출
ㄴ. A 클래스의 가상 함수 테이블의 주소 참조
ㄷ. 해당 주소 참조</p>
<p>= 호출 시 클래스 A에 무조건 한번 들려서 테이블보고 이 번지에 이 함수가 있구나하고 보는것</p>
<ul>
<li>해더파일 속 함수들은 그냥 그 속에 여러개가 아니라 하나만 있기에 컴파일러가 햇갈리지않는다. 가상함수 테이블과는 원리가 다르다.얘는 기록용이고 오버라이드된 함수를 찾기위해 존재하는것이며, 호출을 할때까지 컴파일러는 어떤 함수가 호출될 지 모르니깐 테이블에 정보를 잡아놓은것이다.</li>
</ul>
<p>8-4.그러면 자식 클래스(B)에도 virtual가 붙혀서 있는 경우는 가상함수테이블이 어떻게 생성될까?</p>
<p>B 클래스는 내부에 오버라이드 된 함수들이 있다면 virtual이 없어도 자동으로 가상함수테이블이 잡힌다.</p>
<p>왜냐하면 바로 부모클래스에 virtual가 있기때문에 
-&gt; 부모에 virtual이 있으면 상속 받아서 자식도 virtual이 있다.</p>
<p>그래서 자식 클래스에 오버라이드 된 함수에 virtual을 명시하지않아도 상관이 없는것이다.자식 클래스의 객체들 안에 오버라이드가 명시된 함수 옆에는 다 virtual이 생략되어있다.그니깐 결국은 얘도 가상함수 테이블이 생성되는 것!(물론 자식 클래스에서 객체를 만들면 그 안에도 해당 함수들은 virtual이 있어서 테이블에 기록되어진다.</p>
<p>이때 부모와 자식 클래스 안에 들어있는 오버라이드된 함수는 가상함수 테이블에 두번적히냐? -&gt; 아니다.부모 클래스의 함수는 이미 기록되어있으니 기록할 필요가 없다.테이블에는 두번적으면 햇갈리니 하나만 적힌다. -&gt; 그래서 자식 객체의 함수 하나만 불린다.(=부모의 함수와 주소값이 다름)</p>
<p>== 오버 라이딩된 가상 함수의 주소정보는 유도 클래스(=자식 클래스)의 가상함수 테이블에 포함되지 않는다. </p>
<ul>
<li>자식 객체가 가지고 있는 오버라이드가 되지않은 함수가 테이블에 등록</li>
<li>부모 클래스에서 오버라이드 되지않은 함수가 테이블에 등록(부모와 주소값이 같음)</li>
</ul>
<p>함수란건 코드영역에 존재하기때문에 코드는 한번 빌드되면 변할일이 없기에 부모 객체의 오버라이드 되지않는 함수는 변하지않아 자식객체의 가상테이블에 주소값이 그대로 등록된다.</p>
<p><strong>오버라이딩 된 함수는 부모의 함수와 다른 함수다.오버라이드란건 내가 상속된 부모의 함수를 그대로 쓰는것이 아니라 자식 쪽에서 재정의한것이 오버라이드다.</strong>(이름하고 형태정도만 같은거지 엄연히 다른 함수다.)</p>
<p>9.대량의 동적할당 -&gt; 포인터 배열을 이용한다!</p>
<p>int main()
{
    Animal * arr[100];
    for(int i=0;i&lt;100;++i)
    {
        arr[i]=new Bird()
    }
}</p>
<p>예로 들어 위와 같이 포인터 배열과 for문을 이용한다했을때는 bird라는 객체만 계속 만들어질것이다.근데 여기에서 여러가지를 다양하게 만들고싶을때는 다음과 같이 코드를 짠다.</p>
<pre><code>int main()
{
srand(time(null));
Animal * arr[100];

for(int i=0;i&lt;100;++i)
{
int choice=rand()%3+1;
switch(choice)
{

case1;
{
    arr[i]=new Bird();
}
break;

case2;
{
    arr[i]=new Fish();
}
break;

case3;
{
    arr[i]=new Person();
}
break;

}</code></pre><p>기본에 썼던 동적할당 구문에서 포인터에 배열을 추가하고 랜덤 함수와 switch문을 이용하여 for문을 돌리면 랜덤값에 의해 다양한 자식객체가 생성된다.(rand는 시드 단위로 변경돼서 srand(time(null));코드를 추가하여 수시로 바뀌게끔 코드짜기)</p>
<p>우리가 만약에 생성하고자하는 객체가 몇개씩 정해놓은 상황이라면 아래와 같이 관리해야되는데 이럴경우는 for문을 이용한 호출문을 호출수 만큼 따로따로 해줘야된다.
Bird * arr1[33]
Bird * arr2[33]
Bird * arr3[33]</p>
<p>근데 이것보다 전자의 방법대로하면 호출도 그냥 for문으로 호출해버리면 한번에 편하게 할 수 있다.그리고 새로운 객체를 추가하고싶으면 더 써줘야되는게 많은데 전자에선 case만 하나 더써주면된다.</p>
<p><strong>&quot;c++은 왜 객체지향언어인가?&quot;이걸 정리하기</strong></p>
<p>10.RTTI(Run Time Type Information)
== 프로그램이 실행되고 있는 동안의 자료형의 정보</p>
<p>Run Time : 프로그램이 실행되고 있는 시간
Type Information : 자료형의 정보 </p>
<p>RTTI란 프로그램 실행 중에 개체의 형식이 결정될 수 있도록 하는 메커니즘이다.다시 말하면 실행중 포인터가 가르키는 객체의 타입을 알 수 있게 해주는 하나의 방법이라고 보면된다.</p>
<p>기본적으로 RTTI가 필요한 이유는 A 타입에서 B 타입으로 변경할 때 정보가 필요하기 때문이다.A 클래스의 정보 B 클래스의 정보를 가지고있는 가상함수 테이블이 프로그램의 실행 단계에서 정해진다.부모의 포인터로 가르키는 자식객체가 정확히 뭔지는 프로그램이 실행될때 안다.(렌덤으로 스위치문 작동될때처럼)그래서 자료형이 런타임때 정해진다는것이다.</p>
<p>일시간에 타입 변환이 이루어진다면 굳이 RTTI가 필요없다. 컴파일 단계에서 충분히 알 수 있고 특정 타입으로 확정할 수 있기 때문이다.</p>
<p>virtual 클래스로부터 상속이 하나라도 존재하면 RTTI를 사용하고 있다고 보면 된다.
== 가상함수테이블이란 개념이 RTTI라는 이론을 접목하고있다.</p>
<p>11.RAII 
저번 개념 복습 생성자, 소멸자에서 RAII란 개념이 나오는데, 생성자랑 소멸자 사이에서 메모리 누수 방지를 위해 메모리관리를 해주는 개념이다.
== 생성했으면 꼭 소멸해준다.</p>
<p><strong>RTII와 RAII의 차이를 설명하시오</strong> 대비하기</p>
<p>RTII 같은 경우는 상속,다형성 관련이라서 객체지향언어의 특징 3가지를 설명하라고할때 이 2개념을 접목시켜서 말하면 점수 딸 수 있음.이 두 개념은 고급이론이기때문에</p>
<p>12.STL(Standard Templete Library)
표준 탬플릿 라이브러리로 가져다 활용하는 탬플릿인데 여기서 탬플릿이라하면 
다음과 같다.</p>
<p>c++의 탬플릿은 자료형에 구애받지않게 해준다.( 신경x, 관계없는x ) 
함수나 클래스 이런곳에선 자료형에 엄청 구애받는데 이런 자료형에 얽매이지않도록하기위해쓰는게 탬플릿이다.</p>
<p>보통은 함수의 반환형과 입력값엔 자료형이 들어가는데 우리가 어떤 함수를 쓸 때, 만약 만드는 과정에서 객체들이 추가될때마다 그 객체들의 자료형은 단순 자료형부터 클래스까지 다 다를것이고 그 자료형만의 함수를 또 써줘야된다.</p>
<p>컴퓨터는 이런 비효율적인 반복을 싫어한다.그래서 다형성 같은것도 만든건데,이것같은경우도 효율적으로 함수 하나로 여러 자료형에 구애받지않을 방법이 없을까라는 생각에서 시작돼서 만들어진 것이다.</p>
<p>기존처럼 자료형에 제약받지말고 모든 자료형을 다 받아와서 커버하는 만능 자료형같은 것을 만들자해서 만든게 탬플릿이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C ++ 이론(5)]]></title>
            <link>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A05-3i6efi4n</link>
            <guid>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A05-3i6efi4n</guid>
            <pubDate>Sat, 08 Jul 2023 08:24:06 GMT</pubDate>
            <description><![CDATA[<h1 id="다형성">다형성</h1>
<p>== 다양한 형태의 성질을 가지는것.동일한 종에 속하는 생물이라 할지라도 다양한 변이를 가지는 현상(카테고리는 같은데 하는 짓이 다른것)</p>
<p>Ex) 동물 카테고리 안 여러가지 동물이 있는데 공동된 특징은 움직임이다.근데 어떻게 움직이는지는 다 다르다.움직이기 위한 방법, 사용하는 신체부위 등이 다름.이렇게 내가 이동하라고 동일한 명령을 내리면 각각이 다른 행동을 한다. 이것을 “다형성”이라고 한다.
-&gt; 이걸 코드에 적용하면 똑같은 형태인데 다른 결과같이 나오는것을 뜻한다.</p>
<p>C++ 언어에서의 다형성
-&gt; 3가지만 기억하자.(가상함수, 함수템플릿, 함수 오버로드)</p>
<p>가상 함수
부모 클래스와 자식 클래스에 동일한 이름의 함수의 다른 작동</p>
<p>함수 템플릿(STL=Standard Templete Library)
동일한 이름의 함수가 다양한 자료형을 처리 </p>
<p>함수 오버로드
동일한 이름의 함수가 다른 작동 </p>
<p>연산자 오버로드
한가지 연산자가 다양한 작동</p>
<p>함수 이름이 같아도 다른 작업을 하는 것을 말한다.</p>
<h2 id="가상함수">가상함수</h2>
<p>예로 들어 클래스 A에 임의의 함수가 있는데 클래스 B가 클래스 A를 상속 받았고,클래스 B에도 동일한 이름의 임의의 함수가 있다고 가정할때</p>
<p>보통은 코드에 동일한 함수가 중복되면 오류가 나지만 근데 상속관계에선 함수가 이름이 같은걸 허용해준다.함수이름이 동일하다는 가정하에 클래스 A만의 함수가 있고,클래스 B만의 함수가 있는걸 예외적으로 인정해주겠다는것이다.</p>
<p>이런 특징이 적용된 함수를 “가상 함수”라 한다.
(==함수를 오버라이드 했다.!= 오버로드) </p>
<p>Ex)
A클래스에서 Func란 cout함수를 호출할 땐 A함수란 텍스트가 나오고 
B클래스에서 Func란 cout함수를 호출할 땐 B함수란 텍스트가 나옴.
-&gt; 결국 둘이 하는일이 다르다.</p>
<p>Virtual
부모클래스 앞에 붙는 키워드
부모클래스에서 어떤 함수 앞에 virtual 키워드를 붙히면 그 함수는 가상함수가 된다.(가상함수로 만들겠다는 키워드여서 곧 이 함수는 자식클래스에서 동일명으로 갖다쓸 수 있게하겠다는것이다.) </p>
<p>Override
자식클래스 뒤에 붙는 키워드
상속관계에서 부모 클래스의 가상 함수를 자식 클래스에서 쓴다고 했을때는 이 함수가 오버라이드 되었다고 생각하면된다.내가 부모 클래스의 함수를 쓰고싶으면 가상함수로 지정해주고 오버라이드해서 쓰면된다.
(클래스 간 이름이 같다? -&gt; 이 경우임)</p>
<p>오버라이드는 프로그래머의 선택사항이다.
만약 B클래스에서 오버라이드된 함수를 정의하지않았다고하면 부모클래스의 함수를 가져와서 쓰게된다.(상속받았으니깐)
-&gt;버츄어는 자동이지만 오버라이드는 컴파일러가 자동으로 안붙혀줌</p>
<p>부모클래스에 A클래스에서 Func란 cout함수를 호출할 땐 A함수란 텍스트가 나오고 virtual을 붙여 가상함수가 되어있다해도 오버라이드함수를 꼭 만들 필요없다.(버츄얼은 진짜 오버라이드하기위해서 하는거 그이상 그이하도 아니다.)</p>
<p>만약 오버라이드를 붙였는데 버츄어가 없는 경우는 원래는 오류가 나야되는데 이 상황에서는 컴파일러가 알아서 버츄어를 붙여준다.   </p>
<p> 이 두 키워드가 쓰이는 이유는 부모 클래스와 자식 클래스가 붙어있는게 아니라 떨어진 경우 구분을 해주지않으면 다른 사람이 어떤 함수가 가상함수인지도 모르고 오버라이드가 된 함수가 있겠구나라고 생각을 못하니깐 구분을 해준것이다.</p>
<p>Virtual을 보는 순간 얘를 상속한 무언가가 밑에 어떤 클래스에 있겠네를 생각하자.</p>
<p>Override는 일반클래스에서는 못쓴다. 상속받은 부모클래스에서만 쓸 수 있다.(하지만 이것도 컴파일러가 자동으로 부모클래스에 버추어 붙여서 해결됨)</p>
<ul>
<li>복습 : 생성자 코드가 꼭 코드 맨 첫줄부터 있을 필요x.
코드 순서대로 무조건 실행되는게 아니고 우선순위를 부여하지말자.
생성자는 몇번째 줄에 있든 먼저 실행이 되는거 숙지</li>
</ul>
<p>중괄호가 끝나면 엔터로 한 줄 공백 처리해주자.</p>
<h3 id="가상-함수-출력시">가상 함수 출력시</h3>
<p>가상 함수의 생성자 초기화(출력 ox) 
-&gt; 가상 함수 반환값 출력(가정)
-&gt; 오버라이드된 함수의 생성자 초기화(출력 ox)
-&gt; 오버라이드된 함수의 반환값 출력(가정)
-&gt; 오버라이드된 함수 소멸자 
-&gt; 가상 함수 소멸자</p>
<p>이런 순서로 생각할 수 있는데 실제 결과는 특이점이 있다.</p>
<p>가상 함수의 생성자 초기화(출력 ox) 
-&gt; 가상 함수 반환값 출력(가정)</p>
<p>-&gt; 추가)
오버라이드된 함수의 객체가 생성되기전에 부모의 객체 생성자가 생성</p>
<p>-&gt; 오버라이드된 함수의 생성자 초기화(출력 ox)
-&gt; 오버라이드된 함수의 반환값 출력(가정)
-&gt; 오버라이드된 함수 소멸자</p>
<p>-&gt; 추가)
자식 클래스가 선언되면서 추가로 불렸던 가상함수 생성자가 소멸됨 </p>
<p>-&gt; 첫번째의 가상 함수 소멸자가 불려서 소멸</p>
<p>왜 이렇게되냐?
자식클래스가 메인함수에서 객체가 생성될 때,부모클래스 객체 하나가 같이 추가로 생성이 된다.왜 생성이 되냐면 부모클래스를 상속받았다는게 변수와 함수들을 그대로 가져왔다는건데 여기서 그대로 가져오는 가장 쉬운 방법은 오버라이드 함수가 가상함수를 먹으면된다.(== 그냥 부모클래스 객체를 하나 생성하고 같이 데리고다닌다.)</p>
<p>그러면 상속받으면 부모클래스에 있던 함수가 다 불리는건가?
-&gt; 생성자 함수는 객체가 선언되는 순간 자동으로 생성되는 특성이 있으니깐 생성자가 생성돼서 출력되는거고 부모클래스에 있던 다른 함수들은 자동으로 불리는게 아니라 따로 써줘야된다.그래서 출력상에는 부모클래스의 생성자의 초기화 내용 및 소멸자 내용만 추가로 생기는 것이다.</p>
<p>정리
클래스가 상속관계에 있을때, 메인함수에서 자식클래스 객체를 생성(선언)할땐 부모 객체 생성하고 자식 객체를 생성한다.(코드에선 안보이고 내부적으로만)이때 부모 객체가 생성된다는건 부모의 생성자가 불리고 그런다음 자식 생성자가 불린다.</p>
<p>소멸될때도 소멸은 생성의 역순이니깐 자식이 소멸하고 부모가 소멸한다.근데 자식 소멸 -&gt; 부모 소멸 -&gt; 부모 소멸인데 두번째의 부모 소멸은 자식 객체 선언될때 추가로 불린 부모의 객체를 소멸하는 것이다.그런다음에서야 첫번째 생성되었던 부모 객체를 소멸시키는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C++ 이론(4)]]></title>
            <link>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A04-z1rr9b8r</link>
            <guid>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A04-z1rr9b8r</guid>
            <pubDate>Wed, 05 Jul 2023 07:18:35 GMT</pubDate>
            <description><![CDATA[<h1 id="복사생성자는-언제-호출되는가">복사생성자는 언제 호출되는가?</h1>
<p>1.복사생성자를 쓸 때 크래시 일어나는 상황때문에 객체를 객체로 호출하는 상황에서 두 객체가 같은 동적할당받은 주소를 가리켜 소멸할때 문제가 됐었는데 그걸 받을 객체에 동적할당만 새로 해줘서 박스만 받고 그 안의 값은 넣을 객체로부터의 값만 복사해줬는데 
그때 쓰는 함수의 매개변수에 const가 들어가는 이유는?</p>
<p>-&gt; 우리가 rhs로 넣을 객체를 참조하는데 이 넣을 객체는 변질시키고자하는 의도가 없기에 레퍼런스 변수(별명붙여서)로 가져오고 거기에 const 상수화를 시켜서 변하지않게 해주는것이다.</p>
<p>2.얕은복사(shallow copy)와 깊은복사(deep copy)</p>
<p><strong>면접 질문 베스트!!!</strong>
얕은복사와 깊은복사의 차이점을 설명하시오.
복사생성자에 대해 설명해보세요.</p>
<p>ㄱ.얕은복사(shallow copy)
객체를 가지고와서 호출할때 복사생성자(동적할당을 정의한)에 의해서 포인터변수로 똑같은 주소값을 가져와버려서 똑같은 애를 가리키면서 문제가 됨.이렇게 문제가 된 상황을 &#39;얕은복사&#39;했다라고 한다.</p>
<ul>
<li>얕은복사는 무조건 잘못된것이 아니라 복사생성자에 한해서는 잘못된 방법이다.개념일뿐</li>
<li>얕은 복사는 이동생성자란것에 쓰인다.
복사생성자가 동적할당을 해서 성능(시간)이 좀 안좋다.(운영체제가 빌려주기 전 가능한지 검사하고 빌려주는데 시간이 소요됨) 그렇기때문에 성능때문에 얕은복사를 쓸 때도 있는데 그게 바로 이동생성자이다.(현업에서 어려워서 사용도가 낮다보니 이건 현직때 공부하기)</li>
</ul>
<p>ㄴ.깊은복사(deep copy)
그래서 가리키는 공간을 새로 만들고 넣을 객체의 값만 복사해서 넣어주는 코드를 추가로 짜주면 해결된다.이것을 &#39;깊은복사&#39;라고 한다.</p>
<p>-&gt; 복사생성자를 정의할 때는 꼭 깊은복사로 정의하여야한다.</p>
<p>3.복사생성자는 언제 불리는가?(=호출시점)
복사생성자는 복사해서 생성될 때 쓰이며,
복사 생성자의 호출시점은 크게 세가지로 구분된다.</p>
<p>1) 기존에 생성된 객체를 이용해 새로운 객체를 초기화 하는 경우
2) Call-by-value 방식의 함수호출 과정에서 객체를 인자로 전달하는 경우
3) 객체를 반환하되, 참조형으로 반환하지 않은 경우</p>
<p>1) </p>
<p>ex) person man1(&quot;Lee dong woo&quot;, 29);
    person man2 = man1;</p>
<p>OR CMydata b(a)</p>
<p>2)  Call-by-value 방식
함수에다가 인자로 객체를 넘겨줄때.근데 그 객체를 넘겨주는 형태가 포인터나 레퍼런스가 아닌 그냥 복사하는 형태일때</p>
<p>ex) 
위에 여러 생성자들이 있음</p>
<p>void SimpleFuncObj(SoSimple ob) //객체를 인자로 받는 함수 정의문(소심플은 클래스)
{                               //레퍼런스변수나 포인터변수가 없다
    ob.showData();
}</p>
<p>int main(void)
{
    SoSimple Obj(7);                //메인함수에 Obj라는 객체 선언(지역객체) 
    cout&lt;&lt;&quot;함수 호출 전&quot;&lt;&lt;endl;
    SimpleFuncObj(Obj);       //정의한 함수를 호출하면서 위의 Obj 객체를 넘김
    cout&lt;&lt;&quot;함수 호출 후&quot;&lt;&lt;endl;
    return 0;
}</p>
<p>함수에서 Obj를 호출할때 Obj를 그대로 가져가는게 아니라 SimpleFuncObj 함수 내부의 ob라는 지역객체를 생성한다.(SoSimple ob는 void SimpleFuncObj 내부에서만 사는 지역변수기 때문에) Ob를 생성하는데 Obj를 가지고 생성한다.</p>
<p>*<em>함수에 있는 매개변수는 함수에 정의되어있다고 생성되는 애가 아니라 호출될 때 가져온 인자를 가지고 초기화되면서 실행이 된다.
*</em></p>
<p>이 말은 즉슨 SoSimple ob = Obj와 같게된단 뜻이다.이때 복사생성자가 불리는것이다.
1)의 방법과 차이는 1)은 대놓고 대입하는 경우 2)는 함수의 매개변수를 이용해서 불리는경우다.</p>
<p>3)객체를 반환하되,참조형을 반환하지 않을 경우--&gt;복사생성자가 두 번이여서 효율이 낮음
(반환형으로 참조형은 없다.)</p>
<p>ex)
MyClass TestFunc()      //마이클래스형의 테스트펑크 함수 정의
{
    MyClass temp;       //마이클래스형의 temp 지역객체 선언
    return temp;         //temp를 마이클래스 형태로 리턴
}</p>
<p>int main()
{
   MyClass a;
   MyClass b(a);</p>
<p>   MyClass c = TestFunc();  //테스트펑크의 결과값을 객체C를 만드는데 사용함
   return0;
}</p>
<p>객체 C를 만드는데 TestFunc의 결과값을 쓸 수 있나? temp는 지역변수라 사라질탠데?
레퍼런스도 아닌데 가능한 이유는 바로 &quot;임시객체&quot;이기 때문이다.</p>
<p>return temp한 값이 MyClass c = TestFunc(); 여기에서 살아있어야한다.</p>
<p>보통 일반함수나 일반변수의 경우
int AddNum(int a,int b)
{
    return a + b;
}</p>
<p>또는</p>
<p>int TestFunc2()
{
    return 3;
}
같은 경우처럼 지역변수 규약이 적용되더라도 함수에 반환형이 있다면 그 자료형으로 복사해서 반환되고 지역변수는 사라진다.
(temp가 리턴되야하는데 여기선 자료형이 클래스고 temp는 지역변수여서 사라지지고 MyClass라는 객체를 리턴한 것 이때 이 객체는 temp값을 받아온 상태.
== temp가 메인으로 가야되는데 못가니깐 메인에 있을 객체를 임의적으로 하나만드는데 temp를 가지고 만들자.
== temp를 리턴하고싶은데 나는 수명이 여기서 끝이야 그러니깐 너가 객체 하나만들어 나를 가지고)</p>
<p>그리고 여기서 복사생성자가 한번 불린다. MyClass c = TestFunc();의 TestFunc()에 
객체 MyClass가 들어가니깐</p>
<p>MyClass c = TestFunc();의 TestFunc()가 결과값이다.그 결과값은 곧 마이클래스 객체이고 결국은 MyClass c = MyClass();가 된다.temp의 값을 받아왔는데 이때 MyClass()를 임시로 만들어줬다해서 임시객체다.</p>
<p>근데 여기선 객체(TestFunc)의 이름이 없다.함수를 호출했지 MyClass와 관련된 별도의 객체를 만든적은 없으니깐 여기서 MyClass는 우리가 만든게 아니라 TestFunc에 의해 컴파일러가 임시적으로 하나 만들어준것이다.MyClass 객체는 다음줄을 넘어가면 사라지는 객체이다.(만들고 사용하는건 프로그래머가 하는거지 컴퓨터가해주는게 아니다.컴퓨터가 만들어놓은것을 사용할 수도 없음)</p>
<p>이제 두번째로 복사생성자가 불리는데 MyClass c = MyClass();와 같이 C가 임시객체를 가지고 선언 및 초기화가 되기때문이다.</p>
<p>이렇게 객체는 여러 방식으로 활용된다.복사생성자에도 활용, 상속 외 여러곳에서 활용됨</p>
<h2 id="상속">상속</h2>
<p>C++에는 3가지 특징이 있다.상속, 캡슐화, 다형성
(이것도 베스트 면접질문  각 특징을 설명해보시오)</p>
<p>첫번째 특징(상속)</p>
<ol>
<li>상속의 정의
부모 클래스의 멤버 변수와 메소드를 자식 클래스가 그대로 재사용하는것</li>
</ol>
<p>객체를 여러 개 정의해야하는 경우, 객체들 간의 상호작용을 표현해야하는데 그래픽만 갈아끼운 똑같은 객체들이 많음</p>
<p>예로들어 동물을 만든다고하면 동물 클래스로 하면 동물들 각각의 특징이 다르기에 컨트롤하기 어렵고 일일히 종류별로 클래스를 만든다고하면 호랑이 클래스, 토끼 클래스, 가젤 클래스 등등 일일히 다만들어야되는데 부모클래스가 이동속도같은 공통적인 특징들을 묶어가지고있는다면 자식클래스는 공통적인 특징들을 자동적으로 가지고 태어난다.</p>
<ol start="2">
<li>접근 제한자
ㄱ. private : 오직 자신의 클래스안에서만 접근 가능한 멤버 변수, 메소드
  -&gt; 함수들만 멤버변수에 접근이 가능했었음
ㄴ. protected : 자신을 상속하는 클래스까지만 접근 가능
 -&gt; 밖에서 접근 불가능.예외적으로 내가 부모클래스를 protected로 했으면 자식클래       스의 멤버함수에서 이 부모의 멤버변수를 바꾸는게 가능하다.
ㄷ. public : 어떤 클래스에서나 접근 가능
 -&gt; 밖에서 접근 가능</li>
</ol>
<p>3.상속에는 접근제어자별로의 상속이 있는데 private 상속, protected 상속은 거의 안쓰고 public 상속을 쓴다.</p>
<p>ex)</p>
<p>#include &lt; iostream &gt;
using namespace std;</p>
<p>class A {
private:
        int a;
protected:
        int b;
public:
        int c;
};</p>
<p>class B : public A { //멤버 변수의 접근 제한에 변화없음</p>
<p>};</p>
<p>int main() {
        B b;</p>
<p>   //   a = private, b = protected, c = public
           b.a;
        b.b;
        b.c;
}</p>
<p>: 는 초기화리스트에서 쓰이고 퍼블릭 상속에서도 쓰인다.
class B : public A는 &quot;내가 B를 정의할건데 얘는 A라는 애를 상속받는애야&quot;와 같다는걸 의미한다.== A를 상속받는애다. A앞에서 퍼블릭을 써주기!
이러면 A에 있는 멤버변수,함수가 B에 들어가게된다.</p>
<p>private:
        int a;
protected:
        int b;
public:
        int c;</p>
<p>이게 접근제어자까지 그대로 B로 들어감</p>
<ul>
<li>이걸 별도로 써주면 안됨. 이미 B에는 데이터가 들어가있는건데 이게 또 들어가면 중복이 되는것임</li>
</ul>
<p>B b; 상속받은 B로 b라는 객체를 만들었고 이 안에는 변수와 함수들이 들어있다.
근데 이제 이 안에 있는 변수들을 접근하는데 각 접근제어자가 다르기때문에 a랑 b는 접근을 못한다.쓸려면 PUBLIC에 함수를 정의해서 접근해야된다. </p>
<p>두번째 특징(캡슐화)<br>1.클래스 정의
우리가 클래스에서 멤버변수는 프라이빗에 배치하고 멤버함수는 퍼블릭에 배치한다고 했었는데 이유는 보안 및 협업시 건들지말아야될 데이터 때문(누군가 내가 의도한대로가 아닌 다른 의도로 쓸까봐)이라고 했음</p>
<p>멤버변수를 프라이빗으로 한번 감싸준게 곧 캡슐화!</p>
<p>2.예외처리( 면접 질문 베스트 )</p>
<p>그리고 추가로 우리가 프라이빗 멤버변수에 접근할려면 퍼블릭의 함수에서 접근할 수 밖에 없는데 함수를 짤때는 &quot;예외처리&quot;에 신경써줘야된다.(==상한선,하한선 조정)</p>
<p>예로 들어 자동차 속도계 함수에서 사용자가 일일히 수치를 입력하는만큼 속도가 나는게 아닌 내가 어느 이상의힘으로는 악셀을 밟아도 일정한 속도로만 가는 코드를 짜서 다른 사람이 코드를 잘못 사용못하게 막아놓는 이유(예외처리를 안해놓는다고하면 그 사람이 단위를 착각해서 큰 숫자를 넣으면 엄청 큰 속도가 들어갈 수도 있으니깐)에서도 캡슐화 같은 특징이 필요하다.또한 나중에 코드에 대한 책임에 분란이 있을때 도움이 되는게 나의 책임이 없다는걸 알려줄 수 있는 증거가 되기도한다.매번 회사에서 코드가 기록되기때문에 누가 바꾸면 그 사람 기록이 남는다. 잘못쓰는 사람까지 생각해서 완벽하게 짜놓자)</p>
<p>생명이나 사용자와 관련된 코드를 짤땐 예외처리가 중요하다.(자동으로 꺼지는 인덕션, 고데기 이런것 등등)</p>
<p>3.상속받은 다른 클래스의 구조</p>
<ul>
<li>class B : public A가 아니라 class B : A 인 경우도 있는데 이 코드는 public이 앞에 생략된것이다.자동으로 디폴트값이 public 상속이라고 생각하면됨.</li>
</ul>
<p>위 예시에서 A의 필드와 메서드를 다 가져왔는데 필드는 직접 접근을 못하고 들어있기만하고 들어있는 메서드는 그대로 써줄 수도 있고 일부만 써줄 수도 있다.</p>
<p>즉 상속받는 클래스에선 부모클래스의 퍼블릭 안 멤버함수들만 클래스 내부 코드에 갖다 쓸 수 있다.자식클래스에선 부모클래스랑 아예 다른 함수가 있을 수도 있는거고,부모클래스 퍼블릭의 함수 자체를 갖다쓸 수도 있고 결과값을 가져다 쓸 수도 있음.</p>
<p>여기서 중요한건 상속받은 자식 클래스인 B를 가지고 객체를 선언하면 A에 있던 코드도 있는거고 B 자체에서 새로 정의한 코드도 같이 있는 것이다.</p>
<p>그리고 이때 B에서 A의 함수를 호출하면 퍼블릭 함수에서 바뀐 결과값이 A의 멤버변수에 접근해서 값을 바꿔버릴수있다.(B자체 내에선 A의 멤버변수에 접근은 못함)</p>
<p>여기서 멤버변수가 바뀌었다는건 아까 </p>
<p>int main 안의 B b; 이걸 선언하면서 b 객체 안에 들어있는 멤버변수 a, b가 바뀌었다는것이다.
선언하는 객체마다 멤버변수들은 다 다른것이다!!(하나가 아님)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C ++ 이론(3)]]></title>
            <link>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A03-kmpueccr</link>
            <guid>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A03-kmpueccr</guid>
            <pubDate>Mon, 03 Jul 2023 06:51:29 GMT</pubDate>
            <description><![CDATA[<p>#소멸자와 복사생성자</p>
<p>1.지난시간 복습</p>
<ul>
<li><p>동적할당 테크닉을 사용하지않으면 메모리낭비 및 프로그램 난이도(관련없는 빈공간을 다 계산하니깐)가 올라간다.</p>
</li>
<li><blockquote>
<p>동적할당을 쓰면 변수만큼의 배열을 받아와서 쓸 수 있다.</p>
</blockquote>
</li>
<li><p>동적할당문법에 int 아니여도 다양한 자료형을 쓸 수 있다.즉 이말은 우리가 사용하고있는 클래스도 자료형이기 때문에 클래스로도 동적할당이 가능하다.</p>
</li>
</ul>
<p>ex)
Myclass * ptr = new Myclass;
//클래스변수 하나일때</p>
<p>Myclass * ptr = new Myclass[num];
//클래스변수가 대량 즉 배열일때(이때 반드시 크기 넣어주기)</p>
<p>delete ptr;
//클래스변수 하나일때
delete[ ] ptr;
//클래스변수가 배열일때(이때 대괄호에는 크기 안넣어줘도됨)</p>
<ul>
<li>(중요)생성자는 언제 쓰이냐?
객체에서 필드와 메서드를 초기화할때 사용된다</li>
</ul>
<p>이게 왜 초기화를 할 때 사용하냐?(생성자특징)</p>
<p>클래스변수를 선언할때 생성자가 자동으로 초기화된다.(x)
-&gt; 용어를 똑바로 말하자</p>
<p>생성자는 클래스 객체를 생성할 때 자동으로 생성(정의)될 수도 있고 자동으로 불릴(호출) 수도 있다.(○)</p>
<p>클래스 내부에 생성자가 정의되어있지않은 경우는 컴파일러가 자동으로 생성자를 생성(정의)해준다.</p>
<p>2.본 수업 복습(소멸자)</p>
<p><strong>소멸자 개념</strong>
객체가 소멸될 때 자동으로 실행되는 클래스의 멤버 함수다.
소멸자는 객체의 청소를 돕도록 설계되었다.</p>
<p><strong>소멸자의 역할</strong>
이 객체가 안전하게 소멸할 수 있도록 객체의 필드나 메서드들을 정리해주는 역할을 한다.
(소멸자도 생성자처럼 자동으로 불린다.)</p>
<ul>
<li>객체는 사라질때 자기가 가지고있는것들을 비워내는 작업을 반드시 해야된다!</li>
</ul>
<p>*<em>소멸자의 구조 *</em></p>
<ul>
<li><p>기본 생성자가 아래와 같이 생겼다면
MYclass() {}
기본 소멸자는 여기에 <strong>물결표시</strong>가 붙는다.(delete는 동적할당반납 문법이니 헷갈리지말자)
~MYclass() {}</p>
</li>
<li><p>소멸자의 이름은 클래스 이름과 같아야한다.</p>
</li>
<li><p>소멸자는 인수가 없다.</p>
</li>
<li><p>소멸자는 반환값이 없다.</p>
</li>
</ul>
<p><strong>RAII</strong>
RAII은 객체의 수명과 리소스 관리와 연관있는 프로그래밍 디자인 기법이다. C++에서 RAII는 클래스의 생성자와 소멸자로 구현되었다.</p>
<p>= 리소스를 획득한다는건 초기화인데 이 말은 객체의 생성과소멸로 리소스 관리를 한다와 같다.(프로그래밍 스킬을 C++이 문법으로 만들어놓은 것) 자동이 아니다보니 프로그래머가 관리하는게 중요하다.</p>
<ul>
<li>리소스(메모리,파일,동적 할당 또는 데이터베이스 핸들 등)는 일반적으로 객체의 생성자에서 획득한다.</li>
<li>그러면 그 리소스는 객체가 살아있는 동안 사용될 수 있다.</li>
<li>객체가 소멸하면 자원이 소멸된다.</li>
</ul>
<p>RAII의 장점은 리소스를 보유한 객체가 자동으로 정리됨에 따라 리소스 누수를 방지하는데 도움이된다.</p>
<p><strong>생성자와의 차이</strong> </p>
<p>ㄱ. 갯수</p>
<p>소멸자는 생성자처럼 여러개 있을 수 없다.단 한 개만 존재하는이유는 소멸할때는 인자가 아예 필요없다.</p>
<p>ㄴ. 소멸되는 시점</p>
<p>보통 객체(변수)의 생명주기에 달려있어서 소멸될때인데(예로 들어 메인함수에서 객체 선언을 하는데 여기서 return 코드 밑줄부터 괄호까지는 사라지고 있는 단계다.이건 더이상 필드나 메서드에 접근할 수 없다는 것과 같다.그리고 괄호가 닫힐땐 완전히 끝난것. </p>
<p>근데 소멸자는 소멸된 직후에 불리는 애가 아니라, 소멸될 때 불리는 애다.</p>
<p>생성자는 변수들을 초기화하는거니깐 그전에 먼저 생성부터 시켜줘서 생성 직후에 생성되는거고 소멸자는 그럴 필요가 없어서 소멸 동시에 불리는 것임.</p>
<p>근데 정확히 말하자면 소멸자는 자기가 가지고 있는것들을 정리하는애인데 만약 자기가 정리할게 없다면 소멸자는 일을 못한다.그래서 소멸자는 객체가 삭제되기 직전에 불린다.</p>
<p>int main(){
  Myclass a;</p>
<p>  return 0
  a;
}</p>
<p>이렇게 return이 끝나도 밑에 변수가 살아있을때 소멸자가 불린다.이때 a는 괄호를 나가고나서 끝났다할때 소멸자가 불리고 a가 사라지는것 즉,괄호를 벗어난 시점에 변수도 사라지고 소멸자도 불리는것이다. 그래서 시점이 소멸직전이라는것임.</p>
<p>생성자와 소멸자는 결국 내 멤버변수와 멤버함수를 정리하기위한 함수들이다.</p>
<ul>
<li><p>클래스 내부에서 생성된 포인터변수의 생명주기는 어떻게 될까?</p>
</li>
<li><blockquote>
<p>클래스 내부 멤버변수들은 메인함수에서 생성되는 객체의 생명주기를 따라간다.
왜냐면 클래스의 생명주기 즉 괄호안에서이지않을까 생각하겠지만 클래스의 생명주기는 객체가 생성되었을때 생성돼서 객체가 소멸될때까지 살아있다가 객체가 소멸될 때 같이 소멸됨</p>
</blockquote>
</li>
<li><p>소멸자가 존재하는 이유 (무엇을 정리하느냐)
클래스 내부에서 동적할당 문법을 썼다고 가정하고 (int * ptr = new int) new는 힙공간에 메모리를 잡고 ptr은 주소값만 가지고있다.
이름없는 int형 변수가 있고 그 주소값을 ptr이 지니고있고 이름없는 변수를 ptr이 가리킨다.근데 이 ptr이 속한 클래스가 객체따라 소멸돼서 ptr변수도 소멸됐다고 가정해보자.그러면 이름없는 int형 변수는 어떻게 되는가? </p>
</li>
</ul>
<p>-&gt; 반납을 하지않았기때문에 그 자리에 계속있다.(동적할당으로 빌려온 메모리는 반드시 반납해줘야되니깐) 이렇게 힙공간에 방치하면 메모리도 낭비고 이름은 없고 주소값이 있다보니 그 주소값을 가지고 있어서 유일하게 컨트롤이 가능했던 ptr이 사라지니 더이상 접근할 방법이 없다.(단,프로그램 종료시 운영체제가 정리해주긴한다.근데 프로그램은 하루쓰는게 아니다.)</p>
<p>생성자에서 초기화할 때 동적할당 즉 메모리를 힙영역에 빌렸으면 반드시 소멸자로 반납해야된다!(동적할당 안쓰고 일반함수로도 반납만 잘하면 상관없다.)</p>
<ul>
<li><p>주의할 점
동적할당할때 기본생성자와 기본소멸자는 객체가 있는 이상 무조건 불린다.근데 일반함수는 정의는 해도 빌려놓고 불릴 수도 안불릴 수도 있다.그렇게되면 꼬이고 까먹는다.</p>
</li>
<li><blockquote>
<p>안전빵으로 메모리리크(일반 프로그램에선 어마어마함)가 안일어나게끔 DELETE를 꼭 해주자.</p>
</blockquote>
</li>
<li><blockquote>
<p>클래스 내부에서 동적할당할때는 무조건 포인터변수가 쓰이는데 클래스의 멤버변수에서 포인터변수가 나오면 긴장하고 꼭 동적할당 받은 메모리를 가리키는 포인터변수가 아닌지 생각하고 꼭 반납까지 해야된다!!!</p>
</blockquote>
</li>
<li><p>포인터변수를 보면 체크해줘야할 세 가지
ㄱ. null로 초기화가 되어있는지
ㄴ. 동적할당받은 주소를 가리키는 포인터변수인지 반납은 되어있는지
ㄷ. 복사생성자 정의문을 써서 딜리트 중복이 안일어나지않게했는지</p>
</li>
<li><p>레퍼런스 변수와 CONST 변수는 원본 자체여서 애초에 동적할당과 상관없기에 생성 소멸과 관련없다. </p>
</li>
</ul>
<ul>
<li><p>NULLPTR은 NULL과 같다고보면된다.</p>
</li>
<li><p>클래스 정의문에서 순차적으로 다 돌아가는게 아니라 그 안에 있는 멤버변수와 멤버함수 중에 메인함수에 호출된 애들만 생각하면되고 외의 순서에 해당하는 단순 변수선언문은 리턴값에 영향을 주지않는다.호출문의 인자가 들어가는 함수만 보면된다.</p>
</li>
</ul>
<p>나의 실수 -&gt; 긴장해서그런진 모르겠지만 선언문인데 호출문이나 값이 변경되는 코드로 보고그럼.... 변수선언문은 변수 선언이지 = 때문에 대입해야겠다는 이런 생각은 하지말자. </p>
<p><strong>3.본 수업 복습(복사생성자)  ----  자동으로 생성되는 애 3번째</strong></p>
<p>예로 들어 main 함수에 아래와 같이 객체 즉,클래스 변수가 존재하는데</p>
<p>MYdata a(10);
MYdata b(a);</p>
<ul>
<li>a는 지역변수다.지역변수는 스택에 아래에서 위로 쌓인다.그렇다면 변수a의 메모리가 먼저쌓이고 그 다음에 b가 쌓인다.여기에서 아래있는 a를 뺄려면 b부터 빼야된다.
그렇다는말은 소멸될 때 b가 먼저 소멸된다는말이다.==생성과 소멸은 역순</li>
</ul>
<p>a가 인수 10을 넘기면서 객체 안의 임의의 멤버변수를 거치고 메인함수에 있는 함수를 통해 뭔가 유의미한 과정을 거친다.</p>
<p>반면 b의 형태는 어떻게 보고 b는 어떻게 생성됐냐? 
b는 인자로 int형인 아닌 객체 a(클래스 변수)를 줬다.그렇다면 클래스에선 이 인자에 맞는 생성자가 불려야된다. -&gt; 객체가 인자인 생성자 함수 -&gt; 근데 만약에 클래스내 이런 생성자 함수가 없다면? -&gt; 이럴때 자동으로 복사생성자라는게 생성된다. </p>
<p><strong>복사생성자 == 객체를 가지고 내 객체를 생성하고 싶을때 사용되는 생성자</strong></p>
<p>객체를 넣어서 객체를 초기화한다 == 넣은 객체에 있는것을 넣을 그릇 객체에 그대로 복사하고싶다와 같다.(==a안의것을 b에 그대로 복사해서 넣겠다.)</p>
<p>객체 a를 그대로 객체 b와 똑같이 셋팅하는걸로도 볼 수 있는데 현제 a는 MYdata에서 동적할당을 받아 포인터변수가 이름없는 변수의 주소값을 가리키고있고 그 주소값 안에는 인수로 받은 10이 있다. </p>
<p>객체 b에도 a가 가지고있는것들을 복사해주면 포인터변수가 들어가고 얘도 자동으로 동일한 주소값 안에 동일한 값인 10을 가리킬 것이다.</p>
<p>== 내가 객체를 생성하는데 다른 객체를 가지고 초기화하고싶을때 복사생성자가 불린다.
== 객체를 저 객체처럼 쓰고싶어서 저 객체랑 똑같이 초기화할때 복사생성자가 불린다.
== 내가 객체를 생성하는데 다른 객체를 가지고 생성하고싶을때 복사생성자가 불린다.
== MYdata b(a);의 코드일때 복사생성자가 불린다.
== MYdata b = a;의 코드일때 복사생성자가 불린다.
== 다른객체에 있던 값들로 객체 b를 채워준다.
== int형 생성자처럼 객체를 받고싶을때 불리는 생성자가 복사생성자</p>
<ul>
<li>복사생성자도 정의가 안되어있으면 컴파일러가 자동으로 생성해서 만들어준다.</li>
</ul>
<p><strong>복사생성자 특징</strong></p>
<p>기본생성자는 아무 생성자없이 정의가 안되어있을시에만 생기고 한개라도 정의가 되어있다면 안생긴다.(인수가 다른게 있다면 그것때문에 안생김)
반면에 복사생성자는 정의가 안되어있으면 무조건 자동으로 생성시킨다.
(인수가 다른것들 다 자동으로 정의시켜줌)</p>
<p>기본생성자와 복사생성자가 없으면 자동으로 불려진다.결국은 용도,상황별로 코드에 따라 자동으로 생성자들이 불려지는것(사용된다x.자동으로 해주는거니깐)+생성자 중 형태에 맞는것 하나가 호출이된다.</p>
<p><strong>출력문에 적용시</strong>
위의 예시에서 객체 a와 b 둘다 동적할당받은 메모리의 주소값을 가리키고 있다.그래서 메인함수에서 이 2개를 가지고 어떤 값을 출력하면 둘다 똑같이 가지고 있는 10이 출력된다.</p>
<p><strong>복사생성자가 불려서 만들어진 객체의 소멸</strong>
b가 먼저 소멸되는데 얘가 소멸되기 직전에 소멸자가 불리는데 소멸자는 동적 할당한 메모리를 해체한다.즉,포인터변수가 가리키던애를 없애준다는것이다.그리고 그제서야 b가 소멸된다.이제 남은 a도 소멸되기 직전에 소멸자가 불리는데 코드 상 delete * ptr처럼 주소값에 있는 메모리를 또 해체할려는데 b가 소멸되면서 가리키는 애가 이미 사라져 이미 없는 공간에 delete를 하면 크래시가 일어나게된다.</p>
<p>크래시가 일어난 이유는 
a 소멸자 한 번 b 소멸자 한 번 일대일 대응했기에 이건 이유가 아니고 
동적할당 메모리를 두 번 삭제한게 문제인데 이건 a랑 b랑 똑같은 곳을 주소값이 같으니깐 가리키기 때문인것.주소값이 같은 이유는 복사생성자때문 </p>
<p>-&gt; 그렇다면 동적할당 받은 메모리가 다른 메모리라면 괜찮지않을까?
복사생성자의 원래 의도는 객체 하나 생성하고 동적할당 하나 생성하고 다른 객체 하나 생성하고 다른 동적할당 하나 생성하고이다.</p>
<p>기본 생성자는 이런 의도로 객체마다 동적할당을 선언하는데 클래스 멤버함수 내에서 복사생성자가 자동으로 생겨나서 new함수를 안하고 객체의 값복사해주면서 이런일이 생긴것</p>
<p>Q)소멸할때 두 객체가 똑같은 동적할당 메모리를 가리켜서 크래시가 일어나는데 이것을 해결하는 방법?</p>
<p>A) ( 꼭 밑에 보고오기)복사생성자가 자동으로 생성되니 포인터변수가 그대로 복사돼서 문제가 일어난건데 해결방법은 자동으로 정의되게하지말고 내가 직접 정의해야겠다. delete 두 번 안하도록 내가 직접 가져와서 하면된다.==b가 따로 동적할당한다는 소리다. 그러면 delete할 때 서로 다르게 가리키는 메모리를 지울 수 있음.</p>
<p>여기서 주의할건
어차피 복사생성자여서 복사는 어쩔 수 없이 해야되는데 그러면 각 복사를 하고 그 안에 있는 값만 옯기자는식이다.무슨말이냐면 두 객체가 값도 다른걸 가리키자가 아니라 같은 상자 안을 가리키고 있었으면 서로 다른 상자(서로 메모리의 주소값은 다름)를 가리키고 기존 상자 안에 있던 값만 복사하자는 소리다.</p>
<p>그래서 이렇게되게끔 우리가 직접 정의할 때는 다음과 같이 정의한다.(무조건 이렇게)
무조건 암기하기!</p>
<p>MYdata(const Mydata &amp;rhs)
{<br>    //메모리 할당
    m_pnData = new int;</p>
<p>   //포인터가 가리키는 위치에 값을 복사</p>
<ul>
<li>m_pnData = * rhs.m_pnData
}</li>
</ul>
<p>클래스 내부에서 동적할당을 한다면 무조건 확인하고 에러가 나도 이걸 한번 확인해보자
프로그램을 정상종료를 안하는 경우가 많아 이런 경우는 에러가 발생하는지 몰라서 포인터변수가 존재하면 이런 동적할당 이슈에 신경쓰자.
첨부터 정의하면되지않냐하지만 동적할당을 받은 멤버변수를 단순 보관용으로 쓸 수 있다.
(주소값을 들고만있는)근데 이걸 함부로 해지했다가 또 중복돼서 크래시가 일어날 수 있다.포인터변수가 있다고해서 동적할당 할지 안할지 모르는건데 있으면 할 가능성이 높은것 그러면 이 이슈가 발생할 확률이 높다.써놔도 상관은 없다.(방지차)</p>
<p><strong>복사생성자의 정의문 (이 코드 그대로 자동 생성된다.)</strong></p>
<p>MYclass(Const MYclass&amp; rhs)
{
    ptr = rhs.ptr;      //b이 포인터 변수에 a의 포인터변수 주소값을 넣어라와 같음
}</p>
<p>인자로 MYclass 즉 래퍼런스 변수를 받는다.(const 상수형 뜻은 무시하기)
rhs == 래퍼런스 
즉, 래퍼런스형 객체를 인자로 받는다.
-&gt; 내 객체의 포인터 변수 ptr을 가져온 객체 안의 래퍼런스 변수 안에 있는 포인터 변수 ptr의 값으로 바꿔준다.(복사) 다른객체지만 클래스 자료형은 같기에 포인터변수는 가능</p>
<p>(구조체에서 배웠던 개념 : . 찍으면 구조체 혹은 클래스 안의 멤버변수에 접근할 수 있다.)</p>
<ul>
<li><p>기본생성자 안에 동적할당이 정의되어있을때, 복사생성자 안 포인터변수는 힙영역에서 빌린 메모리를 가리키는거 아닐까 생각하지만 복사생성자 정의문이 있는 시점에는 생성자는 객체에 하나만 불릴 수 있으니 기본생성자의 동적할당은 불리지않은것이다.
그저 아무것도 들어있지않은 ptr에 새로 불려온 객체(레퍼런스 변수,a)의 포인터변수가 들고있는 주소값을 준것</p>
</li>
<li><p>레퍼런스 변수를 인자로 받는건 알겠는데 레퍼런스 변수 선언문은 어딨나?</p>
</li>
<li><blockquote>
<p>Const MYclass&amp; rhs는 함수의 인자고 이건 정의만 일단 되어있는데, 선언문은 이 인자의 출처에 있다.MYclass 함수가 불릴때 Const MYclass&amp; rhs가 초기화됨</p>
</blockquote>
</li>
</ul>
<p>-&gt; 메인함수에서 MYclass b(a); 이렇게 선언할 때 a라는 인자가 Const MYclass&amp; rhs에 들어가면서 초기화된다.즉,레퍼런스 변수는 곧 a다.</p>
<p>Q)생성자는 각 상황마다 불리는데 복사생성자가 생기면 이미 같은 클래스 내부의 멤버변수들과 멤버함수들이 같은걸로 초기화되었으니깐 기본 생성자는 안생기는건지? </p>
<p>A)복사생성자가 실행될때 애초에 기본 생성자가 아예 상관이 없다.
-&gt; 생성자는 여러개 정의될 수 있지만 상황에 따라 호출되는건 하나다.</p>
<p>-&gt; 또한 동적할당받을때도 생성자별로 내부에서 받는데( 생성자라면 무엇이든 동적할당 받을 수 있음 ) 동적할당을 어느 생성자에 했든 그 동적할당받은 생성자가 호출되어야지만 할당이 되는것이지 호출되지도않았는데 임의의 생성자 안에 정의되어있다고 신경 쓸 필요가x.<br>복사생성자를 쓸 때 안에 동적할당 문법이 있으면 즉 복사해서 객체를 생성하고자할때는 그 안에서 동적할당하겠다라는 뜻과 같다.</p>
<p>결론 : 복사해서 생성하고싶을때, 객체를 인자로 줬을때 복사생성자가 불리고 없어도 자동으로 생성된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C++ 이론(2)]]></title>
            <link>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A02-e1sysz06</link>
            <guid>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A02-e1sysz06</guid>
            <pubDate>Wed, 28 Jun 2023 12:13:27 GMT</pubDate>
            <description><![CDATA[<h1 id="복습-내용-정리">복습 내용 정리</h1>
<p>1.std::cout
-&gt; 스탠다드 해더파일(iostream) 안에 있는 표준함수인 cout를 불러오겠다.</p>
<p>2.c언어에서는 해더파일들을 가져와서 참조했었는데 c++은 해더파일이 아닌 그냥 파일 통째로 가져온다.</p>
<p>::은 namespace라는건데 작업공간을 의미한다.코드를 작업하는 공간의 소유주를 정해놓는다라고 생각하면된다.문법이라고 생각하면되는데 아래처럼 이름을 지정해주면 코드를 칠 수 있는 공간이 확보되고 그 안에 코드를 치면되는데 이걸 main에서 std::cout처럼 &quot;namespace명::함수이름&quot;으로 쓰면된다.</p>
<p>EX)</p>
<p>namespace seo {
          int SPEED()
}</p>
<p>int main(){
          seo::SPEED
}</p>
<p>이걸 왜 만들었냐? 협업할 때 각자 만든 동일하거나 유사한 기능의 함수들이 겹치는데 이걸 구분하기위해 만들어준 문법이다.</p>
<p>EX) seo::SPEED 와 kim::SPEED로 구분 </p>
<p>::치기 귀찮으니깐 써주는 문법
using namespace 생략할이름;
== 내가 코드에서 이 이름의 네임스페이스를 사용하겠다.
== 이 네임스페이스의 이름을 생략하겠다.</p>
<p>3.출력할때 문자 쓰고 꺽쇠쓴 후 변수 이름쓰면 문자 변수값이 출력됨
  입력할때는 꺽쇠 반대로,그리고 입력값 2개면 꺽쇠로 2개 나눠서 순서대로만 써주면됨
  (cin &gt;&gt; 입력한 값을 변수쪽으로 읽어드림)</p>
<p>4.<strong>생성자</strong>(=Constructor, C++에 특화된 문법)
=객체(클래스 변수,클래스로 만든 객체가 변수다.)가 생성될 때 필드(=맴버변수)나 여러 메소드(=맴버함수)들을 초기화하는 <strong>함수</strong> </p>
<p>특징1 : 일반 함수 정의문과 다르게 생성자 함수는 모양이 다른데 반환형이 없다.
(이유: 일반함수랑 구분하기 위해서,같은 모양이면 구분이 힘듬)</p>
<p>특징2 : 생성자의 이름은 무조건 그 클래스의 이름과 동일해야된다.</p>
<p>특징3 : 생성자는 무조건 public에서 선언되어야한다.</p>
<p>특징4 : 생성자는 문법적으로 강제하는 함수다
= 모든 클래스에는 생성자가 반드시 1개 이상은 존재한다.
내가 객체에서 생성자를 지정해주지않아도 빌드할때 컴파일러가 자동으로 기본 생성자 하나를 만들어준다.</p>
<p>예시)
class Test{
            int scores;
public
            test(){
                    score=100;
            }
}</p>
<p>이렇게 내가 원하는 값으로 초기화를 시켜줄 수도 있고 score=100;를 안해줄 수도 있는
Default Constructor로 넣어줄 수 있다.</p>
<p>Default Constructor는 매개변수가 없거나 초기화 된 매개변수를 가진 생성자을 의미한다.</p>
<ul>
<li>c언어 구조체도 기본생성자가 자동으로 초기화해준다.</li>
</ul>
<p>무조건 만들어주냐?</p>
<ul>
<li><p>클래스에 기본자료형(int,int형 배열 등)만 존재한다.</p>
</li>
<li><blockquote>
<p>초기화를 직접 해줄필요가 없다.</p>
</blockquote>
</li>
<li><p>클래스에 사용자정의자료형이 존재한다.(=클래스 안 클래스)</p>
</li>
<li><blockquote>
<p>생성자가 자동으로 생성되지않는다.(컴파일러마다 상이)</p>
</blockquote>
</li>
</ul>
<p>즉,해줄 수도 있고 안해줄 수도 있다는것은 그냥 우리가 직접해주는게 합리적이다.
이때 우리가 만들어주면 컴파일러에서 따로 안만들어준다.</p>
<p>특징5 : 생성자는 함수인데도 불구하고 호출할 필요가 없다.==자동으로 호출된다.</p>
<p>언제냐면 <strong>&quot;객체가 생성될 때&quot;</strong>다.
(엄연히 정확하게 말하자면 생선된 직후임)</p>
<p>클래스가 정의될 때가 아닌 객체가 선언(=생성)될 때이다.
class Mycar{} x
Mycar car; o -&gt; 이때 마이카의 생성자가 불려지는것이다.그러면서 정의문 안에 있던 변수들이 초기화가 되는것</p>
<p>특징6 </p>
<p>class mycar{</p>
<p>public:
    test();</p>
<p>private:
    int num;    //멤버변수 선언</p>
<p>}</p>
<p>mycar::test(){
    num = 0;
    cout &lt;&lt; &quot;mycar 생성자 호출&quot; &lt;&lt; endl; </p>
<p>}</p>
<p>int main(){</p>
<p>   mycar A;   //객체 선언</p>
<p>}</p>
<p>위 예시 코드를 보면 클래스 마이카 정의문에 public안에 멤버함수로 생성자 함수 하나만 선언했는데 얘도 C언어 함수처럼 클래스 내부에다가는 선언만 해놓고
(주의할 점은 생성자도 정의랑 선언은 다르다. 정의 -&gt; mycar(){} 선언 -&gt; mycar();)
외부에다가는 생성자 정의문을 만들어주는게 가능해서 클래스 외부에다가 생성자함수를 정의한 것이다.</p>
<p>근데 생성자를 밖에다가 정의할때는 일반함수와 구분해줘야된다.
생성자는 반환형이 없는게 일반함수와 구분할 수 있는 특징이였는데 클래스 외부에서 구분할려면 반환형이 있든없든 생성자 함수는 앞에 namespace처럼 클래스명::을 정의문 생성자이름 앞에 써주면된다. 
mycar::test()  OR  void mycarspeed::test()</p>
<p>생성자 정의문안에는 변수와함수들을 초기화할 수 있으니 변수와 함수들이 들어갈 수 있음</p>
<p>메인에서 클래스 변수 즉 객체가 선언(생성)될 때 동시에 호출돼서 생성자정의문에서 초기화로 넣어준 코드들이 실행된다.
(코드 실행하면 출력문에 써줬던 글이 출력됨)</p>
<p>결론 : 객체가 생성될 때 생성자가 자동으로 불린다.</p>
<p>특징 7 : 생성자가 1개가 아닐 수도 있다.
우리가 봤던 생성자(기본 생성자)는 인자, 매개변수가 없었다.
근데 인자를 받는, 매개변수를 받는 생성자를 만들 수 있다.(int형을 받는, float형을 받는)</p>
<p>이런 생성자도 정의문은 기본형이랑 비슷하다.</p>
<p>클래스명::생성자(매개변수)
{</p>
<p>}</p>
<p>ex)
Mycar::Myclass( )
{</p>
<p>}
Mycar::Myclass(int NUM)
{</p>
<p>}
Mycar::Myclass(float f1, float f2)
{</p>
<p>}</p>
<p>이렇게 생성자를 여러개 정의하고 메인에서 변수를 선언해서 실행해도 에러가 나지않는다.
근데 이렇게 정의된 생성자가 많아도 객체가 선언될 때는 하나의 생성자 함수만 불린다.</p>
<p>그러면 여러개 중 불릴 생성자를 어떻게 판단하냐? 
-&gt; 메인 함수에서 변수 선언문의 넘겨주는 인자값의 자료형을 보면된다.</p>
<p>ㄱ. 기본생성자가 불리는 경우 -&gt; 선언된 변수의 인자가 아무것도 없을때
    ex) Mycar a;
ㄴ. int형을 받아오는 생성자가 불리는 경우 -&gt; 선언된 변수의 인자가 int인 경우
    ex) Mycar b(5);<br>    // Mycar b = Mycar (5)(일반 호출문과 비슷하며, 생성자로 호출하는 개념으로 보면된다.)와 같다. 
    // == &quot;나는 int형 하나 가지고 <strong>b라는 객체</strong>로 만들겠어 </p>
<p>그렇다면 생성자를 왜 이렇게 여러개 정의하냐?
-&gt; 생성자는 멤버변수와 멤버함수를 초기화해주는 함수라고 생각하면 내가 객체를 선언할때 그에 필요한 변수들의 초기값을 가져와서 선언 동시에 초기화 시켜주고싶을때가 있어서 변수의 자료형만큼 여러개 생성자를 만들어주는것이다.</p>
<p>보통은 생성자를 하나로 하는데 여기에 인자 모두를 받아올 수 있도록한다.
(==내가 가지고 있는 변수들에 대해서 초기화할 수 있는 값을 다 가지고 있는 생성자) </p>
<p>ex)
class Mycar{</p>
<p>public
   MYcar();
}</p>
<p>Mycar::Mycar(int num,float f1,float f2)
{
    num1 = num;
    float1 = f1;     //이때 f1의 값은 메인함수에서 객체를 생성할 때 넘겨주는값임
    float2 = f2;
    cout &lt;&lt; &quot;여러개 생성자 호출 가능&quot; &lt;&lt; endl; 
}</p>
<p>int main(){
 Mycar a(5, 1.5, 3.1);</p>
<p>}</p>
<ol start="5">
<li><strong>초기화 리스트(Initialization List)</strong>
생성자에서 필드를 간단하게 초기화하는 방법 -&gt; (b)의 방식</li>
</ol>
<p>생성자에서 초기화하는 방법은 두 가지가 존재하는데 (a)하나는 위처럼 생성자 정의문 내부에 넣어주는법이 있고 (b)두번째는 아래처럼 쓰이는 방법이다.</p>
<p>Ex)
class::생성자명()
    :num(0)    // num=0과 같음
{</p>
<p>}</p>
<p>(b)의 방식은 언제쓰이냐?
-&gt; 레퍼런스 즉 참조형변수 or const변수를 클래스 정의문 안에 멤버변수로 넣었을때
(선언과 초기화 동시에 해줘야되는 변수가 이 2개임)</p>
<ul>
<li>const변수(=상수형 변수,상수화 변수)<br>: 상수화 시켜버려서 값이 한번 정해지면 변하지않는 변수</li>
</ul>
<p>레퍼런스 변수는 정의문에선 살아있지않고 객체가 생성될때 같이 생성되는데 이때 레퍼런스 특성상 생성 동시에 초기화까지 되어야한다.근데 생성 직후에 생기는 생성자에서 레퍼런스를 초기화시키면 너무 늦어서 에러가 난다.그럼 여기서 언제 참조형 변수를 초기화 해야되냐면 바로 (b)처럼 생성자명과 중괄호 사이에 참조형변수를 초기화시켜주면 참조형변수는 생성 동시에 초기화하는게 가능해진다.</p>
<p>정리
참조형변수 초기화 -&gt; (b) -&gt; 객체 생성 동시에 
그 외 다른 변수 초기화 -&gt; (a) -&gt; 객체 생성 직후 </p>
<p>(b)의 문법을 바로 초기화 리스트라고 한다!그리고 이게 가능한 이유는 이런 목적을 위해 특별히 만들어진애여서(생성자보다 먼저 불리는 애를 만들어줄태니 생성자 안에 표기해놔라)</p>
<p>근데 그냥 클래스 정의문 내에서 변수 옆에 초기화식을 넣어주면 안되냐? 
-&gt; 그래도 된다. 그래서 생성자 문법이 중요성이 높은것은 아니다.</p>
<ol start="6">
<li>결국 생성자는 자동으로 초기화시켜줄때도 있고 직접해줄때도 있지만 컴파일러에서 자동으로 초기화를 하는데 있어 제대로 하지않을 가능성이 있으니 왠만하면 직접 생성자를 만들어주자.(100% 컴퓨터를 믿지말자) 본인이 생성자를 컨트롤하는게 중요하다.</li>
</ol>
<p>-&gt; <strong>이게 바로 클래스를 다루는 첫번째 조건이다!!!</strong></p>
<p>7.동적할당영역</p>
<p>프로그래머가 힙영역에서 직접 메모리를 빌려왔으면 반납도 직접 해줘야된다.내가 반납하는것을 까먹으면 그 메모리는 영원히 못쓴다.(운영체제는 내가 계속 쓰고있는걸로여김)</p>
<p>이 반납하는 행위를 생성자와 소멸자란 것으로 컨트롤해서 반납한다.
생성자를 쓰는건 c++에서 단점이 아니라 동적할당영역과 관련하여 장점이다.</p>
<p>전역변수는 운영체제가 시작과 동시에 끝날때까지 쓸 수 있는 장점이 있는 변수다.
근데 전역변수의 단점도 있는데 전역변수로 쓸 수 있는 공간이 작다.
또한 만약 int형 배열의 크기가 100억이라하면 너무 많아서 메모리 컨트롤이 불가능하다.</p>
<p>만약 배열의 크기가 1억이라면,이 배열을 선언해놓은 다음에 초기화를 0으로 해놓고,다음과 같이 코드가 있다고 가정하면</p>
<p>int num[1000000000]; 선언
num = 0;</p>
<p>int main() {
    num                          //num을 이용한 코드1 
    num                          //num을 이용한 코드2
    num                          //num을 이용한 코드3</p>
<p>   ...</p>
<p>   추가적인 코드 10000줄이 있다고 가정 </p>
<p>}</p>
<p>이때 int형 변수 num은 main 함수 내에서 계속 살아있다.(만 줄이 끝날때까지)
num이 쓴 세줄만큼만 살아있으면되는데 이후 다른 코드에서도 살아있고 그말은 곧 메모리가 계속 할당이 되어있어 메모리가 낭비가 된다.</p>
<p>이런 낭비를 막고자 운영체제가 하나의 공간을 제공하는데 그게 바로 힙영역이다.
<strong>여기에선 개발자가 원할때 메모리를 할당받고 원할때 메모리 반납이 가능하다.</strong>
(지역변수도 사라지긴하지만 괄호 영역 안에서 중간에 반납이 불가한걸 생각해보면 특수능력임)</p>
<p>물론 위 상황에 NUM을 지역변수 내에서 따로 쓰는 방식으로 유의미하게 만들어도되는데 여기서는 반환을 해주는 작업을 별도로 해줘야된다.(복사값)</p>
<p><strong>그런고로 동적할당영역에선 NEW라는 함수를 이용한 문법으로 메모리를 할당받고 반납해야된다.</strong></p>
<p>8.동적할당영역 문법
(동적 : 동적으로 크기를 바꿔가면서 할당 받을 수 있다.)</p>
<p>ㄱ.main함수에서 메모리를 할당받고싶을때</p>
<p>int* ptr = new int; 라는 문법을 쓴다.</p>
<p>여기서 new는 함수이고 int는 자료형인데 이것은 곧 &quot;new int의 결과값을 ptr에 넣어준다&quot;다. 즉 new int의 결과값은 주소값이라는것을 추측할 수 있다.</p>
<p>-&gt; 포인터변수에 힙영역 중 임의의 공간의 주소값을 받아오는게 목적이다.</p>
<p>우리가 포인터변수를 사용할 땐 일반적으로 아래와 같이 주소값을 담는다.
int num = 3;
int * p = &num; </p>
<p>num에 접근할 수 있는 방법은 2가지인데 이름과 포인터가 가리키는 주소값이다.근데 지금 여기선 new int는 가리키는 메모리의이름을 모른다.(변수 실체에 대한 이름이 x)</p>
<p>이름을 몰라도 할당받을 수 있는게 힙공간의 특징인데 이 문법이 의미하는것은 &quot;운영체제로부터 int형 만큼의 메모리를 할당해줘&quot;와 같다.</p>
<p>이 문법을 실행하면 힙영역에 운영체제가 int형 변수 하나를 선언한다.(단,이름없는 변수로) 그럼 이 변수에는 어떻게 접근하냐? 
-&gt; 이름으로 접근하는것은 안되고 주소값으로 접근해야되는데 이때 NEW 함수가 주소값을 알려주는것이다.</p>
<p>NEW 함수 = &quot;이름 없는 변수를 힙공간에 만든 후 그 주소값을 가져와줘&quot;</p>
<p>이렇게 주소값이 포인터변수 ptr로 들어오면, 그 변수에 접근할때는 포인터 쓰는것처럼</p>
<ul>
<li>ptr = 3; 식으로 값을 안에 있는 값을 바꿔주면된다.</li>
</ul>
<p>ㄴ.main함수에서 할당받은 메모리를 반납하고싶을때의 문법</p>
<p>delete ptr;</p>
<p>ptr은 이전에 할당받았던 주소값을 가지고있는 포인터변수고 이것을 넣어주면 알아서 반납이 된다.</p>
<p>9.동적할당의 특별한 장점은 배열을 할당 받을 수 있다는것인데, 배열은 크기가 정해져있고,우리는 크기를 맘대로 바꿀 수 없다.근데 동적배열할당을 하게되면 배열의크기를 우리가 정할 수 있게된다.</p>
<p>배열의 크기에는 보통 상수가 들어가고 변수는 들어가지못한다.코드에 따라서 배열의크기가 달라진다는게 불가능하기때문이다.코드를 짤 때 배열의크기는 무조건 고정되어있어야한다.근데 여기선 변수가 들어가는게 가능해진다.</p>
<p>만약 할당을 할 때 배열로 동적배열할당을 할 시 아래와 같이 코드를 짜면 </p>
<p>int * ptr = new int[10];   </p>
<p>//int형 이름없는 배열 10개(40바이트)를 힙영역에서 할당해주고 그 주소값을 가져와줘
(이때의 주소값은 첫번째 배열의 주소값 이걸 ptr에 넣어주는 것임,배열의주소는 배열의 이름이지만 여기선 이름을 모르니 x)</p>
<p>여기선 상수 대신에 변수가 들어갈 수 있다.
cin &gt;&gt; num을 써주는 식으로 우리가 배열 크기를 입력할 수 있음 </p>
<p>10.변수가 들어가면 좋은 이유 
유동적인 코드를 만들 수 있다.상수를 배열의 크기로 정한 코드는 데이터 관리를 할때 현황이 바뀌면 그때마다 코드를 일일히 고쳐야되는데 동적배열할당을 받으면 cin 함수로 배열의크기를 입력받아 유동적으로 할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C++ 이론(1)]]></title>
            <link>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A01</link>
            <guid>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A01</guid>
            <pubDate>Wed, 21 Jun 2023 07:48:44 GMT</pubDate>
            <description><![CDATA[<h1 id="1강">1강</h1>
<p>1.
프로세스(빌드까지 한 파일을 실행한 것)한 시점의 메모리 형태 </p>
<p>운영체제가 무조건 메모리를 빌려주는게 아니라 실행할 때 프로그램을 운영할 만큼의 메모리만 때줌.</p>
<p>이 메모리의 영역은 다음과 같이 나눠진다.
코드영역, 데이터 영역(전역 변수,STATIC 변수), 힙 영역(프로그래머 할당), 스택 영역(지역변수,매개변수)</p>
<p>ㄱ.스택영역: 임시 변수들 메모리가 잡히는 곳 (메모리 공간이 유동적임,임시적으로 생겼다가 사라져서)</p>
<p>프로그램이 실행되면 메모리 한덩이를 딱 때어줌</p>
<p>데이터의 끝에서부터 위로 영역이 생김</p>
<p>스택영역은 변수가 생길 때 바닥에서부터 차곡차곡 쌓아져서 올라가는데 삭제되는건 위에서부터 삭제가 된다.
(FILO OR LIFO)</p>
<p>함수가 끝나면 지역변수의 메모리 반납을 마지막 변수부터 선언 역순으로 한다는 소리임</p>
<p>ㄴ.데이터영역: 전역변수,스테틱변수들 메모리가 잡히는곳(이건 메모리가 정해져있음)</p>
<p>ㄷ.힙 영역: 동적할당 메모리가 쌓이는 것(추후할 예정)</p>
<p>메모리의 시작점부터 아래로 영역을 잡아감</p>
<p>스택 영역과 힙 영역이 각각 차서 만나게 된다는 것은 메모리가 꽉 찼단 것이고,그 시점 부터 프로그램이 돌아가지않는다.(관리 필요)</p>
<p>변수같은건 운영체제에 요청해서 받아오지만 동적할당같은건 어떤 필요에 의해서 우리가 직접 할당 받아오는 것이기에 위험할 수도 있다.</p>
<p>ㄹ.코드영역 
우리가 IDE에서 작업했던 CPP파일이나 해더파일들</p>
<p>2.
래퍼런스</p>
<p>&amp;연산자에는 주소값을 계산해서 가져오는 기능이랑 또 하나의 기능이 있는데 그거게 바로 &#39;래퍼런스&#39;이다.</p>
<p>래퍼런스는 포인터 선언과 비슷하다.
아래처럼 &amp;가 자료형과 변수명 사이에 있으면 얘는 래퍼런스 변수다라고 생각</p>
<p>iNUM = 10;
int&amp; rRef = iNUM;</p>
<p>래퍼런스의 역할
== 오른쪽 변수에다가 rRef라는 새로운 이름(별명)을 지어주겠다.</p>
<p>기본적으로 iNUM은 메모리를 할당받아 선언이 되어있는데 rRef는 새로 생긴게 아니라 iNUM의 메모리를 공유하게된다.
-&gt; 이름이 2개인 메모리 공간이 되는 것</p>
<p>rRef도 안에 10이 들어있다고 보면됨
(메모리가 별개가 아니라 진짜 본질은 하나이기에 공유한다는게 메모리 하나라는 소리다.rRef도 똑같은 값을 갖고있고 동일한 주소값을 갖는다.) </p>
<ul>
<li>래퍼런스를 쓰는 이유?
C++를 사용하면서 체득이 됨</li>
</ul>
<p>3.
참조 대상 변경 불가
참조 대상 == 래퍼런스가 대상으로 삼는 변수</p>
<p>래퍼런스는 선언할 때 동시에 무조건 초기화(대상:변수)까지 해줘야된다.</p>
<p>int&amp; rRef; (X)
int&amp; rRef = iNUM;(O)</p>
<p>래퍼런스는 누군가를 참조했으면 참조의 대상을 다시 바꿀 수는 없다.(빌드 에러남)</p>
<p>4.
포인터와 래퍼런스의 차이</p>
<p>포인터,래퍼런스를 프로그래머마다 쓰는게 다르고 각 장단점이 있지만 C++은 래퍼런스를 적극적으로 쓴다.</p>
<p>ㄱ.차이점(변경 유무)
포인터는 대상을 미리 NULL로 정해놓고 나중에 바꾸는 것이 가능해진다.그러고 여러번 바꾸는것이 가능 </p>
<p>-&gt; NULL이 들어있는지 체크 필요</p>
<p>래퍼런스는 반드시 선언과 동시에 초기화를 하고 래퍼런스는 변경이 불가능함</p>
<p>-&gt; 래퍼런스는 무조건 데이터값이 있는 상황의 코드에만 쓰여야됨.
케릭터들이 싸우는 도중 플레이어가 나간 경우의 NULL을 체크해야되는 상황인데 래퍼런스는 이 체크를 못함</p>
<p>ㄴ.차이점2(메모리 공간의 소모)
포인터 변수는 변수기 때문에 4바이트를 가져간다.</p>
<p>래퍼런스는 참조 대상의 메모리를 가짐으로서 메모리 소요가 없다.(원본 자체 데이터)</p>
<p>ㄷ.차이점3(호출시)
포인터의 경우
매개변수로 함수 인자 전달 시,메모리 소모(매개변수 갯수만큼)가 일어나고 값 복사가 발생된다.(값복사는 추후에)</p>
<p>값복사 : 포인터가 가리키는애의 값이 함수정의문으로 오면서 복사가 한번 되어야되는데 </p>
<p>우리가 함수를 호출할 때 주의했던게 이름으로 매개변수를 받아서 함수정의문에서 코드를 짠 후 메인코드에서 호출하면 지역변수이기때문에 원하던 결과값을 볼 수 없었기에 매개변수를 주소값으로 넘겨받게끔 하고 포인터든 배열이름이든 인수로 받았는데 </p>
<p>이 래퍼런스 변수는 이름으로 접근했는데도 불구하고 같은 메모리 그 자체이기 때문에 함수정의문에서 매개변수를 래퍼런스로 받으면  호출 시 지역변수 영향을 안받고 우리가 원하던 결과값으로 받을 수 있다.</p>
<ul>
<li>래퍼런스를 정의 및 초기화를 안하고 함수정의문의 매개변수를 래퍼런스 변수로 받은 경우?</li>
</ul>
<p>함수정의문에 있는 래퍼런스 매개변수는 정의했을뿐이고 이게 실제로 생기진않았다. 함수라는것은 평소에는 메모리에 잡히지않다가 호출될 때 잡힌다.즉 호출할 때 래퍼런스 변수도 선언이 된다.</p>
<p>그러면 호출 인자로 (a,b)를 넘겼을 때 어떻게 선언이 되냐면 매개변수가
int&amp; rRef X,int&amp; rRef Y라면</p>
<p>int&amp; rRef X = a;
int&amp; rRef y = b;와 같아진다.
즉 호출 되는 순간 선언 및 초기화된거랑 같아짐.</p>
<p>a.포인터변수의 함수문 작동시 스택 영역 메모리 구조 변화 과정</p>
<p>지역변수의 메모리인 스택영역에서 메인에서 임의의 변수 하나를 선언하면 스텍 메모리에 변수 하나만큼 메모리가 밑에 쌓이고 또 다른 변수를 선언하면 또 위에 변수의 자료형만큼의 메모리가 쌓인다.(num1,num2)그리고 임의의 함수를 호출하면(매개변수가 포인터변수고, 인자가 주소값이 들어가야된다고 가정할때.ex - &amp;num1, &amp;num2 ) </p>
<p>함수정의문의 매개변수에 주소값이 들어가면서 스택영역 변수메모리 위에 포인터변수의메모리가 쌓인다.(&amp;num1, &amp;num2에 대한 포인터변수 2개에 대한 메모리,현재까지 총 4번 쌓임) </p>
<ul>
<li>이때 스택 영역에는 함수메인 소속이든 함수정의문 소속이든 상관없이 메모리들이 붙어서 쌓인다.</li>
</ul>
<p>그리고 함수정의문에 새로운 변수가 선언되고 초기화되면 그게 또 쌓임</p>
<p>그리고 대입 코드들이 있다면 이건 새로 쌓이는게 아니라 할당되었던 메모리 위치에서 정보만 바뀐다.</p>
<p>b.매개변수가 포인터 변수가 아닌 래퍼런스 변수일때의 함수 작동시 메모리 구조 변화 과정</p>
<p>위처럼 똑같이 메인에서 선언한 변수 2개가 메모리 구조에 두 번 쌓이고,함수정의문으로 가면 변수가 래퍼런스로 잡혀있기에 메모리구조에서 쌓여있던 변수 2개 메모리가 새롭게 쌓이는거없이 각각 래퍼런스의 별명으로 바뀌기만 한다.
그리고 함수정의문 내에서 선언된 변수만 추가가 됨</p>
<p>결론 : 전자의 경우 후자보다 포인터변수 2개로 인해 8바이트가 스택영역 메모리 구조에서 더 소모하게된다.</p>
<p>5.우리가 포인터나 래퍼런스를 쓰는 이유는 구조체나 배열 및 변수를 이 2가지 없이 쓴다고 가정했을때 , 매개변수를 일반 변수로 받으면 시간이 너무 오래걸리기때문이다.</p>
<p>예시로 매개변수를 구조체로 받는데 구조체 안에 큰 크기의 배열이 있으면 호출될때마다 스텍영역에는 몇 천번 몇 만번 메모리가 쌓일 것이다.(구조체 변수 선언시 배열크기만큼 쌓이고 함수 작동되면서 배열크기만큼 또 쌓이고)</p>
<p>결론: 메모리를 엄청나게 절약시켜준다.
(단,포인터는 8바이트가 소요,그래서 포인터도 많이 쓴다고한다.)</p>
<p>6.객체지향언어</p>
<p>객체(=물체,object)를 가지고 프로그래밍한다.</p>
<p>c++은 절차지향언어이면서 객체지향언어다.</p>
<p>구조체는 사용자 정의 자료형으로 우리는 이전까지 자료형을 가지고 변수를 만들었다.
즉,구조체로 구조체 변수를 생성할 수 있다는것이고, 그 말은 클래스로 클래스 변수를 생성하는게 가능하단 소리다.
클래스는 객체로,객체는 곧 구조체 변수다.</p>
<p>그렇다면 객체 안에 함수는 없는건가?</p>
<p>구조체나 클래스 자체가 자료형이기에 안에 함수가 있다없다를 논할 수 없다.</p>
<p>구조체를 가지고 구조체 변수를 만들었을때 그 변수 안에 멤버변수들이 존재하는것처럼 멤버함수들도 존재한다.그 함수들은 일반적으로 호출되는 함수들이 아니라 그 구조체 변수를 가지고 호출할 수 있는게 멤버함수다.</p>
<p>객체 즉 구조체 변수 안에는 멤버변수들이 있고 멤버함수들이 있다했는데,
객체의 멤버변수를 가져다가 사용할 수 있고,객체를 가지고 멤버함수를 호출할 수 있음.</p>
<p>그렇다면 C언어든 C++든 구조체나 클래스를 사용하고 변수를 사용하는게 같은데 C언어도 객체지향언어 아닌가?</p>
<p>-&gt; C언어도 얼마든지 객체지향식으로 프로그래밍이 가능</p>
<p>결국은 객체지향언어는 컨셉이다. C언어에 일부 추가된 부분이 방대한데 그게 객체 지향 중심으로된 문법이기때문이다.편의를 위한 몇 가지 문법이 추가된것</p>
<p>7.객체의 구조
class 변수명{
   private:
    //멤버변수들</p>
<p>   public:
    //멤버함수들</p>
<p>};</p>
<p>여기서 알아야될건 멤버변수들의 생존주기는 가장 큰 중괄호 안인데 그말은 멤버함수안에서 컨트롤이 가능하다.
(읽어들이고 값을 변경할 수 있음)</p>
<p>외부에서는 멤버변수들을 가져다쓸 수도 있고 없을 수도 있다.(==컨트롤할 수 있다.)</p>
<p>우리가 구조체에서 c.name 이런식으로 했던 것처럼 외부에서 참조하는식으로 가능함</p>
<p>8.객체 멤버함수 호출 코드문 예시 </p>
<p>class MYcar {
private:
    int fuel = 0;
    bool power = false;</p>
<p>public:
   void go() {
        this -&gt; fuel--;
   }</p>
<p>   void oiling(int n) {
           this -&gt; fuel += n;
   }
   void fuel_check() {
           std::cout &lt;&lt; &quot;연료 : &quot; &lt;&lt; fuel &lt;&lt; std::endl;
   }
};</p>
<p>int main (){
MyCar car = MyCar();    //객체(클래스 변수) 선언(객체 생성) </p>
<p>//함수 호출
car.oiling(100);
car.fuel_check();
for(int i = 0; i &lt; 10: i++) car.go();
car.fuel_check();
car.oiling(100);
for(int i = 0; i &lt; 10: i++) car.go();
car.fuel_check();</p>
<p>};</p>
<p>위를 보면 객체 안의 멤버함수를 메인에서 호출할 수 있다.</p>
<p>객체이름.함수이름(인자);</p>
<p>이런식으로 객체이름 안에 있다는것을 명시해주는게 중요하다.</p>
<p>또한 oiling 호출한 순간 멤버 변수 fuel이 변한걸 볼 수 있다.
멤버변수의 값을 변경시키는 방법으로
우리가 멤버변수의 값을 직접적으로 변경시킬 수도 있는 방법이 있고,</p>
<p>ex) car.fuel + 100;</p>
<p>함수를 통해 값을 변경시킬 수도 있다.
-&gt; 직접 바꿀 수 있는데 굳이 이렇게 하는 이유는 장점이 있는데 뒤에 나옴</p>
<p>정리하자면 객체의 상태(멤버 변수, 함수)를 계속 변화시키고 컨트롤하면서
객체의 상태변화를 화면에 띄어주고 그 프로그램을 전개하는게 객체지향언어다.</p>
<p>예시) 게임의 몬스터는 똑같은게 아니라 다 객체 중 하나다.관련된 특성,행동 다 클래스 하나로 묶어서 관리한다.</p>
<p>9.
접근제어자</p>
<p>접근을 제어해주는 역할을 하는건데, 외부에서 접근을 해주게하냐 마냐의 차이다.</p>
<p>외부에서 접근을 가능하게끔 제어해주는게 &#39;접근제어자&#39;다.</p>
<p>종류로는 private(외부에 공개X),public(외부에 공개o),protected(뒤에서 상속배울때)
등이 있다.</p>
<p>처음은 private부터 나오면서 다른 접근제어자가 나올때까진 계속 프라이빗이다.
객체의 디폴트 접근제어자는 private다.그래서 안쓰면 전체가 private가 된다.</p>
<p>C언어에서 배웠던 구조체는 기본적으로 public이다.</p>
<p>프라이빗 안에 있는 요소들(fuel같은거)은 메인함수 즉 외부에서 쓰일 때 빌드에러가 나는데 프로그램이 실행될려면 필요한데 왜 막을까? 그리고 이걸 쓸려면 어떻게 해야될까?</p>
<p>car.oiling(100);처럼 함수호출로 우회해서 사용한다.(oiling은 퍼블릭에서 속하고 밖에서 호출할 수 있음.그리고 oiling 안에서 fuel을 바꿔주고있다.프라이빗이지만 퍼블릭 내부에 있기때문에 건드릴 수 있음</p>
<ol start="10">
<li>프라이빗의 존재 이유</li>
<li>협업 문제
되도록이면 건들고싶지않은 것들이 있을때 쓰는데, 사람이 잘안건드릴려고해도 협업하다보면 건드리게 되어있기때문이다.(중간에 누군가 뭘 껴놓으면 그걸 되게 찾기힘들다.)</li>
</ol>
<p>2.보안문제
코드는 유추하기 어렵지만 숫자는 유추하기쉬워서 이런걸 해커들이 건드린다.</p>
<p>11.
매개함수 장점
예외처리란게 있는데 함수안에서 조건식을 써서 수치를 어느 기준 범위안에서만 처리하고 나머지는 예외로 처리하는 것이다.(비정상동작이든 해킹이든 개발자 실수든 잡을 수 있음)</p>
<p>결론 민감한건 개발할 때 프라이빗 안에 포함시키고 마지못해 퍼블릭에 있어도 매개함수 우회하는 식으로 한번 감싸서 코드를 짜자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C 이론(21)]]></title>
            <link>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A021</link>
            <guid>https://velog.io/@kiwi_100/C-%EC%9D%B4%EB%A1%A021</guid>
            <pubDate>Sun, 18 Jun 2023 08:05:30 GMT</pubDate>
            <description><![CDATA[<h1 id="구조체">구조체</h1>
<p>1.구조체의 멤버로 구조체를 넣을 수 있다.(자기 자신 구조체도 멤버로 넣을 수 있음) </p>
<p>구조체 멤버 각 변수에 접근하고 싶을때
-&gt;
선언한 구조체 변수명.구조체 멤버의 변수명.구조체 멤버 안의 접근하고 싶은 변수명
=대입할 값;</p>
<ul>
<li>한글자로 변수 짜는거 절대 금지 -&gt; 인덱스를 제외한 무조건 남이 봐도 기능을 알 수 있게끔(차라리 풀네임으로 쓰는게 나음)</li>
</ul>
<p>2.두 점(x,y) 사이의 거리 구하는 코드를 보면서 공부한 점</p>
<ul>
<li><p>좌표 변수명은 보통 point로 한다.(point 하나당 좌표 상의 점 하나로 생각하면됨)</p>
</li>
<li><p>좌표를 쓸 땐 단순 변수로 x,y를 안쓰고 구조체 변수로 쓰는 이유는?
안되는건 아니지만 좌표의 성질상 묶여야되는 개념이기에 구조체 point로 묶어주는게 정석(기능 뿐만 아니라 유지 보수 그리고 누가 코드를 봐도 일할 수 있게 코드를 짜야하는게 중요함)</p>
</li>
<li><p>sqrt 함수 = 값에 제곱근을 씌워주는 함수(전처리기 math.h안에 있음)</p>
</li>
<li><p>두 점 사이의 거리를 구할 땐 피타고라스의 정리 이용</p>
</li>
<li><p>사각형 점4개가 아닌 점2개로 구현한다.
(점2개가지고 나머지 점 2개의 좌표를 알 수 있기때문에)</p>
</li>
<li><p>절댓값 씌우기 |x|  -&gt; abs 함수 쓰면된다.</p>
</li>
</ul>
<p>3.같은 구조체 변수끼리 대입이 가능하지만 비교는 불가능하다.
-&gt; 문법적으로 연산자를 써서 조건식을 풀어서 써줘야 허용해준다.</p>
<p>예시)</p>
<p>struct point {
int x;
int y;
};</p>
<p>int main(void)
{
   struct point p1 = {10, 20};
   struct point p2 = {30, 40};</p>
<p>   p2 = p1;                               // 대입 가능</p>
<p>   if( p1 == p2 )                         // 비교 -&gt; 컴파일 오류!!
           printf(&quot;p1와 p2이 같습니다.&quot;)
   if( (p1.x == p2.x) &amp;&amp; (p1.y == p2.y) ) // 올바른 비교
        printf(&quot;p1와 p2이 같습니다.&quot;)
 }</p>
<p>4.구조체 배열 
배열하고 똑같은 방식으로 쓰면되는것이고, 구조체가 인덱스만큼 모여있는것과 같다.</p>
<p>구조체 배열 선언 
-&gt; struct 구조체 태그명 변수명[i];</p>
<p>접근법
-&gt;구조체 변수[인덱스].구조체 멤버변수명 =     ;</p>
<p>구조체 배열의 초기화
-&gt; C언어는 구조체는 우리가 초기화를 안해줘도 자동으로 초기화해주는것이 지원이 된다.
(기본 자료형에 대해서만) 근데 객체지향언어인 C++에선 지원안하니깐 해줘야된다.(인간이 컴퓨터보다 더 꼼꼼해야되고 컴퓨터를 못믿는다.)</p>
<p>구조체 초기화할 때 포인터변수는 초기화 안해줘도된다.즉 포인터변수 포함한 4개의 변수를 가진 구조체여도 3개만 초기화해도 가능! 순서만 틀리지않으면된다.</p>
<p>예시)
struct student {
   int number;
   char name[20];
   double height;
};</p>
<p>int main(void)
{
    struct student list[100];                  // 구조체의 배열 선언
    list[2].number = 27;
    strcpy(list[2].name, &quot;홍길동&quot;);
    list[2].height = 178.0;
}</p>
<p>struct student list[3] = {                     // 구조체 배열의 초기화
{ 1, &quot;Park&quot;, 172.8 },
{ 2, &quot;Kim&quot;, 179.2 },
{ 3, &quot;LEE &quot;, 180 3 }
}</p>
<p>5.구조체의 포인터 
구조체도 포인터 변수가 있다.(자료형은 다 포인터가 있음)
-&gt; 클래스 포인터도 있음(99프로 같은데, 1%가 매우 어려운 내용으로 다름)</p>
<p>struct student * p; 이 말은 즉 student라는 자료형 포인터 변수 P를 선언한 것</p>
<p>예시)
struct student * p;</p>
<p>struct student s = { 20070001, &quot;홍길동&quot;, 180.2 };
struct student student * p; </p>
<p>p = &s;</p>
<p>printf(&quot;학번=%d 이름=%s 키=%f \n&quot;, s.number, s.name, s.height);
printf(&quot;학번=%d 이름=%s 키=%f \n&quot;, p-&gt;number, p-&gt;name, p-&gt;height);</p>
<ul>
<li>-&gt; 연산자
= 구조체 포인터로 구조체 멤버를 참조할 때 사용.
= 포인터가 가리키는 멤버변수의 값에 접근한다.</li>
</ul>
<p>포인터변수가 그 가리키는 애의 멤버변수에 접근할때는 화살표를 써줘야한다.
(.을 안쓴이유는 멤버변수가 P가 가리키는애의 것이지 P의 것은 아니여서 그걸 구분해줄려고 위와 같이 쓴 것임)</p>
<p> p-&gt; 은 (* p)와 같다.</p>
<p> printf(&quot;학번=%d 이름=%s 키=%f \n&quot;, (* p).number,(* p).name,(* p).height);</p>
<p>6.포인터로 멤버를 가지는 구조체 
구조체 안에는 변수들이 들어가니 당연히 포인터 변수도 들어갈 수 있는거고, 구조체 포인터 변수도 들어갈 수 있다.</p>
<p>예시)</p>
<p>struct date {
    int month;
    int day;
    int year;
};</p>
<p>struct student {
    int number;
    char name[20];
    double height;
    struct date * dob;
};</p>
<p>int main(void)
{
struct date d = { 3, 20, 1980 };
struct student s = { 20070001, &quot;Kim&quot;, 180.2 };</p>
<p>s.dob = &d;</p>
<p>printf(&quot;학번: %d\n&quot;, s number, s.number);
printf(&quot;이름: %s\n&quot;, s.name);
printf(&quot;신장: %f\n&quot;, s.height);
printf(&quot;생년월일: %d년 %d월 %d일\n&quot;, s.dob-&gt;year, s.dob-&gt;month, s.dob-&gt;day);</p>
<p>return 0;
}</p>
<hr>
<p>student안의 struct date * dob;에 date의 변수들이 들어있을까? </p>
<p>-&gt; 들어있을것같지만 들어있지않다.student 안에는 포인터 변수만 존재한다.
month,day,year는 멤버변수일뿐 아직 생겨나지않았다.포인터는 어떤 변수를 가리킬 수 있는애인데 포인터 변수는 무조건 가르키는것도 아니여서 안가리킬 수도 있다.</p>
<p>구조체 선언만 한 시점에서는 포인터변수가 가리킬지 아닐지 모른다.</p>
<p>그렇다면 언제 가리키냐</p>
<p>s.dob = &d;
이렇게 주소값을 넣어주는 코드를 넣어야 dob가 date.d를 가리키게되는것이다.
이때 그러면 dob의 데이터 크기는 늘어나냐? 아니다. 각자 다른 존재여서 date의변수들은 가족이 아니라 남의 존재이다.</p>
<p> s.dob-&gt;year, s.dob-&gt;month, s.dob-&gt;day
 == dob가 가리키는 애(d)의 year, month, day를 의미</p>
<p> -&gt;연산자를 언제 써야되지?
 무조건 포인터변수 쓰면 그때 화살표를 쓴다.</p>
<ul>
<li><p>포인터 변수 주의할 점
** 포인터 변수를 쓸땐 항상 NULL 체크를 하여야된다.**
NULL, 즉 없는 공간으로 초기화되어있는데 -&gt; 연산자로 쓰면 아무것도 없는데 뭔가를 가리키는 것이기 때문에 크래쉬가 일어난다.그래서 NULL로 값이 되어있는지를 체크해야된다.</p>
<p>포인터변수를 본다 -&gt; NULL 체크해야지 이렇게 습관화 시키자!
(프로그래머가 실수하는 순위 상위권 항목)</p>
</li>
</ul>
<ul>
<li>포인터변수의 크기
기본 변수들은 int형 변수면 4바이트, float형 변수는 4바이트 이렇게 자료형에 따라 변수의 크기가 달라지는 반면에 포인터변수의 크기는 int형 포인트변수나 float형 포인트변수나 double형 포인트변수나 다 주소값을 가리키는 변수여서 다 메모리크기가 똑같다.</li>
</ul>
<p>만약 구조체 안의 int형 변수들이 100개라고 하면 구조체는 400바이트인데 그러면 그걸 가리키는 포인터변수도 400바이트여야되나? 그건 낭비다.가리키기만 역할 끝(배열도 인덱스가 몇 개든 배열이름 하나로 관리)</p>
<p><strong>그런고로 모든 포인터 변수의 크기는 4byte다.</strong>
int형 포인트 변수 4바이트, double형 포인트 변수 4바이트, char형 포인트 변수 4바이트,구조체 date형 포인트변수, student형 포인트변수 다 4바이트!</p>
<p>단, 
32비트(=X86)나 64비트 운영체제는 운영체제별로 사용하는 비트 단위수인데 64비트 환경에서는 포인터변수가 8 바이트다.(면접 질문 빈도 높음)</p>
<p>7.자체 참조 구조체
자기 자신 구조체 그대로 멤버로 넣을 수 있는 경우가 있는데 그건 포인터로만 된다.
== 즉 구조체 안에 구조체 포인터 변수가 들어간다는 소리와 같다.</p>
<p>가능 이유 : 자기를 가리킬 수 있는 포인터변수가 구조체 안에서 자리잡을 수 있기때문에
구조체 안에 구조체를 하나 더 담는다(x)
자기 구조체의 주소값을 가리키는 포인터변수를 넣는건 가능(0)
그리고 구조체를 가리킬 수 있다는것뿐이지 구조체와 무관한 존재임(같다고 생각X,그 구조체를 안가리킬 수도 있음) 4바이트짜리 student형 포인터 변수임.</p>
<ul>
<li>포인터변수 초기화 시 보통 NULL로 초기화한다.(==아무것도 안가리키겠다)</li>
</ul>
<p>예시)</p>
<p>struct student {                           //구조체 student 선언
    int number;
    char name[10];
    double height;
    struct student * next;                 //포인터 변수 next가 들어있음
};</p>
<p>int main(void)
{
    struct student s1 = { 30, &quot;Kim&quot;, 167.2, NULL };   //구조체 변수선언및초기화
    struct student s2 = { 31, &quot;Park&quot;, 179.1, NULL };  //구조체 변수선언및초기화
    struct student * first = NULL;     //구조체 포인터변수선언 및 초기화
    struct student * current = NULL;   //구조체 포인터변수선언 및 초기화</p>
<p>   first = &s1;        //포인터변수안에 S1 주소값을 넣어줌,얘는 S1을 가리킴
   s1.next = &s2;     //S1의 next에 S2의 주소값을 넣어줌,얘는 S2를 가리킴
   s2.next = NULL;    //S2의 next는 아무것도 안가리킴</p>
<p>   current = first;   //포인터변수에 &amp;S1을 넣어줌 그러면 first하고 추가로 S1을 가
                        리키는애가 하나 더생김</p>
<p>   while( current != NULL )  //while반복문 참이면 계속 거짓이면 탈출(널될때까지)
   {
        printf(&quot;학생의 번호=%d 이름=%s, 키=%f\n&quot;, current-&gt;number,current-            &gt;name, current-&gt;height);
        current = current-&gt;next</p>
<p>   //current는 현재 s1을 가리키고있기에 NULL이 아니여서 S1의 값들이 출력된다.
   //그리고 가리키는 S1의 next가 가지고 있는 주소값을 current에 대입한다.
     즉,S2를 가리키기때문에 S2의 주소값이 들어간다.
   //current는 현재 s2을 가리키고있기에 NULL이 아니여서 S2의 값들이 출력된다.
   //그리고 가리키는 S2의 next가 가지고 있는 값을 current에 대입한다.
     S2의 next는 아무것도 안가리키기에 while문이 종료된다.</p>
<p>   }</p>
<p> }</p>
<p> 8.구조체를 함수에 적용하는법</p>
<p> 똑같이 매개변수에 자료형과 변수를 쓰면되고 여기에 구조체 형식을 넣으면된다.다만 이런식으로 구조체 형식 그대로 인수를 넘겨받냐 구조체 자료형 포인트변수를 써서 주소값을 넘겨받는 방법이 있는데 </p>
<p>전자의 경우 호출시 구조체의 복사본이 함수로 전달되게되고,(메인의 있는 구조체를 자체적으로 복사해서 하나하나를 함수로 넘겨준다.근데 이게 구조체가 많아지면 비효율적)</p>
<p>구조체의 크기만큼 시간이 걸린다.근데 후자의 경우는 시간과 공간을 절약할 수 있다.
다만 이때 다시한번 말하지만 NULL 체크는 꼭 하기</p>
<p>예시)</p>
<p>함수의 인수가 구조체 자체일때 
int equal (struct student s1, struct student s2)
{
    if( strcmp(s1.name, s2.name) == 0 )
            return 1;
    else
            return 0;
}</p>
<p>함수의 인수가 구조체 포인터 변수일때 
int equal(struct student student const * p1 , struct student student const * P2)
{
    if( strcmp(p1-&gt;name, p2-&gt;name) == 0 )
        return 1;
    else
        return 0;
}</p>
<p>9.구조체를 반환할 때(반환값이 구조체)</p>
<p>struct student make_student(void)
{
    struct student s;</p>
<p>   printf(&quot;나이:“);
   scanf(&quot;%d&quot;, &amp;s.age);
   printf(&quot;이름:&quot;);
   scanf(&quot;%s&quot;, s.name);
   printf(&quot;키:&quot;);
   scanf(&quot;%f&quot;,&amp;s.height);</p>
<p>   return s;
}</p>
<p>반환형이 struct로 되어있을때 구조체 변수 선언 후 반환값을 구조체 변수로 해주면 
구조체s의 복사본이 반환된다.(이때 반환되는 변수 S는 함수내의 지역변수여서 main함수에서 쓸려면 return s의 복사본을 써야된다.)</p>
<p>10.열거형이라는 자료형</p>
<p>열거형(enumeration)이란 변수가 가질 수 있는 값들을 미리 열거해놓은 자료형
(예) 요일을 저장하고 있는 변수는 { 일요일, 월요일, 화요일, 수요일, 
목요일, 금요일, 토요일 } 중의 하나의 값만 가질 수 있다.</p>
<p>열거형은 enum이라는 키워드를 사용하여 만들어진다. </p>
<p>enum 태그_이름 { 값1, 값2, ... };</p>
<p>enum days1 { MON, TUE, WED, THU, FRI, SAT, SUN };
enum days3 { MON=1, TUE=2, WED=3, THU=4, FRI=5, SAT=6, SUN=7 };</p>
<p>이건 int형 배열로 편의를 위해 만들어진 자료형인데, 이 안에는 정수들만 들어간다.
(문자열로 생각할 수 있는데 큰따옴표나 작은따옴표가 안들어감 enum은 들어가있는것들에 순서대로 0번부터 숫자를 부여하고 쭉 나열해놓는것과 같다.그리고 나열한 것들의 집합을 변수이름으로 부르는 것과 같음)</p>
<p>효과 : 문법적으로는 딱히 의미없지만 
숫자를 문자처럼 보여줘서 사람입장에서 좀 더 보기 편하게 하기 위함임
숫자를 문자처럼 보여주는게 enum이다.</p>
<p>예시) </p>
<p>#include &lt;stdio.h&gt;</p>
<p>enum days { MON, TUE, WED, THU, FRI, SAT, SUN };     //enum 선언</p>
<p>char * days_name[] = { 
&quot;monday&quot;, &quot;tuesday&quot;, &quot;wednesday&quot;, &quot;thursday&quot;, &quot;friday&quot;,
&quot;saturday&quot;, &quot;sunday&quot; };
                                              //days_name이라는 배열</p>
<p>int main(void) 
{<br>   enum days d;                               //enum 변수 선언</p>
<p>   for(d=MON; d&lt;=SUN; d++)            //enum을 인덱스처럼 사용(숫자처럼사용)
   {
        printf(&quot;%d번째 요일의 이름은 %s입니다\n&quot;, d, days_name[d]);
   }
}</p>
<p>11.typedef</p>
<p>typedef은 새로운 자료형(type)을 정의(define),C의 기본 자료형을 확장시키는 역할
==자료형이라는 이름을 변경하거나 확장시켜준다.(#define의 자료형 버전)</p>
<p>쓰는 이유 : 단순 변수에서는 일괄적 자료형 변경 가능,구조체 변수에선 struct도 생략가능하게됨</p>
<ul>
<li>진짜 이름이 INT가 아니라 새 이름으로 바뀌는 것 </li>
</ul>
<p>예시)
typedef int INT32; 
typedef unsigned int UINT32;</p>
<p>INT32 i; // int i;와 같다.
UINT32 k; // unsigned int k;와 같다.</p>
<p>방법
typedef + 자료형 + 내가 쓰고 싶은 이름 </p>
<p>typedef struct complex {
            double real;
            double imag;
} COMPLEX;</p>
<p>COMPLEX X,Y; </p>
<p>방법
typedef + 자료형 + 내가 쓰고 싶은 이름 
(자료형은 struct 중괄호를 의미, 이름은 중괄호 끝나고 뒤에)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인터랙션 개발에 대하여(19)]]></title>
            <link>https://velog.io/@kiwi_100/%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC19</link>
            <guid>https://velog.io/@kiwi_100/%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC19</guid>
            <pubDate>Thu, 15 Jun 2023 08:04:13 GMT</pubDate>
            <description><![CDATA[<h1 id="내비게이션과-상호작용-구동-기기">내비게이션과 상호작용 구동 기기</h1>
<p>서론
어떤 가상/증강 현실 시스템에서나 가장 근본적이고 필수적인 기반 기술 컴포넌트 중 하나는 바로 사용자가 시뮬레이션 속에서 이동하고 상호작용하는 장치다. 이런 장치는 시스템의 사용성을 극적으로 확장할 뿐만 아니라, 전반적 몰입감에 중요하다고 여겨진다. 이 장에서는 현재 개발되고 있거나 부상 중인 여러 솔루션과 함께, 이런 하드웨어 컴포넌트 하나가 이 산업의 미래를 결정할 수 있는 이유는 과연 무엇인지 알아보자. </p>
<p>1.2D와 3D의 상호작용과 내비게이션 </p>
<p>상호작용형 몰입 가상 현실 애플리케이션은 모델/데이터 상호작용과 내비게이션 혹은 이 둘을 위해 보통 사용자 입력이 가능한 수단이 필요하다. 특수 시스템은 차치하더라도 마우스, 터치패드, 기본적 게임 컨트롤러 같은 표준의 2D 기기는 애플리케이션의 기능 및 유틸리티가 2D 평면에 있거나 해석되지 않는한, 그 용도가 제한적이다. 예를 들어 시점이 일반적으로 Z축(상하)을 따라 제한되는 건축물 안내나 게임 애플리케이션은 2D 입력 기기 사용이 적절하며 이상적인 솔루션일 수 있다. 하지만 일단 Z축을 따르는 사용자 운동을 비행 관련 애플리케이션 등에서 활성화하면, 내비게이션이 방해받거나 불가능하거나 상당히 덜 직관적이 될 수 있다. </p>
<p>분명히 말하자면, 모든 2D 인터페이스가 수동 기기로 되는 것은 아니다. 그림 12.1 처럼 몰입형 디스플레이 솔루션과 결합한 다양한 설정의 러닝 머신이 연구 기관, 대형 건축 회사, 시뮬레이션 및 훈련 애플리케이션에서 폭넓게 사용되고 있다. 대부분의 시스템은 시점을 XY 면을 따라서만 옮기게 돼 있지만, 일부 특수 시스템은 비스듬한 면을 활용해 옮길 수도 있다. 러닝 머신 기반의 시스템 대부분은 한결같이, 발의 움직임 트래킹에 사용하는 기술과는 완전히 독립적으로 사용자의 머리 움직임을 어떻게든  6자유도dOF에 걸쳐 추적한다. 따라서 사용자는 러닝 머신에서 한 방향으로 걸어가면서도 현실 세계에서 움직이는 것과 마찬가지로 머리를 위,아래,옆으로 돌릴 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/01eb7197-1656-413c-a25c-f2d09fd9283e/image.jpg" alt=""></p>
<p>그림 12.1 몰입형 가상 현실 애플리케이션에서 참여자의 시점을 XY 면을 따라 옮길 때 사용하는 러닝 머신 시스템의 세 가지 사례 이미지, 각각 일리노이 어바나 샴페인 대학의 벡맨 일리노이 시뮬레이터 연구소(Beckman Institute linois Simulator Lab)에 있는 컴퓨터 지원 가상환경(CAVE) 디스플레이의 표준 러닝 머신(왼쪽), 버추익스(Virtuix)의 무지향성 러닝 머신(중앙), 그리고 옴니피니티(오른쪽)의 무지향성 러닝 머신이다. </p>
<p>출처: 이미지 제공 - 일리노이 시뮬레이터 연구소(일리노이 대학), 위키미디어 Czar CC 2.0 라이선스 의거 게재, 존 슈미츠 </p>
<p>2.수동 인터페이스의 중요성</p>
<p>1장, ‘컴퓨터로 만든 세계&#39;에서 설명한 대로, 현재 가상 현실이라는 타이틀을 달고 있는 몰입형 시각화에는 다양한 시나리오가 있다. 여기에는 참여자가 단지 &#39;구경만 하며&#39; 동영상이 재생되는 동안 머리를 돌리는 정도로만 행동이 제한되는 3D 시뮬레이 션이나 360도 동영상 재생, 아니면 여러 개개인의 군중이 한 사람이 내비게이션하는 CAVE 디스플레이에 들어가는 경우, 헤드마운트 디스플레이를 사용하는 개인이나 여러 사용자의 인터랙티브 경험까지 다양한 것이 가능하다. 시나리오에 따라 컴퓨터로 생성한 공간이나 모델 안에 있는 것 같은 강력한 시각적 존재감을 제공할 수 있지만, 시뮬레이션 속 물체의 일인칭 내비게이션과 직접 상호작용을 허용하는 시스템은 가장 참여적이고 설득력이 있으며, 가장 몰입감이 큰 편이다. 어떤 식이든 촉각과 포스 피드백이 제공될 때 특히 그렇[몬로이(Monroy) 등 2008; 케차바르지(Kechavarzi) 등 2012; 멕클 로인(McGloin) 등 2013]. </p>
<p>그래서 HTC 바이브 같이 카메라를 통합한 특수 애플리케이션이나 시스템 외에는 완전히 눈을 가리는 헤드마운트 디스플레이를 착용하면 사용자가 현실 환경을 시각적으로 참조할 수 없다는 점을 기억해야 한다. 키보드, 마우스, 트랙볼, 게임 컨트롤러 등 어떤 것도 볼 수 없다. 따라서 애플리케이션에서 반드시 사용해야 하는 어떤 입력 기기든 직관적이고 조작이 쉬워야 한다. 물리학자이자 작가며 예전에는 아타리 게임을 디자인했던 크리스 크로포드는 1984년에 출간된 저서인『The Art of Computer Game Design』에서 이 요건을 통찰력 있게 설명한다. </p>
<p>“배트를 주고 야구의 목표는 공을 치는 것이라고 말해주면, 그 게임의 목표를 이루기 위해 배트를 공 쪽으로 휘둘러야 한다고 판단하는 데 어려움을 겪는 이는 거의 없을 것이다. 하지만 컴퓨터 야구 게임은 규칙을 알아내기가 그리 쉽지 않다. 배트를 휘두르려면 H를 눌러야 하나? 아니면 S를? 아니면 B를? 혹은 START 키를 눌러야 하나? 조이스틱이라면 트리거를 눌러야 하나? 컨트롤 설명이 없다면 목표는 불분명해 진다.”[크로포드, 1984] </p>
<p>크로포드의 이 비유가 몰입형 가상 현실 애플리케이션에 대한 것은 아니지만, 이 말은 이 분야의 수동 인터페이스나 컨트롤러 디자이너가 직면한 과제의 복잡도를 분명히 알려준다. 어느 정도의 크기와 형태가 적절한가? 버튼과 트리거는 어디에 둬야 좋은가? 무게는 어느 정도가 적당한가? 어떤 촉각과 포스 피드백 단서를 통합해야 할까? 버튼과 트리거는 아이콘으로 표시해야 할까? (VR의 가장 큰 사용자 기반이 될) 일반 엔터테인먼트 애플리케이션용으로 설계된 기기가 건축가나 엔지니어에게도 효과적인 솔루션 역할을 할 수 있을까?
이 장에서는 특히 이 분야용으로 나온 다양한 입력 기기와 대안적 용도로 개발됐지만 이 영역에서 일반적으로 적용 가능성을 찾고 있는 몇 가지를 알아보겠다. </p>
<p>다른 장에서의 제품 설명처럼, 모든 상용 솔루션을 하나하나 다루는 것은 실용적이지 않다. 그런만큼 다음에 언급하는 특정 제품과 기능적 방법론은 특정 기기 카테고리를 대표하는 것으로 이해하길 바란다. 공급 업체의 상세한 목록은 이 책의 부록 B, &#39;자료&#39;에 있다.
마지막으로, 논리적으로 이 장에 포함돼야할 여러 기기 중 이미 다른 장에서 핵심 실행 센서 기술을 설명하며 상세히 설명한 것도 있다. 적외선과 스테레오 카메라로 손의 움직임을 추적하는 리프 모션 기기, 구조광 필드와 전파 시간 측정으로 사용자 트래킹 및 상호작용 등이 가능한 마이크로소프트 키넥트센서군이 그렇다. 이런 기기를 어디에서 설명했는지는 이 장에서 적절한 부분에 넣어뒀다. </p>
<p>3.손과 제스처 트래킹 </p>
<p>자신을 위해 완전 몰입형 헤드마운트 디스플레이 기반의 가상 현실 시스템을 사용하는 것 말고, 처음 사용하는 다른 사람의 반응을 자세히 관찰하는 것도 재미있는 경험이다. 흔히 새로운 사용자는 한 손이나 두 손을 모두 들고, 보고 있는 가상 물체를 쥐거나 다른 식으로 상호작용하려는 행동을 보이는 경우가 많다. 이것은 현실 세계에서 물체에 접근해 손으로 만져보고 상호작용하려는 것과 마찬가지로 본능적인 반응이다. 수동 인터페이스는 &#39;불신의 유예suspended disbelief&#39;라는 전반적 목표에 매우 중요하기 때문에 마이크로소프트와 소니에서 제조하는 게임 컨트롤러처럼 실제 이 분야에 참여하는 회사가 궁극적으로 시장을 지배하는 일종의 &#39;킹 메이커&#39;이자 핵심 결정 요인일 수 있다. 다행히 가상 및 증강 현실의 폭넓은 응용 영역을 감안할 때, 공략할 수 있는 시장 점유율은 방대하다. </p>
<p>그럼 가상 환경과 그 안의 물체와 가장 자연스러우면서 직관적인 상호작용 수단이 되는 입력 기기부터 살펴보자. </p>
<p>글러브 </p>
<p>가상 현실/증강 현실 산업의 초창기부터 가상 환경에서 상호작용하고 내비게이션에 사용하는 주요(그리고 선호하는 인터페이스는 물리적 세계와의 가장 자연스러운 상 호작용 수단인 손의 힘, 기민함, 동작 범위, 정확도를 활용하는 기본적인 장갑을 기반으로 한 것이다. 수년간 한두 가지 측면에서 성공한 수십 가지가 생산됐지만, 특히 캘리포니아 산호세의 사이버글러브 시스템 주식회사는 이 업계의 부침을 조심스럽게 헤쳐나가며 계속해서 포춘지 선정 500대/글로벌 500대 기업으로 자리매김했고 전 세계의 정부 기관과 대학에서 폭넓게 사용하는 고품질의 정밀 기기를 생산하고 있다. 그림 12.2가 그런 기기 중 하나다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/f4f48383-b13e-433a-9abc-3020a3732c60/image.jpg" alt=""></p>
<p>그림 12.2 무선 사이버글러브 III 모션 캡처 데이터 글러브는 22개까지의 정확도 높은 관절 각도센서로 손과 손가락의 동작을 정확한 실시간 디지털 관절 각도 데이터로 변환한다.
출처: 사진 제공 사이버글러브 시스템 LLC </p>
<p>사이버글러브 III
사이버글러브 II는 사용자의 손가락과 손의 움직임을 정확히 정량화하고, 제어 소프 트웨어와 함께 이 움직임을 가상 환경이나 컴퓨터 화면 속 환경에서 손의 그래픽 재 현으로 매핑하는 무선의 손 중심 3D 모션 캡처 기기다. 사용자는 물리적 개체처럼 디지털 개체에 &#39;손을 뻗어 조작&#39;할 수 있다[CGS, 2015]. </p>
<p>모델에 따라 사이버글러브 II는 기기의 서로 다른 지점 18~22개에 걸쳐 독자적으로 저항하는 구부러짐 감지 기술로 정확도 높은 관절 각도 측정이 가능하다. 각 손가락의 구부러짐 센서, 외전 센서, 엄지손가락 교차, 손바닥 아치 등을 측정하는 센서가 있으며, 기본 장갑 자체는 신축성 있는 섬유와 환풍이 잘되는 메시 재질의 손바닥으로 구성된다. 센서 데이터 비율은 100레코드/초(SD 카드)부터 120레코드/초(USB, 와이파이)에 이른다. 무선 데이터 전송은 802.11g 와이파이로 가능하다. </p>
<p>그림 12.2의 기본 형태에서 이 기기는 촉각이나 포스 피드백 단서를 제공하지 않는다는 점을 강조하겠다. 그런 성능은 애드온 시스템으로 가능하다. </p>
<p>그런 제품 중 하나가 10장, &#39;촉각과 포스 피드백 기기&#39;에서 상세히 설명한 사이버그래스 힘 반영 외골격이다. </p>
<p>사용자의 손 운동을 3D 공간에서 트래킹해야 하는 애플리케이션에서 글러브는 11 장, &#39;위치, 방향, 동작 트래킹센서&#39;에서 상세히 설명한 트래킹 기술 중 하나와 페어링 돼야 한다. </p>
<p>페레그린 USB 글러브</p>
<p>소비자용으로 그림 12.3의 페레그린 USB 글러브Peregrine USB Glove는 가상 및 증강 현실 산업용으로 비용 대비 효과가 높은 자연스러운 인터페이스로 상당히 유망하다. 앨버 타 로이드민스터의 아이언 윌 이노베이션스가 개발했고, 원래 &lt;마인크래프트&gt; 등 과제 중심 실시간 전략RTS 게임의 &#39;웨어러블 키보드&#39;로 개발된 페레그린은 가상 현실 게임 커뮤니티에서 새로운 사용자군을 찾고 있다. </p>
<p>내구성과 신축성이 있고, 세탁할 수도 있는 스판덱스와 나일론 메시로 만든 이 장갑에는 손바닥 전체에 하나, 엄지에 두 개, 이렇게 총 세 개의 전도성 컨택트 패드가 있다. 또한 손가락 안쪽에 걸쳐 접점이 18개 있다(검지와 셋째, 넷째 손가락에 각각 다섯 개, 약지에 세 개). 컨택트 패드의 손가락 지점 18개 중 어디든 접촉하면 고유의 제어 신호를 게임이나 기타 애플리케이션에 전송한다. 제어 소프트웨어로 사용자는 제스처만을 기반으로 직접 프로그래밍할 수 있는 액션 30개 이상을 커스터마이징하고 보정할 수 있어서 고유한 터치 조합이 이뤄진다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/81cf30ad-8e44-4e32-b4b7-3a95221d902c/image.jpg" alt=""></p>
<p>그림 12.3 페레그린 USB 글러브는 기기의 손가락과 손바닥에 분포된 전도성 컨택트 패드 및 접점을 이용해서 제스처 를 일반 컴퓨터와 소프트웨어 애플리케이션 명령문으로 바꾼다.
출처 : 이미지 제공 - 아이언 윌 이노베이션 캐나다 주식회사 </p>
<p>페레그린은 장갑뒤에 탑재된 탈착식 자기 팟에 붙이는 USB로 컴퓨터에 연결된다. 동작과 몸짓이 케이블 길이를 넘으면 탈착식 팟이 그냥 빠져서 글러브와 센서 손상이 방지된다. </p>
<p>다시 한 번 말하지만, 이 기기는 어떤 형태든 촉각이나 포스 피드백 단서를 제공하지 않는다. 사용자의 손 움직임을 3D 공간에서 트래킹해야 하는 애플리케이션이라면 장갑을 11장에서 자세히 다룬 트래킹 기술 중 하나와 페어링해서 써야 한다.</p>
<p>듀얼 완드/페어링 컨트롤러</p>
<p>간단한 실험을 하나 해보자. 한 손을 바지 주머니에 넣고 하루를 지내는 것이다. 짜증이 나서 실험을 포기하기까지 얼마나 버틸 수 있는지 확인해보자. 가상 현실 시스템을 매우 빈번히, 혹은 수동 조작이 필요한 채로 사용할 때도 마찬가지 개념이 적용된다. 우리 손이 두 개인 데는 이유가 있다. 듀얼 완드/페어링 컨트롤러는 우리 주위의 정보 수집 대역폭을 늘려주고, 기능성과 기민함도 크며, 과제도 더 쉽게 완료할 수 있게 해준다. 그럼 몰입형 가상 환경에서 상호작용과 내비게이션을 돕기 위해 설계된 다양한 듀얼 완드와 페어링 컨트롤러를 알아보자. </p>
<p>HTC 바이브 스팀VR 컨트롤러 </p>
<p>특히 HTC 바이브 가상 현실 시스템에서 사용하도록 설계된 그림 12.4의 바이브 컨트롤러는 질감이 있는 둥근 터치패드, 집게손가락 아래의 듀얼 스테이지 트리거, 두 개의 그립 버튼과 시스템 및 메뉴 버튼이 통합된 균형 잡힌 인체공학적 디자인이다. 미학적으로도 매력적인 컨트롤러 헤드의 도넛 형태는 기기의 위치와 방향을 트래킹하는 센서를 분리할 때 필요하다. 컨트롤러는 마이크로USB 케이블로 충전하는 일체 형 리튬 폴리머 배터리를 사용하며, 한 번 충전으로 수시간 사용할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/08563ba9-ffa3-42cb-adee-05b1dc9153f0/image.jpg" alt=""></p>
<p>그림 12.4 HTC 바이브/스팀 VR 컨트롤러는 가상 현실 시뮬레이션에서 유연하고 다재다능한 상호작용과 내비게이션 을 실행하기 위해 설계된 첨단 3D 입력 기기다.
출처: 사진 제공 HTC </p>
<p>이 컨트롤러의 위치와 방향은 11장에서 설명한 HTC 바이브 헤드마운트 디스플레이처럼, 내부 MEM 센서와 함께 라이트하우스 3D 공간 레이저 트래킹 기술을 활용해 모니터링한다. 인터페이스 컨트롤과 내부 센서에서 나온 데이터는 무선 송신기를 통해, 호스트 컴퓨터가 유발할 수 있는 간섭 노이즈에서 분리돼 바이브 헤드마운트 디스플레이 수신기로 전송된다. 가벼운 햅틱 효과는 진동 촉감 단서로 제공된다. </p>
<p>오큘러스 터치</p>
<p>지금까지 개발된 가장 혁신적 사용자 인터페이스인 오큘러스 터치는 원래 오큘러스 리프트 가상 현실 시스템용으로 개발된 한 쌍의 핸드헬드 무선 컨트롤러다. 터치 컨트롤러는 산업 디자이너가 제품으로 줄 수 있는 영향력에 대한 좋은 사례기도 한데, 이 장의 앞에서 언급한 필수적인 기능 중 상당수를 구현했다. 기기는 손에 편안하게 쥐어지며, 단 몇 초면 작동 방식을 파악할 수 있다. 그림 12.5처럼, 각 유닛은 검지에 잘 맞게 배치된 트리거 하나, 중지에 두 번째 트리거, 완벽히 배치된 아날로그 엄지 스틱과 라벨이 잘 보이는 두 개의 버튼으로 이뤄져 있다. 기기의 전체적인 모양은 사용자의 손가락에 걸리적거리지 않으면서 쥐기, 가리키기, 흔들기 같이 자연스러운 제 스처가 가능하게 돼 있다. 정전식 표면과 기기의 다른 부분은 시스템이 이런 손의 포즈를 인식하도록 도와줘서 추가적인 콘트롤도 가능하다. </p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/4b7185c2-77af-49ee-9bd8-5f0eecee568a/image.jpg" alt=""></p>
<p>그림 12.5 오큘러스 터치 컨트롤러는 위치와 방향 트래킹을 돕는 IR LED 등 다양한 센서와 함께 가리키기, 흔들기 같은 자연스러운 손 포즈를 추적하는 정전식 컨트롤 표면을 활용한다.
출처: 이미지 제공 - 플리커 에브리데이VR </p>
<p>이런 컨트롤러의 포지션 및 방향은 각 기기 주변에 배치된 IR LED 위치를 모니터링 하는 적외선 카메라인 오큘러스 컨스텔레이션 트래킹 기술로 모니터링된다. 사용자의 손가락이 버튼을 터치하는지, 혹은 특정 위치에 있는지 감지하는 인터페이스 컨트롤과 내부 센서에서 나온 데이터는 무선 전송기를 통해, PC가 생성할 수 있는 간섭 노이즈에서 분리된 오큘러스 헤드마운트 디스플레이 수신기에 전송된다. </p>
<p>오큘러스 터치 컨트롤러는 진동 촉감 단서를 통해 햅틱 피드백을 제공하는데, 주파수와 진폭 모두 가변적이어서 애플리케이션 개발자가 직접 관찰하거나 사용자가 개시한 이벤트에 맞는 촉각 감각을 만들때 상당한 자유와 창의성을 누릴 수 있다. </p>
<p>소니 플레이스테이션 무브 VR 컨트롤러 </p>
<p>여러 해 동안 소니 플레이스테이션 라인의 토대가 된 그림 12.6의 무브 VR 컨트롤러는 이 장에서 다룬 다른 제품보다 미적으로나 인체공학적으로도 뒤처지고, 거친 사용자 환경을 고려해 만들어지기도 했지만 과제 수행 면에서는 독보적이다. 무브 컨트롤 러에는 각각 입력 버튼이 아홉 개 있는데, 컨트롤 버튼 네 개(ㅇ, ㅁ, △, X), 측면의 스타트와 선택 버튼, 표준 PS 버튼, 트리거 버튼, 커다란 무브 버튼이 있다. 이 컨트롤러는 특히 상단의 조명 볼(위치 추적에 사용)의 색이 실제 사용 중에 변하는 기능이 참신하다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/b903e276-f6c2-4902-b948-2251a26ee89c/image.jpg" alt=""></p>
<p>그림 12.6 소니 PS 무브 컨트롤러는 3D 공간에서 사용자 손의 빠르고도 미묘한 움직임을 트래킹한다. 
출처: 이미지 제공-에반스 아모스 </p>
<p>내장된 리튬이온 충전배터리는 완충 시 작동 시간이 10시간이다. 이 컨트롤러의 포지션은 소니 플레이스테이션 카메라로 모니터링한다(사실 뎁스 비전을 위한 스테레오 카메라가 포함돼 있다). 기기의 방향은 내부 MEM 자이로스코프, 가속계, 3축 나침반으로 트래킹하며, 빠른 움직임과 미묘한 움직임을 모두 측정한다. 이 센서에서 나온 정보는 블루투스 송신기로 플레이스테이션 베이스 유닛에 전달된다. </p>
<p>플레이스테이션 무브 VR 컨트롤러는 진동 촉감 단서나 시스템 사용자가 럼블링이라고 부르는 떨림으로 햅틱 피드백을 제공한다. </p>
<p>4.몸 전체 트래킹 </p>
<p>몸 전체의 역동적 움직임을 추적해야 하는 몰입형 가상 현실 애플리케이션 시나리오도 매우 많다. 놀라운 예로는 경찰이나 군대가 방 진입 작전과 저격수를 다루는 상황을 위한 필수 기술을 개발할 때 이런 기술을 사용하는 것이다. 몰입형 훈련 시나리오 동안 참여자 몸의 여러 지점과 무기의 움직임을 트래킹함으로써 세부적인 사후 활동 분석을 하고, 문제를 확인하며, 기술을 가다듬을 수 있다. 그림 12.7은 그런 구현을 보여준다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/f8d4a3db-2ff4-4e1f-9c76-07caf0068fb9/image.jpg" alt=""></p>
<p>그림 12.7 동부전선 1군단 157 보병대 군인이 보병 훈련 시스템(DSTS, Dismounted Soldier Training System)을 활용 하고 있다. 비록 이 시스템은 훈련을 대체하지 못하지만, 시나리오를 변경하고 반복할 수 있기에 연습을 보강해주며 개
인과 팀 단위의 동작 등을 분석해준다. 
출처: 미 국방부 제공 사진</p>
<p>이런 세부 동작 연구에서 활용하는 방법은 모션 캡처MOCAP 기술 카테고리에 속하는 데, 광학적과 비광학적 두 가지 유형으로 구분된다. </p>
<p>퍼셉션 뉴런 </p>
<p>새로운 관성 트래킹 기술의 출현으로 광학 MOCAP 솔루션보다 상당히 저렴한 대안의 문이 열렸다. 그중 하나가 중국 베이징의 노이톰 주식회사가 제조한 퍼셉션 뉴런 Perception Neuron이다. 그림 12.8처럼, 퍼셉션 뉴런시스템은 뉴런이라는 허브에 연결되는 각각 1cm×1cm 크기의 상호 호환 가능한 모션센서 기반이다. 뉴런에는 자이로 스코프, 가속계, 자력계로 구성된 관성 측정 유닛IMU이 들어있다. 이 시스템이 영리한 점은 모든 뉴런이 상호 호환 가능하므로 필요한 어떤 곳에는 배치해 무한대의 조합을 만들어낼 수 있다는 점인데 손, 몸의 특정 부분, 액세서리에 이르기까지 배치해 섬세 한 움직임을 측정할 수 있다. 하나의 허브에는 1~30개의 뉴런을 연결할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/6b63a981-bcfe-4cc8-8888-7ecc01e940c9/image.jpg" alt=""></p>
<p>그림 12.8 퍼셉션 뉴런 모션 캡처 시스템은 32개까지 상호 호환 가능한 개별 센서로 사용자의 몸과 사지를 트래킹한다.
출처: 사진 제공 노이톰 주식회사 </p>
<p>퍼셉션 뉴런시스템은 와이파이를 통한 무선이나 내장 레코딩 온보드 녹음으로, 혹은 USB를 이용해 유선으로도 작동할 수 있어서 완벽하게 유연한 사용성을 자랑한다. 이 시스템의 여러 가지 변형으로는 18~32개의 개별 뉴런 센서까지 출시돼 있다. 또한 이미 상당히 매끄럽게 오큘러스와 HTC 바이브 양쪽의 VR 시스템에서 작동하며 마야, 3ds 맥스, 유니티, 언리얼 등 여러 소프트웨어 솔루션과도 잘 작동함이 폭넓게 입증됐다. </p>
<p>5.게임, 엔터테인먼트 인터페이스 </p>
<p>삼성 기어VR처럼 스마트폰 기반 헤드마운트 디스플레이와 함께 사용하는 상용 게임 컨트롤러는 이미 널리 사용되고 있다. 이 사용 시나리오에서는 이런 종류의 여러 블루투스 컨트롤러가 갤럭시 S7, S6, S6 엣지, S6 엣지플러스, 노트 4, 5 같은 안드로이드 기반 삼성 모바일 기기와 연결되긴 하지만, 특정 기기의 정확한 기능에 따라 컨트롤 설계를 다시 매핑해야 할 수도 있다. 그런 설정을 위한 다양한 도움말은 인터넷에서 찾을 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/7b4359fe-f941-43bd-af73-3bf025680a8d/image.jpg" alt=""></p>
<p>그림 12.9 엑스박스 원 게임패드는 오큘러스 리프트 헤드마운트 디스플레이의 소비자 버전에 번들로 판매된 최초의 수동 컨트롤러다.
출처: 플리커에 실린 바고게임즈의 이미지. CC 2.0 라이선스에 의거 수록 </p>
<p>오큘러스 개발자 킷 1과 2 같은 기기의 상용 출시와 함께 개발된 최초의 몰입형 게임 애플리케이션으로는 운전 시뮬레이터가 있다. 이 특정 애플리케이션 시나리오에 사용하는 최고 사양의 게임 운전대 중 일부는 스위스 로망쉬르모르쥬의 로지텍 인터내 셔널이 생산한다. 
그림 12.10은 그중 하나인 G29 드라이빙 포스 레이신 휠과 변속기다. 여기서 특히 주목할 점은 9장, &#39;감각의 구조&#39;에서 설명한 고해상도의 촉각과 포스 피드백 단서의 광범위한 적용이다. 주변 기기는 다양한 게임 콘솔 및 윈도우 기반 PC 와 호환 가능하다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/139a2913-a623-4533-87f0-28e6f2ad5c28/image.jpg" alt=""></p>
<p>그림 12.10 로지텍 G29 드라이빙 포스 레이싱 휠은 오큘러스와 페어링해 상당히 몰입감 있는 운전 시뮬레이션 경험을 전달하는 시뮬레이터 등급의 헬리컬(톱니) 기어 포스 피드백 입력 기기다.
출처: 이미지 제공 - 로지텍 </p>
<p>6.머리로 하는 내비게이션 </p>
<p>사람의 뇌는 특히 매혹적이며 복잡한 장기다. 혈관 길이는 16만 킬로미터에 달하고 [터킹턴(Turkington) 1996] 뉴론 개수는 1,000억 개로 추정되며, 각각 시냅스가 1,000에서 10,000개 사이대처들러(Chudler) 2011]. 그리고 메모리 저장 용량은 2.5페타바이트 범위 로 추정된다(페타바이트는 100만 기가바이트, 1,000테라바이트다)[레버(Reber) 2010]. IBM 의 뇌 구조 컴퓨팅brain-inspired computing 대표 연구원인 다르멘드라 S. 모다는 보수적으로 인간 두뇌가 38페타플롭의 연산력이 있다고 추산한다(페타플롭은 초당 1,000조 회 의 연산력이다)[그리네마이어(Greenemeier) 2009]. 게다가 이런 엄청난 능력이 75%가 물로 이뤄진 약 1.3킬로그램의 젤라틴 덩어리에 들어있는 것이다[후안(Juan) 2006].</p>
<p>우리 존재의 매 순간 드러나는 이 놀라운 기능적 역량을 상상하는 SF 작품 속의 직접적인 두뇌-기계 인터페이스BMI 사례는 터무니없는 것이 아니다. 인간과 기계 간의 경계를 완전히 제거하기란 가까운 미래에는 거의 불가능하겠지만, 그 선은 분명 흐릿해지고 있다. 지난 10년간 상당한 진보가 이뤄져서 간접적, 비간섭적 방법을 사용한 사람의 인지와 감각 운동 기능의 지원, 복구, 증강을 주목표로, 사람의 두뇌와 복잡한 정보 시스템 간의 직접 커뮤니케이션 경로가 만들어졌다. </p>
<p>이런 노력 뒤에 숨은 동력이 증강 및 가상 현실 인터페이스 그 자체에 집중된 것은 아니지만, 이 분야가 이런 발전과 그로 인한 제품을 활용하는 것만은 분명하다. </p>
<p>그런 기기 중 하나는 캘리포니아 샌프란시스코의 바이오 정보과학 회사 이모티브 주식회사가 개발한 에포크 멀티채널 EEG(뇌파도) 측정 시스템이다. 그림 12.11처럼 기기는 개별 센서 14개(그리고 두 개의 참조/측위 센서)가 있는데, 뇌의 전자 신호를 측정한다. 처음에는 사용자가 동작 기반의 행동을 생각하는 동시에 두뇌 활동을 기록하고 분석해 시스템을 &#39;훈련&#39;시킨다. 그러다보면 시스템은 뚜렷한 사고들 간의 차이를 구분할 수 있다. 이어서 이런 감지를 어떤 컴퓨팅 플랫폼이나 애플리케이션에도 할당하고 매핑할 수 있는데[레(Le) 2010], 주의와 명상 데이터의 높은 변동성과 이상성 때문에 아직은 해결해야 할 여러 과제가 남아있다 마스켈리우나스(Maskeliunas) 등 2016].</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/8b33fbe2-5a50-48f0-9fca-a2a0cc332f15/image.jpg" alt=""></p>
<p>그림 12.11 에포크 헤드셋은 고해상도와 멀티채널을 지원하는 휴대 가능한 EEG 시스템으로, 사용자가 생각만으로 몰입형 가상 환경을 내비게이션할 수 있다.
출처: 플리커에 실린 브루노 코르디올리와 보우노우즈의 이미지. CC 2.0 라이선스에 의거 수록</p>
<p>대중 시장용 제품 개발을 가능하게 해준 혁신은 수학적으로 사용자 두뇌의 대뇌피질 주름을 펴서, 주름 패턴이 지문처럼 개인마다 고유함에도 불구하고 신호 매핑을 실제 출처에 가깝게 하는 알고리즘이 개발되면서 이뤄졌다[레(Le) 2010].</p>
<p>이 기기는 이미 여러 몰입형 가상 현실과 로봇공학 애플리케이션의 인터페이스로 전 세계에서 폭넓게 사용중이다.</p>
<p>7.결론
입력 기기, 컨트롤러, 기타 사용자 입력이 가능한 수단은 몰입형 가상 현실 시스템과 애플리케이션 대부분에서 핵심적인 컴포넌트다. 센서로 가득한 장갑, 반지, 완드 같은 수동 인터페이스, 수많은 게임 인터페이스부터 모션 캡처 시스템, 무지향성 러닝 머신, EEG 활동이나 시선 트래킹 기기까지, 이 도구는 컴퓨터가 생성한 환경 내의 이동과 상호작용에 필수적이다.</p>
<p>몰입형 가상 현실 시스템의 다양한 애플리케이션 영역역시 방대하고 다양한 입력 기기를 선택해야 한다. 예를 들어 새로운 우주 정거장 모듈 설계를 평가하는 엔지니어라면 게임 팬이나 미묘한 복강경 기법을 시술하는 의사와는 완전히 다른 도구가 필요 하다. 이런 이유로 실제 애플리케이션, 콘텐츠와 더불어 상호작용과 내비게이션이 가능한 기기는 이 업계에서 가장 역동적이고 변화무쌍한 측면이 될 것이다.</p>
<pre><code>                                                    출처 - 실전 증강 현실(스티븐 옥스타칼니스 지음)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[인터랙션 개발에 대하여(18)]]></title>
            <link>https://velog.io/@kiwi_100/%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC18</link>
            <guid>https://velog.io/@kiwi_100/%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC18</guid>
            <pubDate>Thu, 15 Jun 2023 07:26:41 GMT</pubDate>
            <description><![CDATA[<h1 id="위치-방향-동작-추적용-센서">위치, 방향, 동작 추적용 센서</h1>
<p>서론
디스플레이나 입력 기기의 위치와 방향의 트래킹부터 물리적 입력과 트리거하고자 하는 명령이나 액션의 방향과 강도 모니터링까지, 가상 및 증강 현실 시스템은 광범위하게 센서를 활용한다. 이 장에서는 작동 모드와 각각의 장단점을 위주로 다양한 핵심 센서 기술을 알아 보자. </p>
<p>1.센서 기술 소개
센서는 모든 가상 및 증강 현실 시스템의 핵심 실행 기술이다. 참여자의 위치, 사용자 의 머리(그리고 헤드마운트 조회 기기)와 손(혹은 수동 인터페이스)의 포지션 및 방향을 3D 공간에서 트레킹하는 데는 센서가 사용된다. 어떤 장면을 그릴지, 가상 환경 및 그 안의 물체와 상호작용한 결과로 어떤 이벤트를 트리거할지 파악할 수 있도록 센서 는 컴퓨터 시스템에 어디를 보고 있는지 알려준다. 센서는 가상공간과 그 콘텐츠 안 에 있다는 느낌이나 상호작용을 전달하는 데 절대적으로 중요하다. </p>
<p>이 장에서는 사용자의 포지션(X, Y, Z)과 방향(롤, 피치, 요)을 트래킹하는 다양한 센서 기술과 현재 가상 및 증강 현실 시스템에 가장 흔히 활용되는 입출력 기기를 알아본 다. 이런 솔루션은 광학, 전자기, 관성, 음향 방법론을 기준으로 하위 카테고리로 나눌 수 있는데, 각각 강점과 한계가 있다. 예를 들어 직접적인 선 연결이나 기계적 연결을 요구하는 것도 있지만, 송신기와 수신기 사이를 가리는 것이 없어야 하는 것도 있고, 또한 환경 소음, 자연광 혹은 작동 범위 안에 전도체가 있으면 영향을 받는 것도 있다. 솔루션마다 정확도와 시스템 지연(이동과 반응 사이의 시간 간격)도 다양하다. </p>
<p>2.광학 트래커</p>
<p>광학 트래킹은 일반적으로 카메라로 물체의 이동을 모니터링하는 다양한 기법을 가리킨다. 이 기법은 사람이나 물체가 이동할 때 액티브와 패시브 적외선 마커를 추적하는 단일 혹은 복수 카메라 시스템부터, 송신기에서 전송된 빛이 물체에 반사된 후 수신기에 도달하는 데 필요한 시간을 측정하는 단일 카메라 시스템, 적외선을 알려진 패턴으로 투사한 후 그 패턴의 왜곡을 기반으로 운동을 계산하는 시스템까지 다양하다. 편의상 현재 가상 및 증강 현실 분야에서 활용하는 가장 흔한 광학 솔루션인 멀티 카메라 시스템부터 시작해보자. </p>
<p>멀티카메라 광학 트래킹
멀티카메라 광학 트래커는 적외선 역반사체(패시브 마커)나 적외선 LED(액티브 마커)가 정렬돼, 개인이나 물체의 운동을 측정한다는 기본 원칙하에 작동한다. 위치와 방향의 변화는 삼각 측량법으로 추출한다. 그림 11.1은 기본적인 멀티카메라 구현을 묘사한다. 각 카메라마다 근거리 적외선 LED를 렌즈 주위에 배열한다. 이 LED는 측정 영역을 비추며, 트래킹되는 물체의 패시브 마커가 카메라로 빛을 반사한다. 카메라는 보통 광학 대역 투과 필터로 파장이 다른 앰비언트 라이트의 간섭을 제거해, 마커 확인 과정을 안정시킨다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/226ddc8a-738a-4773-b4f0-3718ed629472/image.jpg" alt=""></p>
<p>그림 11.1 트래킹되는 물체에는 유입되는 적외선 빛을 카메라로 다시 반사시키는 역반사 마커가 붙어있다. 출처: 이미지 제공 - 옵티트랙(OptiTrack) </p>
<p>원격 소스에서 조명을 비출 필요는 없지만, 역반사체와 달리 LED가 배열된 물체를 트래킹해야 하는 애플리케이션 역시 본질적으로 같은 방식으로 작동한다. 적외선 트래커가6자유도(6 DOF)에 걸쳐 운동을 트래킹하려면 최소한 동일 직선상이 아닌 리플렉터 세 개나 LED가 필요하다는 점도 알아두자. 그래서 프로세싱 유닛은 고정 카메라 유닛 간의 거리와 함께 마커의 알려진 기하학 설정을 근거로 단순한 삼각 측량 기법을 사용한다. </p>
<p>컴퓨터 기반 가상 환경CAVE처럼 더 몰입적인 애플리케이션은 반구형이든 대형 포맷의 파노라마 디스플레이든, 트래킹 중인 물체나 사람이 항상 여러 유닛에 잡히도록 추가 카메라를 사용해야 한다. 그림 11.2는 이 개념을 묘사한 것이다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/fd998e2a-4164-4e54-882f-28293e27699e/image.jpg" alt=""></p>
<p>그림 11.2 광학 트래킹 시스템은 추가 카메라를 포함해, 사용자의 물리적 위치에 관계없이 여러 대의 카메라가 역반사 마커를 비춰 포착하도록 하는 경우가 많다.
출처: 이미지 제공 - 옵티트랙 </p>
<p>이런 광학 트래킹 솔루션을 사용할 때는 다음 몇 가지를 중요하게 고려해야 한다. </p>
<p>■ 패시브 리플렉터를 트래킹하는 시스템은 연결선을 줄일 수 있다는 장점이 있 지만, 카메라와 컨트롤러를 더해 복잡도가 높아져서 값도 비싸다. 마커를 지오 메트리에 고정해야 하는 경우도 많다.
■ 적외선 LED 어레이를 이용해 물체를 트래킹하도록 설계된 시스템은 덜 비싸 긴 하지만 LED에 전원을 공급해야 한다. 즉 선으로 연결하거나 배터리를 내장 해야 한다는 뜻이다. </p>
<p>일반적으로 적외선 LED와 반사형 마커를 트래킹하는 고정식 카메라 사용은 아웃사 이드 인outside-in 트래킹이라고 한다. </p>
<p>반대로 인사이드 아웃inside-out이라는 트래킹 방식은 사용자 주변에 위치가 고정된 적 외선 발신기를 배치(컴퓨터 모니터, 벽, 천장 등)하고, 헤드마운트 디스플레이에 탑재된 카메라를 통해 발신기의 위치와 방향을 추적한다. 이런 구현의 혁신적 사례로는 이 장의 뒷부분에서 설명할 밸브Valve의 라이트하우스Lighthouse 트래킹 시스템이 있다. </p>
<p>또한 적외선 조명과 LED 사용을 모두 배제하고, 대신 프로세싱 유닛에서 쉽게 인지 할 수 있게 디자인된 스티커형 마커를 사용하는 시스템도 있다. </p>
<p>마지막으로, 즉석에서 변화를 찾아 연속적 이미지를 비교하는 무차별 대입brute force 방
식이 있다.</p>
<p>3.광학 센서
≪마이너리티 리포트≫나 ≪아이언맨&gt; 같은 SF 영화는 사용자가 허공에 손을 뻗어 홀로그램 데이터와 상호작용하고, 그래픽 요소 속을 돌아다니며, CAD 모델을 조정하는 놀라운 컴퓨터 인터페이스 묘사로 청중을 놀라게 했다. 각 영화의 핵심에는 장갑을 비롯해 그 어떤 센서도 착용하지 않고 3D 공간 안에서 사용자 손의 위치와 방향 을 추적하는 기술을 보여준다. 이런 기술은 이제 막 출현하기 시작했고, 가상 및 증강 현실 분야에서 상당한 밝은 전망을 보여주고 있다. </p>
<p>4.리프 모션 컨트롤러
바로 이런 사례가 리프 모션 컨트롤러 Leap Motion Controller로, 캘리포니아 샌프란시스코의 리프 모션Leap Motion에서 개발한 소비자용 광학 센서다. 이 기기는 터치 없이 컴퓨터 시스템을 3D 손 제스처만으로 제어할 수 있도록 설계됐는데, 100분의 1밀리미터 정확도에 가시적 지연이 없다고 한다[리프, 2013]. 그림 11.3처럼, 리프 기기는 와이드 앵글 렌즈가 있는 카메라 두 대와 적외선 LED 세대로 구성된다. 카메라는 적외선을 850나노미터 파장으로 포착하도록 튜닝됐는데, 빛의 가시광선 외 부분이다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/cfa27e71-9382-4756-83db-4fa375d4f800/image.jpg" alt=""></p>
<p>그림 11.3 HP 엔비 17 리프 모션 SE 노트북과 HP 리프 모션 키보드에서 사용하도록 설계된 축소판 센서 모듈과 독립 형 리프 모션 기기의 회로판을 보여주는 이미지
출처: 이미지 제공 - 리프 모션</p>
<p>그림 11.4처럼 책상에 올려놓으면 기기 위로 0.2미터 영역의 상호작용을 커버하는데, 컨트롤러 위로 약 60센티미터, 양쪽으로 60센티미터(약 150도 각도와 같음), 깊이 60 센티미터(약 120도 각도와 같음)다. </p>
<p>이런 작동 영역의 제한은 부분적으로는 역제곱법칙inverse-square law 이라는 기초 물리
학 원리로 결정된다. 조명의 강도는 광원으로부터의 거리의 역제곱에 비례한다고 선언하는 법칙이다. 다시 말해, 빛이 광원에서 멀리로 이동할 때는 수평 수직 방향 모두로 확산되고 그러면서 강도가 줄게 된다. 적외선 파동의 전체적 힘은 같은 상태가 유지되지만, 빛이 광원에서 멀어지며 더 넓은 영역으로 확산되기 때문에 일어나는 현상 이다. 위에서 설명한 범위를 넘어서면, 적외선의 강도는 카메라가 더 이상 안정적으로 사용자의 손 위치를 측정하기에 충분할 만큼 반사된 빛을 받을 수 없는 수준으로 떨어진다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/82b78592-dcd0-435c-8b8d-cad1121029fe/image.jpg" alt=""></p>
<p>그림 11.4 리프 모션 컨트롤러 위로 영향력이 미치는 영역을 나타내는 선 기기 위로 60센티미터, 양쪽으로 60센티미터에 해당한다.
출처: 이미지 제공 - 리프 모션 </p>
<p>리프 모션 기기가 작동하는 배경 원리는 지금까지 설명한 다른 광학 센서와는 상당히 다르다. 사용자의 손이 기기 위의 상호작용 공간을 뚫고 이동할 때, 스테레오 카메라는 호스트 컴퓨터로 스트리밍되는 장면 정보를 수집한다. 이어서 컨트롤 소프트웨어가 카메라가 보는 모습의 3D 재현을 재구성하고 해석하는데, 제스처를 인식해 가상의 물체를 제어할 때 사용하는 트래킹 데이터도 소프트웨어가 생성한다. </p>
<p>처음에는 데스크톱 인터페이스로 설계됐지만, 첫 출시 직후 개발자들은 리프 모션 센서 데이터를 몰입형 가상 현실 애플리케이션의 자연스러운 입력 장치로 사용하는데 필요한 소프트웨어들을 실험하기 시작했다. </p>
<p>그림 11.5처럼 오큘러스, HTC, OSVR 등의 헤드마운트 디스플레이 전면에 탑재하면 스테레오 카메라로 찍은 장면이 사용자의 손목과 팔을 쉽게 포괄하게 된다. </p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/b9d1a3bd-d4b9-4f76-84e4-8ef5818b6782/image.jpg" alt=""></p>
<p>그림 11.5 가운데는 리프 모션 컨트롤러와 오큘러스 리프트의 시야각 비교를 보여준다. 리프의 시야각이 리프트보다 넓기 때문에 사용자의 시야 밖에 있더라도 손 동작을 추적할 수 있다.
출처: 이미지 제공 - 리프 모션 </p>
<p>시스템 카메라에 분명히 잡히지 않은 손가락과 손 포지션을 예측하기 위해, 리프 모션 애플리케이션 프로그래밍 인터페이스API는 정확하게 손과 손가락을 트래킹해주는 광범위한 유틸리티를 제공한다. API를 이용해 개발자는 관절의 포지션과 뼈 길이를 포함한 손의 뼈 위치와 수치 데이터를 추출할 수 있다. 이 기능은 가상의 손이 가상 물체와 상호작용할 수 있도록 하는 핵심이다. </p>
<p>5.마이크로소프트 키넥트 </p>
<p>마이크로소프트의 모션 감지 입력 기기인 키넥트 라인의 핵심에는 또 다른 강력한 광학 트래킹 기술이 있다. 이 기기는 처음 엑스박스 비디오 게임 콘솔의 제스처 인식과 모션 트래킹을 위해 만들어졌지만, 곧 윈도우 PC와 커스텀 시스템에서 사용할 수 있는 하드웨어의 추가 버전이 출시됐다.
키넥트 센서의 초기 버전은 몸의 포지션을 추론하는 다단계 프로세스를 사용했다. 그 림 11.6처럼 이 시스템은 적외선 레이저 프로젝터와 RGB, 적외선 CMOS(상보형 금속 산화 반도체) 카메라로 구성된다. 구조광이라고도 하는 기법을 활용해 장면에 투사된 적외선 점의 패턴을 분석함으로써, 공간적으로 인코딩된 뎁스 맵이 구성된다. 적외선 프로젝터 앞에는 서로 다른 두 직각면에 다른 초점 길이로 특수 비점수차 렌즈가 있으므로, 투영된 이미지가 서로 다른 거리에서 초점이 맞는 수직과 수평면이 생긴다. 따라서 빛의 둥근 점들을 투영해 타원으로 초점을 맞추는데, 그 방향은 렌즈의 심도에 따라 다르다. 이어서 IR 카메라가 수집한 장면을 분석하고, 뎁스 맵을 만들어 동작을 모니터링한다.
마이크 망과 다언어 인식 기능이 있어 메인 컴퓨터시스템을 음성 명령으로 제어할 수도 있다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/02f92228-48e4-4668-b40b-e776ae0112ad/image.jpg" alt=""></p>
<p>그림 11.6 키넥트 기기의 초기 버전에서 뎁스 맵 생성 및 동작 모니터링을 위한 점을 만드는 구조광 사용을 보여주는 이미지
출처: 키넥트 이미지 제공 - 제임스 파프, 점 패턴 이미지 제공 - 제프 워렌 플리커 CC 2.0 라이선스에 의거 게재 </p>
<p>윈도우용 키넥트 같은 좀 더 최근에 등장한 버전은 완전히 다른 각도로 트래킹에 접근한다. 점의 패턴과 기하학을 분석하는 대신, 최신 센서는 전파 시간time-of-flight 이라 는 기술을 활용한다. 간단히 설명하자면, 이 센서는 빛의 포톤이 레이저 프로젝터에서 나와 타깃 표면에 반사된 후 이미지 센서로 돌아오는 데 걸리는 시간을 측정한다.
그림 11.7처럼, 이 신기술 시스템은 액티브 적외선 이미징(직접적 적외선 장면 조명)을 사용하는데, 상당히 더 많은 장면 세부가 있는 뎁스 맵을 생성해 얼굴의 이목구비, 손 과 손가락 포지션, 옷의 접힌 부분, 구겨짐, 주름까지 인식할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/0b498c42-8c96-474f-ae2a-cb1f73604d32/image.jpg" alt=""></p>
<p>그림 11.7 키넥트 기기의 최신 버전과 액티브 적외선 이미징 및 전파 시간 기술을 사용해 생성된 훨씬 상세한 뎁스 맵 을 보여주는 이미지
출처: 키넥트 기기 이미지 제공 -바고게임즈(BagoGames), 스캔 이미지 제공 - 카일 맥도널드, 플리커 CC 2.0 라이 선스에 의거 게재 </p>
<p>소프트웨어 개발자 툴킷이 출시돼 흥미로운 수많은 애플리케이션에 키넥트 기기를 활용할 수 있게 됐는데, 온라인 가상 현실 소셜, 채팅, 게임 커뮤니티인 알트스페이스 VRAltspaceVR 등이 있다. </p>
<p>6.비콘 트래커
비콘 트래킹은 적외선 발신기를 사용자 주위에 전략적으로 배치해 위치와 방향을 모니터링하는 새로운 방법이다. 그런 다음, 물체에 탑재한 적외선 센서가 고정된 적외선 발신기에 대해 상대적인 위치와 방향을 추적한다. 워싱턴 벨뷰의 밸브 코퍼레이션에서 개발한 이 트래킹 기법은 HTC 바이브 가상 현실 시스템에 활용된다. </p>
<p>그림 11.8처럼, 이 구현은 방 안의 두 모서리 윗부분에 설치한 두 개의 &#39;등대&#39; 기지국으로 구성된다. 각 기지국은 동조화된 파동을 발신하는 적외선 비콘과 적외선 레이저를 반사시켜 연속적으로 트래킹 볼륨을 휩쓸고 지나가는 수직, 수평선을 만들어내는 플라이휠 두 개로 구성된다. 동조화된 파동과 함께 레이저광선으로도 기지국에 상대적인 바이브의 헤드셋과 핸드 컨트롤러 센서의 위치 및 방향을 감지할 수 있다. </p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/619a2908-d0fb-4cca-ba60-1d6fd9946bbd/image.jpg" alt=""></p>
<p>그림 11.8 HTC 바이브 시스템이 사용하는 라이트하우스 트래킹 시스템은 헤드셋과 컨트롤러의 센서로 적외선 레이저
광선과 벽에 설치된 발신기의 빛을 감지한다.
출처: 방과 캐릭터 이미지 stryjekk, subarashi21 ⓒ 123RF.com - S. 옥사칼니스의 연구에서 발췌 </p>
<p>7.전자기 트래커
전자기 트래킹 시스템은 20년 넘게 가상현실 시스템에서 핵심적 역할을 해왔다. 이 분야의 가장 초기 진입자 중 하나며 가장 수요가 많고 업무 수행에 필수적인 애플리 케이션에서 여전히 활약하고 있는 솔루션은 버몬트 콜체스터의 폴히머스 주식회사가 개발한 패스트랙FASTRAK 시스템이다. </p>
<p>자기 트래킹 시스템의 배경이 되는 일반 운영 원칙은 상당히 단순하다. 그림 11.9처럼, 전송기는 서로 각도를 맞춘 와이어형의 코일 세 개가 있는 작은 고정형 정육면체다. 세 개의 코일에 전류를 순서대로 보내면 세 개의 쌍극자기장이 만들어지는데, 서로 직각 방향이 된다. </p>
<p>센서 자체는 대체로 전송기와 같은 디자인이지만 크기는 꽤 작다. 센서를 탑재한 물체가 세 개의 자기장을 통과하면, 자기장의 변화에 비례해 세 개의 코일에서 전류가 만들어진다. 이 신호를 유무선 연결로 컨트롤러에 전송하는데, 여기서 전송기에 상대적인 수신기의 위치와 방향을 계산한다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/d0abfea6-cbef-4e26-99e8-6571a381c34c/image.jpg" alt=""></p>
<p>그림 11.9 폴히머스 패스트랙 전자기 트래커의 송신기와 수신기 내 코일의 직각 와이어를 묘사한 일러스트 출처: 이미지 제공 - <a href="http://www.polhemus.com">www.polhemus.com</a> </p>
<p>패스트랙 시스템은 포지션 갱신율이 120Hz(센서 수로 나눠)고, 지연율은 약 4밀리초다. 표준 작동 범위는 1~2미터지만, 시스템 애드온으로 3미터까지 확장할 수 있다. 측정 정확도는 X, Y, Z 포지션에 대해 0.8밀리 RMS며, 수신기 방향에 대해 0.15도 RMS다. </p>
<p>시중에서 구할 수 있는 다양한 자기장 위치 감지기는 일반적으로 AC 전류로 자기장을 생성하는 것과 DC 전류를 사용하는 것 두 가지가 있지만, 가상 현실 영역에서는 AC 솔루션이 더 지배적인 편이다. AC 시스템은 더 큰 작동 범위에서 정확한 측정이 가능할 뿐 아니라, 신호 대 잡음비도 낮아 여러 유닛을 같은 공간에서 이용하는데 따른 혼선을 최소화할 수 있다. </p>
<p>이 장의 다른 모든 트래킹 솔루션처럼 이 시스템에도 한계와 구현 과제가 있다. 아마 가장 잘 알려져 있는 것은 작동 범위 내 전도체의 영향일 것이다. 자기장을 발생시키는데 사용하는 AC 전류가 변동할 때 전도체에 맴돌이 전류가 생겨서 자기장에 왜곡이 생기고 시스템 성능 저하가 일어날 수 있다. 하지만 적응형 필터링을 포함해 수많은 보정 솔루션이 개발돼 이 영향은 줄어들었다. </p>
<p>8.관성 센서 </p>
<p>관성 센서는 힘을 측정하는 기기다. 현대적인 여러 관성센서, 특히 일반 소비자 상품 의 센서로는 MEMS(초소형 정밀 기계 체계) 기기류가 있다. 가속계(가속 측정용), 자이로스코프(각속도 측정용), 자력계(지구자기장에 상대적인 방향 측정, 즉 나침반)가 여기에 해당한다. 모든 초소형 전자 제품에 흔한 제조 기술과 소재로 제조하는 관성 센서는 현재 매우 다양한 제품과 시스템에서 찾아볼 수 있다. 일부 응용 사례를 보면 자동차(에어백 작동을 위한 충돌 감지용), 다리미와 게임 컨트롤러의 기울기 센서, 모바일 기기 화면 디스플레이의 방향 재설정 등에 쓰인다. </p>
<p>9.관성 센서의 작동 방식 </p>
<p>단순하게 설명하자면, MEMS 관성 센서의 중심 요소는 캔틸레버 앞cantilever arm이나 스프링처럼 중립적 위치에서 외부 가속의 영향하에 움직이는 프루프 proof massass 다. </p>
<p>이 운동은 프루프매스와 몇 가지 고정 요소 간의 정전 용량 capacitance을 변경한다. 측 정된 정전용량의 변화는 가속과 회전을 정량화하는데 사용된다. 그림 11.10은 이런 MEMS 관성센서의 복잡도를 보여주는 예로, 애플 아이폰 4 에 있는 ST 마이크로 3축자이로스코프다. </p>
<p>지난 10년간, 관성 센서는 가상 및 증강 현실 분야의 개발자가 자연스럽게 작은 크기, 낮은 비용, 높은 갱신율, 낮은 지연율 등 여러 혜택을 이용할 수 있는 쪽으로 발전 했다. 단독으로 사용하든 다른 센서 기술과 조합하든(하이브리드 시스템), 관성 센서는 이 분야의 핵심적 실행 기술의 전반적 성능, 크기, 적용 가능성에 상당한 영향을 주기 시작했다. </p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/33d501ea-7f53-4dd9-90b4-ad4959b658cd/image.jpg" alt=""></p>
<p>그림 11.10 아이폰 4s 3축 자이로의 상세 이미지. 여러 MEMS 구조가 분명히 보인다. 출처: 사진 제공 칩웍스 주식회사chipworks </p>
<p>적용 사례
이상적인 예를 들면, 관성 센서를 구글 글래스 디스플레이에서 사용하는 사례가 될 것 같다(5장, &#39;증강 디스플레이&#39; 참조). 이 전자 제품의 컴팩트한 디자인 비결은 그림11.11의 인벤센스 MPU-9150이라는 작은 칩에 숨어있다. 이 관성 센서는 세계 최초의 9축 모션 트래킹 MEMS 기기로, 3축 자이로스코프, 3축 가속계, 3축 디지털 나침반이 있다. 유사한 관성 센서가 캘리포니아 샌프란시스코의 오스터하우트 디자인 그룹이 제조한 R7 스마트글래스 증강 디스플레이에도 쓰인다. </p>
<p>이 책에서 다룬 여러 다른 입력 기기가 MEMS 관성 센서를 적용하고는 있지만, 이 분야는 상업적으로는 아직 유아기라 할 수 있다. 하드웨어 디자이너들이 디스플레이와 입력 기기 같은 핵심 컴포넌트 크기를 줄이고자 노력하고 있으므로, 독자들은 이런 기술을 점차 신제품의 핵심에서 볼 수 있을 것이다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/c599c20a-4142-4a82-9c2d-87efec71675f/image.jpg" alt=""></p>
<p>그림 11.11 구글 글래스 디스플레이 내부의 인벤센스 MPU-9150 9축 모션 트래킹 MEMS 센서의 위치를 보여주는 엑스선 사진
출처: 이미지 제공 - AGL 이니셔티브의 앤드류 반덴 휴벨(Andrew Vanden Heuvel)</p>
<p>10.음향센서
이 책을 저술하는 현재 기준으로 가상 및 증강 현실 영역에서 상용으로 활용되고있는 음향 트래킹 솔루션은 거의 없다. 그럼에도 음향 센서, 구체적으로 초음파 트래커는 적절한 상황에서 강력한 솔루션이 될 수 있다. 이 센서군에서 독보적인 주자는 메사추세스 빌레리카의 인터센스 코퍼레이션이 제조하는 초정밀 IS-900 시스템이다. </p>
<p>전형적인 설정에서 IS-900 시스템은 소니스트립스Sonistrips라는 기기를 사용하는데, 이는 응답기에 맞춰 초음파 펄스를 전달한다. 그림 11.12처럼 소니스트립스는 일반적으로 트래킹하는 작업 공간 위에 설치해, 조회 기기 또는 다른 물체에 탑재한 핸드 헬드 컨트롤러나 센서 바 속에 있는 센서에서 방해받지 않는 시야를 유지할 수 있다. 일단 소니스트립스를 설치하고 나면, 각 소니스트립과 센서 간 관계를 세심히 보정해서 6 DOF 모두에 걸쳐 정확한 트래킹이 되도록 해야 한다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/fc3ce25e-ef02-490b-9551-a2347e5f35ef/image.jpg" alt=""></p>
<p>그림 11.12 미군 유인 휴대 방공(MANPAD) 시뮬레이터에 높이 초음파 응답기가 임베드된 인터센스 소니스트립스망을 보여주는 이미지
출처: 미 해군 제공 사진</p>
<p>인터센스 시스템에서 초음파 트래킹 컴포넌트는 트래킹 작업 공간에서 물체의 위치를 판단하는 측정 값을 찾는데 원칙적으로 데카르트 좌표(X, Y, Z)를 사용한다. 트래킹되는 물체의 방향(롤, 피치, 요)은 그림 11.13과 같은 핸드헬드 컨트롤러나 센서바에 임베드된 이너시아큐브Inertiacube라는 초정밀 관성 센서로 측정한다. 이런 기기의 이동 측정은 유무선 연결을 통해 받침대로 고정된 기반 유닛에 전송된다. </p>
<p>이렇게 여러 트래킹 기술을 사용하는 것을 센서 퓨전이라 하며, 산업 전반에 걸쳐 다양한 조합이 활용된다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/ef5e0c54-4b6f-4a0f-a5e3-fce948f10bc7/image.jpg" alt=""></p>
<p>그림 11.13 인터센스 IS-900 관-초음파 트래킹 시스템의 무선 핸드헬드 컨트롤러와 유선 센서 바 컴포넌트를 보여 주는 이미지
출처: 플리커에 실린 아이다호 국립 연구소 이미지. CC2.0 라이선스에 의거 수록</p>
<p>시뮬레이션과 트레이닝 쪽에서도 폭넓게 사용되지만, IS-900은 매우 많은 CAVE, 파 워월 Powerwall, 반구형 디스플레이 설치에서도 이 장의 앞에서 언급한 광학 트래킹 솔 루션의 대안으로 사용된다. </p>
<p>일반적으로 음향 트래커는 광범위한 초기 설정과 조정이 필요한 까다로운 시스템이다. 환경 소음으로 인한 오류에도 매우 민감한데, 특히 통신사의 신호 파장에 가까운 것들이 그렇다. 비행 시뮬레이터 같은 조종 환경을 완벽히 제어하는 애플리케이션에는 이 트래킹 솔루션이 이상적이다. </p>
<p>11.결론</p>
<p>가상 환경 시스템이 확산되려면 정확하고 효율적이며 적당한 가격대의 센서가 필수 적이다. 가상 및 증강 현실이 다양한 산업에 전환적 영향을 주는 것과 마찬가지로, 이런 핵심적인 발전 중 상당수는 센서가 발달하면서 발생했지만, 여전히 해결해야 할 과제도 남아있다. 기술적 솔루션의 약점 때문이 아니라, 이 분야가 상대적으로 덜 성숙됐기 때문에 일어나는 문제다.
어떤 센서 기술을 활용할지 결정할 때 시스템 개발자가 직면하는 가장 큰 도전은 성능 측정과 제시 방법이 제각각이라는 점이지만, 이 문제는 기존의 업체가 엄격한 산업 표준이 출현하고 있는 이 분야에 충분히 참여하면 자연스럽게 해결될 것이다.</p>
<pre><code>                                                   출처 - 실전 증강 현실(스티븐 옥스타칼니스 지음)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[인터랙션 개발에 대하여(17)]]></title>
            <link>https://velog.io/@kiwi_100/%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC17</link>
            <guid>https://velog.io/@kiwi_100/%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC17</guid>
            <pubDate>Thu, 15 Jun 2023 05:49:05 GMT</pubDate>
            <description><![CDATA[<h1 id="촉각과-포스-피드백-기기">촉각과 포스 피드백 기기</h1>
<p>촉감 유도
이 책에서 다룬 인간-컴퓨터인터페이스의 고급 기술이 특히 많이 다루는 주요 감각
세 가지 중에서 시각과 청각 채널 두 가지에는 개발이 상당히 집중돼왔다. 단지 실생
활에서 이 두 가지 채널에 폭넓게 의존하고 정보가 더 많이 알려져 있기 때문이기도
급 기기뿐 아니라 전반적인 제품군까지로 낮아진 이유가 크다. 이에 비해 촉감을 활 하지만, 더 고해상도 디스플레이와 저지연 센서에 대한 요구 같은 기술적 장벽이 고
용하는 기술에는 상업적인 개발이 훨씬 덜 이뤄졌다.</p>
<p>9장, &#39;감각의 구조&#39;에서 알아본 것처럼, 신체의 감각 체계에는 전반적인 촉감에 기여 하는 두 가지 큰 하부 시스템이 있다. 그 첫 번째인 촉각은 외부 압력, 진동, 퍼덕거림, 질감, 피부 확장 등 기계적 자극을 감지, 인지하는 능력을 맡는다. 두 번째인 운동감 은 근육, 힘줄에 작용하는 긴장 및 기타 힘을 감지한다. 각각 감지할 수 있는 다양한 기계적 자극의 종류에 고도로 특화된 만큼, 가상현실/증강 현실 애플리케이션에서 유용한 방식으로 촉각을 활용하는 데 필요한 기계적 자극의 범위를 인공적으로 만들어내려면 고도로 특화된 기술이 필요하다.</p>
<p>그래서 이 장에서 다루는 실행 기술 사례는 주로 촉각적 피드백을 제공하는 것과 표 스(운동감) 피드백을 제공하는 것 두 가지로 크게 나누겠다. 이 책에서 실행 기술을 다루는 다른 장과 마찬가지로, 여기에 제시된 솔루션은 절대로 전체를 다 담은 목록 이 아니며 전 세계의 정부, 대학, 기업 연구소에서 진행 중인 개발 프로젝트 수십 개 중 극히 일부임을 다시 한 번 강조한다.</p>
<p>촉각 피드백 기기
이 책을 읽는 독자는 아마도 모두 모바일 기기가 손에서 울리거나, 다양한 비디오 게 임 컨트롤러와 입력 기기를 통해 드르륵 갈리는 듯한 진동감을 경험해본 적이 있을 것이다. 이런 감각은 ERM(편심 회전체) 진동 모터라는 기계적 발동기에서 만들어내는 경우가 가장 많다. 그림 10.1처럼, ERM은 그 축에 중심에서 벗어나거나 특이하게 생긴 덩어리가 달린 미니 DC 모터다. 축이 회전하면(보통 매우 고속으로), 편심체는 이 축의 회전축에 직각으로 구심력을 발생시킨다. 이 힘이 모터가 부착된 물체나 컴포넌트에 전달되며 진동을 일으킨다.</p>
<p>이런 장치는 설계가 단순하면서도 매우 효과적이며, 모터에 적용되는 전압을 바꾸면 속도와 그에 따른 구심력 및 진동주파수를 쉽게 제어할 수 있다. 편심회전체 모터는 크기와 진동력이 다양해서 다양한 촉각을 발생시킬 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/9564d744-293e-48b8-a7a0-c5e73471c244/image.jpg" alt=""></p>
<p>그림 10.1 편심회전체 진동 모터의 전개도
출처: 이미지 제공 - 프리시전 마이크로드라이브 햅틱 모터(<a href="http://www.PrecisionMicrodrives.com">www.PrecisionMicrodrives.com</a>)</p>
<p>모바일 컴퓨팅 플랫폼과 입력 기기에 더 많은 컴포넌트와 성능을 넣으려는 노력이 지 속된 결과, 팬케이크 진동 모터pancake vibrator motor라는 ERM 모터의 유형이 개발됐다. 그림 10.2처럼 팬케이크 모터는 여타 ERM과 같은 원리로 기능한다. 편심체 디스크가 가늘고 폐쇄된 하우징 안에서 회전해, 이 구심력이 모터가 부착된 물체나 컴포넌트에 전달돼 진동을 유발하는 것이다[프리시전 2015].</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/793d5861-183a-4a42-9254-7d75b5d8bc48/image.jpg" alt=""></p>
<p>그림 10.2 편심체 진동 모터의 변형인 팬케이크 진동 모터의 전개도
출처: 이미지 제공 - 프리시전 마이크로드라이브 햅틱 모터(<a href="http://www.PrecisionMicrodrives.com">www.PrecisionMicrodrives.com</a>)</p>
<p>애플리케이션에 따라 팬케이크 진동 모터는 여러 장점이 있는데, 가장 큰 장점은 크 기가 작다는 것이지만 그 외에도 바깥쪽은 움직이지 않아서 빽빽한 컴포넌트 설계 시 공간을 더 효율적으로 사용할 수 있다는 것도 큰 강점이다.</p>
<p>진동 촉각 단서의 발생을 활용하는 또 다른 작동기군으로 선형 반향 작동기LRA 진동 모터가 있다. 그림 10.3처럼, 자기체는 스프링과 보이스 코일 사이에 자리 잡는다. 코 일에 전류를 흘려보내면 자기체는 단일 축을 따라 스프링을 누른다. 그리고 코일을 따라 흐르는 전류 방향을 바꾸면 반대 방향으로 움직인다(DC인 ERM과 달리 AC 기기가 되는 것이다). 팬케이크 진동 모터와 마찬가지로 LRA는 크기가 작고 외부의 움직이 는 부분도 없어서, 애플리케이션이 촉각 단서를 발생시키는 소형 기기에 이상적이다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/274b3130-e1bf-4e7f-9a5c-868e9ee19d6b/image.jpg" alt=""></p>
<p>그림 10.3 선형 반향 작동기 모터의 전개도
출처: 이미지 제공 - 프리시전 마이크로드라이브 햅틱 모터(<a href="http://www.PrecisionMicrodrives.com">www.PrecisionMicrodrives.com</a>)</p>
<p>이제부터 살펴볼 두 기기에는 편심 회전체와 선형 반향 작동기 진동 모터의 다양한 조합이 활용된다.</p>
<p>글러브원</p>
<p>지금까지 개발된 가장 전망 있는 대중 시장용 촉각 피드백 입력 기기로 스페인 알메 리아의 뉴로디지털 테크놀러지NeuroDigital Technologies가 선보인 글러브원Gloveone 인터페 이스가 있다. 수년간 개발한 이 경량 장갑은 센서와 진동 촉각 작동기를 탑재해, 컴퓨· 터 화면이나 헤드마운트 디스플레이에 보이는 가상 물체와 상호작용할 때 섬세한 촉 감을 제공한다. 그림 10.4처럼 글러브원의 컴포넌트는 다음과 같은 하위 시스템으로 나눌 수 있다.</p>
<ul>
<li><p>작동기: 글러브원에는 손가락 끝마다 하나씩, 그리고 손바닥 전반에 다섯 개로 총열개의 미니어처 LRA가 있다.</p>
</li>
<li><p>IMU 센서: (6) 3축 IMU가 손가락의 굴곡, 확장, 측면 운동을 트래킹한다. 손의
전체적 방향은 컨트롤러에 있는 (1) 9축 IMU로 트래킹한다.</p>
</li>
<li><p>전도 섬유: 전도성 니트 섬유를 엄지, 검지, 중지 끝과 엄지 안쪽 접히는 부분 근
처의 손바닥에서도 사용해 명령어의 제스처 트리거가 가능하다(꼬집기, 주먹
쥐기 등),</p>
</li>
<li><p>컨트롤러: 손등에 탑재된 마스터 컨트롤러에는 기기의 마더보드, 블루투스 4.0
센서, IMU, USB 포트, 파워 버튼, 리튬 폴리머 배터리가 있다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/51f48ad6-1ed4-4431-9d75-ce238ebe6be2/image.jpg" alt=""></p>
<p>그림 10.4 뉴로디지털 테크놀러지의 글러브원 인터페이스는 손가락 끝과 손바닥 전반에 걸쳐 있는 작동기 열 개를 사
용해 설득력 있는 촉각을 생성한다.
출처: 사진 제공 뉴로디지털 테크놀러지</p>
<p>열 개의 진동 촉각 작동기마다 1,024가지의 서로 다른 강도와 주파수를 만들어서, 광 범위한 촉각을 생성할 수 있다(10×1024의 개별 설정과 조합). 이 책을 저술하는 시점 에 손가락의 움직임과 손의 회전 트래킹에는 IMU가 사용되긴 하지만, 기기의 포지션 (X, Y, Z) 트래킹, 이어지는 사용자의 손 트래킹에는 리프 모션 컨트롤러, 인텔 리얼 센스, 마이크로소프트 키넥트 같은 서드파티 기기의 이용이 동반된다. 제조사에 따르 면, 현재 10~15 밀리초 범위에 이르는 내장 센서의 지연율 때문이기도 하다.
글러브원 매니저 소프트웨어 유틸리티로 기기를 조종하고, 광범위한 개발과 테스트 를 실행할 수 있다. 그림 10.5는 이 유틸리티의 스크린샷이다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/c0c5cd83-51ad-466e-b3c0-cce8c048eacd/image.jpg" alt=""></p>
<p>그림 10.5 글러브원 매니저 소프트웨어 유틸리티의 작동기 설정과 테스트 모드 스크린샷
출처: 사진 제공 뉴로디지털 테크놀러지</p>
<p>이 기기는 애초에는 게임과 엔터테인먼트 시장을 타기팅했지만, 다른 방면으로도 이 미 응용이 이뤄지고 있다. 예를 들어 2015년 말 뉴로디지털 테크놀러지는 런던 왕립 대학과 제휴로 글러브원 기기를 시뮬레이션 과정에 사용하는 복강경 검사기 가상 트 레이너를 공동 개발했다[커스버트슨(Cuthbertson), 2015].</p>
<p>테슬라수트</p>
<p>몸의 표면에서 전기 충동의 촉각 정보 전송은 일반적으로 일렉트로택틸, 혹은 전자 피부 자극이라고 한다[보비치(Bobich) 등 2007; 카지모토(Kajimoto) 등 2004; 카츠마렉(Kaczmarek) 과 하스(Haase) 2003; 메니아(Menia)와 반 도렌(Van Doren) 1994; 히가시야마(Higashiyama)와 롤먼 (Rollman) 1991; 타시로(Tashiro)와 히가시야마 1981]. 이런 기법은 수십 년 동안 연구됐지만, 대 부분은 감각을 대체하는 애플리케이션(한 감각의 기능이나 출력을 다른 감각의 자극으 로 이용)과 인공 기관, 원격 로봇공학의 기능성과 사용성을 높이는 데 집중돼왔다[다닐 로프(Danilov) 등 2008; 탕(Tang)과 비비(Beebe) 2006; 몽크먼(Monkman) 등 2003].</p>
<p>일렉트로택틸 자극은 신경근육 자극과 밀접한 연관이 있는데, 전기 충동으로 선택 된 근육군을 자극하는 의료와 프로 스포츠에서 폭넓게 사용하는 치료요법이다[두셋 (Doucet) 등 2012; 셰플러(Sheffler)와 체이(Chae) 2007; 레이크(Lake) 1992]. 이 기술은 방향 안내,내비게이션, 콕핏 내 커뮤니케이션, 전정 대체 등 다양한 애플리케이션에서도 활용됐
다[밴 어프(Van Erp)와 셀프(Self) 2008; 다닐로프(Danilov) 2008; 즐로트니크(Zlotnik) 1988].</p>
<p>오늘날까지 일렉트로택틸이나 신경근의 역량은 엔터테인먼트산업에서 거의 효과적 으로 활용되지 못했으며, 가상 및 증강현실 시스템의 실행 기술로서 활용되는 경우 는 더더욱 적었다. 부분적으로는 소형화의 기술적 난점과 엄청난 가격, 전기적 촉감 과 기계적 자극 수용기의 크기와 기능 간 차이, 그리고 몸의 서로 다른 부분에 따라 전기적 촉감과 기계적 자극 수용기가 다르게 분포하는 등 여러 연관된 생리 요인에 대한 이해가 부족했기 때문이다. 하지만 이를 비롯한 여러 장벽이 하나씩 해결돼가고 있으며, 그에 따라 최신 촉각 인터페이스 디자인 역시 성장할 것으로 전망된다.</p>
<p>이런 발전을 활용하는 시스템 중 한 사례가 그림 10.6의 테슬라수트 DK1으로, 스코 틀랜드 세인트앤드루스의 테슬라 스튜디오에서 개발했다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/3392f7a3-e968-48d6-9f83-1b6d30d0aa51/image.jpg" alt=""></p>
<p>그림 10.6 풀 바디 테슬라수트 DK1은 모듈형이며 조끼, 바지, 벨트(중앙 제어 유닛 탑재), 장갑으로 구성된다. 전체 시 스템은 현재 일렉트로택틸 자극점 60개가 들어있다.
출처: 이미지 제공-테슬라 스튜디오</p>
<p>9장에서 살펴본 대로, 사람의 피부는 특화된 피부 촉각 수용기의 복잡한 네트워크로
가득하다. 기계적 자극을 받으면 이 수용기는 구심 신경 섬유를 따라 중추 신경계에 작은 전기 충동을 전달한다. 그림 10.7처럼 테슬라수트 DK1은 섬유에 심은 미니어처 전극으로 미세하고 통제된 고통없는 전기자극을 사용자 피부의 전략적으로 선택한 수십 개 지점에 가해 구심 신경 섬유를 자극한다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/a83fc217-8e95-469c-8169-c35755d9cf50/image.jpg" alt=""></p>
<p>그림 10.7 테슬라수트 DK1의 일렉트로택틸 자극점 배포를 보여주는 일러스트 출처: 이미지 제공 - 테슬라 스튜디오</p>
<p>제조사가 택틸 에디터라고 부르는 소프트웨어 제품군으로 충동 패턴의 인코딩을 조 정해, 사용자가 다양한 애플리케이션의 요구 사항에 맞는 촉각을 직접 조절할 수 있 다. 자극 빈도, 진동의 폭/지속 시간, 강도/진폭, 가속 시간, 진동 패턴 등의 요인을 바 꾸면 폭넓고 다양한 감각을 만들어내 실제의 물리적 자극을 시뮬레이션할 수 있다.</p>
<p>풀 바디 테슬라수트는 재킷, 바지, 벨트, 장갑을 포함한 여러 컴포넌트로 구성된다. 현재 수트 전체에는 개별 자극점 60개가 들어있다. 벨트에 있는 고성능 마이크로 컨트롤러는 블루투스 4LE (저 에너지) 연결로 다른 수트 컴포넌트와 통신한다.</p>
<p>테슬라수트 DK1은 여러 9축 IMU 센서를 통합해(11장, &#39;위치, 방향, 동작 추적용 센서&#39;
참조) 모션 캡처 요구 사항에도 대응한다.</p>
<p>햅틱 오디오와 촉각 사운드 변환기</p>
<p>9장에서 논한 촉각과 운동감 수용기는 사운드로도 자극할 수 있다. 예를 들어 비행기 의 낮은 덜컹거림, 다가오는 헬리콥터의 둔탁한 진동, 바닥과 좌석을 진동시키는 폭 발 같은 촉감을 사운드 효과가 발생시킬 때 영화를 보는 경험이 훨씬 더 참여적이고 몰입적이 된다는 데 대부분이 동의할 것이다. 사실 일반 스피커가 저주파 사운드와 진동을 만들어내도록 설계된, 고도로 전문화된 전자 기계 기기군이 있다. 스피커 스 킨과 달리 넓은 표면에 작동하도록 설계된 이들 기기는 촉각 사운드 변환기, 혹은 베 이스 셰이커라 하는데, 군용 시뮬레이션 애플리케이션, 나이트클럽 플로어, 그리고 디즈니와 유니버설 스튜디오 등 놀이 공원에서 광범위하게 사용된다.</p>
<p>지난 수년간 가상 및 증강 현실에 대한 관심이 극적으로 부활하면서, 이런 기기 다수 는 게임과 엔터테인먼트 부문에서 새로운 틈새시장을 찾았다.</p>
<p>서브팩</p>
<p>원래는 새로운 음악 트랙의 낮게 둥둥거리는 베이스 라인이나 영화에 추가되는 특수 사운드 효과처럼 오디오 프로덕션의 범위를 전체를 경험해야 하는 사운드 엔지니어 와 DJ가 사용하도록 설계된 그림 10.8의 서브팩 S2 (스튜디오)는 의자에 장착할 수 있는 촉각 사운드 변환기다. 주파수 반응 범위가 5에서 130Hz인(7장, &#39;청각의 구조&#39;에서 사람 청각의 하한선이 20Hz라고 설명한 것을 기억하자.) 서브팩은 저주파 진동을 몸에 전달하는 변환기가 있으므로 사용자가 문자 그대로 사운드를 &#39;느낄&#39; 수 있다.
서브팩은 고도로 설득력 있는 촉각과 깊이감을 저주파 사운드 효과에 추가하는 기능 덕분에 전문 게이머와 VR 팬에게 꾸준히 좋은 평가를 받고 있다. 벽을 울려대는 서브 우퍼와 달리 서브팩 자체는 비교적 조용하다. 다시 한 번 말하지만, 이 기기를 통해서 는 실제로 소리를 듣는 것이 아니라 느끼게 된다.
<img src="https://velog.velcdn.com/images/kiwi_100/post/d6021fb7-3ed2-43ac-a349-8a9d9085d083/image.jpg" alt=""></p>
<p>그림 10.8 서브팩 S2는 가장 강력하고 정확한 착석형 촉각 베이스 솔루션 중 하나다. 서브팩 M2는 웨어러블 버전으로 똑같은 독자적 촉각 변환기를 활용한다.
출처: 이미지 제공 - Marwan Balaid(<a href="http://mar-one.tumblr.com/">http://mar-one.tumblr.com/</a>)</p>
<p>서브팩의 부드러운 네오프렌 외장과 잘 디자인된 인체공학적 형태는 사용자의 등에 최대로 접촉한다. 서브팩은 세 점 스트랩 시스템으로 의자에 단단히 고정된다. 작은 컨트롤 유닛은 표준 3.5mm 스테레오 잭을 통해서나 A2DP 스트리밍을 통해 블루투 스 4.0으로 오디오 입력을 받을 수 있다. 헤드폰 연결을 위한 출력 잭도 있다.</p>
<p>모바일 솔루션을 요하는 애플리케이션에 서브팩은 같은 범위의 성능과 기능을 제공 하는 M2 (모바일)라는 웨어러블 버전도 생산한다.</p>
<p>우저</p>
<p>가상 및 증강 현실 커뮤니티의 게임 부분에서 상당한 인기를 얻고 있는 촉각 사운드 변환기로 이스라엘 텔아비브에 있는 우저 주식회사에서 생산하는 모바일 웨어러블 액세서리 우저도 있다. 그림 10.9처럼 우저는 셔츠에 자석으로 붙이거나 벨트 에 클립으로 고정하는 탄성 스트랩을 이용해 사용자의 가슴과 직접 접촉하도록 부착하는 성냥갑보다 조금 큰 조용한 웨어러블 폴리포닉(여러 사운드를 동시에 산출) 변환기다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/bfd72d48-4cbe-4ea7-b78a-6fff4ec95612/image.jpg" alt=""></p>
<p>그림 10.9 우저는 특허권이 있는 폴리포닉 변환기로, 풍부하고 감정을 자극하는 초저주파 베이스 톤을 몸에 전달하는 웨어러블 촉각 기기며, 이를 통해 사용자는 사운드 감각을 느낄 수 있다.
출처: 이미지 제공 -우저-Born to FEEL</p>
<p>제조사에 따르면 우저는 인지적 추론에 의존하는데, 사람의 두뇌가 이전 경험을 통해 구축된 내부 신경의 재현에서 비롯된 예측을 근거로 감각 자극을 추론하는 능력이다 [우저 2013; 아겔로풀로스(Aggelopoulos) 2015].</p>
<p>이 제품의 굉장히 독특한 기능은 폴리포닉 진동 발생에 소프트웨어나 알고리즘을 사용하지 않는다는 점이다. 즉 오디오 입력에서 나온 신호를 수신할 때와 이에 상응하는 진동이 만들어질때 지연 시간이 최소한(~1ms)이므로, 귀가 듣는 바와 몸이 느끼는 바의 차이가 없다는 뜻이다.</p>
<p>우저 1.0의 스펙을 보면 0~500Hz의 주파수 반응범위, 세가지 진동 수준 제어 스위치, 충전 가능한 리튬이온배터리, 마이크로USB 충전포트, 온/오프와 오버드라이브를 나타내는 적녹 LED, 진동과 동조화돼 점멸하는 파란 LED와 3.5mm 아날로그 오디오 포트 한 쌍(플레이어용 하나, 헤드폰 하나)이 있다.우저 2.0은 좀 더 작고, 케이블을 없애기 위해 블루투스4.0을 갖췄다.</p>
<p>클라크 신테시스 풀 컨택트 오디오 택틸 사운드 변환기</p>
<p>의자, 소파, 바닥 같은 물체나 표면에 단단히 부착하는 부류의 또 다른 촉각 변환기군 도 있다. 대부분의 변환기는 코일이나 자석으로 구동되는 작은 추를 넣어 고음질의 사운드-모션 증강을 제공한다. 고성능 시뮬레이션과 훈련에서 이런 촉각과 운동감 단서가 주어질 때 정확한 정신운동성 반사 능력이 커지고, 훈련 경험이 더욱 풍성해진다.</p>
<p>이 시장에서 고성능 변환기를 생산하는 선도 업체로 콜로라도 리틀턴의 클라크 신테시스가 있다. 그림 10.10처럼, 여러 모델 중 하나인 TST329 골드 트랜스듀서는 전세계적으로 극장부터 상용/군용 차량 시뮬레이터까지 아우르는 전문가용 오디오/비디오 애플리케이션에 사용된다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/948ea974-5965-45a7-9259-be15767e342e/image.jpg" alt=""></p>
<p>그림 10.10 클라크 신테시스 TST329 골드 트랜스듀서는 전 세계의 전문가용 시뮬레이션과 훈련 애플리케이션에서 사용되는 고음질 사운드 모션 증강 기기다.
출처: 사진과 일러스트레이션 제공 클라크 신테시스</p>
<p>이런 촉각 사운드 변환기군은 보통 제대로 작동하려면 앰프가 필요하다. 클라크 TST329 골드의 경우 임피던스 4옴의 125<del>150와트에서 완전한 범위의 성능에 도달 한다. 직경 20센티미터, 높이 6센티미터며 기기의 주파수 반응은 10</del>17Hz다.</p>
<p>포스 피드백 기기</p>
<p>포스 피드백 기기는 접촉력, 진동, 동작을 사용자에게 적용해 촉감을 준다[로블레스-데 -라-토레(Robles-De-La-Torre) 2010]. 설득력 있는 경험을 제공하고 사람의 경험에 맞추기 위해, 기기가 행사하는 최대의 힘은 사람이 만들 수 있는 최대한의 힘에 맞거나 그보다 커야 한다 [라이사모(Raisamo)와 라이사모 2007]. 그럼 증강 및 가상현실 시스템에 적용
되는 다양한 혁신적 포스 피드백 솔루션을 살펴보자.</p>
<p>사이버글러브 시스템 사이버그래스프</p>
<p>작동자가 수동으로 컴퓨터가 생성한 모델과 상호작용하거나, 실제로 느끼거나, 로봇의 능란한 최종 작동체를 정확히 조종하는 기능이 필요한 고도로 전문화된 산업용, 방위용 애플리케이션은 무수히 많다. 그런 애플리케이션은 다양한 영역의 복잡한 시뮬레이션과 유인 우주 비행의 훈련 시나리오부터 안전거리에서 위험 물질 처리를 해야하는 원격 로봇공학 애플리케이션까지 다양하다. 이런 중요 작업에서 전 세계적으로 활용되는 선도적 기기로 사이버그래스프CyberGrasp라는 힘 반영 외골격이 있는데, 캘리포니아 산호세의 사이버글러브 시스템에서 제조한다.</p>
<p>그림 10.11처럼, 사이버그래스프는 데스크톱 유닛의 작동기 다섯 개에서 기기의 손가락 끝으로 라우팅되는 힘줄(케이블) 네트워크로 저항성 포스 피드백을 손가락마다 제공하는 경량의 힘 반영 외골격이다. 사이버그래스가 손가락마다 행사하는 힘은 최대 12뉴튼(12킬로그램 힘(IbF)과 동등)이다. 사용 시 사이버그래스프는 전체 동작 범위에 걸쳐 손가락 끝에 거의 직각으로 힘을 전달한다(혹은 손가락을 긴장시킨다. 기기는 그 전체를 세세하게 설정할 수 있어, 손가락마다 개별적인 프로그래밍도 가능하다.
사이버그래스를 사용할 때는 가상 캐릭터나 원격 조정 시스템을 조종하기 위해 손가락을 구부리고 펼친 정도를 정확하게 측정해야 한다. 그럴 때를 위한 그림 10.11의 사이버글러브 같은 데이터 장갑 입력 기기에 대해서도 이 회사는 글로벌 선도 공급 업체로 손꼽힌다. 사이버글러브의 고급 버전은 12장, &#39;내비게이션과 상호작용 구동 기기&#39;에서 자세히 살펴보겠다.</p>
<p>사이버그래스프 시스템의 사용은 연구소나 작업장의 고정된 곳에 국한되지 않는다.
작동자의 이동성을 요구하는 애플리케이션에서는 데스크톱 작동기와 컨트롤러를 이런 목적으로 특별히 설계된 배낭 형태로 착용할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/9790724a-a8dc-4d20-b2fe-ca233e4f73c4/image.jpg" alt=""></p>
<p>그림 10.11 사이버그래스프는 사이버글러브 데이터 장갑에 맞춰 사용자 손가락에 저항하는 포스 피드백을 제공하는 경량의 힘 반영 외골격이다.
출처: 사진 제공 CyberGlove Systems/CyberGraspⓗ</p>
<p>지오매직터치 X 햅틱 기기
모델 제작자부터 의사, 화학자, 엔지니어까지 개인이 복잡한 3D 구조의 생성, 조작, 조각, 다듬기 등과 같이 수동으로 상호작용해야 하는 애플리케이션 영역이 존재한다. 외과 의사가 수술실에서 실제로 수술하기전에삐절단과 셰이핑을 연습하거나, 화학자가 약물 분자를 세포내수용영역에 안착시키거나, 기계공학자가 복잡한 가상 조립 작업을 하는 등이 그것이다.</p>
<p>이런 애플리케이션에서 고해상도로 고도의 힘을 산출하는 광범위한 양방향성의 매우 직관적인 포스 피드백 기기군은 디지털 모델과 긴밀한 수동 상호작용을 가능하게 해준다. 매우 작은 기기 중에서 가장 널리 사용되는 것으로는 노스캐롤라이나 모리스빌의 지오매직사가 만든 터치 X Touch X 데스크톱 햅틱 기기가 있다.</p>
<p>그림 10.12처럼 터치 X는 펜 모양의 스타일러스가 있는 힘 반영 로보틱 햅틱 기기다. 작동 시 사용자는 자유롭게 스타일러스를 움직일 수 있으며, 정확히 6 DOF에 걸쳐 추적돼 스크린 속 도구들과 정확히 상응하게 된다. 기하학적 물체와 스크린 속 도구의 상호작용은 실시간으로 실제처럼 보이는 고해상도의 마찰력이 적은 포스 피드백 출력을 각 축(x, y, z)을 따라 스타일러스에 발생시킨다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/94d48cde-e532-41a1-90be-cd7e2a8eb0de/image.jpg" alt=""></p>
<p>그림 10.12 지오매직터치 X는 포스 피드백을 사용자의 손에 적용하는 데스크톱 햅틱 기기로, 화면 속 물체를 조작하 며 가상의 물체를 느끼고 실제와 같은 촉각을 느끼게 해준다.
출처: 이미지 제공 - 3D시스템즈</p>
<p>그림 10.13 의 특허 도안(#6985133) 처럼 작동기와 케이블 드라이브에서 힘이 만들어져, 회전축마다 동력을 제공한다. 일반 작동 모드에서 기기의 위치 해상도 1,100dpi(.023mm) 이상이다. 스타일러스에 최대로 가할 수 있는 힘은 7.9뉴튼(7.9킬 로포스(lbF)와 등등)이다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/be403a20-6ac5-45d4-9738-9f13720c59ac/image.jpg" alt=""></p>
<p>결론
이 장에서 살펴봤듯이, 가상 및 증강 현실 시스템에서 활용하는 사용자 인터페이스의 촉각과 포스 피드백의 구현은 엄청나게 진보하고 있긴 하지만, 생리적 정보 경로의 속성, 복잡성, 감지 가능한 자극의 넓은 범위를 감안할 때 상당한 과제를 안고 있기도 하다. 정확하고 비용 대비 효과적으로 손에 쥐거나 책상에 올려놓거나 몸에 착용할 수 있는 적당한 크기의 기기로 다양한 압력, 퍼덕거림, 질감, 절단력, 가장자리 등의 자극을 만들어내는 것은 공학적으로나 개발적으로 모두 엄청난 기술적 난관이다.</p>
<p>소비자용 촉각과 포스 피드백 기기의 개발과 생산에서 직면하는 또 다른 과제로는 회사가 크든 작든 상관없이 지적 재산권의 장벽을 꼽을 수 있다. 2001년 초부터 강력하고 광범위한 특허가 다수 출원돼 다양한 컨트롤러와 모바일 기기에 촉각과 포스 피드백 효과를 전달하는 많은 기술이 묶여버렸고, 사용료를 지불할 의지나 능력이 없는 회사들의 유망한 여러 제품이 사장됐다. 이런 특허로는 6,424,333, 6,275,213, 6,429,846(El 7,592,999, 7,982,720, 8,031,181, 8,059,105), 7,969,2880] 있다. 사실 마이크로소프트, HTC, 소니, 모토롤라(구글이 인수 후 합의) 같은 여러 회사가 대규모 침해 소송을 당했다. 하지만 사업은 사업이고, 지적 재산권 보유자인 캘리포니아 산호세의 이머전 코퍼레이션은 사용료를 받을 자격이 있다.</p>
<p>이런저런 이유로 나는 사람의 촉각을 정확히 갖출 혁신적인 실행 기술의 경로는 어떤 형식이든 신경 촉각 자극이 될 것이라고 굳게 믿는다. 스코틀랜드 세인트 앤드루스의 테슬라 스튜디오에서 개발한 테슬라수트 설명에서 말한 것처럼 말이다. 9장에서 배운대로 촉각의 대부분은 두뇌의 처리 중추에 전송되는 특화된 수용기에서 생성된, 일련의 고도로 구조화된 전기 충동 패턴에 지나지 않는다. 일단 다양한 감각의인 코딩 방식을 더 잘이해하면(복숭아 표면의 질감을 느끼면 항상 비슷한 자극 패턴이 나오는가?), 완전히 기계적인 자극 수용기 자체를 우회하는 방식으로 측정, 목록화, 재생 하는 법을 개발할 수 있다.</p>
<pre><code>                                                     출처 - 실전 증강 현실(스티븐 옥스타칼니스 지음)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[인터랙션 개발에 대하여(16)]]></title>
            <link>https://velog.io/@kiwi_100/%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC16</link>
            <guid>https://velog.io/@kiwi_100/%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC16</guid>
            <pubDate>Thu, 15 Jun 2023 05:26:02 GMT</pubDate>
            <description><![CDATA[<h1 id="감각의구조">감각의구조</h1>
<p>감각의 과학
친구의 손길, 옷 섬유의 다양한 질감, 골프클럽과 야구방망이를 휘두를 때 느껴지는
힘을 생각해보자.
사람은 놀라울 정도로 복잡한 감각 체계, 신경 경로, 물리적 환경, 물리적 환경 안에 서 우리에게 작용하는 외부의 힘, 그리고 우리 몸의 위치, 방향, 운동에 관한 정보 수 천 건을 매초 감지, 전달, 처리하는 뇌 영역을 갖추고 있기에 이런 감각을 느낄 수 있 다. 이 모든 것을 합쳐서 몸의 감각 체계라고 하는데, 이 책의 주제에 특히 관련이 있 는 것은 두 가지 하위 시스템이다. 첫 번째는 외부의 압력, 진동, 펄럭거림, 질감, 피부 가 늘어나는 것을 포함한 기계적 자극을 감지하고 인지하는 능력이다. 이를 촉각tactile sense이라고 한다. 두 번째는 운동 감각이라고 하는데, 관절 각도와 근육, 힘줄에서 가 해지는 긴장 등의 힘을 감지하고 인지하게 해준다. 이 두 가지 감각을 결합해서 일반 적으로 햅틱haptics이라고 한다.</p>
<p>햅틱이라는 용어의 사용은 가상 현실, 로봇공학, 의료계에서 상당한 혼란과 엄청난 논쟁을 불러일으켰 다. &#39;미투(me too)&#39; 현상으로 인해 이 용어의 적절한 사용에 상당한 불일치가 발생했기 때문이다. 햅틱 은 촉각과 운동 감각 모두를 가리키는 걸까, 아니면 촉각/포스 피드백 기기처럼 점차 입지를 굳혀가고 있는 이런 감각의 기계적 자극을 제공하는 인간과 기계의 인터페이스 부류를 가리키는가? 명확히 하기 위해 이 책에서는 이 용어를 되도록 피하고, 생리학에 대해서만 사용할 것이다.</p>
<p>촉각과 포스 피드백 기술을 가상 및 증강 현실 시스템에서 구현할 때의 난제를 이해하는 데 중요하기 때문에 체계를 본다.
그럼 먼저 이런 감각 대부분이 일어나는 우리 몸의 부분, 즉 피부부터 살펴보자.</p>
<p>피부의 해부학과 구조
피부는 촉각을 담당하는 감각 기관이며, 임신 기간 동안 발달하면서 자극에 반응하는 다섯 가지 주요 감각 중 첫번째[허스(Huss) 1977] 사실 사람의 태아는 발달 후 8주 정
도가 지나면 촉각에 반응한다[란탈라(Rantala) 2013].
중간 크기의 장기인 피부는 약 1.6~1.9평방미터를 덮고 있으며린츨러(Rinzler) 2009], 전 체 체중에서 약 15%를 차지한다[카니타키스(Kanitakis) 2001]. 일반적으로 피부에는 털로 덮인 부분과 자연적으로 매끈한 두 가지 종류가 있는데, 둘 다 보호, 조절, 감각 세 가 지에 속하는 눈에 띄게 복잡한 기능이 있다.</p>
<p>보호: 외부 환경과 내부생리작용이 맞닿는 부분에 위치한 피부는 기계적 충격과 압 력(셈불린검(Sembulingam)과 셈불린검 2002], 위험한 자외선UV[브레너(Brenner)와 히어링(Hearing) 2008], 생물학적 병원균[네슬레(Nestle) 등 2009] 같은 다양한 위협을 방어하는 장벽 역할
을 한다.</p>
<p>조절: 피부는 혈관의 수축과 확장(차쿠디안(Charkoudian) 2003], 수분 분비와 증발을 통한 체온 조절과 안정화에 중요한 역할을 한다.</p>
<p>감각 : 물리적 환경과 주로 맞닿는 피부에는 환경의 변화를 감지하고, 접촉하는 물리적 세계의 속성을 느끼는 감각도 발생시키기 위한 특수한 신경 세포의 광범위한 네트워 크가 있다. 이 신경 세포로 우리는 증강 및 가상 현실 시뮬레이션을 내비게이션하고 조작하는 데 사용하는 진동 컨트롤러 등의 기기가 제공하는 촉각과 포스 피드백 단서 를 감지할 수 있다.</p>
<p>피부층
그림 9.1의 묘사처럼 사람의 피부는 두 개의 주요층으로 구성되는데, 각각 두께와 기 능이 다양하다. 위의 가장 바깥층은 상피라고 한다(그리스어 epi는 &#39;상부&#39;라는 의미며, derma는 &#39;피부&#39;라는 의미다)[옥스포드 2015]. 이 층은 신체내의 생리작용과 외부 환경을 구분하는 물리적, 화학적 장벽 역할을 한다[매디슨(Madison) 2003; 덴다(Denda) 2000]. 구조 를 동적으로 바꿀 수 있는 상피는 대략 45일마다 재생되며, 빽빽하게 채워진 비늘 같 은 세포로 구성된다. 상피는 눈꺼풀이 가장 얇고(0.05mm), 손바닥과 발바닥이 가장 두껍다(1.5mm)[NIH, 2006].</p>
<p>두 번째 층은 진피층이라고 하는데, 상피를 지지하며 피부 두께의 약 80%를 차지한 다. 진피층은 주로 모낭, 분비선, 혈관, 신경, 감각 수용 기관이 있는 결합 조직(콜라 겐으로 구성된다. 이 콜라겐이 피부에 탄력을 주며, 몸에서는 구조적으로 쿠션 역할을 한다[바운들리스(Boundless) 2015]. 위치에 따라 두께도 다른(1.5~4mm) 진피층에는 매 우 혈관이 많아, 모두 합치면 17km를 넘는다자블론스키(Jablonski) 2013]. 이 정맥망은 피 부에 산소와 양분을 공급하며, 피부의 치유와 체온 조절 과정에서 중요한 역할을
한다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/6e7531be-cf8d-4b4c-9fcb-a2e2be88e6e3/image.jpg" alt=""></p>
<p>그림 9.1 두 개의 주요 층과 그 밑에서 숨은 에너지 보유고 역할을 하며 지방을 축적하고 저장하는 데 특화된 세포의 지지 구조를 상세하게 보여주는 사람의 피부 단면
출처: 이미지 gunitaⓒ 123RF.com</p>
<p>세 번째로 가장 안쪽 층(기술적으로는 피부의 일부로 간주하지 않음)은 하피, 혹은 피하 조직이라고 한다. 이 층은 주로 지방을 축적하고 저장하는 데 특화된 세포로 구성된 다. 피하 조직은 진피층을 근육과 뼈에 붙이고 신경과 혈관을 진피층에 공급하는 역 할도 한다. 여러 감각 수용 기관도 이 층에 있다.</p>
<p>촉각의 인지
촉감은 능동적 접촉을 통해서나내슨(Gibson) 1962] 친구와의 접촉, 비행 시뮬레이터에 서 사용하는 베이스 키커bass kicker로부터 나오는 저주파 톤, 불꽃에서 나오는 열기 등 몸에 가해지는 외력에서 경험하는 자극과 물리적 접촉으로 촉발되는 특화된 피부 수 용기관(피부 내에 있음)이 만들어내는 감각 정보에서 출발한다.
눈과 귀에 있는 감각수용기와 비슷하게 피부의 수용기도 효과적으로 기계적 자극, 온도에너지 등 에너지를 전기신호(신경충동)로 변환하므로 변환기로 간주할 수 있 다. 촉감에 관여하는 수용 기관의 유형은 주로 세 범주로 구분된다. 통각수용기 (고통 을 만드는 자극을 감지), 온도 수용기 (온도 관련 자극 감지), 그리고 이 책의 주제와 가장 연관된 기계적 자극 수용기(기계적 자극, 물리적 상호작용 감지)다.</p>
<p>기계적 감각수용기
그림 9.2처럼 사람의 피부에는 특히 주변과의 물리적 상호작용에서 나온 다양한 기 계적 자극에 반응하는 네 가지 주요 수용기인 메이스너 소체, 메르켈 디스크, 파시니 안 소체, 루피니 말단이 있다. 기계적 자극 수용기라고 하는 이 센서들은 촉각, 압력, 진동, 피부 긴장의 정보를 신경계로 보낸다[퍼브즈(Purves) 등 2001]. 넷 모두 낮은 역치의 (매우 민감한) 수용기로도 분류되는데, 각각 약한 기계적 자극에 반응하기 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/576f336f-287c-4771-b002-976ba261b2b6/image.jpg" alt=""></p>
<p>모든 기계적 자극 수용기는 기본적으로 같은 방식으로 기능한다.</p>
<ol>
<li>외부의 자극이나 힘이 피부 표면에 작용한다.</li>
<li>기계적 자극 수용기를 자극하면 힘은 피부 더 깊이 전달된다.</li>
<li>기계적 자극 수용기는 행동 잠재력(전기적 충격)을 발생시킨다.</li>
<li>행동 잠재력은 중앙 신경계에 구심성 신경을 따라 전달돼 무의식적 인지나 행
동 반응, 혹은 둘 모두를 일으킨게프니(Geffeney)와 굿맨(Goodman) 2012].</li>
</ol>
<p>기계적 자극 수용기의 분류
이제 기계적 자극 수용기의 네 가지 유형을 적응률과 수용 영역의 크기라는 두 가지 기준으로 나눠 살펴보자.</p>
<p>적응률
기계적 자극 수용기는 사람 몸의 다른 감각수용기와 마찬가지로 적응이라고 알려진 흥미로운 특성이 있다. 자극이 피부에 작용하면, 적절한 기계적 자극 수용기가 구심 신경(수용기나 감각 기관에서 나온 자극을 중앙 신경계에 전달하는 신경)을 따라 일련의 초기 자극을 발동해 반응하며, 외부의 자극이나 환경의 변화를 알린다. 자극이나 조 직의 이동이 강할수록 신경 반응의 주파수도 더 커진다[니베스톨(Knibestol) 1973]. 이 반응 은 압력과 함께 로그 함수의 형태로 증가한다는 것이 입증됐다[무니악(Muniak) 등 2007]. 수용기가 얼마나 빨리 적응하거나 수동적 상태로 돌아가는지는 그 종류에 따라 다르 다. 느리고 빠르게 적응하는 기계적 자극 수용기 뒤에 숨은 기본 개념은 그림 9.3과 같다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/f65f9e7a-17ad-4c2b-8ef4-598a49ba1abf/image.jpg" alt=""></p>
<p>그림 9.3 감각 적응의 기본 개념과 지속적 자극에 대해 기계적 자극 수용기의 반응성이 보이는 장기적 변화를 묘사한 그림. 느리게 적응하는 수용기는 자극이 존재하는 한 계속해서 발동된다. 빠르게 적응하는 수용기는 초기에는 빨리 반 응하지만 자극이 계속되면 발동을 중단하고, 자극이 제거되면 이를 알리기 위해 다시 발동된다.1 출처: S. 옥스타칼니스 일러스트레이션</p>
<p>느리게 적응하는 수용기(메르켈 디스크, 루피니 말단)는 SA라고도 하는데, 최초와 지 속적 압력, 가장자리와 강도, 그리고 피부 긴장(피부 늘어남)을 포함해 접촉력에 최적 화돼 반응한다[퍼브스 등 2001]. 책을 옆으로 들고 떨어뜨리지 않을 수 있는 것은 느리 게 적응하는 수용기가 반응하는 직접적 결과다. 손에 들고 있는 동안 우리는 문자 그 대로 책의 질량, 무게, 형태, 가장자리를 계속 인식한다. 이 인지는 지속적 감각 정보 의 흐름을 중앙 신경계에 전달하는 느리게 적응하는 기계적 자극 수용기에서 나온다. 빠르게 반응하는 수용기 (메이스너 소체, 파시니안 소체)는 RA라고도 하는데, 진동과 질 감의 변화 등 빠르게 변하는 자극에 최적으로 반응한다. 빠르게 적응하는 수용기 역 시 최초 접촉과 동작에 반응하지만, 지속적 압력에는 반응하지 않는다[탤보트(Talbot) 등 1968]. 물렁한 복숭아의 느낌과 콘크리트 표면을 구별할 수 있는 능력은 빠르게 적응하는 수용기에서 온다. 게임 컨트롤러와 스마트폰에서 찾을 수 있는 진동 촉감 디스플레이도 이 능력에 의존한다.</p>
<p>자극을 기준으로 보면 느리고 빠르게 적응하는 다양한 기계적 자극 수용기의 발동에 는 여러 가지가 있는데, 자세히 들어가면 이장의 범위와 의도를 벗어난다. 이 주제에 대한 추가 정보는 [요한슨(Johansson)과 발보(Vallbo) 1979, 1983, 2014], [발보와 요한슨 1984], [버지스(Burgess) 2012], [마티니(Martini) 등 2013], [하오(Hao) 등 2015]을 참고하자.]</p>
<p>출처: S. 옥스타칼니스 일러스트레이션</p>
<p>수용 영역과 기계적 자극 수용기의 분포
그림 9.4의 묘사처럼, 손이나 다른 곳의 피부 표면에서 기계적 자극 수용기의 수용 영역을 적절히 자극하면 개별 수용기의 반응을 촉발하게 된다. 수용 영역의 크기는 1~2mm에서부터 손가락과 손바닥의 상당 부분까지, 수용기의 종류와 위치에 따라 다양하다[코트럼(Kortum) 2008; 요한슨과 발보 1979]. 수용 영역이 가장 작은 수용기 (메르켈 디스크, 메이스너 소체)는 가장 밀도가 높으며 피부 표면에 가장 가까운 상피에 있다. 반면 가장 수용 영역이 큰 수용기(루피니 말단, 파시니안 소체)는 수가 더 적고, 피부 깊숙한 진피층과 피하층에 있다.</p>
<p>수용 영역의 이런 층과 중첩은 부엌 싱크대에서 커다란 수박을 들어 올리는 것부터 바늘에 실을 꿰거나 눈에 콘택트렌즈를 끼는 섬세한 일까지 온갖 수작업의 수행 능력 에서 중요한 역할을 한다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/df1eb4a0-dfc2-4b83-9d2e-670b134d6f2d/image.jpg" alt=""></p>
<p>그림 9.4 적절히 자극할 때 중첩하는 수용 영역의 피부 수용기는 중앙 신경계에 신호를 전달하는 구심 신경에서 행동
을 일으키도록 만든다.
출처: 손 이미지 julenochek ⓒ 123RF.com</p>
<p>수용기 분포와 공간 해상도
한 손의 털이 없는 피부에는 약 17,000개의 기계적 자극 수용기가 있는 것으로 추산 된다[발보와 요한슨 1984]. 흥미롭게도 촉각 인지는 손가락 크기가 작을수록 향상된다. 그 래서 여성의 촉감이 더 섬세하게 조율되고 민감하다[피터스(Peters) 등 2009]. 수용 영역 이 가장 작은 고밀도의 수용기 (메르켈 디스크, 메이스너 소체)는 공간 해상도가 가장 크기에, 모기가 물 때처럼 외부 자극이 피부에 작용하는 위치를 상당히 정확하게 확 인할 수 있다. 반면 수용 영역이 큰 저밀도 수용기 (루피니 말단, 파시니안 소체)는 공간 해상도가 상당히 낮다. 이 수용기는 힘이 피부의 &#39;어디에서&#39; 작용하는지 판단하는 정 확성은 떨어지지만, 빛의 접촉에는 훨씬 더 민감하다.</p>
<p>기계적 자극 수용기의 세부
네 가지 주요 기계적 자극 수용기 모두 크기, 모양, 정적 및 동적 자극의 감도 범위, 피부 내의 위치, 밀도, 기능의 특정 방식 등이 다양하다. 이 기능 모두 구체적으로 설 명하겠지만, 하나의 자극에도 다양한 기계적 자극 수용기의 반응에 상당한 중첩이 있 음을 잊지 말자. 일례로, 가상 환경에서 물체를 조작할 때 손에서 울리는 컨트롤러나 게임용 조끼가 진동해 가슴에서 느끼는 충격은 다양한 수용기의 반응을 유발하는데, 큰 압력, 피부가 당겨지는 느낌, 진동 감지 (질감 인지로 해석함) 등이 있다.</p>
<p>메르켈 디스크
메르켈 디스크는 구심신경 섬유에 붙은 원반 모양의 상피세포로, 특화된 감각 신경 의 말단이다. 보통 이 신경 섬유는 중간에서 큰 직경의 신경다발이 디스크 군집을 이 룬다[네터(Netter) 2013] 그림 9.6처럼, 메르켈 디스크는 일반적으로 상피와 진피층 사이 경계의 피부층에 있으며, 손가락을 형성하는 융기 아래 등에 있는 매끈한 피부에서 가장 많이 찾을 수 있다[베어(Bear) 등 2007, p389]. 적절한 자극이 주어지면 디스크벽이 변형되면서, 신경 섬유 안의 이온 채널이 열린다. 그러면 나트륨(Na+ 이온이 유입되 면서 행동 잠재력이 발동된다[막시모비치(Maksimovic) 등 2014].</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/486ff337-461d-4b16-a9cc-f00f8e463712/image.jpg" alt=""></p>
<p>그림 9.6 메르켈 디스크는 느리게 적응하며 가벼운 접촉과 진동에 민감하고, 5~15Hz 범위의 저주파에 최대로 반응한다. 출처: 일러스트 BruceBlaus, 위키미디어, CC BY 3.0 라이선스 의거 게재</p>
<p>반응의 특성</p>
<p>메르켈 디스크는 세밀한 표면 패턴과 지속적인 빛의 기계적 자극에 매우 민감한 느 리게 적응하는 (SA) 수용기로, 수용 영역이 작아서 점자 읽기 같은 활동에서 핵심적인 역할을 한다노박(Noback) 등 2005; 겐타즈(Gentaz) 2003] 메르켈 디스크 수용기는 저주파 (5~15Hz)에 최대로 반응한다[길먼(Gilman) 2002].</p>
<p>메이스너 소체</p>
<p>메이스너 소체(촉각 소체라고도 함)는 길쭉한 캡슐 같은 생김새가 특징이다. 이 소체 에는 비비 꼬이고 굽이치는 구심 신경 섬유인 수평으로 납작하게 쌓인 박편 세포가 있다(카우나(Cauna)와 로스(Ross) 1960]. 압력으로 소체가 변형되면 신경 섬유가 자극을 받 아 신경에서 행동잠재력이 만들어진다 [다히야(Dahiya) 등 2010] 자극이 제거되면 소체는 원래 형태로 돌아가, 또 다른 일련의 행동 잠재력을 낳는다[존슨(Johnson) 2001].</p>
<p>그림 9.7처럼 상피와 진피층간의 경계는 일정하지 않지만, 진피층에는 그 위상피 로 뻗어있는 피부 유두라는 작은 굴곡과 융기가 있다. 메이스너 소체는 피부 표면 근 처의 네 번째 돌기마다 존재한다[프라인켈(Freinkel)과 우들리(Woodley) 2001]. 메이스너 소체 밀도가 가장 높은 곳은 접촉에 가장 민감한 매끈한 피부에 있는데, 특히 손가락, 손바 닥,발바닥 등이다[요한슨과 발보 1979; 맥카시(McCarthy) 등 1995; 딜론(Dillon) 등 2001; 켈리(Kelly)등 2005].</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/e6dfc80f-8ea5-4633-a4e0-5d2e5c23b540/image.jpg" alt=""></p>
<p>그림 9.7 메이스너 소체는 피부 표면에 가까이 있으며 빠르게 적응하는 수용기로, 질감과 미끄러짐에 민감하고 중간 범위 주파수(20~50Hz)에서 최대로 반응한다.
출처: 일러스트 BruceBlaus, 위키미디어, CC BY 3.0 라이선스 의거 게재</p>
<p>반응의 특성</p>
<p>메이스너 소체는 빠르게 적응하며 (RA), 기계적 자극의 개시와 제거에 반응한다. 특히 질감이 있는 물체가 피부를 가로질러 이동하거나[퍼브즈 등 2001; 버지스(Burgess) 2012], 물 체의 미끄러짐[바커(Barker)와 시체티(Cicchetti) 2012], 그리고 탐구하고 구별하기 위한 접촉에서 변하는 형태[맨콜(Mancall)과 브록(Brock) 2011] 등의 변화하는 정보에 효율적이다. 메이스너 소체는 부드러운 면 셔츠에서 나오는[클라인(Klein)과 쏜(Thorne) 2006] 것 같은 중간 범위 주파수(20~50Hz)에 최대로 반응한다[길먼 2002].</p>
<p>파시니안 소체</p>
<p>파시니안 소체(층판 소체라고도 함)는 타원형 모양이 특징이며, 액체층으로 분리되는 섬유 결합 조직으로 이뤄진 집중적인 박판(얇은 층) 수십 개로 구성된다. 소체 전체는 외부가 콜라겐으로 싸여 있다. 소체 중앙은 구심 신경 섬유가 하나 이상으로 된 공동이 있다[퍼브스 등 2001].</p>
<p>외부의 힘으로 물리적 압력이 소체에 작용해 구조가 변형되면 중앙에 있는 신경 섬유 도 구부러지거나 확장돼, 이온 채널(화학적 관문을 외부막 쪽으로 열어 나트륨 이온 이 유입된다. 외부력이 더 클수록 소체의 변형이 더 커지고, 나트륨 이온 유입도 커져 중앙 신경계로 전달되는 구심 신경 섬유의 행동 잠재력이 발동된다.</p>
<p>기계적 자극 수용기의 네 가지 종류 중 파시니안 소체는 크기가 가장 크고 수는 가장 적다[칸델(Kandel) 2000]. 그림 9.8처럼 파시니안 소체는 피부 진피층 안에 깊숙이 위치 하고 피하 지방에도 분포한다.</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/90ea6b30-ac7b-429c-86b7-29ff4f04dbef/image.jpg" alt=""></p>
<p>그림 9.8 파시니안 소체는 빠르게 적응하며, 피부 내 깊숙이 위치한다. 또한 고주파 진동(200~300Hz 범위)과 지속적 이지 않은 깊은 압력에 민감하다.
출처: 일러스트 BruceBlaus, 위키미디어, CC BY 3.0 라이선스 의거 게재</p>
<p>반응의 특성</p>
<p>파시니안 소체는 메이스너 소체처럼 빠르게 적응하며(RA) 기계적 자극의 개시와 제거에 반응한다. 찌르기 같이 깊은 반응에 가장 민감하지만, 지속적인 압력에는 둔 하다. 200~300Hz 범위로 피부에 적용되는 고주파 진동에도 잘 반응하지만[베어 등 2007, p 391; 길먼 2002] 수용 영역의 크기가 작아 자극의 위치는 잘 파악하지 못한다.[노 백(Noback) 등 2005]. 파시니안 소체는 굉장히 민감해서, 계면 결합이 물로 이뤄질 때는
실제로 음파를 감지할 수 있다는 것이 입증됐다.[이드(Ide) 등 1987].</p>
<p>루피니 말단</p>
<p>루피니 말단(루피니 소체로도 알려짐)은 끝이 복잡한 나무 같은(그리스어 dendron) 어원인 수상 돌기) 방적기 형태가 특징이다. 이 구조 안에는 콜라겐 연결 조직에 포함 된 신경 말단이 밀도 높게 얽혀 있다.</p>
<p>그림 9.9처럼 루피니 말단은 피부 진피층 깊숙이 위치한다. 손바닥의 접힌 부분, 관절 위, 손톱 끝을 따라 가장 밀도가 높은데, 피부가 확장될 때 방적기 모양 캡슐에 싸여 있는 콜라겐 섬유가 신경 말단을 압축해 행동 잠재력이 발동된다[가드너(Gardner) 2010].</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/7b79fdbe-705a-475e-8f08-783140a61201/image.jpg" alt=""></p>
<p>그림 9.9 루피니 말단은 매우 느리게 적응하며, 지속적 압력과 피부 확장, 미끄러짐에 민감하고 고주파에 반응한다 (300~400Hz).
출처: 일러스트 BruceBlaus, 위키미디어, CC BY 3.0 라이선스 의거 게재</p>
<p>반응의 특성</p>
<p>루피니 말단은 느리게 적응하며(SA), 지속적 압력, 피부 확장, 미끄러짐에 민감하 고 손가락의 위치와 운동 제어에 기여한다[바레트(Barrett)와 가농(Ganong) 2012; 마운트캐슬 (Mountcastle) 2005]. 루피니 말단은 고주파(300~400Hz)에 최대로 반응하며, 적응률은
매우 작다[가이튼(Guyton)과 홀(Hall) 2001].</p>
<p>기계적 자극 수용기 능력 요약
앞서 설명한 내용을 기반으로 표 9.1, 그림 9.10은 네 가지 주요 기계적 자극 수용기 의 성능 특성을 요약한다.</p>
<p>표9.1
<img src="https://velog.velcdn.com/images/kiwi_100/post/fcb433b7-1e30-4acf-a878-db1d6662fc8d/image.jpg" alt=""></p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/f8214966-9bf7-495e-887a-a2e98937aad5/image.jpg" alt=""></p>
<p>그림 9.10 유형별로 손바닥과 손가락 피부에 있는 기계적 자극 수용기의 분포와 수용 영역 크기는 모두 다르다.
출처: 일러스트 BruceBlaus, 위키미디어, CC BY 3.0 라이선스 의거 게재. 손 이미지는 ratu © 123RF.com, S. 옥스타
칼니스 연구에서 발췌</p>
<p>지금까지 피부의 촉각 감각을 발동하는 감각수용기의 생리와 기본 기능을 알아봤다. 손가락이 물체를 만져볼 때 이 정보는 두뇌가 우리 주변의 물리적 특징에 대해 미묘 한 세부까지 이해할 수 있게 돕는다.
그러면 이제 마찬가지로 중요한 생리와 기본 기능을 감지하고 운동감을 담당하며 관 절의 각도와 근육, 힘줄이 느끼는 긴장과 여타 힘을 인지하는 감각 수용기를 간략히 알아보자. 이 책의 주제와 연관이 있는 사례는 고급 게임 조종간을 사용할 때 경험하 는 저항과 덜컹거림(포스 피드백이라 함)에서 찾을 수 있다.</p>
<p>운동감의 감지</p>
<p>운동감은 우리 몸에서 근육, 힘줄, 관절의 위치와 무게, 운동을 감지하게 해주는 감각 이다. 요컨대 신체를 인지하는 감각이다. 이 장의 앞에서 설명한 신체 감각 체계의 일 부인 운동감은 의식적 사고 없이 연속적으로 사용하는 감각이다. 이 감각은 통로에서 누군가를 지나칠 때 옆으로 비킬지(그리고 얼마나 비킬지), 비행기 중간 좌석에 자기 몸이 맞을지 결정하도록 돕는다. 계단을 걸어 내려갈 때는 두뇌에 단서를 주고(발목, 무릎, 엉덩이의 각도로), 농구를 할 때는 레이업 슛을 쏘도록 돕기도 한다.</p>
<p>이 감각 채널에 대한 이해는 10장, &#39;촉각과 포스 피드백 기기&#39; (주로 출력 기기)에서 논 하는 촉각과 포스 피드백 기기 영역의 연구 개발에도 도움이 되고, 사용자의 물리적 동작을 입력 방식으로 측정하는 시스템 실험도 있으므로 알아두자[폰토(Ponto) 등 2012].</p>
<p>자기 수용기</p>
<p>운동감의 핵심 측면은 자기 수용이라는 것이며, 이는 이동의 느낌, 관련된 힘의 강도, 몸에 닿는 부분의 상대적 위치에 대한 무의식적 감각이다[모스비(Mosby&#39;s) 1994]. 외부 자 극이 신경 반응을 촉발하는 기계적 자극 감지와는 상당히 다르게, 자기 수용기는 몸 자체가 감각 수용기에 대한 자극 역할을 한다[셰링턴(Sherrington) 1906]. 간단한 사례로는 눈을 감고도 팔이 옆에 있는지, 머리 위로 뻗었는지, 손가락을 벌렸는지, 무릎을 구부 렸는지 아는 것을 들 수 있다. 보거나 생각할 필요도 없다. 그냥 &#39;아는&#39; 것이다.</p>
<p>몸을 움직일 때, 의자에 앉은채 자세를 바꾸든, 다리를 꼬든, 걷든, 물체에 다가가든, 이런 동작은 모두 프로세스를 촉발하는 중앙 신경계의 신경 충동에서 시작한다. 이 런 움직임을 하는 동안 피부, 근육, 힘줄, 인대를 포함한 관절 조직은 형태를 바꾼에 이드리언(Adrian) 1929; 그리그(Grigg) 1994]. 그러면 이런 조직 속의 다양한 신경과 수용기는 발동을 시작한다.</p>
<p>연구에 따르면, 근방추와 골지 힘줄 기관이라는 두 개의 독특한 감각 신경이 보내 는 신호가 자기 수용감각에 핵심적인 역할을 한다[프로스케(Proske)와 간디비아(Gandevia) 2009, 2012].</p>
<p>근방추</p>
<p>근방추는 캡슐에 싸여있는 작고 길쭉한 감각 기관으로, 사람 몸의 거의 모든 골격근 에 있다[퍼브스(Purves) 등 2001] 그림 9.11 에서 볼 수 있듯, 근방추라는 이름은 실제 생 김새와 구조에서 나온 것이다. 근방추의 밀집도는 근육이 담당하는 기능에 따라 다양
한데, 섬세한 운동에 관련된 근육에 더 많이 분포한다[테일러(Taylor) 2006]</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/37a0481e-75e6-40f5-b1bf-de5c9bfc5cda/image.jpg" alt=""></p>
<p>그림 9.11 근방추는 방추외 근육 섬유에 평행하게 안쪽 깊이 있는 자기 수용기다.
출처: 이미지 N. Stifani, CC BY 4.0 라이선스 의거 배포, S 오스타칼니스의 연구에서 따옴</p>
<p>메이스너나 파시니안 소체와 마찬가지로 근방추의 주 구성원은 콜라겐 캡슐이다. 이 캡슐에 일반 근섬유와 평행한 방향으로 특화된 방추외근섬유가 있는데, 그 주위로는 고리나선신경종말이라는 구심 신경 말단(수상돌기)이 말려 있다.</p>
<p>일반적인 근섬유가 확장할 때는 방추외 섬유의 긴장이 커져서 이온 관문이 열리고, 고리나선신경종말을 자극하게 된다. 그러면 행동 잠재력이 발동한다. 긴장이 더 클수 록 발동되는 충동의 빈도 역시 커진다. 이 충동은 빠르게 중앙 신경계에 도달하고, 반 환 신호가 전송돼 근육의 신장 가능 범위를 제어하며, 이 과정이 근육 손상을 방지한 [프로차즈카(Prochazka) 1980; 셔우드(Sherwood) 2015]</p>
<p>골지 힘줄 기관</p>
<p>확장을 측정하는 근방추와 달리, 또 다른 감각 수용기인 골지 힘줄 기관은 힘줄(근육 과 뼈를 연결하는 튼튼한 섬유)의 긴장도를 측정한다. 야구공을 들든 무거운 짐을 들든 물체를 들어 올릴 때, 아니면 외력에 의해 손발이 작용할 때 골지 힘줄 기관은 근육이 얼마나 많은 긴장을 행사 중인지 알려준다. 10장에서 논할 포스 피드백 기기의 관점 에서 골지 힘줄기관은 손이나 팔다리에 많은 힘이 전달되고 있는지 알려주는 센서다. </p>
<p>근방추는 그림 9.12처럼 실제 근섬유 안에 있지만, 골지 수용기는 근육을 뼈에 연결 하는 힘줄에 있다. 골지 수용기의 핵은 일반적인 근섬유 방향과 평행한 콜라겐 섬유 로 구성된다. 콜라겐 섬유에는 구심 신경 섬유가 엮여 있다. 근육이 늘어나면 힘줄 속 에 긴장이 생긴다. 그러면 이 긴장이 콜라겐 섬유를 바짝 당기고, 구심 신경을 자극한 다. 콜라겐 섬유의 긴장도에 따라 신경의 발동률은 변화한다. 그러면 이 신호는 물리 적 출력을 변조해준다[그레이(Grey) 등 2007; 밀류스닉(Mileusnic)과 로엡(Loeb) 2006].</p>
<p><img src="https://velog.velcdn.com/images/kiwi_100/post/7deb7f72-f433-4c5f-b351-9214fb9797e3/image.jpg" alt=""></p>
<p>그림 9.12 골지 힘줄 기관은 콜라겐 섬유들 사이에 엮인 감각 신경 말단으로 구성된다. 근육이 늘어나 힘줄에 긴장이 가해지면 콜라겐 섬유가 신경을 자극한다.
출처: 공공 부문에서 빌어온 연구 이미지, 위키미디어 컨클루전의 신경학에서 발췌</p>
<p>결론
이 장에서는 두뇌가 물체와 환경의 물리적 형태의 섬세한 세부를 이해하도록 피부의 촉각을 발동하는 감각 기관부터 몸에 작용하는 더 강한 기계적 힘을 인지할 수 있는 감각 기관까지, 촉감을 가능하게 하는 우리 몸의 주요 장치를 알아봤다. 10장에서는 더 직관적인 인간-기계 인터페이스가 가능한 프로세스와 메커니즘을 활용하는 다양 한 기술과 기기를 알아보자.</p>
<pre><code>                                                   출처 - 실전 증강 현실(스티븐 옥스타칼니스 지음)</code></pre>]]></description>
        </item>
    </channel>
</rss>