<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발 메모리</title>
    <link>https://iamjaeeuncho.tistory.com/</link>
    <description>기억하려고 기록하는 중</description>
    <language>ko</language>
    <pubDate>Thu, 18 Jun 2026 10:10:48 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>재은초</managingEditor>
    <image>
      <title>개발 메모리</title>
      <url>https://tistory1.daumcdn.net/tistory/6405398/attach/373de814ae644709b96dc57f198eaa52</url>
      <link>https://iamjaeeuncho.tistory.com</link>
    </image>
    <item>
      <title>[C] C언어 참조 - 바이트 저장 순서, 비트 단위 연산, 음수/실수의 표현</title>
      <link>https://iamjaeeuncho.tistory.com/421</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;비트(bit)와 바이트(byte)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터는 모든 데이터를 2진수로 표현하고 처리한다.&lt;/li&gt;
&lt;li&gt;비트(bit)란 컴퓨터가 데이터를 처리하기 위해 사용하는 데이터의 최소 단위다. 이러한 비트에는 2진수의 값(0과 1)을 단 하나만 저장할 수 있다.&lt;/li&gt;
&lt;li&gt;바이트(byte)란 위와 같은 비트가 8개 모여서 구성되며, 한 문자를 표현할 수 있는 최소 단위다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;바이트&amp;nbsp;저장&amp;nbsp;순서(byte&amp;nbsp;order)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터는 데이터를 메모리에 저장할 때 바이트(byte) 단위로 나눠서 저장한다.&amp;nbsp;하지만 컴퓨터가 저장하는 데이터는 대게 32비트(4바이트)나 64비트(8바이트)로 구성된다.&amp;nbsp;따라서 이렇게 연속되는 바이트를 순서대로 저장해야 하는데, 이것을 바이트 저장 순서(byte order)라고 한다.&lt;/li&gt;
&lt;li&gt;이때 바이트가 저장되는 순서에 따라 ① 빅 엔디안(big endian) ② 리틀 엔디안(little endian)과 같이 두 가지 방식으로 나눌 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;빅&amp;nbsp;엔디안(big&amp;nbsp;endian)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빅 엔디안 방식은 낮은 주소에 데이터의 높은 바이트(MSB, Most Significant Bit)부터 저장하는 방식이다.&lt;/li&gt;
&lt;li&gt;이 방식은 평소 우리가 숫자를 사용하는 선형 방식과 같은 방식이다. 따라서 메모리에 저장된 순서 그대로 읽을 수 있으며, 이해하기가 쉽다는 장점을 가지고 있다.&lt;/li&gt;
&lt;li&gt;SPARC을 포함한 대부분의 RISC CPU 계열에서는 이 방식으로 데이터를 저장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015887702&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 2비트 크기의 정수
0x12345678         

// 이 정수는 각각 다음과 같이 1바이트값 4개로 구성
0x12, 0x34, 0x56, 0x78&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PSRYQ/dJMcahYZQNY/wyyN761I6CBA0eSGNK8NoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PSRYQ/dJMcahYZQNY/wyyN761I6CBA0eSGNK8NoK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_refer_endian&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PSRYQ/dJMcahYZQNY/wyyN761I6CBA0eSGNK8NoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPSRYQ%2FdJMcahYZQNY%2FwyyN761I6CBA0eSGNK8NoK%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;278&quot; height=&quot;254&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_refer_endian&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;리틀&amp;nbsp;엔디안(little&amp;nbsp;endian)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리틀 엔디안 방식은 낮은 주소에 데이터의 낮은 바이트(LSB, Least Significant Bit)부터 저장하는 방식이다.&lt;/li&gt;
&lt;li&gt;이 방식은 평소 우리가 숫자를 사용하는 선형 방식과는 반대로 거꾸로 읽어야 한다.&lt;/li&gt;
&lt;li&gt;대부분의 인텔 CPU 계열에서는 이 방식으로 데이터를 저장한다.&lt;/li&gt;
&lt;li&gt;앞서 예를 든 정수 &quot;0x12345678&quot;를 리틀 엔디안 방식으로 저장하면 다음 그림과 같이 저장된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pUcy9/dJMcabEt1rX/9BTXIIhNjNQR5TASvkqCb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pUcy9/dJMcabEt1rX/9BTXIIhNjNQR5TASvkqCb1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_refer_endian&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pUcy9/dJMcabEt1rX/9BTXIIhNjNQR5TASvkqCb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpUcy9%2FdJMcabEt1rX%2F9BTXIIhNjNQR5TASvkqCb1%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;280&quot; height=&quot;256&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_refer_endian&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;빅&amp;nbsp;엔디안&amp;nbsp;vs&amp;nbsp;리틀&amp;nbsp;엔디안&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빅 엔디안과 리틀 엔디안은 단지 저장해야 할 큰 데이터를 어떻게 나누어 저장하는가에 따른 차이일 뿐, 어느 방식이 더 우수하다고는 단정할 수 없다.&lt;/li&gt;
&lt;li&gt;물리적으로 데이터를 조작하거나 산술 연산을 수행할 때에는 리틀 엔디안 방식이 더 효율적이다. 하지만 데이터의 각 바이트를 배열처럼 취급할 때에는 빅 엔디안 방식이 더 적합하다.&lt;/li&gt;
&lt;li&gt;현재 대부분의 시스템은 인텔 기반의 윈도우이므로 리틀 엔디안 방식을 사용하고 있을 것이지만 네트워크를 통해 데이터를 전송할 때에는 빅 엔디안 방식이 사용된다. 따라서 인텔 기반의 시스템에서 소켓 통신을 할 때는 바이트 순서에 신경을 써서 데이터를 전달해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;바이트&amp;nbsp;저장&amp;nbsp;순서의&amp;nbsp;확인&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1781016682142&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int i;
int test = 0x12345678;
char* ptr = (char*)&amp;amp;test; // 1 바이트만을 가리키는 포인터를 생성함.

for (i = 0; i &amp;lt; sizeof(int); i++) {
    printf(&quot;%x&quot;, ptr[i]); // 1 바이트씩 순서대로 그 값을 출력함.
}

// 78563412 - 결과가 이렇다면 리틀 엔디안 방식의 시스템
// 12345678 - 결과가 이렇다면 빅 엔디안 방식의 시스템&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;비트&amp;nbsp;단위&amp;nbsp;연산(bitwise&amp;nbsp;operation)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터는 모든 데이터를 비트(bit) 단위로 표현하고 처리한다.&lt;/li&gt;
&lt;li&gt;과거에는 개발자가 직접 비트 단위 연산을 사용하여, 복잡한 연산을 훨씬 더 빠르고 효율적으로 수행해야만 했다. 하지만 하드웨어의 발달로 이제는 비트 단위까지 생각하지 않더라도, 충분히 빠른 프로그램을 작성할 수 있게 되었다.&lt;/li&gt;
&lt;li&gt;그러나 아직도 하드웨어 관련 프로그래밍이나 시스템 프로그래밍 등 제한된 자원을 가진 시스템을 위한 프로그램에서는 비트 단위의 연산이 자주 사용되고 있다. 이러한 비트 단위 연산을 통해 사용되는 메모리 공간을 줄이거나, 성능의 향상을 기대할 수 있기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비트 연산자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비트 연산자는 비트(bit) 단위로 논리 연산을 할 때 사용하는 연산자다. 또한 왼쪽이나 오른쪽으로 전체 비트를 이동시킬 때에도 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4NqNn/dJMcaaZSFAt/8awkodRBdKJJiCEjaYdRd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4NqNn/dJMcaaZSFAt/8awkodRBdKJJiCEjaYdRd1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_refer_bitCalculation&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4NqNn/dJMcaaZSFAt/8awkodRBdKJJiCEjaYdRd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4NqNn%2FdJMcaaZSFAt%2F8awkodRBdKJJiCEjaYdRd1%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;758&quot; height=&quot;322&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_refer_bitCalculation&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비트&amp;nbsp;연산자&amp;nbsp;진리표&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비트 연산자 진리표란 각 비트의 값에 따라 얻을 수 있는 가능한 비트값을 표로 나타낸 것을 가리킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce5LkS/dJMb99NoOqh/l0Xp41KXt9CBbfkxxtgXXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce5LkS/dJMb99NoOqh/l0Xp41KXt9CBbfkxxtgXXK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_refer_bitCalculation&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce5LkS/dJMb99NoOqh/l0Xp41KXt9CBbfkxxtgXXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce5LkS%2FdJMb99NoOqh%2Fl0Xp41KXt9CBbfkxxtgXXK%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;757&quot; height=&quot;231&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_refer_bitCalculation&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비트&amp;nbsp;NOT&amp;nbsp;연산자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비트 NOT 연산자는 주어진 비트가 1이면 0으로, 0이면 1로 반전시켜 1의 보수로 만들어 준다. 이러한 비트 NOT 연산자는 피연산자가 단 하나뿐인 단항 연산자다.&lt;/li&gt;
&lt;li&gt;아래 예제처럼 비트 NOT 연산은 부호 비트도 반전시키므로, 결괏값이 음수로 변경된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781017431475&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x = 7;        // 00000000 00000000 00000000 00000111  
printf(&quot;%d&quot;, ~x); // 11111111 11111111 11111111 11111000 : -8  

// -8&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비트&amp;nbsp;AND&amp;nbsp;연산자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비트 AND 연산자는 두 개의 피연산자 비트가 모두 1일 때만 1을 반환한다. 이러한 비트 AND 연산자는 두 개의 피연산자를 가지는 이항 연산자다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781017465286&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x = 7;           // 00000000 00000000 00000000 00000111
int y = 10;          // 00000000 00000000 00000000 00001010  
printf(&quot;%d&quot;, x &amp;amp; y); // 00000000 00000000 00000000 00000010 : 2  

2&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비트&amp;nbsp;OR&amp;nbsp;연산자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비트 OR 연산자는 두 개의 피연산자 비트 중 하나라도 1일 때는 1을 반환한다. 이러한 비트 OR 연산자는 두 개의 피연산자를 가지는 이항 연산자다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781017512212&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x = 7;           // 00000000 00000000 00000000 00000111
int y = 10;          // 00000000 00000000 00000000 00001010  
printf(&quot;%d&quot;, x | y); // 00000000 00000000 00000000 00001111 : 15  

// 15&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비트&amp;nbsp;XOR&amp;nbsp;연산자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XOR 연산이란&amp;nbsp;&amp;nbsp;배타적 논리합(exclusive OR)이라고도 불리며, 두 개의 피연산자 중 하나만이 1일 때 1을 반환한다. 이러한 성질을 이용하면 비트 NOT 연산자는 모든 비트를 반전시키지만, 비트 XOR 연산자는 지정한 비트만을 반전시킬 수 있다.&lt;/li&gt;
&lt;li&gt;즉 비트가 1로 설정된 비트와 XOR 연산을 한 비트만이 반전되므로 반전될 비트를 직접 지정할 수 있게 됩니다. 이러한 비트 XOR 연산자는 두 개의 피연산자를 가지는 이항 연산자다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781017557740&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x = 7;           // 00000000 00000000 00000000 00000111
int y = 10;          // 00000000 00000000 00000000 00001010  
printf(&quot;%d&quot;, x ^ y); // 00000000 00000000 00000000 00001101 : 13  

// 13&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비트&amp;nbsp;시프트&amp;nbsp;연산자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비트 시프트(shift) 연산자는 비트 이동 연산자라고도 하며, 지정한 수만큼 모든 비트를 전부 좌우로 이동시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왼쪽&amp;nbsp;시프트&amp;nbsp;연산자&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왼쪽 시프트 연산자(&amp;lt;&amp;lt;, left shift)는 지정한 수만큼 피연산자의 모든 비트를 전부 왼쪽으로 이동시킨다.&lt;/li&gt;
&lt;li&gt;이렇게 왼쪽으로 모든 비트를 이동시키면, 맨 왼쪽의 비트는 지정된 수만큼 자동으로 버려지게 된다. 그리고 왼쪽으로 이동된 수만큼 비게 되는 오른쪽 비트에는 자동으로 0이 채워진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781017639484&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;피연산자&amp;lt;&amp;lt;이동할비트수&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 예제에서 -1을 2비트만큼 왼쪽으로 이동한 결괏값은 -4가 되며, 3비트만큼 왼쪽으로 이동한 결괏값은 -8이 된다. 즉, 왼쪽 시프트 연산으로 1비트씩 모든 비트를 이동시킬 때마다 피연산자의 값은 두 배씩 증가하게 되는 걸 알 수 있다.&lt;/li&gt;
&lt;li&gt;이러한 특징을 이용하여 속도가 다소 느린 산술 곱셈 연산을 왼쪽 시프트 연산으로 대체할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781017679863&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x = -1;        // 11111111 11111111 11111111 11111111
int y = x&amp;lt;&amp;lt;2;      // 왼쪽으로 2비트만큼 이동시킴.
int z = x&amp;lt;&amp;lt;3;      // 왼쪽으로 3비트만큼 이동시킴.  

printf(&quot;%d\n&quot;, y); // 11111111 11111111 11111111 11111100 : -4
printf(&quot;%d&quot;, z);   // 11111111 11111111 11111111 11111000 : -8  

// -4
// -8&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오른쪽&amp;nbsp;시프트&amp;nbsp;연산자&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오른쪽 시프트 연산자(&amp;gt;&amp;gt;, right shift)는 지정한 수만큼 피연산자의 모든 비트를 전부 오른쪽으로 이동시킨다.&lt;/li&gt;
&lt;li&gt;이렇게 오른쪽으로 모든 비트를 이동시키면 맨 오른쪽의 비트는 지정된 수만큼 자동으로 버려지게 된다. 그리고 오른쪽으로 이동된 수만큼 비게 되는 왼쪽 비트에는 자동으로 0이 채워진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781017982401&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;피연산자&amp;gt;&amp;gt;이동할비트수&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이때 오른쪽 시프트 연산은 왼쪽 시프트 연산과는 달리 시스템마다 약간의 차이가 발생하게 된다. 일부 시스템에서는 최상위 부호 비트(MSB)까지 시프트 연산의 대상이 되기도 하지만, 일부 시스템에서는 최상위 부호 비트는 시프트 연산의 대상에서 제외하기도 하기 때문이다. 따라서 최상위 부호 비트가 중요한 의미를 가지는 부호있는 정수에 대해서는 가급적 시프트 연산을 하지 않는 것이 좋다.&lt;/li&gt;
&lt;li&gt;현재 대부분의 시스템에서는 최상위 부호 비트(MSB)를 시프트 연산의 대상에서 제외하고 있다.&lt;/li&gt;
&lt;li&gt;아래 예제에서 -8을 2비트만큼 오른쪽으로 이동한 결괏값은 -2가 되며, 3비트만큼 오른쪽으로 이동한 결괏값은 -1이 된다. 즉, 오른쪽 시프트 연산으로 1비트씩 모든 비트를 이동시킬 때마다 피연산자의 값은 두 배씩 감소하게 되는 걸 알 수 있다. 이러한 특징을 이용하여 속도가 다소 느린 산술 나눗셈 연산을 오른쪽 시프트 연산으로 대체할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781018012863&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x = -8;        // 11111111 11111111 11111111 11111000
int y = x&amp;gt;&amp;gt;2;      // 오른쪽으로 2비트만큼 이동시킴.
int z = x&amp;gt;&amp;gt;3;      // 오른쪽으로 3비트만큼 이동시킴.  

printf(&quot;%d\n&quot;, y); // 11111111 11111111 11111111 11111110 : -2
printf(&quot;%d&quot;, z);   // 11111111 11111111 11111111 11111111 : -1

// -2
// -1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정수의&amp;nbsp;표현&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터에서 정수를 표현하는 방법은 크게 부호없는 정수와 부호있는 정수로 나누어 생각할 수 있다.&lt;/li&gt;
&lt;li&gt;부호없는 정수를 표현할 때에는 단지 해당 정수 크기의 절댓값을 2진수로 변환하여 표현하면 된다. 하지만 문제는 부호있는 정수에서 음수를 표현하는 방법에 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;음수의&amp;nbsp;표현&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;부호 비트와 절댓값 방법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부호 비트와 절댓값 방법은 최상위 1비트로 부호를 표현하고, 나머지 비트로 해당 정수의 절댓값을 표현하는 방법이다. 이 방법을 사용하면 최상위의 1비트가 부호를 표현하기 위해 사용되어 표현할 수 있는 절댓값의 범위는 절반으로 줄어든다. 그러나 음수를 표현할 수 있으므로, 총 표현할 수 있는 크기는 거의 비슷해진다. 하지만&amp;nbsp;이&amp;nbsp;방법으로&amp;nbsp;음수를&amp;nbsp;표현하면&amp;nbsp;+0과&amp;nbsp;-0이&amp;nbsp;따로&amp;nbsp;존재하게&amp;nbsp;됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1의 보수법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1의 보수법은 해당 양수의 모든 비트를 반전하여 음수를 표현하는 방법이다. 이 방법을 사용하면 음수를 비트 NOT 연산만으로 표현할 수 있어서 연산이 매우 간단해진다.&amp;nbsp;하지만 1의 보수법은 부호 비트와 절댓값 방법과 같이 +0과 -0이 따로 존재하는 문제점을 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce4eIZ/dJMcabLkSy3/dlpHhBfyIftEaHpmOZAqx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce4eIZ/dJMcabLkSy3/dlpHhBfyIftEaHpmOZAqx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce4eIZ/dJMcabLkSy3/dlpHhBfyIftEaHpmOZAqx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce4eIZ%2FdJMcabLkSy3%2FdlpHhBfyIftEaHpmOZAqx1%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvZro9/dJMcaaZSF2p/gzeIxKWj9xK27WwbkOFFrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvZro9/dJMcaaZSF2p/gzeIxKWj9xK27WwbkOFFrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvZro9/dJMcaaZSF2p/gzeIxKWj9xK27WwbkOFFrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvZro9%2FdJMcaaZSF2p%2FgzeIxKWj9xK27WwbkOFFrk%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;https://www.tcpschool.com/c/c_refer_negativeNumber&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2의 보수법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2의 보수법은 해당 양수의 모든 비트를 반전한 1의 보수에 1을 더하여 음수를 표현하는 방법이다. 이 방법은 앞서 살펴본 방법이 모두 두 개의 0을 가지는 문제점(+0과 -0)을 해결하기 위해 고안되었다.&lt;/li&gt;
&lt;li&gt;이 방법을 사용하면 -0은 2의 보수를 구하는 과정에서 최상위 비트를 초과한 오버플로우가 발생하여 +0이 된다. 따라서 2의 보수법에서는 단 하나의 0만이 존재하게 된다. 이 때문에 현재 대부분의 시스템에서는 모두 2의 보수법으로 음수를 표현하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LsHLo/dJMb99NoOHs/KIWowdytHkzL92CYfR5ag1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LsHLo/dJMb99NoOHs/KIWowdytHkzL92CYfR5ag1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LsHLo/dJMb99NoOHs/KIWowdytHkzL92CYfR5ag1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLsHLo%2FdJMb99NoOHs%2FKIWowdytHkzL92CYfR5ag1%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5zXOM/dJMcag6Rx0W/ksRKeZ8NC6DgAtSecbFUb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5zXOM/dJMcag6Rx0W/ksRKeZ8NC6DgAtSecbFUb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5zXOM/dJMcag6Rx0W/ksRKeZ8NC6DgAtSecbFUb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5zXOM%2FdJMcag6Rx0W%2FksRKeZ8NC6DgAtSecbFUb1%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;https://www.tcpschool.com/c/c_refer_negativeNumber&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;실수의&amp;nbsp;표현&amp;nbsp;방식&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터에서 실수를 표현하는 방법은 정수에 비해 훨씬 복잡하다. 왜냐하면 컴퓨터에서는 실수를 정수와 마찬가지로 2진수로만 표현해야 하기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;고정 소수점(fixed point) 방식&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실수는 보통 정수부와 소수부로 나눌 수 있다. 따라서 실수를 표현하는 가장 간단한 방식은 소수부의 자릿수를 미리 정해 놓고, 고정된 자릿수로 소수를 표현하는 것이다.&lt;/li&gt;
&lt;li&gt;32비트 실수를 고정 소수점 방식으로 표현하면 다음과 같다. 하지만 이 방식은 정수부와 소수부의 자릿수가 크지 않으므로, 표현할 수 있는 범위가 매우 적다는 단점이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kwQSl/dJMcacDrYMF/ajYfMkFwL5koPbq85sW4l1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kwQSl/dJMcacDrYMF/ajYfMkFwL5koPbq85sW4l1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_refer_floatingPointNumber&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kwQSl/dJMcacDrYMF/ajYfMkFwL5koPbq85sW4l1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkwQSl%2FdJMcacDrYMF%2FajYfMkFwL5koPbq85sW4l1%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;530&quot; height=&quot;208&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_refer_floatingPointNumber&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;부동 소수점(floating point) 방식&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실수는 보통 정수부와 소수부로 나누지만, 가수부와 지수부로 나누어 표현할 수도 있다.&lt;/li&gt;
&lt;li&gt;부동 소수점 방식은 이렇게 하나의 실수를 가수부와 지수부로 나누어 표현하는 방식이다.&lt;/li&gt;
&lt;li&gt;앞서 살펴본 고정 소수점 방식은 제한된 자릿수로 인해 표현할 수 있는 범위가 매우 작습지만 부동 소수점 방식은 다음 수식을 사용하여 매우 큰 실수까지도 표현할 수 있게 된다. 따라서 현재 대부분의 시스템에서는 부동 소수점 방식으로 실수를 표현하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;EEE&amp;nbsp;부동&amp;nbsp;소수점&amp;nbsp;방식&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 사용되고 있는 부동 소수점 방식은 대부분 IEEE 754 표준을 따르고 있다.&lt;/li&gt;
&lt;li&gt;32비트의 float형 실수와 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;64비트의 double형 실수를 IEEE 부동 소수점 방식으로 표현하면 다음과 같다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img style=&quot;width:49.41860465116279%&quot; src=&quot;https://blog.kakaocdn.net/dna/bFzrkc/dJMcahScUca/AAAAAAAAAAAAAAAAAAAAAMb1C3euRQcLC8dGyIHJc8FFH9RC4ummpztSo62ysk29/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;amp;expires=1782831599&amp;amp;allow_ip=&amp;amp;allow_referer=&amp;amp;signature=aDnR2OLVOY2AQtrR7%2BaO5pnf3kg%3D&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;240&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot; /&gt;&lt;img style=&quot;width:49.41860465116279%&quot; src=&quot;https://blog.kakaocdn.net/dna/bdpjlT/dJMcahScUcl/AAAAAAAAAAAAAAAAAAAAACk8BO3I116JYR-cRDEihoHNk83hNxUF56UpfO3XEQYp/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;amp;expires=1782831599&amp;amp;allow_ip=&amp;amp;allow_referer=&amp;amp;signature=VWezojQrc8nxACMmPpohYkB3KEc%3D&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;240&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot; /&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png&quot; data-phocus=&quot;//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png&quot;&gt;&lt;img src=&quot;//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=%2F%2Ft1.daumcdn.net%2Ftistory_admin%2Fstatic%2Fimages%2Fno-image-v1.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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;https://www.tcpschool.com/c/c_refer_floatingPointNumber&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;부동&amp;nbsp;소수점&amp;nbsp;방식의&amp;nbsp;오차&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부동 소수점 방식을 사용하면 고정 소수점 방식보다 훨씬 더 많은 범위까지 표현할 수 있다. 하지만 부동 소수점 방식에 의한 실수의 표현은 항상 오차가 존재한다는 단점을 가지고 있다.&lt;/li&gt;
&lt;li&gt;부동 소수점 방식에서의 오차는 앞서 살펴본 공식에 의해 발생한다. 이 공식을 사용하면 표현할 수 있는 범위는 늘어나지만, 10진수를 정확하게 표현할 수는 없게 되기 때문이다. 따라서 컴퓨터에서 실수를 표현하는 방법은 정확한 표현이 아닌 언제나 근사치를 표현할 뿐임을 항상 명심해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781020424674&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int i;
float sum = 0.1;

