<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko-KR"><generator uri="https://jekyllrb.com/" version="4.3.3">Jekyll</generator><link href="https://juhoseok.github.io/jekyll-theme-velog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://juhoseok.github.io/jekyll-theme-velog/" rel="alternate" type="text/html" hreflang="ko-KR" /><updated>2026-04-21T17:20:48+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/feed.xml</id><title type="html">Velog Style Jekyll Theme</title><subtitle>velog 감성의 개발 블로그를 GitHub Pages와 Jekyll로 구성한 오픈소스 starter theme</subtitle><entry><title type="html">게임 개발자 전망과 학습 로드맵</title><link href="https://juhoseok.github.io/jekyll-theme-velog/game-developer-roadmap/" rel="alternate" type="text/html" title="게임 개발자 전망과 학습 로드맵" /><published>2026-04-21T16:01:21+09:00</published><updated>2026-04-21T16:01:21+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/game-developer-roadmap</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/game-developer-roadmap/"><![CDATA[<p>2026년 4월 21일 백승현 강사님의 게임 개발자 전망과 학습 로드맵 강의를 들었다.</p>

<p>이번 강의의 핵심은 단순히 “게임 개발자가 유망한가?”가 아니었다. AI 시대에도 게임 개발자가 왜 상대적으로 경쟁력을 가질 수 있는지, 게임 산업의 불확실성이 얼마나 큰지, 그리고 그 안에서 오래 버티려면 어떤 태도와 학습 순서가 필요한지를 함께 다룬 강의였다.</p>

<h2 id="한-줄-요약">한 줄 요약</h2>

<p>게임 개발자는 AI 시대에도 쉽게 대체되기 어려운 영역이지만, 콘텐츠 산업 특유의 낮은 성공 확률과 커리어 불확실성을 견디려면 게임을 좋아하는 것을 넘어 개발 과정 자체를 즐기는 태도와 탄탄한 CS 기본기가 필요하다.</p>

<h2 id="ai-시대에도-게임-개발이-상대적으로-유망한-이유">AI 시대에도 게임 개발이 상대적으로 유망한 이유</h2>

<p>웹 개발과 비교하면 게임 개발은 AI가 곧바로 대체하기 어려운 영역으로 설명되었다.</p>

<p>게임은 텍스트 코드만으로 완성되는 결과물이 아니다. 사운드, 그래픽, 이펙트, 물리, 입력, 네트워크, 렌더링, 게임 플레이가 복합적으로 맞물려야 하나의 경험이 된다. 그래서 프롬프트 하나로 완성도 있는 게임을 바로 만들어 내기는 어렵다.</p>

<p>또 하나의 이유는 학습 데이터의 한계다. 게임 회사의 핵심 코드는 대부분 외부에 공개되지 않는다. 언리얼 엔진의 블루프린트처럼 텍스트 코드가 아닌 형태로 작성되는 자산도 많다. AI가 학습하기 어려운 구조가 오히려 게임 개발자의 전문성을 지켜 주는 진입 장벽이 될 수 있다.</p>

<p>물론 AI의 영향이 없다는 뜻은 아니다. 반복적인 구현, 간단한 코드 생성, 프로토타입 제작은 더 빨라질 것이다. 하지만 AI가 만든 결과물을 이해하고, 수정하고, 실제 게임의 맥락에 맞게 통합하는 능력은 여전히 개발자의 몫이다.</p>

<h2 id="게임-산업의-수요는-계속-커질-가능성이-높다">게임 산업의 수요는 계속 커질 가능성이 높다</h2>

<p>강의에서는 게임 수요가 장기적으로 계속 늘어날 가능성이 크다고 보았다.</p>

<p>과거부터 게임을 즐기던 세대는 나이가 들어도 여가 시간에 게임을 계속 즐길 수 있다. 젊은 세대 역시 게임을 자연스러운 여가 활동으로 받아들인다. 사회가 발전할수록 여가 시간에 대한 욕구도 커지고, 그만큼 게임 산업의 수요도 전 세계적으로 증가할 수 있다.</p>

<p>국내 게임사들도 더 이상 국내 시장만 보고 생존하기 어렵다. 글로벌 시장을 목표로 해야 하는 환경이 되었고, 세계적인 수요 증가는 장기적으로 개발자 처우 개선으로 이어질 가능성이 있다.</p>

<p>다만 반도체 엔지니어, AI 연구자 같은 최상위 직군과 비교하면 처우가 항상 더 좋다고 보기는 어렵다. 그래도 일반적인 개발 직군과 비교했을 때 게임 개발자의 처우가 나쁜 편은 아닐 수 있다는 관점이었다.</p>

<h2 id="게임-개발-커리어의-현실-성공-확률이-낮은-콘텐츠-산업">게임 개발 커리어의 현실: 성공 확률이 낮은 콘텐츠 산업</h2>

<p>게임 개발자의 커리어에는 큰 불확실성이 있다.</p>

<p>게임 프로젝트는 시작한다고 해서 모두 출시되는 것이 아니다. 강의에서는 시작된 프로젝트 중 출시까지 가는 비율이 약 10% 수준이고, 출시된 게임 중 성공하는 비율도 약 5% 내외라고 설명했다. 대형 게임사라고 해서 예외는 아니다. 크래프톤, 넥슨, 블리자드 같은 회사도 신규 게임 성공 확률은 높지 않다.</p>

<p>이 말은 개발자가 7년, 10년을 일해도 대중에게 알려진 대표작 없이 중단된 프로젝트만 경험할 수 있다는 뜻이기도 하다. 대기업에 있어도 프로젝트가 접히면 팀이 해체되고, 사내에서 다른 팀으로 이동하기 위해 다시 면접을 봐야 할 수도 있다.</p>

<p>웹 플랫폼 기업과의 차이도 여기서 나온다. 네이버나 카카오 같은 회사는 이미 성공한 플랫폼 위에서 부가 서비스를 만들면 비교적 높은 확률로 사용자를 확보할 수 있다. 반면 게임은 기술만으로 성공하지 않는다. 재미, 타이밍, 시장 반응, 브랜드, 운영까지 맞아야 하는 콘텐츠 산업이다.</p>

<h2 id="게임-개발자에게-필요한-태도">게임 개발자에게 필요한 태도</h2>

<p>가장 중요한 자질은 게임을 좋아하는 마음만이 아니라 게임을 만드는 과정 자체를 견딜 수 있는 흥미와 끈기다.</p>

<p>게임을 플레이하는 것을 좋아하는 것과 게임을 개발하는 것은 다르다. 게임 개발에는 긴 디버깅, 반복적인 수정, 성능 문제, 일정 압박, 팀 커뮤니케이션이 따라온다. 회사 생활에는 상사, 동료, 연봉, 평가 같은 스트레스도 있다. 이런 요소를 장기적으로 견디려면 일 자체에 대한 최소한의 흥미가 있어야 한다.</p>

<p>게임 프로그래머가 반드시 모든 게임을 열정적으로 좋아해야 하는 것은 아니다. 게임 기획자와 달리 프로그래머는 게임 개발 기술 자체에 흥미가 있어도 충분히 출발할 수 있다. 다만 게임에 대한 관심은 개발 과정에서 분명히 플러스가 된다.</p>

<p>기본적인 직업 윤리도 강조되었다. 특히 시간 약속과 데드라인을 지키는 습관은 신뢰를 만드는 가장 기본적인 요소다. 출근 시간도 중요하지만, 개발자에게 더 중요한 것은 약속한 납기를 지키는 능력이다. 어려운 일을 일정 안에 끝내는 경험이 쌓일수록 개발자로서의 신뢰도도 높아진다.</p>

<h2 id="학습-로드맵">학습 로드맵</h2>

<p>게임 프로그래머가 되기 위해서는 CS 기본기에서 시작해 게임 엔진, 엔진 구성 요소, 컴퓨터 그래픽스로 확장해 가는 순서가 필요하다.</p>

<h2 id="1-cs-기본기">1. CS 기본기</h2>

<p>알고리즘, 네트워크, 운영체제는 게임 개발에서도 중요하다.</p>

<p>알고리즘은 단순히 코딩 테스트를 위한 지식이 아니다. 재귀 함수, 공간 분할, BSP 같은 개념을 이해하는 데도 필요하다. 네트워크 지식도 필수에 가깝다. 대부분의 현대 게임은 멀티플레이 또는 온라인 요소를 포함하기 때문이다.</p>

<p>운영체제 지식은 메모리, 스레드, 프로세스, 파일 I/O, 동시성 문제를 이해하는 기반이 된다. 게임은 성능과 자원 관리가 중요한 분야라서 이런 기본기를 피하기 어렵다.</p>

<h2 id="2-게임-엔진을-직접-써-보기">2. 게임 엔진을 직접 써 보기</h2>

<p>처음부터 엔진 내부 구조만 공부하기보다는 언리얼이나 유니티를 설치해서 간단한 개인 프로젝트를 만들어 보는 것이 좋다.</p>

<p>유튜브, 공식 문서, 튜토리얼을 참고해서 작은 게임을 직접 만들어 보면 엔진이 어떤 문제를 해결해 주는지 체감할 수 있다. 중요한 것은 완성도 높은 대작을 만드는 것이 아니라, 입력을 받고, 캐릭터를 움직이고, 충돌을 처리하고, 화면에 결과를 보여 주는 전체 흐름을 경험하는 것이다.</p>

<h2 id="3-엔진의-구성-요소를-폭넓게-경험하기">3. 엔진의 구성 요소를 폭넓게 경험하기</h2>

<p>게임 엔진은 하나의 기능만으로 이루어져 있지 않다.</p>

<ul>
  <li>UI</li>
  <li>컴퓨터 그래픽스</li>
  <li>렌더링</li>
  <li>피직스</li>
  <li>게임 플레이</li>
  <li>오디오</li>
  <li>네트워크</li>
</ul>

<p>처음부터 한 분야만 깊게 파기보다는 엔진의 여러 구성 요소를 한 번씩 경험해 보는 과정이 필요하다. 어느 부분이 자신에게 맞는지 알기 위해서라도 폭넓게 찍어 보는 시간이 필요하다.</p>

<p>추천 도서로는 <code class="language-plaintext highlighter-rouge">게임 엔진 아키텍처</code>가 언급되었다. 엔진의 다양한 구성 요소를 큰 그림에서 이해하는 데 도움이 되는 책이다.</p>

<h2 id="4-컴퓨터-그래픽스-심화">4. 컴퓨터 그래픽스 심화</h2>

<p>컴퓨터 그래픽스는 게임 프로그래머에게 중요한 핵심 기술이다.</p>

<p>OpenGL을 통해 그래픽스 개념을 익히는 방식이 입문에 도움이 될 수 있다. DirectX 11은 현업 게임에서도 많이 사용되고 학습 자료도 풍부하기 때문에 추천되었다. 이후에는 DirectX 12 같은 최신 기술로 확장해 볼 수 있다.</p>

<p><code class="language-plaintext highlighter-rouge">Real-Time Rendering</code> 같은 책은 난도가 높지만, 특정 렌더링 분야를 깊게 볼 때 참고 자료로 유용하다.</p>

<p>중요한 것은 DirectX나 OpenGL 같은 도구 자체보다 그 아래에 있는 개념을 이해하는 것이다. 좌표계, 행렬, 벡터, 조명, 셰이더, 텍스처, 파이프라인 같은 기반을 이해해야 도구가 바뀌어도 따라갈 수 있다.</p>

<h2 id="ai-시대의-채용과-포트폴리오">AI 시대의 채용과 포트폴리오</h2>

<p>현재 채용 시장이 좋지 않은 이유 중 하나는 AI로 인한 불확실성이다. 기업들은 AI가 개발 생산성에 어떤 영향을 줄지 지켜보는 중이고, 저숙련 개발자의 작업 일부는 이미 AI가 대체하고 있다.</p>

<p>그렇다고 개발자 채용이 사라진다는 뜻은 아니다. 숙련된 개발자는 계속 필요하다. AI가 만든 코드를 검토하고, 고치고, 실제 서비스나 게임에 맞게 통합하려면 여전히 CS 기본기, 알고리즘, 도메인 지식이 필요하다.</p>

<p>다만 포트폴리오의 기준은 올라갈 수 있다. AI 덕분에 포트폴리오 제작 기간이 줄어든 만큼, 결과물의 질적 수준이 더 중요해진다. 웹 포트폴리오라면 코드 저장소만 제출하는 것보다 실제로 접근 가능한 라이브 URL을 함께 제출하는 것이 좋다.</p>

<p>AI를 활용해 자신의 현실 속 문제를 해결한 경험도 좋은 포트폴리오 소재가 될 수 있다. 단순히 AI가 만들어 준 코드를 붙이는 것이 아니라, 문제를 정의하고, AI 결과물을 분석하고, 수정해서 실제로 쓸 수 있는 결과로 만든 경험이 중요하다.</p>

<h2 id="ai를-학습-도구로-쓰는-법">AI를 학습 도구로 쓰는 법</h2>

<p>AI는 즉각적으로 답변을 주는 강력한 학습 도구다.</p>

<p>하지만 훈련 단계에서는 기본기를 먼저 쌓는 것이 중요하다. 특히 정글 같은 교육 과정에서는 처음부터 AI에 지나치게 의존하면 스스로 버티며 이해하는 근육을 만들기 어렵다.</p>

<p>반대로 AI 결과물을 분석하면서 탑다운으로 배우는 방식은 효과적일 수 있다. AI가 만든 코드를 그대로 쓰는 것이 아니라, 왜 이렇게 동작하는지, 어떤 부분이 위험한지, 어떻게 개선할 수 있는지를 파고들면 학습 도구로 충분히 활용할 수 있다.</p>

<h2 id="강의에서-가져갈-과제">강의에서 가져갈 과제</h2>

<ul>
  <li>시간 약속, 특히 데드라인을 지키는 습관을 훈련 과정에서부터 연습하기</li>
  <li>내가 게임을 좋아하는 사람인지, 게임 개발 자체에 흥미가 있는 사람인지 구분해 보기</li>
  <li>알고리즘, 네트워크, 운영체제 등 CS 기본기를 다지기</li>
  <li>언리얼 또는 유니티를 설치해 작은 개인 프로젝트를 만들어 보기</li>
  <li>게임 엔진의 UI, 렌더링, 피직스, 오디오, 네트워크 요소를 폭넓게 경험하기</li>
  <li><code class="language-plaintext highlighter-rouge">게임 엔진 아키텍처</code>와 OpenGL 학습 자료를 통해 컴퓨터 그래픽스 공부를 시작하기</li>
  <li>AI가 생성한 코드를 분석하고 수정하는 경험을 쌓기</li>
  <li>현실의 문제를 AI로 해결해 본 경험을 포트폴리오에 녹여 보기</li>
  <li>1인 또는 팀 프로젝트를 진행하면서 동시에 취업 지원도 병행하기</li>
</ul>

<h2 id="정리">정리</h2>

<p>이번 강의에서 가장 크게 남은 질문은 “게임 개발자가 유망한가?”보다 “나는 게임을 만드는 과정을 오래 견딜 수 있는가?”에 가까웠다.</p>

<p>게임 개발은 분명 매력적인 분야지만, 성공 확률이 낮고 프로젝트 단위의 불확실성이 크다. 그래서 단순한 기대감만으로 접근하면 오래 버티기 어렵다. 대신 개발 과정 자체에 흥미가 있고, CS 기본기와 엔진 경험을 차근차근 쌓아 간다면 AI 시대에도 충분히 경쟁력 있는 커리어가 될 수 있다.</p>]]></content><author><name></name></author><category term="Game Development" /><category term="Career" /><category term="AI" /><category term="Computer Graphics" /><category term="jungle" /><summary type="html"><![CDATA[AI 시대 게임 개발자의 전망, 커리어 현실, 필요한 태도, CS/게임 엔진/컴퓨터 그래픽스 학습 로드맵을 정리한다.]]></summary></entry><entry><title type="html">CS:APP Tiny Web Server: HTTP 요청을 읽고 정적 파일을 응답하기까지</title><link href="https://juhoseok.github.io/jekyll-theme-velog/csapp-tiny-server/" rel="alternate" type="text/html" title="CS:APP Tiny Web Server: HTTP 요청을 읽고 정적 파일을 응답하기까지" /><published>2026-04-21T14:55:00+09:00</published><updated>2026-04-21T14:55:00+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/csapp-tiny-server</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/csapp-tiny-server/"><![CDATA[<p>CS:APP의 echo 서버와 Tiny 서버는 겉으로 보면 비슷한 구조를 가진다.</p>

<p>둘 다 <code class="language-plaintext highlighter-rouge">listenfd</code>를 열고, 클라이언트 연결을 <code class="language-plaintext highlighter-rouge">accept()</code>한 뒤, 연결된 소켓 디스크립터 <code class="language-plaintext highlighter-rouge">connfd</code>를 처리 함수에 넘긴다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">listenfd</span> <span class="o">=</span> <span class="n">Open_listenfd</span><span class="p">(</span><span class="n">port</span><span class="p">);</span>

