<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>UpWrite</title>
    <link>https://lypicfa.tistory.com/</link>
    <description>그냥 내가 쓰고 싶은 글 쓰는 곳</description>
    <language>ko</language>
    <pubDate>Sun, 31 May 2026 05:47:08 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>라이피 (Lypi)</managingEditor>
    <image>
      <title>UpWrite</title>
      <url>https://tistory1.daumcdn.net/tistory/941216/attach/9df2787f42ea4b168614ea80b7d2f495</url>
      <link>https://lypicfa.tistory.com</link>
    </image>
    <item>
      <title>수학. 곱셈 공식과 인수 분해</title>
      <link>https://lypicfa.tistory.com/689</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;대수식을 간단하게 만들기 위해서 외워두어야 하는 공식들.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-02-15 211906.png&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwllTR/btrZqGvRX7D/RnAUbkKZAnWcUizqZmgmA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwllTR/btrZqGvRX7D/RnAUbkKZAnWcUizqZmgmA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwllTR/btrZqGvRX7D/RnAUbkKZAnWcUizqZmgmA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwllTR%2FbtrZqGvRX7D%2FRnAUbkKZAnWcUizqZmgmA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1716&quot; height=&quot;278&quot; data-filename=&quot;화면 캡처 2023-02-15 211906.png&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;곱셈공식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복부호 동순&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;01) \( (a&amp;plusmn;b)^2 = a^2&amp;plusmn;2ab+b^2 \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;02) \( (a+b)(a-b) = a^2-b^2 \)&amp;nbsp; 중요&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;03) \( (x+a)(x+b)(x+c) = x^3+(a+b+c)x^2+(ab+bc+ca)x + abc \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;04) \( (a+b+c)^2 = a^2+b^2+c^2+2(ab+bc+ca) \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;05) \( (a&amp;plusmn;b)^3 = a^3&amp;plusmn;3a^2b+3ab^2&amp;plusmn;b^3 \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;06) \( (a+b)(a^2-ab+b^2)=a^3+b^3 , (a-b)(a^2+ab+b^2)=a^3-b^3 \) 중요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;07) \( (a+b+c)(a^2+b^2+c^2-ab-bc-ca) = a^3+b^3+c^3-3abc \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;08) \( (a^2+ab+b^2)(a^2-ab+b^2) = a^4+(ab)^2+b^4 \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;02)는 \(a^2-b^2\)을 인수분해할 때 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;03)는 3차식의 인수분해에 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;06)은 \(a^3&amp;plusmn;b^3\)을 인수분해할 때 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11) \(a^2+b^2 = (a+b)^2-2ab = (a+b)(a-b)+2b^2 =(a-b)^2+2ab \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12) \(a^3+b^3 = (a+b)^3-3ab(a+b) \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인수분해&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복부호동순&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;01) \( a^2&amp;plusmn;2ab+b^2 = (a&amp;plusmn;b)^2 \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;02) \( a^2-b^2 = (a+b)(a-b) \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;03) \( a^3+b^3 = (a+b)(a^2-ab+b^2) , a^3-b^3 = (a-b)(a^2+ab+b^2) \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;04) \( a^3 &amp;plusmn; 3a^2b + 3ab^2 &amp;plusmn; b^3) = (a&amp;plusmn;b)^3 \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;05) \( a^2+b^2+c^2+2(ab+bc+ca) = (a+b+c)^2 \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;06) \( a^4+(ab)^2+b^4 = (a^2+ab+b^2)(a^2-ab+b^2) \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;07) \( a^3+b^3+c^3 - 3abc = (a+b+c)(a^2+b^2+c^2-ab-bc-ca) \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>공부 중 메모/고교 기초 수학</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/689</guid>
      <comments>https://lypicfa.tistory.com/689#entry689comment</comments>
      <pubDate>Thu, 16 Feb 2023 00:34:02 +0900</pubDate>
    </item>
    <item>
      <title>C&amp;amp;C++ a1 동적할당 연습</title>
      <link>https://lypicfa.tistory.com/688</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;동적할당.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GISwb/btrZoqs9vnp/XC0B6dE6sQtqwaQLLxOjU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GISwb/btrZoqs9vnp/XC0B6dE6sQtqwaQLLxOjU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GISwb/btrZoqs9vnp/XC0B6dE6sQtqwaQLLxOjU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGISwb%2FbtrZoqs9vnp%2FXC0B6dE6sQtqwaQLLxOjU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;151&quot; data-filename=&quot;동적할당.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1676381753944&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string.h&amp;gt;
using namespace std;