for (i = 0; i &amp;lt; 1000; i++) {
    sum += 0.1;  
}

printf(&quot;0.1을 1000번 더한 합계는 %f입니다.\n&quot;, sum);

// 0.1을 1000번 더한 합계는 100.099045입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제에서 0.1을 1000번 더한 합계는 정확히 100이 되어야 하지만, 실제로는 100.099045가 출력된다. 이처럼 컴퓨터에서 실수를 가지고 수행하는 모든 연산에는 언제나 작은 오차가 존재하게 된다. 이것은 C언어에서 뿐만 아니라 모든 프로그래밍 언어에서 발생하는 기본적인 문제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/421</guid>
      <comments>https://iamjaeeuncho.tistory.com/421#entry421comment</comments>
      <pubDate>Wed, 10 Jun 2026 00:54:29 +0900</pubDate>
    </item>
    <item>
      <title>[C] C언어 컴파일 - 헤더 파일, 분할 컴파일, 조건부 컴파일</title>
      <link>https://iamjaeeuncho.tistory.com/420</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;헤더&amp;nbsp;파일(header&amp;nbsp;file)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 함수는 사용되기 전에 먼저 해당 함수의 원형이 선언되어야 한다. 이 원칙은 표준 함수에도 그대로 적용되며, 표준 함수 또한 사용되기 전에 해당 함수의 원형이 선언되어야 한다.&lt;/li&gt;
&lt;li&gt;이러한 표준 함수의 원형 및 표준 함수와 관련된 다양한 정보를 가지고 있는 파일을 표준 헤더 파일이라고 한다.&lt;/li&gt;
&lt;li&gt;또한, 사용자는 자신만의 사용자 헤더 파일을 자유롭게 만들 수도 있다.&lt;/li&gt;
&lt;li&gt;헤더 파일의 확장자는 보통 .h를 사용하며, #include 선행처리 지시자를 사용하여 다른 파일에 포함시킬 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;표준 헤더 파일&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표준 함수의 원형 및 표준 함수와 관련된 다양한 정보를 가지고 있는 표준 헤더 파일은 그 크기가 상당히 크다. 하지만 크기가 큰 헤더 파일을 포함한다고 프로그램의 크기가 반드시 커지는 것은 아니다.&lt;/li&gt;
&lt;li&gt;헤더 파일의 내용은 실행 파일에 추가되는 내용보다는 컴파일러가 실행 파일을 만드는 데 사용하는 정보가 대부분이기 때문이다.&lt;/li&gt;
&lt;li&gt;표준 헤더 파일에 저장되는 정보는 다음과 같다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표준 함수의 원형&lt;/li&gt;
&lt;li&gt;표준 함수의 매크로 상수&lt;/li&gt;
&lt;li&gt;표준 함수의 사용자 정의 타입(구조체, 공용체) 정의&lt;/li&gt;
&lt;li&gt;매크로 함수의 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;사용자&amp;nbsp;헤더&amp;nbsp;파일&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;많은 개발자가 자신의 프로그램에 사용하기 위해서 자신만의 헤더 파일을 작성한다. 이러한 헤더 파일을 이용하면, 여러 파일에서 같이 공유하는 외부 변수를 선언할 수도 있다.&lt;/li&gt;
&lt;li&gt;다음 예제는 사용자가 직접 작성한 사용자 헤더 파일의 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781001110417&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#define COND 2   

struct book {
    char title[30];
    char author[30];
    int price;
};

void local(int);
int bigNum (int, int);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;분할&amp;nbsp;컴파일&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작성된 모듈(module)은 개별적으로 컴파일된 후, 링커에 의해 하나의 실행 파일로 만들어진다. 이렇게 하나의 실행 파일을 만들기 위해서 소스 파일을 여러 개로 나누어 개발하는 방식을 분할 컴파일 방식이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch6hQP/dJMb997J31h/bI3xlLCnOVzl4hPkHE7QN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch6hQP/dJMb997J31h/bI3xlLCnOVzl4hPkHE7QN1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_complie_module&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch6hQP/dJMb997J31h/bI3xlLCnOVzl4hPkHE7QN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch6hQP%2FdJMb997J31h%2FbI3xlLCnOVzl4hPkHE7QN1%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;782&quot; height=&quot;206&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_complie_module&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최종적인 실행 파일의 생성을 위해서 접근하는 변수나 호출하는 함수가 어디에 있는지 서로 연결해주는 작업을 링크(link)라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;모듈(module)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모듈(module)이란 프로그램을 구성하는 구성 요소로, 관련된 데이터와 함수를 하나로 묶은 단위를 의미한다.&lt;/li&gt;
&lt;li&gt;보통 하나의 소스 파일에 모든 함수를 작성하지 않고, 함수의 기능별로 따로 모듈을 구성한다. 이러한 모듈을 합쳐 하나의 파일로 작성하는 방식으로 프로그램을 만들게 된다.&lt;/li&gt;
&lt;li&gt;프로그램 코드를 기능별로 나눠서 독립된 파일에 저장하여 관리하는 방식을 모듈화 프로그래밍이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;extern&amp;nbsp;키워드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분할 컴파일 방식에서 여러 개의 소스 파일 사이의 상호 참조는 전역 변수와 전역 함수만이 가능하다.&lt;/li&gt;
&lt;li&gt;기본적으로 C 컴파일러는 프로그램에 등장하는 전역 변수를 오로지 해당 파일에서만 찾는다. 따라서 외부 파일에서 참조하는 전역 변수는 컴파일러에게 외부 파일에 존재하는 변수라는 사실을 따로 알려줘야 한다.&lt;/li&gt;
&lt;li&gt;외부 파일에서 선언된 전역 변수를 참조하기 위해서는 파일 내에서 extern 키워드를 사용해 다시 한 번 변수를 선언해야 한다. 그러면 C 컴파일러는 extern 키워드가 붙은 전역 변수가 외부 파일에 존재하는 변수임을 인식하고 컴파일을 진행하게 된다. extern 키워드가 붙은 전역 변수는 컴파일된 후, 링크 때가 돼서야 실제로 연결되게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;static&amp;nbsp;키워드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분할 컴파일 방식에서 변수의 접근 영역을 해당 파일로만 한정시키고자 할 때는 static 키워드를 사용하여 선언하면 된다. 이렇게 선언된 변수는 다른 소스 파일에서 extern 키워드를 사용해 선언하더라도 접근할 수 없는 전역 변수가 된다.&lt;/li&gt;
&lt;li&gt;다음 그림은 extern 키워드로 선언된 변수와 static 키워드로 선언된 변수에 접근할 수 있는 영역을 보여준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bblP56/dJMcabqYXcn/Nj3fowk4UL8rXHqn18klCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bblP56/dJMcabqYXcn/Nj3fowk4UL8rXHqn18klCk/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_complie_module&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bblP56/dJMcabqYXcn/Nj3fowk4UL8rXHqn18klCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbblP56%2FdJMcabqYXcn%2FNj3fowk4UL8rXHqn18klCk%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;568&quot; height=&quot;372&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_complie_module&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;조건부 컴파일(conditional compile)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조건부 컴파일을 사용하면 지정한 조건에 따라 코드의 일정 부분을 컴파일할지 안 할지를 지정할 수 있다.&lt;/li&gt;
&lt;li&gt;이러한 조건부 컴파일에 사용할 수 있는 조건부 컴파일 지시자(conditional compile directive)는 ① #if ② #ifdef ③ #ifndef가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;#if&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#if 지시자를 이용한 조건부 컴파일의 사용법은 C언어의 if 조건문과 매우 비슷하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781014003207&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#if 조건식1
    컴파일할 명령문1

#elif 조건식2
    컴파일할 명령문2

#else
    컴파일할 명령문3

#endif&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#if 지시자 다음에 나오는 조건식1의 결과가 0이 아니면 참, 0이면 거짓으로 간주한다.&lt;/li&gt;
&lt;li&gt;#elif 지시자를 사용하여 조건식을 여러 개 사용할 수도 있다.&lt;/li&gt;
&lt;li&gt;#else 지시자를 사용하여 모든 조건에 해당하지 않는 경우를 지정할 수도 있다.&lt;/li&gt;
&lt;li&gt;하지만 C언어의 조건문과는 달리 #endif 지시자를 사용하여 반드시 조건부 컴파일의 끝을 명시해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;#ifdef&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 개의 헤더 파일을 작성한 후에 전부 합치다 보면, 같은 이름의 변수나 함수가 중복으로 선언되어 있을 가능성이 있다. 이러한 경우에는 #ifdef 지시자를 사용하여 중복 선언의 가능성을 없앨 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015419565&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#ifdef 매크로이름
    컴파일할 명령문1

#elif 조건식
    컴파일할 명령문2

#else
    컴파일할 명령문3

#endif&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#ifdef는 'if defined'라는 문장을 줄여서 만든 것으로&amp;nbsp;&amp;nbsp;#ifdef 지시자 다음에 나오는 매크로 이름과 같은 이름의 매크로가 이미 정의되어 있으면, 컴파일할 명령문1이 컴파일될 것이다.&lt;/li&gt;
&lt;li&gt;만약 매크로 이름과 같은 이름의 매크로가 정의되어 있지 않으면, 컴파일할 명령문1은 컴파일되지 않고 넘어갈 것이다.&lt;/li&gt;
&lt;li&gt;또한 #elif 지시자와 #else 지시자를 사용하여 컴파일의 조건을 확장할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015483317&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#define PI 3.14 // 이 부분을 주석처리하고 난 후에 다시 실행시켜 보세요!  

int main(void) {
    #ifdef PI
        printf(&quot;매크로 상수 PI가 선언되어 있으며 그 값은 %.2f입니다.\n&quot;, PI);

    #else
        puts(&quot;매크로 상수 PI가 선언되어 있지 않습니다.&quot;);

    #endif
    
    return 0;
}

// 매크로 상수 PI가 선언되어 있으며 그 값은 3.14입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;#ifndef&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#ifndef 지시자를 이용한 조건부 컴파일의 사용법은 #ifdef 지시자를 이용한 조건부 컴파일과 거의 같다. 다만 #ifndef 지시자는 #ifdef 지시자와는 정반대의 조건을 검사하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015528973&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#ifndef 매크로이름
    컴파일할 명령문1

#elif 조건식
    컴파일할 명령문2

#else
    컴파일할 명령문3

#endif&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#ifndef는 'if not defined'라는 문장을 줄여서 만든 것으로 #ifndef 지시자 다음에 나오는 매크로 이름과 같은 이름의 매크로가 앞서 정의되어 있지 않으면, 컴파일할 명령문1이 컴파일될 것이다.&lt;/li&gt;
&lt;li&gt;만약 매크로 이름과 같은 이름의 매크로가 앞서 정의되어 있으면, 컴파일할 명령문1은 컴파일되지 않고 넘어갈 것이다.&lt;/li&gt;
&lt;li&gt;또한 #elif 지시자와 #else 지시자를 사용하여 컴파일의 조건을 확장할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015622860&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt; //#define PI 3.14 // 이 부분의 주석처리를 없애고 난 후에 다시 실행시켜 보세요!  

int main(void) {
    #ifndef PI
        puts(&quot;매크로 상수 PI가 선언되어 있지 않습니다.&quot;);

    #else
        printf(&quot;매크로 상수 PI가 선언되어 있으며 그 값은 %.2f입니다.\n&quot;, PI);

    #endif

    return 0;
}  

// 매크로 상수 PI가 선언되어 있지 않습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자 헤더 파일을 선언할 때에는 중복 선언을 피하기 위해 파일 내의 모든 내용을 #ifdef나 #ifndef, #endif 지시자로 감싸는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/420</guid>
      <comments>https://iamjaeeuncho.tistory.com/420#entry420comment</comments>
      <pubDate>Tue, 9 Jun 2026 23:34:07 +0900</pubDate>
    </item>
    <item>
      <title>[C] C언어 선행처리 - 선행처리기, 매크로 함수</title>
      <link>https://iamjaeeuncho.tistory.com/419</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;선행처리(preprocess)란?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선행처리란 실행 파일을 생성하는 과정에서 소스 파일 내에 존재하는 선행처리 지시문을 처리하는 작업을 의미한다. 이러한 선행처리 작업은 컴파일하기 전 선행처리기(preprocessor)에 의해 먼저 처리된다.&lt;/li&gt;