<span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">connfd</span> <span class="o">=</span> <span class="n">Accept</span><span class="p">(</span><span class="n">listenfd</span><span class="p">,</span> <span class="p">...);</span>
    <span class="err">처리함수</span><span class="p">(</span><span class="n">connfd</span><span class="p">);</span>
    <span class="n">Close</span><span class="p">(</span><span class="n">connfd</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>하지만 처리 함수의 역할은 완전히 다르다.</p>

<ul>
  <li>echo 서버: <code class="language-plaintext highlighter-rouge">echo(connfd)</code></li>
  <li>Tiny 서버: <code class="language-plaintext highlighter-rouge">doit(connfd)</code></li>
</ul>

<p>echo 서버는 받은 바이트를 해석하지 않고 그대로 다시 보낸다. 반면 Tiny 서버는 HTTP 요청을 해석하고, 그에 맞는 HTTP 응답을 만들어야 한다.</p>

<h2 id="echo-서버와-tiny-서버의-차이">echo 서버와 Tiny 서버의 차이</h2>

<p>echo 서버의 핵심은 단순하다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Rio_readinitb</span><span class="p">(</span><span class="o">&amp;</span><span class="n">rio</span><span class="p">,</span> <span class="n">connfd</span><span class="p">);</span>

<span class="k">while</span> <span class="p">((</span><span class="n">n</span> <span class="o">=</span> <span class="n">Rio_readlineb</span><span class="p">(</span><span class="o">&amp;</span><span class="n">rio</span><span class="p">,</span> <span class="n">buf</span><span class="p">,</span> <span class="n">MAXLINE</span><span class="p">))</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">Rio_writen</span><span class="p">(</span><span class="n">connfd</span><span class="p">,</span> <span class="n">buf</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>클라이언트가 <code class="language-plaintext highlighter-rouge">"hello"</code>를 보내면 서버는 <code class="language-plaintext highlighter-rouge">"hello"</code>를 그대로 돌려준다. 메시지의 의미를 해석하지 않는다.</p>

<p>Tiny 서버는 다르다. 클라이언트가 다음과 같은 HTTP 요청을 보내면:</p>

<p>```plain text
GET /home.html HTTP/1.1</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
Tiny는 이 한 줄을 해석해야 한다.

```plain text
method  = GET
uri     = /home.html
version = HTTP/1.1
</code></pre></div></div>

<p>그리고 다음 질문들에 답해야 한다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">GET</code> 요청인가?</li>
  <li><code class="language-plaintext highlighter-rouge">/home.html</code> 파일이 실제로 있는가?</li>
  <li>읽을 수 있는 정적 파일인가?</li>
  <li>어떤 <code class="language-plaintext highlighter-rouge">Content-type</code>으로 보내야 하는가?</li>
  <li>성공 또는 실패에 대해 어떤 HTTP 응답을 보내야 하는가?</li>
</ul>

<p>정리하면 다음과 같다.</p>

<table>
  <thead>
    <tr>
      <th>구분</th>
      <th>echo 서버</th>
      <th>Tiny 서버</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>처리 함수</td>
      <td><code class="language-plaintext highlighter-rouge">echo(connfd)</code></td>
      <td><code class="language-plaintext highlighter-rouge">doit(connfd)</code></td>
    </tr>
    <tr>
      <td>입력</td>
      <td>일반 문자열</td>
      <td>HTTP 요청</td>
    </tr>
    <tr>
      <td>해석 여부</td>
      <td>해석하지 않음</td>
      <td>요청 라인, URI, 헤더 해석</td>
    </tr>
    <tr>
      <td>출력</td>
      <td>받은 내용 그대로 반환</td>
      <td>HTTP 응답 생성</td>
    </tr>
    <tr>
      <td>예시 출력</td>
      <td><code class="language-plaintext highlighter-rouge">hello</code></td>
      <td><code class="language-plaintext highlighter-rouge">HTTP/1.0 200 OK ...</code></td>
    </tr>
  </tbody>
</table>

<h2 id="doit의-첫-번째-역할-요청-라인-읽기">doit의 첫 번째 역할: 요청 라인 읽기</h2>

<p>Tiny 서버에서 <code class="language-plaintext highlighter-rouge">doit()</code>는 클라이언트 요청 하나를 처리한다.</p>

<p>처음 구현할 때는 요청 라인을 읽고, <code class="language-plaintext highlighter-rouge">method</code>, <code class="language-plaintext highlighter-rouge">uri</code>, <code class="language-plaintext highlighter-rouge">version</code>으로 나누는 흐름부터 잡으면 된다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">doit</span><span class="p">(</span><span class="kt">int</span> <span class="n">connfd</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">char</span> <span class="n">buf</span><span class="p">[</span><span class="n">MAXLINE</span><span class="p">];</span>
    <span class="kt">char</span> <span class="n">method</span><span class="p">[</span><span class="n">MAXLINE</span><span class="p">],</span> <span class="n">uri</span><span class="p">[</span><span class="n">MAXLINE</span><span class="p">],</span> <span class="n">version</span><span class="p">[</span><span class="n">MAXLINE</span><span class="p">];</span>
    <span class="n">rio_t</span> <span class="n">rio</span><span class="p">;</span>

    <span class="n">Rio_readinitb</span><span class="p">(</span><span class="o">&amp;</span><span class="n">rio</span><span class="p">,</span> <span class="n">connfd</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">Rio_readlineb</span><span class="p">(</span><span class="o">&amp;</span><span class="n">rio</span><span class="p">,</span> <span class="n">buf</span><span class="p">,</span> <span class="n">MAXLINE</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">sscanf</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="s">"%s %s %s"</span><span class="p">,</span> <span class="n">method</span><span class="p">,</span> <span class="n">uri</span><span class="p">,</span> <span class="n">version</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"Bad request line: %s"</span><span class="p">,</span> <span class="n">buf</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"Request line: %s"</span><span class="p">,</span> <span class="n">buf</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"method=%s, uri=%s, version=%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">method</span><span class="p">,</span> <span class="n">uri</span><span class="p">,</span> <span class="n">version</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">method</span><span class="p">,</span> <span class="s">"GET"</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"Tiny only supports GET for now: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">method</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">read_requesthdrs</span><span class="p">(</span><span class="o">&amp;</span><span class="n">rio</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>핵심 단계는 네 가지다.</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">connfd</code>에서 요청 라인 한 줄을 읽는다.</li>
  <li>그 줄을 <code class="language-plaintext highlighter-rouge">method</code>, <code class="language-plaintext highlighter-rouge">uri</code>, <code class="language-plaintext highlighter-rouge">version</code>으로 나눈다.</li>
  <li><code class="language-plaintext highlighter-rouge">GET</code> 요청인지 확인한다.</li>
  <li>남은 요청 헤더를 읽어 비운다.</li>
</ol>

<h2 id="sscanf는-이미-읽은-문자열을-나눈다">sscanf는 이미 읽은 문자열을 나눈다</h2>

<p><code class="language-plaintext highlighter-rouge">scanf()</code>는 표준 입력에서 값을 읽어 변수에 넣는다.</p>

<p>반면 <code class="language-plaintext highlighter-rouge">sscanf()</code>는 이미 메모리에 있는 문자열을 읽어서 변수에 넣는다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sscanf</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="s">"%s %s %s"</span><span class="p">,</span> <span class="n">method</span><span class="p">,</span> <span class="n">uri</span><span class="p">,</span> <span class="n">version</span><span class="p">);</span>
</code></pre></div></div>

<p>예를 들어 <code class="language-plaintext highlighter-rouge">buf</code>에 다음 문자열이 들어 있다면:</p>

<p>```plain text
GET /home.html HTTP/1.1\r\n</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
`%s`는 공백 전까지 읽기 때문에 다음처럼 나뉜다.

| 변수 | 값 | 의미 |
| --- | --- | --- |
| `method` | `GET` | 클라이언트가 원하는 동작 |
| `uri` | `/home.html` | 서버에서 요청한 대상 |
| `version` | `HTTP/1.1` | HTTP 버전 |

## RIO는 HTTP 요청을 줄 단위로 읽기 좋다

HTTP 요청은 줄 단위 구조를 가진다.

```plain text
GET /home.html HTTP/1.1\r\n
Host: localhost:8000\r\n
User-Agent: curl/8.0\r\n
\r\n
</code></pre></div></div>

<p>첫 줄은 요청 라인이고, 그 뒤는 헤더다. 빈 줄 <code class="language-plaintext highlighter-rouge">\r\n</code>이 나오면 헤더가 끝난다.</p>

<p>이런 형식은 <code class="language-plaintext highlighter-rouge">Rio_readlineb()</code>로 읽기 좋다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">read_requesthdrs</span><span class="p">(</span><span class="n">rio_t</span> <span class="o">*</span><span class="n">rp</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">char</span> <span class="n">buf</span><span class="p">[</span><span class="n">MAXLINE</span><span class="p">];</span>

    <span class="k">do</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Rio_readlineb</span><span class="p">(</span><span class="n">rp</span><span class="p">,</span> <span class="n">buf</span><span class="p">,</span> <span class="n">MAXLINE</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span> <span class="n">buf</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Tiny의 기본 구현에서는 <code class="language-plaintext highlighter-rouge">Host</code>, <code class="language-plaintext highlighter-rouge">User-Agent</code>, <code class="language-plaintext highlighter-rouge">Accept</code> 같은 헤더를 적극적으로 사용하지 않는다. 그래도 헤더 끝까지 읽어야 다음 처리 흐름이 깔끔해진다.</p>

<h2 id="http-응답은-상태-라인-헤더-본문으로-구성된다">HTTP 응답은 상태 라인, 헤더, 본문으로 구성된다</h2>

<p>브라우저가 <code class="language-plaintext highlighter-rouge">/home.html</code>을 요청했고, 서버가 파일을 정상적으로 찾았다면 Tiny는 대략 다음 응답을 보낸다.</p>

<p>```plain text
HTTP/1.0 200 OK
Server: Tiny Web Server
Connection: close
Content-length: 120
Content-type: text/html</p>

<html>
...
</html>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
응답은 세 부분으로 나눌 수 있다.

| 부분 | 예시 | 의미 |
| --- | --- | --- |
| 상태 라인 | `HTTP/1.0 200 OK` | 요청 처리 결과 |
| 헤더 | `Content-length`, `Content-type` | 본문을 해석하는 데 필요한 정보 |
| 본문 | `&lt;html&gt;...&lt;/html&gt;` | 실제로 클라이언트에게 보낼 데이터 |

`Content-length`는 빈 줄 다음에 오는 본문 크기를 알려 준다. 브라우저는 이 값을 보고 앞으로 몇 바이트를 읽으면 응답 본문이 끝나는지 알 수 있다.

`Content-type`은 본문을 어떻게 해석해야 하는지 알려 준다.

```plain text
home.html     -&gt; text/html
godzilla.gif  -&gt; image/gif
godzilla.jpg  -&gt; image/jpeg
plain text    -&gt; text/plain
</code></pre></div></div>

<h2 id="정적-콘텐츠-제공-흐름">정적 콘텐츠 제공 흐름</h2>

<p>Tiny 서버가 정적 파일을 제공하는 흐름은 다음 순서로 정리할 수 있다.</p>

<p>```plain text</p>
<ol>
  <li>요청 URI를 파일 경로로 바꾼다.</li>
  <li>stat()으로 파일이 존재하는지 확인한다.</li>
  <li>정규 파일인지, 읽기 권한이 있는지 확인한다.</li>
  <li>확장자를 보고 MIME type을 정한다.</li>
  <li>HTTP 응답 헤더를 보낸다.</li>
  <li>파일 본문을 클라이언트에게 보낸다.
```</li>
</ol>

<p>이 흐름에서 주요 함수는 다음과 같다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">parse_uri()</code></li>
  <li><code class="language-plaintext highlighter-rouge">stat()</code></li>
  <li><code class="language-plaintext highlighter-rouge">S_ISREG()</code></li>
  <li><code class="language-plaintext highlighter-rouge">S_IRUSR</code></li>
  <li><code class="language-plaintext highlighter-rouge">get_filetype()</code></li>
  <li><code class="language-plaintext highlighter-rouge">serve_static()</code></li>
</ul>

<h2 id="parse_uri-uri를-파일-경로로-바꾸기">parse_uri: URI를 파일 경로로 바꾸기</h2>

<p>브라우저 요청 라인은 이런 형태다.</p>

<p>```plain text
GET /home.html HTTP/1.0</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
`doit()`는 여기서 `uri`를 꺼낸다.

```plain text
uri = /home.html
</code></pre></div></div>

<p>하지만 Unix 파일 시스템에서 실제 파일을 찾으려면 서버 기준의 파일 경로가 필요하다.</p>

<p>```plain text
/home.html –parse_uri()–&gt; ./home.html</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
정적 콘텐츠 요청이라면 CGI 인자는 필요 없으므로 `cgiargs`는 빈 문자열이 된다.

```plain text
uri      = /home.html
filename = ./home.html
cgiargs  = ""
</code></pre></div></div>

<h2 id="stat-파일이-실제로-있는지-확인하기">stat: 파일이 실제로 있는지 확인하기</h2>

<p><code class="language-plaintext highlighter-rouge">parse_uri()</code>가 만든 <code class="language-plaintext highlighter-rouge">filename</code>은 문자열일 뿐이다. 그 파일이 실제로 존재하는지는 아직 모른다.</p>

<p>그래서 <code class="language-plaintext highlighter-rouge">stat()</code>으로 파일 정보를 가져온다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">stat</span> <span class="n">sbuf</span><span class="p">;</span>

<span class="k">if</span> <span class="p">(</span><span class="n">stat</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">sbuf</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">clienterror</span><span class="p">(</span><span class="n">connfd</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="s">"404"</span><span class="p">,</span> <span class="s">"Not found"</span><span class="p">,</span>
                <span class="s">"Tiny could not find this file"</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">stat()</code>이 성공하면 <code class="language-plaintext highlighter-rouge">sbuf</code> 안에 파일 타입, 크기, 권한 같은 정보가 들어간다.</p>

<p>실패하면 해당 파일을 찾을 수 없거나 접근할 수 없는 것이므로 <code class="language-plaintext highlighter-rouge">404 Not found</code> 응답을 보내면 된다.</p>

<h2 id="s_isreg와-s_irusr-보낼-수-있는-파일인지-확인하기">S_ISREG와 S_IRUSR: 보낼 수 있는 파일인지 확인하기</h2>

<p>파일이 존재한다고 해서 무조건 보내면 안 된다.</p>

<p>예를 들어 디렉터리일 수도 있고, 읽기 권한이 없을 수도 있다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">S_ISREG</span><span class="p">(</span><span class="n">sbuf</span><span class="p">.</span><span class="n">st_mode</span><span class="p">))</span> <span class="o">||</span> <span class="o">!</span><span class="p">(</span><span class="n">S_IRUSR</span> <span class="o">&amp;</span> <span class="n">sbuf</span><span class="p">.</span><span class="n">st_mode</span><span class="p">))</span> <span class="p">{</span>
    <span class="n">clienterror</span><span class="p">(</span><span class="n">connfd</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="s">"403"</span><span class="p">,</span> <span class="s">"Forbidden"</span><span class="p">,</span>
                <span class="s">"Tiny could not read the file"</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>여기서 검사하는 내용은 두 가지다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">S_ISREG(sbuf.st_mode)</code>: 정규 파일인가?</li>
  <li><code class="language-plaintext highlighter-rouge">S_IRUSR &amp; sbuf.st_mode</code>: 파일 소유자에게 읽기 권한이 있는가?</li>
</ul>

<p>둘 중 하나라도 만족하지 않으면 Tiny는 파일을 보내지 않고 <code class="language-plaintext highlighter-rouge">403 Forbidden</code>을 응답한다.</p>

<h2 id="get_filetype-확장자로-mime-type-정하기">get_filetype: 확장자로 MIME type 정하기</h2>

<p>브라우저는 응답 본문만 보고 타입을 확정하지 않는다. 서버가 보내는 <code class="language-plaintext highlighter-rouge">Content-type</code> 헤더를 보고 본문을 해석한다.</p>

<p>Tiny는 파일 이름의 확장자를 보고 MIME type을 정한다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">get_filetype</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">filetype</span><span class="p">);</span>
</code></pre></div></div>

<p>예시는 다음과 같다.</p>

<table>
  <thead>
    <tr>
      <th>파일</th>
      <th>MIME type</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">home.html</code></td>
      <td><code class="language-plaintext highlighter-rouge">text/html</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">godzilla.gif</code></td>
      <td><code class="language-plaintext highlighter-rouge">image/gif</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">godzilla.jpg</code></td>
      <td><code class="language-plaintext highlighter-rouge">image/jpeg</code></td>
    </tr>
  </tbody>
</table>

<h2 id="serve_static-응답-헤더와-파일-본문-보내기">serve_static: 응답 헤더와 파일 본문 보내기</h2>

<p>마지막 단계는 실제 응답을 보내는 것이다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">serve_static</span><span class="p">(</span><span class="n">connfd</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">sbuf</span><span class="p">.</span><span class="n">st_size</span><span class="p">);</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">serve_static()</code>은 먼저 응답 헤더를 보낸다.</p>

<p>```plain text
HTTP/1.0 200 OK
Server: Tiny Web Server
Connection: close
Content-length: 120
Content-type: text/html</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
그다음 파일 본문을 보낸다.

```html
&lt;html&gt;
&lt;head&gt;&lt;title&gt;test&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;img align="middle" src="godzilla.gif"&gt;
Dave O'Hallaron
&lt;/body&gt;
&lt;/html&gt;
</code></pre></div></div>

<p>결국 브라우저가 받는 것은 HTTP 형식으로 포장된 파일 데이터다.</p>

<h2 id="정리">정리</h2>

<p>echo 서버와 Tiny 서버는 <code class="language-plaintext highlighter-rouge">accept()</code> 이후 처리 함수가 다르다.</p>

<p>echo 서버는 받은 데이터를 그대로 돌려주는 프로그램이다.</p>

<p>Tiny 서버는 HTTP 요청을 해석하고, 파일 시스템을 확인하고, 브라우저가 이해할 수 있는 HTTP 응답을 만들어 보내는 프로그램이다.</p>

<p>전체 흐름은 이렇게 묶을 수 있다.</p>

<p><code class="language-plaintext highlighter-rouge">plain text
connfd
  ↓
Rio_readlineb()로 요청 라인 읽기
  ↓
sscanf()로 method, uri, version 분리
  ↓
GET 요청인지 확인
  ↓
read_requesthdrs()로 헤더 끝까지 읽기
  ↓
parse_uri()로 파일 경로 만들기
  ↓
stat()으로 존재 여부 확인
  ↓
S_ISREG, S_IRUSR로 파일 타입과 권한 확인
  ↓
get_filetype()으로 Content-type 결정
  ↓
serve_static()으로 HTTP 응답 전송
</code></p>

<p>Tiny 서버를 이해할 때는 <code class="language-plaintext highlighter-rouge">doit()</code> 하나만 외우기보다, 요청을 해석하고 응답을 조립하는 전체 흐름으로 보는 것이 가장 중요하다.</p>]]></content><author><name></name></author><category term="C" /><category term="CSAPP" /><category term="Network" /><category term="HTTP" /><category term="Web Server" /><summary type="html"><![CDATA[echo 서버와 Tiny 서버의 차이를 바탕으로 doit, HTTP 요청 파싱, 응답 메시지, 정적 콘텐츠 제공 흐름을 정리한다.]]></summary></entry><entry><title type="html">CS:APP 네트워크 프로그래밍: Echo 클라이언트 연결 흐름</title><link href="https://juhoseok.github.io/jekyll-theme-velog/csapp-echo-client/" rel="alternate" type="text/html" title="CS:APP 네트워크 프로그래밍: Echo 클라이언트 연결 흐름" /><published>2026-04-21T14:50:00+09:00</published><updated>2026-04-21T14:50:00+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/csapp-echo-client</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/csapp-echo-client/"><![CDATA[<p>CS:APP의 echo 예제를 보면 클라이언트 쪽 핵심은 <code class="language-plaintext highlighter-rouge">open_clientfd()</code>에 모여 있다.</p>

<p>이 함수는 단순히 파일 디스크립터 하나를 반환하는 것처럼 보이지만, 내부에서는 다음 흐름을 거친다.</p>

<p>```plain text
hostname, port 입력
   ↓
getaddrinfo(hostname, port)
   ↓
connect에 사용할 수 있는 주소 후보 리스트 생성
   ↓
후보마다 socket() 생성 후 connect() 시도
   ↓
성공한 소켓 디스크립터 반환</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
즉, `open_clientfd()`는 클라이언트가 서버에 연결하기 위해 필요한 준비 과정을 한 함수 안에 묶어 둔 것이다.

## open_clientfd의 전체 흐름

대표적인 구현은 아래와 같다.

```c
int open_clientfd(char *hostname, char *port)
{
    int clientfd, rc;
    struct addrinfo hints, *listp, *p;

    memset(&amp;hints, 0, sizeof(struct addrinfo));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_NUMERICSERV;
    hints.ai_flags |= AI_ADDRCONFIG;

    if ((rc = getaddrinfo(hostname, port, &amp;hints, &amp;listp)) != 0) {
        fprintf(stderr, "getaddrinfo failed (%s:%s): %s\n",
                hostname, port, gai_strerror(rc));
        return -2;
    }

    for (p = listp; p; p = p-&gt;ai_next) {
        if ((clientfd = socket(p-&gt;ai_family,
                               p-&gt;ai_socktype,
                               p-&gt;ai_protocol)) &lt; 0) {
            continue;
        }

        if (connect(clientfd, p-&gt;ai_addr, p-&gt;ai_addrlen) != -1) {
            break;
        }

        close(clientfd);
    }

    freeaddrinfo(listp);

    if (!p) {
        return -1;
    }

    return clientfd;
}
</code></pre></div></div>

<p>이 코드는 크게 세 단계로 읽으면 된다.</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">getaddrinfo()</code>로 서버 주소 후보를 얻는다.</li>
  <li>후보마다 <code class="language-plaintext highlighter-rouge">socket()</code>으로 통신 endpoint를 만든다.</li>
  <li><code class="language-plaintext highlighter-rouge">connect()</code>가 성공하는 후보를 찾으면 그 소켓을 사용한다.</li>
</ol>

<h2 id="getaddrinfo는-왜-필요할까">getaddrinfo는 왜 필요할까</h2>

<p>클라이언트는 보통 <code class="language-plaintext highlighter-rouge">"localhost"</code>, <code class="language-plaintext highlighter-rouge">"example.com"</code>, <code class="language-plaintext highlighter-rouge">"8000"</code> 같은 문자열을 가지고 있다.</p>

<p>하지만 <code class="language-plaintext highlighter-rouge">connect()</code>는 문자열을 직접 받지 않는다. <code class="language-plaintext highlighter-rouge">connect()</code>가 필요로 하는 것은 <code class="language-plaintext highlighter-rouge">struct sockaddr</code> 계열의 실제 주소 구조체와 그 길이다.</p>

<p><code class="language-plaintext highlighter-rouge">getaddrinfo()</code>는 이 간격을 메워 준다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">getaddrinfo</span><span class="p">(</span><span class="n">hostname</span><span class="p">,</span> <span class="n">port</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hints</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">listp</span><span class="p">);</span>
</code></pre></div></div>

<p>이 함수의 역할은 두 가지다.</p>

<ul>
  <li>문자열 형태의 <code class="language-plaintext highlighter-rouge">hostname</code>, <code class="language-plaintext highlighter-rouge">port</code>를 실제 네트워크 주소 구조체로 바꾼다.</li>
  <li>연결 가능한 주소 후보들을 linked list 형태로 돌려준다.</li>
</ul>

<p>예를 들어 <code class="language-plaintext highlighter-rouge">localhost</code> 하나만 넘겨도 실제 후보는 여러 개일 수 있다.</p>

<p>```plain text
localhost
   ↓
127.0.0.1   IPv4
::1         IPv6</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
그래서 `open_clientfd()`는 `listp`부터 시작해서 `p = p-&gt;ai_next`로 후보를 순회한다.

## hints는 어떤 주소를 원하는지 알려준다

`hints`는 `getaddrinfo()`에게 어떤 종류의 주소 후보를 받고 싶은지 알려주는 설정값이다.

```c
memset(&amp;hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_ADDRCONFIG;
</code></pre></div></div>

<p>각 설정의 의미는 다음과 같다.</p>

<table>
  <thead>
    <tr>
      <th>설정</th>
      <th>의미</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SOCK_STREAM</code></td>
      <td>TCP 연결용 소켓을 원한다.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">AI_NUMERICSERV</code></td>
      <td><code class="language-plaintext highlighter-rouge">port</code>가 <code class="language-plaintext highlighter-rouge">"80"</code> 같은 숫자 문자열임을 알려준다.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">AI_ADDRCONFIG</code></td>
      <td>현재 시스템에서 사용 가능한 주소 계열 위주로 후보를 받는다.</td>
    </tr>
  </tbody>
</table>

<p>여기서 중요한 점은 echo 클라이언트가 UDP가 아니라 TCP 연결을 사용한다는 것이다. <code class="language-plaintext highlighter-rouge">SOCK_STREAM</code>은 이 방향을 명확히 잡아 준다.</p>

<h2 id="socket은-통신-endpoint를-만든다">socket은 통신 endpoint를 만든다</h2>

<p><code class="language-plaintext highlighter-rouge">socket()</code>은 실제 통신에 사용할 파일 디스크립터를 만든다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">clientfd</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">ai_family</span><span class="p">,</span> <span class="n">p</span><span class="o">-&gt;</span><span class="n">ai_socktype</span><span class="p">,</span> <span class="n">p</span><span class="o">-&gt;</span><span class="n">ai_protocol</span><span class="p">);</span>
</code></pre></div></div>

<p>여기서 인자를 직접 정하지 않고 <code class="language-plaintext highlighter-rouge">p</code>에서 꺼내 쓰는 이유가 있다. 주소 후보마다 IPv4인지 IPv6인지, 어떤 프로토콜 정보를 가져야 하는지가 다를 수 있기 때문이다.</p>

<p>따라서 <code class="language-plaintext highlighter-rouge">socket()</code>은 현재 후보 주소 <code class="language-plaintext highlighter-rouge">p</code>에 맞는 소켓을 만든다.</p>

<h2 id="connect는-서버에-실제로-연결한다">connect는 서버에 실제로 연결한다</h2>

<p><code class="language-plaintext highlighter-rouge">connect()</code>는 방금 만든 클라이언트 소켓을 특정 서버 주소에 연결한다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">connect</span><span class="p">(</span><span class="n">clientfd</span><span class="p">,</span> <span class="n">p</span><span class="o">-&gt;</span><span class="n">ai_addr</span><span class="p">,</span> <span class="n">p</span><span class="o">-&gt;</span><span class="n">ai_addrlen</span><span class="p">);</span>
</code></pre></div></div>

<p>성공하면 반복문을 빠져나오고, 실패하면 해당 소켓을 닫은 뒤 다음 주소 후보로 넘어간다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">connect</span><span class="p">(</span><span class="n">clientfd</span><span class="p">,</span> <span class="n">p</span><span class="o">-&gt;</span><span class="n">ai_addr</span><span class="p">,</span> <span class="n">p</span><span class="o">-&gt;</span><span class="n">ai_addrlen</span><span class="p">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">break</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">close</span><span class="p">(</span><span class="n">clientfd</span><span class="p">);</span>
</code></pre></div></div>

<p>이 구조 때문에 하나의 주소 후보가 실패해도 바로 전체 연결이 실패하지 않는다. 가능한 후보들을 순서대로 시도하고, 그중 성공한 소켓을 최종 <code class="language-plaintext highlighter-rouge">clientfd</code>로 반환한다.</p>

<h2 id="클라이언트가-서버-주소를-정해-주는-것은-아니다">클라이언트가 서버 주소를 정해 주는 것은 아니다</h2>

<p>여기서 헷갈리기 쉬운 지점이 있다.</p>

<p>클라이언트가 <code class="language-plaintext highlighter-rouge">hostname</code>, <code class="language-plaintext highlighter-rouge">port</code>를 넘긴다고 해서 서버의 주소를 새로 정하는 것은 아니다.</p>

<p>서버는 이미 어떤 주소와 포트에서 <code class="language-plaintext highlighter-rouge">listen()</code> 중이다. 클라이언트는 그 목적지를 선택해서 연결을 시도할 뿐이다.</p>

<p>```plain text
서버:
  “나는 이 포트에서 기다릴게”</p>

<p>클라이언트:
  “나는 저 주소와 포트로 연결할게”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
`getaddrinfo()`도 서버 주소를 새로 만드는 함수가 아니다. 클라이언트가 받은 문자열을 `connect()`가 사용할 수 있는 주소 구조체로 변환해 주는 함수다.

## rio_t는 왜 필요할까

echo 예제에서는 연결 이후 RIO 패키지를 사용해 읽기와 쓰기를 처리한다.

```c
rio_t rio;

Rio_readinitb(&amp;rio, clientfd);
Rio_readlineb(&amp;rio, buf, MAXLINE);
Rio_writen(clientfd, buf, strlen(buf));
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">rio_t</code>는 소켓에서 읽어 온 데이터를 관리하기 위한 버퍼 구조체다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">rio_fd</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">rio_cnt</span><span class="p">;</span>
    <span class="kt">char</span> <span class="o">*</span><span class="n">rio_bufptr</span><span class="p">;</span>
    <span class="kt">char</span> <span class="n">rio_buf</span><span class="p">[</span><span class="n">RIO_BUFSIZE</span><span class="p">];</span>
<span class="p">}</span> <span class="n">rio_t</span><span class="p">;</span>
</code></pre></div></div>

<p>핵심 목적은 소켓에서 데이터를 넉넉히 읽어 둔 뒤, 사용자가 요청한 만큼 조금씩 꺼내 주는 것이다.</p>

<p>그래서 <code class="language-plaintext highlighter-rouge">Rio_readlineb(&amp;rio, buf, MAXLINE)</code>는 단순히 <code class="language-plaintext highlighter-rouge">fd</code>만 받지 않고 <code class="language-plaintext highlighter-rouge">rio_t</code>의 주소를 받는다. 내부에서 다음 상태를 계속 관리해야 하기 때문이다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">rio_fd</code>: 어떤 파일 디스크립터에서 읽을지</li>
  <li><code class="language-plaintext highlighter-rouge">rio_cnt</code>: 내부 버퍼에 남은 바이트 수</li>
  <li><code class="language-plaintext highlighter-rouge">rio_bufptr</code>: 다음에 읽을 위치</li>
  <li><code class="language-plaintext highlighter-rouge">rio_buf</code>: 실제 내부 버퍼</li>
</ul>

<h2 id="readwrite를-직접-쓰는-것과-rio를-쓰는-것">read/write를 직접 쓰는 것과 RIO를 쓰는 것</h2>

<p>네트워크 I/O에서는 한 번의 <code class="language-plaintext highlighter-rouge">read()</code>나 <code class="language-plaintext highlighter-rouge">write()</code>가 원하는 만큼 정확히 처리된다고 가정하면 안 된다. 일부만 읽히거나 일부만 쓰일 수 있다.</p>

<p>RIO 패키지는 이 반복 처리를 감싸서 코드 흐름을 단순하게 만든다.</p>

<table>
  <thead>
    <tr>
      <th>구분</th>
      <th><code class="language-plaintext highlighter-rouge">read</code> / <code class="language-plaintext highlighter-rouge">write</code> 직접 사용</th>
      <th>RIO 패키지 사용</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>수준</td>
      <td>낮은 수준의 시스템콜</td>
      <td>시스템콜을 감싼 헬퍼 함수</td>
    </tr>
    <tr>
      <td>한 줄 읽기</td>
      <td>직접 <code class="language-plaintext highlighter-rouge">\n</code>, <code class="language-plaintext highlighter-rouge">\r\n</code>을 찾아야 함</td>
      <td><code class="language-plaintext highlighter-rouge">Rio_readlineb</code>로 한 줄씩 읽음</td>
    </tr>
    <tr>
      <td>일부만 쓰이는 경우</td>
      <td>남은 바이트를 직접 다시 써야 함</td>
      <td><code class="language-plaintext highlighter-rouge">Rio_writen</code>이 끝까지 쓰려고 반복</td>
    </tr>
    <tr>
      <td>내부 버퍼</td>
      <td>직접 관리해야 함</td>
      <td><code class="language-plaintext highlighter-rouge">rio_t</code>가 내부 버퍼를 관리</td>
    </tr>
  </tbody>
</table>

<p>echo 클라이언트에서는 이 구조 덕분에 연결 자체와 데이터 입출력을 분리해서 이해할 수 있다.</p>

<h2 id="정리">정리</h2>

<p><code class="language-plaintext highlighter-rouge">open_clientfd()</code>는 클라이언트 연결 과정을 다음 순서로 추상화한다.</p>

<p><code class="language-plaintext highlighter-rouge">plain text
문자열 주소
   ↓
getaddrinfo()
   ↓
주소 후보 리스트
   ↓
socket()
   ↓
소켓 디스크립터
   ↓
connect()
   ↓
서버와 연결된 clientfd
</code></p>

<p>그리고 연결 이후에는 RIO 패키지가 소켓 I/O를 더 안정적으로 다룰 수 있게 해 준다.</p>

<p>따라서 echo 클라이언트를 볼 때는 <code class="language-plaintext highlighter-rouge">getaddrinfo()</code>, <code class="language-plaintext highlighter-rouge">socket()</code>, <code class="language-plaintext highlighter-rouge">connect()</code>, <code class="language-plaintext highlighter-rouge">rio_t</code>를 따로 외우기보다, 서버에 연결하고 데이터를 안전하게 주고받기 위한 하나의 흐름으로 묶어서 이해하는 것이 좋다.</p>]]></content><author><name></name></author><category term="C" /><category term="CSAPP" /><category term="Network" /><category term="Socket" /><category term="Rio" /><summary type="html"><![CDATA[echo 클라이언트에서 open_clientfd가 서버 주소를 찾고, 소켓을 만들고, connect까지 이어지는 흐름을 정리한다.]]></summary></entry><entry><title type="html">이진 탐색 트리와 B-Tree / B+Tree 정리</title><link href="https://juhoseok.github.io/jekyll-theme-velog/b-tree-summary/" rel="alternate" type="text/html" title="이진 탐색 트리와 B-Tree / B+Tree 정리" /><published>2026-04-16T20:00:00+09:00</published><updated>2026-04-16T20:00:00+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/b-tree-summary</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/b-tree-summary/"><![CDATA[<h2 id="1-먼저-bst부터">1. 먼저, BST부터</h2>

<h3 id="핵심-용어">핵심 용어</h3>
<p><img src="/jekyll-theme-velog/assets/b-tree-summary/00-bst.png" alt="트리 기본 용어 도식" /></p>

<ul>
  <li>차수: 한 노드가 가질 수 있는 최대 자식 수</li>
  <li>서브트리: 특정 노드와 그 자손들로 이루어진 하위 트리</li>
  <li>리프 노드: 자식이 없는 말단 노드</li>
</ul>

<h3 id="bstbinary-search-tree의-성질">BST(Binary Search Tree)의 성질</h3>

<ul>
  <li>왼쪽 서브트리의 모든 값은 부모보다 작다.</li>
  <li>오른쪽 서브트리의 모든 값은 부모보다 크다.</li>
  <li>각 노드는 자식을 최대 2개까지 가진다.</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/01-bst.svg" alt="BST 예시" /></p>

<p>BST는 탐색이 빠르지만, 한 노드가 자식을 2개까지만 가질 수 있다는 한계가 있다. 데이터가 많아지면 높이가 커지고, 디스크/페이지 단위 저장에서는 비효율적일 수 있다.</p>

<h2 id="2-그래서-b-tree를-쓴다">2. 그래서 B-Tree를 쓴다</h2>

<p>BST의 한계를 줄이기 위해, 한 노드 안에 여러 개의 key를 저장하고 자식 수도 늘린 구조가 B-Tree다.</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/02-btree-concept.svg" alt="B-Tree 기본 개념" /></p>

<p>한 노드에 key가 2개 있으면 자식은 3개가 된다.<br />
즉, <code class="language-plaintext highlighter-rouge">key 수 + 1 = 자식 수</code>가 항상 성립한다.</p>

<h2 id="3-3차-b-tree의-규칙">3. 3차 B-Tree의 규칙</h2>

<p>여기서는 <code class="language-plaintext highlighter-rouge">M = 3</code>인 B-Tree를 기준으로 정리한다.</p>

<h3 id="기본-규칙">기본 규칙</h3>

<ul>
  <li>최대 자식 수: <code class="language-plaintext highlighter-rouge">M = 3</code></li>
  <li>최대 key 수: <code class="language-plaintext highlighter-rouge">M - 1 = 2</code></li>
  <li>최소 자식 수: <code class="language-plaintext highlighter-rouge">ceil(M / 2) = 2</code></li>
  <li>최소 key 수: <code class="language-plaintext highlighter-rouge">ceil(M / 2) - 1 = 1</code></li>
</ul>

<h3 id="예외">예외</h3>

<ul>
  <li>root는 예외적으로 더 적은 key/child를 가질 수 있다.</li>
  <li>모든 리프 노드는 같은 높이에 있어야 한다.</li>
</ul>

<h3 id="꼭-기억할-성질">꼭 기억할 성질</h3>

<ul>
  <li>인터널 노드에 key가 <code class="language-plaintext highlighter-rouge">x</code>개 있으면 자식은 반드시 <code class="language-plaintext highlighter-rouge">x + 1</code>개다.</li>
  <li>리프가 아닌 노드는 최소 2개의 자식을 가져야 한다.</li>
  <li>key는 항상 오름차순으로 정렬되어 있어야 한다.</li>
</ul>

<h2 id="4-b-tree에서-가질-수-없는-구조">4. B-Tree에서 가질 수 없는 구조</h2>

<h3 id="1-key-수와-자식-수가-맞지-않는-경우">1) key 수와 자식 수가 맞지 않는 경우</h3>

<ul>
  <li>key가 1개인데 자식이 3개인 구조는 불가능하다.</li>
  <li>key가 2개인데 자식이 2개뿐인 구조도 불가능하다.</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/03-invalid-structure.svg" alt="잘못된 B-Tree 구조 예시" /></p>

<p>위 구조는 부모 key가 1개인데 자식이 3개라서 규칙 위반이다.</p>

<h3 id="2-자식-구간이-잘못된-경우">2) 자식 구간이 잘못된 경우</h3>

<p>부모가 <code class="language-plaintext highlighter-rouge">20 | 40</code>이면:</p>

<ul>
  <li>왼쪽 자식: <code class="language-plaintext highlighter-rouge">20</code>보다 작은 값</li>
  <li>가운데 자식: <code class="language-plaintext highlighter-rouge">20</code>과 <code class="language-plaintext highlighter-rouge">40</code> 사이 값</li>
  <li>오른쪽 자식: <code class="language-plaintext highlighter-rouge">40</code>보다 큰 값</li>
</ul>

<p>이 구간을 어기면 B-Tree가 아니다.</p>

<h2 id="5-삽입-규칙">5. 삽입 규칙</h2>

<ul>
  <li>삽입은 항상 리프 노드에서 시작한다.</li>
  <li>삽입 후 key 수가 초과되면 노드를 분할한다.</li>
  <li>가운데 key를 부모로 승진시킨다.</li>
  <li>부모도 넘치면 같은 과정을 위로 반복한다.</li>
</ul>

<p>3차 B-Tree에서는 한 노드에 key가 최대 2개까지 들어갈 수 있으므로, 임시로 3개가 되는 순간 분할이 일어난다.</p>

<h2 id="6-3차-b-tree-삽입-예시">6. 3차 B-Tree 삽입 예시</h2>

<p>삽입 순서:</p>

<p><code class="language-plaintext highlighter-rouge">1, 15, 2, 5, 30, 90, 20, 7, 9, 8, 10, 50, 70, 60, 40</code></p>

<h3 id="step-1-1-15-삽입">Step 1. 1, 15 삽입</h3>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/04-step-1.svg" alt="삽입 Step 1" /></p>

<p>루트가 리프이므로 그냥 들어간다.</p>

<h3 id="step-2-2-삽입-첫-분할">Step 2. 2 삽입, 첫 분할</h3>

<p><code class="language-plaintext highlighter-rouge">[1 | 15]</code>에 <code class="language-plaintext highlighter-rouge">2</code>를 넣으면 <code class="language-plaintext highlighter-rouge">[1 | 2 | 15]</code>가 되어 overflow가 발생한다.<br />
가운데 key <code class="language-plaintext highlighter-rouge">2</code>를 승진시키면:</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/05-step-2.svg" alt="삽입 Step 2" /></p>

<h3 id="step-3-5-30-삽입">Step 3. 5, 30 삽입</h3>

<ul>
  <li><code class="language-plaintext highlighter-rouge">5</code>는 오른쪽 리프 <code class="language-plaintext highlighter-rouge">[15]</code>에 들어가 <code class="language-plaintext highlighter-rouge">[5 | 15]</code></li>
  <li><code class="language-plaintext highlighter-rouge">30</code>을 넣으면 <code class="language-plaintext highlighter-rouge">[5 | 15 | 30]</code>이 되어 <code class="language-plaintext highlighter-rouge">15</code>가 부모로 승진</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/06-step-3.svg" alt="삽입 Step 3" /></p>

<h3 id="step-4-90-20-삽입-후-루트-분할">Step 4. 90, 20 삽입 후 루트 분할</h3>