int main()
{
    char name0[100];
    int nameVolume = 1;
    char** nameList = new char*[nameVolume];
    int count = 0;

    while(true) {
        cout &amp;lt;&amp;lt; &quot;너의 이름에는 힘이 있다. 이름을 입력하라.&quot; &amp;lt;&amp;lt; endl;
        cin &amp;gt;&amp;gt; name0;
        

        if(strcmp(name0, &quot;EXIT&quot;) == 0) {
            return 0;
        }

        nameList[count] = new char[strlen(name0)+1];
        strcpy(nameList[count],name0);

        cout &amp;lt;&amp;lt; &quot;현재 저장된 이름의 갯수&quot; &amp;lt;&amp;lt; endl &amp;lt;&amp;lt; count+1 &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; &quot;현재 저장된 이름 목록&quot; &amp;lt;&amp;lt; endl;

        for (int i = 0; i &amp;lt;= count; i++) {
            cout &amp;lt;&amp;lt; nameList[i] &amp;lt;&amp;lt; endl;
        }

        if(count+1 &amp;gt;= nameVolume) {
            nameVolume++;
            char* tempList[nameVolume];
            memcpy(&amp;amp;tempList, &amp;amp;nameList, sizeof(nameList));
            nameList = new char*[nameVolume];
            memcpy(&amp;amp;nameList, &amp;amp;tempList, sizeof(tempList));

        }
        cout &amp;lt;&amp;lt; &quot;끝내려면 EXIT&quot; &amp;lt;&amp;lt; endl;
        count++;
    }

    for (int i = 0; i &amp;lt; count; i++) {
        delete nameList[i];
    }
    delete[] nameList;

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆&amp;nbsp; 버퍼에 문자열을 입력받고 이름의 길이만큼 문자열 배열을 동적할당 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆&amp;nbsp; 이를 저장하기 위한 리스트를 1개씩 동적할당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆&amp;nbsp; 1개씩 하면 매번 새로운 이름을 입력할 때 마다 동적할당을 반복해야해서 퍼포먼스가 떨어지지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆&amp;nbsp; 이번에는 연습이니까 확인을 쉽게 하기 위해서 매번 해주도록 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆&amp;nbsp; 5개씩 하려고 하니까 세그멘테이션 오류가 떳다...&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;◆&amp;nbsp;&lt;span&gt; 사실 C++을 쓰면 string과 Vector를 쓰면 해결될 문제.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆&amp;nbsp;&lt;span&gt;&lt;span&gt; 물론 string과 Vector를 공부해야함...&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>리메이크 중/C,C++ 실습 중심</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/688</guid>
      <comments>https://lypicfa.tistory.com/688#entry688comment</comments>
      <pubDate>Tue, 14 Feb 2023 23:19:28 +0900</pubDate>
    </item>
    <item>
      <title>C(&amp;amp;C++) 이론 20. 동적 할당</title>
      <link>https://lypicfa.tistory.com/687</link>
      <description>&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;동적할당.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ld2uP/btrZaiap0a0/FcGk9UN2h2DknI0zTzUfA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ld2uP/btrZaiap0a0/FcGk9UN2h2DknI0zTzUfA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ld2uP/btrZaiap0a0/FcGk9UN2h2DknI0zTzUfA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fld2uP%2FbtrZaiap0a0%2FFcGk9UN2h2DknI0zTzUfA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;151&quot; data-filename=&quot;동적할당.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: right; font-size: 10pt; color: black;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내용 참고&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right; font-size: 10pt; color: black;&quot; data-ke-size=&quot;size16&quot;&gt;C++ 기초플러스 4판 (성안당)&lt;/p&gt;
&lt;p style=&quot;text-align: right; font-size: 10pt; color: black;&quot; data-ke-size=&quot;size16&quot;&gt;혼자 연구하는 C/C++ (Soen.kr/와우북스)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;동적 할당&lt;/b&gt;&lt;/h1&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 동적 할당이란 프로그래밍 시점에서는 메모리가 얼마나 필요한지 알 수 없어 실행 중에 메모리를 할당하는 것을 말한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;■&amp;nbsp;&lt;span&gt; 예를 들어 주소록을 저장하는 배열을 만들어야 하는데, 몇명이나 저장해야 할지 모를 때 동적할당을 사용한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;■&amp;nbsp; 동적할당 대신에 충분히 큰 배열을 만들어 놓으면 대처할 수는 있겠지만 이 경우에는 메모리 낭비가 극심할 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h2 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; C언어에서는 동적할당을 위해서 malloc()과 free()라는 함수를 사용했다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; C++에서는 언어에서 지원하는 new와 delete라는 전용 연산자를 사용한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; C++의 명령어가 더 사용이 편하고 직관적이기 때문에 주로 C++의 방법이 사용된다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 여기서 free()와 delete는 할당받은 메모리를 반납하는 역할을 한다.&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅰ. C언어의 경우&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; C언어에서 임의의 크기를 갖는 int형 배열을 동적할당하고 싶다면 아래와 같이 쓰면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1676279681153&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int* pi;
int num;

pi = (int*)malloc(num * sizeof(int));

free(pi);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 일반 배열이면 변수인 num으로 크기 지정을 할 수 없기 때문에 동적할당을 해야한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; malloc() 함수는 void형 포인터를 반환하므로 필요한 타입으로 캐스팅이 필요하다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; malloc() 함수의 인자로는 동적할당 받을 크기를 넣어줘야 하므로 갯수 * 타입의 크기를 계산해서 넣는다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 마지막에 동적할당받은 메모리를 free() 함수로 반환한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; free() 함수의 인자로 동적할당 받은 포인터를 넘기면 된다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 위의 예제의 전체 코드는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1676280050829&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

int main()
{
    int* pi;

    int num;
    cin &amp;gt;&amp;gt; num;

    pi = (int*)malloc(num * sizeof(int));

    for (int i = 1; i &amp;lt;= num; i++) {
        pi[i-1] = i;
        cout &amp;lt;&amp;lt; pi[i-1] &amp;lt;&amp;lt; endl;
    }

    free(pi);

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; num 변수에 임의의 수를 입력받아 int형 포인터인 pi에 그만큼의 사이즈를 동적할당 받았다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 동적할당된 배열에는 간단하게 차례대로 1부터 num까지의 숫자를 저장한뒤 출력했다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅱ. C++의 경우&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; C++에서 임의의 크기를 갖는 int형 배열을 동적할당하고 싶다면 아래와 같이 쓰면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1676280375264&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int* pi;
int num;

pi = new int[num];

delete[] pi;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; new 연산자의 뒤에 어떤 타입을 몇개 받을지 적어주면 끝이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 뒤에 타입을 적기 때문에 따로 캐스팅할 필요가 없으며, 크기 계산도 필요 없어졌다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 주의할 점은 new int; 로 int형 한개를 동적할당 받는 경우에는 delete pi;로 반환하지만,&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 위와 같이 new int[num];으로 임의의 갯수를 배열로 할당받는 경우에는 delete[] pi;로 반환해야 한다는 것이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; new와 delete, new (타입)[]와 delete[]의 두쌍이 있다고 생각하는게 좋다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; delete를 빠트리거나 잘못 쓸 경우 컴파일 에러가 나지 않고, 메모리가 누수되므로 작성 시점에서 주의해야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1676280812002&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

int main()
{
    int* pi;

    int num;
    cin &amp;gt;&amp;gt; num;

    pi = new int[num];

    if (pi != NULL) {
        for (int i = 1; i &amp;lt;= num; i++) {
            pi[i-1] = i;
            cout &amp;lt;&amp;lt; pi[i-1] &amp;lt;&amp;lt; endl;
        }
    }

    delete[] pi;

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 할당에 실패할 경우 null포인터를 반환하므로 위에서는 if문으로 예외처리를 해주었다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;</description>
      <category>리메이크 중/C,C++ 이론 중심</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/687</guid>
      <comments>https://lypicfa.tistory.com/687#entry687comment</comments>
      <pubDate>Mon, 13 Feb 2023 18:38:15 +0900</pubDate>
    </item>
    <item>
      <title>C(&amp;amp;C++) 이론 19. 이중 포인터</title>
      <link>https://lypicfa.tistory.com/685</link>
      <description>&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/evcBZW/btrYTgKZ7k0/2VekoTxD9yil0acA8FwYhK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/evcBZW/btrYTgKZ7k0/2VekoTxD9yil0acA8FwYhK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/evcBZW/btrYTgKZ7k0/2VekoTxD9yil0acA8FwYhK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FevcBZW%2FbtrYTgKZ7k0%2F2VekoTxD9yil0acA8FwYhK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;272&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: right; font-size: 10pt; color: black;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내용 참고&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right; font-size: 10pt; color: black;&quot; data-ke-size=&quot;size16&quot;&gt;혼자 연구하는 C/C++ (Soen.kr/와우북스)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;이중 포인터&lt;/b&gt;&lt;/h1&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 이중 포인터란 포인터를 가리키는 포인터라는 의미이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; int** ppi; 라고 쓰면 이중 포인터가 되고, int*** pppi; 라고 쓰면 3중 포인터가 될 것이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 원한다면 10중 포인터나 그 이상도 만들 수 있지만 3중 포인터 이상은 딱히 의미가 없다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h2 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; T형 타입에 대한 T형 포인터를 만들 수 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; T형 포인터는 하나의 타입으로 인정된다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 즉, T형 포인터에 대한 포인터를 만들 수 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 이런식으로 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1676179922082&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

int main() 
{
  int i = 1234; 
  int* pi = &amp;amp;i; 
  int** ppi = &amp;amp;pi;
  
  cout &amp;lt;&amp;lt; **ppi &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 여기서 주의할 점은 int* pi = &amp;amp;i; 상태에서 int** ppi = &amp;amp;pi;는 가능하지만, int** ppi = &amp;amp;&amp;amp;i;는 안된다는 것이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 포인터 안의 값을 읽어내는 * 연산자는 중복 사용이 가능하지만, 주소값을 저장하는 &amp;amp; 연산자는 중복 사용이 안된다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 왜냐하면 &amp;amp;i 의 리턴값은 아직 메모리에 저장되지 않은 값일 뿐이기 때문이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 그래서 이 값을 int* pi; 라는 메모리 안에 담고 그 메모리 주소를 저장해야 한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 대신에 * 연산자는 주소값의 실제 위치에서 값을 뽑아오므로 int* pi; 안에 주소값이 있다면 연속으로 접근이 가능하다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 이중 포인터는 문자열이나 배열처럼 그 자체가 포인터인 값을 이용할 때 유용하다.&lt;/p&gt;
&lt;pre id=&quot;code_1676181356870&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string.h&amp;gt;

using namespace std;

void InputName(char** pName) 
{
  *pName= new char;
  strcpy(*pName, &quot;Cabin&quot;);
}

int main()
{
  char* name;
  
  InputName(&amp;amp;name);
  cout &amp;lt;&amp;lt; name &amp;lt;&amp;lt; endl;
  
  delete name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; &amp;nbsp;void InputName(char** pName) 함수는 문자열인 char* 타입의 주소를 인자로 받는 함수이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; *pName;은 인자로 받은 char* 타입을 의미하며 new로 char형을 동적할당하면 char* 값이 리턴된다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 문자열인 char* 의 주소는 char** 타입이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 이 부분은 참조 호출이 필요한 부분이기 때문에 주소로 주고받아야 하는 것이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;</description>
      <category>리메이크 중/C,C++ 이론 중심</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/685</guid>
      <comments>https://lypicfa.tistory.com/685#entry685comment</comments>
      <pubDate>Sun, 12 Feb 2023 15:03:22 +0900</pubDate>
    </item>
    <item>
      <title>C(&amp;amp;C++) 이론 18. 포인터 응용</title>
      <link>https://lypicfa.tistory.com/684</link>
      <description>&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;watercolor-g64da1cf13_1920.jpg&quot; data-origin-width=&quot;1403&quot; data-origin-height=&quot;299&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o67Z8/btrWxslHS6U/fHjZO8ezLjRek1BPnYoHDK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o67Z8/btrWxslHS6U/fHjZO8ezLjRek1BPnYoHDK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o67Z8/btrWxslHS6U/fHjZO8ezLjRek1BPnYoHDK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo67Z8%2FbtrWxslHS6U%2FfHjZO8ezLjRek1BPnYoHDK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1403&quot; height=&quot;299&quot; data-filename=&quot;watercolor-g64da1cf13_1920.jpg&quot; data-origin-width=&quot;1403&quot; data-origin-height=&quot;299&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: right; font-size: 10pt; color: black;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내용 참고&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right; font-size: 10pt; color: black;&quot; data-ke-size=&quot;size16&quot;&gt;혼자 연구하는 C/C++ (Soen.kr/와우북스)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포인터 응용&lt;/b&gt;&lt;/h1&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 포인터의 기본 개념은 단순한 만큼 파생될 수 있는 내용이 많다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 특히 포인터와 메모리에 대한 내용과 이중 포인터, 포인터 배열, 배열 포인터, 함수 포인터 등이 중요하다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 여기서는 *ptr++ 표현에 대한 내용과 void형 포인터에 대한 내용을 담았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h2 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Ⅰ. *ptr++&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 처음보면 당황스러울 수 있는 표현이다.&amp;nbsp;차근차근 분석해보자.&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅰ. 예제&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1673956024043&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

int main()
{
    int ar[] = {1,2,3,4,5};

    int arMAX = sizeof(ar)/sizeof(ar[0]);

    //배열의 이름은 상수 포인터로 배열의 첫번째 요소를 가리키지만, 
    //sizeof() 연산자에서는 배열 전체의 크기를 리턴한다.
    
    int* ptr;

    //*ptr++은 포인터의 값을 리턴하고 다음 요소로 하나씩 넘어간다.
    ptr = ar;  
    for (int i = 0; i &amp;lt; arMAX; i++) {
        cout &amp;lt;&amp;lt; &quot;ptr = &quot; &amp;lt;&amp;lt; *ptr++ &amp;lt;&amp;lt; &quot; &quot;;
    } 
    cout &amp;lt;&amp;lt; endl;

    //*ptr++을 풀어쓰면 다음과 같다.
    ptr = ar;  
    for (int i = 0; i &amp;lt; arMAX; i++) {
        cout &amp;lt;&amp;lt; &quot;ptr = &quot; &amp;lt;&amp;lt; *ptr &amp;lt;&amp;lt; &quot; &quot;;
        ptr++;
    } 
    cout &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅱ.&amp;nbsp; 포인터로서의 배열의 이름과 sizeof()&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 앞에서 언급했지만 배열의 이름은 포인터 상수이며, 배열의 첫번째 요소를 가리킨다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 즉, int* ptr = ar; 과 int* ptr = &amp;amp;ar[0];은 같다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 하지만 배열의 이름을 sizeof()로 계산하면 배열의 전체 크기가 나온다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 그러므로 sizeof(ar)은 배열의 전체 크기를 반환하고 sizeof(ar[0])은 배열 요소 하나의 크기를 반환한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅲ. (*ptr)과 (ptr++)을 합치면 *ptr++&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; *ptr++; 는 1) *ptr;로 포인터 ptr이 가리키는 값을 리턴하고, 2) ptr++로 다음 주소의 요소로 이동한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 왜냐하면 후위 증감 연산자는 값이 리턴된 뒤에야 계산되기 때문이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 이 표현은 공식 문서 등에서도 많이 사용되는 표현이기 때문에 알아둘 필요가 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Ⅱ. void형 포인터&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; C 및 C++에서 void는 타입이 없음을 나타내는 예약어이다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 일반 변수를 선언할 때는 당연히 쓸 수 없고, 함수와 포인터에만 쓸 수 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; void형 포인터는 일반 포인터와는 다른 특성을 갖는다.&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅰ. 임의의 대상체를 가리킬 수 있다.&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; void형 포인터는 일반 포인터와는 달리 임의의 대상체를 가리킬 수 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 이때 명시적인 캐스팅은 필요로 하지 않는다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 반대로 일반 포인터에 void형 포인터를 대입할 때는 반드시 명시적인 캐스팅을 해야한다. (C++ 기준)&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅱ. 대상체의 값을 바로 가져올 수 없다.&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; void 포인터인 상태로는 대상체가 무슨 타입인지 모르기 때문이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 대신에 명시적 캐스팅을 한 상태에서는 대상체의 값을 가져올 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1674030488198&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

int main()
{
    void* vp;

    int i = 68;
    char c = 'k';
    float f = 0.1;

    vp = &amp;amp;i;
    //cout &amp;lt;&amp;lt; *vp &amp;lt;&amp;lt; endl; // 에러
    cout &amp;lt;&amp;lt; *(int*)vp &amp;lt;&amp;lt; endl;

    vp = &amp;amp;c;   
    cout &amp;lt;&amp;lt; *(char*)vp &amp;lt;&amp;lt; endl;

    vp = &amp;amp;f;
    cout &amp;lt;&amp;lt; *(float*)vp &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 이렇게 대상체의 타입을 정확하게 알고, 그 타입의 포인터로 캐스팅을 하면 사용할 수 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅲ. 증감 연산자를 사용할 수 없다.&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 대상체의 값을 가져올 수 없는 것과 같은 이유이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 대상체의 타입을 모르므로 얼마나 이동해야하는지 모르기 때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1674031965667&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

int main()
{
    int ar[] = {1,2,3,4};

    int arMAX = sizeof(ar)/sizeof(ar[0]) - 1;

    void* vp = ar;

    for (int i = 0; i &amp;lt;= arMAX; i++) {
        cout &amp;lt;&amp;lt; *(int*)vp &amp;lt;&amp;lt; endl;      //윗 내용
        vp = (int*)vp + 1; //이번 내용
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; void형 포인터를 이용하여 증감 연산자처럼 쓰고 싶으면 위의 방법밖에 없다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅳ. 정리&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; void형 포인터는 대상체가 정해져 있지 않으므로 임의의 번지를 지정하는 것만 가능하다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; void형 포인터는 *연산자로 값을 읽거나, 증감 연산자를 사용하려면 반드시 명시적 캐스팅이 필요하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Ⅲ. NULL 포인터&lt;/b&gt;&lt;/h2&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅰ. 정의&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; null 포인터란 포인터에 저장된 주소값이 null, 즉 0인 포인터이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 주소값이 0이라는 소리는 절대 주소로 메모리 번호가 0인 위치이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; #define NULL 0 이라는 명령어로 숫자 0 대신 NULL을 사용하는 것이 더 직관적이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 헤더파일에 정의되어 있으므로 직접 정의해야할 일은 거의 없을 것이다.&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅱ. 실제 의미&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 절대 번지가 0인 메모리는 시스템 영역이기 때문에 응용 프로그램에서 이 위치를 건드려서는 안된다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 그래서 null 포인터는 에러를 나타내도록 약속되어 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 포인터를 반환하는 함수들은 에러가 발생했을 때 이 NULL값을 리턴한다.&lt;/p&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ⅳ. 예외 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; null은 0이기 때문에 에러 상황에서 반환된 값을 그대로 사용하면 문제가 생길 여지가 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 그래서 포인터를 반환하는 함수가 null을 반환하는지 확인하는 예외 처리를 할 필요가 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 예를 들어 문자열의 특정 문자를 찾아서 변환하는 함수인 strchr() 함수의 경우를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1676177973914&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string.h&amp;gt;

int main() 
{
  char str[] = &quot;korea&quot;;
  char *p;
  
  p = strchr(str,'s');
  //if(p != NULL) {
    *p = 'r';
  //}
  puts(str);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;font-size: 12pt; margin-left: 2em;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 8번째 줄에서 char형 포인터에 strchr() 함수의 반환값을 담고 있다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; &quot;korea&quot; 라는 문자열에는 's'가 없으므로 strchr() 함수는 null값을 반환할 것이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 4em; font-size: 10pt;&quot; data-ke-size=&quot;size16&quot;&gt;■&amp;nbsp; 여기서 if문으로 예외처리를 하지 않았다면 10번째 줄은 0번지의 값을 변경하려고 시도해서 런타임 에러가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;</description>
      <category>리메이크 중/C,C++ 이론 중심</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/684</guid>
      <comments>https://lypicfa.tistory.com/684#entry684comment</comments>
      <pubDate>Wed, 18 Jan 2023 18:09:25 +0900</pubDate>
    </item>
    <item>
      <title>C(&amp;amp;C++) 실습 13. 테트리스 개작</title>
      <link>https://lypicfa.tistory.com/683</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-01-13 192056.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vesGm/btrWpYZ1XII/0gyxL7G181hCDz83AwSDJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vesGm/btrWpYZ1XII/0gyxL7G181hCDz83AwSDJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vesGm/btrWpYZ1XII/0gyxL7G181hCDz83AwSDJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvesGm%2FbtrWpYZ1XII%2F0gyxL7G181hCDz83AwSDJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;80&quot; data-filename=&quot;화면 캡처 2023-01-13 192056.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;출처&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;soen.kr&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;pre id=&quot;code_1673862766875&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;Turboc.h&quot;

//키 바인딩
#define LEFT 75
#define RIGHT 77
#define UP 72
#define DOWN 80
#define ESC 27
#define PGUP 73
#define PGDN 81

//게임판 좌 상단 좌표와 게임판의 넓이와 높이
#define BX 5
#define BY 1
#define BW 10
#define BH 20

void DrawScreen();
void DrawBoard();
bool ProcessKey();
void PrintBrick(bool show);
int GetAround(int x, int y, int b, int r);
bool MoveDown();
void TestFull();
void DrawNext();
void PrintInfo();

//좌표를 나타내는 구조체
struct Point {
	int x, y;
};

//벽돌 모양을 정의한 배열
//마지막에 전통 테트리스와 다른 3가지 모양이 추가되었다.
Point Shape[][4][4] = {
     { {0,0,1,0,2,0,-1,0}, {0,0,0,1,0,-1,0,-2}, {0,0,1,0,2,0,-1,0}, {0,0,0,1,0,-1,0,-2} },
     { {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1} },
     { {0,0,-1,0,0,-1,1,-1}, {0,0,0,1,-1,0,-1,-1}, {0,0,-1,0,0,-1,1,-1}, {0,0,0,1,-1,0,-1,-1} },
     { {0,0,-1,-1,0,-1,1,0}, {0,0,-1,0,-1,1,0,-1}, {0,0,-1,-1,0,-1,1,0}, {0,0,-1,0,-1,1,0,-1} },
     { {0,0,-1,0,1,0,-1,-1}, {0,0,0,-1,0,1,-1,1}, {0,0,-1,0,1,0,1,1}, {0,0,0,-1,0,1,1,-1} },
     { {0,0,1,0,-1,0,1,-1}, {0,0,0,1,0,-1,-1,-1}, {0,0,1,0,-1,0,-1,1}, {0,0,0,-1,0,1,1,1} },
     { {0,0,-1,0,1,0,0,1}, {0,0,0,-1,0,1,1,0}, {0,0,-1,0,1,0,0,-1}, {0,0,-1,0,0,-1,0,1} },
     { {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}},
     { {0,0,0,0,0,0,0,1}, {0,0,0,0,0,0,1,0}, {0,0,0,0,0,0,0,1}, {0,0,0,0,0,0,1,0}},
     { {0,0,0,0,0,-1,1,0},{0,0,0,0,-1,0,0,-1},{0,0,0,0,0,1,-1,0},{0,0,0,0,0,1,1,0} },
};

//게임판 상태 표시
enum {EMPTY, BRICK, WALL};
//게임판에 표시할 문자. 위의 열거형 값과 동일한 순서로 맞췄다.
const char* arTile[][3] = 
    { {&quot;. &quot;,&quot;■&quot;, &quot;□&quot;}, 
      {&quot;  &quot;,&quot;■&quot;, &quot;□&quot;},
      {&quot;  &quot;,&quot;##&quot;, &quot;||&quot;},
      {&quot;. &quot;,&quot;●&quot;, &quot;▩&quot;},
    };
//arTile[EMPTY] == &quot;. &quot; 이다.
int ttype = 0;

//외벽을 포함한 게임판의 상태를 기록한다.
//x축 y축의 순서이며 넓이가 x축에 기록되었으므로 
//반시계 방향으로 90도 돌아가게 기록될 것이다.
int board[BW + 2][BH + 2];

//이동중인 벽돌의 배열상의 현재 좌표이다.
//화면상의 좌표로 변환하려면 BX+nx*2, BY+ny식을 쓰면 된다. 
//벽돌 하나가 x축(넓이) 두칸, y축 (높이) 한칸을 차지하기 때문이다. 
//&quot;::&quot;이런 느낌이다.
int nx, ny;

//이동중인 벽돌의 번호와 회전번호를 나타낸다.
int brick, rot;

//다음에 나올 벽돌을 미리 저장한다.
int nbrick;

//점수와 총 벽돌 갯수
int score, bricksum;

int main() {

    setcursortype(NOCURSOR);
    randomize();

    while (3) {
    clrscr();

    //게임 초기화 (보드 배열을 초기화한다.)
    for (int x = 0; x &amp;lt; BW + 2; x++) {
        for (int y = 0; y &amp;lt; BH + 2; y++) {
            board[x][y] = (y == 0 || y == BH + 1 || x == 0 || x == BW + 1) ? WALL : EMPTY;
        }
    }
    //보드를 그린다.
    DrawScreen();
    int nFrame = 20;
    score = 0;
    bricksum = 0;

    nbrick = random(sizeof(Shape) / sizeof(Shape[0]));
        while (1) { //첫번째 루프
            bricksum++;
            brick = nbrick;
            //랜덤으로 새 벽돌 생성
            nbrick = random(sizeof(Shape) / sizeof(Shape[0]));
            DrawNext();
            nx = BW / 2;        //x좌표는 게임판 가운데
            ny = 3;             //y좌표는 위에서 3번째 (첫번째는 외벽임)
            rot = 0;           //회전 좌표는 첫번째로
            PrintBrick(true);   //벽돌을 그린다.

            //게임 종료 조건 확인
            //새로 생성한 벽돌의 주변이 공백이 아니라면 게임 오버이므로 루프를 탈출한다.
            //확실한 방법은 아니다.
            if (GetAround(nx, ny, brick, rot) != EMPTY) break;
            int nStay = nFrame;

            while (2) { //두번째 루프 
                //벽돌 하나를 처리하는 루프이다.

                //프레임이 지나면 벽돌을 내린다.
                //초당 한칸씩 내려온다.
                if (--nStay == 0) {
                    nStay = nFrame;
                    //MoveDown() 함수는 벽돌이 바닥에 닿으면 true를 리턴한다.
                    if (MoveDown()) break;
                }
                //키 입력 처리를 한다.
                //ProcessKey() 함수도 벽돌이 바닥에 닿으면 true를 리턴한다.
                if (ProcessKey()) break;

                //if문이 true가 되면 2번째 루프를 빠져나간다.

                //시간을 지연시킨다.
                //20fps이다.
                delay(1000 / nFrame);
            }
            if (bricksum % 10 == 0 &amp;amp;&amp;amp; nFrame &amp;gt; 5) {
                nFrame--;
            }
        }

        //게임 오버 처리
        clrscr();
        gotoxy(30, 12); puts(&quot; G A M E   O V E R&quot;);
        gotoxy(25, 14); puts(&quot;다시 시작하려면 Y를 누르세요.&quot;);
        if (tolower(_getch()) != 'y') break;
    }
    setcursortype(NORMALCURSOR);
}

//화면 전체를 그린다.
//게임판과 게임 이름, 벽까지 한번에 그림.
void DrawScreen()
{
    for (int x = 0; x &amp;lt; BW + 2; x++) {
        for (int y = 0; y &amp;lt; BH + 2; y++) {
            gotoxy(BX + x * 2, BY + y);
            puts(arTile[ttype][board[x][y]]);
        }
    }
    
    gotoxy(50, 3); puts(&quot;Tetris Ver 1.1&quot;);
    gotoxy(50, 5); puts(&quot;좌우:이동, 위:회전, 아래:내림&quot;);
    gotoxy(50, 6); puts(&quot;공백: 전부 내림, ESC : 종료&quot;);
    gotoxy(50, 7); puts(&quot;P:정지, PgUp, PgDn : 블럭 그림 변경&quot;);

    DrawNext();
    PrintInfo();

}

//안쪽 게임판만 그린다. 
//쌓이는 벽돌도 얘가 그린다.
void DrawBoard()
{
    for (int x = 1; x &amp;lt; BW + 1; x++) {
        for (int y = 1; y &amp;lt; BH + 1; y++) {
            gotoxy(BX + x * 2, BY + y);
            puts(arTile[ttype][board[x][y]]);
        }
    }
}

//키 입력을 처리한다.
//이동중인 벽돌이 바닥에 닿으면 true를 리턴한다.
bool ProcessKey() 
{
    int trot;

    if (_kbhit()) {
        int ch = _getch();
        if (ch == 0xE0 || ch == 0) {
            ch = _getch();
            switch (ch) {
            case LEFT:
                if (GetAround(nx - 1, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    nx--;
                    PrintBrick(true);
                }
                break;

            case RIGHT:
                if (GetAround(nx + 1, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    nx++;
                    PrintBrick(true);
                }
                break;

            case UP:
                trot = (rot == 3 ? 0 : rot + 1);
                if (GetAround(nx, ny, brick, trot) == EMPTY) {
                    PrintBrick(false);
                    rot = trot;
                    PrintBrick(true);
                }
                break;

            case DOWN:
                if (MoveDown()) {
                    return true;
                }
                break;

            case PGUP:
                ttype++;
                if (ttype == sizeof(arTile) / sizeof(arTile[0])) ttype = 0;
                DrawScreen();
                PrintBrick(true);
                break;

            case PGDN:
                if (ttype == 0) ttype = sizeof(arTile) / sizeof(arTile[0]);
                ttype--;
                DrawScreen();
                PrintBrick(true);
                break;
            }
        } else {
            switch (tolower(ch)) {
            case ' ':
                while (MoveDown() == false) { ; }
                return true;
            case ESC:
                clrscr();
                gotoxy(30, 12); puts(&quot; G A M E   O V E R&quot;);
                exit(0);
            case 'p':
                clrscr();
                gotoxy(12, 10);
                puts(&quot;일시 중지 \n 다시 시작하려면 아무키나 누르세요&quot;);
                _getch();
                clrscr();
                DrawScreen();
                PrintBrick(true);
                break;
            }
        }
    }

    return false;
}

//이동중인 벽돌을 그리거나 삭제한다.
//전역 변수를 참조한다.
void PrintBrick(bool Show) 
{
    for (int i = 0; i &amp;lt; 4; i++) {
        gotoxy(BX + (Shape[brick][rot][i].x + nx) * 2, BY + Shape[brick][rot][i].y + ny);
        puts(arTile[ttype][Show ? BRICK : EMPTY]);
    }
}

//인수로 전달된 벽돌 주변에 뭐가 있는지 확인한다.
//이동중인 벽돌 주변을 확인하는게 아니다.
int GetAround(int x, int y, int b, int r) 
{
    int k = EMPTY;

    for (int i = 0; i &amp;lt; 4; i++) {
        k = max(k, board[x + Shape[b][r][i].x][y + Shape[b][r][i].y]);
    }

    return k;
}

//벽돌을 한칸 아래로 이동시킨다.
//만약 바닥에 닿았으면 TestFull()함수를 호출한 후 true를 리턴한다.
bool MoveDown()
{
    if (GetAround(nx, ny + 1, brick, rot) != EMPTY) {
        TestFull();
        return true;
    }

    PrintBrick(false);
    ny++;
    PrintBrick(true);
    return false;
}

//수평으로 다 채워진 줄을 찾아 삭제한다.
void TestFull() {
    int count = 0;
    static int arScore[] = { 0, 1, 3, 8, 20 };

    for (int i = 0; i &amp;lt; 4; i++) {
        board[nx + Shape[brick][rot][i].x][ny + Shape[brick][rot][i].y] = BRICK;
    }

    int x, y;
    for (y = 1; y &amp;lt; BH + 1; y++) {
        for (x = 1; x &amp;lt; BW + 1; x++) {
            if (board[x][y] != BRICK) break;
        }
        if (x == BW + 1) {
            count++;
            for (int ty = y; ty &amp;gt; 1; ty--) {
                for (x = 1; x &amp;lt; BW + 1; x++) {
                    board[x][ty] = board[x][ty - 1];
                }
            }
            DrawBoard();
            delay(200);
        }
    }

    score += arScore[count];
    PrintInfo();

}

void DrawNext() {
    for (int x = 50; x &amp;lt;= 70; x += 2) {
        for (int y = 12; y &amp;lt;= 18; y++) {
            gotoxy(x, y);
            puts(arTile[ttype][x == 50 || x == 70 || y == 12 || y == 18 ? WALL : EMPTY ]);
        }
    }

    for (int i = 0; i &amp;lt; 4; i++) {
        gotoxy(60 + (Shape[nbrick][0][i].x) * 2, 15 + Shape[nbrick][0][i].y);
        puts(arTile[ttype][BRICK]);
    }
}

void PrintInfo() {
    gotoxy(50, 9); printf(&quot;점수 : %d 점 \t&quot;, score);
    gotoxy(50, 10); printf(&quot;총벽돌 : %d 개&quot;, bricksum);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ■ 강의의 내용에 따라 조금 바꿔보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ■ 다음 블럭을 알 수 있는 기능과 일시 정지 및 다시 하기, 점수 기능과 난이도 조절 기능을 넣었다.&lt;/p&gt;</description>
      <category>리메이크 중/C,C++ 실습 중심</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/683</guid>
      <comments>https://lypicfa.tistory.com/683#entry683comment</comments>
      <pubDate>Mon, 16 Jan 2023 18:55:05 +0900</pubDate>
    </item>
    <item>
      <title>C(&amp;amp;C++) 13. 테트리스 주석 추가</title>
      <link>https://lypicfa.tistory.com/682</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-01-13 192056.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgSInS/btrWee2rnxF/TZKqEXEt5kOyPrukz9bFH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgSInS/btrWee2rnxF/TZKqEXEt5kOyPrukz9bFH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgSInS/btrWee2rnxF/TZKqEXEt5kOyPrukz9bFH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgSInS%2FbtrWee2rnxF%2FTZKqEXEt5kOyPrukz9bFH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;80&quot; data-filename=&quot;화면 캡처 2023-01-13 192056.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;soen.kr&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;pre id=&quot;code_1673682354283&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;Turboc.h&quot;

//키 바인딩
#define LEFT 75
#define RIGHT 77
#define UP 72
#define DOWN 80
#define ESC 27

//게임판 좌 상단 좌표와 게임판의 넓이와 높이
#define BX 5
#define BY 1
#define BW 10
#define BH 20

void DrawScreen();
void DrawBoard();
bool ProcessKey();
void PrintBrick(bool show);
int GetAround(int x, int y, int b, int r);
bool MoveDown();
void TestFull();

struct Point {
	int x, y;
};

Point Shape[][4][4] = {
     { {0,0,1,0,2,0,-1,0}, {0,0,0,1,0,-1,0,-2}, {0,0,1,0,2,0,-1,0}, {0,0,0,1,0,-1,0,-2} },
     { {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1} },
     { {0,0,-1,0,0,-1,1,-1}, {0,0,0,1,-1,0,-1,-1}, {0,0,-1,0,0,-1,1,-1}, {0,0,0,1,-1,0,-1,-1} },
     { {0,0,-1,-1,0,-1,1,0}, {0,0,-1,0,-1,1,0,-1}, {0,0,-1,-1,0,-1,1,0}, {0,0,-1,0,-1,1,0,-1} },
     { {0,0,-1,0,1,0,-1,-1}, {0,0,0,-1,0,1,-1,1}, {0,0,-1,0,1,0,1,1}, {0,0,0,-1,0,1,1,-1} },
     { {0,0,1,0,-1,0,1,-1}, {0,0,0,1,0,-1,-1,-1}, {0,0,1,0,-1,0,-1,1}, {0,0,0,-1,0,1,1,1} },
     { {0,0,-1,0,1,0,0,1}, {0,0,0,-1,0,1,1,0}, {0,0,-1,0,1,0,0,-1}, {0,0,-1,0,0,-1,0,1} },
};

//게임판 상태 표시
enum {EMPTY, BRICK, WALL};
//게임판에 표시할 문자. 위의 열거형 값과 동일한 순서로 맞췄다.
const char* arTile[] = { &quot;. &quot;,&quot;■&quot;, &quot;□&quot; };
//arTile[EMPTY] == &quot;. &quot; 이다.

//외벽을 포함한 게임판의 상태를 기록한다.
//x축 y축의 순서이며 넓이가 x축에 기록되었으므로 
//반시계 방향으로 90도 돌아가게 기록될 것이다.
int board[BW + 2][BH + 2];

//이동중인 벽돌의 배열상의 현재 좌표이다.
//화면상의 좌표로 변환하려면 BX+nx*2, BY+ny식을 쓰면 된다. 
//벽돌 하나가 x축(넓이) 두칸, y축 (높이) 한칸을 차지하기 때문이다. 
//&quot;::&quot;이런 느낌이다.
int nx, ny;

//이동중인 벽돌의 번호와 회전번호를 나타낸다.
int brick, rot;

int main() {

    
    setcursortype(NOCURSOR);
    randomize();
    clrscr();

    //게임 초기화 (보드 배열을 초기화한다.)
    for (int x = 0; x &amp;lt; BW + 2; x++) {
        for (int y = 0; y &amp;lt; BH + 2; y++) {
            board[x][y] = (y == 0 || y == BH + 1 || x == 0 || x == BW + 1) ? WALL : EMPTY;
        }
    }
    //보드를 그린다.
    DrawScreen();
    int nFrame = 20;

    while (1) { //첫번째 루프
        //랜덤으로 새 벽돌 생성
        brick = random(sizeof(Shape) / sizeof(Shape[0]));
        nx = BW / 2;        //x좌표는 게임판 가운데
        ny = 3;             //y좌표는 위에서 3번째 (첫번째는 외벽임)
        rot = 0 ;           //회전 좌표는 첫번째로
        PrintBrick(true);   //벽돌을 그린다.

        //게임 종료 조건 확인
        //새로 생성한 벽돌의 주변이 공백이 아니라면 게임 오버이므로 루프를 탈출한다.
        //확실한 방법은 아니다.
        if (GetAround(nx, ny, brick, rot) != EMPTY) break;
        int nStay = nFrame;
        
        while (2) { //두번째 루프 
            //벽돌 하나를 처리하는 루프이다.

            //프레임이 지나면 벽돌을 내린다.
            //초당 한칸씩 내려온다.
            if (--nStay == 0) {
                nStay = nFrame;
                //MoveDown() 함수는 벽돌이 바닥에 닿으면 true를 리턴한다.
                if (MoveDown()) break;
            }
            //키 입력 처리를 한다.
            //ProcessKey() 함수도 벽돌이 바닥에 닿으면 true를 리턴한다.
            if (ProcessKey()) break;
            
            //if문이 true가 되면 2번째 루프를 빠져나간다.

            //시간을 지연시킨다.
            //20fps이다.
            delay(1000 / nFrame);
        }
    }

    //게임 오버 처리
    clrscr();
    gotoxy(30, 12); puts(&quot; G A M E   O V E R&quot;);
    setcursortype(NORMALCURSOR);
}

//화면 전체를 그린다.
//게임판과 게임 이름, 벽까지 한번에 그림.
void DrawScreen()
{
    for (int x = 0; x &amp;lt; BW + 2; x++) {
        for (int y = 0; y &amp;lt; BH + 2; y++) {
            gotoxy(BX + x * 2, BY + y);
            puts(arTile[board[x][y]]);
        }
    }
    
    gotoxy(50, 3); puts(&quot;Tetris Ver 1.0&quot;);
    gotoxy(50, 5); puts(&quot;좌우:이동, 위:회전, 아래:내림&quot;);
    gotoxy(50, 6); puts(&quot;공백: 전부 내림&quot;);
}

//안쪽 게임판만 그린다. 
//쌓이는 벽돌도 얘가 그린다.
void DrawBoard()
{
    for (int x = 1; x &amp;lt; BW + 1; x++) {
        for (int y = 1; y &amp;lt; BH + 1; y++) {
            gotoxy(BX + x * 2, BY + y);
            puts(arTile[board[x][y]]);
        }
    }
}

//키 입력을 처리한다.
//이동중인 벽돌이 바닥에 닿으면 true를 리턴한다.
bool ProcessKey() 
{
    int trot;

    if (_kbhit()) {
        int ch = _getch();
        if (ch == 0xE0 || ch == 0) {
            ch = _getch();
            switch (ch) {
            case LEFT:
                if (GetAround(nx - 1, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    nx--;
                    PrintBrick(true);
                }
                break;

            case RIGHT:
                if (GetAround(nx + 1, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    nx++;
                    PrintBrick(true);
                }
                break;

            case UP:
                trot = (rot == 3 ? 0 : rot + 1);
                if (GetAround(nx, ny, brick, trot) == EMPTY) {
                    PrintBrick(false);
                    rot = trot;
                    PrintBrick(true);
                }
                break;

            case DOWN:
                if (MoveDown()) {
                    return true;
                }
                break;
            }
        } else {
            switch (ch) {
            case ' ':
                while (MoveDown() == false) { ; }
                return true;
            }
        }
    }

    return false;
}

//이동중인 벽돌을 그리거나 삭제한다.
//전역 변수를 참조한다.
void PrintBrick(bool Show) 
{
    for (int i = 0; i &amp;lt; 4; i++) {
        gotoxy(BX + (Shape[brick][rot][i].x + nx) * 2, BY + Shape[brick][rot][i].y + ny);
        puts(arTile[Show ? BRICK : EMPTY]);
    }
}

//인수로 전달된 벽돌 주변에 뭐가 있는지 확인한다.
//이동중인 벽돌 주변을 확인하는게 아니다.
int GetAround(int x, int y, int b, int r) 
{
    int k = EMPTY;

    for (int i = 0; i &amp;lt; 4; i++) {
        k = max(k, board[x + Shape[b][r][i].x][y + Shape[b][r][i].y]);
    }

    return k;
}

//벽돌을 한칸 아래로 이동시킨다.
//만약 바닥에 닿았으면 TestFull()함수를 호출한 후 true를 리턴한다.
bool MoveDown()
{
    if (GetAround(nx, ny + 1, brick, rot) != EMPTY) {
        TestFull();
        return true;
    }

    PrintBrick(false);
    ny++;
    PrintBrick(true);
    return false;
}

//수평으로 다 채워진 줄을 찾아 삭제한다.
void TestFull() {
    for (int i = 0; i &amp;lt; 4; i++) {
        board[nx + Shape[brick][rot][i].x][ny + Shape[brick][rot][i].y] = BRICK;
    }

    int x, y;
    for (y = 1; y &amp;lt; BH + 1; y++) {
        for (x = 1; x &amp;lt; BW + 1; x++) {
            if (board[x][y] != BRICK) break;
        }
        if (x == BW + 1) {
            for (int ty = y; ty &amp;gt; 1; ty--) {
                for (x = 1; x &amp;lt; BW + 1; x++) {
                    board[x][ty] = board[x][ty - 1];
                }
            }
            DrawBoard();
            delay(200);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;■ 테트리스 코드에 주석을 추가했다.&lt;/p&gt;</description>
      <category>리메이크 중/C,C++ 실습 중심</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/682</guid>
      <comments>https://lypicfa.tistory.com/682#entry682comment</comments>
      <pubDate>Sat, 14 Jan 2023 16:46:39 +0900</pubDate>
    </item>
    <item>
      <title>C(&amp;amp;C++) 실습 12. 테트리스 1</title>
      <link>https://lypicfa.tistory.com/681</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-01-13 192056.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo9ciy/btrWcKmSNjW/d24Qp4Soayk7bhBOOsqKS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo9ciy/btrWcKmSNjW/d24Qp4Soayk7bhBOOsqKS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo9ciy/btrWcKmSNjW/d24Qp4Soayk7bhBOOsqKS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo9ciy%2FbtrWcKmSNjW%2Fd24Qp4Soayk7bhBOOsqKS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;80&quot; data-filename=&quot;화면 캡처 2023-01-13 192056.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;출처&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;soen.kr&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1673605148459&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;Turboc.h&quot;

#define LEFT 75
#define RIGHT 77
#define UP 72
#define DOWN 80
#define ESC 27

#define BX 5
#define BY 1
#define BW 10
#define BH 20

void DrawScreen();
void DrawBoard();
bool ProcessKey();
void PrintBrick(bool show);
int GetAround(int x, int y, int b, int r);
bool MoveDown();
void TestFull();

struct Point {
	int x, y;
};

Point Shape[][4][4] = {
     { {0,0,1,0,2,0,-1,0}, {0,0,0,1,0,-1,0,-2}, {0,0,1,0,2,0,-1,0}, {0,0,0,1,0,-1,0,-2} },
     { {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1} },
     { {0,0,-1,0,0,-1,1,-1}, {0,0,0,1,-1,0,-1,-1}, {0,0,-1,0,0,-1,1,-1}, {0,0,0,1,-1,0,-1,-1} },
     { {0,0,-1,-1,0,-1,1,0}, {0,0,-1,0,-1,1,0,-1}, {0,0,-1,-1,0,-1,1,0}, {0,0,-1,0,-1,1,0,-1} },
     { {0,0,-1,0,1,0,-1,-1}, {0,0,0,-1,0,1,-1,1}, {0,0,-1,0,1,0,1,1}, {0,0,0,-1,0,1,1,-1} },
     { {0,0,1,0,-1,0,1,-1}, {0,0,0,1,0,-1,-1,-1}, {0,0,1,0,-1,0,-1,1}, {0,0,0,-1,0,1,1,1} },
     { {0,0,-1,0,1,0,0,1}, {0,0,0,-1,0,1,1,0}, {0,0,-1,0,1,0,0,-1}, {0,0,-1,0,0,-1,0,1} },
};

enum {EMPTY, BRICK, WALL};
const char* arTile[] = { &quot;. &quot;,&quot;■&quot;, &quot;□&quot; };

int board[BW + 2][BH + 2];
int nx, ny;
int brick, rot;

int main() {

    int nFrame, nStay;

    setcursortype(NOCURSOR);
    randomize();
    clrscr();

    for (int x = 0; x &amp;lt; BW + 2; x++) {
        for (int y = 0; y &amp;lt; BH + 2; y++) {
            board[x][y] = (y == 0 || y == BH + 1 || x == 0 || x == BW + 1) ? WALL : EMPTY;
        }
    }

    DrawScreen();
    nFrame = 20;

    while (true) {
        brick = random(sizeof(Shape) / sizeof(Shape[0]));
        nx = BW / 2;
        ny = 3;
        rot = 0;
        PrintBrick(true);

        if (GetAround(nx, ny, brick, rot) != EMPTY) break;
        nStay = nFrame;
        
        while (true) {
            if (--nStay == 0) {
                nStay = nFrame;
                if (MoveDown()) break;
            }
            if (ProcessKey()) break;
            delay(1000 / 20);
        }
    }

    clrscr();
    gotoxy(30, 12); puts(&quot; G A M E   O V E R&quot;);
    setcursortype(NORMALCURSOR);
}

void DrawScreen()
{
    for (int x = 0; x &amp;lt; BW + 2; x++) {
        for (int y = 0; y &amp;lt; BH + 2; y++) {
            gotoxy(BX + x * 2, BY + y);
            puts(arTile[board[x][y]]);
        }
    }
    
    gotoxy(50, 3); puts(&quot;Tetris Ver 1.0&quot;);
    gotoxy(50, 5); puts(&quot;좌우:이동, 위:회전, 아래:내림&quot;);
    gotoxy(50, 6); puts(&quot;공백: 전부 내림&quot;);
}

void DrawBoard()
{
    for (int x = 1; x &amp;lt; BW + 1; x++) {
        for (int y = 1; y &amp;lt; BH + 1; y++) {
            gotoxy(BX + x * 2, BY + y);
            puts(arTile[board[x][y]]);
        }
    }
}

bool ProcessKey() 
{
    int trot;

    if (_kbhit()) {
        int ch = _getch();
        if (ch == 0xE0 || ch == 0) {
            ch = _getch();
            switch (ch) {
            case LEFT:
                if (GetAround(nx - 1, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    nx--;
                    PrintBrick(true);
                }
                break;

            case RIGHT:
                if (GetAround(nx + 1, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    nx++;
                    PrintBrick(true);
                }
                break;

            case UP:
                trot = (rot == 3 ? 0 : rot + 1);
                if (GetAround(nx, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    rot = trot;
                    PrintBrick(true);
                }
                break;

            case DOWN:
                if (MoveDown()) {
                    return true;
                }
                break;
            }
        } else {
            switch (ch) {
            case ' ':
                while (MoveDown() == false) { ; }
                return true;
            }
        }
    }

    return false;
}

void PrintBrick(bool Show) 
{
    for (int i = 0; i &amp;lt; 4; i++) {
        gotoxy(BX + (Shape[brick][rot][i].x + nx) * 2, BY + Shape[brick][rot][i].y + ny);
        puts(arTile[Show ? BRICK : EMPTY]);
    }
}

int GetAround(int x, int y, int b, int r) 
{
    int k = EMPTY;

    for (int i = 0; i &amp;lt; 4; i++) {
        k = max(k, board[x + Shape[b][r][i].x][y + Shape[b][r][i].y]);
    }

    return k;
}

bool MoveDown()
{
    if (GetAround(nx, ny + 1, brick, rot) != EMPTY) {
        TestFull();
        return true;
    }

    PrintBrick(false);
    ny++;
    PrintBrick(true);
    return false;
}

void TestFull() {
    for (int i = 0; i &amp;lt; 4; i++) {
        board[nx + Shape[brick][rot][i].x][ny + Shape[brick][rot][i].y] = BRICK;
    }

    int x, y;
    for (y = 1; y &amp;lt; BH + 1; y++) {
        for (x = 1; x &amp;lt; BW + 1; x++) {
            if (board[x][y] != BRICK) break;
        }
        if (x == BW + 1) {
            for (int ty = y; ty &amp;gt; 1; ty--) {
                for (x = 1; x &amp;lt; BW + 1; x++) {
                    board[x][ty] = board[x][ty - 1];
                }
            }
            DrawBoard();
            delay(200);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;■ 이번 예제는 기능이 함수들로 좀 쪼개져 있어서 나은 편이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;■ 테트리스는 누구나 아는 게임이라 재밌다.&lt;/p&gt;</description>
      <category>리메이크 중/C,C++ 실습 중심</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/681</guid>
      <comments>https://lypicfa.tistory.com/681#entry681comment</comments>
      <pubDate>Fri, 13 Jan 2023 19:19:50 +0900</pubDate>
    </item>
    <item>
      <title>C(&amp;amp;C++) 실습 11. 슈팅 게임 일부 수정</title>
      <link>https://lypicfa.tistory.com/680</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-01-13 170830.png&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxzW93/btrWbcR0h4t/S5CxiEeVai2AqyoikyH050/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxzW93/btrWbcR0h4t/S5CxiEeVai2AqyoikyH050/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxzW93/btrWbcR0h4t/S5CxiEeVai2AqyoikyH050/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxzW93%2FbtrWbcR0h4t%2FS5CxiEeVai2AqyoikyH050%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1001&quot; height=&quot;120&quot; data-filename=&quot;화면 캡처 2023-01-13 170830.png&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;출처&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;soen.kr&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;pre id=&quot;code_1673597161458&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;Turboc.h&quot;

//특수키 바인딩
#define ESC			27

//MAX값 지정
#define MAXENEMY	10
#define MAXBALL		20
#define MAXBULLET	5

int fx;			//조종기의 x좌표
int Score;		//점수

//적 구조체
struct Enemy
{
	bool exist;
	int Type;
	int x, y;
	int Delta;
	int nFrame;
	int nStay;
};

//적 총알 구조체
struct Ball
{
	bool exist;
	int x, y;
	int nFrame;
	int nStay;
};

//조종기 총알 구조체
struct Bullet {
	bool exist;
	int x, y;
};

//적기 종류
const char *arEnemy[4] = { &quot;--$--&quot;, &quot;ZzTzZ&quot;, &quot;oO@Oo&quot;, &quot;&amp;lt;-&amp;amp;-&amp;gt;&quot;};

//키가 눌러져 있는지 확인하는 함수
bool IsKeyDown(int Key) { return ((GetAsyncKeyState(Key) &amp;amp; 0x8000) != 0); }

Enemy eCount[MAXENEMY];			//적 배열
Ball bCount[MAXBALL];			//적 총알 배열
Bullet bBullet[MAXBULLET];		//아군 총알 배열


int main() {
	int i, j;

	randomize();
	clrscr();
	fx = 40;
	Score = 0;
	setcursortype(NOCURSOR);

	int count = 0;
	while(true) {	//전체 무한 루프 시작



		//좌우 이동 처리
		//count 처리가 없으면 너무 빨리 움직인다.
		//if 처리는 화면 밖으로 나가지 않게 하기 위한 처리.
		//IsKeyDown함수도 키 입력을 확인하는 함수로 만들어져있는데
		//_kbhit() _getch()와 다른 점은 키를 누르고 있는 것도 연속된 입력으로 인식하고,
		//다른 키와 같이 누른 것도 인식한다는 것이다.
		if (count % 5 == 0) {
			if (IsKeyDown(VK_LEFT)) {
				if (fx &amp;gt; 3) { 
					gotoxy(fx - 3, 23);
					puts(&quot;　　　　&quot;);
					fx--; 
				}
			}
			if (IsKeyDown(VK_RIGHT)) {
				if (fx &amp;lt; 75) {
					gotoxy(fx - 3, 23);
					puts(&quot;　　　　&quot;);
					fx++; 
				}
			}
		}

		//키 입력 처리
		if (_kbhit()) {
			int ch = _getch();
			// 특수키가 눌린건지 확인
			// 특수키 종류를 확인해 볼 것
			if (ch == 0xE0 || ch == 0) {
				_getch();

			//아니라면 처리
			} else {
				switch (ch) {
				case ' ':
					//발사된 총알이 없다면
					// + 최대 총알 수 만큼 발사 가능
					//조종기의 x좌표를 기준으로 위쪽에 총알을 만든다.
					for (i = 0; i &amp;lt; MAXBULLET &amp;amp;&amp;amp; bBullet[i].exist == true; i++) { ; }
					if (i != MAXBULLET) {
						bBullet[i].x = fx;
						bBullet[i].y = 23;
						bBullet[i].exist = true;
					}
					break;

				case ESC:
					//ESC키를 누르면 종료 처리 
					//goto문으로 되어 있어서 바꿨다.
					setcursortype(NORMALCURSOR);
					return 0;
				}
			}
		}

		//적군 생성 
		//1%의 확률인데 1초에 100프레임이므로 초당 하나 정도 만들어질 것이다.
		if (random(100) == 0) {
			//eCount안에서 exist가 false인 것을 찾는다
			for (i = 0; i &amp;lt; MAXENEMY &amp;amp;&amp;amp; eCount[i].exist == true; i++) { ; }

			//루프가 끝까지 돌아서 끝난게 아닌지 확인한다.
			if (i != MAXENEMY) {
				//이동 방향을 결정하고 화면 끝으로 위치를 설정한다.
				if (random(2) == 1) {
					eCount[i].x = 5;
					eCount[i].Delta = 1;
				}
				else {
					eCount[i].x = 75;
					eCount[i].Delta = -1;
				}

				
				//무한 루프
				while(true) {
					int bFound = false;
					//세로 좌표를 랜덤으로 정한다.
					eCount[i].y = random(10) + 1;
					for (j = 0; j &amp;lt; MAXENEMY; j++) {
						//그 세로 좌표에 이미 적이 존재하는지 확인한다.
						if (eCount[j].exist == true &amp;amp;&amp;amp; eCount[j].y == eCount[i].y) {
							bFound = true;
							break;
						}
					}
					//없다면 루프를 나간다.
					if (bFound == false) {
						break;
					}
				}
				//속도와 모양을 결정하고 존재 여부를 true로 한다.
				eCount[i].nFrame = eCount[i].nStay = random(6) + 1;
				eCount[i].Type = random(sizeof(arEnemy) / sizeof(arEnemy[0]));
				eCount[i].exist = true;
			}
		}

		// 조종기에서 발사한 총알을 이동시킨다.
		for (i = 0; i &amp;lt; MAXBULLET; i++) {
			if (bBullet[i].exist) {
				if (count % 3) break;
				gotoxy(bBullet[i].x, bBullet[i].y); _putch(' ');
				if (bBullet[i].y == 0) {
					bBullet[i].exist = false;
				}
				else {
					bBullet[i].y--;
					gotoxy(bBullet[i].x, bBullet[i].y); _putch('@');
				}
			}
		}

		//적군과 아군 총알이 충돌했는지 판정한다.
		//+ 충돌시 바로 사라지지 않고 잠시 시체가 남게 했다.
		for (i = 0; i &amp;lt; MAXENEMY; i++) {
			if (eCount[i].exist == false || eCount[i].Type == -1) continue;
			for(j=0; j&amp;lt;MAXBULLET; j++) {
				if (bBullet[j].exist == false) continue;
				if (eCount[i].y == bBullet[j].y &amp;amp;&amp;amp; abs(eCount[i].x - bBullet[j].x) &amp;lt;= 2) {
					gotoxy(bBullet[j].x, bBullet[j].y); _putch(' ');
					bBullet[j].exist = false;
					eCount[i].Type = -1;
					gotoxy(eCount[i].x - 2, eCount[i].y);
					puts(&quot;.,:,.&quot;);
					Score += 7 - eCount[i].nFrame;
					eCount[i].nFrame = eCount[i].nStay = 50;
					break;
				}
			}
		}

		//적군 총알을 이동시킨다.
		for (i = 0; i &amp;lt; MAXBALL; i++) {
			if (bCount[i].exist == false) continue;
			if (--bCount[i].nStay == 0) {
				bCount[i].nStay = bCount[i].nFrame;
				gotoxy(bCount[i].x, bCount[i].y); _putch(' ');
				if (bCount[i].y &amp;gt;= 23) {
					bCount[i].exist = false;
				}
				else {
					if (random(5)) {
						if (bCount[i].x &amp;lt; fx) {
							bCount[i].x++;
						}
						else {
							bCount[i].x--;
						}
					}

					bCount[i].y++;
					gotoxy(bCount[i].x, bCount[i].y); _putch('*');
				}
			}
		}

		//적군 총알과 아군 조종기가 충돌했는지 판정한다.
		for (i = 0; i &amp;lt; MAXBALL; i++) {
			if (bCount[i].exist == false) continue;
			if (bCount[i].y == 23 &amp;amp;&amp;amp; abs(bCount[i].x - fx) &amp;lt;= 2) {
				gotoxy(fx - 3, 21); puts(&quot;   .   &quot;);
				gotoxy(fx - 3, 22); puts(&quot;.  .  .&quot;);
				gotoxy(fx - 3, 23); puts(&quot;..:V:..&quot;);
				delay(2000);

				//충돌했다면 게임을 종료한다.
				delay(500);
				setcursortype(NORMALCURSOR);
				return 0;
			}
		}

		//적군 이동 
		for (i = 0; i &amp;lt; MAXENEMY; i++) {

			if (eCount[i].exist == false) continue;

			if (--eCount[i].nStay == 0) {
				if (eCount[i].Type == -1) {
					gotoxy(eCount[i].x - 2, eCount[i].y);
					puts(&quot;　　　　　&quot;);
					eCount[i].exist = false;
					continue;
				}

				eCount[i].nStay = eCount[i].nFrame;
				
				//적군이 화면 밖에 있으면
				if (eCount[i].x &amp;gt;= 76 || eCount[i].x &amp;lt;= 4) {
					eCount[i].exist = false;
					gotoxy(eCount[i].x - 2, eCount[i].y);
					puts(&quot;　　　　&quot;);
				}
				else {
					//적군의 원래 이미지를 지우고 새로운 이미지를 그린다.
					gotoxy(eCount[i].x - 2, eCount[i].y);
					puts(&quot;　　　　&quot;);
					eCount[i].x += eCount[i].Delta;
					gotoxy(eCount[i].x - 2, eCount[i].y);
					puts(arEnemy[eCount[i].Type]);

					//1/40 확률로 총알을 발사한다.
					if (random(40) == 0) {
						for (j = 0; j &amp;lt; MAXBALL &amp;amp;&amp;amp; bCount[j].exist == true; j++) { ; }
						if (j != MAXBALL) {
							bCount[j].x = eCount[i].x + 2;
							bCount[j].y = eCount[i].y + 1;
							bCount[j].nFrame = bCount[j].nStay = eCount[i].nFrame * 6;
							bCount[j].exist = true;
						}
					}
				}
			}
		}

		gotoxy(fx - 3, 23);
		puts(&quot;&amp;lt;&amp;lt;A&amp;gt;&amp;gt;&quot;);
		gotoxy(0, 24);
		printf(&quot;점수 = %d&quot;, Score);

		delay(10);

		count++; //루프 카운터 증가
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;■ 사이트에 나온 내용에 따라 조금 바꿔보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;■ 클래스로 변경한게 아니고 기능을 조금 바꾼 정도이기 때문에 조금만 바꿔도 전체에 문제가 생길 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>리메이크 중/C,C++ 실습 중심</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/680</guid>
      <comments>https://lypicfa.tistory.com/680#entry680comment</comments>
      <pubDate>Fri, 13 Jan 2023 17:08:55 +0900</pubDate>
    </item>
    <item>
      <title>C(&amp;amp;C++) 실습 10. 슈팅 게임</title>
      <link>https://lypicfa.tistory.com/679</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-01-13 170830.png&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGPW3f/btrV85Z8INX/aJaIfRJA1d4B8Gy1xXd4OK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGPW3f/btrV85Z8INX/aJaIfRJA1d4B8Gy1xXd4OK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGPW3f/btrV85Z8INX/aJaIfRJA1d4B8Gy1xXd4OK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGPW3f%2FbtrV85Z8INX%2FaJaIfRJA1d4B8Gy1xXd4OK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1001&quot; height=&quot;120&quot; data-filename=&quot;화면 캡처 2023-01-13 170830.png&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;출처&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;soen.kr&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;pre id=&quot;code_1673512927478&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;Turboc.h&quot;

//특수키 바인딩
#define ESC			27

//MAX값 지정
#define MAXENEMY	10
#define MAXBALL		20


int fx;			//조종기의 x좌표
int bx, by;		//아군 총알의 x,y좌표
int Score;		//점수

//적 구조체
struct Enemy
{
	bool exist;
	int Type;
	int x, y;
	int Delta;
	int nFrame;
	int nStay;
};

//적 총알 구조체
struct Ball
{
	bool exist;
	int x, y;
	int nFrame;
	int nStay;
};

//적기 종류
const char *arEnemy[4] = { &quot;--$--&quot;, &quot;ZzTzZ&quot;, &quot;oO@Oo&quot;, &quot;&amp;lt;-&amp;amp;-&amp;gt;&quot;};

//키가 눌러져 있는지 확인하는 함수
bool IsKeyDown(int Key) { return ((GetAsyncKeyState(Key) &amp;amp; 0x8000) != 0); }

Enemy eCount[MAXENEMY];			//적 배열
Ball bCount[MAXBALL];			//적 총알 배열

int main() {
	int i, j;

	randomize();
	clrscr();
	setcursortype(NOCURSOR);
	fx = 40;
	bx = -1;
	Score = 0;

	int count = 0;
	while(true) {	//전체 무한 루프 시작

		//좌우 이동 처리
		//count 처리가 없으면 너무 빨리 움직인다.
		//if 처리는 화면 밖으로 나가지 않게 하기 위한 처리.
		//IsKeyDown함수도 키 입력을 확인하는 함수로 만들어져있는데
		//_kbhit() _getch()와 다른 점은 키를 누르고 있는 것도 연속된 입력으로 인식하고,
		//다른 키와 같이 누른 것도 인식한다는 것이다.
		if (count % 5 == 0) {
			if (IsKeyDown(VK_LEFT)) {
				if (fx &amp;gt; 3) { 
					gotoxy(fx - 3, 23);
					puts(&quot;　　　　&quot;);
					fx--; 
				}
			}
			if (IsKeyDown(VK_RIGHT)) {
				if (fx &amp;lt; 75) {
					gotoxy(fx - 3, 23);
					puts(&quot;　　　　&quot;);
					fx++; 
				}
			}
		}

		//키 입력 처리
		if (_kbhit()) {
			int ch = _getch();
			// 특수키가 눌린건지 확인
			// 특수키 종류를 확인해 볼 것
			if (ch == 0xE0 || ch == 0) {
				_getch();

			//아니라면 처리
			} else {
				switch (ch) {
				case ' ':
					//발사된 총알이 없다면
					//조종기의 x좌표를 기준으로 위쪽에 총알을 만든다.
					if (bx == -1) {
						bx = fx;
						by = 23;
					}
					break;
				case ESC:
					//ESC키를 누르면 종료 처리 
					//goto문으로 되어 있어서 바꿨다.
					setcursortype(NORMALCURSOR);
					return 0;
				}
			}
		}

		//적군 생성 
		//1%의 확률인데 1초에 100프레임이므로 초당 하나 정도 만들어질 것이다.
		if (random(100) == 0) {
			//eCount안에서 exist가 false인 것을 찾는다
			for (i = 0; i &amp;lt; MAXENEMY &amp;amp;&amp;amp; eCount[i].exist == true; i++) { ; }

			//루프가 끝까지 돌아서 끝난게 아닌지 확인한다.
			if (i != MAXENEMY) {
				//이동 방향을 결정하고 화면 끝으로 위치를 설정한다.
				if (random(2) == 1) {
					eCount[i].x = 5;
					eCount[i].Delta = 1;
				}
				else {
					eCount[i].x = 75;
					eCount[i].Delta = -1;
				}

				
				//무한 루프
				while(true) {
					int bFound = false;
					//세로 좌표를 랜덤으로 정한다.
					eCount[i].y = random(10) + 1;
					for (j = 0; j &amp;lt; MAXENEMY; j++) {
						//그 세로 좌표에 이미 적이 존재하는지 확인한다.
						if (eCount[j].exist == true &amp;amp;&amp;amp; eCount[j].y == eCount[i].y) {
							bFound = true;
							break;
						}
					}
					//없다면 루프를 나간다.
					if (bFound == false) {
						break;
					}
				}
				//속도와 모양을 결정하고 존재 여부를 true로 한다.
				eCount[i].nFrame = eCount[i].nStay = random(6) + 1;
				eCount[i].Type = random(sizeof(arEnemy) / sizeof(arEnemy[0]));
				eCount[i].exist = true;
			}
		}

		// 조종기에서 발사한 총알을 이동시킨다.
		if (bx != -1) {
			gotoxy(bx, by); _putch(' ');
			if (by == 0) {
				bx = -1;
			}
			else {
				by--;
				gotoxy(bx, by); _putch('i');
			}
		}

		//적군과 아군 총알이 충돌했는지 판정한다.
		for (i = 0; i &amp;lt; MAXENEMY; i++) {
			if (eCount[i].exist == false) continue;
			if (eCount[i].y == by &amp;amp;&amp;amp; abs(eCount[i].x - bx) &amp;lt;= 2) {
				gotoxy(bx, by); _putch(' ');
				bx = -1;
				eCount[i].exist = false;
				gotoxy(eCount[i].x - 3, eCount[i].y);
				puts(&quot;　　　　&quot;);
				Score += 7 - eCount[i].nFrame;
				break;
			}
		}

		//적군 총알을 이동시킨다.
		for (i = 0; i &amp;lt; MAXBALL; i++) {
			if (bCount[i].exist == false) continue;
			if (--bCount[i].nStay == 0) {
				bCount[i].nStay = bCount[i].nFrame;
				gotoxy(bCount[i].x, bCount[i].y); _putch(' ');
				if (bCount[i].y &amp;gt;= 23) {
					bCount[i].exist = false;
				}
				else {
					bCount[i].y++;
					gotoxy(bCount[i].x, bCount[i].y); _putch('*');
				}
			}
		}

		//적군 총알과 아군 조종기가 충돌했는지 판정한다.
		for (i = 0; i &amp;lt; MAXBALL; i++) {
			if (bCount[i].exist == false) continue;
			if (bCount[i].y == 23 &amp;amp;&amp;amp; abs(bCount[i].x - fx) &amp;lt;= 2) {
				gotoxy(fx - 3, 21); puts(&quot;   .   &quot;);
				gotoxy(fx - 3, 22); puts(&quot;.  .  .&quot;);
				gotoxy(fx - 3, 23); puts(&quot;..:V:..&quot;);
				delay(2000);

				//충돌했다면 게임을 종료한다.
				setcursortype(NORMALCURSOR);
				return 0;
			}
		}

		//적군 이동 
		for (i = 0; i &amp;lt; MAXENEMY; i++) {

			if (eCount[i].exist == false) continue;

			if (--eCount[i].nStay == 0) {
				eCount[i].nStay = eCount[i].nFrame;
				
				//적군이 화면 밖에 있으면
				if (eCount[i].x &amp;gt;= 76 || eCount[i].x &amp;lt;= 4) {
					eCount[i].exist = false;
					gotoxy(eCount[i].x - 2, eCount[i].y);
					puts(&quot;　　　　&quot;);
				}
				else {
					//적군의 원래 이미지를 지우고 새로운 이미지를 그린다.
					gotoxy(eCount[i].x - 2, eCount[i].y);
					puts(&quot;　　　　&quot;);
					eCount[i].x += eCount[i].Delta;
					gotoxy(eCount[i].x - 2, eCount[i].y);
					puts(arEnemy[eCount[i].Type]);

					//1/40 확률로 총알을 발사한다.
					if (random(40) == 0) {
						for (j = 0; j &amp;lt; MAXBALL &amp;amp;&amp;amp; bCount[j].exist == true; j++) { ; }
						if (j != MAXBALL) {
							bCount[j].x = eCount[i].x + 2;
							bCount[j].y = eCount[i].y + 1;
							bCount[j].nFrame = bCount[j].nStay = eCount[i].nFrame * 6;
							bCount[j].exist = true;
						}
					}
				}
			}
		}

		gotoxy(fx - 3, 23);
		puts(&quot;&amp;lt;&amp;lt;A&amp;gt;&amp;gt;&quot;);
		gotoxy(0, 24);
		printf(&quot;점수 = %d&quot;, Score);

		delay(10);

		count++; //루프 카운터 증가
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;■ 주석으로 쓸말은 다 쓴 것 같음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;■ C스타일로 만들어진 예제라서 통으로 움직인다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;■ C++스타일의 클래스로 재설계해보고 싶다.&lt;/p&gt;</description>
      <category>리메이크 중/C,C++ 실습 중심</category>
      <author>라이피 (Lypi)</author>
      <guid isPermaLink="true">https://lypicfa.tistory.com/679</guid>
      <comments>https://lypicfa.tistory.com/679#entry679comment</comments>
      <pubDate>Thu, 12 Jan 2023 17:44:42 +0900</pubDate>
    </item>
  </channel>
</rss>