&lt;li&gt;선행처리기는 코드를 생성하는 것이 아니라, 컴파일러가 컴파일하기 좋도록 소스를 재구성해 주는 역할만을 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;선행처리문의&amp;nbsp;특징&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선행처리문은 선행처리 문자(#)로 시작한다.&lt;/li&gt;
&lt;li&gt;선행처리문은 코드 내에서 하나의 라인을 모두 차지하며, 선행처리문 뒤에 C언어 코드를 추가하여 같이 사용할 수 없다.&lt;/li&gt;
&lt;li&gt;선행처리문은 다른 C언어의 명령문과는 달리 맨 뒤에 세미콜론(;)을 붙이지 않는다.&lt;/li&gt;
&lt;li&gt;선행처리문은 소스 파일 어디에나 위치할 수 있지만, 선행처리문이 위치한 곳에서부터 파일의 끝까지만 영향을 미친다.&lt;/li&gt;
&lt;li&gt;단, 주석은 같은 라인의 선행처리문 뒤에 위치할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;선행처리&amp;nbsp;지시자(preprocessing&amp;nbsp;directives)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선행처리 문자(#)로 시작하는 선행처리 지시자는 다음과 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UhOa8/dJMcageJIiR/JlCYgDEbyUgqKHKHjaKGSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UhOa8/dJMcageJIiR/JlCYgDEbyUgqKHKHjaKGSk/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_prepro_preprocessor&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UhOa8/dJMcageJIiR/JlCYgDEbyUgqKHKHjaKGSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUhOa8%2FdJMcageJIiR%2FJlCYgDEbyUgqKHKHjaKGSk%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;770&quot; height=&quot;413&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_prepro_preprocessor&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;#include&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#include 선행처리 지시자는 외부에 선언된 함수나 상수 등을 사용하기 위해서 헤더 파일을 현재 파일에 포함할 때 사용한다.&lt;/li&gt;
&lt;li&gt;선행처리기는 #include 지시자 뒤에 나오는 파일 이름을 보고 해당 파일을 찾아서 그 내용을 현재 파일에 포함해 준다.&lt;/li&gt;
&lt;li&gt;#include 선행처리 지시문에서 파일 이름을 표시하는 방법에는 ① #include과 ② #include &quot;myStdio.h&quot;이 있다.&lt;/li&gt;
&lt;li&gt;C언어에서 제공하는 표준 헤더 파일을 포함할 때에는 보통 꺾쇠괄호(&amp;lt;&amp;gt;)를 사용한다. 꺾쇠괄호를 사용하여 파일 이름을 표시하면, 선행처리기는 가장 먼저 표준 시스템 디렉터리에서 파일 이름에 해당하는 헤더 파일을 찾는다. 하지만 표준 시스템 디렉터리에서 파일 이름에 해당하는 헤더 파일을 찾지 못하면, 현재 작업 디렉터리도 검색한다.&lt;/li&gt;
&lt;li&gt;사용자가 직접 작성한 헤더 파일을 포함할 때에는 보통 큰따옴표(&quot;&quot;)를 사용한다. 큰따옴표를 사용하여 파일 이름을 표시하면, 선행처리기는 가장 먼저 현재 작업 디렉터리에서 파일 이름에 해당하는 헤더 파일을 찾는다. 하지만 파일 이름에 해당하는 헤더 파일을 찾지 못하면, 표준 시스템 디렉터리도 검색한다.&lt;/li&gt;
&lt;li&gt;따라서 결과적으로 이 두 방법에 큰 차이는 없지만, 많은 개발자가 이 기준에 맞춰 코드를 작성하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;#define&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#define 선행처리 지시자는 함수나 상수를 단순화해주는 매크로를 정의할 때 사용한다.&lt;/li&gt;
&lt;li&gt;매크로는 함수나 상수에 이름을 붙임으로써, 해당 매크로가 무엇을 가리키고 있는지를 명확하게 나타내 준다. 따라서 코드의 가독성을 증가시키고, 코드를 훨씬 더 읽기 편하게 해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780991981046&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#define 식별자 대체리스트&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선행처리기는 #define 선행처리 지시문의 식별자(identifier)를 단순히 대체 리스트(replacement-list)로 치환해 주기만 한다. 이러한 과정을 매크로 확장(macro expansion)이라고 한다.&lt;/li&gt;
&lt;li&gt;#define 선행처리 지시문에서 식별자는 매크로(macro)라고 부르는 사용자가 미리 정의한 약어다. 이때 매크로 이름인 식별자는 C언어의 변수 이름 생성 규칙과 똑같은 생성 규칙을 따라서 작성해야 한다. 따라서 매크로 이름 중간에는 공백을 넣을 수 없지만, 실제값은 공백을 가질 수 있다. 또한, 매크로끼리 중첩하여 사용할 수도 있다. 단, 문자열에 포함된 매크로 이름에 대한 치환 작업은 이루어지지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780998096090&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#define PI 3.14  

int main(void) {
    double radius = 12;  

    printf(&quot;원주율을 나타내는 PI의 값은 %.2f입니다.\n&quot;, PI);
    printf(&quot;원의 면적은 %.2f * %.2f * %.2f = %.2f입니다.\n&quot;, PI, radius, radius, PI * radius * radius);
    return 0;
}

// 원주율을 나타내는 PI의 값은 3.14입니다.
// 원의 면적은 3.14 * 12.00 * 12.00 = 452.16입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제에서 PI라는 매크로는 3.14로 전부 단순 치환된다. 하지만 문자열에 포함된 PI라는 문자는 이러한 치환 작업에서 제외된다. 위처럼 값을 나타내는 매크로를 객체 같은 매크로(object-like macro)라고도 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;매크로&amp;nbsp;함수란?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서는 #define 선행처리 지시문에 인수로 함수의 정의를 전달함으로써, 함수처럼 동작하는 매크로를 만들 수 있다. 이러한 매크로를 함수 같은 매크로(function-like macro) 또는 매크로 함수라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780999477449&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#define SUB(X,Y) X-Y
#define PRT(X) printf(&quot;계산 결과는 %d입니다.\n&quot;, X)  

int main(void) {
    int result;
    int num_01 = 15, num_02 = 7;  

    result = SUB(num_01, num_02);
    PRT(result);
    return 0;
}  

// 계산 결과는 8입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제는 SUB(X, Y)와 PRT(X)라는 매크로 함수를 정의하고 사용하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;함수와&amp;nbsp;매크로&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매크로 함수는 일반 함수와는 달리 단순 치환만을 해주므로, 일반 함수와 완전히 똑같은 방식으로 동작하지는 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780999664170&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#define SQR(X) X*X
#define PRT(X) printf(&quot;계산 결과는 %d입니다.\n&quot;, X)  

int main(void) {
    int result;
    int x = 5;  

    result = SQR(10);
    PRT(result);

    result = SQR(x);
    PRT(result);

    result = SQR(x+3);
    PRT(result);

    return 0;
}  

// 계산 결과는 100입니다.
// 계산 결과는 25입니다.
// 계산 결과는 23입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제는 일반 함수와 매크로 함수와의 차이를 보여주는 예제다. 위의 예제에서 맨 마지막의 매크로 함수는 예상한 결과와는 전혀 다른 결괏값을 반환한다. 선행처리기는 매크로 정의에서 모든 X를 X+3으로 대체한다. 따라서 SQR(x+3)은 다음과 같이 대체되어 계산된다.&lt;/li&gt;
&lt;li&gt;x+3*x+3 = 5+3*5+3 = 5+15+3 = 23&lt;/li&gt;
&lt;li&gt;예상한 결괏값은 8*8=64였지만 전혀 다른 결괏값이 반환되는 것이다. 일반 함수는 인수를 프로그램이 실행 중일 때 전달받지만, 매크로 함수는 인수를 컴파일 이전에 미리 치환하기 때문이다. 따라서 이와 같은 오류를 미리 방지하기 위해서는 다음 예제의 ①번 코드처럼 각 인수를 모두 괄호(())로 묶어줘야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780999795532&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
① #define SQR(X) ((X)*(X)) // 매크로 함수는 이처럼 모든 인수를 괄호로 묶어줘야 함.
#define PRT(X) printf(&quot;계산 결과는 %d입니다.\n&quot;, X)  

int main(void) {
    int result;
    int x = 5;  

    result = SQR(10);
    PRT(result);

    result = SQR(x);
    PRT(result);

    result = SQR(x+3);
    PRT(result);

    return 0;
}

// 계산 결과는 100입니다.
// 계산 결과는 25입니다.
// 계산 결과는 64입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제는 앞선 예제를 수정하여 정상적인 결과를 반환하게 해주는 예제다. 이처럼 매크로 함수가 일반 함수와 같이 동작하기 위해서는 다음과 같은 사항에 주의하여 작성해야 한다. 매크로 함수는 얼핏 함수처럼 보이지만 일반 함수와는 전혀 다른 시간대에 이루어지는 다른 과정임을 명심해야 한다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매크로 함수의 전체를 괄호(())로 감싸야 한다.&lt;/li&gt;
&lt;li&gt;매크로 함수의 인수들도 각각 괄호로 감싸야 한다.&lt;/li&gt;
&lt;li&gt;매크로 함수를 호출할 때에는 증감 연산자(++, --)나 복합 대입 연산자 등은 사용하지 않는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;매크로 함수의 장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매크로 함수는 단순 치환만을 해주므로, 인수의 타입을 신경 쓰지 않는다.&lt;/li&gt;
&lt;li&gt;매크로 함수를 사용하면 여러 개의 명령문을 동시에 포함할 수 있다.&lt;/li&gt;
&lt;li&gt;함수 호출에 의한 성능 저하가 일어나지 않으므로, 프로그램의 실행속도가 향상된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;매크로 함수의 단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원하는 결과를 얻는 정확한 매크로 함수의 구현은 어려우며, 따라서 디버깅 또한 매우 어렵다.&lt;/li&gt;
&lt;li&gt;매크로 함수의 크기가 증가하면 증가할수록 사용되는 괄호 또한 매우 많아져서 가독성이 떨어진다.&lt;/li&gt;
&lt;li&gt;따라서 매크로 함수는 크기가 큰 함수보다는 간단한 함수를 대체하는 데 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;#과 ## 연산자&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#과 ## 연산자는 선행처리기 연산자로 #define 선행처리 지시문에서만 사용되는 연산자다.&lt;/li&gt;
&lt;li&gt;C언어에서 토큰(token)이란 컴파일러가 인식하는 최소 단위의 문자나 문자열을 의미한다. 이 두 연산자는 바로 이러한 토큰 단위의 연산에서 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;# 연산자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;# 연산자는 매크로 함수의 대체 리스트 안의 인수 앞에 사용하여, 토큰을 문자열로 변환시켜준다.&amp;nbsp;해당 토큰은 실인수로 치환되면서 양쪽에 위치한 큰따옴표(&quot;&quot;)를 포함해 그대로 문자열 상수로 변환된다.&lt;/li&gt;
&lt;li&gt;# 연산자를 사용하면 문자열 안에 매크로 함수로 전달된 인수를 포함시킬 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781000326501&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#define SQR(X) printf(&quot;&quot;#X&quot;의 제곱은 %d입니다.\n&quot;, ((X)*(X)))  

int main(void) {
    int x = 5;

    SQR(x);
    SQR(3+4);

    return 0;
}  

// x의 제곱은 25입니다.
// 3+4의 제곱은 49입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;##&amp;nbsp;연산자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;## 연산자는 두 개의 토큰을 하나의 토큰으로 결합해 주는 선행처리기 연산자다.&lt;/li&gt;
&lt;li&gt;이 연산자는 함수 같은 매크로뿐만 아니라 객체 같은 매크로의 대체 리스트에도 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;이 연산자를 사용하면 변수나 함수의 이름을 프로그램의 런타임에 정의할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781000393377&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#define XN(n) x ## n  

int main(void) {
    int XN(1) = 10;
    int XN(2) = 20;  

    printf(&quot;x1에 저장된 값은 %d입니다.\n&quot;, x1);
    printf(&quot;x2에 저장된 값은 %d입니다.\n&quot;, x2);

    return 0;
}  

// x1에 저장된 값은 10입니다.
// x2에 저장된 값은 20입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제에서는 XN(n)이라는 매크로 함수를 사용하여 변수의 이름을 동적으로 작성하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781000449844&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#define XN(n) x ## n
#define PRT_XN(n) printf(&quot;x&quot;#n&quot;에 저장된 값은 %d입니다.\n&quot;, x ## n)  

int main(void) {
    int XN(1) = 10;
    int XN(2) = 20;  

    PRT_XN(1);
    PRT_XN(2);

    return 0;
}  

// x1에 저장된 값은 10입니다.
// x2에 저장된 값은 20입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제는 # 연산자와 ## 연산자를 이용하여, 동적으로 작성한 변수의 이름에 접근하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;미리&amp;nbsp;정의된&amp;nbsp;매크로(predefined&amp;nbsp;macro)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서는 컴파일러가 참고해야 할 정보를 알려주기 위해서 몇몇 매크로를 미리 정의하여 제공하고 있다.&lt;/li&gt;
&lt;li&gt;미리 정의된 매크로는 #define 선행처리 지시자로 정의하지 않아도 사용할 수 있으나, 사용자가 재정의할 수는 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWcMK1/dJMcadWAX4Y/mTtumsDokRr1KlA9vZo3B0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWcMK1/dJMcadWAX4Y/mTtumsDokRr1KlA9vZo3B0/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_prepro_preMacro&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWcMK1/dJMcadWAX4Y/mTtumsDokRr1KlA9vZo3B0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWcMK1%2FdJMcadWAX4Y%2FmTtumsDokRr1KlA9vZo3B0%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;665&quot; height=&quot;322&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_prepro_preMacro&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1781000657845&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;  

int main(void) {
    printf(&quot;선행처리가 수행된 날짜는 %s입니다.\n&quot;, __DATE__);
    printf(&quot;선행처리가 수행된 시간은 %s입니다.\n&quot;, __TIME__);
    printf(&quot;현재 소스 파일에서 처리중인 라인 번호는 %d입니다.\n&quot;, __LINE__);
    printf(&quot;__STDC__ : %d\n&quot;, __STDC__);
    printf(&quot;__STDC_HOSTED__ : %d\n&quot;, __STDC_HOSTED__);

    return 0;
}

// 선행처리가 수행된 날짜는 Feb 15 2017입니다.
// 선행처리가 수행된 시간은 17:03:55입니다.
// 현재 소스 파일에서 처리중인 라인 번호는 7입니다.
// __STDC__ : 1
// __STDC_HOSTED__ : 1&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;#line&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#line 선행처리 지시자는 __LINE__ 매크로와 __FILE__ 매크로를 재정의할 수 있게 해준다.&lt;/li&gt;
&lt;li&gt;라인 번호는 int형 타입으로, 파일명은 문자열로 전달된다.&lt;/li&gt;
&lt;li&gt;이 선행처리 지시자는 사용자가 직접 사용하기보다는 주로 컴파일러가 오류 메시지를 위해 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;#error&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#error 선행처리 지시자는 지정한 오류 메시지를 출력하고, 컴파일 과정을 중단시킨다.&lt;/li&gt;
&lt;li&gt;주로 조건부 컴파일 선행처리 지시자와 함께 사용하여 디버깅에 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;#undef&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#undef 선행처리 지시자는 #define 선행처리 지시지와 정확히 반대되는 동작을 수행한다. 즉, 이미 정의되어 있는 매크로를 취소하는 동작을 수행한다.&lt;/li&gt;
&lt;li&gt;따라서 #define 선행처리 지시자에 의해 정의되는 매크로가 치환하는 범위는 #define 지시자가 정의된 위치부터 #undef 지시자에 의해 취소되는 위치나 파일의 끝까지가 된다. 단, 위에서 살펴본 미리 정의된 매크로는 사용자가 임의로 정의를 취소할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/419</guid>
      <comments>https://iamjaeeuncho.tistory.com/419#entry419comment</comments>
      <pubDate>Tue, 9 Jun 2026 19:26:14 +0900</pubDate>
    </item>
    <item>
      <title>[C] C언어 입력과 출력 - 콘솔, 파일, 함수</title>
      <link>https://iamjaeeuncho.tistory.com/418</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;버퍼(buffer)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지금까지 우리가 사용한 printf(), scanf(), puts() 함수 등은 C언어의 표준 입출력 함수다. 이러한 표준 입출력 함수를 사용할 때에는 버퍼(buffer)라는 임시 메모리 공간을 사용하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQG5Pr/dJMcagMBHlA/4UzBBOWW3nVUDXXnGbDNx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQG5Pr/dJMcagMBHlA/4UzBBOWW3nVUDXXnGbDNx1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_io_console&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQG5Pr/dJMcagMBHlA/4UzBBOWW3nVUDXXnGbDNx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQG5Pr%2FdJMcagMBHlA%2F4UzBBOWW3nVUDXXnGbDNx1%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;670&quot; height=&quot;330&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_io_console&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문자를 하나씩 전달하는 것이 아닌 묶어서 한 번에 전달하므로, 전송 시간이 적게 걸려 성능이 향상된다.&lt;/li&gt;
&lt;li&gt;사용자가 문자를 잘못 입력했을 경우 수정을 할 수가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빠른 반응이 요구되는 게임과 같은 프로그램에서는 키를 누르는 즉시 바로 전달되어야만 하므로 입력 작업에 버퍼를 사용하는 것이 반드시 좋은 것만은 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;버퍼링&amp;nbsp;방식&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입출력에 사용되는 버퍼링에는 다음과 같이 두 가지 방식이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;완전 버퍼링(fully buffered)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;완전 버퍼링은 버퍼가 가득 차면 버퍼 안의 내용을 목적지로 보내는 방식이다.&lt;/li&gt;
&lt;li&gt;이 방식은 보통 파일 입출력에서 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;라인 버퍼링(line-buffered)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라인 버퍼링은 입력된 문자 중 개행 문자가 나타날 때마다 버퍼 안의 내용을 목적지로 보내는 방식이다.&lt;/li&gt;
&lt;li&gt;이 방식은 보통 키보드 입력에서 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기타&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러한 입력 작업뿐만 아니라 printf() 함수 등을 통해 모니터에 데이터를 출력할 때도 버퍼를 사용한다.&lt;/li&gt;
&lt;li&gt;출력하고자 하는 데이터는 일단 출력 버퍼에 저장되었다가 출력 스트림을 통해 모니터로 전송된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fflush()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fflush() 함수는 인수로 전달된 스트림에 연결된 버퍼를 비워준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780907573795&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fflush(FILE *stream);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인수로 전달되는 스트림이 입력 스트림과는 관련이 없으며, 출력 스트림과 관련이 있습다.&lt;/li&gt;
&lt;li&gt;출력 스트림이 인수로 전달되면 출력 버퍼 안에 있는 데이터를 즉시 목적지로 보내준다.&lt;/li&gt;
&lt;li&gt;만약에 널 포인터가 인수로 전달되면, 해당 프로그램에서 앞서 정의한 모든 스트림에 대한 버퍼를 전부 비워준다.&lt;/li&gt;
&lt;li&gt;fflush() 함수는 버퍼를 성공적으로 비우면 0을 반환하고, 버퍼를 비우는 데 실패하면 EOF(End Of File)를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780907728109&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;  

int main(void) {
    char str[20];
    char ch;  

    puts(&quot;당신의 이름을 적어주세요 : &quot;);
    scanf(&quot;%s&quot;, str);

    puts(&quot;당신의 성별을 약자로 적어주세요 : &quot;);
    puts(&quot;(남성=M, 여성=F)&quot;);
    scanf(&quot;%c&quot;, &amp;amp;ch);  

    if (ch=='m' | ch=='M') {
        printf(&quot;당신은 남성인 %s입니다.\n&quot;, str);
    } else if(ch=='f' | ch=='F') {
        printf(&quot;당신은 여성인 %s입니다.\n&quot;, str);
    } else {
        printf(&quot;%s님, 성별을 잘못 입력하셨습니다.\n&quot;, str);
    }
    return 0;
}

// 당신의 이름을 적어주세요 :
// 홍길동
// 당신의 성별을 약자로 적어주세요 :
// &amp;lt;남성=M, 여성=F&amp;gt;
// 홍길동님, 성별을 잘못 입력하셨습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제를 실행하면 사용자가 이름을 입력할 수 있지만, 성별은 입력하지 못하고 프로그램이 종료된다. 그 이유는 이름을 입력받을 때 마지막으로 입력한 엔터(Enter) 키가 입력 버퍼에 남아있기 때문이다. 이렇게 입출력 함수는 입력 버퍼에 데이터가 남아 있으면, 키보드로부터 데이터를 입력받지 않고 버퍼에 남아있는 데이터를 먼저 사용한다. 따라서 이 프로그램이 제대로 동작하기 위해서는 다음과 같이 fflush() 함수를 이용해 버퍼에 남아있는 데이터를 비워야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780907998552&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;  

int main(void) {
    char str[20];
    char ch;  

    puts(&quot;당신의 이름을 적어주세요 : &quot;);
    scanf(&quot;%s&quot;, str);

	fflush(stdin); // 표준 입력 스트림의 입력 버퍼를 비움  
    
    puts(&quot;당신의 성별을 약자로 적어주세요 : &quot;);
    puts(&quot;(남성=M, 여성=F)&quot;);
    scanf(&quot;%c&quot;, &amp;amp;ch);  

    if (ch=='m' | ch=='M') {
        printf(&quot;당신은 남성인 %s입니다.\n&quot;, str);
    } else if(ch=='f' | ch=='F') {
        printf(&quot;당신은 여성인 %s입니다.\n&quot;, str);
    } else {
        printf(&quot;%s님, 성별을 잘못 입력하셨습니다.\n&quot;, str);
    }
    return 0;
}

// 당신의 이름을 적어주세요 :
// 홍길동
// 당신의 성별을 약자로 적어주세요 :
// &amp;lt;남성=M, 여성=F&amp;gt;
// M
// 당신은 남성인 홍길동입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fflush()은 입력스트림과 관련이 있다고 알고 있지만, 결과적으로는 출력스트림에만 관련이 있다. 출력스트림으론 stdout, stderr이 있다. Visual Studio 2013에서는 비표준함수인 fflush()를 허용해주고 있지만, Visual Studio2015부터 비표준함수인 fflush()가 사라졌기 때문에 위의 예제에서 fflush(stdin)을 사용하더라도 똑같은 현상이 반복될 것이다. 그렇기 때문에 입력 버퍼를 지우기 위해서는 fflush()함수가 아닌 getchar() 함수를 이용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780908171093&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;  

int main(void) {
    char str[20];
    char ch;  
    
    puts(&quot;당신의 이름을 적어주세요 : &quot;);
    scanf(&quot;%s&quot;, str);
    getchar()

    puts(&quot;당신의 성별을 약자로 적어주세요 : &quot;);
    puts(&quot;(남성=M, 여성=F)&quot;);
    scanf(&quot;%c&quot;, &amp;amp;ch);  

    if (ch=='m' | ch=='M') {
        printf(&quot;당신은 남성인 %s입니다.\n&quot;, str);
    } else if(ch=='f' | ch=='F') {
        printf(&quot;당신은 여성인 %s입니다.\n&quot;, str);
    } else {
        printf(&quot;%s님, 성별을 잘못 입력하셨습니다.\n&quot;, str);
    }
    return 0;
}

// 당신의 이름을 적어주세요 :
// 홍길동
// 당신의 성별을 약자로 적어주세요 :
// &amp;lt;남성=M, 여성=F&amp;gt;
// M
// 당신은 남성인 홍길동입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제에서 getchar()함수를 이용하면 이름을 입력받을 때 마지막으로 입력한(Enter)키를 입력버퍼에서 비워주기 때문에 프로그램이 정상적으로 작동한다. fflush()함수는 출력스트림만 관련있기 때문에 fflush()함수를 이용해 입력버퍼를 비우기보다는 getchar()함수를 이용하여 입력버퍼를 지워야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;파일(file)이란?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일(file)이란 의미 있는 정보를 담고 있으며, 이름을 가지고 있는 저장 장치상의 논리적인 단위를 의미한다. C언어에서는 이러한 파일을 바이트별로 따로 읽을 수 있는 연속적인 바이트의 집합으로 취급한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;파일의&amp;nbsp;종류&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바이너리 파일(binary file)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바이너리 파일은 데이터의 저장과 처리를 목적으로 0과 1의 이진 형식으로 인코딩된 파일을 가리킨다.&lt;/li&gt;
&lt;li&gt;프로그램이 이 파일의 데이터를 읽거나 쓸 때는 데이터의 어떠한 변환도 일어나지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;텍스트 파일(text file)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;텍스트 파일은 사람이 알아볼 수 있는 문자열로 이루어진 파일을 가리킨다.&lt;/li&gt;
&lt;li&gt;프로그램이 이 파일의 데이터를 읽거나 쓸 때는 포맷 형식에 따라 데이터의 변환이 일어난다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;파일의&amp;nbsp;입출력&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 콘솔 장치에 대한 스트림은 프로그램 실행 시 자동으로 생성되며, 프로그램 종료 시 자동으로 소멸한다. 하지만 파일과의 연결을 위한 스트림은 사용자가 직접 생성하고 소멸시켜야 한다.&lt;/li&gt;
&lt;li&gt;C언어에서 파일에 대한 입출력 동작은 다음과 같은 순서에 따라 진행된다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;① 파일과의 스트림 생성&lt;/li&gt;
&lt;li&gt;② FILE 구조체 변수의 포인터를 이용한 작업 진행&lt;/li&gt;
&lt;li&gt;③ 파일과의 스트림 종결&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fopen()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fopen() 함수는 파일을 열어주는 함수다.&lt;/li&gt;
&lt;li&gt;파일을 연다는 것은 파일과의 입출력을 위한 스트림을 생성한다는 의미다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780908711976&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
FILE *fopen(const char * restrict filename, const char * restrict mode);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fopen() 함수의 첫 번째 인수는 열고자 하는 파일의 이름과 그 경로를 가지고 있는 문자열이다.&lt;/li&gt;
&lt;li&gt;두 번째 인수는 파일을 여는 데 사용할 모드를 지정하는 문자열이다.&lt;/li&gt;
&lt;li&gt;모드 문자열은 파일의 사용 용도를 결정하는 문자열과 파일의 데이터를 어떤 방식으로 입출력할지 결정하는 문자열로 구성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;모드&amp;nbsp;문자열&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fopen() 함수는 파일을 여는 데 사용할 모드 문자열을 두 번째 인수로 전달받는다. 이 모드 문자열은 파일의 사용 용도를 결정하고, 파일의 데이터를 어떤 방식으로 입출력할지를 결정한다.&lt;/li&gt;
&lt;li&gt;우선 파일의 사용 용도를 결정하는데 사용할 수 있는 모드 문자열은 다음과 같다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;r (read mode) : 읽기 전용 모드&lt;/li&gt;
&lt;li&gt;w (write mode) : 쓰기 전용 모드&lt;/li&gt;
&lt;li&gt;a (append mode) : 추가 모드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파일의 데이터를 어떤 방식으로 입출력할지를 결정하는 사용할 수 있는 모드 문자열은 다음과 같다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;t (text mode) : 해당 파일의 데이터를 텍스트 파일로 인식하고 입출력함&lt;/li&gt;
&lt;li&gt;b (binary mode) : 해당 파일의 데이터를 바이너리 파일로 인식하고 입출력함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;추가적으로 다음과 같은 모드 문자열을 사용할 수 있다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;x (exclusive mode) : 열고자 하는 파일이 이미 존재하면 파일 개방에 실패함&lt;/li&gt;
&lt;li&gt;+ (update mode) : 파일을 읽을 수도 있고 쓸 수도 있는 모드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;따라서 fopen() 함수에서 사용할 수 있는 모드 문자열의 조합은 다음과 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;screencapture-tcpschool-c-c-io-file-2026-06-08-17_57_13.png&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;1085&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y3Jk6/dJMb9900mD8/KLKX4LSueLAwBH7bzpayC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y3Jk6/dJMb9900mD8/KLKX4LSueLAwBH7bzpayC1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_io_file&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y3Jk6/dJMb9900mD8/KLKX4LSueLAwBH7bzpayC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy3Jk6%2FdJMb9900mD8%2FKLKX4LSueLAwBH7bzpayC1%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;664&quot; height=&quot;1085&quot; data-filename=&quot;screencapture-tcpschool-c-c-io-file-2026-06-08-17_57_13.png&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;1085&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_io_file&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램이 성공적으로 파일을 열면, fopen() 함수는 FILE 구조체 변수의 포인터를 반환한다. 만약에 해당 파일을 열 수 없으면, fopen() 함수는 널 포인터를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;FILE&amp;nbsp;구조체&amp;nbsp;변수의&amp;nbsp;포인터&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FILE 구조체 변수의 포인터는 해당 파일이 사용하는 버퍼 정보를 비롯한 파일에 관한 정보가 들어있는 데이터를 가리킨다.&amp;nbsp;따라서 모든 파일 입출력 함수는 FILE 구조체 변수의 포인터를 인수로 전달받아 해당 파일에 접근한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fclose()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fclose() 함수는 파일을 닫아주는 함수다.&lt;/li&gt;
&lt;li&gt;파일을 닫는다는 것은 파일과의 입출력을 위해 생성한 스트림을 소멸시키는 것을 의미한다. 즉, 버퍼에 남아있는 데이터를 파일로 완전히 내보내고, 파일 입출력을 위해 내부적으로 생성했던 FILE 구조체를 해제한다.&lt;/li&gt;
&lt;li&gt;C언어에서 다 사용한 파일은 반드시 fclose() 함수를 사용하여 닫아줘야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780913686312&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fclose(FILE *stream);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fclose() 함수는 인수로 닫고자 하는 파일을 가리키는 FILE 구조체 변수의 포인터를 전달받는다. 이 함수는 파일을 성공적으로 닫으면 0을 반환하고, 해당 파일을 닫지 못했다면 EOF(End Of File)를 반환한다.&lt;/li&gt;
&lt;li&gt;다음 예제는 단순히 파일을 여닫는 동작을 하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780913858943&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

int main(void) {
    /* 파일 open */
    FILE* ptr_file = fopen(&quot;example.txt&quot;, &quot;w+&quot;);
    if (ptr_file == NULL) {   // 파일을 열 수가 없다면, fopen() 함수는 널 포인터를 반환함.
        puts(&quot;파일을 열 수가 없습니다!&quot;);
        exit(1);            // 현재의 C프로그램 자체를 완전 종료하고, 운영체제에 1을 반환함.
    } else {
        puts(&quot;파일을 성공적으로 열었습니다!&quot;);
    }

    /* 파일 close */
    if (fclose(ptr_file)!=0) { // fclose() 함수는 파일을 성공적으로 닫으면 0을 반환함.
        puts(&quot;파일을 닫을 수가 없습니다!&quot;);
        exit(1);
    } else {
        puts(&quot;파일을 성공적으로 닫았습니다!&quot;);
    }
    return 0;
}

// 파일을 성공적으로 열었습니다!
// 파일을 성공적으로 닫았습니다!&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제는 모드 문자열로 전달된 &quot;w+&quot;의 정의에 따라, 해당 파일을 쓰는 것만이 가능한 텍스트 모드로 열어다. 이 때 파일이 없으면 새 파일을 만들며, 파일이 존재하면 해당 파일의 모든 데이터를 지우고 파일을 열게 된다. 따라서 처음 이 프로그램을 동작시키면, 해당 이름의 파일이 존재하지 않으므로 현재 디렉터리에 example.txt라는 파일이 생성될 것이다. 그 파일에 임의의 문자열을 입력하고 저장한 후, 이 프로그램을 다시 실행시키면 해당 파일의 모든 내용이 지워지는 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;파일&amp;nbsp;입출력&amp;nbsp;함수&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 인수를 하나만 전달받는 대부분의 입출력 함수는 스트림이 stdin이나 stdout으로 고정되어 있는 함수다. 하지만 입출력 함수 중에서 이름이 f로 시작되는 함수는 입출력 스트림을 사용자가 직접 지정할 수 있는 함수다. 인수로 FILE 구조체 변수의 포인터를 전달함으로써 표준 입출력 장치뿐만 아니라 파일로도 입출력을 진행할 수 있다.&lt;/li&gt;
&lt;li&gt;표준 입출력 함수 중에서 스트림을 직접 지정할 수 있는 함수는 다음과 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fgetc() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fgetc() 함수는 지정된 스트림으로부터 하나의 문자를 읽어 들이는 함수다.&lt;/li&gt;
&lt;li&gt;이 함수는 읽기에 성공하면 읽은 문자를 반환하고, 파일의 끝에 도달하면 EOF(End of File)를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780914733636&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fgetc(FILE *stream);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fputc() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fputc() 함수는 지정된 스트림에 문자 하나를 출력(저장)하는 함수다.&lt;/li&gt;
&lt;li&gt;이 함수는 저장에 성공하면 저장한 문자를 반환하고, 저장에 실패하면 EOF(End of File)를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780914812726&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fputc(int c, FILE *stream);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제는 fputc() 함수와 fgetc() 함수를 이용하여, 해당 파일의 모든 문자를 한 문자씩 읽어 들여 출력하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780914990911&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

int main(void) {
①  char ch;

    /* 파일 open */
    FILE* ptr_file = fopen(&quot;text_readonly.txt&quot;, &quot;r&quot;); // &quot;C언어 파일 입출력&quot; 문자열이 저장된 파일
    ...
    if(ptr_file != NULL) {
②      while(EOF != (ch = fgetc(ptr_file))) { // fgetc() 함수를 사용하여 파일로부터 문자 한 개를 읽어들임.
③          fputc(ch, stdout);               // fputc() 함수를 사용하여 모니터에 문자 한 개를 출력함.
        }
    }

    /* 파일 close */
    ...
    return 0;
}  

// C언어 파일 입출력&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제의 ②번 라인에서는 fgetc() 함수가 반환하는 값을 char형 변수인 ch에 저장하고 있다. 하지만 C언어의 fgetc() 함수는 char형이 아닌 int형의 값을 반환하는 함수다. 즉, 위 예제에서는 int형으로 반환된 값을 char형 변수에 저장하는 것이므로, 반환값의 상위 3바이트가 잘려나가게 될 것이다. 따라서 파일의 끝에 도달했을 때 반환되는 EOF 값인 -1의 16진수 값 '0xFFFFFFFF'도 '0xFF'로 저장될 것이다. 그러므로 while 문은 현재 파일의 끝인 EOF를 읽은 것인지, 아니면 단순히 16진수 데이터인 '0xFF'를 읽은 것인지를 알 수가 없게 된다.&lt;/li&gt;
&lt;li&gt;또한 EOF와 변수 ch를 비교할 때 EOF는 int형 값이므로, 변수 ch의 char형 값은 int형 값으로 자동 변환된다. 이때 만약 변수 ch가 signed char형이라면, EOF는 '0xFFFFFFFF'로 제대로 변환되므로 별문제가 발생하지 않는다. 하지만 변수 ch가 unsigned char형이라면, EOF는 '0x000000FF'로 변환되므로 위의 while 문은 무한히 반복될 것이다.&lt;/li&gt;
&lt;li&gt;위와 같은 문제점을 가지고 있으므로, fgetc() 함수의 반환값은 다음과 같이 반드시 int형 변수로 저장해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780927738999&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main(void) {
①  int ch;
    ...
    if(ptr_file != NULL) {
        while(EOF != (ch = fgetc(ptr_file))) { // fgetc() 함수를 사용하여 파일로부터 문자 한 개를 읽어들임.
            fputc(ch, stdout);                 // fputc() 함수를 사용하여 모니터에 문자 한 개를 출력함.
        }
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fgets() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fgets() 함수는 지정된 스트림으로부터 문자열을 읽어 들이는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780928816930&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
char *fgets(char * restrict s, int n, FILE * restrict stream)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 함수의 첫 번째 인수는 읽은 문자열이 저장될 주소이며, 세 번째 인수는 스트림을 결정할 FILE 구조체 변수의 포인터다. 두 번째 인수로 전달받은 최대 입력 문자 개수보다 하나 적은 수의 문자를 읽거나, 파일의 끝에 도달할 때까지 문자를 읽는다.&lt;/li&gt;
&lt;li&gt;이 함수는 읽기에 성공하면 읽은 문자열이 저장된 주소를 반환하고, 파일의 끝에 도달하거나 읽기에 실패하면 NULL을 반환한다.&lt;/li&gt;
&lt;li&gt;fgets() 함수는 문자를 읽어 들이는 도중에 개행 문자('\n')를 만나게 되면 곧바로 읽기를 종료한다. 그리고 지금까지 읽어 들인 문자들이 C언어에서 문자열로 인식되도록 맨 마지막에 널 문자('\0')를 자동으로 추가해 준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fputs() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fputs() 함수는 지정된 스트림에 문자열을 출력(저장)하는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780928913242&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fputs(const char * restrict s, FILE * restrict stream);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 함수의 첫 번째 인수는 쓰고자 하는 문자열의 주소이며, 두 번째 인수는 스트림을 결정할 FILE 구조체 변수의 포인터다. 인수로 전달된 스트림이 stdout이면 모니터에 문자열을 출력하고, 파일이면 문자열을 해당 파일에 저장한다.&lt;/li&gt;
&lt;li&gt;이 함수는 쓰기(저장)에 성공하면 음수가 아닌 값을 반환하고, 저장에 실패하면 EOF를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780929007027&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

int main(void) {
    char str[100];

    /* 파일 open */
    FILE* ptr_src = fopen(&quot;text_readonly.txt&quot;, &quot;r&quot;);
    FILE* ptr_dst = fopen(&quot;text_writeonly.txt&quot;, &quot;w&quot;);
    ...
    while(fgets(str, 100, ptr_src) != NULL) { // fgets() 함수를 사용하여 파일로부터 문자열을 읽어들임.
        fputs(str, ptr_dst);                // fputs() 함수를 사용하여 파일에 문자열을 옮겨적음.
    }

    puts(&quot;text_readonly.txt 파일의 모든 내용이 text_writeonly.txt 파일로 옮겨졌습니다.&quot;);
    /* 파일 close */
    ...
    return 0;
}  

// 파일을 성공적으로 열었습니다!
// text_readonly.txt 파일의 모든 내용이 text_writeonly.txt 파일로 옮겨졌습니다.
// 파일을 성공적으로 닫았습니다!&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제는 fputs()함수와 fgets() 함수를 이용하여, 파일에서 문자열을 읽어 들여 다른 파일로 옮겨 저장하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fscanf() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fscanf() 함수는 지정된 스트림으로부터 다양한 서식 변환 문자를 이용하여 문자열을 읽어 들이는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780929075147&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fscanf(FILE * restrict stream, const char * restrict format, ...);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 함수의 첫 번째 인수는 스트림을 결정할 FILE 구조체 변수의 포인터이며, 두 번째 인수는 읽어 들일 문자열의 서식이다.&lt;/li&gt;
&lt;li&gt;이 함수는 읽기에 성공하면 읽어 들인 변수의 개수를 반환하고, 읽기에 실패하면 EOF를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fprintf() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fprintf() 함수는 지정된 스트림에 다양한 서식 변환 문자를 이용하여 문자열을 출력(저장)하는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780929123885&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fprintf(FILE * restrict stream, const char * restrict format, ...);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 함수의 첫 번째 인수는 스트림을 결정할 FILE 구조체 변수의 포인터이며, 두 번째 인수는 출력할 문자열의 서식이다. 이 함수는 쓰기(저장)에 성공하면 저장한 문자열의 크기를 바이트 단위로 반환하고, 실패하면 음수를 반환한다.&lt;/li&gt;
&lt;li&gt;다음 예제는 fprintf()함수와 fscanf() 함수를 이용해 서식에 맞춰 문자열을 읽어 들여 모니터에 출력하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780929233794&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

int main(void) {
    int scan_num, int_num;
    double double_num;
    char str[100];

    /* 파일 open */
    FILE* ptr_file = fopen(&quot;text_fscanf.txt&quot;, &quot;r&quot;);
    ...

    // fscanf 함수를 사용하여 파일로부터 문자열을 서식에 맞춰서 읽어들임.
    while(scan_num = (fscanf(ptr_file, &quot;%d %lf %s&quot;, &amp;amp;int_num, &amp;amp;double_num, str)) != EOF)
    {         
        // fprintf 함수를 사용하여 모니터에 서식에 맞춰서 문자열을 옮겨적음.         
        fprintf(stdout, &quot;%d %f %s\n&quot;, int_num, double_num, str);
    }

    /* 파일 close */
    ...
    return 0;
}

// 파일을 성공적으로 열었습니다!
// 123 3.14 C언어
// 파일을 성공적으로 닫았습니다!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/418</guid>
      <comments>https://iamjaeeuncho.tistory.com/418#entry418comment</comments>
      <pubDate>Mon, 8 Jun 2026 23:34:30 +0900</pubDate>
    </item>
    <item>
      <title>[C] C언어 구조체 - 개념, 포인터, 활용, 공용체와 열거체</title>
      <link>https://iamjaeeuncho.tistory.com/417</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;구조체란?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조체(structure type)란 사용자가 C언어의 기본 타입을 가지고 새롭게 정의할 수 있는 사용자 정의 타입이다.&lt;/li&gt;
&lt;li&gt;구조체는 기본 타입만으로는 나타낼 수 없는 복잡한 데이터를 표현할 수 있다.&lt;/li&gt;
&lt;li&gt;배열이 같은 타입의 변수 집합이라고 한다면, 구조체는 다양한 타입의 변수 집합을 하나의 타입으로 나타낸 것이다. 이때 구조체를 구성하는 변수를 구조체의 멤버(member) 또는 멤버 변수(member variable)라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;구조체의&amp;nbsp;정의와&amp;nbsp;선언&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서&amp;nbsp;구조체는&amp;nbsp;struct&amp;nbsp;키워드를&amp;nbsp;사용하여&amp;nbsp;다음과&amp;nbsp;같이&amp;nbsp;정의합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834408643&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct 구조체이름 {
    멤버변수1의타입 멤버변수1의이름;
    멤버변수2의타입 멤버변수2의이름;
    ...
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 그림에서 struct라는 키워드를 사용하여 구조체의 시작을 알리고, 구조체 이름인 book으로 구조체를 정의하고 있다.&lt;/li&gt;
&lt;li&gt;중괄호 사이에 char titile[30], char author[30], int price와 같은 변수들은 book의 멤버 변수들이다.&lt;/li&gt;
&lt;li&gt;마지막 세미콜론은 구조체 정의를 종료한다는 의미다.&lt;/li&gt;
&lt;li&gt;이렇게 정의된 book 구조체는 사용자 정의 자료형이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;378&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QeQkj/dJMcaar3uM7/AINnWPYi3F7qWi6JkMcaIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QeQkj/dJMcaar3uM7/AINnWPYi3F7qWi6JkMcaIk/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_struct_intro&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QeQkj/dJMcaar3uM7/AINnWPYi3F7qWi6JkMcaIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQeQkj%2FdJMcaar3uM7%2FAINnWPYi3F7qWi6JkMcaIk%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;360&quot; height=&quot;378&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;378&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_struct_intro&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이렇게 정의된 구조체 타입은 다음과 같이 구조체 변수로 선언하여 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;또한, 구조체의 정의와 구조체 변수의 선언을 동시에 할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834521256&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct 구조체이름 구조체변수이름;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1780834537154&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct 구조체이름 {
    멤버변수1의타입 멤버변수1의이름;
    멤버변수2의타입 멤버변수2의이름;
    ...
} 구조체변수이름;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;typedef&amp;nbsp;키워드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어의 typedef 키워드는 이미 존재하는 타입에 새로운 이름을 붙일 때 사용한다.&lt;/li&gt;
&lt;li&gt;구조체 변수를 선언하거나 사용할 때에는 매번 struct 키워드를 사용하여 구조체임을 명시해야 한다. 하지만 typedef 키워드를 사용하여 구조체에 새로운 이름을 선언하면 매번 struct 키워드를 사용하지 않아도 된다.&lt;/li&gt;
&lt;li&gt;typedef 키워드를 사용하여 새로운 이름을 선언하는 방법은 다음과 같으며, 또한 구조체의 정의와 typedef 선언을 동시에 할 수도 있다.&lt;/li&gt;
&lt;li&gt;참고로 구조체의 정의와 typedef 선언을 동시에 할 때에는 구조체의 이름을 생략할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834621488&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct 구조체이름 구조체의새로운이름;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1780834640950&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct (구조체이름) {
    멤버변수1의타입 멤버변수1의이름;
    멤버변수2의타입 멤버변수2의이름;
    ...
} 구조체의새로운이름;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구조체&amp;nbsp;멤버로의&amp;nbsp;접근&amp;nbsp;방법&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열에서는 인덱스를 이용하여 배열 요소에 접근할 수 있다.&amp;nbsp;하지만 구조체에서 구조체 멤버로 접근하려고 할 때는 멤버 연산자(.)를 사용해야 한다.&lt;/li&gt;
&lt;li&gt;참고로 구조체의 주소값과 구조체의 첫 번째 멤버 변수의 주소값은 언제나 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834728668&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;구조체변수이름.멤버변수이름&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구조체&amp;nbsp;변수의&amp;nbsp;초기화&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조체 변수를 초기화할 때에는 멤버 연산자(.)와 중괄호({})를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834809127&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;구조체변수이름 = {.멤버변수1이름 = 초깃값, .멤버변수2이름 = 초깃값, ...};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 방법을 사용하면 원하는 멤버 변수만을 초기화할 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이때 멤버 변수가 정의된 순서와 초기화하는 순서는 아무런 상관이 없으며, 초기화하지 않은 멤버 변수는 0으로 초기화된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834858085&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;구조체변수이름 = {멤버변수1의초깃값, 멤버변수2의초깃값, ...};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;또한 배열의 초기화와 같은 방법으로 구조체 변수를 초기화할 수도 있다.&lt;/li&gt;
&lt;li&gt;이때 구조체 정의에서 멤버 변수가 정의된 순서에 따라 차례대로 초깃값이 설정되며, 나머지 멤버 변수는 0으로 초기화된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834945090&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;  

struct book {
    char title[30];
    char author[30];
    int price;
};  

int main(void) {
    struct book my_book = {&quot;HTML과 CSS&quot;, &quot;홍길동&quot;, 28000};
    struct book java_book = {.title = &quot;Java language&quot;, .price = 30000};  

    printf(&quot;첫 번째 책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n&quot;,
            my_book.title, my_book.author, my_book.price);

    printf(&quot;두 번째 책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n&quot;,
            java_book.title, java_book.author, java_book.price);

    return 0;
}

// 첫 번째 책의 제목은 HTML과 CSS이고, 저자는 홍길동이며, 가격은 28000원입니다.
// 두 번째 책의 제목은 Java language이고, 저자는 이며, 가격은 30000원입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제는&amp;nbsp;앞서&amp;nbsp;살펴본&amp;nbsp;두&amp;nbsp;가지&amp;nbsp;방법을&amp;nbsp;사용하여&amp;nbsp;각각&amp;nbsp;구조체&amp;nbsp;변수를&amp;nbsp;초기화하는&amp;nbsp;예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780835026862&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;  

typedef struct {
    char title[30];
    char author[30];
    int price;
}  TEXTBOOK;  

int main(void) {
    TEXTBOOK my_book = {&quot;HTML과 CSS&quot;, &quot;홍길동&quot;, 28000};
    TEXTBOOK java_book = {.title = &quot;Java language&quot;, .price = 30000};  

    printf(&quot;첫 번째 책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n&quot;,
            my_book.title, my_book.author, my_book.price);

    printf(&quot;두 번째 책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n&quot;,
            java_book.title, java_book.author, java_book.price);

    return 0;
}

// 첫 번째 책의 제목은 HTML과 CSS이고, 저자는 홍길동이며, 가격은 28000원입니다.
// 두 번째 책의 제목은 Java language이고, 저자는 이며, 가격은 30000원입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제는 앞선 예제의 구조체에 typedef 키워드를 사용하여 새로운 이름을 선언한 후 사용하는 예제다. 위 예제의 실행 결과처럼 typedef 키워드를 사용하여 구조체에 새로운 이름을 선언한 후 사용해도 structr 키워드를 그대로 사용한 것과 같은 결과를 얻을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;구조체&amp;nbsp;배열&amp;nbsp;선언&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C 언어에서 배열의 요소가 될 수 있는 타입에는 제한이 없으므로, 구조체 역시 배열의 한 요소가 될 수 있다.&lt;/li&gt;
&lt;li&gt;구조체 배열을 선언하는 방법은 다른 타입의 배열을 선언하는 방법과 같다. 또한 구조체 배열에서 각 배열 요소로 접근하는 방법도 일반 배열의 접근 방법과 완전히 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780886821061&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct book text_book[3] = {
    {&quot;국어&quot;, &quot;홍길동&quot;, 15000},
    {&quot;영어&quot;, &quot;이순신&quot;, 18000},
    {&quot;수학1&quot;, &quot;강감찬&quot;, 10000}
};  

puts(&quot;각 교과서의 이름은 다음과 같습니다.&quot;);
printf(&quot;%s, %s, %s\n&quot;, text_book[0].title, text_book[1].title, text_book[2].title);  

// 각 교과서의 이름은 다음과 같습니다.
// 국어, 영어, 수학1&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제처럼 구조체 배열은 2차원 배열의 초기화 방법과 똑같은 방법으로 초기화할 수 있으며, 멤버 연산자(.)를 사용하여 각 배열 요소의 멤버에 접근할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;388&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tZFf3/dJMcahkrADQ/hBzDhHpk140ikyjzawtJKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tZFf3/dJMcahkrADQ/hBzDhHpk140ikyjzawtJKK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_struct_pointer&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tZFf3/dJMcahkrADQ/hBzDhHpk140ikyjzawtJKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtZFf3%2FdJMcahkrADQ%2FhBzDhHpk140ikyjzawtJKK%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;388&quot; height=&quot;336&quot; data-origin-width=&quot;388&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_struct_pointer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;구조체를&amp;nbsp;가리키는&amp;nbsp;포인터&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조체 변수를 가리키는 구조체 포인터는 다음과 같이 선언한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780886904143&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct 구조체이름* 구조체포인터이름;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의&amp;nbsp;경우와는&amp;nbsp;달리&amp;nbsp;구조체의&amp;nbsp;이름은&amp;nbsp;구조체를&amp;nbsp;가리키는&amp;nbsp;주소가&amp;nbsp;아니다.&amp;nbsp;따라서&amp;nbsp;포인터에&amp;nbsp;할당할&amp;nbsp;때에는&amp;nbsp;반드시&amp;nbsp;주소&amp;nbsp;연산자(&amp;amp;)를&amp;nbsp;사용해야&amp;nbsp;한다.&lt;/li&gt;
&lt;li&gt;구조체&amp;nbsp;포인터를&amp;nbsp;이용하여&amp;nbsp;구조체의&amp;nbsp;멤버에&amp;nbsp;접근하는&amp;nbsp;방법에는 ① 참조 연산자(*)를 이용하는 방법과 ② 화살표 연산자(-&amp;gt;)를 이용하는 방법이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;참조&amp;nbsp;연산자를&amp;nbsp;이용하는&amp;nbsp;방법&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조 연산자(*)는 멤버 연산자(.)보다 연산자 우선순위가 낮으므로 반드시 괄호(())를 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780887043211&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(*구조체포인터).멤버변수이름&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;화살표 연산자를 사용하는 방법&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;화살표 연산자(-&amp;gt;)의 앞쪽에는 구조체 포인터를, 뒤쪽에는 접근하고자 하는 구조체의 멤버 변수 이름을 사용하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780887111077&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;구조체포인터 -&amp;gt; 멤버변수이름&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 두 가지 방법은 완전히 같은 동작을 하며, 일반적으로 화살표 연산자가 좀 더 많이 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780887154698&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct book my_book = {&quot;C언어 완전 해부&quot;, &quot;홍길동&quot;, 35000};
struct book* ptr_my_book; // 구조체 포인트 선언  

ptr_my_book = &amp;amp;my_book;  

strcpy((*ptr_my_book).title, &quot;C언어 마스터&quot;); // 참조 연산자(*)를 이용하는 방법
strcpy(ptr_my_book-&amp;gt;author, &quot;이순신&quot;);        // 화살표 연산자(-&amp;gt;)를 이용하는 방법
my_book.price = 32000;                        // 구조체 변수을 이용한 직접 수정  

printf(&quot;책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n&quot;,
        my_book.title, my_book.author, my_book.price);
        
// 책의 제목은 C언어 마스터이고, 저자는 이순신이며, 가격은 32000원입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;함수와&amp;nbsp;구조체&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서는 함수를 호출할 때 전달되는 인수나, 함수가 종료될 때 반환되는 반환값으로 구조체를 사용할 수 있다. 그 방식은 기본 타입과 완전히 같으며, 구조체를 가리키는 포인터나 구조체의 한 멤버 변수만을 사용할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780887382347&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct {
    int savings;
    int loan;
} PROP;  

int main(void) {
    int hong_prop;
    PROP hong = {10000000, 4000000};  

    hong_prop = calcProperty(hong.savings, hong.loan); // 구조체의 멤버 변수를 함수의 인수로 전달함  

    printf(&quot;홍길동의 재산은 적금 %d원에 대출 %d원을 제외한 총 %d원입니다.\n&quot;,
            hong.savings, hong.loan, hong_prop);
    return 0;
}

// 홍길동의 재산은 적금 10000000원에 대출 4000000원을 제외한 총 6000000원입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위와 같이 구조체를 인수로 전달하는 방식은 함수가 원본 구조체의 복사본을 가지고 작업하므로 안전하다는 장점을 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780887433861&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int hong_prop;
PROP hong = {10000000, 4000000};  

hong_prop = calcProperty(&amp;amp;hong); // 구조체의 주소를 함수의 인수로 전달함.  
printf(&quot;홍길동의 재산은 적금 %d원에 대출 %d원을 제외한 총 %d원입니다.\n&quot;, hong.savings, hong.loan, hong_prop);

// 홍길동의 재산은 적금 100원에 대출 4000000원을 제외한 총 -3999900원입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위와 같이 구조체 포인터를 인수로 전달하는 방식은 구조체의 복사본이 아닌 주소 하나만을 전달하므로 처리가 빠르다. 하지만 호출된 함수에서 원본 구조체에 직접 접근하므로 원본 데이터의 보호 측면에서는 매우 위험하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780887486690&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PROP prop;
int hong_prop;  

prop = initProperty();
hong_prop = calcProperty(&amp;amp;prop);  

printf(&quot;홍길동의 재산은 적금 %d원에 대출 %d원을 제외한 총 %d원입니다.\n&quot;, prop.savings, prop.loan, hong_prop);

// 홍길동의 재산은 적금 10000000원에 대출 4000000원을 제외한 총 6000000원입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;따라서 위 예제의 calcProperty() 함수처럼 const 키워드를 사용하여 함수에 전달된 인수를 함수 내에서는 직접 수정할 수 없도록 하는 것이 좋다.&lt;/li&gt;
&lt;li&gt;위의 예제에서 initProperty() 함수는 반환값으로 구조체를 직접 반환한다. 기본적으로 C언어의 함수는 한 번에 하나의 데이터만을 반환할 수 있다. 하지만 이렇게 구조체를 사용하면 여러 개의 데이터를 한 번에 반환할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;중첩된&amp;nbsp;구조체&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서는 구조체를 정의할 때 멤버 변수로 또 다른 구조체를 포함할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780887629906&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct name {
    char first[30];
    char last[30];
};  

struct friends {
    struct name friend_name;
    char address[30];
    char job[30];
};  

int main(void) {
    struct friends hong =
    {
        { &quot;길동&quot;, &quot;홍&quot; },
        &quot;서울시 강남구 역삼동&quot;,
        &quot;학생&quot;
    };  

    printf(&quot;%s\n\n&quot;, hong.address);
    printf(&quot;%s%s에게,\n&quot;, hong.friend_name.last, hong.friend_name.first);
    printf(&quot;그동안 잘 지냈니? 아직 %s이지?\n&quot;, hong.job);

    puts(&quot;공부 잘 하고, 다음에 꼭 한번 보자.\n잘 지내^^&quot;);
    return 0;
}

// 서울시 강남구 역삼동

// 홍길동에게,
// 그동안 잘 지냈니? 아직 학생이지?
// 공부 잘 하고, 다음에 꼭 한번 보자.
// 잘 지내^^&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;구조체의&amp;nbsp;크기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 구조체의 크기는 멤버 변수들의 크기에 따라 결정된다. 하지만 구조체의 크기가 언제나 멤버 변수들의 크기 총합과 일치하는 것은 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780887760805&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct {
    char a;
    int b;
    double c;
} TYPESIZE;  

int main(void) {
    puts(&quot;구조체 TypeSize의 각 멤버의 크기는 다음과 같습니다.&quot;);
    printf(&quot;%d %d %d\n&quot;, sizeof(char), sizeof(int), sizeof(double));  

    puts(&quot;구조체 TypeSize의 크기는 다음과 같습니다.&quot;);
    printf(&quot;%d\n&quot;, sizeof(TYPESIZE));

    return 0;
}

// 구조체 TYPESIZE의 각 멤버의 크기는 다음과 같습니다.
// 1 4 8
// 구조체 TYPESIZE의 크기는 다음과 같습니다.
// 16&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제에서 구조체 멤버 변수의 크기는 각각 1, 4, 8바이트지만 구조체의 크기는 멤버 변수들의 크기 총합인 13바이트가 아니라 16바이트가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;바이트&amp;nbsp;패딩(byte&amp;nbsp;padding)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조체를 메모리에 할당할 때 컴파일러는 프로그램의 속도 향상을 위해 바이트 패딩(byte padding)이라는 규칙을 이용한다.&lt;/li&gt;
&lt;li&gt;구조체는 다양한 크기의 타입을 멤버 변수로 가질 수 있는 타입이다. 하지만 컴파일러는 메모리의 접근을 쉽게 하기 위해 크기가 가장 큰 멤버 변수를 기준으로 모든 멤버 변수의 메모리 크기를 맞추게 된다. 이것을 바이트 패딩이라고 하며, 이때 추가되는 바이트를 패딩 바이트(padding byte)라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k3Agw/dJMcaglsHqi/8vv47tqxA0m3MJ6qviTzJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k3Agw/dJMcaglsHqi/8vv47tqxA0m3MJ6qviTzJ0/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_struct_application&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k3Agw/dJMcaglsHqi/8vv47tqxA0m3MJ6qviTzJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk3Agw%2FdJMcaglsHqi%2F8vv47tqxA0m3MJ6qviTzJ0%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;376&quot; height=&quot;348&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_struct_application&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;앞선 예제에서는 크기가 가장 큰 double형 타입의 크기인 8바이트가 기준이 된다. 맨 처음 char형 멤버 변수를 위해 8바이트가 할당되며, 할당되는 1바이트를 제외한 7바이트가 남게 된다. 그 다음 int형 멤버 변수는 남은 7바이트보다 작으므로, 그대로 7바이트 중 4바이트를 할당하고 3바이트가 남게 된다. 마지막 double형 멤버 변수는 8바이트인데 남은 공간은 3바이트뿐이므로 다시 8바이트를 할당받는다. 따라서 이 구조체의 크기는 총 16바이트가 되며, 그중에서 패딩 바이트(padding byte)는 3바이트가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;공용체&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공용체(union)는 union 키워드를 사용하여 선언하며, 한 가지를 제외한 모든 면에서 구조체와 같다. 바로 모든 멤버 변수가 하나의 메모리 공간을 공유한다는 점만이 다르다.&lt;/li&gt;
&lt;li&gt;모든 멤버 변수가 같은 메모리를 공유하므로, 공용체는 한 번에 하나의 멤버 변수밖에 사용할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WTa2P/dJMcafNHtDB/Fpw4Nh2B8OViblHdLqzQZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WTa2P/dJMcafNHtDB/Fpw4Nh2B8OViblHdLqzQZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WTa2P/dJMcafNHtDB/Fpw4Nh2B8OViblHdLqzQZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWTa2P%2FdJMcafNHtDB%2FFpw4Nh2B8OViblHdLqzQZ0%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8PgsE/dJMcaiDBoEk/ZA4QNaeWvfBzOxsH3s2vD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8PgsE/dJMcaiDBoEk/ZA4QNaeWvfBzOxsH3s2vD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8PgsE/dJMcaiDBoEk/ZA4QNaeWvfBzOxsH3s2vD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8PgsE%2FdJMcaiDBoEk%2FZA4QNaeWvfBzOxsH3s2vD1%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;https://www.tcpschool.com/c/c_struct_unionEnum&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공용체는 순서가 규칙적이지 않고, 미리 알 수 없는 다양한 타입의 데이터를 저장할 수 있도록 설계된 타입이다. 이러한 공용체는 크기가 가장 큰 멤버 변수의 크기로 메모리를 할당받는다. 따라서 공용체 배열을 사용하면, 같은 크기로 구성된 배열 요소에 다양한 크기의 데이터를 저장할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780890228989&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef union {
    unsigned char a;
    unsigned short b;
    unsigned int c;
} SHAREDATA;

int main(void) {
    SHAREDATA var;
    var.c = 0x12345678;  

    printf(&quot;%x\n&quot;, var.a);
    printf(&quot;%x\n&quot;, var.b);
    printf(&quot;%x\n&quot;, var.c);

    return 0;
}

// 78
// 5678
// 12345678&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제는 공용체의 멤버 변수를 단 하나만 초기화해도, 나머지 멤버 변수들이 모두 같은 데이터를 공유한다는 것을 보여주는 예제다.&lt;/li&gt;
&lt;li&gt;공용체에 저장된 값의 의미는 값을 저장할 때 공용체의 어떤 멤버 변수를 사용했는지에 따라 전혀 달리 해석된다. 따라서 공용체의 어떤 멤버 변수를 사용하여 저장했는지를 별도로 저장하여, 접근할 때에도 같은 멤버 변수를 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;열거체&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;열거체(enumerated types)는 새로운 타입을 선언하면서, 동시에 해당 타입이 가질 수 있는 정수형 상숫값도 같이 명시할 수 있는 타입이다. 이러한 열거체를 이용하면 프로그램의 가독성이 높아지고, 변수가 지니는 값에 의미를 부여할 수도 있게 된다.&lt;/li&gt;
&lt;li&gt;C언어에서 열거체는 enum 키워드를 사용하여 선언한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780890378075&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum Weather {SUNNY = 0, CLOUD = 10, RAIN = 20, SNOW = 30};  

int main(void) {
    enum Weather wt;  
    wt = SUNNY;  

    switch (wt) {
        case SUNNY:
            puts(&quot;오늘은 햇볕이 쨍쨍!&quot;);
            break;

        case CLOUD:
            puts(&quot;비가 올락말락하네요!&quot;);
            break;

        case RAIN:
            puts(&quot;비가 내려요.. 우산 챙기세요!&quot;);
            break;

        case SNOW:
            puts(&quot;오늘은 눈싸움하는 날!&quot;);
            break;

        default: puts(&quot;도대체 무슨 날씨인건가요!!!&quot;);
    }  
    puts(&quot;각각의 열거체에 해당하는 정수값은 다음과 같습니다.&quot;);
    printf(&quot;%d %d %d %d\n&quot;, SUNNY, CLOUD, RAIN, SNOW);
    return 0;
}

// 오늘은 햇볕이 쨍쨍!
// 각각의 열거체 멤버에 해당하는 정수값은 다음과 같습니다.
// 0 10 20 30&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제처럼 사용자가 별도로 각 멤버에 해당하는 상숫값을 명시할 수 있다. 이때 상숫값을 따로 명시하지 않으면 0부터 시작되며, 그 다음 멤버의 값은 바로 앞 멤버의 값보다 1만큼 증가되며 정의된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780890469904&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum Days {MON, TUE, WED, THU, FRI, SAT, SUN};  

int main(void) {
    enum Days today;  
    today = SAT;  

    if (today &amp;gt;= SAT &amp;amp;&amp;amp; today &amp;lt;= SUN) {
        puts(&quot;오늘은 주말이네요~ 주말에도 열심히 공부하는 여러분은 최고에요!&quot;);
    } else {
        printf(&quot;주말까지 %d일 남았어요~ 조금만 더 힘내자구요!&quot;, 5 - today);
    }

    puts(&quot;각각의 열거체에 해당하는 정수값은 다음과 같습니다.&quot;);
    printf(&quot;%d %d %d %d %d %d %d\n&quot;, MON, TUE, WED, THU, FRI, SAT, SUN);
    return 0;
}

// 오늘은 주말이네요~ 주말에도 열심히 공부하는 여러분은 최고에요!
// 각각의 열거체 멤버에 해당하는 정수값은 다음과 같습니다.
// 0 1 2 3 4 5 6&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/417</guid>
      <comments>https://iamjaeeuncho.tistory.com/417#entry417comment</comments>
      <pubDate>Mon, 8 Jun 2026 12:48:49 +0900</pubDate>
    </item>
    <item>
      <title>[C] C언어 문자와 문자열 - 입출력, 함수</title>
      <link>https://iamjaeeuncho.tistory.com/416</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;기본적인&amp;nbsp;입출력&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서는 기억장치에 저장되는 파일을 다루는 것과 마찬가지 방식으로 입출력 장치를 다룬다.&lt;/li&gt;
&lt;li&gt;따라서 키보드, 모니터와 같은 대부분의 콘솔 장치도 C 프로그램에서는 자동으로 열리는 파일처럼 다뤄진다.&lt;/li&gt;
&lt;li&gt;C언어에서는 stdin 표준 스트림을 통해 입력 장치를 다루며, stdout 표준 스트림을 통해 출력 장치를 다룬다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스트림(stream)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C 프로그램은 파일이나 콘솔의 입출력을 직접 다루지 않고, 스트림(stream)이라는 것을 통해 다룬다.&lt;/li&gt;
&lt;li&gt;스트림(stream)이란 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름을 의미한다. 즉, 스트림은 운영체제에 의해 생성되는 가상의 연결 고리를 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLO0HV/dJMcadIXHc4/YuRNkZAJsNKxOs5yBJgYK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLO0HV/dJMcadIXHc4/YuRNkZAJsNKxOs5yBJgYK0/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_string_io&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLO0HV/dJMcadIXHc4/YuRNkZAJsNKxOs5yBJgYK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLO0HV%2FdJMcadIXHc4%2FYuRNkZAJsNKxOs5yBJgYK0%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;556&quot; height=&quot;292&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_string_io&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 파일과의 연결을 위한 스트림은 사용자가 직접 생성하고 소멸시켜야 한다. 하지만 콘솔 장치에 대한 스트림은 프로그램 실행 시 자동으로 생성되며, 프로그램 종료 시 자동으로 소멸한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmhzMd/dJMcagFPncd/D3h6O8iK59Ru7wZVgYs6iK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmhzMd/dJMcagFPncd/D3h6O8iK59Ru7wZVgYs6iK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_string_io&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmhzMd/dJMcagFPncd/D3h6O8iK59Ru7wZVgYs6iK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmhzMd%2FdJMcagFPncd%2FD3h6O8iK59Ru7wZVgYs6iK%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;644&quot; height=&quot;268&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_string_io&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 기본적으로 제공되는 표준 스트림(standard stream)은 다음과 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5CGnJ/dJMcadIXHfv/dUMZ32I7zqGBmgKfSL9zF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5CGnJ/dJMcadIXHfv/dUMZ32I7zqGBmgKfSL9zF1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_string_io&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5CGnJ/dJMcadIXHfv/dUMZ32I7zqGBmgKfSL9zF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5CGnJ%2FdJMcadIXHfv%2FdUMZ32I7zqGBmgKfSL9zF1%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;585&quot; height=&quot;187&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_string_io&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;EOF(End&amp;nbsp;Of&amp;nbsp;File)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;운영체제에서 파일의 끝을 탐지하는 방법은 운영체제마다 약간씩 다르다. 하지만 C언어는 운영체제와 상관없이, 파일의 끝에 도달했을 때 언제나 특별한 값을 반환하도록 한다. 그 값을 EOF(End Of File)라고 하며, 실제로 이 값은 -1을 나타낸다.&lt;/li&gt;
&lt;li&gt;파일뿐만 아니라 키보드를 통한 입력 시에도 입력의 끝을 알려주는 방법이 필요하다. 대부분의 유닉스(UNIX) 시스템에서는 라인의 시작 위치에서 Ctrl+D를 누르면 EOF를 발생시킬 수 있다. 윈도우 명령창에서는 해당 라인의 어디에서든 Ctrl+Z를 누르고 나서 Enter를 누르면 EOF를 발생시킬 수 있다.&lt;/li&gt;
&lt;li&gt;다음 예제는 사용자가 EOF를 입력할 때까지 계속해서 영문자를 한 문자씩 입력받는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780824209654&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

int main(void) {
    char ch;
    printf(&quot;EOF가 입력될 때까지 영문자를 계속 입력받습니다 :\n&quot;);
    printf(&quot;(윈도우에서 EOF의 강제 발생은 Ctrl+Z를 누르고 나서 Enter를 누르면 됩니다)\n&quot;);

    while ((ch = getchar()) != EOF) {
        putchar(ch);
    }
    return 0;
}

// EOF가 입력될 때까지 영문자를 계속 입력받습니다 : 
// (윈도우에서 EOF의 강제 발생은 Ctrl+Z를 누르고 나서 Enter를 누르면 됩니다)
// a
// a
// b
// b
// -1
// -1
// ^Z&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;단일&amp;nbsp;문자&amp;nbsp;입력&amp;nbsp;함수&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 하나의 문자를 입력할 때에는 getchar() 함수나 fgetc() 함수를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;getchar() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;getchar() 함수는 표준 입력 스트림(stdin)인 키보드로부터 하나의 문자를 입력받는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832299021&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int getchar(void);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fgetc()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fgetc() 함수는 getchar() 함수와 마찬가지로 표준 입력 스트림(stdin)인 키보드로부터 하나의 문자를 입력받는 함수다. 하지만 getchar() 함수와는 달리 문자를 입력받을 스트림을 인수로 전달하여 직접 지정할 수 있다. 따라서 fgetc() 함수는 키보드뿐만 아니라 파일을 통해서도 문자를 입력받을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832338805&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fgetc(FILE *stream);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;단일&amp;nbsp;문자&amp;nbsp;출력&amp;nbsp;함수&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 하나의 문자를 출력할 때에는 putchar() 함수나 fputc() 함수를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;putchar()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;putchar() 함수는 표준 출력 스트림(stdout)인 모니터에 하나의 문자를 출력하는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832388829&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int putchar(int c);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fputc() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fputc() 함수는 putchar() 함수와 마찬가지로 표준 출력 스트림(stdout)인 모니터에 하나의 문자를 출력하는 함수다. 하지만 putchar() 함수와는 달리 문자를 출력할 스트림을 인수로 전달하여 직접 지정할 수 있다. 따라서 fputc() 함수는 모니터뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832431731&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fputc(int c, FILE *stream);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제는 단일 문자 입출력 함수를 사용하여, 'x'문자가 입력될 때까지 계속해서 영문자를 입력받고 출력하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832485459&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;  

int main(void) {
    char ch;
    printf(&quot;x가 입력될 때까지 영문자를 계속 입력받습니다 :\n&quot;);  

    while ((ch = getchar()) != 'x') {
        putchar(ch);
    }  

    printf(&quot;x를 입력하셨습니다.\n&quot;);  
    return 0;
}

// x가 입력될 때까지 영문자를 계속 입력받습니다 : 
// c
// c
// d
// d
// x
// x를 입력하셨습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문자열(string)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서는 큰따옴표(&quot;&quot;)를 사용해 표현되는 문자열을 문자열 상수(string constant)라고 한다. 상수라고 표현하는 이유는 해당 문자열이 이름을 가지고 있지 않으며, 문자열의 내용 또한 변경할 수 없기 때문이다.&lt;/li&gt;
&lt;li&gt;C언어에서 문자열(string)은 메모리에 저장된 일련의 연속된 문자(character)들의 집합을 의미한다. 따라서 문자형 배열을 선언하면 이 배열이 곧 문자열 변수가 된다.&lt;/li&gt;
&lt;li&gt;'%s'는&amp;nbsp;문자열을&amp;nbsp;표현하기&amp;nbsp;위한&amp;nbsp;입출력&amp;nbsp;서식&amp;nbsp;문자다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832586756&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;char str01[] = &quot;This is a string.&quot;;    // 크기를 지정하지 않은 문자열 변수 선언
char str02[7] = &quot;string&quot;;              // 크기를 지정한 문자열 변수 선언

printf(&quot;이것은 문자열 상수입니다.\n&quot;); // 문자열 상수
printf(&quot;문자열 str01에 저장되어 있는 문자열은 \&quot;%s\&quot;입니다.\n&quot;, str01);
printf(&quot;문자열 str02에 저장되어 있는 문자열은 \&quot;%s\&quot;입니다.\n&quot;, str02);  

// 이것은 문자열 상수입니다.
// 문자열 str01에 저장되어 있는 문자열은 &quot;This is a string.&quot;입니다.
// 문자열 str02에 저장되어 있는 문자열은 &quot;string&quot;입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;널(NULL)&amp;nbsp;문자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문자형 배열로 선언된 문자열 변수는 문자열의 끝을 프로그램에 따로 알려주어야 한다. 그래야만 프로그램이 실제 문자열에 속한 값과 그 외의 쓰레깃값을 구분할 수 있다. 따라서 C언어에서는 문자열에 속한 데이터가 끝나면, 문자열의 끝을 의미하는 문자를 하나 더 삽입해 준다. 이 문자를 널(NULL) 문자라고 하며, '\0'으로 표시하고 아스키코드값은 0이다.&lt;/li&gt;
&lt;li&gt;다음 예제는 널 문자를 제외한 문자열의 길이를 계산하여 출력해주는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832724754&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int str_len = 0;
char str[] = &quot;string&quot;;

while (str[str_len] != '\0') { // 널 문자가 나올 때까지 길이를 증가함
    str_len++;
}

printf(&quot;이 문자열의 길이는 %d입니다.\n&quot;, str_len);

// 이 문자열의 길이는 6입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;382&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nIUkZ/dJMcah5NFUz/SkPHknKMF1Dxv58uIslBDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nIUkZ/dJMcah5NFUz/SkPHknKMF1Dxv58uIslBDk/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_string_string&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nIUkZ/dJMcah5NFUz/SkPHknKMF1Dxv58uIslBDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnIUkZ%2FdJMcah5NFUz%2FSkPHknKMF1Dxv58uIslBDk%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;382&quot; height=&quot;296&quot; data-origin-width=&quot;382&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_string_string&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문자열&amp;nbsp;입력&amp;nbsp;함수&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 문자열을 입력할 때에는 fgets() 함수를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fgets()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fgets() 함수는 키보드뿐만 아니라 파일에서도 문자열을 입력받을 수 있는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832802834&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
char *fgets(char * restrict s, int n, FILE * restrict stream);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fgets() 함수의 첫 번째 인수는 입력받는 문자열을 저장하기 위해 선언한 배열의 시작 주소를 전달한다. 두 번째 인수로는 입력받을 수 있는 문자열의 최대 길이를 전달하고, 마지막 인수로는 문자열을 입력받을 스트림을 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문자열&amp;nbsp;출력&amp;nbsp;함수&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서&amp;nbsp;문자열을&amp;nbsp;입력할&amp;nbsp;때에는&amp;nbsp;puts()함수나&amp;nbsp;fputs()&amp;nbsp;함수를&amp;nbsp;사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;puts() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;puts() 함수는 표준 출력 스트림(stdout)인 모니터에 하나의 문자열을 출력하는 함수다. 이 함수는 모니터에 문자열을 출력한 다음에 자동으로 줄을 바꿔준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832888611&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int puts(const char *s);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;puts() 함수는 인수로 출력할 문자열을 가리키는 포인터를 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fputs()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fputs() 함수는 모니터뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있는 함수다. 이 함수는 puts() 함수와는 달리 문자열을 출력한 다음에 자동으로 줄을 바꿔주지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780832953294&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int fputs(const char * restrict s, FILE * restrict stream);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fputs() 함수의 첫 번째 인수는 출력할 문자열을 가리키는 포인터를 전달한다. 두 번째 인수로는 문자열을 출력할 스트림을 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833014970&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

int main(void) {
    char str[100];

    fputs(&quot;문자열을 입력해 주세요 :\n&quot;, stdout);
    fgets(str, sizeof(str), stdin);

    puts(&quot;입력하신 문자열 : &quot;);
    puts(str);

    fputs(&quot;입력하신 문자열 : &quot;, stdout);
    fputs(str, stdout);

    return 0;
}

// 문자열을 입력해 주세요 : 
// C언어 문자열 입출력
// 입력하신 문자열 : 
// C언어 문자열 입출력
// 입력하신 문자열 : C언어 문자열 입출력&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제에서 puts() 함수는 문자열을 출력한 후에 자동으로 줄 바꿈을 해주지만 fputs() 함수는 문자열을 출력한 후에 줄 바꿈을 하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문자열&amp;nbsp;처리&amp;nbsp;함수&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 문자열이란 마지막에 널 문자를 가지는 문자형 배열로 표현되며, 기본 타입에는 포함되지 않는다. 따라서 C 컴파일러가 기본 타입을 위해 제공하는 다양한 연산자를 자유롭게 사용할 수 없다. 이 때문에 C언어는 문자열을 처리하기 위한 다양한 함수를 별도로 제공하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;strlen() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strlen() 함수는 인수로 전달된 문자열의 길이를 반환하는 함수다. 이때 문자열 여부를 구분하는 마지막 문자인 널 문자는 문자열의 길이에서 제외된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833151497&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string.h&amp;gt;
size_t strlen(const char *s);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음은 strlen() 함수를 이용하여 문자열의 길이를 구하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833183798&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;char str[] = &quot;C언어&quot;;
printf(&quot;이 문자열의 길이는 %d입니다.\n&quot;, strlen(str));

// 이 문자열의 길이는 7입니다.
// 참고로 utf-8 인코딩 환경에서 한글은 한 문자당 3바이트다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;strcat(), strncat() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strcat()함수와 strncat() 함수는 하나의 문자열에 다른 문자열을 연결해주는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833246905&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string.h&amp;gt;
char *strcat(char * restrict s1, const char * restrict s2);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strcat() 함수의 첫 번째 인수로 전달된 문자열은 기준 문자열이 된다.&lt;/li&gt;
&lt;li&gt;두 번째 인수로 전달된 추가하고자 하는 문자열의 복사본이 기준 문자열 뒤에 추가된다.&lt;/li&gt;
&lt;li&gt;위의 원형에서 볼 수 있는 restrict 키워드는 포인터의 선언에서만 사용할 수 있는 C99부터 추가된 키워드다. 포인터를 선언할 때 이 키워드를 명시하면, 컴파일러는 해당 포인터가 가리키는 메모리에 대한 최적화를 실시한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2F9ZD/dJMcadCblo3/0UYnTX8fXKdWUX3r8ksB4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2F9ZD/dJMcadCblo3/0UYnTX8fXKdWUX3r8ksB4k/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_string_handling&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2F9ZD/dJMcadCblo3/0UYnTX8fXKdWUX3r8ksB4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2F9ZD%2FdJMcadCblo3%2F0UYnTX8fXKdWUX3r8ksB4k%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;292&quot; height=&quot;464&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_string_handling&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이때 기준 문자열이 저장된 배열의 공간이 충분하지 않으면, 배열을 채우고 남은 문자들이 배열 외부로 흘러넘칠 수 있다. 이 현상을 배열 오버플로우(overflow)라고 한다.&lt;/li&gt;
&lt;li&gt;배열 오버플로우 현상을 방지하기 위해서는 strcat() 함수 대신에 strncat() 함수를 사용하는 것이 좋다.&lt;/li&gt;
&lt;li&gt;strncat() 함수는 strcat() 함수와 하는 일은 같지만, 세 번째 인수로 추가할 문자열의 최대 길이를 지정할 수 있다. 이 함수는 널 문자를 만나거나, 추가하는 문자의 개수가 세 번째 인수로 전달된 최대 길이에 도달할 때까지 추가를 계속한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833441805&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string.h&amp;gt;
char *strncat(char * restrict s1, const char * restrict s2, size_t n);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 예제에서는 우선 널 문자를 포함한 총 14바이트 크기의 문자열을 19바이트 크기의 배열에 저장하고 그 문자열에 정확히 5바이트 크기의 문자열을 추가하는 예제다.&lt;/li&gt;
&lt;li&gt;이때 strncat() 함수가 아닌 strcat() 함수를 사용해도 괜찮지만, 만약 5바이트 이상의 문자열을 추가하려고 한다면 배열 오버플로우가 발생할 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833487896&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;char str01[20] = &quot;C language is &quot;; // 널 문자를 포함하여 15문자
char str02[] = &quot;Cool! and funny!&quot;;  

//strcat(str01, str02);   // 이 부분의 주석 처리를 삭제한 후 실행시키면 배열 오버플로우우가 발생함
strncat(str01, str02, 5); // 이렇게 최대 허용치를 설정해 놓으면 배열 오버플로우우에 대해서는 안전해짐

puts(str01);

// C language is Cool!&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;strcpy(), strncpy() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strcpy()&amp;nbsp;함수와&amp;nbsp;strncpy()&amp;nbsp;함수는&amp;nbsp;문자열을&amp;nbsp;복사하는&amp;nbsp;함수다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833559353&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string.h&amp;gt;
char *strcpy(char * restrict s1, const char * restrict s2);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strcpy() 함수는 첫 번째 인수로 전달된 배열에, 두 번째 인수로 전달된 문자열을 복사한다. 하지만 이때 첫 번째 인수로 전달된 배열의 크기가 복사할 문자열의 길이보다 작으면, 배열 오버플로우가 발생한다. 배열 오버플로우 현상을 방지하기 위해서는 strcpy() 함수 대신에 strncpy() 함수를 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIsRb7/dJMcag6PWQ1/vBRuKO4JmoJsCchWFvdDkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIsRb7/dJMcag6PWQ1/vBRuKO4JmoJsCchWFvdDkK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_string_handling&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIsRb7/dJMcag6PWQ1/vBRuKO4JmoJsCchWFvdDkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIsRb7%2FdJMcag6PWQ1%2FvBRuKO4JmoJsCchWFvdDkK%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;498&quot; height=&quot;222&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_string_handling&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strncpy() 함수는 strcpy() 함수와 하는 일은 같지만, 세 번째 인수로 복사할 문자열의 최대 길이를 지정할 수 있습다. 이 함수는 널 문자를 만나거나, 복사하는 문자의 개수가 세 번째 인수로 전달된 최대 길이에 도달할 때까지 복사를 계속한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833644200&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string.h&amp;gt;
char *strncpy(char * restrict s1, const char * restrict s2, size_t n);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제는 strncpy() 함수를 이용하여 문자열의 일부분만을 복사하는 예제다. 이렇게 복사한 문자열의 마지막에는 반드시 널 문자를 삽입해 주어야만 C 프로그램이 제대로 문자열로 인식할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833689856&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;char str01[20] = &quot;C is Cool!&quot;;
char str02[11];  

// str02 배열의 크기만큼만 복사를 진행하며, 마지막 한 문자는 널 문자를 위한 것임

strncpy(str02, str01, sizeof(str02)-1);

str02[sizeof(str02)-1] = '\0'; // 이 부분을 주석 처리하면, 맨 마지막에 널 문자를 삽입하지 않음

puts(str02);

// C is Cool!&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제는 strncpy() 함수를 이용하여 문자열의 일부분만을 수정하는 예제다. strncpy() 함수의 첫 번째 인수에 배열 이름을 이용한 포인터 연산을 사용하여 수정을 시작할 지점을 지정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833729899&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;char str[20] = &quot;C is cool!&quot;;  
strncpy(str+5, &quot;nice&quot;, 4); // 배열 이름을 이용한 포인터 연산으로 수정할 부분의 시작 부분을 지정함
puts(str);

// C is nice!&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;strcmp(), strncmp() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strcmp()&amp;nbsp;함수와&amp;nbsp;strncmp()&amp;nbsp;함수는&amp;nbsp;문자열의&amp;nbsp;내용을&amp;nbsp;비교하는&amp;nbsp;함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833757489&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string.h&amp;gt;
int strcmp(const char *s1, const char *s2);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strcmp() 함수는 인수로 두 개의 문자열 포인터를 전달받아, 해당 포인터가 가리키는 문자열의 내용을 서로 비교한다. 두 문자열의 모든 문자는 아스키 코드값으로 자동 변환되며, 문자열의 맨 앞에서부터 순서대로 비교된다.&lt;/li&gt;
&lt;li&gt;strcmp() 함수의 상황별 반환값은 다음과 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQCL1p/dJMcab5xtyD/Eqel2VAYYjw1zFx9MiqAOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQCL1p/dJMcab5xtyD/Eqel2VAYYjw1zFx9MiqAOk/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_string_handling&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQCL1p/dJMcab5xtyD/Eqel2VAYYjw1zFx9MiqAOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQCL1p%2FdJMcab5xtyD%2FEqel2VAYYjw1zFx9MiqAOk%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;669&quot; height=&quot;188&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_string_handling&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strncmp() 함수는 strcmp() 함수와 하는 일은 같지만, 세 번째 인수로 비교할 문자의 개수를 지정할 수 있다. 이 함수는 일치하지 않는 문자를 만나거나, 세 번째 인수로 전달된 문자의 개수만큼 비교를 계속한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780833860008&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string.h&amp;gt;
int strncmp(const char *s1, const char *s2, size_t n);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제는 strcmp() 함수를 이용하여 두 문자열을 비교하는 예제다.&lt;/li&gt;
&lt;li&gt;strcmp() 함수는 문자열을 비교하는 함수이므로, 문자를 비교할 때에는 관계연산자 '=='를 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834061261&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;  

int main(void) {
    char str[20];
    char ch;  

    while (1) {
        puts(&quot;미국의 수도를 입력하세요 :&quot;);
        scanf(&quot;%s&quot;, str);
        if (strcmp(str, &quot;워싱턴&quot;) == 0 || strcmp(str, &quot;washington&quot;) == 0) { // 문자열의 비교
            puts(&quot;정답입니다!&quot;);
            break;
        }
        else
            puts(&quot;아쉽네요~&quot;);
        fflush(stdin);  

        puts(&quot;\n이 프로그램을 끝내고자 한다면 'q'를 눌러주세요!&quot;);
        puts(&quot;계속 도전하고자 하시면 Enter를 눌러주세요!&quot;);

        scanf(&quot;%c&quot;, &amp;amp;ch);  

        if (ch == 'q') { // 문자의 비교
            break;
        }
        fflush(stdin);
    }
    return 0;
}

// 미국의 수도를 입력하세요 : 
// 뉴욕
// 아쉽네요~

// 이 프로그램을 끝내고자 한다면 'q'를 눌러주세요!
// 계속 도전하고자 하시면 Enter를 눌러주세요!

// 미국의 수도를 입력하세요 : 
// 워싱턴
// 정답입니다!&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;atoi(), atol(), atoll(), atof() 함수&lt;/li&gt;
&lt;li&gt;이 함수들은 인수로 전달된 문자열을 해당 타입의 숫자로 변환시켜주는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834097268&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdlib.h&amp;gt;
int atoi(const char *nptr);            // int형 정수로 변환함.
long int atol(const char *nptr);       // long형 정수로 변환함.
long long int atoll(const char *nptr); // long long형 정수로 변환함.
double atof(const char *nptr);         // double형 실수로 변환함.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제는 숫자로 이루어진 문자열을 숫자로 변환하여, 곱셈 연산을 수행하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834127584&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;char str01[] = &quot;10&quot;;
char str02[] = &quot;20&quot;;  
printf(&quot;문자열을 숫자로 변환해서 곱한 값은 %d입니다.\n&quot;, atoi(str01) * atoi(str02));

// 문자열을 숫자로 변환해서 곱한 값은 200입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;toupper(), tolower() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 함수들은 인수로 전달된 문자열의 영문자를 모두 대문자나 소문자로 변환시켜주는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834164306&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;ctype.h&amp;gt;
int toupper(int c); // 문자열의 모든 영문자를 대문자로 변환함.
int tolower(int c); // 문자열의 모든 영문자를 소문자로 변환함.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제는 문자열 내의 모든 영문자를 대문자로 변환하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780834199380&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int i, str_len;
char str[] = &quot;Hello C World!&quot;;  
printf(&quot;원래 문자열 : %s\n&quot;, str);

str_len = strlen(str);
for (i = 0; i &amp;lt; str_len; i++) {
    str[i] = toupper(str[i]);
}

printf(&quot;바뀐 문자열 : %s\n&quot;, str);

// 원래 문자열 : Hello C World!
// 바뀐 문자열 : HELLO C WORLD!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/416</guid>
      <comments>https://iamjaeeuncho.tistory.com/416#entry416comment</comments>
      <pubDate>Sun, 7 Jun 2026 21:10:39 +0900</pubDate>
    </item>
    <item>
      <title>[C] C언어 메모리 관리 - 구조, 스택 프레임, 동적 할당</title>
      <link>https://iamjaeeuncho.tistory.com/415</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;메모리의&amp;nbsp;구조&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램이 실행되기 위해서는 먼저 프로그램이 메모리에 로드(load)되어야 하며, 또한 프로그램에서 사용되는 변수들을 저장할 메모리도 필요하다. 따라서&amp;nbsp;컴퓨터의&amp;nbsp;운영체제는&amp;nbsp;프로그램의&amp;nbsp;실행을&amp;nbsp;위해&amp;nbsp;다양한&amp;nbsp;메모리&amp;nbsp;공간을&amp;nbsp;제공하고&amp;nbsp;있습니다.&lt;/li&gt;
&lt;li&gt;프로그램이 운영체제로부터 할당받는 대표적인 메모리 공간은 다음과 같습니다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드(code) 영역&lt;/li&gt;
&lt;li&gt;데이터(data) 영역&lt;/li&gt;
&lt;li&gt;스택(stack) 영역&lt;/li&gt;
&lt;li&gt;힙(heap) 영역&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;314&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XdOaw/dJMcaaewdrq/lesETGuTKesIaUZkDsJaCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XdOaw/dJMcaaewdrq/lesETGuTKesIaUZkDsJaCK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_memory_structure&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XdOaw/dJMcaaewdrq/lesETGuTKesIaUZkDsJaCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXdOaw%2FdJMcaaewdrq%2FlesETGuTKesIaUZkDsJaCK%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;314&quot; height=&quot;512&quot; data-origin-width=&quot;314&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_memory_structure&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;코드(code)&amp;nbsp;영역&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리의 코드(code) 영역은 실행할 프로그램의 코드가 저장되는 영역으로 텍스트(code) 영역이라고도 부른다.&lt;/li&gt;
&lt;li&gt;CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터(data) 영역&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리의 데이터(data) 영역은 프로그램의 전역 변수와 정적(static) 변수가 저장되는 영역이다.&lt;/li&gt;
&lt;li&gt;데이터 영역은 프로그램의 시작과 함께 할당되며, 프로그램이 종료되면 소멸한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스택(stack) 영역&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리의 스택(stack) 영역은 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역이다.&lt;/li&gt;
&lt;li&gt;스택 영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다.&lt;/li&gt;
&lt;li&gt;이렇게 스택 영역에 저장되는 함수의 호출 정보를 스택 프레임(stack frame)이라고 한다.&lt;/li&gt;
&lt;li&gt;스택 영역은 푸시(push) 동작으로 데이터를 저장하고, 팝(pop) 동작으로 데이터를 인출한다. 이러한 스택은 후입선출(LIFO, Last-In First-Out) 방식에 따라 동작하므로, 가장 늦게 저장된 데이터가 가장 먼저 인출된다.&lt;/li&gt;
&lt;li&gt;스택 영역은 메모리의 높은 주소에서 낮은 주소의 방향으로 할당된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;힙(heap) 영역&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리의 힙(heap) 영역은 사용자가 직접 관리할 수 있는 '그리고 해야만 하는' 메모리 영역이다.&lt;/li&gt;
&lt;li&gt;힙 영역은 사용자에 의해 메모리 공간이 동적으로 할당되고 해제된다.&lt;/li&gt;
&lt;li&gt;힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;스택&amp;nbsp;프레임(stack&amp;nbsp;frame)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리의 스택(stack) 영역은 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역이다.&lt;/li&gt;
&lt;li&gt;스택 영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다.&lt;/li&gt;
&lt;li&gt;함수가 호출되면 스택에는 함수의 매개변수, 호출이 끝난 뒤 돌아갈 반환 주소값, 함수에서 선언된 지역 변수 등이 저장된다. 이렇게 스택 영역에 차례대로 저장되는 함수의 호출 정보를 스택 프레임(stack frame)이라고 한다. 이러한 스택 프레임 덕분에 함수의 호출이 모두 끝난 뒤에, 해당 함수가 호출되기 이전 상태로 되돌아갈 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스택&amp;nbsp;프레임의&amp;nbsp;동작&amp;nbsp;방식&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1780819588306&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main(void) {
    func1();  // func1() 호출
    return 0;
}

void func1() {
    func2();  // func2() 호출
}
void func2() {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G1a43/dJMcadWzcir/6hodZNhmaBlMyk70wfZLr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G1a43/dJMcadWzcir/6hodZNhmaBlMyk70wfZLr1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_memory_stackframe&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G1a43/dJMcadWzcir/6hodZNhmaBlMyk70wfZLr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG1a43%2FdJMcadWzcir%2F6hodZNhmaBlMyk70wfZLr1%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;560&quot; height=&quot;452&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;452&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_memory_stackframe&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFjnRL/dJMcaffQqiH/C8dJ4mifhLnRpnughVzw20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFjnRL/dJMcaffQqiH/C8dJ4mifhLnRpnughVzw20/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_memory_stackframe&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFjnRL/dJMcaffQqiH/C8dJ4mifhLnRpnughVzw20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFjnRL%2FdJMcaffQqiH%2FC8dJ4mifhLnRpnughVzw20%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;736&quot; height=&quot;456&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_memory_stackframe&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 그림은 위 예제 코드에서 함수 호출에 의한 스택 프레임의 변화를 보여주고 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1. 프로그램이 실행되면, 가장 먼저 main() 함수가 호출되어 main() 함수의 스택 프레임이 스택에 저장된다.&lt;/li&gt;
&lt;li&gt;2. func1() 함수를 호출하면 해당 함수의 매개변수, 반환 주소값, 지역 변수 등의 스택 프레임이 스택에 저장된다.&lt;/li&gt;
&lt;li&gt;3. func2() 함수를 호출하면 해당 함수의 스택 프레임이 추가로 스택에 저장된다.&lt;/li&gt;
&lt;li&gt;4. func2() 함수의 모든 작업이 완료되어 반환되면, func2() 함수의 스택 프레임만이 스택에서 제거된다.&lt;/li&gt;
&lt;li&gt;5. func1() 함수의 호출이 종료되면, func1() 함수의 스택 프레임이 스택에서 제거된다.&lt;/li&gt;
&lt;li&gt;6. main() 함수의 모든 작업이 완료되면, main() 함수의 스택 프레임이 스택에서 제거되면서 프로그램이 종료된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이처럼 스택은 가장 나중에 저장된 데이터가 가장 먼저 인출되는 방식으로 동작하며, 이러한 방식을 후입선출(LIFO, Last-In First-Out) 방식이라고 한다.&lt;/li&gt;
&lt;li&gt;이때 스택은 푸시(push) 동작으로 데이터를 저장하고, 팝(pop) 동작으로 데이터를 인출한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스택&amp;nbsp;오버플로우(stack&amp;nbsp;overflow)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수의 재귀 호출이 무한히 반복되면, 해당 프로그램은 스택 오버플로우(stack overflow)에 의해 종료된다. 만약 재귀 호출이 무한히 반복되면, 위 그림에서 Step 3 이후로는 재귀 호출에 의한 스택 프레임이 계속해서 쌓여만 갈 것이다. 이렇게 스택의 모든 공간을 다 차지하고 난 후 더 이상의 여유 공간이 없을 때 또 다시 스택 프레임을 저장하게 되면, 해당 데이터는 스택 영역을 넘어가서 저장된다.&lt;/li&gt;
&lt;li&gt;이렇게 해당 스택 영역을 넘어가도 데이터가 저장될 수 있으면, 해당 프로그램은 오동작을 하게 되거나 보안상의 크나큰 취약점을 가지게 된다. 따라서 C언어에서는 실행 중인 프로그램에서 스택 오버플로우가 발생하면, 에러를 발생하고 곧바로 강제 종료시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YswTp/dJMcagyZzte/lZi2NKLqD88xl0aTOpwmb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YswTp/dJMcagyZzte/lZi2NKLqD88xl0aTOpwmb1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_memory_stackframe&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YswTp/dJMcagyZzte/lZi2NKLqD88xl0aTOpwmb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYswTp%2FdJMcagyZzte%2FlZi2NKLqD88xl0aTOpwmb1%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;770&quot; height=&quot;508&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_memory_stackframe&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;메모리의&amp;nbsp;동적&amp;nbsp;할당(dynamic&amp;nbsp;allocation)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 영역과 스택 영역에 할당되는 메모리의 크기는 컴파일 타임(compile time)에 미리 결정된다. 하지만 힙 영역의 크기는 프로그램이 실행되는 도중인 런 타임(run time)에 사용자가 직접 결정해야 한다. 이렇게 런 타임에 메모리를 할당받는 것을 메모리의 동적 할당(dynamic allocation)이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;malloc() 함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;malloc() 함수는 프로그램이 실행 중일 때 사용자가 직접 힙 영역에 메모리를 할당할 수 있게 해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780819940782&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdlib.h&amp;gt;
void *malloc(size_t size);                    // size_t 타입은 부호없는 정수&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;malloc() 함수는 인수로 할당받고자 하는 메모리의 크기를 바이트 단위로 전달받는다. 이 함수는 전달받은 메모리 크기에 맞고, 아직 할당되지 않은 적당한 블록을 찾는다. 이렇게 찾은 블록의 첫 번째 바이트를 가리키는 주소값을 반환한다. 힙 영역에 할당할 수 있는 적당한 블록이 없을 때에는 널 포인터를 반환한다. 주소값을 반환받기 때문에 힙 영역에 할당된 메모리 공간으로 접근하려면 포인터를 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;calloc()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;calloc() 함수는 malloc() 함수와 마찬가지로 힙 영역에 메모리를 동적으로 할당해주는 함수다.&lt;/li&gt;
&lt;li&gt;이 함수가 malloc() 함수와 다른 점은 할당하고자 하는 메모리의 크기를 두 개의 인수로 나누어 전달받는 점이다. 또한, calloc() 함수는 메모리를 할당받은 후에 해당 메모리의 모든 비트값을 전부 0으로 초기화해 준다.&lt;/li&gt;
&lt;li&gt;calloc() 함수도 malloc() 함수와 마찬가지로 free() 함수를 통해 할당받은 메모리를 해제해 주어야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780821020663&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;#include &amp;lt;stdlib.h&amp;gt;
void *calloc(size_t nmemb, size_t size);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;calloc() 함수의 첫 번째 인수는 메모리 블록의 개수를 나타내며, 두 번째 인수는 각 블록의 바이트 수를 나타낸다.&amp;nbsp;따라서 calloc() 함수는 힙 영역에 size 크기의 메모리 블록을 nmemb개 할당받을 수 있도록 요청한다.&lt;/li&gt;
&lt;li&gt;앞선 예제에서 사용한 malloc() 함수와 다음 예제의 calloc() 함수는 똑같은 동작을 수행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780821035245&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ptr_arr = (int*) malloc(arr_len * sizeof(int));
ptr_arr = (int*) calloc(arr_len, sizeof(int));&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;free()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;free() 함수는 힙 영역에 할당받은 메모리 공간을 다시 운영체제로 반환해 주는 함수다.&lt;/li&gt;
&lt;li&gt;데이터 영역이나 스택 영역에 할당되는 메모리의 크기는 컴파일 타임에 결정되어, 프로그램이 실행되는 내내 고정된다. 하지만 메모리의 동적 할당으로 힙 영역에 생성되는 메모리의 크기는 런 타임 내내 변화한다. 따라서 free() 함수를 사용하여 다 사용한 메모리를 해제해 주지 않으면, 메모리가 부족해지는 현상이 발생할 수 있다. 이처럼 사용이 끝난 메모리를 해제하지 않아서 메모리가 부족해지는 현상을 메모리 누수(memory leak)라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780820163519&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdlib.h&amp;gt;
void free(void *ptr);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;free() 함수는 인수로 해제하고자 하는 메모리 공간을 가리키는 포인터를 전달받는다.&lt;/li&gt;
&lt;li&gt;인수의 타입이 void형 포인터로 선언되어 있으므로, 어떠한 타입의 포인터라도 인수로 전달될 수 있다.&lt;/li&gt;
&lt;li&gt;다음 예제는 크기가 고정된 배열이 아닌 런 타임에 크기가 결정되는 배열을 생성하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780820914464&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ptr_arr = (int*) malloc(arr_len * sizeof(int)); // 메모리의 동적 할당  

if (ptr_arr == NULL) { // 메모리의 동적 할당이 실패할 경우
    printf(&quot;메모리의 동적 할당에 실패했습니다.\n&quot;);
    exit(1);
}  

printf(&quot;동적으로 할당받은 메모리의 초깃값은 다음과 같습니다.\n&quot;);


for (i = 0; i &amp;lt; arr_len; i++) {
    printf(&quot;%d &quot;, ptr_arr[i]);
}

free(ptr_arr);       // 동적으로 할당된 메모리의 반환  


// 동적으로 할당받은 메모리의 초기값은 다음과 같습니다.
// 0 0 0&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;realloc()&amp;nbsp;함수&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;realloc() 함수는 이미 할당된 메모리의 크기를 바꾸어 재할당할 때 사용하는 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780821064081&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdlib.h&amp;gt;
void *realloc(void *ptr, size_t size);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;realloc() 함수의 첫 번째 인수는 크기를 바꾸고자 하는 메모리 공간을 가리키는 포인터를 전달받는다.&lt;/li&gt;
&lt;li&gt;두 번째 인수로는 해당 메모리 공간에 재할당할 크기를 전달한다.&lt;/li&gt;
&lt;li&gt;따라서 첫 번째 인수로 NULL이 전달되면, malloc() 함수와 정확히 같은 동작을 하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780821205304&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ptr_arr = (int*) malloc(arr_len * sizeof(int)); // 메모리의 동적 할당  

if (ptr_arr == NULL) { // 메모리의 동적 할당이 실패할 경우
    printf(&quot;메모리의 동적 할당에 실패했습니다.\n&quot;);
    exit(1);
}  

printf(&quot;동적으로 할당받은 메모리의 초깃값은 다음과 같습니다.\n&quot;);

for (i = 0; i &amp;lt; arr_len; i++) {
    printf(&quot;%d &quot;, ptr_arr[i]);
}

total_len = arr_len + add_len;

ptr_arr = (int*) realloc(ptr_arr, (total_len * sizeof(int))); // 메모리의 추가 할당

if (ptr_arr == NULL) { // 메모리의 추가 할당에 실패할 경우
    printf(&quot;메모리의 추가 할당에 실패했습니다.\n&quot;);
    exit(1);
}  

printf(&quot;\n추가로 할당받은 메모리의 초깃값은 다음과 같습니다.\n&quot;);

for (i = 0; i &amp;lt; total_len; i++) {
    printf(&quot;%d &quot;, ptr_arr[i]);
}

free(ptr_arr); // 동적으로 할당된 메모리의 반환

// 동적으로 할당받은 메모리의 초기값은 다음과 같습니다.
// 0 0 0 
// 추가로 할당받은 메모리의 초기값은 다음과 같습니다.
// 0 0 0 0 0&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제는 런 타임에 크기가 결정된 배열의 크기를 realloc() 함수를 사용해 다시 한 번 늘려주는 예제다.&lt;/li&gt;
&lt;li&gt;realloc() 함수는 만약 기존의 메모리 위치에 충분한 공간이 있다면 바로 이어서 추가 메모리 공간을 할당해 준다. 하지만 기존의 메모리 위치에 충분한 공간이 없으면 메모리의 다른 공간에 기존의 데이터를 복사한 후, 이어서 추가 메모리 공간을 할당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/415</guid>
      <comments>https://iamjaeeuncho.tistory.com/415#entry415comment</comments>
      <pubDate>Sun, 7 Jun 2026 17:34:41 +0900</pubDate>
    </item>
    <item>
      <title>[C] C언어 포인터와 배열 - 관계, 포인터 배열과 배열 포인터</title>
      <link>https://iamjaeeuncho.tistory.com/414</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포인터와&amp;nbsp;배열의&amp;nbsp;관계&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포인터와 배열은 매우 긴밀한 관계를 맺고 있으며, 어떤 부분에서는 서로를 대체할 수도 있다.&lt;/li&gt;
&lt;li&gt;배열의 이름은 그 값을 변경할 수 없는 상수라는 점을 제외하면 포인터와 같아서, 따라서 배열의 이름은 포인터 상수(constant pointer)다.&lt;/li&gt;
&lt;li&gt;포인터 상수(constant pointer)란 포인터 변수가 가리키고 있는 주소 값을 변경할 수 없는 포인터를 의미하며, 상수 포인터(pointer to constant)란 상수를 가르키는 포인터를 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780815722449&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int arr[3] = {10, 20, 30}; // 배열 선언
int* ptr_arr = arr;        // 포인터에 배열의 이름을 대입함  

printf(&quot;배열의 이름을 이용하여 배열 요소에 접근 : %d %d %d\n&quot;, arr[0], arr[1], arr[2]);
printf(&quot;     포인터를 이용하여 배열 요소에 접근 : %d %d %d\n&quot;, ptr_arr[0], ptr_arr[1], ptr_arr[2]);  
printf(&quot;배열의 이름을 이용한 배열의 크기 계산 : %d\n&quot;, sizeof(arr));
printf(&quot;     포인터를 이용한 배열의 크기 계산 : %d\n&quot;, sizeof(ptr_arr));  

// 배열의 이름을 이용하여 배열 요소에 접근 : 10 20 30
//      포인터를 이용하여 배열 요소에 접근 : 10 20 30
// 배열의 이름을 이용한 배열의 크기 계산 : 12
//      포인터를 이용한 배열의 크기 계산 : 8&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제에서는 포인터에 배열의 이름을 대입한 후, 해당 포인터를 배열의 이름처럼 사용한다. 이처럼 C언어에서는 배열의 이름을 포인터처럼 사용할 수 있을 뿐만 아니라, 포인터를 배열의 이름처럼 사용할 수도 있다.&lt;/li&gt;
&lt;li&gt;하지만 배열의 크기를 계산할 때에는 배열의 이름과 포인터 사이에 차이가 발생한다. 배열의 이름을 이용한 크기 계산에서는 배열의 크기가 int형 배열 요소 3개의 크기인 12바이트로 제대로 출력된다. 하지만 포인터를 이용한 크기 계산에서는 배열의 크기가 아닌 포인터 변수 자체의 크기가 출력되는 차이가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;배열의&amp;nbsp;포인터&amp;nbsp;연산&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제는 앞선 예제와는 반대로 배열의 이름을 포인터처럼 사용하는 예제다. 배열의 이름으로 포인터 연산을 수행하여 각각의 배열 요소에 접근한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780815880685&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int arr[3] = {10, 20, 30}; // 배열 선언  
printf(&quot;          배열의 이름을 이용하여 배열 요소에 접근 : %d %d %d\n&quot;, arr[0], arr[1], arr[2]);
printf(&quot;배열의 이름으로 포인터 연산을 해 배열 요소에 접근 : %d %d %d\n&quot;, *(arr+0), *(arr+1), *(arr+2));

//           배열의 이름을 이용하여 배열 요소에 접근 : 10 20 30
// 배열의 이름으로 포인터 연산을 해 배열 요소에 접근 : 10 20 30&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KcRwa/dJMcacDp6rv/6PvaQqsskjoiSHbaFGK0U1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KcRwa/dJMcacDp6rv/6PvaQqsskjoiSHbaFGK0U1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_pointerArray_relation&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KcRwa/dJMcacDp6rv/6PvaQqsskjoiSHbaFGK0U1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKcRwa%2FdJMcacDp6rv%2F6PvaQqsskjoiSHbaFGK0U1%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;472&quot; height=&quot;304&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_pointerArray_relation&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;따라서 배열의 이름과 포인터 사이에는 다음과 같은 공식이 성립함을 알 수 있다.&lt;/li&gt;
&lt;li&gt;아래 공식은 1차원 배열뿐만 아니라 다차원 배열에서도 언제나 성립한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780815943922&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr이 배열의 이름이거나 포인터이고 n이 정수일 때,
arr[n] == *(arr + n)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열에 관계된 연산을 할 때는 언제나 배열의 크기를 넘어서는 접근을 하지 않도록 주의해야 한다. 포인터 연산을 이용하여 계산하다가 배열의 크기를 넘어서는 접근을 하는 경우, C 컴파일러는 어떠한 오류도 발생시키지 않는다. 다만 잘못된 결과만을 반환하므로 C언어로 프로그래밍할 때에는 언제나 배열의 크기에도 주의해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포인터&amp;nbsp;배열&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포인터 배열이란 배열 요소로 포인터 변수를 가지는 배열을 의미한다. 즉, 포인터 변수를 저장할 수 있는 배열을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780816065232&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int i, arr_len;
int num01 = 10, num02 = 20, num03 = 30;
int* arr[3] = {&amp;amp;num01, &amp;amp;num02, &amp;amp;num03}; // int형 포인터 배열 선언  

arr_len = sizeof(arr)/sizeof(arr[0]);
for (i = 0; i &amp;lt; arr_len; i++) {
    printf(&quot;%d\n&quot;, *arr[i]);
}

// 10
// 20
// 30&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DK5Rq/dJMcab5xnQc/YW5Gm1OIE8Wts8l6TfA3JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DK5Rq/dJMcab5xnQc/YW5Gm1OIE8Wts8l6TfA3JK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_pointerArray_arrayPointer&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DK5Rq/dJMcab5xnQc/YW5Gm1OIE8Wts8l6TfA3JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDK5Rq%2FdJMcab5xnQc%2FYW5Gm1OIE8Wts8l6TfA3JK%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;794&quot; height=&quot;444&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_pointerArray_arrayPointer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;배열&amp;nbsp;포인터&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열 포인터란 배열을 가리킬 수 있는 포인터를 의미한다.&lt;/li&gt;
&lt;li&gt;앞서 배열의 이름은 그 값을 변경할 수 없는 상수라는 점을 제외하면 포인터와 같다고 했다. 이렇게 배열 이름이 있는데도 따로 배열 포인터를 정의하여 사용하는 이유는 2차원 이상의 배열을 가리킬 때 포인터를 통해 배열과 같은 인덱싱을 할 수 있도록 하기 위해서다. 즉, 포인터를 배열처럼 사용하기 위해서 배열 포인터를 정의하여 사용한다.&lt;/li&gt;
&lt;li&gt;따라서 배열 포인터는 1차원 배열에서는 아무런 의미가 없으며, 2차원 이상의 배열에서만 의미를 가집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC9dyy/dJMcafz7iqw/Am1QukAU578lBTZs8i17u1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC9dyy/dJMcafz7iqw/Am1QukAU578lBTZs8i17u1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_pointerArray_arrayPointer&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC9dyy/dJMcafz7iqw/Am1QukAU578lBTZs8i17u1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC9dyy%2FdJMcafz7iqw%2FAm1QukAU578lBTZs8i17u1%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;458&quot; height=&quot;458&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_pointerArray_arrayPointer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 그림에서 보면 2차원 배열의 배열 이름 arr는 부분 배열 arr[0]와 같은 곳을 가리킨다. 2차원 배열의 배열 이름으로 포인터 연산을 하면 배열의 행 단위로 이동하게 된다. 즉, (arr+1)은&amp;nbsp;&amp;nbsp;arr[1]과 같은 곳을 가리키게 된다.&lt;/li&gt;
&lt;li&gt;다음 예제는 2차원 배열에서 각 부분 배열의 시작 주소가 가리키는 메모리에 저장된 데이터를 출력하는 예제다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780817054596&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int arr[2][3] = {
    {10, 20, 30},
    {40, 50, 60}
};  

printf(&quot;%d\n&quot;, *arr[0]);
printf(&quot;%d\n&quot;, *arr[1]);

// 10
// 40&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2차원 배열에서는 포인터 연산 시 증가하는 값이 행의 길이에 따라 차이를 보이게 된다.&lt;/li&gt;
&lt;li&gt;2차원 배열의 행의 길이란 부분 배열의 크기를 의미하며, 다음 수식으로 구할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780817094359&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sizeof(arr[0]) / sizeof(타입)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제에서 포인터 연산 시 증감하는 값의 크기는 int형 타입의 크기인 4바이트에 배열 행의 길이인 3를 곱한 12바이트가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780817159091&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int arr[2][3];&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;따라서 위의 예제에서 배열 이름 arr의 타입은 정확하게 다음과 같이 정의할 수 있다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 이름 arr는 int형 데이터를 가리키는 배열 포인터다.&lt;/li&gt;
&lt;li&gt;이 배열 포인터는 포인터 연산 시 증감하는 값의 크기가 12바이트다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;따라서 위의 예제에서 배열 arr를 가리키는 배열 포인터는 다음과 같이 선언할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780817211446&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int (*pArr)[3];

// 위의 배열 포인터는 다음과 같은 배열들을 가리킬 수 있다
int arr01[2][3];
int arr02[3][3];
int arr03[4][3];
...&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음&amp;nbsp;예제는&amp;nbsp;배열&amp;nbsp;포인터를&amp;nbsp;사용하여&amp;nbsp;배열과&amp;nbsp;같은&amp;nbsp;인덱싱&amp;nbsp;방법으로&amp;nbsp;배열&amp;nbsp;요소를&amp;nbsp;참조하는&amp;nbsp;예제다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780817357017&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int arr[2][3] =             // 배열의 선언
{
    {10, 20, 30},
    {40, 50, 60}
};

int (*pArr)[3] = arr;       // 배열 포인터의 선언  

printf(&quot;%d\n&quot;, arr[1][1]);  // 배열 이름으로 참조
printf(&quot;%d\n&quot;, pArr[1][1]); // 배열 포인터로 참조

// 50
// 50&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포인터&amp;nbsp;배열과&amp;nbsp;배열&amp;nbsp;포인터의&amp;nbsp;구분&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;앞선 예제의 배열 포인터에서 괄호(())를 생략하면 전혀 다른 의미가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780817433707&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. int (*pArr)[3];  // int형 데이터를 저장할 수 있는 2차원 배열을 가리키는 배열 포인터
2. int* pArr[3];    // int형 데이터를 가리킬 수 있는 포인터 변수를 모아 놓은 배열을 가리키는 포인터 배열&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;main()&amp;nbsp;함수의&amp;nbsp;인수&amp;nbsp;전달&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;main() 함수는 프로그램이 실행되면 제일 먼저 자동으로 호출되는 함수다.&lt;/li&gt;
&lt;li&gt;main() 함수도 함수이기 때문에 인수를 전달받을 수도 있고, 반환값을 가질 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780817569779&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// C언어의 main() 함수의 원형
void(또는 int) main(int argc, char *argv[]);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어의 main() 함수의 첫 번째 인수는 int형 변수인 argc로 main() 함수에 인수로 전달되는 문자열의 개수를 명시한다.&lt;/li&gt;
&lt;li&gt;두 번째 인수는 char형 포인터 배열인 argv로 main() 함수에 인수로 전달된 각각의 문자열이 저장된 배열을 가리킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/414</guid>
      <comments>https://iamjaeeuncho.tistory.com/414#entry414comment</comments>
      <pubDate>Sun, 7 Jun 2026 16:33:35 +0900</pubDate>
    </item>
    <item>
      <title>[C] C언어 포인터 - 개념, 연산, 인수 전달 방법, 이중/void/함수/Null 포인터</title>
      <link>https://iamjaeeuncho.tistory.com/413</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포인터란?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 포인터(pointer)란 메모리의 주소값을 저장하는 변수이며, 포인터 변수라고도 부른다.&lt;/li&gt;
&lt;li&gt;int형 변수가 정수를 저장하는 것처럼 포인터는 주소값을 저장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780752942033&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int n = 100;   // 변수의 선언
int *ptr = &amp;amp;n; // 포인터의 선언&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmAa2r/dJMcahEDRS9/aKyHgV5yBepzanWpdjrlAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmAa2r/dJMcahEDRS9/aKyHgV5yBepzanWpdjrlAK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_pointer_intro&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmAa2r/dJMcahEDRS9/aKyHgV5yBepzanWpdjrlAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmAa2r%2FdJMcahEDRS9%2FaKyHgV5yBepzanWpdjrlAK%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;298&quot; height=&quot;436&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_pointer_intro&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;주소값의&amp;nbsp;이해&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 데이터가 저장된 메모리의 시작 주소가 데이터의 주소값을 의미한다. C언어에서는 이러한 주소값을 1바이트 크기의 메모리 공간으로 나누어 표현한다.&lt;/li&gt;
&lt;li&gt;예를 들어, int형 데이터는 4바이트의 크기를 가지지만, int형 데이터의 주소값은 시작 주소 1바이트만을 가리킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A4D5Y/dJMcaiwO3de/8uMccRiq6VtxvZjYb92GbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A4D5Y/dJMcaiwO3de/8uMccRiq6VtxvZjYb92GbK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_pointer_intro&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A4D5Y/dJMcaiwO3de/8uMccRiq6VtxvZjYb92GbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA4D5Y%2FdJMcaiwO3de%2F8uMccRiq6VtxvZjYb92GbK%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;276&quot; height=&quot;264&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_pointer_intro&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포인터&amp;nbsp;연산자&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;주소 연산자(&amp;amp;)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주소 연산자는 변수의 이름 앞에 사용하여, 해당 변수의 주소값을 반환한다.&lt;/li&gt;
&lt;li&gt;'&amp;amp;'기호는 앰퍼샌드(ampersand)라고 읽으며, 번지 연산자라고도 불린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;참조 연산자(*)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조 연산자는 포인터의 이름이나 주소 앞에 사용하여, 포인터에 가리키는 주소에 저장된 값을 반환한다.&lt;/li&gt;
&lt;li&gt;C언어에서 '*'기호는 사용하는 위치에 따라 다양한 용도로 사용된다. 이항 연산자로 사용하면 곱셈 연산으로 사용되며, 포인터의 선언 시나 메모리에 접근할 때도 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포인터의&amp;nbsp;선언&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입이란 포인터가 가리키고자 하는 변수의 타입을 명시한다.&lt;/li&gt;
&lt;li&gt;포인터 이름은 포인터가 선언된 후에 포인터에 접근하기 위해 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780753131271&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;타입* 포인터이름;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포인터를 선언한 후 참조 연산자(*)를 사용하기 전에 포인터는 반드시 먼저 초기화되어야 한다. 그렇지 않으면 의도하지 않은 메모리의 값으로 변경되기 때문이다. 따라서 C 컴파일러는 초기화하지 않은 포인터에 참조 연산자를 사용하면 오류를 발생시킨다. 따라서 아래와 같이 포인터의 선언과 동시에 초기화하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780754929161&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;타입* 포인터이름 = &amp;amp;변수이름;
또는
타입* 포인터이름 = 주소값;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포인터의&amp;nbsp;참조&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 선언된 포인터는 참조 연산자(*)를 사용하여 참조할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780780815255&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x = 7;        // 변수의 선언
int *ptr = &amp;amp;x;    // 포인터의 선언
int *pptr = &amp;amp;ptr; // 포인터의 참조&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nfftI/dJMcadoFUZO/T6VxOPyxM8IMd5hexp0Du1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nfftI/dJMcadoFUZO/T6VxOPyxM8IMd5hexp0Du1/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_pointer_intro&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nfftI/dJMcadoFUZO/T6VxOPyxM8IMd5hexp0Du1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnfftI%2FdJMcadoFUZO%2FT6VxOPyxM8IMd5hexp0Du1%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;318&quot; height=&quot;434&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_pointer_intro&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1780780888312&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int num01 = 1234;
double num02 = 3.14;  
int* ptr_num01 = &amp;amp;num01;
double* ptr_num02 = &amp;amp;num02;  

① printf(&quot;포인터의 크기는 %d입니다.\n&quot;, sizeof(ptr_num01));
② printf(&quot;포인터 ptr_num01이 가리키고 있는 주소값은 %#x입니다.\n&quot;, ptr_num01);
③ printf(&quot;포인터 ptr_num02가 가리키고 있는 주소값은 %#x입니다.\n&quot;, ptr_num02);
printf(&quot;포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 %d입니다.\n&quot;, *ptr_num01);
printf(&quot;포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 %f입니다.\n&quot;, *ptr_num02);

// 포인터의 크기는 8입니다.
// 포인터 ptr_num01이 가리키고 있는 주소값은 0x7c255e4입니다.
// 포인터 ptr_num02가 가리키고 있는 주소값은 0x7c255e8입니다.
// 포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 1234입니다.
// 포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 3.140000입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제의 ①번 라인에서는 sizeof 연산자를 사용하여 포인터 변수의 크기를 구하고 있다.&lt;/li&gt;
&lt;li&gt;포인터 변수는 메모리에서 변수의 위치를 나타내는 주소를 다루는 변수이므로, 그 크기는 일반적으로 CPU에 따라 결정된다. 따라서 32비트 CPU에서는 1워드(word)의 크기가 4바이트이므로, 포인터 변수의 크기 또한 4바이트가 될 것이다.&lt;/li&gt;
&lt;li&gt;하지만 이러한 포인터 변수의 크기는 컴파일러로 컴파일할 때 그 크기까지 직접 명시할 수 있다. 따라서 포인터 변수의 크기는 CPU의 종류와 컴파일할 때 사용된 컴파일러의 정책에 따라서 달라질 수 있다.&lt;/li&gt;
&lt;li&gt;②번과 ③번 라인에서처럼 포인터가 가리키는 변수의 타입에 따라 포인터의 타입도 같이 바꿔주고 있다. 포인터의 타입은 참조 연산자를 통해 값을 참조할 때, 참조할 메모리의 크기를 알려주는 역할을 하기 때문이다. 다음 그림은 char형 포인터와 int형 포인터가 각각 메모리 상에서 해당 타입의 변수를 가리키는 것을 보여준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0KCNg/dJMcadWyZBj/XmqZ82t8MnmcJy1Xw6FcKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0KCNg/dJMcadWyZBj/XmqZ82t8MnmcJy1Xw6FcKK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_pointer_intro&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0KCNg/dJMcadWyZBj/XmqZ82t8MnmcJy1Xw6FcKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0KCNg%2FdJMcadWyZBj%2FXmqZ82t8MnmcJy1Xw6FcKK%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;328&quot; height=&quot;436&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_pointer_intro&lt;/figcaption&gt;
&lt;/figure&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포인터는 값을 증가시키거나 감소시키는 등의 제한된 연산만을 할 수 있다.&lt;/li&gt;
&lt;li&gt;C언어의 포인터 연산에는 다음과 같은 규칙이 있다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포인터끼리의 덧셈, 곱셈, 나눗셈은 아무런 의미가 없다.&lt;/li&gt;
&lt;li&gt;포인터끼리의 뺄셈은 두 포인터 사이의 상대적 거리를 나타낸다.&lt;/li&gt;
&lt;li&gt;포인터에 정수를 더하거나 뺄 수는 있지만, 실수와의 연산은 허용하지 않는다.&lt;/li&gt;
&lt;li&gt;포인터끼리 대입하거나 비교할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780813751681&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;char* ptr_char = 0;
int* ptr_int = NULL;
double* ptr_double = 0x00;  

printf(&quot;포인터 ptr_char가 현재 가리키고 있는 주소값은 %#x입니다.\n&quot;, ptr_char);
printf(&quot;포인터 ptr_int가 현재 가리키고 있는 주소값은 %#x입니다.\n&quot;, ptr_int);
printf(&quot;포인터 ptr_double이 현재 가리키고 있는 주소값은 %#x입니다.\n&quot;, ptr_double);  

printf(&quot;포인터 ptr_char가 1 증가 후에 가리키고 있는 주소값은 %#x입니다.\n&quot;, ++ptr_char);
printf(&quot;포인터 ptr_int가 1 증가 후에 가리키고 있는 주소값은 %#x입니다.\n&quot;, ++ptr_int);
printf(&quot;포인터 ptr_double이 1 증가 후에 가리키고 있는 주소값은 %#x입니다.\n&quot;, ++ptr_double);  

// 포인터   ptr_char가 현재 가리키고 있는 주소값은 0입니다.
// 포인터    ptr_int가 현재 가리키고 있는 주소값은 0입니다.
// 포인터 ptr_double이 현재 가리키고 있는 주소값은 0입니다.
// 포인터   ptr_char가 1 증가 후에 가리키고 있는 주소값은 0x1입니다.
// 포인터    ptr_int가 1 증가 후에 가리키고 있는 주소값은 0x4입니다.
// 포인터 ptr_double이 1 증가 후에 가리키고 있는 주소값은 0x8입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제는 타입에 따른 포인터 연산의 증가값을 비교하는 예제다. 위의 예제에서 모든 포인터에 저장된 초기 주소값은 0x00다. 하지만 1을 증가시키는 포인터 연산 후 포인터가 가리키고 있는 주소는 각각의 포인터 타입에 따라 달라진다. 그 증가 폭은 포인터가 가리키는 변수의 타입의 크기와 같게 된다. 예를 들어, int형 포인터의 증가폭은 int형 타입의 크기인 4바이트만큼 증가하며, 이 법칙은 포인터의 뺄셈에서도 똑같이 적용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780813958964&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int num01 = 10;
int num02 = 20;
int *ptr_num01 = &amp;amp;num01;
int *ptr_num02 = &amp;amp;num02;  

if (ptr_num01 != ptr_num02) {              // 포인터끼리의 비교 연산
    printf(&quot;포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 %d입니다.\n&quot;, *ptr_num01);
    printf(&quot;포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 %d입니다.\n&quot;, *ptr_num02);
    printf(&quot;포인터 ptr_num01과 ptr_num02는 현재 다른 주소를 가리키고 있습니다.\n\n&quot;);
    ptr_num02 = ptr_num01;                 // 포인터끼리의 대입 연산
}  

printf(&quot;포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 %d입니다.\n&quot;, *ptr_num01);
printf(&quot;포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 %d입니다.\n&quot;, *ptr_num02);  

if (ptr_num01 == ptr_num02) {              // 포인터끼리의 비교 연산
    printf(&quot;포인터 ptr_num01과 ptr_num02는 현재 같은 주소를 가리키고 있습니다.\n&quot;);
}

// 포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 10입니다.
// 포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 20입니다.
// 포인터 ptr_num01과 ptr_num02는 현재 다른 주소를 가리키고 있습니다.

// 포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 10입니다.
// 포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 10입니다.
// 포인터 ptr_num01과 ptr_num02는 현재 같은 주소를 가리키고 있습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;인수&amp;nbsp;전달&amp;nbsp;방법&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수를 호출할 때에는 함수에 필요한 데이터를 인수(argument)로 전달해 줄 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;값에 의한 전달(call by value)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값에 의한 전달 방법은 인수로 전달되는 변수가 가지고 있는 값을 함수 내의 매개변수에 복사하는 방식이다.&lt;/li&gt;
&lt;li&gt;복사된 값으로 초기화된 매개변수는 인수로 전달된 변수와는 완전히 별개의 변수가 된다. 따라서 함수 내에서의 매개변수 조작은 인수로 전달되는 변수에 아무런 영향을 미치지 않는다.&lt;/li&gt;
&lt;li&gt;아래 예제에서 local() 함수의 매개변수 num는 인수로 변수 var의 값을 전달받는다. 따라서 함수 내에서 매개변수 num의 값을 아무리 변경하더라도 원래 인수로 전달된 변수 var의 값은 절대 변경되지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780814162064&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;  
void local(int);  

int main(void) {
    int var = 10;
    printf(&quot;변수 var의 초깃값은 %d입니다.\n&quot;, var);  

    local(var);
    printf(&quot;local() 함수 호출 후 변수 var의 값은 %d입니다.\n&quot;, var);
    return 0;
}  

void local(int num) {
    num += 10;
}

// 변수 var의 초기값은 10입니다.
// local() 함수 호출 후 변수 var의 값은 10입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;참조에 의한 전달(call by reference)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조에 의한 전달 방법은 인수로 변수의 값을 전달하는 것이 아닌, 해당 변수의 주소값을 전달한다. 즉, 함수의 매개변수에 인수로 전달된 변수의 원래 주소값을 저장하는 것이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이 방식을 사용하면 인수로 전달된 변수의 값을 함수 내에서 변경할 수 있다.&lt;/li&gt;
&lt;li&gt;아래 예제에서 local() 함수의 매개변수 num는 인수로 변수 var의 주소값을 전달받는다. 따라서 함수 내에서 매개변수 num의 값을 변경하면, 원래 인수인 변수 var의 값도 같이 변경된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780814833174&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;  
void local(int*);

int main(void) {
    int var = 10;
    printf(&quot;변수 var의 초깃값은 %d입니다.\n&quot;, var);  

    local(&amp;amp;var);
    printf(&quot;local() 함수 호출 후 변수 var의 값은 %d입니다.\n&quot;, var);
    return 0;
}  

void local(int* num) {
    *num += 10;
}  

// 변수 var의 초기값은 10입니다.
// local() 함수 호출 후 변수 var의 값은 20입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포인터의 포인터&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포인터 변수를 가리키는 포인터를 포인터의 포인터라 한다.&lt;/li&gt;
&lt;li&gt;참조 연산자(*)를 두 번 사용하여 표현하며, 이중 포인터라고도 부른다.&lt;/li&gt;
&lt;li&gt;다음 그림은 포인터와 포인터의 포인터와의 동작 상 차이점을 보여준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvitMW/dJMcahxVSvb/7byCcfktRb3DN4ZnOe2MT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvitMW/dJMcahxVSvb/7byCcfktRb3DN4ZnOe2MT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvitMW/dJMcahxVSvb/7byCcfktRb3DN4ZnOe2MT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvitMW%2FdJMcahxVSvb%2F7byCcfktRb3DN4ZnOe2MT1%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPEyt4/dJMcabqXdsK/4wEDIQkClNK77BzmBgt3y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPEyt4/dJMcabqXdsK/4wEDIQkClNK77BzmBgt3y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPEyt4/dJMcabqXdsK/4wEDIQkClNK77BzmBgt3y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPEyt4%2FdJMcabqXdsK%2F4wEDIQkClNK77BzmBgt3y1%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;https://www.tcpschool.com/c/c_pointer_various&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1780815064953&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int num = 10;              // 변수 선언
int* ptr_num = &amp;amp;num;       // 포인터 선언
int** pptr_num = &amp;amp;ptr_num; // 포인터의 포인터 선언  

printf(&quot;변수 num가 저장하고 있는 값은 %d입니다.\n&quot;, num);
printf(&quot;포인터  ptr_num가 가리키는 주소에 저장된 값은 %d입니다.\n&quot;, *ptr_num);
printf(&quot;포인터의 포인터 pptr_num가 가리키는 주소에 저장된 포인터가 가리키는 주소에 저장된 값은 %d입니다.\n&quot;,
       **pptr_num);  
    
// 변수 num가 저장하고 있는 값은 10입니다.
// 포인터 ptr_num가 가리키는 주소에 저장된 값은 10입니다.
// 포인터의 포인터 pptr_num가 가리키는 주소에 저장된 포인터가 가리키는 주소에 저장된 값은 10입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;void&amp;nbsp;포인터(void&amp;nbsp;pointer)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;void 포인터는 일반적인 포인트 변수와는 달리 대상이 되는 데이터의 타입을 명시하지 않은 포인터다. 따라서 변수, 함수, 포인터 등 어떠한 값도 가리킬 수 있지만, 포인터 연산이나 메모리 참조와 같은 작업은 할 수 없다. 즉, void 포인터는 주소값을 저장하는 것 이외에는 아무것도 할 수 없는 포인터다.&lt;/li&gt;
&lt;li&gt;void 포인터를 사용할 때에는 반드시 먼저 사용하고자 하는 타입으로 명시적 타입 변환 작업을 거친 후에 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780815177045&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int num = 10;         // 변수 선언
void* ptr_num = &amp;amp;num; // void 포인터 선언  

printf(&quot;변수 num가 저장하고 있는 값은 %d입니다.\n&quot;, num);
printf(&quot;void 포인터 ptr_num가 가리키는 주소에 저장된 값은 %d입니다.\n&quot;, *(int*)ptr_num);  

*(int*)ptr_num = 20;  // void 포인터를 통한 메모리 접근  
printf(&quot;void 포인터 ptr_num가 가리키는 주소에 저장된 값은 %d입니다.\n&quot;, *(int*)ptr_num);

// 변수 num가 저장하고 있는 값은 10입니다.
// void 포인터 ptr_num가 가리키는 주소에 저장된 값은 10입니다.
// void 포인터 ptr_num가 가리키는 주소에 저장된 값은 20입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;함수 포인터(function pointer)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램에서 정의된 함수는 프로그램이 실행될 때 모두 메인 메모리에 올라가게 된다. 이때 함수의 이름은 메모리에 올라간 함수의 시작 주소를 가리키는 포인터 상수(constant pointer)가 된다. 이렇게 함수의 시작 주소를 가리키는 포인터 상수를 함수 포인터(function pointer)라고 부른다.&lt;/li&gt;
&lt;li&gt;함수 포인터의 포인터 타입은 함수의 반환값과 매개변수에 의해 결정된다. 즉, 함수의 원형을 알아야만 해당 함수에 맞는 함수 포인터를 만들 수 있다.&lt;/li&gt;
&lt;li&gt;함수 포인터 사용시 연산자의 우선순위 때문에 반드시 *ptr_func 부분을 괄호(())로 둘러싸야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780815318298&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void func (int, int);           // 함수 원형
void (*ptr_func) (int, int);    // 함수 포인터&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 포인터는 다음 예제처럼 함수를 또 다른 함수의 인수로 전달할 때 유용하게 사용된다.&lt;/li&gt;
&lt;li&gt;다음 예제에서는 함수 포인터를 사용하여 변수 oper의 값에 따라 4개의 사칙연산 함수 중 하나를 선택한다. 이렇게 선택된 함수는 함수 포인터를 사용하여 calculator() 함수에 인수로 전달되게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780815400601&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;double (*calc)(double, double) = NULL; // 함수 포인터 선언
double result = 0;  
double num01 = 3, num02 = 5;
char oper = '*';  

switch (oper) {
    case '+':
        calc = add;
        break;

    case '-':
        calc = sub;
        break;

    case '*':
        calc = mul;
        break;

    case '/':
        calc = div;
        break;

    default:
        puts(&quot;사칙연산(+, -, *, /)만을 지원합니다.&quot;);
}  

result = calculator(num01, num02, calc);
printf(&quot;사칙 연산의 결과는 %lf입니다.\n&quot;, result);

// 사칙 연산의 결과는 15.000000입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;널&amp;nbsp;포인터(null&amp;nbsp;pointer)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0이나 NULL을 대입하여 초기화한 포인터를 널 포인터(null pointer)라고 한다.&lt;/li&gt;
&lt;li&gt;널 포인터는 아무것도 가리키지 않는 포인터라는 의미다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/413</guid>
      <comments>https://iamjaeeuncho.tistory.com/413#entry413comment</comments>
      <pubDate>Sun, 7 Jun 2026 15:58:46 +0900</pubDate>
    </item>
    <item>
      <title>[C] C언어 배열 - 1차원, 다차원</title>
      <link>https://iamjaeeuncho.tistory.com/412</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;배열(array)이란?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열(array)은 같은 타입의 변수들로 이루어진 유한 집합으로 정의된다.&lt;/li&gt;
&lt;li&gt;배열을 구성하는 각각의 값을 배열 요소(element)라고 하며, 배열에서의 위치를 가리키는 숫자는 인덱스(index)라고 한다. C언어에서 인덱스는 언제나 0부터 시작하며, 0을 포함한 양의 정수만을 가질 수 있다.&lt;/li&gt;
&lt;li&gt;배열은 선언되는 형식에 따라 1차원 배열, 2차원 배열뿐만 아니라 그 이상의 다차원 배열로도 선언할 수 있지만 현실적으로 이해하기가 쉬운 2차원 배열까지가 많이 사용된다.&lt;/li&gt;
&lt;li&gt;C언어에서는 배열을 선언만 하고 초기화하지 않으면, 각 배열 요소에 아무런 의미를 가지지 않는 쓰레기값이 저장되어 있게 된다. 따라서 초기화되지 않은 배열은 사용하지 않도록 주의를 기울여야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1차원&amp;nbsp;배열&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1차원 배열은 가장 기본적인 배열로 다음과 같은 문법에 따라 선언된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780727075145&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;타입 배열이름[배열길이];&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입은 배열 요소로 들어가는 변수의 타입을 명시한다.&lt;/li&gt;
&lt;li&gt;배열 이름은 배열이 선언된 후에 배열로 접근하기 위해 사용된다.&lt;/li&gt;
&lt;li&gt;배열의 길이는 해당 배열이 몇 개의 배열 요소를 가지게 되는지 명시한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780727207552&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int i;
int sum = 0;
int grade[3];        // 길이가 3인 int형 배열 선언  

/* 배열의 초기화 */
grade[0] = 85;       // 국어 점수
grade[1] = 65;       // 영어 점수
grade[2] = 90;       // 수학 점수  

for (i = 0; i &amp;lt; 3; i++) {
    sum += grade[i]; // 인덱스를 이용한 배열의 접근
}  

printf(&quot;국영수 과목 총 점수 합계는 %d점이고, 평균 점수는 %f점입니다.\n&quot;, sum, (double)sum/3);

// 국영수 과목 총 점수 합계는 240점이고, 평균 점수는 80.000000점입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 그림은 위의 예제에서 사용된 배열 grade가 메모리 상에서 어떻게 저장되는지를 보여준다.&lt;/li&gt;
&lt;li&gt;아래 그림처럼 언제나 배열의 이름은 배열의 첫 번째 요소와 같은 주소를 가리키고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img_c_onedimensional_array.png&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E1o5Y/dJMcah5NaTw/yA1DQ6gOEePToIcuAkGpjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E1o5Y/dJMcah5NaTw/yA1DQ6gOEePToIcuAkGpjK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_array_oneDimensional&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E1o5Y/dJMcah5NaTw/yA1DQ6gOEePToIcuAkGpjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE1o5Y%2FdJMcah5NaTw%2FyA1DQ6gOEePToIcuAkGpjK%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;352&quot; height=&quot;280&quot; data-filename=&quot;img_c_onedimensional_array.png&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_array_oneDimensional&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;배열의&amp;nbsp;선언과&amp;nbsp;동시에&amp;nbsp;초기화&amp;nbsp;하는&amp;nbsp;방법&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서는 변수와 마찬가지로 배열도 선언과 동시에 초기화할 수 있다.&amp;nbsp;단, 초기화 리스트의 타입과 배열의 타입은 반드시 일치해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780728022030&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;타입 배열이름[배열길이] = {배열요소1, 배열요소2, ...};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음과&amp;nbsp;같이&amp;nbsp;중괄호({})를&amp;nbsp;사용하여&amp;nbsp;초깃값을&amp;nbsp;나열한&amp;nbsp;것을&amp;nbsp;초기화&amp;nbsp;리스트라고&amp;nbsp;합니다.&lt;/li&gt;
&lt;li&gt;만약에 초기화 리스트의 개수가 배열의 총 길이보다 적으면, 배열의 앞에서부터 차례대로 초기화된다. 이때 초기화되지 못한 나머지 배열 요소는 모두 0으로 자동 초기화된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780728076881&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int i;
int sum = 0;
int grade[3] = {85, 65, 90}; // 길이가 3인 int형 배열의 선언과 동시에 초기화  

for (i = 0; i &amp;lt; 3; i++) {
    sum += grade[i];
}  

printf(&quot;국영수 과목 총 점수 합계는 %d이고, 평균 점수는 %f입니다.\n&quot;, sum, (double)(sum/3));  

// 국영수 과목 총 점수 합계는 240이고, 평균 점수는 80.000000입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;배열의&amp;nbsp;길이&amp;nbsp;자동&amp;nbsp;설정&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서는 초기화 리스트에 맞춰 자동으로 배열의 길이를 설정할 수도 있다.&lt;/li&gt;
&lt;li&gt;배열의 길이를 따로 입력하지 않은 배열은 초기화 리스트의 배열 요소의 개수에 맞춰 자동으로 배열의 길이가 설정된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780728181537&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;타입 배열이름[] = {배열요소1, 배열요소2, ...};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 예제에서 int형 배열 arr의 길이는 자동으로 3으로 설정됨과 동시에 초기화 리스트에 의해 초기화된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780729104611&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int arr[] = {1, 2, 3};&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;배열의&amp;nbsp;특징&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 길이를 선언할 때에는 반드시 상수를 사용해야 한다.&lt;/li&gt;
&lt;li&gt;배열 요소의 인덱스는 언제나 0부터 시작한다.&lt;/li&gt;
&lt;li&gt;C 컴파일러는 배열의 길이를 전혀 신경 쓰지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780729474167&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int i;
int sum = 0;
int grade[3] = {85, 65, 90};  // grade[0], grade[1], grade[2]만 선언 및 초기화
grade[3] = 100;               // grade[3]를 선언하지 않고 초기화 진행  

for (i = 0; i &amp;lt; 4; i++) {     // grade[3]도 수식에 포함
    sum += grade[i];
}  

printf(&quot;국영수 과목 총 점수 합계는 %d이고, 평균 점수는 %f입니다.\n&quot;, sum, (double)sum/3);  

// 국영수 과목 총 점수 합계는 340이고, 평균 점수는 113.333333입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예제에서는 크기가 3인 int형 배열 grade를 선언하고 있으며, 배열 grade의 배열 요소는 grade[0], grade[1], grade[2]만 존재한다. 하지만 존재하지도 않는 grade[3]이라는 배열 요소의 초기화를 진행하고, 반복문을 통해 수식에서도 이용한다. 이때 C 컴파일러는 오류는 커녕 수식에서까지 이 배열 요소를 이용하여 결과를 출력한다. 하지만&amp;nbsp;이&amp;nbsp;결과는&amp;nbsp;개발자가&amp;nbsp;전혀&amp;nbsp;의도하지&amp;nbsp;않은&amp;nbsp;결과물이며,&amp;nbsp;이러한&amp;nbsp;프로그램은&amp;nbsp;종종&amp;nbsp;예상치&amp;nbsp;못한&amp;nbsp;결과를&amp;nbsp;내주기도&amp;nbsp;합니다.&lt;/li&gt;
&lt;li&gt;위와 같이 C언어에서는 컴파일러가 일일이 배열의 길이 등을 검사하여 오류를 출력해 주지 않으므로, C언어로 프로그래밍할 때에는 이런 계산을 언제나 개발자가 직접 신경 써야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;배열이&amp;nbsp;차지하는&amp;nbsp;메모리의&amp;nbsp;크기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 배열을 복사하거나 배열 요소에 특정 작업을 하고 싶을 때는 해당 배열이 차지하는 메모리의 크기를 정확히 알고 있어야한다.&lt;/li&gt;
&lt;li&gt;배열이 차지하는 총 메모리의 크기는 다음 수식을 사용하여 구할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780729901873&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;배열이 차지하는 메모리의 크기 = 배열의 길이 X sizeof(타입)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1780729989386&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int grade[] = {85, 65, 90};                     // 배열의 길이를 명시하지 않음
int arr_len = sizeof(grade) / sizeof(grade[0]); // 배열의 길이를 구하는 공식  

printf(&quot;배열 arrGrade의 길이는 %d입니다.\n&quot;, arr_len);

// 배열 grade의 길이는 3입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 길이를 알고 싶을 때에는 다음 수식을 사용하여 구할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780729934587&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;배열의 길이 = sizeof(배열 이름) / sizeof(배열 이름[0])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;다차원 배열(multi-dimensional array)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다차원 배열이란 2차원 이상의 배열을 의미하며, 배열 요소로 또 다른 배열을 가지는 배열을 의미한다.&lt;br /&gt;즉, 2차원 배열은 배열 요소로 1차원 배열을 가지는 배열이며, 3차원 배열은 배열 요소로 2차원 배열을 가지는 배열이고, 4차원 배열은 배열 요소로 3차원 배열을 가지는 배열이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2차원&amp;nbsp;배열(two&amp;nbsp;dimensional&amp;nbsp;array)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2차원 배열이란 배열의 요소로 1차원 배열을 가지는 배열이다.&lt;/li&gt;
&lt;li&gt;C언어에서는 2차원 배열을 나타내는 타입을 따로 제공하지 않는다. 대신에 1차원 배열의 배열 요소로 또 다른 1차원 배열을 사용하여 2차원 배열을 나타낼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780730117811&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;타입 배열이름[행의길이][열의길이];&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입은 배열 요소로 저장되는 변수의 타입을 설정한다.&lt;/li&gt;
&lt;li&gt;배열 이름은 배열이 선언된 후에 배열에 접근하기 위해 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6sL4H/dJMcahxVvuZ/pHIidk5DXQNac1puPjGTiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6sL4H/dJMcahxVvuZ/pHIidk5DXQNac1puPjGTiK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_array_twoDimensional&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6sL4H/dJMcahxVvuZ/pHIidk5DXQNac1puPjGTiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6sL4H%2FdJMcahxVvuZ%2FpHIidk5DXQNac1puPjGTiK%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;412&quot; height=&quot;208&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_array_twoDimensional&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 그림은 2차원 배열을 이해하기 쉽도록 도식적으로 표현한 그림이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwGbVV/dJMcahSaPVR/fF9ziIGKdUgK0VwrJy4SbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwGbVV/dJMcahSaPVR/fF9ziIGKdUgK0VwrJy4SbK/img.png&quot; data-alt=&quot;https://www.tcpschool.com/c/c_array_twoDimensional&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwGbVV/dJMcahSaPVR/fF9ziIGKdUgK0VwrJy4SbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwGbVV%2FdJMcahSaPVR%2FfF9ziIGKdUgK0VwrJy4SbK%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;694&quot; height=&quot;458&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.tcpschool.com/c/c_array_twoDimensional&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만 컴퓨터의 메모리는 위와 같은 입체적 공간이 아닌 선형 공간이므로 실제로는 위의 그림과 같이 저장된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780730535880&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int arr01[6] = {10, 20, 30, 40, 50, 60};
int arr02[2][3] = {10, 20, 30, 40, 50, 60};  

// arr01의 배열 요소의 값 - 10 20 30 40 50 60
// arr02의 배열 요소의 값 - 10 20 30 40 50 60&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;배열의&amp;nbsp;선언과&amp;nbsp;동시에&amp;nbsp;초기화하는&amp;nbsp;방법&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1차원 배열과 마찬가지로 2차원 배열도 선언과 동시에 초기화할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1차원 배열의 초기화 형태를 따르는 방식&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1780730732617&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;타입 배열이름[행의길이][열의길이] = {배열요소[0][0], 배열요소[0][1], ..., 배열요소[1][0], 배열요소[1][1], ..., 배열요소[2][0], 배열요소[2][1], ...};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위와 같은 방식으로는 2차원 배열의 배열 요소[0][0]부터 차례대로 초기화된다.&lt;/li&gt;
&lt;li&gt;만약에 초기화하는 배열 요소의 개수가 배열의 총 길이보다 적으면, 나머지 배열 요소는 모두 0으로 초기화된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;배열의 모든 요소를 초기화하는 방식&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1780730763422&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;타입 배열이름[행의길이][열의길이] =
{
    {배열요소[0][0], 배열요소[0][1], ...},
    {배열요소[1][0], 배열요소[1][1], ...},
    {배열요소[2][0], 배열요소[2][1], ...},
    ...
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 방식은 앞서 살펴본 1차원 배열의 초기화 형태를 따르는 방식과 결과는 똑같다. 하지만 좀 더 직관적으로 2차원 배열의 모습을 알 수 있으므로 보통 이 방식을 가장 많이 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;배열의 일부 요소만을 초기화하는 방식&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 방식으로는 다음 예제와 같이 2차원 배열의 원하는 배열 요소만을 초기화할 수 있다.&lt;/li&gt;
&lt;li&gt;이때 초기화하지 않은 배열 요소는 모두 0으로 자동초기화된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780731090380&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int arr[3][4] = {
    {10, 20},
    {30, 40, 50, 60},
    {0, 0, 70, 80}
};

//   10  20   0   0
//   30  40  50  60
//    0   0  70  80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;배열의&amp;nbsp;길이&amp;nbsp;자동&amp;nbsp;설정&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1차원 배열과 마찬가지로 2차원 배열도 배열의 길이를 명시하지 않고, 자동으로 배열의 길이를 설정할 수 있다.&lt;/li&gt;
&lt;li&gt;단, 행의 길이는 생략할 수 있지만, 열의 길이는 반드시 명시해야 한다. 행의 길이를 명시하고, 열의 길이를 생략하면 컴파일할 때 오류가 발생한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780731173304&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int arr[][4] = {
    {10, 20},
    {30, 40, 50, 60},
    {0, 0, 70, 80}
};

//   10  20   0   0
//   30  40  50  60
//    0   0  70  80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;a href=&quot;http://www.tcpschool.com/css/intro&quot;&gt;http://www.tcpschool.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Language/C</category>
      <author>재은초</author>
      <guid isPermaLink="true">https://iamjaeeuncho.tistory.com/412</guid>
      <comments>https://iamjaeeuncho.tistory.com/412#entry412comment</comments>
      <pubDate>Sat, 6 Jun 2026 16:33:29 +0900</pubDate>
    </item>
  </channel>
</rss>