<ul>
  <li><code class="language-plaintext highlighter-rouge">90</code>은 <code class="language-plaintext highlighter-rouge">[30]</code>에 들어가 <code class="language-plaintext highlighter-rouge">[30 | 90]</code></li>
  <li><code class="language-plaintext highlighter-rouge">20</code>을 넣으면 <code class="language-plaintext highlighter-rouge">[20 | 30 | 90]</code> overflow</li>
  <li><code class="language-plaintext highlighter-rouge">30</code>이 부모로 승진하려는데, 부모 <code class="language-plaintext highlighter-rouge">[2 | 15]</code>도 overflow</li>
  <li>다시 루트 분할이 일어나 <code class="language-plaintext highlighter-rouge">15</code>가 새 루트가 된다</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/07-step-4.svg" alt="삽입 Step 4" /></p>

<h3 id="step-5-7-9-삽입">Step 5. 7, 9 삽입</h3>

<ul>
  <li><code class="language-plaintext highlighter-rouge">7</code>은 <code class="language-plaintext highlighter-rouge">[5]</code>에 들어가 <code class="language-plaintext highlighter-rouge">[5 | 7]</code></li>
  <li><code class="language-plaintext highlighter-rouge">9</code>를 넣으면 <code class="language-plaintext highlighter-rouge">[5 | 7 | 9]</code> overflow</li>
  <li>가운데 <code class="language-plaintext highlighter-rouge">7</code>이 승진해서 왼쪽 인터널 노드가 <code class="language-plaintext highlighter-rouge">[2 | 7]</code>이 된다</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/08-step-5.svg" alt="삽입 Step 5" /></p>

<h3 id="step-6-8-10-삽입-후-왼쪽-서브트리-재분할">Step 6. 8, 10 삽입 후 왼쪽 서브트리 재분할</h3>

<ul>
  <li><code class="language-plaintext highlighter-rouge">8</code>은 <code class="language-plaintext highlighter-rouge">[9]</code>에 들어가 <code class="language-plaintext highlighter-rouge">[8 | 9]</code></li>
  <li><code class="language-plaintext highlighter-rouge">10</code>을 넣으면 <code class="language-plaintext highlighter-rouge">[8 | 9 | 10]</code> overflow</li>
  <li><code class="language-plaintext highlighter-rouge">9</code>가 부모 <code class="language-plaintext highlighter-rouge">[2 | 7]</code>로 올라가면서 부모도 overflow</li>
  <li>부모를 다시 분할하고 <code class="language-plaintext highlighter-rouge">7</code>이 루트로 승진</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/09-step-6.svg" alt="삽입 Step 6" /></p>

<h3 id="step-7-50-70-60-40-삽입-후-최종-트리">Step 7. 50, 70, 60, 40 삽입 후 최종 트리</h3>

<ul>
  <li><code class="language-plaintext highlighter-rouge">50</code>은 <code class="language-plaintext highlighter-rouge">[90]</code>에 들어가 <code class="language-plaintext highlighter-rouge">[50 | 90]</code></li>
  <li><code class="language-plaintext highlighter-rouge">70</code>을 넣으면 <code class="language-plaintext highlighter-rouge">[50 | 70 | 90]</code> overflow, <code class="language-plaintext highlighter-rouge">70</code> 승진</li>
  <li>오른쪽 인터널 노드가 <code class="language-plaintext highlighter-rouge">[30 | 70]</code>이 된다</li>
  <li><code class="language-plaintext highlighter-rouge">60</code>은 가운데 리프에 들어가 <code class="language-plaintext highlighter-rouge">[50 | 60]</code></li>
  <li><code class="language-plaintext highlighter-rouge">40</code>을 넣으면 <code class="language-plaintext highlighter-rouge">[40 | 50 | 60]</code> overflow, <code class="language-plaintext highlighter-rouge">50</code> 승진</li>
  <li>오른쪽 인터널이 overflow되고, 마지막으로 루트도 분할된다</li>
</ul>

<p>최종 결과:</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/10-step-7-final.svg" alt="삽입 Step 7 최종 트리" /></p>

<h2 id="7-삽입-변화-한눈에-보기">7. 삽입 변화 한눈에 보기</h2>

<table>
  <thead>
    <tr>
      <th>삽입 값</th>
      <th>결과 요약</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>루트 <code class="language-plaintext highlighter-rouge">[1]</code></td>
    </tr>
    <tr>
      <td>15</td>
      <td>루트 <code class="language-plaintext highlighter-rouge">[1 | 15]</code></td>
    </tr>
    <tr>
      <td>2</td>
      <td>overflow, <code class="language-plaintext highlighter-rouge">2</code> 승진 -&gt; 루트 <code class="language-plaintext highlighter-rouge">[2]</code></td>
    </tr>
    <tr>
      <td>5</td>
      <td>오른쪽 리프 <code class="language-plaintext highlighter-rouge">[5 | 15]</code></td>
    </tr>
    <tr>
      <td>30</td>
      <td>overflow, <code class="language-plaintext highlighter-rouge">15</code> 승진 -&gt; 루트 <code class="language-plaintext highlighter-rouge">[2 | 15]</code></td>
    </tr>
    <tr>
      <td>90</td>
      <td>오른쪽 리프 <code class="language-plaintext highlighter-rouge">[30 | 90]</code></td>
    </tr>
    <tr>
      <td>20</td>
      <td>overflow, <code class="language-plaintext highlighter-rouge">30</code> 승진 -&gt; 루트까지 overflow -&gt; 새 루트 <code class="language-plaintext highlighter-rouge">[15]</code></td>
    </tr>
    <tr>
      <td>7</td>
      <td>리프 <code class="language-plaintext highlighter-rouge">[5 | 7]</code></td>
    </tr>
    <tr>
      <td>9</td>
      <td>overflow, <code class="language-plaintext highlighter-rouge">7</code> 승진 -&gt; 왼쪽 인터널 <code class="language-plaintext highlighter-rouge">[2 | 7]</code></td>
    </tr>
    <tr>
      <td>8</td>
      <td>리프 <code class="language-plaintext highlighter-rouge">[8 | 9]</code></td>
    </tr>
    <tr>
      <td>10</td>
      <td>overflow, <code class="language-plaintext highlighter-rouge">9</code> 승진 -&gt; 인터널 overflow -&gt; <code class="language-plaintext highlighter-rouge">7</code>이 루트로 승진</td>
    </tr>
    <tr>
      <td>50</td>
      <td>리프 <code class="language-plaintext highlighter-rouge">[50 | 90]</code></td>
    </tr>
    <tr>
      <td>70</td>
      <td>overflow, <code class="language-plaintext highlighter-rouge">70</code> 승진 -&gt; 오른쪽 인터널 <code class="language-plaintext highlighter-rouge">[30 | 70]</code></td>
    </tr>
    <tr>
      <td>60</td>
      <td>리프 <code class="language-plaintext highlighter-rouge">[50 | 60]</code></td>
    </tr>
    <tr>
      <td>40</td>
      <td>overflow, <code class="language-plaintext highlighter-rouge">50</code> 승진 -&gt; 인터널 overflow -&gt; 루트 분할 -&gt; 최종 루트 <code class="language-plaintext highlighter-rouge">[15]</code></td>
    </tr>
  </tbody>
</table>

<h2 id="8-btree-기본-구조">8. B+Tree 기본 구조</h2>

<p>B+Tree는 B-Tree와 비슷하지만, <strong>실제 데이터는 leaf node에만 저장</strong>하고 internal node는 탐색용 key만 둔다.</p>

<ul>
  <li>internal node: 어느 방향으로 내려갈지 결정하는 안내판 역할</li>
  <li>leaf node: 실제 key 또는 레코드 위치를 저장</li>
  <li>모든 leaf는 같은 높이에 있고, 보통 서로 연결된다</li>
</ul>

<p>예시:</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/11-bplustree-structure.svg" alt="B+Tree 구조" /></p>

<p>위 그림에서는:</p>

<ul>
  <li>루트와 internal node는 탐색 경로를 나누는 key만 가진다</li>
  <li>실제 값은 맨 아래 leaf에만 있다</li>
  <li>leaf들은 오른쪽으로 연결되어 있어서 순차 탐색이 쉽다</li>
</ul>

<h2 id="9-btree에서-leaf-연결이-중요한-이유">9. B+Tree에서 leaf 연결이 중요한 이유</h2>

<p>B+Tree는 값을 찾은 뒤 같은 구간의 다음 값들을 읽을 때 다시 루트로 올라갈 필요가 없다.<br />
처음 leaf만 찾으면, 이후에는 연결된 leaf를 따라 오른쪽으로 이동하면 된다.</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/12-bplustree-leaf-chain.svg" alt="B+Tree leaf 연결" /></p>

<p>이 구조 덕분에 B+Tree는 다음 작업에 특히 유리하다.</p>

<ul>
  <li>범위 검색: <code class="language-plaintext highlighter-rouge">20 이상 70 이하</code></li>
  <li>정렬 순회: 작은 값부터 큰 값까지 출력</li>
  <li>데이터베이스 인덱스 스캔</li>
</ul>

<h2 id="10-b-tree와-btree-차이">10. B-Tree와 B+Tree 차이</h2>

<h3 id="b-tree">B-Tree</h3>

<ul>
  <li>internal node와 leaf node 모두 key를 가질 수 있다</li>
  <li>검색 도중 internal node에서 바로 값을 찾을 수도 있다</li>
  <li>범위 검색은 가능하지만 leaf 연속 순회 구조는 B+Tree보다 덜 직접적이다</li>
</ul>

<h3 id="btree">B+Tree</h3>

<ul>
  <li>실제 데이터는 leaf에만 저장한다</li>
  <li>internal node는 탐색 전용 key만 가진다</li>
  <li>leaf node들이 연결되어 있어 범위 검색과 순차 접근에 강하다</li>
</ul>

<p>한 줄 비교:</p>

<ul>
  <li>B-Tree: “중간 노드에도 값이 들어갈 수 있는 트리”</li>
  <li>B+Tree: “중간 노드는 길 안내, 실제 데이터는 leaf에 모아둔 트리”</li>
</ul>

<h2 id="11-btree-삽입-과정">11. B+Tree 삽입 과정</h2>

<p>여기서는 <strong>3차 B+Tree</strong> 느낌으로 간단한 삽입 흐름만 본다.</p>

<ul>
  <li>internal node의 역할: 경로 안내</li>
  <li>실제 key는 leaf에 저장</li>
  <li>leaf가 overflow되면 <strong>분할한 뒤, 오른쪽 leaf의 첫 key를 부모에 복사해서 올린다</strong></li>
</ul>

<p>이 지점이 B-Tree와 다르다.<br />
B-Tree는 가운데 key가 위로 <strong>승진</strong>하면서 원래 자리에서 빠질 수 있지만,<br />
B+Tree는 leaf에 실제 데이터가 남아 있어야 하므로 separator key를 부모에 <strong>복사</strong>한다.</p>

<h3 id="step-1-시작-상태">Step 1. 시작 상태</h3>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/13-bplustree-insert-start.svg" alt="B+Tree 삽입 시작" /></p>

<p>루트가 leaf인 상태에서 시작한다.</p>

<h3 id="step-2-30-삽입---루트-leaf-분할">Step 2. 30 삽입 -&gt; 루트 leaf 분할</h3>

<p><code class="language-plaintext highlighter-rouge">[10 | 20]</code>에 <code class="language-plaintext highlighter-rouge">30</code>을 넣으면 leaf overflow가 발생한다.</p>

<ul>
  <li>leaf를 둘로 나눈다</li>
  <li>오른쪽 leaf의 첫 key <code class="language-plaintext highlighter-rouge">20</code>을 부모에 복사한다</li>
  <li>루트가 분할되었으므로 새 루트가 생긴다</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/14-bplustree-insert-root-split.svg" alt="B+Tree 루트 분할" /></p>

<p>중요한 점:</p>

<ul>
  <li>부모에는 <code class="language-plaintext highlighter-rouge">20</code>이 들어가지만</li>
  <li>leaf에도 <code class="language-plaintext highlighter-rouge">20</code>이 그대로 남아 있다</li>
</ul>

<h3 id="step-3-25-삽입---leaf-split--부모-key-추가">Step 3. 25 삽입 -&gt; leaf split + 부모 key 추가</h3>

<p><code class="language-plaintext highlighter-rouge">25</code>는 오른쪽 leaf <code class="language-plaintext highlighter-rouge">[20 | 30]</code>에 들어가서 overflow를 만든다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">[20 | 25 | 30]</code>을 <code class="language-plaintext highlighter-rouge">[20]</code>, <code class="language-plaintext highlighter-rouge">[25 | 30]</code>으로 분할</li>
  <li>새 오른쪽 leaf의 첫 key <code class="language-plaintext highlighter-rouge">25</code>를 부모에 복사</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/15-bplustree-insert-second-split.svg" alt="B+Tree 두 번째 leaf 분할" /></p>

<p>이후에도 삽입 규칙은 같다.</p>

<ol>
  <li>leaf에 삽입</li>
  <li>overflow면 leaf split</li>
  <li>오른쪽 leaf의 첫 key를 부모에 복사</li>
  <li>부모도 overflow면 internal node split</li>
  <li>루트가 overflow면 새 루트 생성</li>
</ol>

<h2 id="12-b-tree-삭제-기본">12. B-Tree 삭제 기본</h2>

<p>B-Tree 삭제는 삽입보다 조금 더 복잡하다.<br />
삭제 후 어떤 노드의 key 수가 최소 개수보다 작아지면 <strong>underflow</strong>가 발생하고, 이때:</p>

<ol>
  <li>형제에게서 하나 빌릴 수 있으면 <strong>재분배</strong></li>
  <li>못 빌리면 부모 key와 함께 <strong>병합</strong></li>
</ol>

<p>참고로 internal node에서 key를 삭제할 때는 보통:</p>

<ul>
  <li>왼쪽 서브트리의 최대값(전임자, predecessor)</li>
  <li>또는 오른쪽 서브트리의 최소값(후임자, successor)</li>
</ul>

<p>로 대체한 뒤, 실제 삭제는 leaf에서 처리한다.</p>

<h3 id="case-1-단순-삭제">Case 1. 단순 삭제</h3>

<p>삭제 전:</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/16-btree-delete-simple-before.svg" alt="B-Tree 단순 삭제 전" /></p>

<p>여기서 <code class="language-plaintext highlighter-rouge">10</code>을 삭제하면 왼쪽 leaf는 <code class="language-plaintext highlighter-rouge">[5]</code>가 된다.<br />
3차 B-Tree에서 leaf의 최소 key 수는 1이므로 underflow가 아니다.</p>

<p>삭제 후:</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/17-btree-delete-simple-after.svg" alt="B-Tree 단순 삭제 후" /></p>

<p>즉, 삭제 후에도 최소 조건을 만족하면 아무 재조정도 하지 않는다.</p>

<h2 id="13-b-tree-재분배빌려오기">13. B-Tree 재분배(빌려오기)</h2>

<p>이번에는 삭제 때문에 어떤 leaf가 최소 조건을 깨는 경우다.</p>

<p>삭제 직전 상태:</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/18-btree-redistribute-before.svg" alt="B-Tree 재분배 전" /></p>

<p>여기서 왼쪽 leaf의 <code class="language-plaintext highlighter-rouge">5</code>를 삭제하면 왼쪽 노드는 비게 된다.<br />
하지만 오른쪽 형제 <code class="language-plaintext highlighter-rouge">[20 | 30]</code>은 key가 2개라서 하나를 빌려줄 수 있다.</p>

<p>재분배 후:</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/19-btree-redistribute-after.svg" alt="B-Tree 재분배 후" /></p>

<p>흐름은 다음과 같다.</p>

<ul>
  <li>부모 key <code class="language-plaintext highlighter-rouge">15</code>를 왼쪽 자식으로 내려 보낸다</li>
  <li>오른쪽 형제의 가장 작은 key <code class="language-plaintext highlighter-rouge">20</code>이 부모로 올라온다</li>
</ul>

<p>결과적으로:</p>

<ul>
  <li>부모: <code class="language-plaintext highlighter-rouge">[20]</code></li>
  <li>왼쪽 자식: <code class="language-plaintext highlighter-rouge">[15]</code></li>
  <li>오른쪽 자식: <code class="language-plaintext highlighter-rouge">[30]</code></li>
</ul>

<p>이렇게 형제에게서 하나 빌려오는 과정을 <strong>재분배(redistribution)</strong> 또는 <strong>borrow</strong>라고 한다.</p>

<h2 id="14-b-tree-병합merge">14. B-Tree 병합(merge)</h2>

<p>형제가 최소 key만 가지고 있다면, 더 이상 빌릴 수 없다.<br />
이때는 부모의 separator key를 내려 보내고 형제와 합쳐서 하나의 노드로 만든다.</p>

<p>삭제 직전 상태:</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/20-btree-merge-before.svg" alt="B-Tree 병합 전" /></p>

<p>여기서 왼쪽 leaf의 <code class="language-plaintext highlighter-rouge">10</code>을 삭제하면 왼쪽 leaf가 비게 된다.<br />
오른쪽 형제 <code class="language-plaintext highlighter-rouge">[30]</code>도 최소 key 수만 가지고 있으므로 빌려줄 수 없다.</p>

<p>그래서:</p>

<ul>
  <li>부모 key <code class="language-plaintext highlighter-rouge">20</code>을 아래로 내리고</li>
  <li>오른쪽 형제 <code class="language-plaintext highlighter-rouge">[30]</code>과 합쳐서</li>
  <li>하나의 노드 <code class="language-plaintext highlighter-rouge">[20 | 30]</code>으로 만든다</li>
</ul>

<p>병합 후:</p>

<p><img src="/jekyll-theme-velog/assets/b-tree-summary/21-btree-merge-after.svg" alt="B-Tree 병합 후" /></p>

<p>이 예시에서는 루트가 비게 되어 트리 높이가 1 줄어든다.<br />
즉, <strong>병합은 트리 높이를 감소시킬 수도 있다.</strong></p>

<h2 id="16-한-줄로-정리">16. 한 줄로 정리</h2>

<p>BST는 자식이 최대 2개인 기본 탐색 트리이고, B-Tree는 한 노드에 여러 key를 넣어 높이를 줄인 균형 트리이며, B+Tree는 실제 데이터를 leaf에만 모아 범위 검색까지 빠르게 만든 구조다.</p>]]></content><author><name></name></author><category term="Data Structure" /><category term="Tree" /><category term="B-Tree" /><category term="B+Tree" /><category term="Database" /><summary type="html"><![CDATA[이진 탐색 트리(BST)와 B-Tree, B+Tree의 구조와 삽입, 삭제 흐름을 그림과 함께 정리한다.]]></summary></entry><entry><title type="html">Dynamic Memory Allocation (Optimization fisrt_fit→ next_fit)</title><link href="https://juhoseok.github.io/jekyll-theme-velog/dynamic-memory-allocation-(Optimization-fisrt_fit-next_fit)/" rel="alternate" type="text/html" title="Dynamic Memory Allocation (Optimization fisrt_fit→ next_fit)" /><published>2026-04-14T16:00:00+09:00</published><updated>2026-04-14T16:00:00+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/dynamic-memory-allocation%20(Optimization%20fisrt_fit%E2%86%92%20next_fit)</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/dynamic-memory-allocation-(Optimization-fisrt_fit-next_fit)/"><![CDATA[<h1 id="dynamic-memory-allocation-optimization-fisrt_fitnext_fit">Dynamic Memory Allocation (Optimization fisrt_fit→next_fit)</h1>

<ul>
  <li>현재 mdriver 결과</li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Results</span> <span class="k">for</span> <span class="n">mm</span> <span class="n">malloc</span><span class="o">:</span>
<span class="n">trace</span>  <span class="n">valid</span>  <span class="n">util</span>     <span class="n">ops</span>      <span class="n">secs</span>  <span class="n">Kops</span>
 <span class="mi">0</span>       <span class="n">yes</span>   <span class="mi">99</span><span class="o">%</span>    <span class="mi">5694</span>  <span class="mi">0</span><span class="p">.</span><span class="mo">0051</span><span class="mi">80</span>  <span class="mi">1099</span>
 <span class="mi">1</span>       <span class="n">yes</span>   <span class="mi">99</span><span class="o">%</span>    <span class="mi">5848</span>  <span class="mi">0</span><span class="p">.</span><span class="mo">003205</span>  <span class="mi">1825</span>
 <span class="mi">2</span>       <span class="n">yes</span>   <span class="mi">99</span><span class="o">%</span>    <span class="mi">6648</span>  <span class="mi">0</span><span class="p">.</span><span class="mo">005431</span>  <span class="mi">1224</span>
 <span class="mi">3</span>       <span class="n">yes</span>  <span class="mi">100</span><span class="o">%</span>    <span class="mi">5380</span>  <span class="mi">0</span><span class="p">.</span><span class="mo">003</span><span class="mi">890</span>  <span class="mi">1383</span>
 <span class="mi">4</span>       <span class="n">yes</span>   <span class="mi">66</span><span class="o">%</span>   <span class="mi">14400</span>  <span class="mi">0</span><span class="p">.</span><span class="mo">00005</span><span class="mi">9245734</span>
 <span class="mi">5</span>       <span class="n">yes</span>   <span class="mi">92</span><span class="o">%</span>    <span class="mi">4800</span>  <span class="mi">0</span><span class="p">.</span><span class="mo">003247</span>  <span class="mi">1478</span>
 <span class="mi">6</span>       <span class="n">yes</span>   <span class="mi">92</span><span class="o">%</span>    <span class="mi">4800</span>  <span class="mi">0</span><span class="p">.</span><span class="mo">003012</span>  <span class="mi">1594</span>
 <span class="mi">7</span>       <span class="n">yes</span>   <span class="mi">55</span><span class="o">%</span>   <span class="mi">12000</span>  <span class="mi">0</span><span class="p">.</span><span class="mi">086887</span>   <span class="mi">138</span>
 <span class="mi">8</span>       <span class="n">yes</span>   <span class="mi">51</span><span class="o">%</span>   <span class="mi">24000</span>  <span class="mi">0</span><span class="p">.</span><span class="mi">152517</span>   <span class="mi">157</span>
 <span class="mi">9</span>       <span class="n">yes</span>   <span class="mi">27</span><span class="o">%</span>   <span class="mi">14401</span>  <span class="mi">0</span><span class="p">.</span><span class="mo">033016</span>   <span class="mi">436</span>
<span class="mi">10</span>       <span class="n">yes</span>   <span class="mi">34</span><span class="o">%</span>   <span class="mi">14401</span>  <span class="mi">0</span><span class="p">.</span><span class="mo">001337</span> <span class="mi">10774</span>
<span class="n">Total</span>          <span class="mi">74</span><span class="o">%</span>  <span class="mi">112372</span>  <span class="mi">0</span><span class="p">.</span><span class="mi">297778</span>   <span class="mi">377</span>
</code></pre></div></div>

<ul>
  <li>Kops (throughtput) 처리량</li>
  <li>util (utilzation) 메모리이용도</li>
  <li>trace 7, 8에서 throughput이 심각하게 떨어짐 → find_fit 병목</li>
  <li>trace 4, 7, 8, 9에서 util 낮음 → fragmentation (단편화) 문제</li>
</ul>

<p>처음부터 끝까지 탐색하여 free공간을 찾는 묵시적 리스트 + 처음의 요청 했던 공간이 나오면 바로 할당하는 first fit  방식</p>

<p>앞부분에 free block이 있더라고 요청 크기에 맞지 않는 작은 조각들이 많아 사용하지 못하는 문하고 앞부분을 무시하고 뒤까지 찾아 처리량과 메모리 이용도가 떨어지는 현상이 나타남</p>

<h4 id="find_fit-병목-문제의-원인">find_fit 병목 문제의 원인</h4>

<ul>
  <li>implicit free list라서 전체 힙을 선형 탐색함</li>
  <li>first fit이라 매번 앞에서부터 다시 검사함</li>
  <li>앞부분에 요청 크기를 만족하지 못하는 작은 free block이 많아지면 검사 비용이 커짐</li>
</ul>

<h4 id="단편화-문제의-원인">단편화 문제의 원인</h4>

<ul>
  <li>split 이후 남은 작은 free block들이 축적됨</li>
  <li>alloc/free 패턴 때문에 free 공간이 연속되지 않고 흩어짐</li>
  <li>coalescing은 인접 free block만 합칠 수 있어서 조각난 공간을 완전히 해결하지 못함</li>
</ul>

<hr />

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">0</span><span class="o">:</span> <span class="n">amptjp</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">1</span><span class="o">:</span> <span class="n">cccp</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">2</span><span class="o">:</span> <span class="n">cp</span><span class="o">-</span><span class="n">decl</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">3</span><span class="o">:</span> <span class="n">expr</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">4</span><span class="o">:</span> <span class="n">coalescing</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">5</span><span class="o">:</span> <span class="n">random</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">6</span><span class="o">:</span> <span class="n">random2</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">7</span><span class="o">:</span> <span class="n">binary</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">8</span><span class="o">:</span> <span class="n">binary2</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">9</span><span class="o">:</span> <span class="n">realloc</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">10</span><span class="o">:</span> <span class="n">realloc2</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
</code></pre></div></div>

<p>첫번째 해결방법</p>

<ul>
  <li>trace 7, 8을 해결하기 위한 next_fit 방식 채택</li>
  <li>
    <p>현재 trace 7 패턴 분석</p>

    <p>### 1단계</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  a 0 64
  a 1 448
  a 2 64
  a 3 448
  ...
  ------------------------------------------------------------
  - 작은 블록 (64)
  - 큰 블록 (448)
  - 반복
</code></pre></div>    </div>

    <ul>
      <li><strong>작은/큰 블록을 번갈아가며 엄청 많이 할당</strong></li>
    </ul>

    <p>### 2단계</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  f 1
  f 3
  f 5
  ...
</code></pre></div>    </div>

    <ul>
      <li><strong>큰 블록들만 free</strong></li>
    </ul>

    <p>### 결과</p>

    <p>힙 상태</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [64][free 448][64][free 448][64][free 448]...
</code></pre></div>    </div>

    <ul>
      <li>free block 엄청 많음</li>
      <li>힙 길이 엄청 길어짐</li>
    </ul>

    <p>### 3단계</p>

    <p>뒤쪽 보면:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  a 4000 512
  a 4001 512
  ...
</code></pre></div>    </div>

    <ul>
      <li>큰 블록 다시 할당 시작</li>
    </ul>

    <p>#### find_fit 상황</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  find_fit(512) 할당할시 
  --&gt;
     
  [64] → 안됨
  [free 448] → 안됨
  [64] → 안됨
  [free 448] → 안됨
  ...
  (수천 개 반복)
</code></pre></div>    </div>

    <ul>
      <li><strong>끝까지 다 보고 나서야 큰 블록 찾음</strong></li>
    </ul>
  </li>
</ul>

<hr />

<h4 id="mm_realloc">mm_realloc()</h4>

<ul>
  <li>mm_realloc()
    <ul>
      <li>
        <p>mm_realloc</p>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kt">void</span> <span class="o">*</span><span class="nf">mm_realloc</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">)</span>
  <span class="p">{</span>
      <span class="kt">void</span> <span class="o">*</span><span class="n">newptr</span><span class="p">;</span>
      <span class="kt">size_t</span> <span class="n">copySize</span><span class="p">;</span>
        
      <span class="k">if</span> <span class="p">(</span><span class="n">ptr</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="n">mm_malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
      <span class="p">}</span>
        
      <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">mm_free</span><span class="p">(</span><span class="n">ptr</span><span class="p">);</span>
          <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
      <span class="p">}</span>
        
      <span class="n">newptr</span> <span class="o">=</span> <span class="n">mm_malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">newptr</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
      <span class="p">}</span>
        
      <span class="n">copySize</span> <span class="o">=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">ptr</span><span class="p">))</span> <span class="o">-</span> <span class="n">DSIZE</span><span class="p">;</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">&lt;</span> <span class="n">copySize</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">copySize</span> <span class="o">=</span> <span class="n">size</span><span class="p">;</span>
      <span class="p">}</span>
        
      <span class="n">memcpy</span><span class="p">(</span><span class="n">newptr</span><span class="p">,</span> <span class="n">ptr</span><span class="p">,</span> <span class="n">copySize</span><span class="p">);</span>
      <span class="n">mm_free</span><span class="p">(</span><span class="n">ptr</span><span class="p">);</span>
      <span class="k">return</span> <span class="n">newptr</span><span class="p">;</span>
  <span class="p">}</span>
        
</code></pre></div>        </div>
      </li>
    </ul>

    <p><code class="language-plaintext highlighter-rouge">realloc(bp, size)</code>의 뜻 == 최종적으로 확보하고 싶은 새 메모리 크기</p>

    <blockquote>
      <p>현재 블록이 이미 새 요청을 만족하면, 굳이 새 블록을 만들 필요는 없다</p>

    </blockquote>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  "기존 블록 bp의 데이터를 유지하면서,
  크기를 size로 바꿔라"
</code></pre></div>    </div>

    <ul>
      <li>더 크게 바꿀 수도 있고</li>
      <li>더 작게 바꿀 수도 있고</li>
      <li>없애버릴 수도 있고</li>
      <li>새로 만들 수도 있음</li>
    </ul>

    <p>1단계: <code class="language-plaintext highlighter-rouge">bp == NULL</code></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">(</span><span class="n">bp</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">mm_malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="o">-------------------------------------------</span>
  <span class="err">기존</span> <span class="err">블럭이</span> <span class="err">없으니</span> <span class="err">그냥</span> <span class="err">새로</span> <span class="err">만들어버림</span>
  <span class="n">realloc</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span> <span class="o">==</span> <span class="n">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">)</span>
</code></pre></div>    </div>

    <p>2단계: <code class="language-plaintext highlighter-rouge">size == 0</code></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">mm_free</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
      <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <ul>
      <li>크기가 0 이라는 의미는 필요없다는의미</li>
      <li>기존 bp 블럭 free로 만듬</li>
    </ul>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="err">기존</span><span class="o">:</span>
  <span class="p">[</span> <span class="n">old</span> <span class="n">block</span> <span class="p">]</span>
      <span class="o">^</span>
      <span class="n">bp</span>
    
  <span class="n">realloc</span><span class="p">(</span><span class="n">bp</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
  <span class="o">-&gt;</span> <span class="n">free</span><span class="p">(</span><span class="n">bp</span><span class="p">)</span>
    
  <span class="err">결과</span><span class="o">:</span>
  <span class="p">[</span> <span class="n">free</span> <span class="n">block</span> <span class="p">]</span>
</code></pre></div>    </div>

    <p>3단계: 새 블록 만들기</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">newptr</span> <span class="o">=</span> <span class="n">mm_malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">newptr</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <ul>
      <li>기존 블록이 있고, 새 크기도 0이 아니니까,</li>
      <li>새 크기에 맞는 새 블록을 하나 만듬</li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ old H | old payload | old F ]
            ^
            bp
</code></pre></div>    </div>

    <p>새 블록 생성 후 →</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ old H | old payload | old F ]      [ new H | new payload | new F ]
            ^                                    ^
            bp                                 newptr
              
  -----------------------------------------------------------------------
  이미 mm_malloc으로 인해 new block의 header/footer는 준비 완료
  이제 bp의 old payload를 new payload로 옮겨야함
</code></pre></div>    </div>

    <p><strong>4단계: 복사할 크기 계산</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">copySize</span> <span class="o">=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">))</span> <span class="o">-</span> <span class="n">DSIZE</span><span class="p">;</span>
</code></pre></div>    </div>

    <ul>
      <li>전체크기 - 8바이트(header, footer크기) == payload크기</li>
    </ul>

    <p><strong>5단계: 너무 많이 복사하지 않게 조정</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">&lt;</span> <span class="n">copySize</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">copySize</span> <span class="o">=</span> <span class="n">size</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <ul>
      <li>요청한 사이즈가 기존 old payload에 데이터의 크기보다 작으면</li>
      <li>요청한 사이즈대로 됨 → 데이터 손실됨</li>
    </ul>

    <p>6단계: 실제 복사</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">memcpy</span><span class="p">(</span><span class="n">newptr</span><span class="p">,</span> <span class="n">bp</span><span class="p">,</span> <span class="n">copySize</span><span class="p">)</span>
  <span class="o">=</span> <span class="n">old</span> <span class="n">payload</span> <span class="o">-&gt;</span> <span class="n">new</span> <span class="n">payload</span>
</code></pre></div>    </div>

    <p>7단계: 기존 블록 free</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">mm_free</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
</code></pre></div>    </div>

    <p>복사 전:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ old block ]      [ new block ]
      ^                  ^
      bp               newptr
</code></pre></div>    </div>

    <p>복사 후 free:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ free block ]     [ new block with copied data ]
                         ^
                       newptr
</code></pre></div>    </div>

    <p><strong>8단계: 새 포인터 반환</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">return</span> <span class="n">newptr</span><span class="p">;</span>
</code></pre></div>    </div>

    <p>#### 시작</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ old H | old payload DATA | old F ]
            ^
            bp
</code></pre></div>    </div>

    <p>#### 새 블록 생성</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ old H | old payload DATA | old F ]     [ new H | new payload | new F ]
            ^                                       ^
            bp                                    newptr
</code></pre></div>    </div>

    <p>#### payload만 복사</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ old H | old payload DATA | old F ]     [ new H | new payload DATA | new F ]
            ^                                       ^
            bp                                    newptr
</code></pre></div>    </div>

    <p>#### old block free</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ free block ]                           [ new H | new payload DATA | new F ]
                                                 ^
                                               newptr
</code></pre></div>    </div>

    <p>#### 반환</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  return newptr;
</code></pre></div>    </div>
  </li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">0</span><span class="o">:</span> <span class="n">amptjp</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">1</span><span class="o">:</span> <span class="n">cccp</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">2</span><span class="o">:</span> <span class="n">cp</span><span class="o">-</span><span class="n">decl</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">3</span><span class="o">:</span> <span class="n">expr</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">4</span><span class="o">:</span> <span class="n">coalescing</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">5</span><span class="o">:</span> <span class="n">random</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">6</span><span class="o">:</span> <span class="n">random2</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">7</span><span class="o">:</span> <span class="n">binary</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">8</span><span class="o">:</span> <span class="n">binary2</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">9</span><span class="o">:</span> <span class="n">realloc</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
<span class="mi">10</span><span class="o">:</span> <span class="n">realloc2</span><span class="o">-</span><span class="n">bal</span><span class="p">.</span><span class="n">rep</span>
</code></pre></div></div>

<h4 id="변경전후--implicit-list-first_fit---implicit-list-next_fit"><strong>변경전후 : implicit list (first_fit) -&gt; implicit list (next_fit)</strong></h4>

<ul>
  <li><strong>implicit list (first_fit)</strong></li>
</ul>

<p>Results for mm malloc:
trace  valid  util     ops      secs  Kops
0       yes   99%    5694  0.005180  1099
1       yes   99%    5848  0.003205  1825
2       yes   99%    6648  0.005431  1224
3       yes  100%    5380  0.003890  1383
4       yes   66%   14400  0.000059245734
5       yes   92%    4800  0.003247  1478
6       yes   92%    4800  0.003012  1594
7       yes   55%   12000  0.086887   138
8       yes   51%   24000  0.152517   157
9       yes   27%   14401  0.033016   436
10       yes   34%   14401  0.001337 10774
Total          74%  112372  0.297778   377</p>

<p>Perf index = 44 (util) + 26 (thru) = 70/100</p>

<ul>
  <li><strong>implicit list (next_fit)</strong></li>
</ul>

<p>Results for mm malloc:
trace  valid  util     ops      secs  Kops
0       yes   91%    5694  0.001868  3048
1       yes   92%    5848  0.000735  7959
2       yes   96%    6648  0.002205  3015
3       yes   96%    5380  0.002318  2321
4       yes   66%   14400  0.000072200278
5       yes   91%    4800  0.002264  2121
6       yes   90%    4800  0.001992  2410
7       yes   55%   12000  0.008668  1384
8       yes   51%   24000  0.003968  6048
9       yes   27%   14401  0.033191   434
10       yes   53%   14401  0.000064225368
Total          73%  112372  0.057344  1960</p>

<p>Perf index = 44 (util) + 40 (thru) = 84/100</p>

<ul>
  <li>
    <p>바꾼 코드들 리뷰</p>

    <p><strong>1. 전역 변수 / 함수 원형 추가</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">heap_listp</span><span class="p">;</span>
  <span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">rover</span><span class="p">;</span>  <span class="c1">// 추가: next fit의 "탐색 시작점"을 기억하는 커서</span>
    
  <span class="k">static</span> <span class="kt">void</span> <span class="o">*</span><span class="nf">extend_heap</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">words</span><span class="p">);</span>
  <span class="k">static</span> <span class="kt">void</span> <span class="o">*</span><span class="nf">coalesce</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">bp</span><span class="p">);</span>
  <span class="k">static</span> <span class="kt">void</span> <span class="o">*</span><span class="nf">find_fit</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">asize</span><span class="p">);</span>
  <span class="k">static</span> <span class="kt">void</span> <span class="nf">place</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">bp</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">asize</span><span class="p">);</span>
  <span class="k">static</span> <span class="kt">size_t</span> <span class="nf">adjust_block_size</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">size</span><span class="p">);</span>            <span class="c1">// 추가: size 계산 규칙 일원화</span>
  <span class="k">static</span> <span class="kt">int</span> <span class="nf">can_expand_into_next</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">bp</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">asize</span><span class="p">);</span> <span class="c1">// 추가: realloc 제자리 확장 가능 여부 검사</span>
  <span class="k">static</span> <span class="kt">void</span> <span class="nf">expand_into_next</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">bp</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">asize</span><span class="p">);</span>    <span class="c1">// 추가: realloc 제자리 확장 수행</span>
</code></pre></div>    </div>

    <p><strong>2. mm_init</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kt">int</span> <span class="nf">mm_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
  <span class="p">{</span>
      <span class="k">if</span> <span class="p">((</span><span class="n">heap_listp</span> <span class="o">=</span> <span class="n">mem_sbrk</span><span class="p">(</span><span class="mi">4</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">))</span> <span class="o">==</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
      <span class="p">}</span>
    
      <span class="n">PUT</span><span class="p">(</span><span class="n">heap_listp</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">heap_listp</span> <span class="o">+</span> <span class="p">(</span><span class="mi">1</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">DSIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">heap_listp</span> <span class="o">+</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">DSIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">heap_listp</span> <span class="o">+</span> <span class="p">(</span><span class="mi">3</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">));</span>
      <span class="n">heap_listp</span> <span class="o">+=</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">);</span>
    
      <span class="n">rover</span> <span class="o">=</span> <span class="n">heap_listp</span><span class="p">;</span>  <span class="c1">// 추가: 처음에는 힙 시작점에서 next fit 탐색을 시작하게 함</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">extend_heap</span><span class="p">(</span><span class="n">CHUNKSIZE</span> <span class="o">/</span> <span class="n">WSIZE</span><span class="p">)</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
      <span class="p">}</span>
    
      <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p><strong>3. find_fit</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">static</span> <span class="kt">void</span> <span class="o">*</span><span class="nf">find_fit</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">asize</span><span class="p">)</span>
  <span class="p">{</span>
      <span class="kt">void</span> <span class="o">*</span><span class="n">bp</span><span class="p">;</span>
    
      <span class="c1">// 변경: heap 처음부터 매번 찾지 않고 rover부터 끝까지 먼저 탐색</span>
      <span class="k">for</span> <span class="p">(</span><span class="n">bp</span> <span class="o">=</span> <span class="n">rover</span><span class="p">;</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">))</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span> <span class="n">bp</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">))</span> <span class="p">{</span>
          <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">GET_ALLOC</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">))</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">asize</span> <span class="o">&lt;=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">))))</span> <span class="p">{</span>
              <span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
          <span class="p">}</span>
      <span class="p">}</span>
    
      <span class="c1">// 변경: 끝까지 못 찾으면 앞부분(heap 시작 ~ rover 직전)만 다시 탐색</span>
      <span class="c1">// 이유: 힙 전체를 최대 한 바퀴만 보게 해서 반복 스캔 비용을 줄이려는 것</span>
      <span class="k">for</span> <span class="p">(</span><span class="n">bp</span> <span class="o">=</span> <span class="n">heap_listp</span><span class="p">;</span> <span class="n">bp</span> <span class="o">!=</span> <span class="n">rover</span><span class="p">;</span> <span class="n">bp</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">))</span> <span class="p">{</span>
          <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">GET_ALLOC</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">))</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">asize</span> <span class="o">&lt;=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">))))</span> <span class="p">{</span>
              <span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
          <span class="p">}</span>
      <span class="p">}</span>
      <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p><strong>4. mm_malloc</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kt">void</span> <span class="o">*</span><span class="nf">mm_malloc</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">size</span><span class="p">)</span>
  <span class="p">{</span>
      <span class="kt">size_t</span> <span class="n">asize</span><span class="p">;</span>
      <span class="kt">char</span> <span class="o">*</span><span class="n">bp</span><span class="p">;</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
      <span class="p">}</span>
    
      <span class="c1">// 변경: block size 계산을 helper로 분리</span>
      <span class="c1">// 이유: malloc/realloc이 같은 size 계산 규칙을 공유하게 하려는 것</span>
      <span class="n">asize</span> <span class="o">=</span> <span class="n">adjust_block_size</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
    
      <span class="k">if</span> <span class="p">((</span><span class="n">bp</span> <span class="o">=</span> <span class="n">find_fit</span><span class="p">(</span><span class="n">asize</span><span class="p">))</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">place</span><span class="p">(</span><span class="n">bp</span><span class="p">,</span> <span class="n">asize</span><span class="p">);</span>
          <span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
      <span class="p">}</span>
    
      <span class="k">if</span> <span class="p">((</span><span class="n">bp</span> <span class="o">=</span> <span class="n">extend_heap</span><span class="p">(</span><span class="n">MAX</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="n">CHUNKSIZE</span><span class="p">)</span> <span class="o">/</span> <span class="n">WSIZE</span><span class="p">))</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
      <span class="p">}</span>
    
      <span class="n">place</span><span class="p">(</span><span class="n">bp</span><span class="p">,</span> <span class="n">asize</span><span class="p">);</span>
      <span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p><strong>5. place</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">static</span> <span class="kt">void</span> <span class="nf">place</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">bp</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">asize</span><span class="p">)</span>
  <span class="p">{</span>
      <span class="kt">size_t</span> <span class="n">csize</span> <span class="o">=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">));</span>
    
      <span class="k">if</span> <span class="p">((</span><span class="n">csize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">DSIZE</span><span class="p">))</span> <span class="p">{</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
    
          <span class="n">bp</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
    
          <span class="n">rover</span> <span class="o">=</span> <span class="n">bp</span><span class="p">;</span>
          <span class="c1">// 추가: split이 일어나면 남은 free block 쪽으로 rover를 이동</span>
          <span class="c1">// 이유: 다음 탐색이 방금 남겨둔 free 공간부터 시작되게 해서 next fit 효과를 살림</span>
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
    
          <span class="n">rover</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
          <span class="c1">// 추가: split이 없으면 다음 블록으로 rover 이동</span>
          <span class="c1">// 이유: 같은 블록/앞부분을 반복 탐색하지 않게 하려는 것</span>
      <span class="p">}</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p><strong>6. coalesce</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">static</span> <span class="kt">void</span> <span class="o">*</span><span class="nf">coalesce</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span> <span class="n">bp</span><span class="p">)</span> <span class="p">{</span>
    
      <span class="kt">size_t</span> <span class="n">prev_alloc</span> <span class="o">=</span> <span class="n">GET_ALLOC</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)));</span>
      <span class="kt">size_t</span> <span class="n">next_alloc</span> <span class="o">=</span> <span class="n">GET_ALLOC</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)));</span>
      <span class="kt">size_t</span> <span class="n">size</span> <span class="o">=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">));</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">prev_alloc</span> <span class="o">&amp;&amp;</span> <span class="n">next_alloc</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">prev_alloc</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">next_alloc</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">size</span> <span class="o">+=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span><span class="mi">0</span><span class="p">));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span><span class="mi">0</span><span class="p">));</span>
    
      <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">prev_alloc</span> <span class="o">&amp;&amp;</span> <span class="n">next_alloc</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">size</span> <span class="o">+=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
          <span class="n">bp</span> <span class="o">=</span> <span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
    
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
          <span class="n">size</span> <span class="o">+=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)))</span>
                <span class="o">+</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
          <span class="n">bp</span> <span class="o">=</span> <span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
      <span class="p">}</span>
    
      <span class="k">if</span> <span class="p">((</span><span class="n">rover</span> <span class="o">&gt;</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">bp</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">rover</span> <span class="o">&lt;</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)))</span> <span class="p">{</span>
          <span class="n">rover</span> <span class="o">=</span> <span class="n">bp</span><span class="p">;</span>
          <span class="c1">// 추가: rover가 병합된 큰 free block 내부를 가리키고 있으면</span>
          <span class="c1">// 병합 결과 블록의 시작점으로 되돌림</span>
          <span class="c1">// 이유: rover가 "유효한 블록 시작점"이 아니면 find_fit이 잘못된 header를 읽어서</span>
          <span class="c1">// overlap / heap outside 같은 오류가 날 수 있음</span>
      <span class="p">}</span>
    
      <span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p><strong>7. mm_realloc</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kt">void</span> <span class="o">*</span><span class="nf">mm_realloc</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">bp</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">)</span>
  <span class="p">{</span>
      <span class="kt">void</span> <span class="o">*</span><span class="n">newptr</span><span class="p">;</span>
      <span class="kt">size_t</span> <span class="n">copySize</span><span class="p">;</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">bp</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="n">mm_malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
          <span class="c1">// 유지/정리: realloc(NULL, size)는 malloc과 동일하게 처리</span>
      <span class="p">}</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">mm_free</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
          <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
          <span class="c1">// 유지/정리: realloc(ptr, 0)은 free와 동일하게 처리</span>
      <span class="p">}</span>
    
      <span class="kt">size_t</span> <span class="n">oldsize</span> <span class="o">=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">));</span>
      <span class="kt">size_t</span> <span class="n">asize</span> <span class="o">=</span> <span class="n">adjust_block_size</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
      <span class="c1">// 변경: realloc도 malloc과 같은 block size 계산 사용</span>
    	
      <span class="k">if</span> <span class="p">(</span><span class="n">asize</span> <span class="o">&lt;=</span> <span class="n">oldsize</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
          <span class="c1">// 추가: 현재 블록이 이미 충분히 크면 새로 malloc/memcpy/free 함</span>
    
          <span class="kt">size_t</span> <span class="n">remainder</span> <span class="o">=</span> <span class="n">oldsize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">;</span>
    				
  				<span class="c1">// 추가 : 뒤에 공간이 최소 크기 16 바이트 이상이면 뒤에꺼 free해줌</span>
          <span class="k">if</span> <span class="p">(</span><span class="n">remainder</span> <span class="o">&gt;=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DSIZE</span><span class="p">)</span> <span class="p">{</span>
                
              <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
              <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
    
              <span class="kt">void</span> <span class="o">*</span><span class="n">split_bp</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
              <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">split_bp</span><span class="p">),</span>  <span class="n">PACK</span><span class="p">(</span><span class="n">remainder</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
              <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">split_bp</span><span class="p">),</span>  <span class="n">PACK</span><span class="p">(</span><span class="n">remainder</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
    
              <span class="k">if</span> <span class="p">((</span><span class="n">rover</span> <span class="o">&gt;</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">bp</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">rover</span> <span class="o">&lt;</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">split_bp</span><span class="p">)))</span> <span class="p">{</span>
                  <span class="n">rover</span> <span class="o">=</span> <span class="n">split_bp</span><span class="p">;</span>
              <span class="p">}</span>
    
              <span class="n">coalesce</span><span class="p">(</span><span class="n">split_bp</span><span class="p">);</span>
          <span class="p">}</span>
            
  			<span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
    			
      <span class="p">}</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">can_expand_into_next</span><span class="p">(</span><span class="n">bp</span><span class="p">,</span> <span class="n">asize</span><span class="p">))</span> <span class="p">{</span>
          <span class="n">expand_into_next</span><span class="p">(</span><span class="n">bp</span><span class="p">,</span> <span class="n">asize</span><span class="p">);</span>
          <span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
          <span class="c1">// 추가: 다음 블록이 free이고 합치면 충분하면 제자리 확장</span>
          <span class="c1">// 이유: realloc trace에서 malloc+memcpy+free를 피하려고</span>
      <span class="p">}</span>
    
      <span class="n">newptr</span> <span class="o">=</span> <span class="n">mm_malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">newptr</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
      <span class="p">}</span>
    
      <span class="n">copySize</span> <span class="o">=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">))</span> <span class="o">-</span> <span class="n">DSIZE</span><span class="p">;</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">&lt;</span> <span class="n">copySize</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">copySize</span> <span class="o">=</span> <span class="n">size</span><span class="p">;</span>
      <span class="p">}</span>
    
      <span class="n">memcpy</span><span class="p">(</span><span class="n">newptr</span><span class="p">,</span> <span class="n">bp</span><span class="p">,</span> <span class="n">copySize</span><span class="p">);</span>
      <span class="n">mm_free</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
      <span class="k">return</span> <span class="n">newptr</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p><strong>8. adjust_block_size</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">static</span> <span class="kt">size_t</span> <span class="nf">adjust_block_size</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">size</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">&lt;=</span> <span class="n">DSIZE</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DSIZE</span><span class="p">;</span>
          <span class="c1">// 추가: 최소 블록 크기 보장</span>
          <span class="c1">// 이유: 헤더/푸터 + 최소 payload를 담을 수 있어야 함</span>
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
          <span class="k">return</span> <span class="n">DSIZE</span> <span class="o">*</span> <span class="p">((</span><span class="n">size</span> <span class="o">+</span> <span class="n">DSIZE</span> <span class="o">+</span> <span class="p">(</span><span class="n">DSIZE</span> <span class="o">-</span> <span class="mi">1</span><span class="p">))</span> <span class="o">/</span> <span class="n">DSIZE</span><span class="p">);</span>
          <span class="c1">// 추가: 헤더/푸터 포함 후 8바이트 정렬된 실제 block size 계산</span>
          <span class="c1">// 이유: malloc/free/realloc이 동일한 규칙으로 block 크기를 맞추게 하려는 것</span>
      <span class="p">}</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p><strong>9. can_expand_into_next</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">static</span> <span class="kt">int</span> <span class="nf">can_expand_into_next</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">bp</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">asize</span><span class="p">)</span>
  <span class="p">{</span>
      <span class="kt">void</span> <span class="o">*</span><span class="n">next_bp</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">next_bp</span><span class="p">))</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
          <span class="c1">// 추가: epilogue면 확장 불가</span>
      <span class="p">}</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">GET_ALLOC</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">next_bp</span><span class="p">)))</span> <span class="p">{</span>
          <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
          <span class="c1">// 추가: 다음 블록이 할당 중이면 흡수 불가</span>
      <span class="p">}</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">))</span> <span class="o">+</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">next_bp</span><span class="p">))</span> <span class="o">&gt;=</span> <span class="n">asize</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
          <span class="c1">// 추가: 현재 블록 + 다음 free 블록 크기가 요청 크기를 만족하면 확장 가능</span>
      <span class="p">}</span>
    
      <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p><strong>10. expand_into_next</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">static</span> <span class="kt">void</span> <span class="nf">expand_into_next</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">bp</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">asize</span><span class="p">)</span>
  <span class="p">{</span>
      <span class="kt">void</span> <span class="o">*</span><span class="n">next_bp</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
      <span class="kt">size_t</span> <span class="n">oldsize</span> <span class="o">=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">));</span>
      <span class="kt">size_t</span> <span class="n">nextsize</span> <span class="o">=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">next_bp</span><span class="p">));</span>
      <span class="kt">size_t</span> <span class="n">combined</span> <span class="o">=</span> <span class="n">oldsize</span> <span class="o">+</span> <span class="n">nextsize</span><span class="p">;</span>
    
      <span class="k">if</span> <span class="p">(</span><span class="n">combined</span> <span class="o">-</span> <span class="n">asize</span> <span class="o">&gt;=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DSIZE</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
          <span class="c1">// 변경: 요청 크기만큼 현재 블록을 확장해서 allocated로 유지</span>
    
          <span class="kt">void</span> <span class="o">*</span><span class="n">split_bp</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">split_bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">combined</span> <span class="o">-</span> <span class="n">asize</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">split_bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">combined</span> <span class="o">-</span> <span class="n">asize</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
          <span class="c1">// 추가: 남는 공간이 충분하면 뒤를 다시 free block으로 남겨둠</span>
          <span class="c1">// 이유: utilization을 덜 해치기 위해</span>
      <span class="p">}</span>
      <span class="k">else</span> <span class="p">{</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">combined</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
          <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">combined</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
          <span class="c1">// 추가: 애매하게 남는 작은 조각은 split하지 않고 전부 현재 블록에 포함</span>
          <span class="c1">// 이유: 쓸모없는 작은 free block 생성을 막기 위해</span>
            
      <span class="c1">// 추가 필요: rover 보정</span>
      <span class="kt">void</span> <span class="o">*</span><span class="n">merged_end</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span> <span class="c1">// expand 후 bp의 다음 블록</span>
      <span class="k">if</span> <span class="p">((</span><span class="n">rover</span> <span class="o">&gt;</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">bp</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">rover</span> <span class="o">&lt;</span> <span class="n">merged_end</span><span class="p">))</span> <span class="p">{</span>
          <span class="n">rover</span> <span class="o">=</span> <span class="n">bp</span><span class="p">;</span> <span class="c1">// 또는 split 결과 free block 위치로</span>
    
  	    <span class="p">}</span>
  	<span class="p">}</span>
  <span class="p">}</span>
</code></pre></div>    </div>
  </li>
</ul>]]></content><author><name></name></author><category term="C" /><category term="Memory" /><category term="Allocator" /><category term="malloc" /><category term="free" /><summary type="html"><![CDATA[fisrt_fit의 방식을 next_fit방식으로 전환을 통해 최적화를 진행한다.]]></summary></entry><entry><title type="html">Dynamic Memory Allocation (implicit free list)</title><link href="https://juhoseok.github.io/jekyll-theme-velog/dynamic-memory-allocation/" rel="alternate" type="text/html" title="Dynamic Memory Allocation (implicit free list)" /><published>2026-04-13T16:00:00+09:00</published><updated>2026-04-13T16:00:00+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/dynamic-memory-allocation</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/dynamic-memory-allocation/"><![CDATA[<ul>
  <li>런타임 (프로그램에 실행중)에 메모리를 획득할때 동적 메모리 할당기(malloc, free)를 사용하는게 편리하고 호환성이 좋음</li>
  <li>동적메모리 할당기는 os가 주는 힙영역에서 받아온 메모리를 관리</li>
  <li>힙에서 메모리의 크기를 결정하고 관리하는데 brk는 위쪽 기준으로 힙의 끝이다</li>
  <li>메모리를 키운다는 의미는 brk를 위쪽으로 민다는 의미 (메모리의 경계를 늘림)</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/images/posts/dynamic-memory-allocation/heap-memory-layout.png" alt="힙 메모리 구조" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>        [ 높은 주소 ]
             ↑
             │
    ┌───────────────────┐
    │    미사용 공간     │
    ├───────────────────┤  ← brk (현재 힙의 끝)
    │     힙 (Heap)      │
    │  할당기가 관리하는 │
    │       영역         │
    ├───────────────────┤
    │    데이터 영역     │
    ├───────────────────┤
    │     코드 영역      │
    └───────────────────┘
             │
             ↓
        [ 낮은 주소 ]
</code></pre></div></div>

<p>메모리 구조</p>

<ul>
  <li>
    <p><strong>void *mem_sbrk(int incr)</strong></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">mem_brk</span><span class="p">;</span>   <span class="c1">// 현재 힙의 끝(next free position)을 가리키는 포인터</span>
    
  <span class="kt">void</span> <span class="o">*</span><span class="nf">mem_sbrk</span><span class="p">(</span><span class="kt">int</span> <span class="n">incr</span><span class="p">)</span> <span class="c1">// 힙을 incr 바이트 늘림</span>
  <span class="p">{</span>
      <span class="kt">char</span> <span class="o">*</span><span class="n">old_brk</span> <span class="o">=</span> <span class="n">mem_brk</span><span class="p">;</span> <span class="c1">// 늘리기 전 힙 끝 주소를 저장</span>
    
      <span class="k">if</span> <span class="p">((</span><span class="n">incr</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="o">||</span> <span class="p">((</span><span class="n">mem_brk</span> <span class="o">+</span> <span class="n">incr</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">mem_max_addr</span><span class="p">))</span> <span class="p">{</span>
          <span class="p">...</span>
          <span class="k">return</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span>
      <span class="p">}</span>
    
      <span class="n">mem_brk</span> <span class="o">+=</span> <span class="n">incr</span><span class="p">;</span> <span class="c1">// 힙 끝을 incr 바이트 앞으로 이동</span>
      <span class="k">return</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">old_brk</span><span class="p">;</span> <span class="c1">// 새로 확보된 공간의 시작 주소 반환</span>
  <span class="p">}</span>
    
  <span class="c1">//old_brk = 1000</span>
  <span class="c1">// mem_brk = 1016</span>
  <span class="c1">// return 1000</span>
    
  <span class="c1">// 1000 ~ 1015 확보된 공간</span>
  <span class="c1">// 유효 바이트 1015 그다음위치 1016를 가리킴 </span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>brk 힙영역의 메모리의 끝주소 를 늘리고 그 전의 끝 주소를 반환받는 과정</p>
  </li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>늘리기 전:
[ ... 기존 힙 ... ][mem_brk=1000]

mem_sbrk(24) 호출 후:
[ ... 기존 힙 ... ][ 새 공간 24바이트 ][mem_brk=1024]
                  ^
                old_brk=1000 반환
                
// ord_brk 는 새로운 공간의 시작점
</code></pre></div></div>

<hr />

<ul>
  <li>힙의 공간이 아래와 같다 했을때</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[-------------------------------------------]
</code></pre></div></div>

<p>이걸 할당기는 내부적으로 이렇게 쪼개 생각한다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[블록][블록][블록][블록][블록] ...
</code></pre></div></div>

<p>그리고 각 블록은 상태가 다르다</p>

<ul>
  <li>어떤 블록은 <strong>사용 중(allocated)</strong></li>
  <li>어떤 블록은 <strong>비어 있음(free)</strong></li>
</ul>

<p>예를 들어</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ 사용중 32B ][ 빈공간 64B ][ 사용중 16B ][ 빈공간 128B ]
</code></pre></div></div>

<ul>
  <li>이렇게 본다.</li>
  <li><strong>힙 = 여러 크기의 블록들의 모음이다.</strong></li>
</ul>

<p><img src="/jekyll-theme-velog/assets/images/posts/dynamic-memory-allocation/heap-blocks-overview.png" alt="힙 블록 구성 예시" /></p>

<p>할당기는 두개의 기본 유형이 가능</p>

<ul>
  <li>명시적 할당기
    <ul>
      <li>프로그래머가 할당하고 해제하는걸 명시적 할당기 라고함</li>
    </ul>
  </li>
  <li>묵시적 할당기
    <ul>
      <li>프로그램이 알아서 해제 하는걸 묵시적 할당기라고함 (가비지 컬랙터)</li>
    </ul>
  </li>
</ul>

<hr />

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#inclue &lt;stdlib.h&gt;
</span>
<span class="kt">void</span> <span class="o">*</span><span class="nf">malloc</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">size</span><span class="p">);</span>

<span class="c1">//malloc(size)는</span>

<span class="c1">// 최소 `size` 바이트 이상** 쓸 수 있는</span>
<span class="c1">// 연속된 메모리 블록**을 잡아주고</span>
<span class="c1">// 그 블록의 **시작 주소**를 포인터로 리턴한다.</span>
</code></pre></div></div>

<ul>
  <li>메모리 블록의 포인터를 리턴함</li>
  <li><del>그럼 처음시작 위치의 포인터와 끝위치의 포인터를 리턴해줘서 그 사이를 사용할 수 있게해주는거야?</del>
    <ul>
      <li><code class="language-plaintext highlighter-rouge">malloc</code>은 <strong>시작 위치의 포인터 딱 하나</strong>만 리턴합니다. 끝 위치를 따로 알려주지 않는 이유는 할당기가 그 정보를 <strong>헤더(Header)</strong>에 숨겨두었기 때문입니다.</li>
      <li>현재위치에다가 헤더에 크기를 더하면 다음 블럭의위치를 알수 있기때문에</li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  주소 (낮음)
      |
  +-----------+ 
  |   Header  | (여기에 "크기=32"라고 적혀 있음)
  +-----------+ &lt;--- malloc이 리턴하는 포인터 (p)
  |           |
  |  Payload  | (사용자가 실제로 쓰는 24바이트 공간)
  |           |
  +-----------+ 
  |  Padding  | (정렬을 위한 빈 공간)
  +-----------+ 
      |
  주소 (높음)
</code></pre></div>    </div>
  </li>
  <li>malloc은 적절히 정렬된 주소를 반환해줌
    <ul>
      <li>32비트 모드에서 주소는 항상 8의배수</li>
      <li>64비트 모드에서 주소는 항상 16의 배수</li>
    </ul>
  </li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>char *p = malloc(8);

p가 리턴하는 것
↓
주소 2000 [ ][ ][ ][ ][ ][ ][ ][ ]
          ↑                    ↑
        시작 바이트          마지막 바이트

사용 가능 범위: 2000 ~ 2007
</code></pre></div></div>

<ul>
  <li>malloc과 free를 사용해서 블록을 할당하고 반환시키기</li>
</ul>

<p><img src="/jekyll-theme-velog/assets/images/posts/dynamic-memory-allocation/malloc-free-allocation-example.png" alt="malloc 과 free 재사용 예시" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(a) 4 ints requested
[ w ][ w ][ w ][ w ]
= 4 words
= 16 bytes
-&gt; already aligned

(b) 5 ints requested
[ w ][ w ][ w ][ w ][ w ]
= 5 words
= 20 bytes
-&gt; not aligned to 8 bytes

add 1 more word padding:
[ w ][ w ][ w ][ w ][ w ][ pad ]
= 6 words
= 24 bytes
-&gt; aligned
</code></pre></div></div>

<aside>
💡

- 각 사각형은 워드를나타냄
- 1워드는 int형, 4byte로 봄
- 4워드 블록요청 (16 byte)
- 5워드 블록요청 (20byte) 8의 배수의 맞지않음 → 6워드 반환 (24byte)
</aside>

<ol>
  <li>
    <p><code class="language-plaintext highlighter-rouge">p1 = malloc(4 * sizeof(int))</code></p>

    <p>→ 처음 free 블록에서 <strong>4워드</strong>를 잘라서 <code class="language-plaintext highlighter-rouge">p1</code>에 할당함.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">p2 = malloc(5 * sizeof(int))</code></p>

    <p>→ 그 다음 남은 공간에서 <code class="language-plaintext highlighter-rouge">p2</code>를 할당함.</p>

    <p>→ <strong>정렬 때문에 실제로는 6워드</strong>가 사용됨.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">p3 = malloc(6 * sizeof(int))</code></p>

    <p>→ 남아 있는 free 블록에서 다시 <strong>6워드</strong>를 잘라 <code class="language-plaintext highlighter-rouge">p3</code>에 할당함.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">free(p2)</code></p>

    <p>→ <code class="language-plaintext highlighter-rouge">p2</code>가 쓰던 블록을 <strong>반환해서 free 블록</strong>으로 만듦.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">p4 = malloc(2 * sizeof(int))</code></p>

    <p>→ 새 공간을 늘리기보다, <strong>방금 free된 p2 자리 일부를 재사용</strong>해서 <code class="language-plaintext highlighter-rouge">p4</code>를 할당함.</p>
  </li>
</ol>

<hr />

<h3 id="할당기-요구사항과-목표">할당기 요구사항과 목표</h3>

<h4 id="제약사항">제약사항</h4>

<ul>
  <li>
    <p>요청 순서를 마음대로 바꿀 수 없음</p>

    <p>### 1) 임의의 요청 순서 처리하기</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  malloc
  malloc
  free
  malloc
  free
  free
  malloc
</code></pre></div>    </div>

    <p>‘아마 malloc다음에 free가 오겠지?’</p>

    <p>‘항상 짝지어 들어오겠지?’</p>

    <p>라는 가정을 하면 안됨</p>

    <ul>
      <li>요청순서는 예측 불가</li>
      <li>할당기는 그때그때 처리해야함</li>
    </ul>
  </li>
  <li>요청이 오면 바로 응답해야 함
    <ul>
      <li>프로그램이 malloc을 호출하면</li>
      <li>요청을 모아뒀다 나중에 한꺼번에 처리하지않고 당장 적절한 블록을 찾아 응답해야함</li>
    </ul>
  </li>
  <li>힙(heap) 안에서 관리해야 함
    <ul>
      <li>“할당기를 관리하려고 힙 밖에 큰 보조창고를 따로 만들지 말라”</li>
    </ul>
  </li>
  <li>
    <p>정렬(alignment)을 맞춰야 함</p>

    <p>## 4. 정렬</p>

    <p>블록 크기를 8바이트, 16바이트의 배수로 맞추는 이유</p>

    <ul>
      <li>데이터를 메모리에서 읽어올 때 CPU가 가장 좋아하는 ‘규격’에 맞춰 정렬함으로써 <strong>성능을 최적화</strong>하고 <strong>오류를 방지</strong>하기 위함</li>
    </ul>

    <p>→ <code class="language-plaintext highlighter-rouge">mm_malloc</code>에서 <code class="language-plaintext highlighter-rouge">asize</code> 계산할 때 반드시 반영</p>

    <p>예:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  adjustedsize=alignment맞춘실제블록크기
</code></pre></div>    </div>

    <p>이 계산 틀리면 전체가 무너져.</p>
  </li>
  <li>
    <p>이미 할당된 블록은 함부로 옮기거나 수정하면 안 됨</p>

    <p>## 5. 할당된 블록 수정 금지</p>

    <p>→ <code class="language-plaintext highlighter-rouge">coalesce</code>는 <strong>free 블록끼리만</strong> 가능</p>

    <p>→ 할당된 블록은 건드리면 안 됨</p>

    <p>즉:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ allocated ][ free ][ free ]
</code></pre></div>    </div>

    <p>이면 free끼리는 합칠 수 있지만</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ allocated ][ free ][ allocated ]
</code></pre></div>    </div>

    <p>에서 가운데 free를 양옆과 막 합칠 수는 없어.</p>
  </li>
</ul>

<h4 id="목표">목표</h4>

<ul>
  <li>
    <p>처리량(throughput)높이기 vs 메모리 이용도 높이기</p>

    <p>## 6. throughput vs utilization</p>

    <p>이건 네 설계 선택과 직결돼.</p>

    <p>### implicit free list</p>

    <ul>
      <li>구현 쉬움</li>
      <li>탐색 느릴 수 있음</li>
    </ul>

    <p>### explicit free list</p>

    <ul>
      <li>탐색 빨라질 수 있음</li>
      <li>구현 복잡도 증가</li>
    </ul>

    <p>### segregated free list</p>

    <ul>
      <li>더 빠를 수 있음</li>
      <li>설계/디버깅 더 어려움</li>
    </ul>

    <p>그래서 학습 우선순위를</p>

    <p><strong>implicit → heap checker → realloc → explicit/segregated 비교</strong></p>

    <p>로 잡는 게 맞아.</p>
  </li>
</ul>

<hr />

<h3 id="단편화">단편화</h3>

<blockquote>
  <p>메모리가 충분히 남아 있음에도 불구하고, 그 공간이 <strong>조각조각 나 있거나 규격에 맞지 않아</strong> 실제로 할당할 수 없는 ‘메모리 낭비’ 현상을 말합니다. Malloc Lab의 목표 중 하나인 <strong>이용도(Utilization) 높이기</strong>는 바로 이 단편화를 최소화하는 싸움입니다.</p>

  <ul>
    <li>내부단편화
      <ul>
        <li>정렬(alignment)에서 블록의 최소크기, 20바이트를 할당하는 경우 8의 배수를 맞추기위해 4바이트의 크기인 1블럭을 추가하여 정렬하는 경우</li>
      </ul>
    </li>
    <li>외부단편화
      <ul>
        <li>외부 단편화는 “free 공간 총합은 충분한데, 조각조각 흩어져 있어서 큰 요청을 못 주는 현상”</li>
      </ul>
    </li>
  </ul>
</blockquote>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    ### 아주 쉬운 비유
    
    주차장 비유로 생각하면 편해.
    
    ```
    [ 차 ][ 빈칸 ][ 차 ][ 빈칸 ][ 차 ][ 빈칸 ]
    ```
    
    빈칸이 총 3칸이 있어도,
    
    그게 서로 떨어져 있으면 **큰 차 1대**는 못 세울 수 있어.
    
    즉:
    
    - 빈 공간은 충분함
    - 하지만 붙어 있지 않음
    - 그래서 큰 요청을 못 받음
    
    →외부 단편화를 줄이기 위한 방법 `coalesce`
    
    예를 들어:
    
    ```
    [ alloc ][ free 20 ][ free 28 ][ alloc ]
    ```
    
    ```
    [ alloc ][ free 48 ][ alloc ]
    ```
    
    - 이렇게 **인접한 free 블록 둘**이 있으면 합쳐셔 외부단편화를 줄임
    - 이러면 큰 요청 (malloc(큰크기 요청))도 처리하기 쉬워짐
</code></pre></div></div>

<hr />

<h3 id="구현이슈">구현이슈</h3>

<p>실용적인 할당기는 아래 4가지를 꼭 고민해야 함</p>

<ol>
  <li>가용 블록 구성</li>
  <li>배치</li>
  <li>분할</li>
  <li>연결</li>
</ol>

<ul>
  <li>
    <p><strong>초보 할당기 예시</strong></p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  힙의 맨 앞에서 시작하는 포인터 p 하나만 있음
  malloc(size) 오면:
    현재 p 위치를 주고
    p를 size만큼 뒤로 민다
    
  free(ptr) 오면:
    아무것도 안 한다
</code></pre></div>    </div>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  처음:
  [................................]
   ^ p
    
  malloc(8)
  [########........................]
           ^ p
    
  malloc(16)
  [########################........]
                           ^ p
    
  free(...) 해도
  그 공간을 다시 안 씀
</code></pre></div>    </div>

    <ul>
      <li>할당은 엄청 쉬움</li>
      <li>찾을 필요도 없음</li>
      <li>그냥 계속 뒤로만 감</li>
      <li>처리량 은 좋을수 있지만 free를 하지않아 힙이 계속 커져 메모리 낭비가 심함</li>
    </ul>
  </li>
  <li>
    <p>가용 블록 구성</p>

    <p>어떻게 가용할 수 있는 블록을 추적할건지</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  ## 단순한 방식
    
  힙 전체를 처음부터 끝까지 보면서
  alloc/free 표시를 확인
</code></pre></div>    </div>

    <p>묵시적 할당</p>

    <p>8, 16의 배수는 마지막 3비트가 000으로 끝남 그걸이용하여</p>

    <p>마지막 비트의 0이면 가용(사용가능) 1이면 할당(할당됨) 을 표시함</p>

    <p>? 100001 , 100000 은 전혀 다른 주소아닌가 이렇게 표시하면 다른 배열에 접근한다는뜻아닌가</p>
  </li>
  <li>
    <p>배치</p>

    <p>새롭게 할당된 블록을 배치하기 위한 가용 블록을 어떻게 선택하는가?</p>

    <ul>
      <li>빈 블록이 여러 개 있을 때</li>
      <li>그중 어디에 넣을지</li>
    </ul>

    <p>ex)</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ free 20 ][ alloc ][ free 40 ][ alloc ][ free 12 ]
</code></pre></div>    </div>

    <ul>
      <li><strong>First Fit</strong>: 힙의 시작점부터 탐색하여 크기가 맞는 <strong>첫 번째</strong> 가용 블록을 선택합니다.
        <ul>
          <li>처리량좋음</li>
          <li>단편화가 많이 생겨 나중에 탐색 시간이 길어질 수 있음</li>
        </ul>
      </li>
      <li><strong>Next Fit</strong>: First Fit과 비슷하지만, 탐색을 <strong>마지막으로 할당했던 지점</strong>부터 시작합니다.
        <ul>
          <li>메모리 이용도가 제일 안좋음</li>
        </ul>
      </li>
      <li><strong>Best Fit</strong>: 모든 가용 블록을 검사하여 요청 크기와 <strong>가장 차이가 적은(딱 맞는)</strong> 블록을 선택합니다.
        <ul>
          <li>메모리 이용도 좋음</li>
          <li>처리량느림</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<hr />

<h3 id="묵시적-가용-리스트-구현">묵시적 가용 리스트 구현</h3>

<ul>
  <li>
    <p><strong>prologue / epilogue</strong>→ 힙의 앞뒤 경계 처리를 쉽게 해주는 가짜 블록</p>

    <p>#### prologue</p>

    <ul>
      <li>아주 작은 <strong>가짜 할당 블록</strong></li>
      <li>힙 맨 앞에 둠</li>
      <li>“이전 블록 없음” 문제를 없애 줌</li>
    </ul>

    <p>#### epilogue</p>

    <ul>
      <li>힙 맨 끝에 있는 <strong>크기 0짜리 가짜 헤더</strong></li>
      <li>“다음 블록 없음” 문제를 없애 줌</li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ padding ][ prologue ][ ... 실제 블록들 ... ][ epilogue ]
</code></pre></div>    </div>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  힙 전체 모양
    
  [ pad ][ prologue hdr/ftr ][ free/alloc block ][ free/alloc block ] ... [ epilogue hdr ]
</code></pre></div>    </div>

    <p><code class="language-plaintext highlighter-rouge">coalesce</code> 입장에서는:</p>

    <ul>
      <li>맨 앞에 가도 prologue가 있으니 안전</li>
      <li>맨 끝에 가도 epilogue가 있으니 안전</li>
    </ul>

    <p><strong>예외 처리를 줄이기 위한 안전 장치</strong></p>
  </li>
  <li>
    <p><strong>매크로들</strong>→ header/footer/다음 블록/이전 블록을 계산하는 도구</p>

    <p>### <strong>블록의 정확한 메모리 모양</strong></p>

    <p><strong>implicit free list의 기본 블록</strong></p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ header | payload ... | footer ]
</code></pre></div>    </div>

    <p>들어가있는 정보</p>

    <ul>
      <li>이 블록의 크기</li>
      <li>이 블록이 할당 상태인지 free 상태인지</li>
    </ul>

    <p>### payload는 뭐냐?</p>

    <ul>
      <li>할당된 블록이면 사용자가 쓰는 영역</li>
      <li>free 블록이면 일단 비어 있는 영역</li>
    </ul>
  </li>
  <li>
    <p><strong>coalesce 4가지 경우</strong>→ free된 블록을 주변 free 블록과 어떻게 합칠지</p>

    <p>## 4. coalesce의 4가지 경우</p>

    <p><code class="language-plaintext highlighter-rouge">mm_free(bp)</code>를 하면</p>

    <p>현재 블록을 free로 바꾸고 끝이 아니야.</p>

    <p>왼쪽/오른쪽 이웃도 free인지 보고,</p>

    <p>가능하면 합쳐야 해.</p>

    <p>현재 free된 블록을 <code class="language-plaintext highlighter-rouge">C</code>라고 하자.</p>

    <hr />

    <p>### 경우 1: 이전 alloc, 다음 alloc</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ alloc ][ C free ][ alloc ]
</code></pre></div>    </div>

    <p>양옆이 다 사용 중이면</p>

    <p>그냥 C만 free 상태로 둠</p>

    <hr />

    <p>### 경우 2: 이전 alloc, 다음 free</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ alloc ][ C free ][ next free ]
</code></pre></div>    </div>

    <p>C와 next를 합침</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ alloc ][      bigger free      ]
</code></pre></div>    </div>

    <hr />

    <p>### 경우 3: 이전 free, 다음 alloc</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ prev free ][ C free ][ alloc ]
</code></pre></div>    </div>

    <p>prev와 C를 합침</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [      bigger free      ][ alloc ]
</code></pre></div>    </div>

    <hr />

    <p>### 경우 4: 이전 free, 다음 free</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ prev free ][ C free ][ next free ]
</code></pre></div>    </div>

    <p>셋 다 합침</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [           one big free block           ]
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>place / split</strong>→ 큰 free 블록을 찾았을 때 통째로 줄지, 나눌지</p>

    <p>## 5. place와 split</p>

    <p><code class="language-plaintext highlighter-rouge">find_fit</code>으로 적당한 free 블록을 찾았다고 해보자.</p>

    <p>예:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  free 블록 크기 = 40
  요청 크기 = 16
</code></pre></div>    </div>

    <p>그럼 두 가지 선택이 있어.</p>

    <hr />

    <p>### 통째로 주기</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ alloc 40 ]
</code></pre></div>    </div>

    <p>쉬운데 낭비가 큼</p>

    <hr />

    <p>### 나눠서 주기 = split</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ alloc 16 ][ free 24 ]
</code></pre></div>    </div>

    <p>이게 더 좋음</p>

    <hr />

    <p>### 그런데 항상 나누면 되나?</p>

    <p>아니야.</p>

    <p>남는 조각이 너무 작으면</p>

    <p>그 조각은 블록으로 쓸 수 없어.</p>

    <p>예:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  free 24에 요청 16 넣고 남는 게 8
  근데 최소 블록 크기가 16이면
  남은 8은 쓸모 없는 조각
</code></pre></div>    </div>

    <p>그러면 그냥 통째로 줘야 해.</p>

    <p>즉 <code class="language-plaintext highlighter-rouge">place</code>에서는 보통 이런 판단을 함:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  남는 크기 &gt;= 최소 블록 크기
  -&gt; split
    
  남는 크기 &lt; 최소 블록 크기
  -&gt; 통째로 할당
</code></pre></div>    </div>

    <hr />

    <p>### 왜 중요한지</p>

    <p>이걸 잘해야:</p>

    <ul>
      <li>내부 단편화 줄이고</li>
      <li>이용도 좋아지고</li>
      <li>쓸데없는 작은 조각 안 생김</li>
    </ul>
  </li>
  <li>
    <p><strong>extend_heap</strong>→ 맞는 free 블록이 없을 때 힙을 늘리는 함수</p>

    <p>## 6. extend_heap</p>

    <p>적당한 free 블록이 없으면</p>

    <p>힙을 더 늘려야 해.</p>

    <p>그때 쓰는 게 <code class="language-plaintext highlighter-rouge">extend_heap</code>이야.</p>

    <p>흐름은 보통 이래:</p>

    <ol>
      <li><code class="language-plaintext highlighter-rouge">mem_sbrk(size)</code>로 힙 늘림</li>
      <li>새로 받은 공간을 free 블록처럼 초기화</li>
      <li>끝에 새 epilogue 헤더 설치</li>
      <li>직전 블록이 free라면 <code class="language-plaintext highlighter-rouge">coalesce</code></li>
    </ol>

    <hr />

    <p>### 그림으로 보면</p>

    <p>### 늘리기 전</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ ... 마지막 실제 블록 ... ][ epilogue ]
</code></pre></div>    </div>

    <p>### 힙 확장 후</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ ... 마지막 실제 블록 ... ][ 새 free 블록 ][ epilogue ]
</code></pre></div>    </div>

    <p>즉 epilogue가 원래 맨 끝 표시였는데,</p>

    <p>힙을 늘리면 그 자리가 실제 free 블록의 일부가 되고</p>

    <p>맨 끝에 새 epilogue를 다시 놓는 거야.</p>

    <hr />

    <p>### 왜 바로 coalesce하냐?</p>

    <p>만약 원래 마지막 블록도 free였다면</p>

    <p>새로 늘린 free 블록과 붙어 있으니까 합칠 수 있어.</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ old free ][ new free ]
  -&gt; [ one big free ]
</code></pre></div>    </div>

    <p>그래서 <code class="language-plaintext highlighter-rouge">extend_heap</code>은 보통 마지막에 <code class="language-plaintext highlighter-rouge">coalesce</code>까지 같이 해.</p>
  </li>
</ul>

<p>이 5개를 <code class="language-plaintext highlighter-rouge">mm.c</code> 함수 흐름으로 연결하면:</p>

<h3 id="mm_init"><code class="language-plaintext highlighter-rouge">mm_init</code></h3>

<ul>
  <li>prologue 만들기</li>
  <li>epilogue 만들기</li>
  <li>초기 힙 준비</li>
  <li>처음 <code class="language-plaintext highlighter-rouge">extend_heap</code> 호출</li>
</ul>

<h3 id="extend_heap"><code class="language-plaintext highlighter-rouge">extend_heap</code></h3>

<ul>
  <li>힙 늘리기</li>
  <li>새 free 블록 만들기</li>
  <li>epilogue 갱신</li>
  <li>coalesce</li>
</ul>

<h3 id="mm_malloc"><code class="language-plaintext highlighter-rouge">mm_malloc</code></h3>

<ul>
  <li>요청 크기 정렬해서 <code class="language-plaintext highlighter-rouge">asize</code> 계산</li>
  <li><code class="language-plaintext highlighter-rouge">find_fit</code>으로 free 블록 찾기</li>
  <li>있으면 <code class="language-plaintext highlighter-rouge">place</code></li>
  <li>없으면 <code class="language-plaintext highlighter-rouge">extend_heap</code> 후 <code class="language-plaintext highlighter-rouge">place</code></li>
</ul>

<h3 id="mm_free"><code class="language-plaintext highlighter-rouge">mm_free</code></h3>

<ul>
  <li>header/footer를 free로 바꾸기</li>
  <li><code class="language-plaintext highlighter-rouge">coalesce</code></li>
</ul>

<hr />

<h2 id="구현">구현</h2>

<ul>
  <li>
    <p><strong>size_t 타입을 사용하는 이유</strong></p>

    <p><strong>“이 값은 일반 숫자가 아니라 메모리 크기다”라는 뜻을 코드에 분명하게 드러내기 위해</strong></p>

    <ul>
      <li><code class="language-plaintext highlighter-rouge">int</code> : 일반적인 정수 (수학적 / 계산) 4바이트</li>
      <li><strong><code class="language-plaintext highlighter-rouge">unsigned int</code></strong>: 음수를 포함하지 않는 정수 대부분의 시스템에서 여전히 4바이트(32비트)</li>
      <li><strong><code class="language-plaintext highlighter-rouge">size_t</code></strong>:  해당 시스템의 주소 체계에 맞춰 4바이트(32), 8바이트(64비트)로 작동
        <ul>
          <li>컴파일 시점(Compile-time)에 시스템 환경에 따라 4바잍, 8바이트 결정</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<h3 id="매크로-작성">매크로 작성</h3>

<ul>
  <li>
    <p>매크로 작성</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    
  <span class="cp">#define WSIZE 4   // 헤더/푸터 1칸의 크기(4바이트)
</span>  <span class="cp">#define DSIZE 8   // 워드 2칸 크기(8바이트), 정렬 기준으로도 자주 사용
</span>  <span class="cp">#define CHUNKSIZE (1 &lt;&lt; 12) // 힙을 늘릴때 기본으로 요청하는 사이즈 2 의 12승-&gt;4096
</span>    
  <span class="cp">#define MAX(x, y) ((x) &gt; (y) ? (x) : (y)) 
</span>  <span class="c1">// 둘중 더 큰 값 반환, 사용자가 요청한 크기/최소한 확보해야하는 기본 크기 중 큰값 반환</span>
  <span class="cp">#define PACK(size, alloc) ((size) | (alloc)) 
</span>  <span class="c1">// 블록크기 size와 할당 여부를 하나의 값으로 합쳐, header/footer에 저장할 값을 만든다.</span>
    
  <span class="cp">#define GET(p) (*(unsigned int *)(p))
</span>  <span class="c1">// 주소 p가 가리키는 곳에 있는 4바이트 값(unsigned int 양수값)을 읽어온다.</span>
  <span class="cp">#define PUT(p, val) (*(unsigned int *)(p) = (val))
</span>  <span class="c1">// 주소 p가 가리키는 곳에 val 값을 4바이트 정수로 저장 </span>
    
  <span class="cp">#define GET_SIZE(p) (GET(p) &amp; ~0x7)
</span>  <span class="c1">// header/footer 값에서 크기 부분만 꺼내기</span>
  <span class="cp">#define GET_ALLOC(p) (GET(p) &amp; 0x1)
</span>  <span class="c1">//이 블록이 사용 중인지(1), 빈 블록인지(0) 확인</span>
    
  <span class="cp">#define HDRP(bp) ((char *)(bp) - WSIZE)
</span>  <span class="c1">// payload 포인터 bp를 가지고 header 주소를 찾아라</span>
  <span class="cp">#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)
</span>  <span class="c1">// bp가 가리키는 블록의 footer 주소</span>
  <span class="cp">#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE)))
</span>  <span class="c1">// bp위치 + (전체크기 -4)</span>
  <span class="c1">// NEXT_BLKP(bp)는 현재 블록 크기만큼 앞으로 이동해서 다음 블록으로 감</span>
  <span class="c1">// 1. bp는 payload라서 bp-WSIZE로 현재 header를 찾고,</span>
  <span class="c1">// 2. 거기 저장된 block size만큼 더해 다음 payload로 이동</span>
    
  <span class="cp">#define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE)))
</span>  <span class="c1">// bp-DSIZE 위치에서 이전 block footer의 size를 읽고,</span>
  <span class="c1">// 그 크기만큼 빼서 이전 payload로 이동</span>
  <span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">heap_listp</span><span class="p">;</span>
  <span class="c1">// 힙 리스트 시작점을 가리키는 전역 포인터</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="mm_init-1">mm_init</h3>

<ul>
  <li>mm_init
    <ul>
      <li>
        <p>전체 코드</p>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kt">int</span> <span class="nf">mm_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
  <span class="p">{</span>
      <span class="c1">// if (heap_listp = mem_sbrk(4 * WSIZE) == (void *)-1) {</span>
      <span class="c1">//     return -1;</span>
      <span class="c1">// }</span>
      <span class="k">if</span> <span class="p">((</span><span class="n">heap_listp</span> <span class="o">=</span> <span class="n">mem_sbrk</span><span class="p">(</span><span class="mi">4</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">))</span> <span class="o">==</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
      <span class="p">}</span>
        
      <span class="n">PUT</span><span class="p">(</span><span class="n">heap_listp</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// 패딩넣어줌 생성 </span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">heap_listp</span> <span class="o">+</span> <span class="p">(</span><span class="mi">1</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">DSIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span> <span class="c1">// 프롤로그 헤더 넣어줌</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">heap_listp</span> <span class="o">+</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">DSIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span> <span class="c1">// 프롤로그 푸터 넣어줌</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">heap_listp</span> <span class="o">+</span> <span class="p">(</span><span class="mi">3</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">));</span> <span class="c1">// 에필로그 헤더 넣어줌</span>
      <span class="n">heap_listp</span> <span class="o">+=</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">WSIZE</span><span class="p">);</span> <span class="c1">// 페이로드 자리 옮겨줌 프롤로그 푸터 자리로 </span>
            
      <span class="k">if</span> <span class="p">(</span><span class="n">extend_heap</span><span class="p">(</span><span class="n">CHUNKSIZE</span> <span class="o">/</span> <span class="n">WSIZE</span><span class="p">)</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 청크 사이즈 4096로 늘리는데 null이면 리턴함 </span>
          <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> 
      <span class="p">}</span>
        
      <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
        
  <span class="p">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>힙 공간에 초기 세팅을 만드는 함수</p>
      </li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ padding | prologue header | prologue footer | epilogue header ]
</code></pre></div>    </div>

    <p><strong>0단계: <code class="language-plaintext highlighter-rouge">mem_sbrk(4 * WSIZE)</code></strong></p>

    <p><code class="language-plaintext highlighter-rouge">WSIZE = 4</code>라면 총 <code class="language-plaintext highlighter-rouge">16바이트</code>, 즉 <strong>4칸</strong>을 확보</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  처음 확보한 4워드 공간
    
  주소 낮음 -&gt; 높음
    
  [ 0칸 ][ 1칸 ][ 2칸 ][ 3칸 ]
</code></pre></div>    </div>

    <ul>
      <li>아직은 그냥 빈 공간</li>
    </ul>

    <p>1단계: <code class="language-plaintext highlighter-rouge">PUT(heap_listp, 0);</code></p>

    <p>첫 칸에 0을 씀. 이건 <strong>padding</strong>.</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ padding ][      ?      ][      ?      ][      ?      ]
</code></pre></div>    </div>

    <ul>
      <li>정렬 맞추기 쉽게 하려고 두는 <strong>빈 안전칸</strong></li>
    </ul>

    <p><strong>2단계: <code class="language-plaintext highlighter-rouge">PUT(heap_listp + (1 * WSIZE), PACK(DSIZE, 1));</code></strong></p>

    <ul>
      <li>두 번째 칸에 <strong>prologue header</strong>를 씀
        <ul>
          <li>크기 = <code class="language-plaintext highlighter-rouge">DSIZE = 8</code></li>
          <li>alloc = <code class="language-plaintext highlighter-rouge">1</code>
  즉, <strong>크기 8짜리 할당된 블록</strong>이라는 뜻</li>
        </ul>
      </li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ padding ][ prologue header: 8/1 ][      ?      ][      ?      ]
</code></pre></div>    </div>

    <p><strong>3단계: <code class="language-plaintext highlighter-rouge">PUT(heap_listp + (2 * WSIZE), PACK(DSIZE, 1));</code></strong></p>

    <p>세 번째 칸에 <strong>prologue footer</strong>를 씀</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ padding ][ prologue hdr: 8/1 ][ prologue ftr: 8/1 ][      ?      ]
</code></pre></div>    </div>

    <ul>
      <li>왜 alloc로 두냐?</li>
      <li>coalesce할 때 맨 앞 경계를 처리하기 쉽게 하려고</li>
    </ul>

    <p>4단계: <code class="language-plaintext highlighter-rouge">PUT(heap_listp + (3 * WSIZE), PACK(0, 1));</code></p>

    <ul>
      <li>네 번째 칸에 <strong>epilogue header</strong>를 씀</li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ padding ][ prologue hdr: 8/1 ][ prologue ftr: 8/1 ][ epilogue hdr: 0/1 ]
</code></pre></div>    </div>

    <p>여기서 epilogue는:</p>

    <ul>
      <li>크기 = 0</li>
      <li>alloc = 1</li>
      <li>즉 <strong>힙의 끝 표시용 가짜 헤더</strong></li>
    </ul>

    <p>5단계: <code class="language-plaintext highlighter-rouge">heap_listp += (2 * WSIZE);</code></p>

    <p>현재 <code class="language-plaintext highlighter-rouge">heap_listp</code>는 원래 맨 처음, 즉 padding 위치를 가리키고 있었음.</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  처음 heap_listp
    |
    v
  [ padding ][ prologue hdr ][ prologue ftr ][ epilogue hdr ]
</code></pre></div>    </div>

    <p>그런데 <code class="language-plaintext highlighter-rouge">+ 2 * WSIZE</code>를 하면 2칸 앞으로 이동하니까:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  이동 후 heap_listp
  						                        |
  						                        v
  [ padding ][ prologue hdr ][ prologue ftr ][ epilogue hdr ]
</code></pre></div>    </div>

    <p>즉 <code class="language-plaintext highlighter-rouge">heap_listp</code>가 <strong>prologue의 “payload 자리처럼 취급되는 위치”</strong> 를 가리키게 됨</p>

    <p>이걸 그림으로 더 정확히 말하면:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  prologue 블록을 일반 블록처럼 생각하면
    
  [ header ][ footer ]
            ^
        heap_listp
</code></pre></div>    </div>

    <ul>
      <li>프로logue는 실제 payload가 없지만,</li>
      <li>코드에서 블록 포인터(<code class="language-plaintext highlighter-rouge">bp</code>)를 다루는 규칙과 맞추려고 이렇게 잡음</li>
      <li>이게 중요한 이유는 나중에 <code class="language-plaintext highlighter-rouge">HDRP(heap_listp)</code>, <code class="language-plaintext highlighter-rouge">NEXT_BLKP(heap_listp)</code> 같은 매크로가 일관되게 동작되기 위해</li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  초기 힙 뼈대
    
  주소 낮음 -------------------------------------------------&gt; 높음
    
  [ padding: 0 ]
  [ prologue header: PACK(8,1) ]
  [ prologue footer: PACK(8,1) ]   &lt;- heap_listp가 이 근처(프로로그 payload 자리 개념)
  [ epilogue header: PACK(0,1) ]
</code></pre></div>    </div>

    <p>6단계: <code class="language-plaintext highlighter-rouge">extend_heap(CHUNKSIZE / WSIZE)</code></p>

    <ul>
      <li>이제 진짜 쓸 free block을 만들러 감</li>
      <li><code class="language-plaintext highlighter-rouge">extend_heap</code>이 힙을 늘리면 기존 epilogue 자리가 밀리고,</li>
      <li>그 자리에 <strong>새 free block</strong>이 생기고,</li>
      <li>맨 끝에 <strong>새 epilogue</strong>가 다시 놓여.</li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  extend_heap 후
    
  [ pad ][ prologue ][ 첫 free block ................. ][ epilogue ]
</code></pre></div>    </div>

    <p>조금 더 자세히 보면:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ padding ]
  [ prologue hdr: 8/1 ]
  [ prologue ftr: 8/1 ]
  [ free hdr: big/0 ]
  [ free payload ................. ] // 큰 free 블록 하나”를 추가
  [ free ftr: big/0 ]
  [ epilogue hdr: 0/1 ]
</code></pre></div>    </div>

    <ul>
      <li>큰 free 블록 하나”를 추가</li>
      <li>이제부터 allocator는 이 첫 free block을 가지고</li>
      <li><code class="language-plaintext highlighter-rouge">mm_malloc</code> 요청을 처리할 수 있게 됌 → free블록에서 필요한만큼 뗴어 할당블록을 만듬→남은 부분이 크면 split해서 나머지를 free 블록으로 남김</li>
    </ul>
  </li>
</ul>

<h3 id="extend_heap-1">extend_heap</h3>

<ul>
  <li>extend_heap
    <ul>
      <li><code class="language-plaintext highlighter-rouge">extend_heap</code>는 “힙을 더 늘리고, 그 새 공간을 큰 free 블록 1개로 등록한 뒤, 맨 끝 epilogue를 다시 세팅하고, 필요하면 앞 free 블록과 합치는 함수</li>
    </ul>

    <p>[1] 한줄 요약</p>

    <p><strong>맞아, <code class="language-plaintext highlighter-rouge">mem_sbrk(size)</code>는 old epilogue의 “다음 자리”부터 새 공간을 줘. 그런데 <code class="language-plaintext highlighter-rouge">bp</code>는 payload 기준 포인터라서, <code class="language-plaintext highlighter-rouge">HDRP(bp)</code>를 하면 한 칸 왼쪽인 old epilogue 자리를 새 free header로 덮어쓰게 되는 거야.</strong></p>

    <p>[2] 핵심 개념 정리</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  mem_sbrk(size)가 주는 시작점 = old epilogue "다음"
  HDRP(bp)                    = bp의 한 칸 왼쪽
  그래서 HDRP(bp)가 old epilogue 위치를 가리킴
</code></pre></div>    </div>

    <p>mm_init (1~5단계) → extend_heap</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  초기 상태
    
  [ padding | P-HDR | P-FTR | E-HDR ] 
                             ^
                        old epilogue
</code></pre></div>    </div>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  이때 mem_brk는 epilogue "뒤"에 있음
    
  [ padding | P-HDR | P-FTR | E-HDR ] [ mem_brk ]
</code></pre></div>    </div>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  mem_sbrk(size) 직후
    
  [ padding | P-HDR | P-FTR | E-HDR |      새 공간      ]
                                     ^
                                     bp
</code></pre></div>    </div>

    <ul>
      <li>bp는 old epiloge자리가 아니라</li>
      <li>old epilogue “다음 칸”을 가리킴</li>
      <li>그런데 bp는 “블록의 payload 포인터”처럼 쓰는 포인터라서</li>
      <li>HDRP(bp) = bp보다 한 칸 왼쪽</li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  HDRP(bp)를 찍어보면
    
  [ padding | P-HDR | P-FTR | E-HDR |      새 공간      ]
                             ^
                          HDRP(bp)
                                     ^
                                     bp
</code></pre></div>    </div>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  즉,
  HDRP(bp)가 old epilogue 자리를 가리키니까
    
  PUT(HDRP(bp), PACK(size, 0));
    
  를 하면 old epilogue가 새 free header로 바뀜
</code></pre></div>    </div>

    <ul>
      <li>즉 HDRP(bp)가 old epiologue 자리를 가리키니까</li>
      <li>PUT (HDRP(bp), PACK(size, 0));</li>
      <li>을 하면 old epilogue가 새 free header로 바뀜</li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  1) PUT(HDRP(bp), PACK(size, 0)) 후
    
  [ padding | P-HDR | P-FTR | FREE-HDR |      새 공간      ]
                                       ^
                                       bp
</code></pre></div>    </div>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  2) PUT(FTRP(bp), PACK(size, 0)) 후
    
  [ padding | P-HDR | P-FTR | FREE-HDR | free payload ... | FREE-FTR ]
                                       ^
                                       bp
</code></pre></div>    </div>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  3) PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)) 후
    
  [ padding | P-HDR | P-FTR | FREE-HDR | free payload ... | FREE-FTR | E-HDR ]
</code></pre></div>    </div>
  </li>
  <li>
    <p>coalesce</p>

    <p><strong>case 1</strong>: <code class="language-plaintext highlighter-rouge">이전 alloc / 다음 alloc</code></p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ alloc ][ current free ][ alloc ]
                 ^
                 bp
</code></pre></div>    </div>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">(</span><span class="n">prev_alloc</span><span class="o">&amp;&amp;</span><span class="n">next_alloc</span><span class="p">)</span>
  		<span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
</code></pre></div>    </div>

    <ul>
      <li>아무것도 안 함</li>
    </ul>

    <p>case 2: <code class="language-plaintext highlighter-rouge">이전 alloc / 다음 free</code></p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ alloc ][ current free ][ next free ]
                 ^
                 bp
</code></pre></div>    </div>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">size</span> <span class="o">+=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)));</span>
  <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
  <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
</code></pre></div>    </div>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  합치기 전
  [ current free: 16 ][ next free: 24 ]
    
  합치기 후
  [        free: 40        ]
  ^
  bp 유지
</code></pre></div>    </div>

    <p>case 3: <code class="language-plaintext highlighter-rouge">이전 free / 다음 alloc</code></p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  [ prev free ][ current free ][ alloc ]
                 ^
                 bp
</code></pre></div>    </div>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">size</span> <span class="o">+=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)));</span>
  <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
  <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
  <span class="n">bp</span> <span class="o">=</span> <span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
</code></pre></div>    </div>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="err">합치기</span> <span class="err">전</span>
  <span class="p">[</span> <span class="n">prev</span> <span class="n">free</span><span class="o">:</span> <span class="mi">24</span> <span class="p">][</span> <span class="n">current</span> <span class="n">free</span><span class="o">:</span> <span class="mi">16</span> <span class="p">]</span>
    
  <span class="err">합치기</span> <span class="err">후</span>
  <span class="p">[</span>        <span class="n">free</span><span class="o">:</span> <span class="mi">40</span>        <span class="p">]</span>
  <span class="o">^</span>
  <span class="n">bp</span> <span class="err">이동</span> <span class="p">(</span><span class="n">prev</span> <span class="err">쪽</span><span class="p">)</span>
</code></pre></div>    </div>

    <p>case 4: <code class="language-plaintext highlighter-rouge">이전 free / 다음 free</code></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="p">[</span> <span class="n">prev</span> <span class="n">free</span> <span class="p">][</span> <span class="n">current</span> <span class="n">free</span> <span class="p">][</span> <span class="n">next</span> <span class="n">free</span> <span class="p">]</span>
                 <span class="o">^</span>
                 <span class="n">bp</span>
</code></pre></div>    </div>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">size</span> <span class="o">+=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)))</span> 
        <span class="o">+</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)));</span>
    
  <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
  <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">)),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
  <span class="n">bp</span> <span class="o">=</span> <span class="n">PREV_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
</code></pre></div>    </div>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="err">합치기</span> <span class="err">전</span>
  <span class="p">[</span> <span class="n">prev</span><span class="o">:</span><span class="mi">24</span> <span class="p">][</span> <span class="n">current</span><span class="o">:</span><span class="mi">16</span> <span class="p">][</span> <span class="n">next</span><span class="o">:</span><span class="mi">32</span> <span class="p">]</span>
    
  <span class="err">합치기</span> <span class="err">후</span>
  <span class="p">[</span>           <span class="n">free</span><span class="o">:</span><span class="mi">72</span>            <span class="p">]</span>
  <span class="o">^</span>
  <span class="n">bp</span> <span class="err">이동</span> <span class="p">(</span><span class="n">prev</span> <span class="err">쪽</span><span class="p">)</span>
</code></pre></div>    </div>

    <aside>
  💡
    
  size = 합쳐진 전체 블록 크기
    
  header = 합쳐진 블록의 시작 위치
    
  footer = 합쳐진 블록의 끝 위치
    
  bp = 항상 "새 블록의 시작(payload)"으로 이동
    
  bp                     = 현재 블록 payload
  PREV_BLKP(bp)          = 이전 블록 payload
  NEXT_BLKP(bp)          = 다음 블록 payload
    
  HDRP(bp)               = header
  FTRP(bp)               = footer
    
  </aside>
  </li>
</ul>

<h3 id="mm_malloc-1">mm_malloc</h3>

<ul>
  <li>
    <p>mm_malloc</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  1. 사용자 요청 size 받음
  2. 실제 블록 크기 asize로 바꿈
  3. 힙 안 free block 찾음
  4. 있으면 거기에 배치
  5. 없으면 힙 늘리고 거기에 배치
  6. bp 반환
</code></pre></div>    </div>

    <p>0단계 : 변수 선언</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kt">void</span> <span class="o">*</span><span class="nf">mm_malloc</span><span class="p">(</span><span class="n">size_</span> <span class="n">size</span><span class="p">)</span> <span class="c1">// 사용자가 요청한 크기</span>
  <span class="p">{</span>
  <span class="kt">size_t</span> <span class="n">asize</span><span class="p">;</span> <span class="c1">// 실제로 필요한 블록크기</span>
  <span class="kt">size_t</span> <span class="n">extendsize</span><span class="p">;</span> <span class="c1">// 힙을 늘릴 때 얼마만큼 늘릴지, 힙 확장 크기 </span>
  <span class="kt">char</span><span class="o">*</span> <span class="n">bp</span><span class="p">;</span> <span class="o">/</span> <span class="err">찾거나</span> <span class="err">새로</span> <span class="err">만든</span> <span class="err">블록의</span> <span class="n">payload</span> <span class="err">시작</span> <span class="err">주소</span><span class="p">,</span> <span class="err">현재</span> <span class="err">사용할</span> <span class="err">블록</span> <span class="err">포인터</span> 
  <span class="p">...</span>
</code></pre></div>    </div>

    <p>1단계: <code class="language-plaintext highlighter-rouge">size == 0</code> 처리</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 만약 사이즈(요청한크기)가 0이면 NULL반환</span>
      <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p>2단계 : <code class="language-plaintext highlighter-rouge">asize</code> 계산</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">&lt;=</span> <span class="n">DSIZE</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// size(요청크기)가 8바이트보다 작으면 기본 최소 사이즈 반환 </span>
      <span class="n">asize</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DSIZE</span><span class="p">;</span> <span class="c1">// 실제 필요한 블록크기를 16 최소 크기로 설정</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="n">asize</span> <span class="o">=</span> <span class="n">DSIZE</span> <span class="o">*</span> <span class="p">((</span><span class="n">size</span> <span class="o">+</span> <span class="p">(</span><span class="n">DSIZE</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="n">DSIZE</span> <span class="o">-</span> <span class="mi">1</span><span class="p">))</span> <span class="o">/</span> <span class="n">DSIZE</span><span class="p">);</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <ul>
      <li>
        <p>2단계 : asize 계산 alignment 올림용 보정 식</p>

        <p>### 헤더와 푸터의 진짜 크기</p>

        <ul>
          <li><strong>Header</strong>: 4바이트 (WSIZE)</li>
          <li><strong>Footer</strong>: 4바이트 (WSIZE)</li>
          <li><strong>payload</strong> : 8바이트</li>
          <li><strong>합계 (Overhead)</strong>: <strong>8바이트 (DSIZE)</strong></li>
        </ul>

        <p><strong>왜 7(DSIZE - 1)을 더하나요?</strong></p>

        <ul>
          <li>이게 바로 이 수식의 핵심인 <strong>“올림(Rounding up)”</strong> 테크닉.</li>
          <li>7바이트짜리 푸터가 있는 게 아니라, 주소를 <strong>8의 배수</strong>로 딱 맞춰주기 위한 <strong>보정치</strong></li>
          <li>정수 나눗셈의 특징을 이용한 수학적 공식,</li>
          <li>어떤 수 X K의 배수로 올림하고 싶을 때 쓰는 공식은 다음과 같음</li>
        </ul>

\[\mathrm{RoundedValue} = ((X + (K - 1))/K) \ast K\]

        <p>여기서 우리 상황을 대입해 보면:</p>

        <ul>
          <li>X = size + DSIZE (사용자 요청 크기 + 헤더/푸터 8바이트)</li>
          <li>K = DSIZE (8바이트 정렬 기준)</li>
          <li>즉, 7(DSIZE-1) 은 푸터의 크기가 아니라, 너 혹시 8의 배수에서 조금이라도 넘어가면 다음 8의 배수로 점프해!”라고 밀어주는 힘</li>
        </ul>
      </li>
    </ul>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  payload size
  + overhead(header/footer)
  + alignment 올림용 보정
  ----------------------------------------------------------------------------
  전체 뜻:
  header/footer 포함한 뒤
  8바이트 배수로 올림한 실제 블록 크기
</code></pre></div>    </div>

    <ul>
      <li><code class="language-plaintext highlighter-rouge">/ DSIZE</code></li>
      <li>8바이트 단위로 몇 덩어리인지 계산</li>
      <li><code class="language-plaintext highlighter-rouge">* DSIZE</code></li>
      <li>다시 8바이트 배수 크기로 만듦</li>
      <li>
        <p>예시 size = 9, size = 20</p>

        <p>### 예시 1: size = 9</p>

        <p>가정: <code class="language-plaintext highlighter-rouge">DSIZE = 8</code></p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  asize = 8 * ((9 + 8 + 7) / 8)
        = 8 * (24 / 8)
        = 24
</code></pre></div>        </div>

        <p>즉 9바이트 요청이지만 실제 블록은 24바이트</p>

        <hr />

        <p>### 예시 2: size = 20</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  asize = 8 * ((20 + 8 + 7) / 8)
        = 8 * (35 / 8)
        = 8 * 4
        = 32
</code></pre></div>        </div>

        <p>즉 20바이트 요청 → 실제 블록 크기 32</p>

        <hr />

        <p>##</p>
      </li>
    </ul>

    <p>3단계: <code class="language-plaintext highlighter-rouge">find_fit(asize)</code></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// 현재 힙안에 있는 free bloock들중 NULL아닌, free가 있으면 place하고 return bp 해라 </span>
  <span class="k">if</span> <span class="p">((</span><span class="n">bp</span> <span class="o">=</span> <span class="n">find_fit</span><span class="p">(</span><span class="n">asize</span><span class="p">))</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> 
      <span class="n">place</span><span class="p">(</span><span class="n">bp</span><span class="p">,</span> <span class="n">asize</span><span class="p">);</span>
      <span class="k">return</span> <span class="n">bp</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p>왜 바로 <code class="language-plaintext highlighter-rouge">return bp</code> 하냐?</p>

    <ul>
      <li>이미 들어갈 자리를 찾았고,</li>
      <li>거기에 배치까지 끝났으니까</li>
      <li>사용자에게 그 블록 주소를 주면 됨</li>
    </ul>

    <p>4단계 : 못 찾았으면 힙 확장 크기 결정</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">extendsize</span> <span class="o">=</span> <span class="n">MAX</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="n">CHUNKSIZE</span><span class="p">);</span>
</code></pre></div>    </div>

    <ul>
      <li>extendsize = asize와 CHUNKSIZE 중 더 큰 값</li>
      <li>요청 블록이 작으면
  → 굳이 조금만 늘리지 말고 <code class="language-plaintext highlighter-rouge">CHUNKSIZE</code>만큼 크게 늘려서 future malloc 대비</li>
      <li>요청 블록이 엄청 크면
  → <code class="language-plaintext highlighter-rouge">CHUNKSIZE</code>로는 부족할 수 있으니 <code class="language-plaintext highlighter-rouge">asize</code>만큼은 늘려야 함</li>
    </ul>

    <p>5단계: <code class="language-plaintext highlighter-rouge">extend_heap</code></p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">((</span><span class="n">bp</span><span class="o">=</span><span class="n">extend_heap</span><span class="p">(</span><span class="n">extendsize</span><span class="o">/</span><span class="n">WSIZE</span><span class="p">))</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="o">-------------------------------------------------------------------------------</span>
  <span class="err">힙</span> <span class="err">확장</span> <span class="err">후</span> <span class="err">새</span> <span class="n">free</span> <span class="n">block</span> <span class="err">얻기</span>
  <span class="err">실패하면</span> <span class="nb">NULL</span> <span class="p">(</span><span class="err">힙을</span> <span class="err">더</span> <span class="err">늘릴</span> <span class="err">공간이</span> <span class="err">없는경우</span><span class="p">)</span> 
</code></pre></div>    </div>

    <ul>
      <li>기존 free block으로는 못 찾았으니까</li>
      <li>힙을 더 늘려서 새 free block을 만들자.</li>
      <li><code class="language-plaintext highlighter-rouge">extend_heap</code>는 words 단위로 받으니까</li>
      <li><code class="language-plaintext highlighter-rouge">extendsize / WSIZE</code>로 바꿔서 넘김</li>
    </ul>

    <p>6단계: 새 free block에 배치</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">place</span><span class="p">(</span><span class="n">bp</span><span class="p">,</span><span class="n">asize</span><span class="p">);</span>
  <span class="n">returnbp</span><span class="p">;</span>
</code></pre></div>    </div>

    <p>###</p>
  </li>
</ul>

<h3 id="place">place</h3>

<ul>
  <li>
    <p>place</p>

    <p>#### 0. 함수가 호출되는 시점</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  mm_malloc
  -&gt; find_fit(asize)   // 들어갈 free block 찾기
  -&gt; place(bp, asize)  // 실제 배치
</code></pre></div>    </div>

    <ul>
      <li><code class="language-plaintext highlighter-rouge">place</code>는 <strong>찾은 뒤에 실행되는 함수</strong></li>
      <li>찾는 건 <code class="language-plaintext highlighter-rouge">find_fit</code>, 실제로 넣는 건 <code class="language-plaintext highlighter-rouge">place</code>.</li>
    </ul>

    <p>#### 1. <code class="language-plaintext highlighter-rouge">csize</code> 에 의미</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kt">size_t</span> <span class="n">csize</span> <span class="o">=</span> <span class="n">GET_SIZE</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">));</span>
</code></pre></div>    </div>

    <ul>
      <li><code class="language-plaintext highlighter-rouge">bp</code>가 가리키는 free block의 <strong>전체 크기</strong></li>
      <li>ex) free block 이 40 바이트 → csize = 40</li>
    </ul>

    <p>#### 2. 핵심분기 : 남는 공간이 충분한가?</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">((</span><span class="n">csize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">DSIZE</span><span class="p">))</span> <span class="c1">//전체크기 - 요청크기 &gt;= 최소블럭크기</span>
</code></pre></div>    </div>

    <ul>
      <li><code class="language-plaintext highlighter-rouge">2 * DSIZE</code>는 보통 최소 블록 크기</li>
      <li>는 조각이 <strong>16바이트 이상</strong>이면 새 free block으로 남김</li>
    </ul>

    <p>#### 3. 분할하는 경우</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">((</span><span class="n">csize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">DSIZE</span><span class="p">))</span> <span class="p">{</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">asize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
      <span class="n">bp</span> <span class="o">=</span> <span class="n">NEXT_BLKP</span><span class="p">(</span><span class="n">bp</span><span class="p">);</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <ul>
      <li><strong>3-1. 앞부분을 alloc 블록으로 만든다</strong>
        <ul>
          <li>현재 블록의 앞부분 크기를  <code class="language-plaintext highlighter-rouge">asize</code>  로 정하고</li>
          <li>alloc bit를 1로 해서</li>
          <li>이제 이 블록은 할당됨 이라고 표시</li>
        </ul>

        <p>ex)</p>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="err">원래</span>
  <span class="p">[</span>            <span class="n">free</span> <span class="n">block</span> <span class="mi">40</span>            <span class="p">]</span>
        
  <span class="err">앞부분</span> <span class="n">alloc</span> <span class="err">처리</span> <span class="err">후</span>
  <span class="p">[</span> <span class="n">alloc</span> <span class="mi">16</span> <span class="p">][</span>        <span class="err">아직</span> <span class="err">남은</span> <span class="err">공간</span>        <span class="p">]</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p><strong>3-2. <code class="language-plaintext highlighter-rouge">bp = NEXT_BLKP(bp);</code></strong></p>

        <p><code class="language-plaintext highlighter-rouge">bp</code>를 방금 만든 alloc 블록 다음 블록으로 옮긴다</p>

        <ul>
          <li>즉 이제 <code class="language-plaintext highlighter-rouge">bp</code>는 <strong>남은 조각의 시작</strong>을 가리키게 됨</li>
        </ul>

        <p>ex)</p>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="p">[</span> <span class="n">alloc</span> <span class="mi">16</span> <span class="p">][</span> <span class="n">free</span> <span class="mi">24</span> <span class="p">]</span>
               <span class="o">^</span>
               <span class="n">bp</span> <span class="err">이동</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p><strong>3-3. 남은 조각을 새 free block으로 만든다</strong></p>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
  <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span> <span class="o">-</span> <span class="n">asize</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
</code></pre></div>        </div>

        <p>ex)</p>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="p">[</span> <span class="n">alloc</span> <span class="mi">16</span> <span class="p">][</span> <span class="n">free</span> <span class="mi">24</span> <span class="p">]</span>
</code></pre></div>        </div>
      </li>
    </ul>

    <p>#### 4. 분할하지 않는 경우</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">else</span> <span class="p">{</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">HDRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
      <span class="n">PUT</span><span class="p">(</span><span class="n">FTRP</span><span class="p">(</span><span class="n">bp</span><span class="p">),</span> <span class="n">PACK</span><span class="p">(</span><span class="n">csize</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <ul>
      <li>남는 공간이 너무 작으면 쪼개지 말고, 현재 free block 전체를 통째로 할당</li>
    </ul>

    <p>ex)</p>

    <ul>
      <li><code class="language-plaintext highlighter-rouge">csize = 24</code></li>
      <li><code class="language-plaintext highlighter-rouge">asize = 16</code></li>
      <li>남는 크기 = 8</li>
      <li>그런데 8은 최소 블록 크기 16보다 작음</li>
      <li>그냥 자르지 않고 할당</li>
    </ul>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="err">처음</span>
  <span class="p">[</span>      <span class="n">free</span> <span class="mi">24</span>      <span class="p">]</span>
    
  <span class="err">남는</span> <span class="err">크기</span> <span class="o">=</span> <span class="mi">8</span> <span class="o">&lt;</span> <span class="mi">16</span>
    
  <span class="n">place</span> <span class="err">후</span>
  <span class="p">[</span>      <span class="n">alloc</span> <span class="mi">24</span>      <span class="p">]</span>
</code></pre></div>    </div>
  </li>
</ul>]]></content><author><name></name></author><category term="C" /><category term="Memory" /><category term="Allocator" /><category term="malloc" /><category term="free" /><summary type="html"><![CDATA[동적 메모리 할당기의 기본 개념과 implicit free list 기반 allocator의 흐름을 정리한다.]]></summary></entry><entry><title type="html">C 언어 변수, 포인터, 이중 포인터, 포인터 배열 정리</title><link href="https://juhoseok.github.io/jekyll-theme-velog/c-variables-pointers-and-pointer-arrays/" rel="alternate" type="text/html" title="C 언어 변수, 포인터, 이중 포인터, 포인터 배열 정리" /><published>2026-04-11T20:00:00+09:00</published><updated>2026-04-11T20:00:00+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/c-variables-pointers-and-pointer-arrays</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/c-variables-pointers-and-pointer-arrays/"><![CDATA[<h2 id="변수의-의미">변수의 의미</h2>

<p>C 언어에서 변수는 단순한 이름표가 아니라, 값을 저장하기 위한 메모리 공간 자체로 볼 수 있다.</p>

<ul>
  <li>변수를 선언하면 메모리 공간이 생성된다.</li>
  <li>그 공간에 정수, 문자, 구조체 같은 실제 값이 저장된다.</li>
</ul>

<p>예를 들어:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</code></pre></div></div>

<p>위 코드는 <code class="language-plaintext highlighter-rouge">a</code>라는 이름의 정수형 메모리 공간을 만들고, 그 안에 <code class="language-plaintext highlighter-rouge">5</code>를 저장한다.</p>

<h2 id="포인터">포인터</h2>

<p>포인터는 주소를 저장하기 위한 변수다.</p>

<h3 id="-연산자"><code class="language-plaintext highlighter-rouge">&amp;</code> 연산자</h3>

<p><code class="language-plaintext highlighter-rouge">&amp;</code>는 어떤 변수의 주소를 구하는 연산자다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"%p"</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">a</span><span class="p">);</span>
</code></pre></div></div>

<p>이 코드는 변수 <code class="language-plaintext highlighter-rouge">a</code>가 저장된 메모리 주소를 출력한다.</p>

<h3 id="의-두-가지-의미"><code class="language-plaintext highlighter-rouge">*</code>의 두 가지 의미</h3>

<p><code class="language-plaintext highlighter-rouge">*</code>는 문맥에 따라 의미가 달라진다.</p>

<ol>
  <li>선언에서의 <code class="language-plaintext highlighter-rouge">*</code>
포인터 변수를 선언할 때 사용한다.</li>
</ol>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">;</span>
</code></pre></div></div>

<p>위 코드는 <code class="language-plaintext highlighter-rouge">int</code>를 가리키는 포인터 변수 <code class="language-plaintext highlighter-rouge">p</code>를 선언하고, <code class="language-plaintext highlighter-rouge">a</code>의 주소를 저장한다.</p>

<ol>
  <li>사용에서의 <code class="language-plaintext highlighter-rouge">*</code>
역참조를 할 때 사용한다.</li>
</ol>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">printf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span> <span class="o">*</span><span class="n">p</span><span class="p">);</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">p</code> 안에 들어 있는 주소를 따라가서, 그 위치에 저장된 실제 값을 읽는다.</p>

<h2 id="역참조">역참조</h2>

<p>역참조는 주소를 담은 변수에서, 그 주소가 가리키는 실제 메모리 공간으로 다시 찾아가는 동작이다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="kt">int</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">;</span>

<span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="o">*</span><span class="n">p</span><span class="p">);</span>
</code></pre></div></div>

<p>결과:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>5
</code></pre></div></div>

<p>흐름은 이렇게 이해하면 된다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">p</code>에는 <code class="language-plaintext highlighter-rouge">a</code>의 주소가 저장되어 있다.</li>
  <li><code class="language-plaintext highlighter-rouge">*p</code>는 그 주소로 이동한다.</li>
  <li>그 주소에 저장된 실제 값 <code class="language-plaintext highlighter-rouge">5</code>를 읽는다.</li>
</ul>

<h2 id="이중-포인터">이중 포인터</h2>

<p>이중 포인터는 포인터 변수의 주소를 저장하기 위한 포인터다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="kt">int</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">;</span>
<span class="kt">int</span> <span class="o">**</span><span class="n">p2</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">p</span><span class="p">;</span>
</code></pre></div></div>

<p>각 변수의 의미는 다음과 같다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">a</code>는 정수 값을 저장하는 변수</li>
  <li><code class="language-plaintext highlighter-rouge">p</code>는 <code class="language-plaintext highlighter-rouge">a</code>의 주소를 저장하는 포인터</li>
  <li><code class="language-plaintext highlighter-rouge">p2</code>는 <code class="language-plaintext highlighter-rouge">p</code>의 주소를 저장하는 이중 포인터</li>
</ul>

<p>즉, 저장 관계를 보면 다음과 같다.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>a   &lt;- 실제 정수 값 저장
p   &lt;- a의 주소 저장
p2  &lt;- p의 주소 저장
</code></pre></div></div>

<h3 id="별의-개수와-저장-대상">별의 개수와 저장 대상</h3>

<p>저장하려는 대상보다 <code class="language-plaintext highlighter-rouge">*</code>가 하나 더 많아야 그 주소를 저장할 수 있다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="kt">int</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">;</span>
<span class="kt">int</span> <span class="o">**</span><span class="n">p2</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">p</span><span class="p">;</span>
<span class="kt">int</span> <span class="o">***</span><span class="n">p3</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">p2</span><span class="p">;</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">p</code>는 <code class="language-plaintext highlighter-rouge">a</code>를 가리킨다.</li>
  <li><code class="language-plaintext highlighter-rouge">p2</code>는 <code class="language-plaintext highlighter-rouge">p</code>를 가리킨다.</li>
  <li><code class="language-plaintext highlighter-rouge">p3</code>는 <code class="language-plaintext highlighter-rouge">p2</code>를 가리킨다.</li>
</ul>

<p>즉:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">*p</code>는 <code class="language-plaintext highlighter-rouge">a</code></li>
  <li><code class="language-plaintext highlighter-rouge">**p2</code>는 <code class="language-plaintext highlighter-rouge">a</code></li>
  <li><code class="language-plaintext highlighter-rouge">***p3</code>는 <code class="language-plaintext highlighter-rouge">a</code></li>
</ul>

<p>처럼 더 깊게 역참조할 수 있다.</p>

<h2 id="포인터-배열">포인터 배열</h2>

<p>포인터 배열은 포인터 변수를 여러 개 배열 형태로 관리하는 구조다.</p>

<p>예를 들어 다음 두 코드는 비슷하게 보일 수 있다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="o">*</span><span class="n">p1</span><span class="p">,</span> <span class="o">*</span><span class="n">p2</span><span class="p">,</span> <span class="o">*</span><span class="n">p3</span><span class="p">,</span> <span class="o">*</span><span class="n">p4</span><span class="p">,</span> <span class="o">*</span><span class="n">p5</span><span class="p">;</span>
<span class="kt">int</span> <span class="o">*</span><span class="n">p</span><span class="p">[</span><span class="mi">5</span><span class="p">];</span>
</code></pre></div></div>

<p>둘 다 <code class="language-plaintext highlighter-rouge">int</code>를 가리키는 포인터 5개를 만든다는 점에서는 비슷하지만, 자료구조는 다르다.</p>

<ul>
  <li>첫 번째는 서로 독립적인 포인터 변수 5개</li>
  <li>두 번째는 포인터를 원소로 가지는 배열 1개</li>
</ul>

<h3 id="일반-배열과-포인터-배열-비교">일반 배열과 포인터 배열 비교</h3>

<p>일반 정수 배열은 값을 직접 저장한다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">arr</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>

<span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</code></pre></div></div>

<p>반면 포인터 배열은 주소를 저장한다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>

<span class="kt">int</span> <span class="o">*</span><span class="n">arr</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="o">&amp;</span><span class="n">a</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">b</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">c</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">d</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">e</span><span class="p">};</span>

<span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="o">*</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</code></pre></div></div>

<p>여기서:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">arr[0]</code>은 <code class="language-plaintext highlighter-rouge">a</code>의 주소</li>
  <li><code class="language-plaintext highlighter-rouge">*arr[0]</code>은 그 주소에 저장된 실제 값 <code class="language-plaintext highlighter-rouge">1</code></li>
</ul>

<p>즉 포인터 배열의 값을 사용할 때는, 주소만 보고 싶다면 <code class="language-plaintext highlighter-rouge">arr[i]</code>, 실제 값을 읽고 싶다면 <code class="language-plaintext highlighter-rouge">*arr[i]</code>처럼 역참조해야 한다.</p>

<h2 id="포인터가-가리킨다는-의미">포인터가 가리킨다는 의미</h2>

<p>포인터가 어떤 대상을 가리킨다는 것은, 그 변수가 특정 메모리 주소를 저장하고 있고, 그 주소를 통해 실제 데이터에 접근할 수 있다는 뜻이다.</p>

<p>즉:</p>

<ul>
  <li>포인터는 주소를 저장한다.</li>
  <li>역참조는 그 주소를 따라가 실제 값에 접근한다.</li>
  <li>이중 포인터는 포인터의 주소를 저장한다.</li>
  <li>포인터 배열은 여러 주소를 배열 형태로 관리한다.</li>
</ul>

<h2 id="정리">정리</h2>

<ul>
  <li>변수는 값을 담는 메모리 공간이다.</li>
  <li>포인터는 주소를 저장하는 변수다.</li>
  <li><code class="language-plaintext highlighter-rouge">&amp;</code>는 주소를 구한다.</li>
  <li><code class="language-plaintext highlighter-rouge">*</code>는 선언에서는 포인터 타입을 뜻하고, 사용에서는 역참조를 뜻한다.</li>
  <li>이중 포인터는 포인터의 주소를 저장한다.</li>
  <li>포인터 배열은 여러 포인터를 배열로 묶어 관리한다.</li>
</ul>

<p>처음에는 <code class="language-plaintext highlighter-rouge">*</code>와 <code class="language-plaintext highlighter-rouge">&amp;</code>가 헷갈리지만, “값”, “주소”, “그 주소를 다시 따라가는 것”을 구분해서 보면 훨씬 이해하기 쉬워진다.</p>]]></content><author><name></name></author><category term="C" /><category term="Pointer" /><category term="Memory" /><category term="Array" /><category term="jungle" /><summary type="html"><![CDATA[C 언어에서 변수는 메모리 공간이라는 관점으로 보고, 포인터와 이중 포인터, 포인터 배열의 의미를 정리한다.]]></summary></entry><entry><title type="html">정글 [week5] WIL + React(Component, State, Hooks)</title><link href="https://juhoseok.github.io/jekyll-theme-velog/jungle-week5-wil-react-component-state-hooks/" rel="alternate" type="text/html" title="정글 [week5] WIL + React(Component, State, Hooks)" /><published>2026-04-02T20:00:00+09:00</published><updated>2026-04-02T20:00:00+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/jungle-week5-wil-react-component-state-hooks</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/jungle-week5-wil-react-component-state-hooks/"><![CDATA[<h1 id="정글-week5-wil--reactcomponent-state-hooks">정글 [week5] WIL + React(Component, State, Hooks)</h1>

<h2 id="이번-주-목표">이번 주 목표</h2>

<p>이번 주 학습 키워드는 <strong>동적 계획법(DP)</strong> 과 <strong>탐욕 알고리즘(Greedy)</strong>, 두 가지였다.</p>

<p>처음에는 키워드가 적어서 비교적 쉬운 주차가 될 것이라고 생각했다. 하지만 실제로 공부해 보니 전혀 그렇지 않았다. 오히려 가장 기본적으로 보이지만, 문제에 따라 가장 어렵게 느껴질 수도 있는 개념이라고 생각했다.</p>

<p>저번 주까지는 알고리즘마다 어느 정도 ‘공식처럼 적용할 수 있는 로직’이 있다고 느꼈다면, 이번 주에 배운 개념들은 단순히 외워서 적용하기보다 문제를 보고 스스로 규칙을 찾아야 한다는 점에서 마치 IQ 테스트를 푸는 느낌에 가까웠다.</p>

<aside>
💡

### 1. 문제해결

**목표:** 동적 계획법(DP), 탐욕 알고리즘(Greedy) 개념을 설명할 수 있고, 관련 문제를 풀며 풀이 원리를 말할 수 있기

**결과: 50%**

DP와 Greedy 둘 다 아주 기본적인 수준에서는 설명할 수 있지만, 아직 제한적인 수준에 머무르고 있다고 느꼈다.

예를 들어 DP는 1차원 배열로 푸는 피보나치나 계단 오르기 같은 문제는 설명할 수 있지만, 그보다 복잡한 문제에서는 상태 정의나 점화식을 스스로 세우는 데 어려움을 느꼈다. Greedy 역시 개념은 말할 수 있지만, 왜 그 선택이 항상 최적해가 되는지까지 깊게 설명하는 수준은 아직 부족하다고 느꼈다.

즉, 개념을 완전히 모르는 것은 아니지만, 문제에 따라 스스로 적용하고 설명하는 힘은 아직 더 길러야 한다고 생각했다.

---

### 2. 설계

**목표:** 문제를 풀기 전에 아이디어, 시간복잡도, 예외 케이스를 먼저 생각하고 구현하기

**결과: 30%**

이번 주에는 설계를 체계적으로 했다고 보기 어려웠다.

아이디어가 어느 정도 떠오르는 문제에서는 적어보기도 했지만, 아예 아이디어가 잘 생각나지 않는 문제에서는 설계 자체를 생략하고 바로 막히는 경우가 있었다. 또한 시간복잡도나 예외 케이스까지 충분히 고민하고 들어가기보다는, 문제를 풀다가 막히거나 다 풀고 난 뒤에 다시 생각하는 경우가 많았다.

즉, 문제를 풀기 전 설계를 하는 습관이 아직 충분히 자리 잡지 않았고, 특히 어려운 문제일수록 더 흐트러졌던 것 같다.

---

### 3. 구현

**목표:** 코드를 짜기 전에 함수 역할 주석과 TODO를 적고 시작하기

**결과: 50%**

DP 문제를 풀 때는 TODO를 적어본 적이 있었지만, Greedy 문제를 풀 때는 그렇게 하지 못했다.

특히 습관이 아직 자리 잡지 않아서, 생각나는 문제에서만 적고 그렇지 않은 경우에는 바로 코딩으로 들어갔다. 또 아이디어가 아예 떠오르지 않을 때는 TODO를 적는 것 자체도 하지 못했다.

다만 이번 주를 통해, 앞으로는 막연하게 TODO를 적으려고 하기보다는 **함수 단위로 나누고, 어떤 함수가 필요한지 중심으로 적는 방식**이 더 잘 맞겠다는 기준을 조금 세울 수 있었다.

---

### 4. 품질

**목표:** 변수명을 더 의미 있게 짓고, 읽기 쉬운 코드로 작성하기

**결과: 70%**

이번 주에는 변수명을 조금 더 신경 쓰려고 노력했다.

특히 AI에게 물어보면서 더 의미 있는 변수명을 지으려고 했고, 실제로 그렇게 적용한 적도 있었다. 다만 항상 잘 되었던 것은 아니어서, 여전히 변수명을 대충 지어서 나중에 다시 볼 때 헷갈렸던 적도 있었다.

즉, 이전보다 분명히 신경은 더 쓰게 되었지만, 아직 완전히 자연스럽게 좋은 변수명을 짓는 수준까지는 가지 못한 것 같다.

---

### 5. 유지보수

**목표:** 주석을 남겨서 나중에 봐도 이해할 수 있게 만들기

**결과: 60%**

이번 주에는 주석을 남기려고 꽤 노력했다.

다만 문제를 보자마자 아이디어가 바로 떠오르고 쉽게 느껴졌던 문제들은 주석을 거의 남기지 않았고, 조금 복잡하거나 다시 봤을 때 헷갈릴 수 있을 것 같은 문제들 위주로 적으려고 했다.

특히 변수의 의미를 적는 것이 중요하다고 느꼈고, 실제로 변수명을 대충 지었을 때는 나중에 다시 봐도 헷갈린다는 점을 경험했다. 하지만 아직도 **주석을 정확히 어디에, 어떤 방식으로 달아야 하는지에 대한 감은 완전히 잡히지 않았다.**

---

### 6. 협업

**목표:** 팀원에게 모르는 것을 질문하고 같이 이해하기

**결과: 60%**

이번 주에는 팀원에게 질문한 적이 있었고, 실제로 도움이 되었다.

예를 들어 문제를 어떤 식으로 subproblem으로 나눌 수 있을지 물어본 적이 있었는데, 그 질문이 문제를 보는 데 도움이 되었다.

하지만 여전히 질문하지 못하고 넘어간 경우도 있었다. 그 이유는 단순히 소극적이어서라기보다는, **내가 무엇을 정확히 이해하지 못하고 있는지 스스로 정리하지 못한 상태**였기 때문이다. 그래서 질문을 잘 정리하지 못해 그냥 넘어간 적이 있었다.

다음에는 다 같이 코어타임을 할 때, 막히는 부분을 더 구체적으로 정리해서 질문해보고 싶다고 느꼈다.

---

### 7. 태도

**목표:** 공유학습과 수요 코딩회에 더 적극적으로 참여하기

**결과: 30%**

이번 주에도 Codex가 너무 많은 코드를 작성해줘서, 그 코드를 충분히 이해하지 못한 채 넘어간 부분이 있었다.

실제로 결과물은 있었지만, 그 안의 구조와 흐름을 완전히 이해했다고 말하기는 어려웠다. 그래서 단순히 따라가기보다는, 내가 주도적으로 이해하고 있는지 계속 점검했어야 했다는 아쉬움이 남는다.

즉, 참여는 했지만 **이해를 끝까지 붙잡고 가는 태도** 면에서는 아직 부족했다고 느꼈다.

---

### 8. 비즈니스 이해

**목표:** 기능을 만들 때 왜 필요한 기능인지 한 번 더 생각하기

**결과: 0%**

이번 주에는 이 부분을 거의 생각하지 못했다.

구현 자체를 따라가고 결과물을 만드는 데 집중하느라, 이 기능이 왜 필요한지, 사용자 입장에서는 어떤 의미가 있는지를 생각할 여유가 없었다.

그래서 비즈니스 이해 측면에서는 이번 주 목표를 달성하지 못했다고 느꼈다.

---

### 9. AI 활용

**목표:** 내가 무엇을 모르는지 정확히 파악하고 AI에게 질문하기

**결과: 50%**

이번 주를 돌아보면서, AI를 더 잘 활용하려면 먼저 **내가 무엇이 궁금한지 스스로 더 생각하고 정리해야 한다**는 점을 느꼈다.

무작정 “모르겠다”고 질문하고, 답변을 본 뒤에도 다시 “그래도 모르겠다”고 하는 방식은 학습에 큰 도움이 되지 않는다는 생각이 들었다.

앞으로는 개념이 헷갈리는 건지, 아이디어가 안 떠오르는 건지, 문법이 막히는 건지를 먼저 나누고, 그에 맞게 프롬프트를 짜서 질문해야겠다고 느꼈다.

완전히 잘했다고 보기는 어렵지만, 적어도 이번 주에 이런 문제의식을 가지게 된 점은 의미 있었다고 생각한다.

---

### 10. 학습 민첩성

**목표:** 강의나 해설을 보고 설명할 수 있을 정도로 개념 정리하기

**결과: 20%**

이번 주에는 강의나 해설을 보고 “이제는 내가 설명할 수 있다”고 느낄 정도까지 정리된 개념은 많지 않았다.

해설을 볼 때는 이해된 것처럼 느껴지지만, 막상 다시 설명하거나 혼자 풀어보려고 하면 어려운 경우가 많았다.

즉, 단순히 본 것과 내 것으로 만든 것은 다르다는 점을 다시 느꼈고, 이 부분은 다음 주에 더 보완해야 할 부분이라고 생각했다.

</aside>

<h2 id="시도한-접근-방식">시도한 접근 방식</h2>

<p>이번 주에는 지난주에 충분히 하지 못했던 <strong>시간 복잡도 고려</strong>를 하면서 문제를 풀어보려고 했다.</p>

<p>문제를 보자마자 바로 코드부터 작성하기보다는, 어떤 방식으로 접근해야 하는지와 시간 복잡도가 적절한지를 먼저 생각해 보려고 노력했다.</p>

<p>하지만 문제 난이도가 너무 높아서 혼자 힘으로 흐름이 잡히지 않을 때는, 해당 문제에 대한 해설 영상이 있다면 그것을 보면서 원리를 이해하는 식으로 공부했다. 단순히 정답만 보는 것이 아니라, 왜 그런 방식으로 풀리는지 이해하려고 하면서 접근했다.</p>

<h2 id="문제와-해결-과정">문제와 해결 과정</h2>

<p>이번 주에 가장 많은 시간을 들인 문제는 <strong>DP 문제 ‘평범한 배낭’(백준 12865)</strong> 이었다.</p>

<ul>
  <li>
    <p>백준 12865 평범한 배낭</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1"># DP - 평범한 배낭 (백준 골드5)
</span>  <span class="c1"># 문제 링크: https://www.acmicpc.net/problem/12865
</span>    
  <span class="k">def</span> <span class="nf">solve</span><span class="p">():</span>
      <span class="c1"># 1. 입력 받기
</span>      <span class="n">n</span><span class="p">,</span> <span class="n">k</span> <span class="o">=</span> <span class="nb">map</span><span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="nb">input</span><span class="p">().</span><span class="n">split</span><span class="p">())</span>
    
      <span class="c1"># 2. dp 테이블 생성: 행(k+1개, 무게 0~k) x 열(n개, 물건 0~n-1)
</span>      <span class="c1"># 초기값은 모두 0으로 설정
</span>      <span class="n">dp</span> <span class="o">=</span> <span class="p">[[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)]</span>
    
      <span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>
      <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
          <span class="n">w</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="nb">map</span><span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="nb">input</span><span class="p">().</span><span class="n">split</span><span class="p">())</span>
          <span class="n">items</span><span class="p">.</span><span class="n">append</span><span class="p">((</span><span class="n">w</span><span class="p">,</span> <span class="n">v</span><span class="p">))</span>
    
      <span class="n">fisrt_w</span><span class="p">,</span> <span class="n">first_v</span> <span class="o">=</span> <span class="n">items</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
      <span class="k">if</span> <span class="n">fisrt_w</span> <span class="o">&lt;=</span> <span class="n">k</span><span class="p">:</span>
          <span class="n">dp</span><span class="p">[</span><span class="n">fisrt_w</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">first_v</span>
    
      <span class="c1"># 3. 물건을 하나씩 확인 (열을 하나씩 채워나감)
</span>      <span class="k">for</span> <span class="n">baggage</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
          <span class="n">current_w</span><span class="p">,</span> <span class="n">current_v</span> <span class="o">=</span> <span class="n">items</span><span class="p">[</span><span class="n">baggage</span><span class="p">]</span>
    
          <span class="c1"># [Case 2] 두 번째 물건부터 처리
</span>          <span class="c1"># Step 1: 이전 열(j-1)의 결과를 현재 열(j)로 그대로 복사
</span>          <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
              <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">baggage</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">baggage</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
    
          <span class="c1"># Step 2: 밀어내기 (물건을 넣는 경우)
</span>          <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
              <span class="c1"># 이전 물건까지의 결과(i)에 현재 물건(current_w)을 더했을 때 한도 내라면
</span>              <span class="k">if</span> <span class="n">i</span> <span class="o">+</span> <span class="n">current_w</span> <span class="o">&lt;=</span> <span class="n">k</span><span class="p">:</span>
                  <span class="c1"># 도착지 칸(i + current_w)에 기존 값과 새 값을 비교하여 더 큰 값 이면 가방에 담고 작으면 가방에 안담고
</span>                  <span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">current_w</span><span class="p">][</span><span class="n">baggage</span><span class="p">]</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">current_w</span><span class="p">][</span><span class="n">baggage</span><span class="p">],</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">baggage</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">current_v</span> <span class="p">)</span>
    
      <span class="c1"># 4. 결과 출력: 마지막 열(n-1)에 담긴 값들 중 최댓값
</span>      <span class="c1"># 리스트 컴프리헨션을 사용하여 마지막 열의 값들을 모아 최댓값을 찾습니다.
</span>      <span class="n">result</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span>
      <span class="k">print</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
    
  <span class="n">solve</span><span class="p">()</span>
</code></pre></div>    </div>
  </li>
</ul>

<p>코드 자체만 보면 비교적 단순해 보일 수 있지만, 실제로는 그 원리를 이해하는 데 많은 시간이 걸렸다.</p>

<p>이 문제를 풀면서 가장 어려웠던 점은 <strong>2차원 DP 테이블을 어떤 기준으로 해석해야 하는지</strong> 이해하는 것이었다.</p>

<p>내가 이해한 방식으로 설명하자면, 가방에 현재 물건을 <strong>넣지 않는 경우</strong>에는 이전 열의 값을 그대로 참고하기 때문에 무게를 더하지 않는다. 반면, 현재 물건을 넣는 경우에는 이전 상태에서 현재 물건의 무게를 더한 위치로 이동하면서 가치를 갱신한다.</p>

<p>즉, 이전까지의 결과를 그대로 가져오는 경우와, 현재 물건을 추가해서 새로운 상태를 만드는 경우를 비교하면서 테이블을 채워 나가는 방식이라고 이해했다.</p>

<p>머리로는 어느 정도 이해했지만, 이것을 2차원 표의 흐름으로 완전히 설명하는 것은 아직도 쉽지 않다. 그래도 이 문제를 오래 붙잡고 고민하면서 DP가 단순한 암기 개념이 아니라, <strong>상태를 어떻게 정의하고 전이시키는지 이해하는 과정</strong>이라는 것을 느낄 수 있었다.</p>

<h2 id="새롭게-배운-점">새롭게 배운 점</h2>

<p>이번 주에는 알고리즘뿐 아니라 <strong>리액트를 직접 구현해보는 경험</strong>도 할 수 있었다.</p>

<p>그 과정에서 <strong>Component, useEffect, useState, useMemo</strong>와 같은 핵심 개념들이 어떤 역할을 하는지 조금 더 알게 되었다. 단순히 문법만 보는 것이 아니라, 직접 구현해 보면서 왜 이런 개념이 필요한지 생각해 볼 수 있었다는 점이 의미 있었다.</p>

<p>또 이번 주 발표를 들으면서, 어떤 조는 <strong>코덱스에 스킬을 적용하고 하네스 기법을 활용한 방식</strong>으로 작업을 진행했다는 점이 인상적이었다.</p>

<p>그 모습을 보며 다음 주에는 나도 최소 기능부터 직접 구현해 보면서, AI나 다른 도구에 끌려다니기보다 내가 흐름을 주도하면서 개념을 더 단단히 잡아보고 싶다는 생각이 들었다.</p>

<h2 id="다음-주-계획">다음 주 계획</h2>

<p>다음 주에는 파이썬이 아니라 <strong>C 언어로 자료구조를 구현</strong>하게 된다.</p>

<p>아직 C 언어를 제대로 다뤄본 적이 없어서 걱정도 되지만, 새로운 언어를 배우는 만큼 기본 개념을 더 탄탄하게 다질 수 있는 기회가 될 것이라고 생각한다. 두려움이 있지만, 그만큼 더 열심히 해봐야겠다는 생각이 들었다.</p>]]></content><author><name></name></author><category term="python" /><category term="data structures and algorithms" /><category term="jungle" /><category term="React" /><summary type="html"><![CDATA[정글 5주차 회고]]></summary></entry><entry><title type="html">정글 [week6] WIL + SQL 처리기</title><link href="https://juhoseok.github.io/jekyll-theme-velog/jungle-week6-wil-sql-processor/" rel="alternate" type="text/html" title="정글 [week6] WIL + SQL 처리기" /><published>2026-04-02T20:00:00+09:00</published><updated>2026-04-02T20:00:00+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/jungle-week6-wil-sql-processor</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/jungle-week6-wil-sql-processor/"><![CDATA[<h1 id="정글-week6-wil--sql-처리기">정글 [week6] WIL + SQL 처리기</h1>

<h1 id="이번-주-목표">이번 주 목표</h1>

<p>이번 주에는 C 언어와 필수 자료구조를 다루는 주차였기 때문에, 가장 우선적으로 잡은 목표는 <strong>C 언어의 포인터 개념에 익숙해지는 것</strong>과 <strong>SQL 처리기에서 전체 파싱 흐름을 이해하는 것</strong>이었다.</p>

<p>저번 주에는 문제를 풀기 전 설계, 변수명, 시간복잡도 같은 요소들을 더 신경 써보려는 목표가 있었지만, 이번 주는 방향이 조금 달랐다. 이번에는 C 언어 자체가 익숙하지 않았기 때문에, 설계나 코드 품질을 세밀하게 챙기기보다는 <strong>강의를 듣고 짧은 연습문제를 직접 풀어보면서 언어 자체에 익숙해지는 것</strong>에 더 집중했다.</p>

<p>또한 수요 코딩회의 SQL 처리기 구현에서도 완성도 높은 확장 구현보다는, <strong>최소 기능을 먼저 만들고 AI가 생성한 코드를 분석하면서 흐름을 이해하는 것</strong>에 더 비중을 두었다. 이번 주는 결과적으로 “잘 설계하는 연습”보다는, C 언어와 포인터, 그리고 SQL 처리기의 구조를 이해하는 주간이었다고 정리할 수 있다.</p>

<aside>
💡

### 1. 문제해결

**목표:**

C 언어 포인터 개념을 이해하고, SQL 처리기에서 `입력 → 파싱 → 실행 → 저장` 흐름을 설명할 수 있기

**결과: 60%**

이번 주에는 알고리즘 문제 풀이보다, **C 언어와 SQL 처리기의 구조를 이해하는 것**에 더 집중했다.

특히 포인터 개념과 SQL 처리기의 전체 흐름을 이해하려고 노력했고, 실제로 `SQL 구문 → parsing → execute → storage`로 이어지는 큰 흐름은 어느 정도 설명할 수 있게 되었다. 또한 Linked List 같은 자료구조도 연결이 끊기고 이어지는 구조를 그림으로 보며 이해하려고 했다.

다만 포인터 표현식이나 이중 포인터처럼 세부 개념에서는 아직 완전히 확신이 없는 부분이 남아 있다. 즉, 전체 흐름은 전보다 더 잘 보이게 되었지만, 세부 문법과 동작 원리까지 정확히 설명하는 수준은 아직 부족하다고 느꼈다.

---

### 2. 설계

**목표:**

문제를 풀거나 기능을 구현하기 전에 구조와 흐름을 먼저 생각하고 접근하기

**결과: 20%**

이번 주는 설계를 중심으로 공부한 주간은 아니었다.

C 언어 자체가 익숙하지 않았기 때문에, 설계나 시간복잡도, 예외 케이스를 먼저 꼼꼼히 적어보는 방식보다는 **강의와 짧은 연습문제를 통해 언어 자체에 익숙해지는 것**에 더 비중을 두었다. SQL 처리기 역시 최소 기능을 먼저 구현하고, 그 흐름을 따라가며 이해하는 방식으로 접근했다.

즉, 이번 주에는 “설계 역량을 키웠다”기보다는, 설계보다 **언어와 구조를 익히는 데 집중한 주간**이었다고 보는 것이 더 맞다고 생각한다.

---

### 3. 구현

**목표:**

최소 기능을 직접 구현해 보고, 코드의 흐름을 따라가며 이해하기

**결과: 55%**

이번 주에는 SQL 처리기에서 **INSERT와 SELECT 기능을 최소 단위로 구현해 놓고**, 그 코드를 따라가며 이해하려고 했다.

직접 처음부터 끝까지 모든 코드를 주도적으로 작성한 것은 아니지만, 최소 구현을 바탕으로 `파싱 → 실행 → 저장` 흐름을 따라가며 코드가 어떤 식으로 동작하는지 분석하려고 노력했다. C 연습문제 역시 짧은 문제들을 직접 풀어보며 문법을 익히는 식으로 접근했다.

다만 아직은 내가 먼저 구조를 짜고 구현을 리드했다기보다, **구현된 코드를 해석하고 따라가는 비중**이 더 컸다. 그래서 구현 역량이 아예 없었다고 보기는 어렵지만, 주도적으로 구현했다고 말하기에도 아직 부족한 부분이 있었다.

---

### 4. 품질

**목표:**

읽기 쉽고 검증 가능한 코드에 대한 감각 기르기

**결과: 25%**

이번 주에는 변수명이나 코드 가독성을 적극적으로 챙기기보다는, **C 문법과 포인터 개념을 익히는 것**이 우선이었다.

그래서 저번 주처럼 변수명, 주석, 가독성을 의식적으로 다듬었다기보다는, 이번 주에는 그런 요소들을 거의 신경 쓰지 못했다. 특히 “좋은 코드”를 만들기 위한 품질보다는, “이 코드가 지금 어떻게 돌아가는지 이해하는 것”에 더 초점을 맞췄다.

그래도 SQL 처리기의 흐름을 단계별로 이해하려고 하면서, 기능이 나뉘어 있는 구조가 왜 중요한지는 조금 느낄 수 있었다. 다만 전반적으로 품질 면에서는 이번 주에 크게 발전했다고 보기는 어려웠다.

---

### 5. 유지보수

**목표:**

코드를 다시 봤을 때 구조를 이해할 수 있도록 정리하는 습관 만들기

**결과: 30%**

이번 주에는 유지보수 관점에서 코드를 정리하거나 기록하는 습관은 많이 챙기지 못했다.

다만 자료구조를 공부하면서, **그림 없이 코딩하면 나중에 다시 볼 때 훨씬 헷갈릴 수 있다**는 점을 느꼈다. 특히 Linked List처럼 연결 관계가 중요한 구조는, 단순히 코드만 보는 것보다 그림이나 구조 정리가 함께 있어야 이해가 더 오래 남는고 느꼈다.

즉, 실제로 유지보수를 잘 실천했다기보다는, **왜 정리와 구조화가 필요한지 체감한 주간**에 더 가까웠다.

---

### 6. 협업

**목표:**

팀 프로젝트에서 기능 흐름을 함께 이해하고 필요한 부분을 나누어 보기

**결과: 40%**

SQL 처리기 프로젝트를 하면서 팀 단위로 결과물을 만들었기 때문에, 완전히 혼자 공부한 주간은 아니었다.

특히 프로젝트의 큰 흐름을 같이 보면서 `SQL 구문 → parsing → execute → storage` 구조를 이해하려고 했고, 다른 팀의 발표를 들으면서 AST 구조 같은 새로운 접근 방식도 접할 수 있었다. 이런 점에서 협업과 공유학습의 자극은 분명히 있었다.

다만 이번 주 회고를 보면, 협업 과정에서 적극적으로 질문을 많이 하거나 구조를 주도적으로 정리했다기보다는, **주어진 흐름을 따라가며 이해하는 입장**에 가까웠다. 그래서 협업을 통해 도움은 받았지만, 적극성 면에서는 더 보완할 여지가 있다고 느껴진다.

---

### 7. 태도

**목표:**

AI가 만든 코드도 끝까지 이해하려는 태도로 학습하기

**결과: 60%**

이번 주에는 이해 중심으로 공부하겠다는 방향이 분명했다.

단순히 결과물만 만들어 두는 것이 아니라, AI가 만든 코드라도 **왜 이런 줄이 필요한지**, 지**금 어떤 포인터를 가리키는지**를 계속 질문하면서 이해하려고 했다. SQL 처리기 역시 최소 구현을 만들어 둔 뒤, 그 위에서 흐름을 분석하려는 태도를 유지했다는 점은 의미 있었다.

다만 여전히 완전히 이해하지 못한 부분도 있었고, 예를 들어 이중 포인터처럼 아직 명확히 잡히지 않은 개념도 남아 있다. 그래도 이번 주는 “결과만 두고 넘어가기”보다는, **이해하려고 붙잡고 간 태도** 자체는 지난주보다 더 좋아졌다고 볼 수 있다.

---

### 8. 비즈니스 이해

**목표:**

SQL 처리기 기능이 왜 필요한지, 사용자 입장에서 어떤 역할을 하는지 생각해 보기

**결과: 20%**

이번 주에는 비즈니스 관점까지 깊게 생각하지는 못했다.

다만 SQL 처리기를 공부하면서, 입력된 명령을 파싱하고 실행해서 저장하는 흐름이 결국은 **사용자의 요청을 받아 데이터 처리 결과를 돌려주는 시스템의 기본 구조**라는 점은 조금 느낄 수 있었다. 즉, 단순한 과제 구현이 아니라 작은 DB 시스템의 동작 원리를 맛보는 경험이라는 점은 이해하게 되었다.

그래도 여전히 구현과 이해 자체에 집중하느라, “사용자에게 왜 필요한 기능인가”까지 충분히 확장해서 생각하지는 못했다.

---

### 9. AI 활용

**목표:**

막히는 지점을 정확히 좁혀서 AI에게 질문하기

**결과: 70%**

이번 주에는 AI를 비교적 목적에 맞게 사용한 편이었다.

특히 C 문법 설명, 포인터 메모리 구조 설명, 특정 코드 줄의 필요성 질문처럼 **막히는 부분을 좁혀서 질문하려고 노력했다.** 예를 들어 “이 줄이 왜 필요한지”처럼 한 줄 단위로 물어보는 방식은, 막연하게 전체 코드를 다시 설명받는 것보다 더 학습에 도움이 되었다.

물론 여전히 완벽하게 질문을 구조화했다고 보기는 어렵지만, 적어도 이번 주에는 AI를 단순 코드 생성 도구로만 쓰기보다 **개념 보조 도구**로 활용하려고 한 점에서 지난주보다 발전이 있었다고 생각한다.

---

### 10. 학습 민첩성

**목표:**

낯선 C 언어와 포인터 개념을 빠르게 익히고, 이해 방식도 함께 개선하기

**결과: 65%**

이번 주에는 익숙하지 않은 C 언어를 다뤄야 했기 때문에, 낯선 개념을 빠르게 받아들이는 과정 자체가 중요했다.

강의를 보고, 짧은 연습문제를 풀고, 자료구조를 그림으로 이해하려고 하면서 새로운 개념을 따라가려는 시도는 꾸준히 했다. 또한 돌아보면서 “다음에는 메모리 그림을 먼저 그리면서 공부해야겠다”는 식으로 **학습 방식 자체를 개선할 포인트를 찾은 것**도 의미 있었다.

즉, 아직 완전히 익숙해졌다고는 할 수 없지만, 낯선 개념을 받아들이고 **더 나은 학습 방법을 스스로 발견했다는 점**에서 학습 민첩성은 비교적 높았다고 느꼈다

</aside>

<hr />

<h1 id="시도한-접근-방식">시도한 접근 방식</h1>

<p>이번 주에는 처음부터 C 언어를 완벽히 이해하려 하기보다는, 먼저 <strong>강의를 중심으로 개념을 익히고</strong>, 이후에 간단한 연습문제를 풀면서 익숙해지려고 했다. 특히 AI에게 짧은 문제를 만들어 달라고 해서 직접 풀어보는 방식으로 반복 연습을 했다.</p>

<p>돌아보면, 이번 주에는 코드를 눈으로만 따라간 경우가 많았는데, 그 과정에서 <strong>메모리 그림을 함께 그리면서 공부했으면 더 좋았겠다는 생각</strong>이 들었다. 포인터나 자료구조는 코드만 보는 것보다, 실제 메모리에서 어떤 값이 저장되고 어떤 주소를 가리키는지를 그림으로 그려야 훨씬 잘 이해된다는 점을 느꼈다. 그래서 이번 주의 방식은 강의와 간단한 문제 풀이 중심이었다면, 다음에는 여기에 메모리 그림까지 반드시 함께 가져가야겠다고 생각했다.</p>

<p>자료구조를 이해할 때는 특히 <strong>그림을 통해 연결 구조를 따라가려고 노력했다.</strong> Linked List를 볼 때도 단순히 코드 줄을 읽기보다, 어떤 노드가 어디를 가리키고 있고, 어디서 연결이 끊기고 다시 이어지는지를 그려보면서 이해하려고 했다. 이 과정에서 포인터를 따라가며 구조를 보는 감각이 조금씩 생겼다.</p>

<p>SQL 처리기 프로젝트에서는 <strong>INSERT와 SELECT 기능을 최소 단위로 먼저 구현한 뒤</strong>, 그 코드를 따라가면서 전체 흐름을 이해하려고 했다. 단순히 “기능이 동작한다”에서 끝내지 않고, SQL 구문 → 파싱 → execute → storage로 이어지는 흐름을 하나의 처리 과정으로 이해하려고 노력했다. 이번 주에는 구현 자체보다도, 각 단계가 어떤 역할을 맡는지를 따라가며 보는 접근이 더 컸다.</p>

<p>AI는 주로 <strong>C 문법 설명</strong>과 <strong>포인터의 메모리 구조 설명</strong>을 받는 데 사용했다. 특히 이해가 안 되는 코드 줄이 있을 때는 전체 코드를 다시 달라고 하기보다, “이 줄이 왜 필요한지”, “이 포인터가 지금 무엇을 가리키는지”처럼 좁혀서 질문하려고 했다.</p>

<hr />

<h1 id="문제와-해결-과정">문제와 해결 과정</h1>

<p>이번 주에 가장 오래 붙잡고 있었던 것은 <strong>포인터 표현식 이해</strong>, 그중에서도 <code class="language-plaintext highlighter-rouge">*p++</code> 같은 표현이었다. 겉으로 보기에는 짧은 코드인데, 실제로는 연산자 우선순위와 포인터 이동, 역참조가 한 번에 섞여 있어서 쉽게 이해되지 않았다.</p>

<p>특히 헷갈렸던 점은 <strong>문자열 배열과 포인터의 관계</strong>, 그리고 경우에 따라 왜 이중 포인터가 필요한지헷갈였다. 예를 들어 <code class="language-plaintext highlighter-rouge">char</code> 배열이 문자열을 담고 있을 때, 그것이 단순한 배열인지, 포인터처럼 동작하는지, 또 어떤 상황에서 <code class="language-plaintext highlighter-rouge">char *</code>와 <code class="language-plaintext highlighter-rouge">char **</code>가 구분되는지 완전히 명확하게 잡히지 않았다. 지금도 완전히 이해했다고 말하기는 어렵지만, 적어도 어디가 헷갈리는지는 조금 더 분명하게 알게 되었다.</p>

<p>이 문제를 해결하려고 할 때 가장 많이 사용한 방법은 <strong>AI에게 특정 줄의 역할을 좁혀서 질문하는 방식</strong>이었다. “이 줄이 왜 필요한지”, “여기서 p가 가리키는 대상이 뭔지”, “증가되는 건 주소인지 값인지” 같은 방식으로 하나씩 확인하려고 했다. 아직은 코드 전체를 한 번에 이해하기보다, <strong>한 줄씩 잘라서 해석하는 방식</strong>이 더 잘 맞는다고 느꼈다.</p>

<p>SQL 처리기에서는 세부 구현 하나하나보다도, <strong>SQL 구문이 들어와서 파싱되고, 실행을 거쳐 저장 단계로 가는 전체 흐름</strong>을 이해하려고 했다. 즉, 입력된 SQL 문장이 단순한 문자열이 아니라, 파싱을 통해 구조화되고, 그 결과가 실행 단계에서 실제 동작으로 이어지며, 마지막에는 storage에서 파일에 반영된다는 흐름을 파악한 것이 가장 큰 수확이었다.</p>

<hr />

<h1 id="새롭게-배운-점">새롭게 배운 점</h1>

<p>이번 주를 통해 가장 크게 느낀 점은, <strong>C 언어는 메모리를 직접 의식하면서 공부해야 하는 언어</strong>라는 점이었다. 파이썬처럼 결과만 보고 넘어갈 수 있는 부분이 적고, 포인터와 주소, 값의 관계를 정확히 이해해야 코드의 동작 원리가 보인다는 것을 느꼈다. 그래서 단순히 문법을 외우는 것보다, <strong>메모리를 직접 그려보며 문제를 푸는 방식이 훨씬 중요하겠다</strong>는 생각이 들었다.</p>

<p>자료구조를 공부하면서도 비슷한 점을 느꼈다. 특히 Linked List처럼 연결 관계가 중요한 구조는, 코드만 보고 이해하려고 하면 금방 헷갈리기 쉽다. 반대로 그림으로 노드와 포인터의 연결 상태를 그려 보면, 어디서 연결이 끊기고 어디에 다시 붙는지가 훨씬 잘 보인다. 그래서 이번 주에는 “그림 없이 코딩하면 헷갈리기 쉽다”는 점을 분명히 배웠다.</p>

<p>SQL 처리기 프로젝트를 하면서는, 작은 DB 처리 흐름이 어떻게 구성되는지 감을 잡을 수 있었다. <strong>입력 → 파싱 → 실행 → 저장</strong>이라는 흐름은 단순히 이번 과제만의 구조가 아니라, 데이터를 처리하는 프로그램 전반에 공통적으로 적용될 수 있는 사고방식이라는 점에서 의미가 있었다.</p>

<p>또 발표를 들으면서 <strong>AST 구조를 사용한 팀</strong>이 있었는데, 그 부분이 인상 깊었다. 같은 SQL 처리기라도 단순 문자열 분기 수준을 넘어서 더 구조화된 방식으로 접근할 수 있다는 점이 흥미로웠고, 나중에 AST가 어떤 식으로 파싱 결과를 표현하는지 더 알아보고 싶다는 생각이 들었다.</p>

<hr />

<h1 id="다음-주-계획">다음 주 계획</h1>

<p>다음 주에는 이번 주에 느꼈던 부족한 점을 바탕으로, <strong>C 언어 문법 복습</strong>, <strong>테스트 습관 만들기</strong>, 그리고 메모리 구조를 그려가며 문제를 푸는 방식을 가장 우선적인 목표로 잡고 싶다.</p>

<p>이번 주에는 이해 중심으로 접근한 덕분에 큰 흐름은 볼 수 있었지만, 반대로 테스트를 꼼꼼히 붙이거나 코드를 검증하는 습관은 부족했다. 그래서 다음 주에는 단순히 “동작하는 코드”를 넘어서, 작은 기능이라도 직접 테스트하면서 확인하는 습관을 들이고 싶다.</p>

<p>또 포인터와 자료구조는 머릿속으로만 생각하면 자주 헷갈리기 때문에, 다음부터는 <strong>코드를 치기 전에 먼저 메모리 그림을 그리고 시작하는 방식</strong>을 습관으로 만들고 싶다. 특히 포인터 이동, 연결 리스트 구조, 함수에 포인터를 넘길 때 값이 어떻게 바뀌는지를 그림으로 먼저 정리하고 나서 코드를 작성해보려고 한다.</p>

<p>정리하면 다음 주 목표는 아래처럼 잡고 싶다.</p>

<p><strong>1. C 언어 문법과 포인터 개념을 다시 복습하면서, 헷갈리는 표현식을 메모리 그림으로 설명할 수 있을 정도로 정리하기</strong></p>

<p><strong>2. 자료구조 문제를 풀 때 코드를 바로 쓰기보다, 먼저 연결 구조와 메모리 상태를 그림으로 그리고 시작하기</strong></p>

<p><strong>3. 구현한 기능은 반드시 작은 테스트로 검증하는 습관을 들이기</strong></p>]]></content><author><name></name></author><category term="C" /><category term="data structures and algorithms" /><category term="jungle" /><category term="SQL" /><summary type="html"><![CDATA[정글 6주차 회고]]></summary></entry><entry><title type="html">정글 [week4] WIL + React(Vdom, diff)</title><link href="https://juhoseok.github.io/jekyll-theme-velog/jungle-week4-wil-react-vdom-diff/" rel="alternate" type="text/html" title="정글 [week4] WIL + React(Vdom, diff)" /><published>2026-03-26T20:00:00+09:00</published><updated>2026-03-26T20:00:00+09:00</updated><id>https://juhoseok.github.io/jekyll-theme-velog/jungle-week4-wil-react-vdom-diff</id><content type="html" xml:base="https://juhoseok.github.io/jekyll-theme-velog/jungle-week4-wil-react-vdom-diff/"><![CDATA[<h1 id="정글-week4-wil--reactvdom-diff">정글 [week4] WIL + React(Vdom, diff</h1>

<p><a href="https://www.notion.so/4-32bc2e888cb5805888bbf545414c1ee0?pvs=21">4주차 학습목표 수립 </a></p>

<h2 id="1-이번-주-목표">1. 이번 주 목표</h2>

<p>이번 주 목표는 <strong>트리,이진 검색 트리, 그래프(vertex, edge, node, arc), BFS, DFS, 위상정렬</strong> 개념을 설명할 수 있을 정도로 이해하고, BFS와 DFS를 직접 코드로 구현할 수 있도록 익히는 것이었다.</p>

<p>또한 단순히 문제를 푸는 데서 끝나는 것이 아니라,</p>

<ul>
  <li>아이디어와 시간복잡도, 예외 케이스를 먼저 정리해보고 구현하기</li>
  <li>함수의 역할을 주석으로 적고 TODO를 작성한 뒤 시작하기</li>
  <li>변수명을 더 명확하게 짓고, 주석을 충분히 남기기</li>
  <li>팀원들과 적극적으로 질문하고 공유학습에 참여하기</li>
  <li>내가 모르는 것을 정확히 파악해 AI에게 질문하기를 이번 주 학습 태도의 목표로 삼았다.</li>
</ul>

<p>추가로, 유튜브 강의를 보고 <strong>다른 사람에게 설명할 수 있을 정도로 개념을 정리하는 것</strong>도 목표였다.</p>

<aside>
💡

핵심 역량 목표 설정 

1. 문제해결 : 트리, 이진 검색 트리, 그래프(vertex, edge, node, arc), BFS, DFS, 위상정렬 개념 설명가능할 정도로 개념다지고, BFS, DFS 코드 구현하며 설명하기 

- 결과: 70 % 아직 재귀로 트리를 만드는게 부족하다
1. 설계 : 아이디어, 시간복잡도, 어떤케이스 있는지 타이핑 해보고 구현
    - 결과: 50% 아이디어는 타이핑하지만 시간복잡도, 케이스들은 많이 생각해보지 않는다.
2. 구현 : 구현할때 교수님이 말씀하신 대로 함수만들 때 어떤 함수인지 주석으로 간단하게 적고 todo적어보고 시작해보기 
    - 결과: 0% 어떤식으로 해야할지 모르겠어서 다음주에 더 체계화 해봐야겠따.
3. 품질 : 변수이름 ai에게 물어봐서 추천받거나 구글링해서 알아보기 쉽게 사용하기
    - 결과 : 80% 반복문을사용할때는 i, j를 사용하지만 다른 변수를 초기화할때는 번역을 해서 의미있는 변수를 사용하도록 신경썼다.
4. 유지보수 : 주석 최대한 많이 남겨놓기 
    - 결과: 10% 주석 남기는 습관도 위와 구현할때 같이하면 좋을거 같은데 마찮가지로 방법을 잘몰라 찾아봐야겠다.
5. 협업 : 팀원간의 모르는거 있으면 계속 물어보기 
    - 50% 아직 적극적으로 물어보지는 못하는것 같다.
6. 태도 : 팀원간의 공유학습 적극적으로 참여하기 
    - 50% 수요코딩회때  종종 이해안될때 그냥 넘어간적이 있었다.
7. 비즈니스 이해 : 기능을 볼때 한번더 생각하기 
    - 0% 코덱스로 만들기만 바빠서 비즈니스쪽으로 생각하지 못했다.
8. Ai 활용 : 내가 어떤걸 모르는지 정확히 알고 ai에게 질문하기 (개념, 문법, 아이디어) 
    - 60% 문제를 다풀고 작동하지 않을때 더 깊이 뭘 모르는지 연구했으면 좋았겠지만 얕게 생각하고 바로 힌트를 요청한적이 많았다.
9. 학습 민첩성 : 유튜브강의 설명할수 있을정도로 개념다지기 
</aside>

<hr />

<h2 id="2-시도한-접근-방식">2. 시도한 접근 방식</h2>

<p>저번 주에는 문제를 보면 먼저 <strong>입력,출력, 그리고 어떤 흐름으로 풀 수 있을지</strong>를 VSCode에 짧게 적어본 뒤 문제를 풀려고 했다.</p>

<p>이번 주에는 그 방법만으로는 부족하다고 느꼈다. 특히 트리와 그래프, BFS/DFS 같은 개념은 머릿속으로만 이해하려고 하면 잘 잡히지 않았다. 그래서 <strong>직접 그림을 그리면서</strong>, 스택이나 큐에 값이 <strong>어떤 순로 들어가고 나오는지 흐름을 시각적으로 확인</strong>해 보았다. 그 과정을 통해 추상적인 개념을 코드와 연결하려고 노력했다.</p>

<p>또 구현을 시작하기 전에</p>

<ul>
  <li>이 함수가 어떤 역할을 하는 함수인지 간단히 적고</li>
  <li>TODO를 먼저 작성한 뒤</li>
  <li>그 다음 코드를 채워 넣는 방식을 의식적으로 연습해 보았다.</li>
</ul>

<hr />

<h2 id="3-문제와-해결-과정">3. 문제와 해결 과정</h2>

<p>이번 주에는 지난주보다 더 어려운 <strong>트리와 그래프 관련 알고리즘 문제</strong>를 풀었다.</p>

<p>개념 자체는 어느 정도 이해했다고 생각했지만, 막상 그것을 코드로 옮기려고 하니 <strong>어떻게 구현해야 할지 막막한 순간이 많았다.</strong></p>

<p>그래서 단순히 “이 알고리즘은 이런 것이다”로 넘어가지 않고,</p>

<p><strong>이 개념이 실제 코드에서는 어떤 자료구조와 연결되는지</strong>를 많이 고민했다.</p>

<p>예를 들어 BFS는 “너비 우선 탐색”이라는 설명만 들으면 추상적으로 느껴질 수 있다. 하지만 실제 코드에서는 이것이 큐(Queue)와 연결되고,</p>

<ul>
  <li>먼저 들어간 노드가 먼저 나온다는 점</li>
  <li>방문한 노드를 기록해야 중복 탐색이 생기지 않는다는 점</li>
  <li>현재 노드에서 갈 수 있는 다음 노드들을 큐에 차례로 넣는 방식으로 구현된다는 것을 연결해서 이해하려고 했다.</li>
</ul>

<p>DFS도 마찬가지였다. 깊이 우선 탐색이라는 개념을,</p>

<ul>
  <li><strong>재귀 호출</strong>로 구현할 수도 있고</li>
  <li><strong>스택</strong>으로 직접 구현할 수도 있다는 점을 생각하며 “탐색 방식의 차이”가 코드에서 어떻게 드러나는지 보려고 했다.</li>
</ul>

<p>즉, 이번 주에는 문제를 푸는 것보다도</p>

<p><strong>개념과 코드가 어떻게 매칭되는지 이해하는 과정</strong>에 많은 시간을 썼다.</p>

<hr />

<h2 id="4-새롭게-배운-점">4. 새롭게 배운 점</h2>

<p>이번 주에 가장 크게 배운 점은,</p>

<p><strong>트리, 이진 검색 트리, 그래프, BFS, DFS, 위상정렬</strong> 같은 개념을 예전보다 훨씬 더 구체적으로 설명할 수 있게 되었다는 점이다.</p>

<p>아직 완벽하다고 말할 수는 없지만,</p>

<p>“이 개념을 코드로 어떻게 구현할 수 있어?”라는 질문을 받았을 때</p>

<p>이전보다 훨씬 더 자신 있게 흐름을 설명할 수 있을 것 같다.</p>

<p>또 하나 새롭게 인상 깊었던 점은 <strong>React</strong>에 대한 이해였다.</p>

<p>전에도 React를 사용해본 적은 있었지만, “어떻게 만들어지고 동작하는지”까지는 깊게 생각해보지 않았다. 이번 수요 코딩회를 통해 React도 결국 <strong>트리 구조</strong>로 생각할 수 있고, 탐색 과정과 재귀적인 구*를 바탕으로 동작한다는 점을 배웠다. 또한 <strong>diff 알고리즘을 통해 변경된 노드만 비교하고 반영한다</strong>는 점도 새롭게 알게 되었다.</p>

<p>이 경험을 통해 알고리즘 개념이 단순히 문제 풀이에서만 쓰이는 것이 아니라,</p>

<p>내가 익숙하게 사용하던 프론트엔드 기술과도 연결된다는 점이 흥미로웠다.</p>

<hr />

<h2 id="5-아쉬웠던-점">5. 아쉬웠던 점</h2>

<p>아쉬웠던 점도 있었다.</p>

<p>Codex가 만들어준 가상 DOM 프로젝트의 코드를 <strong>완벽하게 이해하지 못한 점</strong>이 가장 아쉬웠다.</p>

<p>프로젝트를 먼저 만들고, 각자 그 코드를 분석하는 방식으로 진행했는데,</p>

<p>돌이켜보면 <strong>다 같이 코드를 한 줄씩 분석하고 토론하는 방식</strong>으로 진행했으면 더 좋았을 것 같다는 생각이 들었다.</p>

<p>단순히 결과물이 있는 것보다,</p>

<p>그 안의 구조와 흐름을 모두가 함께 해석해보는 과정이 있었다면</p>

<p>이해도가 더 높아졌을 것 같다.</p>

<hr />

<h2 id="6-회고">6. 회고</h2>

<p>이번 주는 실력 면에서 <strong>많이 성장했다고 느낀 주</strong>였다.</p>

<p>동시에, 공부하는 내 태도에 대해서도 많이 생각해보게 된 한 주였다.</p>

<p>예를 들어 “HTML에는 DOM이 있고, 그것이 어떤 구조로 이루어진다”는 말을 들으면 나는 종종 “아 그렇구나” 하고 넘어가는 편이었다. 그런데 다른 분들은 거기서 멈추지 않고</p>

<p><strong>“왜 DOM으로 만드는 건데?”</strong>,</p>

<p><strong>“왜 이런 구조를 쓰는 거지?”</strong></p>

<p>같은 질문을 계속 던지면서 토론을 이어갔다.</p>

<p>그 토론을 보면서 나도 많이 배웠고,</p>

<p>동시에 <strong>나는 왜 그냥 수긍하고 넘어가는 편일까</strong>를 돌아보게 되었다.</p>

<p>이번 주는 단순히 개념을 배운 것뿐 아니라,</p>

<p><strong>더 깊게 파고드는 질문의 중요성</strong>을 느끼게 된 주였다.</p>

<hr />

<h2 id="7-다음-주-계획">7. 다음 주 계획</h2>

<p>다음 주에는 <strong>동적 계획법(Dynamic Programming, DP)</strong> 과 <strong>탐욕 알고리즘(Greedy Algorithm)</strong> 을 배우게 된다. 이번 주와 마찬가지로, 단순히 문제를 푸는 수준이 아니라</p>

<ul>
  <li>개념을 직접 설명할 수 있고</li>
  <li>왜 그 알고리즘을 쓰는지 말할 수 있고</li>
  <li>코드로 어떻게 구현되는지까지 설명할 수 있는 수준으로 이해하고 싶다.</li>
</ul>

<p>또한 <strong>CSAPP 1장</strong>에 대해서도 개념을 정리하며,</p>

<p>알고리즘뿐 아니라 컴퓨터 시스템의 기초에 대해서도 이해를 넓혀가고 싶다.</p>]]></content><author><name></name></author><category term="python" /><category term="data structures and algorithms" /><category term="jungle" /><category term="React" /><summary type="html"><![CDATA[정글 4주차 회고]]></summary></entry></feed>