<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>E0u0n.log</title>
        <link>https://velog.io/</link>
        <description>이세계 개발자입니다.</description>
        <lastBuildDate>Sat, 27 Jul 2024 14:00:27 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>E0u0n.log</title>
            <url>https://velog.velcdn.com/images/cey_adda/profile/3afaa8d3-51e9-4823-b263-e1fa31c80499/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. E0u0n.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/cey_adda" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[정보처리기사 실기] 7. 애플리케이션 테스트]]></title>
            <link>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-7.-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%ED%85%8C%EC%8A%A4%ED%8A%B8-f75m7b08</link>
            <guid>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-7.-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%ED%85%8C%EC%8A%A4%ED%8A%B8-f75m7b08</guid>
            <pubDate>Sat, 27 Jul 2024 14:00:27 GMT</pubDate>
            <description><![CDATA[<p>애플리케이션 테스트 관련 파트입니다.</p>
<hr>
<h1 id="1-애플리케이션-테스트-케이스-설계">1. 애플리케이션 테스트 케이스 설계</h1>
<h2 id="span-stylebackground-colorfff5b101-애플리케이션-테스트-케이스-작성-⭐⭐⭐span"><span style="background-color:#fff5b1">01. 애플리케이션 테스트 케이스 작성 ⭐⭐⭐</span></h2>
<h3 id="1-소프트웨어-테스트의-이해">1) 소프트웨어 테스트의 이해</h3>
<h4 id="①-소프트웨어-테스트">① 소프트웨어 테스트</h4>
<ul>
<li>개발된 응용 애플리케이션이나 시스템이 <strong>사용자가 요구</strong>하는 기능과 성능, 사용성, 안정성 등을 만족하는지 확인하고, 노출되지 않은 숨어있는 소프트웨어의 <strong>결함</strong>을 찾아내는 활동</li>
</ul>
<h4 id="②-소프트웨어-테스트-필요성">② 소프트웨어 테스트 필요성</h4>
<ul>
<li>오류 발견 관점 : 프로그램에 잠재된 오류를 발견하고 이를 수정</li>
<li>오류 예방 관점 : 프로그램 실행 전 동료 검토, 워크 스루, 인스펙션 등을 통해 오류 사전 발견</li>
<li>품질 향상 관점 : 사용자의 요구사항 및 기대 수준 만족을 위해 반복적인 테스트를 거쳐 신뢰도 향상</li>
</ul>
<h4 id="③-소프트웨어-테스트의-기본-원칙-⭐">③ 소프트웨어 테스트의 기본 원칙 ⭐</h4>
<ol>
<li><p>소프트웨어 테스트 원리</p>
<table>
<thead>
<tr>
<th align="center">원리</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">결함 존재 증명</td>
<td>- <strong>결함은 없을 수 없기</strong>에 존재함을 밝히고 줄이는 방향</td>
</tr>
<tr>
<td align="center">완벽한 테스팅은 불가능</td>
<td>- 무한 경로, 무한 입력값</td>
</tr>
<tr>
<td align="center">초기 집중</td>
<td>- 조기 테스트 설계 장점 : 테스팅 결과를 단시간에 알 수 있고, 재작업을 줄여 개발 기간 단축 및 결함 예방 <br>- <strong>요르돈의 법칙</strong>(Snowball Effect, 눈덩이 법칙)</td>
</tr>
<tr>
<td align="center">결함 집중</td>
<td>- 적은 수의 모듈에서 대다수 결함 발견 <br>- <strong>파레토 법칙</strong>(Pareto Principle) : 오류 80%는 전체 모듈 20% 내에서 발견</td>
</tr>
<tr>
<td align="center">살충제 패러독스</td>
<td>- <strong>동일한 테스트 케이스</strong>에 의한 반복적 테스트는 새로운 버그 찾지 못함 <br>- 테스트 케이스의 <strong>정기적 리뷰와 개선</strong> 필요</td>
</tr>
<tr>
<td align="center">정황 의존성</td>
<td>- 소프트웨어의 성격에 맞게 테스트 실시 <br>- 정황과 비즈니스 도메인에 따라 테스트를 다르게 수행</td>
</tr>
<tr>
<td align="center">오류-부재의 궤변</td>
<td>- <strong>요구사항</strong>을 충족시켜주지 못하면, 결함이 없어도 품질이 높지 않음</td>
</tr>
</tbody></table>
</li>
<li><p>소프트웨어 테스트 프로세스</p>
<ul>
<li>테스트 계획 → 테스트 분석 및 디자인 → 테스트 케이스 및 시나리오 작성 → 테스트 수행 → 테스트 결과 평가 및 리포팅</li>
</ul>
</li>
<li><p>소프트웨어 테스트 산출물</p>
<table>
<thead>
<tr>
<th align="center">산출물</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">테스트 계획서 <br>(Test Plan)</td>
<td>테스트 목적과 범위, 대상 시스템 구조, 테스트 수행 절차, 테스트 일정, 조직의 역할 및 책임, <br>종료 조건 등 <strong>테스트 수행 계획</strong> 문서</td>
</tr>
<tr>
<td align="center">테스트 베이시스 <br>(Test Basis)</td>
<td>분석, 설계 단계의 논리적인 Case로 테스트 설계를 위한 <strong>기준</strong>이 되는 문서 <br> (요구사항 명세서, 관련 기준 또는 표준 등)</td>
</tr>
<tr>
<td align="center">테스트 케이스 <br>(Test Case)</td>
<td>테스트를 위한 <strong>설계 산출물</strong>, SW가 <strong>요구사항</strong>을 준수하는지 확인하기 위해 설계된 입력값, 실행 조건, <br>기대 결과로 구성된 <strong>테스트 항목</strong>의 명세서</td>
</tr>
<tr>
<td align="center">테스트 슈트 <br>(Test Suites)</td>
<td>- 테스트 케이스를 <strong>실행환경</strong>에 따라 구분해 놓은 <strong>테스트 케이스 집합</strong> <br>- <strong>시나리오가 포함되지 않은</strong> 단순 테스트 케이스 모음</td>
</tr>
<tr>
<td align="center">테스트 시나리오 <br>(Test Scenario)</td>
<td>- 테스트 되어야 할 기능 및 특징, 테스트 필요 상황 작성 문서 <br>- 하나의 단일 테스트 시나리오가 하나/여러 케이스들 포함 가능 <br>- 예 : Test Scenario 1. 로그인 &gt; 상품검색 &gt; 장바구니 담기 &gt; 주문 &gt;결제</td>
</tr>
<tr>
<td align="center">테스트 스크립트 <br>(Test Script)</td>
<td>- 테스트 케이스의 <strong>실행 순서(절차)</strong> 작성 문서 <br>- Test Step, Test Procedure라고도 함  <br>- 예 : Test Procedure 1. 로그인,  Test Procedure 2. 상품검색,  Test Procedure 3. 장바구니 담기, ...</td>
</tr>
<tr>
<td align="center">테스트 결과서 <br>(Test Results)</td>
<td>테스트 결과를 정리한 문서, 테스트 프로세스 리뷰, 테스트 결과 평가를 리포팅</td>
</tr>
</tbody></table>
</li>
</ol>
<h3 id="2-소프트웨어-테스트-유형-⭐⭐">2) 소프트웨어 테스트 유형 ⭐⭐</h3>
<h4 id="①-프로그램-실행-여부에-따른-분류">① 프로그램 실행 여부에 따른 분류</h4>
<ul>
<li>정적 테스트 
: 테스트 대상 실행 X, 구조 분석<ul>
<li>리뷰, 정적 분석</li>
</ul>
</li>
<li>동적 테스트
: 소프트웨어를 실행<ul>
<li>블랙박스 테스트(명세 기반 테스트)</li>
<li>화이트박스 테스트(구조 기반 테스트)</li>
<li>경험기반 테스트</li>
</ul>
</li>
</ul>
<h4 id="②-테스트-기법에-따른-분류-⭐">② 테스트 기법에 따른 분류 ⭐</h4>
<ul>
<li>화이트박스 테스트
: 코드 분석, 프로그램 구조<ul>
<li>구분=문장(Statement Coverage)</li>
<li>결정=선택(Decision Coverage)=분기 커버리지(Branch Coverage)</li>
<li>조건(Condition Coverage)</li>
<li>조건/결정(Condition/Decision Coverage)</li>
<li>변경 조건/결정(Modified Condition/Decision Coverage)</li>
<li>다중 조건(Multiple Condition Coverage)</li>
<li>기본 경로=경로(Base Path Coverage)</li>
<li>제어 흐름(Control Flow Coverage)</li>
<li>데이터 흐름(Data Flow Coverage)</li>
<li>루프(Loop Coverage)</li>
</ul>
</li>
<li>블랙박스 테스트
: 요구사항 명세 수행<ul>
<li>동등분할=동치 분할, 균등 분할=동치 클래스 분해(Equivalence Partitioning Testing)</li>
<li>경곗값 분석(Boundary Value Analysis Testing)</li>
<li>결정 테이블(Decision Table Testing)</li>
<li>상태 전이(State Transition Testing)</li>
<li>유스케이스(Use Case Testing)</li>
<li>분류 트리(Classification Tree Testing)</li>
<li>페어와이즈(Pairwise Testing)</li>
<li>원인-결과 그래프(Cause-Effect Testing)</li>
<li>비교(Comparison Testing)</li>
<li>오류 추정(Error Guessing Testing)</li>
</ul>
</li>
</ul>
<ol>
<li><p>화이트박스 테스트(White-Box Test)</p>
<ul>
<li>응용 프로그램의 내부 구조와 동작을 검사</li>
<li>구조 기반 테스트, 코드 기반 테스트, 로직 기반 테스트, 글래스(Glass) 박스 테스트라고 불림</li>
</ul>
</li>
</ol>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">구문 커버리지<br>=문장 커버리지<br>(Statement Coverage)</td>
<td>- 프로그램 내 모든 명령문을 적어도 한 번 수행 <br>- 조건문 결과와 관계없이 구문 실행 개수로 계산</td>
</tr>
<tr>
<td align="center">결정 커버리지<br>=선택 커버리지<br>(Decision Coverage)<br>=분기 커버리지<br>(Branch Coverage)</td>
<td>- (각 분기의) 결정 포인트 내의 <strong>전체 조건식</strong>이 적어도 한 번은 참과 거짓의 결과를 수행 <br>- 구문 커버리지 포함</td>
</tr>
<tr>
<td align="center">조건 커버리지<br>(Condition Coverage)</td>
<td>- (각 분기의) 결정 포인트 내의 <strong>개별 조건식</strong>이 적어도 한 번은 참과 거짓의 결과가 되도록 수행 <br>- 구문 커버리지 포함</td>
</tr>
<tr>
<td align="center">조건/결정 커버리지<br>(Condition/Decision Coverage)</td>
<td>전체 조건식 뿐만 아니라 개별 조건식도 적어도 한 번은 참과 거짓의 결과가 되도록 수행</td>
</tr>
<tr>
<td align="center">변경 조건/결정 커버리지<br>(Modified Condition/<br>Decision Coverage)</td>
<td>개별 조건식이 다른 개별 조건식에 <strong>영향을 받지 않고</strong>, 전체 조건식에 <strong>독립적</strong>으로 영향을 주어 <strong>조건/결정 커버리지</strong>를 향상</td>
</tr>
<tr>
<td align="center">다중 조건 커버리지<br>(Multiple Condition <br>Coverage)</td>
<td>결정 조건 내 모든 <strong>개별 조건식</strong>이 <strong>모든 가능한 조합 100%</strong> 보장</td>
</tr>
<tr>
<td align="center">기본 경로 커버리지<br>=경로 커버리지<br>(Base Path Coverage)</td>
<td>수행 가능한 <strong>모든 경로</strong> 테스트</td>
</tr>
<tr>
<td align="center">제어 흐름 커버리지<br>(Control Flow Coverage)</td>
<td>프로그램 <strong>제어 구조를 그래프 형태</strong>로 나타내어 새부 로직 테스트</td>
</tr>
<tr>
<td align="center">데이터 흐름 커버리지<br>(Data Flow Coverage)</td>
<td><strong>제어 흐름 그래프</strong>에서 데이터 사용현황 <strong>추가</strong>한 그래프를 통해 테스트</td>
</tr>
<tr>
<td align="center">루프 커버리지<br>(Loop Coverage)</td>
<td>프로그램의 반복(Loop) 구조</td>
</tr>
</tbody></table>
<ol start="2">
<li><p>블랙박스 테스트(Black-Box Test)</p>
<ul>
<li>기능 및 동작 위주의 테스트</li>
</ul>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">동등분할=<br>동치 분할, 균등 분할=<br>동치 클래스 분해<br>(Equivalence Partitioning)</td>
<td>입력 데이터 영역을 유사한 도메인 별로 유효값/무효값 <strong>그룹핑</strong>, <strong>대푯값 테스트 케이스</strong> 도출</td>
</tr>
<tr>
<td align="center">경곗값 분석<br>(Boundary Value Analysis)</td>
<td>경곗값 포함하여 테스트 케이스 설계</td>
</tr>
<tr>
<td align="center">결정 테이블<br>(Decision Table)</td>
<td>요구사항의 논리와 발생 조건을 <strong>테이블</strong> 형태로 나열, 조건과 행위를 모두 조합하여 테스트</td>
</tr>
<tr>
<td align="center">상태 전이<br>(State Transition)</td>
<td>테스트 대상, 시스템, 객체의 상태를 <strong>구분</strong>, 이벤트에 의해 <strong>상태가 전이</strong>되는 경우의 수 수행</td>
</tr>
<tr>
<td align="center">유스케이스<br>(Use Case)</td>
<td>유스케이스가 모델링 되어 있을 때 <strong>프로세스 흐름</strong>을 기반으로 테스트 케이스 명세화 수행</td>
</tr>
<tr>
<td align="center">분류 트리<br>(Classification Tree)</td>
<td>SW의 일부 또는 전체를 <strong>트리 구조</strong>로 분석 및 표현</td>
</tr>
<tr>
<td align="center">페어와이즈<br>(Pairwise)</td>
<td>테스트 데이터 값들을 <strong>최소 한 번씩 조합</strong>, 테스트 범위를 줄임</td>
</tr>
<tr>
<td align="center">원인-결과 그래프<br>(Cause-Effect)</td>
<td><strong>그래프</strong>로 입력 데이터 간의 관계 및 출력에 미치는 영향 <strong>분석</strong>, 효용성 높은 테스트 케이스 선정</td>
</tr>
<tr>
<td align="center">비교<br>(Comparison)</td>
<td>여러 버전 프로그램에 <strong>같은 입력값</strong>을 넣어 <strong>동일한 결과</strong>가 나오는지 비교</td>
</tr>
<tr>
<td align="center">오류 추정<br>(Error Guessing)</td>
<td>개발자 <strong>실수 추정</strong>, 다른 블랙박스 테스트 기법 보완</td>
</tr>
</tbody></table>
</li>
</ol>
<h4 id="③-테스트-시작에-따른-분류">③ 테스트 시작에 따른 분류</h4>
<ul>
<li>검증(Verification)</li>
<li>확인(Validation)</li>
</ul>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">검증(Verification)</td>
<td>- 소프트웨어 개발 과정 테스트 <br>- 올바른 제품 생산 검증 <br>- 이전 단계에서 설정된 개발 규격과 요루 충족 판단 <br>- 개발자 혹은 시험자의 시각으로 <strong>명세화된 기능</strong>을 올바로 수행하는지 알아보는 과정</td>
</tr>
<tr>
<td align="center">확인(Validation)</td>
<td>- 소프트웨어 결과 테스트 <br>- 만들어진 제품이 제대로 동작하는지 확인 <br>- 최종 사용자 요구 또는 소프트웨어 요구에 적합 판단 <br>- <strong>사용자 시각</strong>으로 올바른 소프트웨어가 개발되었는지 입증하는 과정</td>
</tr>
</tbody></table>
<h4 id="④-테스트-목적에-따른-분류">④ 테스트 목적에 따른 분류</h4>
<ul>
<li>회복(Recovery)</li>
<li>안전(Security)</li>
<li>성능(Performance)  <ul>
<li>부하(Load) : 부하 증가, 시스템 <strong>임계점</strong> 찾고, <strong>병목 현상</strong> 제거</li>
<li>강도(Stress) : 처리 <strong>능력 이상</strong> 부하에서 시스템 동작 상태 확인</li>
<li>스파이크(Spike) : <strong>짧은 시간</strong>에 사용자가 몰릴 때 시스템의 <strong>반응</strong> 측정</li>
<li>내구성(Endurance) : <strong>오랜 시간 동안</strong> 높은 부하를 가하여 시스템 반응 확인</li>
</ul>
</li>
<li>구조(Structure)</li>
<li>회귀(Regression)</li>
<li>병행(Parallel)</li>
</ul>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">회복(Recovery)</td>
<td>시스템에 고의로 실패 유도, 시스템 정상 복귀 여부 테스트</td>
</tr>
<tr>
<td align="center">안전(Security)</td>
<td>불법적인 소프트웨어 접근 예방을 위해, 소스 코드 내의 보안적인 결함 미리 점검</td>
</tr>
<tr>
<td align="center">성능(Performance)</td>
<td>사용자 이벤트에 시스템 응답 시간, 특정 시간 내 처리하는 업무량 등을 측정</td>
</tr>
<tr>
<td align="center">구조(Structure)</td>
<td>시스템의 내부 논리 경로, 소스 코드의 복잡도 평가</td>
</tr>
<tr>
<td align="center">회귀(Regression)</td>
<td>오류를 제거하거나 수정한 시스템에서 새로이 유입된 오류가 없는지 확인하는 <strong>반복 테스트</strong></td>
</tr>
<tr>
<td align="center">병행(Parallel)</td>
<td>변경된 시스템과 기존 시스템에 <strong>동일한 데이터 입력</strong> 결과 비교</td>
</tr>
</tbody></table>
<h4 id="⑤-테스트-종류에-따른-분류">⑤ 테스트 종류에 따른 분류</h4>
<ul>
<li>명세 기반 테스트(블랙박스 테스트)</li>
<li>구조 기반 테스트(화이트박스 테스트)</li>
<li>경험 기반 테스트(블랙박스 테스트)
: 유사 소프트웨어나 유사 기술 평가에서 테스터의 경험을 토대로 수행<ul>
<li>탐색적 테스트(Exploratory Test) 
: 문서 X, 휴리스틱한 능력, 구성요소(테스트 차터, 시간 제한, 노트, 회고)</li>
<li>오류 추정(Error Geussing)
: 개발자 실수 추정</li>
</ul>
</li>
</ul>
<h3 id="3-정적-테스트">3) 정적 테스트</h3>
<h4 id="①-리뷰review">① 리뷰(Review)</h4>
<ol>
<li><p>동료 검토(Peer Review)</p>
<ul>
<li>2~3 명이 진행하는 리뷰 형태로, 요구사항 명세서 작성자가 요구사항 명세서를 설명하고, 이해관계자들이 설명을 들으면서 결함 발견</li>
</ul>
</li>
<li><p>인스펙션(Inspection)</p>
<ul>
<li>저작자 외의 <strong>다른 전문가 팀</strong>이 검사하여 문제 식별 및 해결</li>
<li>개발 초기에 검사해야만 개발 초기 작업물에서 문제 발견</li>
<li><strong>관리자</strong> 직책 담당은 멤버 참여 <strong>금지</strong></li>
</ul>
</li>
<li><p>워크 스루(Walk Throughts)</p>
<ul>
<li>검토 자료를 회의 전 배포하여 사전 검토 후, 짧은 시간 동안 회의 진행</li>
<li>결함 검출 및 참가자 교육, 지식 공유</li>
<li>작성자 본인이 회의를 주재하며, <strong>관리자</strong> 직책 담당은 멤버 참여 <strong>금지</strong></li>
</ul>
</li>
</ol>
<h4 id="②-정적-분석static-analysis">② 정적 분석(Static Analysis)</h4>
<ul>
<li>도구의 지원을 받음</li>
<li>자동화된 도구를 이용하여 산출물의 결함 검출, 복잡도 측정</li>
<li>코딩 표준 부합, 코드 복잡도 계산, 자료 흐름 분석</li>
</ul>
<h3 id="4-테스트-오라클">4) 테스트 오라클</h3>
<ul>
<li><p>테스트의 결과가 참인지 거짓인지 판단하기 위해 사전 정의된 참값을 입력하여 비교하는 기법</p>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">참(True) 오라클</td>
<td>모든 입력값에 대해 기대 결과를 생성, 발생된 오류 모두 검출</td>
</tr>
<tr>
<td align="center">샘플링(Sampling) 오라클</td>
<td>특정한 몇 개 입력값에 대해 기대하는 결과를 제공</td>
</tr>
<tr>
<td align="center">휴리스틱(Heuristic) 오라클</td>
<td>샘플링 오라클 개선, 특정 입력값에 올바른 결과 제공, 나머지 값은 휴리스틱(추정)으로 처리</td>
</tr>
<tr>
<td align="center">일관성 검사(Consistent) 오라클</td>
<td>APP 변경 시, 수행 전과 후 결괏값이 동일한지 확인</td>
</tr>
</tbody></table>
</li>
</ul>
<h2 id="02-애플리케이션-테스트-시나리오-작성-⭐⭐">02. 애플리케이션 테스트 시나리오 작성 ⭐⭐</h2>
<h3 id="1-테스트-레벨">1) 테스트 레벨</h3>
<h4 id="①-테스트-레벨test-level">① 테스트 레벨(Test Level)</h4>
<ul>
<li>함께 편성되고 관리되는 테스트 활동 그룹</li>
<li>프로젝트에서 책임과 연관</li>
<li>각각의 테스트 레벨은 서로 <strong>독립적</strong></li>
</ul>
<h4 id="②-테스트-레벨-종류">② 테스트 레벨 종류</h4>
<ul>
<li>단위 테스트<ul>
<li>정적 테스트</li>
<li>동적 테스트</li>
</ul>
</li>
<li>통합 테스트<ul>
<li>하향식 테스트</li>
<li>상향식 테스트</li>
<li>빅뱅 테스트</li>
<li>샌드위치 테스트</li>
</ul>
</li>
<li>시스템 테스트<ul>
<li>기능적 테스트</li>
<li>비기능적 테스트</li>
</ul>
</li>
<li>인수 테스트<ul>
<li>알파 테스트 : 사용자가 개발자 환경에서 함께 수행</li>
<li>베타 테스트 : 실제 환경에서 사용자가 사용</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/3974b018-42b3-4db5-8d0c-3cc1b4d9064c/image.png" alt=""></p>
<h5 id="a-hrefhttpsblognavercombada744222213088535-target_blankqwerty-ncs학습모듈지필-애플리케이션-테스트-관리a"><a href="https://blog.naver.com/bada744/222213088535" target="_blank">[qwerty] [NCS학습모듈/지필] 애플리케이션 테스트 관리</a></h5>
<table>
<thead>
<tr>
<th align="center">종류</th>
<th>설명</th>
<th>기법</th>
</tr>
</thead>
<tbody><tr>
<td align="center">단위 테스트</td>
<td>사용자 요구사항에 대한 단위 모듈, 서브루틴 테스트</td>
<td>정적, 동적 테스트</td>
</tr>
<tr>
<td align="center">통합 테스트</td>
<td>인터페이스, 통합된 컴포넌트 간의 상호 작용 검증</td>
<td>빅뱅, 샌드위치, 상향식, 하향식 테스트</td>
</tr>
<tr>
<td align="center">시스템 테스트</td>
<td>통합된 단위 시스템의 기능이 시스템에서 정상 수행되는지</td>
<td>기능, 비기능 요구사항 테스트</td>
</tr>
<tr>
<td align="center">인수 테스트</td>
<td>요구사항 만족 확인</td>
<td>알파, 베타 테스트</td>
</tr>
</tbody></table>
<h1 id="2-애플리케이션-통합-테스트">2. 애플리케이션 통합 테스트</h1>
<h2 id="01-애플리케이션-테스트-수행">01. 애플리케이션 테스트 수행</h2>
<h3 id="1-단위-테스트">1) 단위 테스트</h3>
<h4 id="①-단위-테스트unit-test">① 단위 테스트(Unit Test)</h4>
<ul>
<li>개별적인 모듈(또는 컴포넌트) 테스트</li>
<li>구현 단계에서 각 모듈을 구현한 후 수행</li>
<li>개별적인 모듈에 대해 컴포넌트 테스트를 수행하려면 모듈을 단독으로 실행할 수 있는 테스트 배드 환경 필요</li>
</ul>
<h4 id="②-단위-테스트-수행-도구">② 단위 테스트 수행 도구</h4>
<ul>
<li>테스트 드라이버(Test Driver)<ul>
<li>모듈 테스트 수행 후 결과를 도출하는 시험용 모듈</li>
<li>필요 테스트를 인자로 넘겨주고, 테스트 완료 후 그 결괏값을 받는 역할을 하는 가상 모듈</li>
<li>하위 모듈을 호출하는 <strong>상위 모듈</strong></li>
</ul>
</li>
<li>테스트 스텁(Test Stub) <ul>
<li>일시적으로 필요한 조건만 가지고 임시로 제공되는 시험용 모듈</li>
<li>상위 모듈에 의해 호출되는 <strong>하위 모듈</strong></li>
</ul>
</li>
</ul>
<h3 id="2-통합-테스트">2) 통합 테스트</h3>
<h4 id="①-통합-테스트integration-test">① 통합 테스트(Integration Test)</h4>
<ul>
<li>소프트웨어 각 모듈 간의 인터페이스 관련 오류 및 결함을 찾아내기 위함</li>
<li>단위 테스트가 끝난 모듈 또는 컴포넌트 단위의 프로그램이 <strong>설계 단계</strong>에서 제시한 애플리케이션과 <strong>동일한 구조와 기능</strong>으로 구현된 것인지 확인</li>
</ul>
<h4 id="②-하향식-통합">② 하향식 통합</h4>
<ul>
<li>메인 제어 모듈로부터 <strong>아래 방향</strong>으로 이동하면서 통합하면서 테스트 진행</li>
<li>&#39;깊이-우선&#39; 또는 &#39;너비-우선&#39; 방식으로 통합</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/767b4003-04ca-421d-8036-e7930fd7d852/image.png" alt=""></p>
<h5 id="a-hrefhttpsshlee1990tistorycom833-target_blank해솔-정보처리기사-실기--19강-애플리케이션-테스트-관리-애플리케이션-통합-테스트하기a"><a href="https://shlee1990.tistory.com/833" target="_blank">[해솔] 정보처리기사 실기 : 19강 애플리케이션 테스트 관리 (애플리케이션 통합 테스트하기)</a></h5>
<h4 id="③-상향식-통합">③ 상향식 통합</h4>
<ul>
<li>최하위 레벨 모듈 또는 컴포넌트로부터 위쪽 방향으로 구축 및 테스트</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/c10f3f39-52ff-4937-aeec-e606fde07ddd/image.png" alt=""></p>
<h5 id="a-hrefhttpsshlee1990tistorycom833-target_blank해솔-정보처리기사-실기--19강-애플리케이션-테스트-관리-애플리케이션-통합-테스트하기a-1"><a href="https://shlee1990.tistory.com/833" target="_blank">[해솔] 정보처리기사 실기 : 19강 애플리케이션 테스트 관리 (애플리케이션 통합 테스트하기)</a></h5>
<h4 id="④-샌드위치-통합">④ 샌드위치 통합</h4>
<ul>
<li>상향식 + 하향식 통합 테스트 결합</li>
<li>하위 프로젝트가 있는 큰 규모의 통합 테스트에서 사용</li>
<li>병렬 테스트 가능, 시간 절약, 기용 소모</li>
</ul>
<h4 id="⑤-통합-테스트-수행-방법-간-비교">⑤ 통합 테스트 수행 방법 간 비교</h4>
<table>
<thead>
<tr>
<th align="center">테스트 방안</th>
<th>빅뱅 테스트</th>
<th>상향식 테스트</th>
<th>하향식 테스트</th>
<th>샌드위치 테스트</th>
</tr>
</thead>
<tbody><tr>
<td align="center">테스트 <br>수행 방법</td>
<td>- 모든 모듈 통시 통합</td>
<td>- 최하위 모듈 부터</td>
<td>- 최상위 모듈부터</td>
<td>- 상위는 하향식+<br>하위는 상향식</td>
</tr>
<tr>
<td align="center">드라이버 <br>/스텁</td>
<td>- 실제 모듈</td>
<td>- 테스트 드라이버</td>
<td>- 테스트 스텁</td>
<td>- 스텁+드라이버</td>
</tr>
<tr>
<td align="center">장점</td>
<td>- 단시간 테스트 가능 <br>- 작은 시스템에 유리</td>
<td>- 장애 위치 파악 쉬움 <br> - 모든 모듈 개발 시간 낭비 없음</td>
<td>- 장애 위치 파악 쉬움 <br> - 이른 프로토타입 가능 <br> - 중요 모듈 선 테스트</td>
<td>- 병렬 테스트 가능 <br>- 시간 절약 <br>- 큰 규모 통합 테스트</td>
</tr>
<tr>
<td align="center">단점</td>
<td>- 장애 위치 파악 어려움 <br>- 모든 모듈 개발 필요</td>
<td>- 중요 모듈 마지막 테스트 <br> - 이른 프로토타입 어려움</td>
<td>- 많은 스텁 필요 <br>- 하위 모듈의 불충분 테스트</td>
<td>- 큰 비용</td>
</tr>
</tbody></table>
<h3 id="3-테스트-자동화-도구">3) 테스트 자동화 도구</h3>
<ul>
<li>테스트 도구를 활용하여 반복적인 테스트 작업을 스크립트 형태로 구현함으로써, 테스트 시간 단축, 인력 투입 비용 최소화</li>
</ul>
<h4 id="①-정적-분석-도구static-analysis-tools">① 정적 분석 도구(Static Analysis Tools)</h4>
<ul>
<li>만들어진 APP을 <strong>실행하지 않고</strong> 분석하는 도구</li>
<li>소스 코드에 대한 코딩 표준, 코딩 스타일, 코드 복잡도 및 남은 결함 발견을 위해 사용</li>
<li><strong>테스트를 수행하는 사람</strong>이 작성된 소스 코드에 대한 이해를 바탕으로 도구를 이용하여 분석</li>
</ul>
<h4 id="②-테스트-실행-도구test-execution-tools">② 테스트 실행 도구(Test Execution Tools)</h4>
<ul>
<li>테스트를 위해 작성된 스크립트 실행, 각 스크립트 마다 특정 데이터와 테스트 수행 방법 포함</li>
<li>데이터 주도 접근 방식 : 테스트 데이터</li>
<li>키워드 주도 접근 방식 : 테스트 수행 동작 키워드</li>
</ul>
<h4 id="③-성능-테스트-도구performance-test-tools">③ 성능 테스트 도구(Performance Test Tools)</h4>
<ul>
<li>APP의 처리량, 응답 시간, 경과 시간, 자원 사용률에 대해 가상의 사용자를 생성하고 테스트를 수행</li>
</ul>
<h4 id="④-테스트-통제-도구test-control-tools">④ 테스트 통제 도구(Test Control Tools)</h4>
<ul>
<li>테스트 계획 및 관리를 위한 테스트 관리 도구</li>
<li>테스트 수행에 필요한 데이터와 도구를 관리하는 형상 관리 도구</li>
<li>테스트에서 발생한 결함에 대해 관리하거나 협업을 지원하기 위한 결함 추적/관리 도구</li>
</ul>
<h4 id="⑤-테스트-하네스">⑤ 테스트 하네스</h4>
<ul>
<li><p>APP 컴포넌트 및 모듈을 테스트하는 환경의 일부분, 테스트 지원 코드 및 데이터, 단위 또는 모듈 테스트에 사용하기 위해 <strong>코드 개발자</strong>가 작성</p>
<table>
<thead>
<tr>
<th align="center">구성요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">테스트 드라이버 <br>(Test Driver)</td>
<td>테스트 대상 하위 모듈 호출, 파라미터 전달, 테스트 수행 후 결과 도출 등 <strong>상향식 테스트</strong>에 필요</td>
</tr>
<tr>
<td align="center">테스트 스텁 <br>(Test Stub)</td>
<td>제어 모듈이 호출하는 타 모듈의 기능을 단순히 수행하는 도구로 <strong>하향식 테스트</strong>에 필요</td>
</tr>
<tr>
<td align="center">테스트 슈트 <br>(Test Suites)</td>
<td>테스트 대상 컴포넌트나 모듈, 시스템에 사용되는 테스트 케이스 집합</td>
</tr>
<tr>
<td align="center">테스트 케이스 <br>(Test Case)</td>
<td>입력값, 실행 조건, 기대 결과 등의 집합</td>
</tr>
<tr>
<td align="center">테스트 시나리오 <br>(Test Scenario)</td>
<td>테스트 되어야 할 기능 및 특징, 테스트가 필요한 상황 작성 문서, 여러 개 테스트 케이스 포함 가능</td>
</tr>
<tr>
<td align="center">테스트 스크립트 <br>(Test Script)</td>
<td>자동화된 테스트 실행 절차에 대한 명세</td>
</tr>
<tr>
<td align="center">목 오브젝트 <br>(Mock Object)</td>
<td>사용자의 행위를 조건부로 사전에 입력해 두면, 그 상황에 예정된 행위를 수행하는 객체</td>
</tr>
</tbody></table>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[정보처리기사 실기] 2. 데이터 입출력 구현]]></title>
            <link>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-2.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-2.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Sat, 27 Jul 2024 10:03:19 GMT</pubDate>
            <description><![CDATA[<h1 id="1-논리-데이터-저장소-확인">1. 논리 데이터 저장소 확인</h1>
<h2 id="01-데이터-모델">01. 데이터 모델</h2>
<h3 id="1-데이터-모델data-model">1) 데이터 모델(Data Model)</h3>
<ul>
<li>현실 세계의 정보를 인간과 컴퓨터가 이해할 수 있도록 <strong>추상화</strong>하여 표현한 모델</li>
<li>데이터 모델 표시요소</li>
</ul>
<table>
<thead>
<tr>
<th align="center">표시요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">연산 <br>(Operation)</td>
<td>- 데이터베이스에 저장된 실제 데이터를 <strong>처리</strong>하는 작업에 대한 명세 <br>- 릴레이션을 조작하기 위한 <strong>관계 연산</strong>을 나타냄(SELECT, PROJECT, JOIN, DIVISION)</td>
</tr>
<tr>
<td align="center">구조 <br>(Structure)</td>
<td>- 데이터베이스에 논리적으로 표현될 대상으로서의 개체 타입과 개체 타입 간의 <strong>관계</strong><br>- <strong>데이터 구조</strong> 및 <strong>정적 성질</strong>을 표현</td>
</tr>
<tr>
<td align="center">제약 조건 <br>(Constraint)</td>
<td>- 데이터베이스에 저장될 수 있는 실제 데이터의 <strong>논리적인 제약 조건</strong> <br>- 데이터 무결성 유지를 위한 DB의 보편적인 방법 <br>- 릴레이션의 <strong>특정 칼럼에 설정</strong>하는 제약을 의미(개체 무결성, 참조 무결성 등)</td>
</tr>
</tbody></table>
<h3 id="2-데이터-모델링-절차">2) 데이터 모델링 절차</h3>
<h4 id="①-개념적-설계개념적-데이터-모델">① 개념적 설계(개념적 데이터 모델)</h4>
<ul>
<li>사용자의 요구에 대한 트랜잭션을 모델링</li>
<li>현실 세계에 대한 인식을 추상적, 개념적으로 표현하여 <strong>개념적 구조</strong>를 도출<blockquote>
<ul>
<li>트랜잭션 모델링, View 통합방법 및 Attribute 합성 고려</li>
<li>개념적 데이터 모델은 DB 종류와 관계 없음</li>
<li>주요 산출물은 <strong>개체관계 다이어그램(ERD)</strong>이 있음</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/51bd439f-5e70-47e5-a233-5611f611ccd5/image.png" alt=""></p>
<h6 id="a-hrefhttpsmangkyutistorycom27-target_blankmangkyus-diary티스토리-database-6-데이터-모델링data-modelinga"><a href="https://mangkyu.tistory.com/27" target="_blank">[MangKyu&#39;s Diary:티스토리] [Database] 6. 데이터 모델링(Data Modeling)</a></h6>
<h4 id="②-논리적-설계논리적-데이터-모델">② 논리적 설계(논리적 데이터 모델)</h4>
<ul>
<li>트랜잭션의 인터페이스를 설계하는 단계</li>
<li>DBMS에 맞는 <strong>논리적 스키마</strong>를 설계하는 단계</li>
<li>업무의 모습을 모델링 표기법으로 형상화하여 사람이 이해하기 쉽게 표현한 데이터 모델<blockquote>
<ul>
<li><strong>정규화</strong> 수행</li>
<li>논리적 데이터베이스 구조로 매핑</li>
<li>스키마의 평가 및 정제</li>
<li>논리적 데이터 모델링 중 하나에 맞게 설계</li>
<li>관계형 데이터베이스에서는 테이블을 설계하는 단계</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/bc0a9525-f4c9-4d1a-b27a-dfcc800aea8f/image.png" alt=""></p>
<h6 id="a-hrefhttpsmangkyutistorycom27-target_blankmangkyus-diary티스토리-database-6-데이터-모델링data-modelinga-1"><a href="https://mangkyu.tistory.com/27" target="_blank">[MangKyu&#39;s Diary:티스토리] [Database] 6. 데이터 모델링(Data Modeling)</a></h6>
<h4 id="③-물리적-설계물리적-데이터-모델">③ 물리적 설계(물리적 데이터 모델)</h4>
<ul>
<li>논리 데이터 모델을 특정 DBMS의 특성 및 성능을 고려하여 <strong>물리적인 스키마</strong>를 만드는 단계</li>
<li><strong>데이터베이스 저장 구조</strong>(물리 데이터 모델)로 변환<blockquote>
<ul>
<li>Table, Index, View, Partition 등 객체를 생성</li>
<li>응답시간, 저장 공간의 효율화, 트랜잭션 처리를 고려하여 설계</li>
<li>성능 측면에서 <strong>반 정규화</strong>를 수행</li>
<li>레코드 집중의 분석 및 설계</li>
<li>저장 레코드 양식 설계</li>
<li>접근 경로(Access Path) 설계</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/13de8163-aefe-495b-841d-313fd6499c86/image.png" alt=""></p>
<h6 id="a-hrefhttpsmangkyutistorycom27-target_blankmangkyus-diary티스토리-database-6-데이터-모델링data-modelinga-2"><a href="https://mangkyu.tistory.com/27" target="_blank">[MangKyu&#39;s Diary:티스토리] [Database] 6. 데이터 모델링(Data Modeling)</a></h6>
<h2 id="02-논리-데이터-모델-검증">02. 논리 데이터 모델 검증</h2>
<h3 id="1-정규화normalization">1) 정규화(Normalization)</h3>
<ul>
<li><strong>관계형 데이터 모델</strong>에서 데이터의 <strong>중복성</strong>을 제거하여 <strong>이상 현상</strong>을 방지하고, 데이터의 일관성과 정확성을 유지하기 위해 무손실 <strong>분해</strong>하는 </li>
</ul>
<h4 id="①-이상현상anomaly-⭐">① 이상현상(Anomaly) ⭐</h4>
<ul>
<li>데이터의 <strong>중복성</strong>으로 인해 <strong>릴레이션</strong>을 조작할 때 발생하는 비합리적 현상</li>
</ul>
<table>
<thead>
<tr>
<th align="center">이상현상</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">삽입 이상</td>
<td>정보 저장 시 해당 정보의 <strong>불필요한 세부정보를 입력</strong>해야 하는 경우</td>
</tr>
<tr>
<td align="center">삭제 이상</td>
<td>정보 삭제 시 <strong>원치 않는 다른 정보</strong>가 같이 삭제되는 경우</td>
</tr>
<tr>
<td align="center">갱신 이상</td>
<td>중복 데이터 중에서 <strong>특정 부분만 수정</strong>되어 중복된 값이 모순을 일으키는 경우</td>
</tr>
</tbody></table>
<p>[이상 현상 설명 테이블]</p>
<table>
<thead>
<tr>
<th align="center">학번</th>
<th align="center">이름</th>
<th align="center">교수번호</th>
<th align="center">지도교수</th>
</tr>
</thead>
<tbody><tr>
<td align="center">201901</td>
<td align="center">홍길동</td>
<td align="center">1</td>
<td align="center">김교수</td>
</tr>
<tr>
<td align="center">201902</td>
<td align="center">김영희</td>
<td align="center">2</td>
<td align="center">이교수</td>
</tr>
</tbody></table>
<p>[삽입 이상]</p>
<table>
<thead>
<tr>
<th align="center">학번</th>
<th align="center">이름</th>
<th align="center">교수번호</th>
<th align="center">지도교수</th>
</tr>
</thead>
<tbody><tr>
<td align="center">201901</td>
<td align="center">홍길동</td>
<td align="center">1</td>
<td align="center">김교수</td>
</tr>
<tr>
<td align="center">201902</td>
<td align="center">김영희</td>
<td align="center">2</td>
<td align="center">이교수</td>
</tr>
<tr>
<td align="center">201903</td>
<td align="center">이철수</td>
<td align="center">?</td>
<td align="center">?</td>
</tr>
<tr>
<td align="center">→ 지도교수가 정해지지 않으면 삽입할 수 없음</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
</tbody></table>
<p>[삭제 이상]</p>
<table>
<thead>
<tr>
<th align="center">학번</th>
<th align="center">이름</th>
<th align="center">교수번호</th>
<th align="center">지도교수</th>
</tr>
</thead>
<tbody><tr>
<td align="center">201901</td>
<td align="center">홍길동</td>
<td align="center">1</td>
<td align="center">김교수</td>
</tr>
<tr>
<td align="center"><del>201902</del></td>
<td align="center"><del>김영희</del></td>
<td align="center"><del>2</del></td>
<td align="center"><del>이교수</del></td>
</tr>
<tr>
<td align="center">→ &#39;이 교수&#39;라는 교수가 퇴사할 경우 &#39;김영희&#39; 학생 정보도 같이 삭제</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
</tbody></table>
<p>[갱신 이상]</p>
<table>
<thead>
<tr>
<th align="center">학번</th>
<th align="center">이름</th>
<th align="center">교수번호</th>
<th align="center">지도교수</th>
</tr>
</thead>
<tbody><tr>
<td align="center">201901</td>
<td align="center">홍길동</td>
<td align="center">3</td>
<td align="center">박교수</td>
</tr>
<tr>
<td align="center">201902</td>
<td align="center">김영희</td>
<td align="center">2</td>
<td align="center">이교수</td>
</tr>
</tbody></table>
<p>→ &#39;홍길동&#39;의 지도교수가 &#39;박교수&#39;로 바뀌면 &#39;김교수&#39;의 정보가 사라짐</p>
<h4 id="③-함수-종속">③ 함수 종속</h4>
<ul>
<li>릴레이션에서 속성의 의미와 속성 간 상호 관계로부터 발생하는 제약조건</li>
</ul>
<ol>
<li><p>결정자/종속자</p>
<ul>
<li>X → Y 관계일 때 X는 결정자(Determinant), Y는 종속자(Dependent)</li>
</ul>
</li>
<li><p>함수 종속 종류</p>
<table>
<thead>
<tr>
<th align="center">종류</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">부분 함수 종속 <br>(Partial Functional <br>Dependency)</td>
<td>릴레이션에서 <strong>기본 키가 복합 키</strong>일 경우 기본 키를 구성하는 속성 중 <strong>일부</strong>에게 종속</td>
</tr>
<tr>
<td align="center">완전 함수 종속 <br>(Full Functional <br>Dependency)</td>
<td>릴레이션에서 X → Y 관계가 있을 때, Y는 X의 <strong>전체 속성</strong>에 대해 종속하고, <br><strong>부분 집합 속성</strong>에 종속하지 않는 경우</td>
</tr>
<tr>
<td align="center">이행 함수 종속 <br>(Transitive Functional <br>Dependency)</td>
<td>릴레이션에서 X → Y, Y → Z 종속 관계가 있을 때,** X → Z** 가 성립되는 경우</td>
</tr>
</tbody></table>
</li>
</ol>
<h4 id="④-정규화-단계">④ 정규화 단계</h4>
<table>
<thead>
<tr>
<th align="center">단계</th>
<th>조건</th>
</tr>
</thead>
<tbody><tr>
<td align="center">1정규형(1NF)</td>
<td>원자값으로 구성</td>
</tr>
<tr>
<td align="center">2정규형(2NF)</td>
<td>부분 함수 종속 제거(완전 함수적 종속 관계)</td>
</tr>
<tr>
<td align="center">3정규형(3NF)</td>
<td>이행 함수 종속 제거</td>
</tr>
<tr>
<td align="center">보이스-코드 정규형(BCNF)</td>
<td>결정자 후보 키가 아닌 함수 종속 제거</td>
</tr>
<tr>
<td align="center">4정규형(4NF)</td>
<td>다치(다중 값) 종속 제거</td>
</tr>
<tr>
<td align="center">5정규형(5NF)</td>
<td>조인 종속 제거</td>
</tr>
</tbody></table>
<ol>
<li><p>1차 정규화(1NF)</p>
<p> <img src="https://velog.velcdn.com/images/cey_adda/post/cdd7747a-b231-453a-b75e-6ddf71ef50b1/image.jpg" alt=""></p>
<h6 id="a-hrefhttpsmangkyutistorycom110-target_blankmangkyus-diary티스토리-database-정규화normalization-쉽게-이해하기a"><a href="https://mangkyu.tistory.com/110" target="_blank">[MangKyu&#39;s Diary:티스토리] [Database] 정규화(Normalization) 쉽게 이해하기</a></h6>
<p>→ 취미가 속성에 2개 이상 가지고 있는 경우 <strong>원자값</strong>이 아니기 때문에 속성 1개만 가지도록 저장</p>
</li>
<li><p>2차 정규화(2NF)</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/29f88dee-db66-434c-a74e-9ee89be10557/image.jpg" alt=""></p>
<h6 id="a-hrefhttpsmangkyutistorycom110-target_blankmangkyus-diary티스토리-database-정규화normalization-쉽게-이해하기a-1"><a href="https://mangkyu.tistory.com/110" target="_blank">[MangKyu&#39;s Diary:티스토리] [Database] 정규화(Normalization) 쉽게 이해하기</a></h6>
<p>→ &lt;학생번호, 강좌이름&gt;이 &lt;성적&gt;에 영향을 주고, &lt;강좌이름&gt;이 &lt;강의실&gt;에 영향을 주는 관계를 <strong>&#39;부분함수 종속 관계&#39;</strong>
→ 부분 관계인 &lt;강좌이름, 강의실&gt; 관계를 별도의 테이블로 둠</p>
</li>
<li><p>3차 정규화(3NF)</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/3e4dcc32-ba2c-433d-9c43-46a32d59fcf1/image.jpg" alt=""></p>
<h6 id="a-hrefhttpsmangkyutistorycom110-target_blankmangkyus-diary티스토리-database-정규화normalization-쉽게-이해하기a-2"><a href="https://mangkyu.tistory.com/110" target="_blank">[MangKyu&#39;s Diary:티스토리] [Database] 정규화(Normalization) 쉽게 이해하기</a></h6>
<p>→ &lt;학생번호&gt;가 &lt;강좌이름&gt;에 영향을 주고, &lt;강좌이름&gt;이 &lt;수강료&gt;에 영향을 주는 관계를 <strong>&#39;이행함수 종속 관계&#39;</strong>
→ &lt;학생번호&gt;는 &lt;수강료&gt;에 직접 영향을 주는 관계가 아니기에 &lt;학생번호, 강좌이름&gt; &lt;강좌이름, 수강료&gt; 테이블로 분리</p>
</li>
<li><p>보이스-코드 정규화(BCNF)</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/4a69e628-b098-4df9-8cdd-9726ba60dbb7/image.jpg" alt=""></p>
<h6 id="a-hrefhttpsmangkyutistorycom110-target_blankmangkyus-diary티스토리-database-정규화normalization-쉽게-이해하기a-3"><a href="https://mangkyu.tistory.com/110" target="_blank">[MangKyu&#39;s Diary:티스토리] [Database] 정규화(Normalization) 쉽게 이해하기</a></h6>
<p>→ &lt;학생번호, 특강이름&gt;이 &lt;교수&gt;에 영향을 주고, &lt;교수&gt;가 &lt;특강이름&gt;에 영향을 주는 관계로서, &lt;교수&gt;는 키가 아닌 상황이므로 결정자인 &lt;교수&gt;가 <strong>후보키</strong>가 아님
→ &lt;교수, 특강이름&gt; 테이블로 분리하여 교수가 <strong>후보키</strong> 역할을 하도록 함</p>
</li>
</ol>
<h3 id="2-반-정규화de-normalization">2) 반 정규화(De-Normalization)</h3>
<ul>
<li>정규화된 엔터티, 속성, 관계에 대해 성능 향상과 개발 운영의 단순화를 위해 중복, 통합, 분리 등을 수행</li>
<li>비정규화 역정규화라고도 불림</li>
<li>장점 <ul>
<li>반 정규화된 데이터 구조는 성능 향상과 관리의 효율성 증가</li>
</ul>
</li>
<li>단점<ul>
<li>데이터의 일관성 및 정합성 저하</li>
<li>유지를 위한 비용이 별도로 발생하여 성능에 나쁜 영향</li>
</ul>
</li>
</ul>
<h4 id="①-반-정규화-기법">① 반 정규화 기법</h4>
<ul>
<li>테이블<ul>
<li>테이블 병합</li>
<li>데이블 분할</li>
<li>중복 테이블 추가</li>
</ul>
</li>
<li>컬럼<ul>
<li>컬럼 중복화</li>
</ul>
</li>
<li>관계<ul>
<li>중복관계 추가</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[정보처리기사 실기] 8. SQL 응용]]></title>
            <link>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-8.-SQL-%EC%9D%91%EC%9A%A9</link>
            <guid>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-8.-SQL-%EC%9D%91%EC%9A%A9</guid>
            <pubDate>Thu, 25 Jul 2024 14:45:30 GMT</pubDate>
            <description><![CDATA[<h1 id="1-데이터베이스-기본">1. 데이터베이스 기본</h1>
<h2 id="span-stylebackground-colorfff5b101-트랜잭션-⭐⭐⭐span"><span style="background-color:#fff5b1">01. 트랜잭션 ⭐⭐⭐</span></h2>
<h3 id="1-트랜잭션">1) 트랜잭션</h3>
<h4 id="①-트랜잭션">① 트랜잭션</h4>
<ul>
<li>인가받지 않은 사용자로부터 데이터를 보장하기 위해 DBMS가 가져야 하는 특성이자, 데이터베이스 시스템에서 하나의 논리적 기능을 정상적으로 수행하기 위한 작업의 기본 단위</li>
</ul>
<h4 id="②-트랜잭션의-특성-⭐-acid">② 트랜잭션의 특성 ⭐ ACID</h4>
<table>
<thead>
<tr>
<th align="center">특성</th>
<th>설명</th>
<th>주요기법</th>
</tr>
</thead>
<tbody><tr>
<td align="center">원자성<br>(Atomicity)</td>
<td>- 트랜잭션을 구성하는 연산 전체가 모두 정상적으로 실행되거나 <br>모두 취소되어야 하는 성질 <br>- 트랜잭션의 연산 전체가 성공 또는 실패(All or Nothing) <br>되어야 하는 성질</td>
<td>- Commit/Rollback <br>- 회복성 보장</td>
</tr>
<tr>
<td align="center">일관성<br>(Consistency)</td>
<td>- 시스템이 가지고 있는 고정요소는 트랜잭션 수행 전과 <br>트랜잭션 수행 완료 후의 상태가 같아야 하는 성질</td>
<td>- 무결성 제약조건 <br>- 동시성 제어</td>
</tr>
<tr>
<td align="center">격리성=고립성<br>(Isolation)</td>
<td>- 동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않아야 한다는 성질</td>
<td>- Read Uncommitted <br>- Read Commited<br>- Repeatable Read <br>- Serializable</td>
</tr>
<tr>
<td align="center">영속성<br>(Durability)</td>
<td>- 성공이 완료된 트랜잭션의 결과는 영속적으로 데이터베이스에 <br>저장되어야 하는 성질</td>
<td>- 회복 기법</td>
</tr>
</tbody></table>
<h4 id="③-트랜잭션의-상태-변화">③ 트랜잭션의 상태 변화</h4>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/61c8f605-39bc-4eef-994f-85ba977142d8/image.png" alt=""></p>
<p><a href="https://thebook.io/006977/0277/" target="_blank">[모두의 SQL] 트랜잭션의 상태 변화와 트랜잭션 제어어</a></p>
<ul>
<li>실행(active) : 트랜잭션이 실행 중</li>
<li>부분 완료(partially committed) : DML 등 트랜잭션의 마지막 명령을 실행한 후</li>
<li>완료(committed) : 트랜잭션이 성공적으로 완료</li>
<li>실패(failed) : 더 이상 정상적으로 실행될 수 없음을 발견</li>
<li>철회(aborted) : 트랜잭션이 복원되어 트랜잭션 수행 이전 상태로 돌아감</li>
</ul>
<h4 id="④-트랜잭션-제어">④ 트랜잭션 제어</h4>
<ul>
<li>트랜잭션 제어언어는 <strong>TCL</strong>(Transaction Control Language)이라고 하며, 트랜잭션의 결과를 허용하거나 취소하는 목적으로 사용되는 언어를 지칭</li>
</ul>
<table>
<thead>
<tr>
<th align="center">명령어</th>
<th>핵심</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">COMMIT</td>
<td>트랜잭션 확정</td>
<td>트랜잭션을 메모리에 영구적으로 저장하는 명령어</td>
</tr>
<tr>
<td align="center">ROLLBACK</td>
<td>트랜잭션 취소</td>
<td>트랜잭션 내역을 저장 무효화시키는 명령어</td>
</tr>
<tr>
<td align="center">CHECKPOINT</td>
<td>저장 시기 설정</td>
<td>ROLLBACK을 위한 시점을 지정하는 명령어</td>
</tr>
</tbody></table>
<h4 id="⑤-병행-제어일관성-주요-기법">⑤ 병행 제어(<em>일관성</em> 주요 기법)</h4>
<ol>
<li><p>병행 제어의 목적</p>
<ul>
<li>데이터베이스의 공유를 최대화</li>
<li>시스템의 활용도를 최대화</li>
<li>데이터베이스의 일관성 유지</li>
<li>사용자에 대한 응답시간 회소화</li>
</ul>
</li>
<li><p>병행 제어 미보장 시 문제점</p>
<ul>
<li><strong>갱신 손실(Lost Update) **
: 먼저 실행된 트랜잭션의 결과를 나중에 실행된 트랜잭션이 **덮어 쓸 때</strong> 발생하는 오류</li>
<li><strong>현황 파악오류(Dirty Read) **
: 트랜잭션의 **중간 수행 결과</strong>를 다른 트랜잭션이 <strong>참조</strong>하여 발생하는 오류</li>
<li><strong>모순성(Inconsistency) **
: 두 트랜잭션이 **동시에 실행</strong>되어 데이터베이스의 일관성이 결여되는 오류</li>
<li><strong>연쇄복귀(Cascading Rollback) **
: 복수의 트랜잭션이 데이터 공유 시 특정 트랜잭션이 처리를 취소할 경우 트랜잭션이 처리한 곳의 **부분을 취소하지 못하는</strong> 오류</li>
</ul>
</li>
<li><p>병행 제어 기법 종류</p>
<table>
<thead>
<tr>
<th align="center">기법</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">로킹 <br>(Locking)</td>
<td>하나의 트랜잭션을 실행하는 동안 특정 데이터 항목에 대해서 다른 트랜잭션이 <br>동시에 접근하지 못하도록 상호배제 기능을 제공하는 기법</td>
</tr>
<tr>
<td align="center">낙관적 검증 <br>(Optimistic Validation)</td>
<td>트랜잭션이 어떠한 검증도 수행하지 않고 일단 트랜잭션을 수행하고, <br>트랜잭션 종료 시 검증을 수행하여 데이터베이스에 반영하는 기법</td>
</tr>
<tr>
<td align="center">타임 스탬프 순서 <br>(Time Stamp Ordering)</td>
<td>트랜잭션과 트랜잭션이 읽거나 갱신한 데이터에 대해 트랜잭션이 실행을 시작하기 <br>전에 타임 스탬프를 부여하여 부여된 시간에 따라 트랜잭션 작업을 수행하는 기법</td>
</tr>
<tr>
<td align="center">다중버전 동시성 제어 <br>(MVCC; Multi Version <br>Concurrency Control)</td>
<td>트랜잭션의 타임스탬프와 접근하려는 데이터의 타임스탭프를 비교하여 <br>직렬가능성이 보장되는 적절한 버전을 선택하여 접근하도록 하는 기법</td>
</tr>
<tr>
<td align="center">#### ⑥ 데이터베이스 고립화 수준(<em>격리성</em> 주요 기법)</td>
<td></td>
</tr>
</tbody></table>
</li>
</ol>
<ul>
<li>다른 트랜잭션이 현재의 데이터에 대한 무결성을 해치지 않기 위해 잠금을 설정하는 정도<ul>
<li>Read Uncommitted
: 한 트랜잭션에서 연산(갱신) 중인(아직 커밋되지 않은) 데이터를 다른 트랜잭션이 읽는 것을 허용, 연산은 불허</li>
<li>Read Committed
: 한 트랜잭션에서 연산(갱신)을 수행할 때, 연산이 완료될 때까지 연산 대상 데이터에 대한 읽기를 제한, 연산이 완료되어 커밋된 데이터는 다른 트랜잭션이 읽는 것을 허용</li>
<li>Repeatable Read
: 선행 트랜잭션이 특정 데이터를 읽을 때, 트랜잭션 종료 시까지 해당 데이터에 대한 갱신/삭제를 제한</li>
<li>Serializable Read
: 선행 트랜잭션이 특정 데이터 영역을 순차적으로 읽을 때, 해당 데이터 영역 전체에 대한 접근을 제한</li>
</ul>
</li>
</ul>
<h4 id="⑦-회복-기법영속성-주요-기법-⭐">⑦ 회복 기법(<em>영속성</em> 주요 기법) ⭐</h4>
<ul>
<li><p>트랜잭션을 수행하는 도중 장애로 인해 속상된 데이터베이스를 손상되기 이전의 정상적인 상태로 복구시키는 작업</p>
</li>
<li><p><strong>REDO</strong></p>
<ul>
<li>데이터베이스가 비정상적으로 종료되었을 때 디스크에 저장된 <strong>로그</strong>를 분석하여 트랜잭션의 <strong>시작과 완료에 대한 기록</strong>이 있는 트랜잭션들의 작업을 <strong>재작업</strong>하는 기법</li>
<li>데이터베이스 내용 자체가 손상된 경우, 가장 최근의 <strong>복제본</strong>을 적재한 후 일어난 변경만을 로그를 이용하여 <strong>재실행</strong>함으로써 데이터베이스 복원</li>
</ul>
</li>
<li><p><strong>UNDO</strong></p>
<ul>
<li>데이터베이스가 비정상적으로 종료되었을 때 디스크에 저장된 <strong>로그</strong>를 분석하여 트랜잭션의 시작은 있지만, <strong>완료에 대한 기록이 없는</strong> 트랜잭션들이 작업한 변경 내용들을 모두 <strong>취소</strong>하는 기법</li>
<li>데이터베이스 내용 자체는 손상되지 않았지만, 변경 중이거나 변경된 내용에 대한 신뢰성을 잃어버린 경우, <strong>모든 변경 내용을 취소</strong>하여 복원하는 기법</li>
</ul>
</li>
<li><p>회복 기법 종류</p>
<ul>
<li>로그 기반 회복 기법 <ul>
<li>지연 갱신 회복 기법(Deffered Update) 
: 트랜잭션이 완료되기 전까지 데이터베이스에 <strong>기록하지 않는</strong> 기법</li>
<li>즉각 갱신 회복 기법(Immediate Update)
: 트랜잭션 수행 중 갱신 결과를 <strong>바로</strong> DB에 반영하는 기법</li>
</ul>
</li>
<li>체크 포인트 회복 기법(Checkpoint Recovery) 
: 장애 발생 시 <strong>검사점</strong> 이후에 처리된 트랜잭션에 대해서만 장애 발생 <strong>이전의 상태로 복원</strong>시키는 회복 기법</li>
<li>그림자 페이징 회복 기법(Shadow Paging Recovery)
: 데이터베이스 트랜잭션 수행 시 <strong>복제본</strong>을 생성하여 데이터베이스 장애 시 이를 이용해 복구하는 방법</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/6ee55fd8-2f78-4dfc-b122-3d2fe07f730f/image.png" alt=""></p>
<p><a href="https://artist-developer.tistory.com/39" target="_blank">출처 : https://artist-developer.tistory.com/39</a></p>
<h3 id="2-ddl">2) DDL</h3>
<h4 id="①-데이터-정의어ddl-data-definition-language">① 데이터 정의어(DDL; Data Definition Language)</h4>
<ul>
<li>데이터를 담는 그릇을 정의하는 언어</li>
<li>테이블과 같은 데이터 구조를 정의</li>
</ul>
<h4 id="②-ddl의-대상">② DDL의 대상</h4>
<table>
<thead>
<tr>
<th align="center">DDL 대상</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">도메인 <br>(Domain)</td>
<td>- 하나의 속성이 가질 수 있는 원자값들의 집합 <br>- 속성의 데이터 타입과 크기, 제약조건 등의 정보</td>
</tr>
<tr>
<td align="center">스키마 <br>(Schema)</td>
<td>- 데이터베이스의 구조, 제약조건 등의 정보를 담고 있는 기본적인 구조</td>
</tr>
<tr>
<td align="center">테이블 <br>(Table)</td>
<td>- 데이터 저장 공간</td>
</tr>
<tr>
<td align="center">뷰 <br>(View)</td>
<td>- 하나 이상의 물리 테이블에서 유도되는 가상의 테이블</td>
</tr>
<tr>
<td align="center">인덱스 <br>(Index)</td>
<td>- 검색을 빠르게 하기 위한 데이터 구조</td>
</tr>
</tbody></table>
<ol>
<li><p>스키마(Schema)</p>
<p>ⓐ 스키마의 구성</p>
<table>
<thead>
<tr>
<th align="center">계층</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">외부 스키마 <br>(External Schema)</td>
<td>- 사용자나 개발자의 관점에서 필요로 하는 데이터베이스의 논리적 구조 <br>- 사용자 뷰를 나타냄 <br>- 서브 스키마로 불림</td>
</tr>
<tr>
<td align="center">개념 스키마 <br>(Conceptual Schema)</td>
<td>- 데이터베이스의 전체적인 논리적 구조 <br>- 전체적인 뷰를 나타냄 <br>- 개체 간의 관계, 제약조건, 접근 권한, 무결성, 보안에 대해 정의</td>
</tr>
<tr>
<td align="center">내부 스키마 <br>(Internal Schema)</td>
<td>- 물리적 저장 장치의 관점에서 보는 데이터베이스 구조 <br>- 실제로 데이터베이스에 저장될 레코드의 형식을 정의하고 저장 데이터 항목의 표현 방법, <br>내부 레코드의 물리적 순서 등을 표현</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/fc215076-8dcd-4383-8a25-3326358843ba/image.png" alt=""></p>
<p><a href="https://terms.tta.or.kr/dictionary/dictionaryView.do?subject=%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4+%EC%8A%A4%ED%82%A4%EB%A7%88" target="_blank">출처 : [정보통신용어사전] 데이터베이스 스키마, database schema</a></p>
</li>
<li><p>테이블(Table)</p>
<p>ⓐ 테이블의 개념</p>
<ul>
<li>테이블은 데이터를 저장하는 항목인 필드(Field)들로 구성된 데이터의 집합체</li>
<li>하나의 DB 내에 여러 개의 테이블로 구성될 수 있고, 릴레이션(Relation) 혹은 엔터티(Entity)라고도 불림</li>
</ul>
<p>ⓑ 테이블의 용어</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/ae4791fc-b123-4f62-a590-48b907f75dcf/image.png" alt=""></p>
<p><a href="https://inpa.tistory.com/entry/DB-%F0%9F%93%9A-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%9A%A9%EC%96%B4-%F0%9F%95%B5%EF%B8%8F-%EC%A0%95%EB%A6%AC" target="_blank">출처 : [Inpa Dev] [DB] 📚 테이블 용어 🕵️ 정리</a></p>
</li>
</ol>
<table>
<thead>
<tr>
<th align="center">계층</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">튜플(Tuple) / 행(Row)</td>
<td>- 테이블 내의 행을 의미하여 레코드(Record)라고도 함 <br>- 튜플은 릴레이션(Realtion)에서 같은 값을 가질 수 없음 <br>- 행의 개수를 <strong>카디널리티(Cardinality)</strong>라고 함</td>
</tr>
<tr>
<td align="center">애트리뷰트(Attribute) <br> / 열(Column)</td>
<td>- 테이블 내의 열을 의미 <br>- 열의 개수를 <strong>차수(Degree)</strong>라고 함</td>
</tr>
<tr>
<td align="center">식별자(Identifier)</td>
<td>- 여러 개의 집합체를 담고 있는 관계형 데이터베이스에서 각각의 구분할 수 있는 논리적인 집합</td>
</tr>
<tr>
<td align="center">도메인(Domain)</td>
<td>- 하나의 애트리뷰트가 취할 수 있는 같은 타입의 원자값 들의 집합</td>
</tr>
</tbody></table>
<ol start="3">
<li><p>뷰(View)</p>
<p>ⓐ 뷰의 개념</p>
<ul>
<li>뷰는 논리 테이블로서 사용자에게(생성 관점 아닌 사용 관점에서) 테이블과 동일</li>
<li>뷰와 같은 결과를 만들기 위해 <strong>조인</strong> 기능을 활용할 수 있으나, 뷰가 만들어져 있다면 사용자는 조인 없이 하나의 테이블을 대상으로 하는 단순한 질의어를 사용할 수 있음</li>
<li>아래 그림에서 왼쪽 &#39;Theater&#39;, &#39;Opera&#39;, &#39;Cinema&#39;는 <strong>물리 테이블</strong>을 의미하고, &#39;Executed View&#39;는 세 개의 테이블을 이용하여 생성한 <strong>뷰</strong>를 의미
<img src="https://velog.velcdn.com/images/cey_adda/post/5c4287d4-8abb-4cd2-827b-3dba0efd8c9a/image.png" alt="">
<a href="https://learnsql.com/blog/sql-view/" target="_blank">출처 : [Learn Sql] What is an SQL View?</a></li>
</ul>
<p>ⓑ 뷰의 특징</p>
<table>
<thead>
<tr>
<th align="center">특징</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">논리적 데이터 독립성 제공</td>
<td>데이터베이스에 <strong>영향을 주지 않고</strong> 애플리케이션이 원하는 형태로 데이터에 접근 가능</td>
</tr>
<tr>
<td align="center">데이터 조작 연산 간소화</td>
<td>애플리케이션이 원하는 형태의 논리적 구조를 형성하여 데이터 조작 <strong>연산을 간소화</strong> <br> 예) 회원 테이블에서 우수 회원을 뷰로 생성하여 활용</td>
</tr>
<tr>
<td align="center">보안 기능(접근제어) 제공</td>
<td>특정 필드만을 선택해 뷰를 생성할 경우 애플리케이션은 <strong>선택되지 않은</strong> 필드의 조회 및 접근 불가</td>
</tr>
<tr>
<td align="center">뷰 변경 불가</td>
<td>뷰 정의는 <strong>ALTER</strong> 문을 이용하여 변경할 수 없음 <br> (뷰는 <strong>CREATE</strong> 문을 사용하여 정의, 뷰를 제거할 때에는 <strong>DROP</strong> 문을 사용)</td>
</tr>
</tbody></table>
<p>ⓒ 뷰의 목적</p>
<ul>
<li>뷰를 사용하는 주된 이유는 단순 <strong>질의어</strong>를 사용할 수 있기 때문</li>
<li>FROM 절에 있는 <strong>하나의 뷰</strong>를 통해 뷰를 구성하는 복수의 테이블을 대체하는 <strong>단순성</strong>에 의의</li>
<li>장점<ul>
<li>논리적 독립성 제공</li>
<li>사용자 데이터 관리 용이</li>
<li>데이터 보안의 용이</li>
</ul>
</li>
<li>단점<ul>
<li>뷰 자체 인덱스 불가 </li>
<li>뷰 정의 변경 불가</li>
<li>데이터 변경 제약 존재</li>
</ul>
</li>
</ul>
</li>
<li><p>인덱스(Index)</p>
<p>ⓐ 인덱스의 개념</p>
<ul>
<li><strong>검색 연산의 최적화</strong>를 위해 데이터베이스 내 값에 대한 주소 정보로 구성된 데이터 구조</li>
<li>인덱스는 데이터를 빠르게 찾을 수 있는 수단으로서, 테이블에 대한 조회 속도를 높여 주는 자료 구조</li>
<li>테이블의 특정 레코드 위치를 알려주는 용도로 사용</li>
</ul>
<p>ⓑ 인덱스의 특징</p>
<ul>
<li><strong>기본 키(PK; Primary Key)</strong> 컬럼은 <strong>자동</strong>으로 인덱스가 생성</li>
<li>연월일이나 이름을 기준으로 하는 인덱스는 자동으로 생성되지 않음</li>
<li>테이블의 컬럼에 인덱스가 없는 경우, 테이블의 전체 내용을 검색(테이블 전체 스캔; Table Full Scan)</li>
<li>인덱스가 생성되어 있을 때 데이터를 빠르게 찾을 수 있음(인덱스 범위 스캔; Index Range Scan)</li>
<li>조건절에 &#39;=&#39;로 비교되는 컬럼을 대상으로 인덱스를 생성하면 검색 속도를 높일 수 있음</li>
</ul>
<p>ⓒ 인덱스의 종류</p>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">순서 인덱스 <br>(Ordered Index)</td>
<td>- 데이터가 정렬된 순서로 생성되는 인덱스 <br>- B-Tree 알고리즘 활용(오름차순/내림차순 지정가능)</td>
</tr>
<tr>
<td align="center">해시 인덱스 <br>(Hash Index)</td>
<td>- 해시 함수에 의해 직접 데이터에 키 값으로 접근하는 인덱스 <br>- 데이터 접근 비용이 균일, 튜플(Row) 양에 무관</td>
</tr>
<tr>
<td align="center">비트맵 인덱스 <br>(Bitmap Index)</td>
<td>- 각 컬럼에 적은 개수 값이 저장된 경우 선택하는 인덱스 <br>- 수정 변경이 적을 경우 유용(생년월일, 상품번호 등)</td>
</tr>
<tr>
<td align="center">함수기반 인덱스 <br>(Functional Index)</td>
<td>- 수식이나 함수를 적용하여 만든 인덱스</td>
</tr>
<tr>
<td align="center">단일 인덱스 <br>(Singled Index)</td>
<td>- 하나의 컬럼으로만 구성한 인덱스 <br>- 주 사용 컬럼이 하나일 경우 사용</td>
</tr>
<tr>
<td align="center">결합 인덱스 <br>(Concatenated Index)</td>
<td>- 두 개 이상의 컬럼으로 구성한 인덱스 <br>- WHERE 조건으로 사용하는 빈도가 높은 경우 사용</td>
</tr>
<tr>
<td align="center">클러스터드 인덱스 <br>(Clustered Index)</td>
<td>- 기본 키(PK) 기준으로 레코드를 묶어서 저장하는 인덱스 <br>- 저장 데이터의 물리적 순서에 따라 인덱스가 생성 <br>- 특정 범위 검색 시 유리함</td>
</tr>
</tbody></table>
</li>
</ol>
<h4 id="③-ddl-명령어">③ DDL 명령어</h4>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th align="center">DDL 명령어</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">생성</td>
<td align="center">CREATE</td>
<td>데이터베이스 오브젝트 <strong>생성</strong>하는 명령어</td>
</tr>
<tr>
<td align="center">수정</td>
<td align="center">ALTER</td>
<td>데이터베이스 오브젝트 <strong>변경</strong>하는 명령어</td>
</tr>
<tr>
<td align="center">삭제</td>
<td align="center">DROP <br>TRUNCATE</td>
<td>데이터베이스 오브젝트 <strong>삭제</strong>하는 명령어 <br>데이터베이스 오브젝트 <strong>내용 삭제</strong>하는 명령어</td>
</tr>
</tbody></table>
<h4 id="④-table-관련-ddl">④ TABLE 관련 DDL</h4>
<ol>
<li><p>CREATE TABLE
ⓐ CREATE TABLE 기본문법</p>
<pre><code class="language-sql">  CREATE TABLE 테이블명
  (
    컬럼명 데이터타입 [제약조건],
  ···
  );</code></pre>
<p>ⓑ CREATE TABLE 상세문법</p>
<pre><code class="language-sql">  CREATE TABLE 테이블명
  (
    컬럼명 데이터타입 PRIMARY KEY, -- 기본키 설정,
    컬럼명 데이터타입 FOREIGN KEY REFERENCES 참조테이블(기본키), --외래키 설정 
    컬럼명 데이터타입 UNIQUE, 
    컬럼명 데이터타입 NOT NULL, 
    컬럼명 데이터타입 CHECH(조건식), --제약조건 설정 
    컬럼명 데이터타입 DEFAULT 값 
  );</code></pre>
<p>ⓒ CREATE TABLE 예시</p>
<pre><code class="language-sql">  CREATE TABLE 사원
  (
    사번 VARCHAR(10) PRIMARY KEY,
    업무 VARCHAR(20) FOREIGN KEY REFERENCES 부서(부서코드),
    이름 VARCHAR(10) UNIQUE,
    생년월일 CHAR(8) NOT NULL, 
    성별 CHAR(1) CHECK (성별 = &#39;M&#39; OR 성별 = &#39;F&#39;),
    입사일 DATE DEFAULT SYSDATE -- SYSDATE는 현재시간/날짜
  );</code></pre>
<p>ⓓ CREATE TABLE 제약조건</p>
<table>
<thead>
<tr>
<th align="center">제약조건</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>PRIMARY KEY</code></td>
<td>- 테이블의 기본 키를 정의 <br>- 유일하게 테이블의 각 행을 식별</td>
</tr>
<tr>
<td align="center"><code>FOREIGN KEY</code></td>
<td>- 외래 키를 정의 <br>- 참조 대상을 테이블(컬럼명)로 명시 <br>- 열과 참조된 테이블의 열 사이의 외래 키 관계를 적용하고 설정</td>
</tr>
<tr>
<td align="center"><code>UNIQUE</code></td>
<td>- 테이블 내에서 얻은 유일한 값을 갖도록 하는 제약조건</td>
</tr>
<tr>
<td align="center"><code>NOT NULL</code></td>
<td>- 해당 컬럼은 NULL 값을 포함하지 않도록 하는 제약조건</td>
</tr>
<tr>
<td align="center"><code>CHECK</code></td>
<td>- 개발자가 정의하는 제약조건 <br>- 참이어야 하는 조건을 지정</td>
</tr>
<tr>
<td align="center"><code>DEFAULT</code></td>
<td>- 데이터를 INSERT 할 때 해당 컬럼의 값을 넣지 않는 경우 기본값으로 설정해주는 제약조건</td>
</tr>
</tbody></table>
</li>
<li><p>ALTER TABLE
ⓐ ALTER TABLE 컬럼 추가</p>
<ul>
<li>CREATE TABLE의 컬럼에 사용되는 제약조건 사용 가능</li>
</ul>
<pre><code class="language-sql"> ALTER TABLE 테이블명 ADD 컬럼명 데이터타입 [제약조건];</code></pre>
<ul>
<li>예시<pre><code class="language-sql">ALTER TABLE 사원 ADD 전화번호 VARCHAR(11) UNIQUE;</code></pre>
→ 사원 테이블의 전화번호라는 컬럼에 대해 타입이 VARCHAR(11)이면서 UNIQUE 제약 조건을 걸도록 추가</li>
</ul>
<p>ⓑ ALTER TABLE 컬럼 수정</p>
<ul>
<li>CREATE 문에 제약조건을 명시 후에 ALTER를 통해 테이블 제약조건 변경 가능</li>
</ul>
<pre><code class="language-sql"> ALTER TABLE 테이블명 MODIFY 컬럼명 데이터타입 [제약조건];</code></pre>
<ul>
<li>예시<pre><code class="language-sql">ALTER TABLE 사원 MODIFY 이름 VARCHAR(30) NOT NULL;</code></pre>
→ 사원 테이블의 이름이라는 컬럼에 대해 타입이 VARCHAR(30)이면서 NOT NULL 제약 조건을 걸도록 수정</li>
</ul>
<p>ⓒ ALTER TABLE 컬럼 삭제</p>
<pre><code class="language-sql"> ALTER TABLE 테이블명 DROP COLUMN 컬럼명;</code></pre>
<ul>
<li>예시<pre><code class="language-sql">ALTER TABLE 사원 DROP COLUMN 생년월일;</code></pre>
→ 사원 테이블에 생년월일이라는 컬럼 삭제</li>
</ul>
</li>
<li><p>DROP TABLE</p>
<pre><code class="language-sql"> DROP TABLE 테이블명 [CASCADE | RESTRICT];</code></pre>
<ul>
<li><p>예시</p>
<pre><code class="language-sql">DROP TABLE 사원;</code></pre>
<p>→ 사원 테이블 삭제</p>
</li>
<li><p>CASCADE와 RESTRICT의 경우 외래 키(FOREIGN KEY)가 걸려 있을 때 해당</p>
<table>
<thead>
<tr>
<th align="center">옵션</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>CASCADE</code></td>
<td>참조하는 테이블까지 연쇄적으로 제거하는 옵션</td>
</tr>
<tr>
<td align="center"><code>RESTRICT</code></td>
<td>다른 테이블이 삭제할 테이블을 참조 중이면 제거하지 않는 옵션</td>
</tr>
</tbody></table>
</li>
</ul>
</li>
<li><p>TRUNCATE TABLE</p>
<pre><code class="language-sql"> TRUNCATE TABLE 테이블명;</code></pre>
<ul>
<li>예시<pre><code class="language-sql">TRUNCATE TABLE 사원;</code></pre>
→ 사원 테이블 내의 모든 데이터를 삭제</li>
</ul>
</li>
</ol>
<h4 id="⑤-view-관련-ddl">⑤ VIEW 관련 DDL</h4>
<ol>
<li><p>CREATE VIEW</p>
<pre><code class="language-sql"> CREATE VIEW 뷰이름 AS
 조회쿼리;</code></pre>
<ul>
<li>예시<pre><code class="language-sql">CREATE VIEW 사원뷰 AS
SELECT 사번, 이름
FROM 사원
WHERE 성별 = &#39;M&#39;;</code></pre>
→ 사원 테이블에서 성별 값이 &#39;M&#39;을 가진 사번, 이름으로 생성된 사원뷰라는 이름의 뷰 생성<ul>
<li>VIEW 테이블의 SELECT 문에는 <code>UNION</code> 이나 <code>ORDER BY</code> 절을 사용할 수 없음</li>
<li><code>UNION</code> : 집합연산자로 중복 행이 제거된 쿼리 결과 집합</li>
<li><code>ORDER BY</code> : 속성값을 정렬하고자 할 때 사용</li>
<li>컬럼명을 기술하지 않으면 SELECT 문의 컬럼명이 자동으로 사용</li>
</ul>
</li>
</ul>
</li>
<li><p>CREATE OR REPLACE VIEW</p>
<ul>
<li>뷰를 교체</li>
</ul>
<pre><code class="language-sql"> CREATE OR REPLACE VIEW 뷰이름 AS
 조회쿼리;</code></pre>
</li>
<li><p>DROP VIEW</p>
<ul>
<li>뷰를 삭제<pre><code class="language-sql">DROP VIEW 뷰이름;</code></pre>
</li>
</ul>
</li>
</ol>
<h4 id="⑥-index-관련-ddl">⑥ INDEX 관련 DDL</h4>
<ol>
<li><p>CREATE INDEX</p>
<ul>
<li><code>UNIQUE</code> 는 생략 가능하고, 인덱스 걸린 컬럼에 중복 값을 허용하지 않음</li>
<li>복수 컬럼을 인덱스로 걸 수 있음</li>
</ul>
<pre><code class="language-sql"> CREATE [UNIQUE] INDEX 인덱스명 ON 테이블명(컬럼명1, 컬럼명2);</code></pre>
<ul>
<li>예시<pre><code class="language-sql">CREATE INDEX 사번인덱스 ON 사원(사번);</code></pre>
→ 사원 테이블의 사번 컬럼에 대해 사번인덱스라는 인덱스 명으로 인덱스 생성</li>
</ul>
</li>
<li><p>ALTER INDEX</p>
<ul>
<li>일부 DBMS는 ALTER INDEX를 제공하지 않음</li>
<li>기존 인덱스를 삭제하고 신규 인덱스를 생성하는 방식으로 사용 권고</li>
</ul>
<pre><code class="language-sql"> ALTER [UNIQUE] INDEX 인덱스명 ON 테이블명(컬럼명1, 컬럼명2);</code></pre>
<ul>
<li>예시<pre><code class="language-sql">ALTER INDEX 사번인덱스 ON 사원(사번);</code></pre>
→ 사원 테이블의 사번 컬럼에 대해 사번인덱스라는 인덱스 명으로 인덱스 수정</li>
</ul>
</li>
<li><p>DROP INDEX</p>
<pre><code class="language-sql"> DROP INDEX 인덱스명;</code></pre>
</li>
</ol>
<h3 id="3-dml-⭐⭐⭐">3) DML ⭐⭐⭐</h3>
<h4 id="①-데이터-조작어dml-data-manipulation-language">① 데이터 조작어(DML; Data Manipulation Language)</h4>
<ul>
<li>데이터베이스에 저장된 자료들을 입력, 수정, 삭제, 조회하는 언어</li>
</ul>
<h4 id="②-dml-명령어">② DML 명령어</h4>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th align="center">동작</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>SELECT</code></td>
<td align="center">조회</td>
<td>테이블 내 칼럼에 저장된 데이터를 조회</td>
</tr>
<tr>
<td align="center"><code>INSERT</code></td>
<td align="center">삽입</td>
<td>테이블 내 칼럼에 데이터를 추가</td>
</tr>
<tr>
<td align="center"><code>UPDATE</code></td>
<td align="center">갱신</td>
<td>테이블 내 칼럼에 저장된 데이터를 수정</td>
</tr>
<tr>
<td align="center"><code>DELETE</code></td>
<td align="center">삭제</td>
<td>테이블 내 칼럼에 저장된 데이터를 삭제</td>
</tr>
</tbody></table>
<h4 id="③-select">③ SELECT</h4>
<ol>
<li><p>SELECT 명령어 </p>
<ul>
<li>속성명 별칭은 <code>AS</code>를 사용</li>
<li><code>DISTINCT</code> : 중복된 속성 중 하나만</li>
<li><code>HAVING</code> : <code>GROUP BY</code>에 의해 분류한 후 그룹에 대한 조건 지정<pre><code class="language-sql">SELECT [ALL | DISTICT] 속성명1, 속성명2, ...
FROM 테이블명1, ...
[WHERE 조건]
[GROUP BY 속성명 1, ...]
[HAVING 그룹조건]
[ORDER BY 속성 [ASC | DESC] ];</code></pre>
</li>
</ul>
<p>ⓐ SELECT 절</p>
<p>[성적 테이블]</p>
<table>
<thead>
<tr>
<th align="center">이름</th>
<th align="center">과목</th>
<th align="center">학점</th>
</tr>
</thead>
<tbody><tr>
<td align="center">김철수</td>
<td align="center">C언어</td>
<td align="center">A</td>
</tr>
<tr>
<td align="center">한유리</td>
<td align="center">자료구조</td>
<td align="center">A</td>
</tr>
<tr>
<td align="center">신짱구</td>
<td align="center">자료구조</td>
<td align="center">A</td>
</tr>
<tr>
<td align="center">이훈이</td>
<td align="center">알고리즘</td>
<td align="center">B</td>
</tr>
</tbody></table>
<pre><code class="language-sql">SELECT DISTINCT 과목
FROM 성적
WHERE 학점 = &#39;A&#39;</code></pre>
<table>
<thead>
<tr>
<th align="center">과목</th>
</tr>
</thead>
<tbody><tr>
<td align="center">C언어</td>
</tr>
<tr>
<td align="center">자료구조</td>
</tr>
</tbody></table>
</li>
</ol>
<pre><code class="language-sql"> SELECT COUNT(DISTINCT 과목)
   FROM 성적;</code></pre>
<table>
<thead>
<tr>
<th align="center">DISTINCT 과목</th>
</tr>
</thead>
<tbody><tr>
<td align="center">3</td>
</tr>
</tbody></table>
<p> ⓑ WHERE 절</p>
<ul>
<li><p>비교 </p>
<ul>
<li><code>=</code> : 값이 같은 경우 조회</li>
<li><code>&lt;&gt;, !=</code> : 값이 다른 경우 조회</li>
<li><code>&lt;, &lt;=, &gt;, &gt;=</code> : 비교 연산에 해당하는 데이터 조회</li>
</ul>
</li>
<li><p>범위</p>
<pre><code class="language-sql">SELECT *
  FROM PRODUCT
 WHERE PRICE BETWEEN 50000 AND 80000;
-- = WHERE PRICE &gt;=50000 AND PRICE &lt;= 80000; </code></pre>
</li>
<li><p>집합</p>
<ul>
<li><code>IN</code>, <code>NOT IN</code><pre><code class="language-sql">SELECT *
FROM PRODUCT
WHERE PRICE IN (40000, 50000, 80000);</code></pre>
</li>
</ul>
</li>
<li><p>패턴</p>
<ul>
<li><code>%</code> : 0개 이상의 문자열과 일치</li>
<li><code>[ ]</code> : 1개 문자와 일치</li>
<li><code>[^]</code> : 1개 문자와 불일치</li>
<li><code>_</code> : 특정 위치의 1개의 문자와 일치<pre><code class="language-sql">SELECT *
FROM PRODUCT
WHERE PRICE IN (40000, 50000, 80000);</code></pre>
</li>
</ul>
</li>
<li><p>NULL</p>
<ul>
<li><code>IS NULL</code>, <code>IS NOT NULL</code><pre><code class="language-sql">SELECT *
FROM PRODUCT
WHERE PRICE IS NULL;</code></pre>
</li>
</ul>
</li>
<li><p>복합조건</p>
<ul>
<li><code>AND</code>, <code>OR</code>, <code>NOT</code></li>
</ul>
<p>ⓒ GROUP BY</p>
<p>[급여 테이블]</p>
<table>
<thead>
<tr>
<th align="center">이름</th>
<th align="center">직책</th>
<th align="center">부서</th>
<th align="center">급여</th>
</tr>
</thead>
<tbody><tr>
<td align="center">김철수</td>
<td align="center">차장</td>
<td align="center">마케팅</td>
<td align="center">5000</td>
</tr>
<tr>
<td align="center">한유리</td>
<td align="center">차장</td>
<td align="center">전산</td>
<td align="center">4800</td>
</tr>
<tr>
<td align="center">신짱구</td>
<td align="center">사원</td>
<td align="center">마케팅</td>
<td align="center">2500</td>
</tr>
<tr>
<td align="center">이훈이</td>
<td align="center">사원</td>
<td align="center">마케팅</td>
<td align="center">2700</td>
</tr>
</tbody></table>
<pre><code class="language-sql">SELECT 직책, 부서, SUM(급여) AS 급여합계
FROM 급요
GROUP BY 직책, 부서</code></pre>
<table>
<thead>
<tr>
<th align="center">직책</th>
<th align="center">부서</th>
<th align="center">급여합계</th>
</tr>
</thead>
<tbody><tr>
<td align="center">차장</td>
<td align="center">마케팅</td>
<td align="center">5000</td>
</tr>
<tr>
<td align="center">차장</td>
<td align="center">전산</td>
<td align="center">4800</td>
</tr>
<tr>
<td align="center">사원</td>
<td align="center">마케팅</td>
<td align="center">5200</td>
</tr>
</tbody></table>
</li>
</ul>
<pre><code class="language-sql"> SELECT COUNT(*)
   FROM 급여;</code></pre>
<table>
<thead>
<tr>
<th align="center">COUNT(*)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">4</td>
</tr>
</tbody></table>
<p> ⓓ HAVING 절</p>
<pre><code class="language-sql"> SELECT 직책, 부서, SUM(급여) AS 급여합계
   FROM 급요
  GROUP BY 직책, 부서
 HAVING 급여합계 &gt;= 5000;</code></pre>
<table>
<thead>
<tr>
<th align="center">직책</th>
<th align="center">부서</th>
<th align="center">급여합계</th>
</tr>
</thead>
<tbody><tr>
<td align="center">차장</td>
<td align="center">마케팅</td>
<td align="center">5000</td>
</tr>
<tr>
<td align="center">사원</td>
<td align="center">마케팅</td>
<td align="center">5200</td>
</tr>
</tbody></table>
<ol start="2">
<li><p>JOIN</p>
<ul>
<li>두 개 이상의 테이블을 결합하여 하나의 튜플로 만드는 연결 방법</li>
<li>조인 예시
[도서]&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp[도서가격]</li>
</ul>
<table>
<thead>
<tr>
<th align="center">책번호</th>
<th align="center">책명</th>
<th align="center"></th>
<th align="center">책번호</th>
<th align="center">가격</th>
</tr>
</thead>
<tbody><tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center"></td>
<td align="center">111</td>
<td align="center">20000</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center"></td>
<td align="center">222</td>
<td align="center">25000</td>
</tr>
<tr>
<td align="center">555</td>
<td align="center">컴퓨터구조</td>
<td align="center"></td>
<td align="center">333</td>
<td align="center">10000</td>
</tr>
<tr>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center">444</td>
<td align="center">15000</td>
</tr>
</tbody></table>
<p>ⓐ 내부 조인(Inner Join) : 공통 존재 컬럼의 값이 같은 경우 추출</p>
<pre><code class="language-sql">SELECT A.컬럼1, A.컬럼2, ...,
     B.컬럼1, B.컬럼2, ...
FROM 테이블1 A [INNER] JOIN 테이블2 B
  ON 조인조건
[WHERE 검색조건];</code></pre>
<pre><code class="language-sql">SELECT A.책번호, A.책명, B.가격
FROM 도서 A JOIN 도서가격 B
  ON A.책번호 = B.책번호</code></pre>
<table>
<thead>
<tr>
<th align="center">책번호</th>
<th align="center">책명</th>
<th align="center">가격</th>
</tr>
</thead>
<tbody><tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">20000</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">25000</td>
</tr>
</tbody></table>
<p>ⓑ 외부 조인(Outer Join) 
1) 왼쪽 외부 조인 : 왼쪽 테이블의 모든 데이터와 오른쪽 테이블의 동일 데이터 추출</p>
<pre><code class="language-sql">SELECT A.컬럼1, A.컬럼2, ...,
      B.컬럼1, B.컬럼2, ...
FROM 테이블1 A LEFT [OUTER] JOIN 테이블2 B
  ON 조인조건
[WHERE 검색조건];</code></pre>
<pre><code class="language-sql">SELECT A.책번호, A.책명, B.책번호, B.가격
FROM 도서 A LEFT JOIN 도서가격 B
  ON A.책번호 = B.책번호;</code></pre>
<table>
<thead>
<tr>
<th align="center">책번호</th>
<th align="center">책명</th>
<th align="center">책번호</th>
<th align="center">가격</th>
</tr>
</thead>
<tbody><tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">111</td>
<td align="center">20000</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">222</td>
<td align="center">25000</td>
</tr>
<tr>
<td align="center">555</td>
<td align="center">컴퓨터구조</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
</tr>
</tbody></table>
<p>2) 오른쪽 외부 조인 : 오른쪽 테이블의 모든 데이터와 왼쪽 테이블의 동일 데이터 추출</p>
<pre><code class="language-sql">SELECT A.컬럼1, A.컬럼2, ...,
      B.컬럼1, B.컬럼2, ...
FROM 테이블1 A RIGHT [OUTER] JOIN 테이블2 B
  ON 조인조건
[WHERE 검색조건];</code></pre>
<pre><code class="language-sql">SELECT A.책번호, A.책명, B.책번호, B.가격
FROM 도서 A RIGHT JOIN 도서가격 B
  ON A.책번호 = B.책번호;</code></pre>
<table>
<thead>
<tr>
<th align="center">책번호</th>
<th align="center">책명</th>
<th align="center">책번호</th>
<th align="center">가격</th>
</tr>
</thead>
<tbody><tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">111</td>
<td align="center">20000</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">222</td>
<td align="center">25000</td>
</tr>
<tr>
<td align="center">NULL</td>
<td align="center">NULL</td>
<td align="center">333</td>
<td align="center">10000</td>
</tr>
<tr>
<td align="center">NULL</td>
<td align="center">NULL</td>
<td align="center">444</td>
<td align="center">15000</td>
</tr>
</tbody></table>
</li>
</ol>
<p> 3) 완전 외부 조인 : 양쪽의 모든 데이터를 추출</p>
<pre><code class="language-sql"> SELECT A.컬럼1, A.컬럼2, ...,
         B.컬럼1, B.컬럼2, ...
   FROM 테이블1 A FULL [OUTER] JOIN 테이블2 B
     ON 조인조건
 [WHERE 검색조건];</code></pre>
<pre><code class="language-sql"> SELECT A.책번호, A.책명, B.책번호, B.가격
   FROM 도서 A FULL JOIN 도서가격 B
     ON A.책번호 = B.책번호;</code></pre>
<table>
<thead>
<tr>
<th align="center">책번호</th>
<th align="center">책명</th>
<th align="center">책번호</th>
<th align="center">가격</th>
</tr>
</thead>
<tbody><tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">111</td>
<td align="center">20000</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">222</td>
<td align="center">25000</td>
</tr>
<tr>
<td align="center">NULL</td>
<td align="center">NULL</td>
<td align="center">333</td>
<td align="center">10000</td>
</tr>
<tr>
<td align="center">NULL</td>
<td align="center">NULL</td>
<td align="center">444</td>
<td align="center">15000</td>
</tr>
<tr>
<td align="center">555</td>
<td align="center">컴퓨터구조</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
</tr>
</tbody></table>
<p> ⓒ 교차 조인(Cross Join) : 조인 조건이 없는 모든 데이터 조합을 추출 ⭐</p>
<pre><code class="language-sql"> SELECT 컬럼1, 컬럼2, ...,
   FROM 테이블1 A CROSS JOIN 테이블2 B</code></pre>
<pre><code class="language-sql"> SELECT A.책번호, A.책명, B.책번호, B.가격
   FROM 도서 A CROSS JOIN 도서가격 B;</code></pre>
<table>
<thead>
<tr>
<th align="center">책번호</th>
<th align="center">책명</th>
<th align="center">책번호</th>
<th align="center">가격</th>
</tr>
</thead>
<tbody><tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">111</td>
<td align="center">20000</td>
</tr>
<tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">222</td>
<td align="center">25000</td>
</tr>
<tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">333</td>
<td align="center">10000</td>
</tr>
<tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">444</td>
<td align="center">15000</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">111</td>
<td align="center">20000</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">222</td>
<td align="center">25000</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">333</td>
<td align="center">10000</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">444</td>
<td align="center">25000</td>
</tr>
<tr>
<td align="center">555</td>
<td align="center">컴퓨터구조</td>
<td align="center">111</td>
<td align="center">20000</td>
</tr>
<tr>
<td align="center">555</td>
<td align="center">컴퓨터구조</td>
<td align="center">222</td>
<td align="center">25000</td>
</tr>
<tr>
<td align="center">555</td>
<td align="center">컴퓨터구조</td>
<td align="center">333</td>
<td align="center">10000</td>
</tr>
<tr>
<td align="center">555</td>
<td align="center">컴퓨터구조</td>
<td align="center">444</td>
<td align="center">25000</td>
</tr>
</tbody></table>
<p> ⓓ 셀프 조인(Self Join) : 자기 자신에게 별칭을 지정한 후 다시 조인</p>
<pre><code class="language-sql"> SELECT A.컬럼1, A.컬럼2, ...,
         B.컬럼1, B.컬럼2, ...
   FROM 테이블1 A [INNER] JOIN 테이블1 B
     ON 조인조건
 [WHERE 검색조건];</code></pre>
<p> [도서]</p>
<table>
<thead>
<tr>
<th align="center">책번호</th>
<th align="center">책명</th>
<th align="center">선수과목_책번호</th>
</tr>
</thead>
<tbody><tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">222</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">555</td>
</tr>
<tr>
<td align="center">555</td>
<td align="center">컴퓨터구조</td>
<td align="center">NULL</td>
</tr>
</tbody></table>
<pre><code class="language-sql"> SELECT A.책번호, A.책명, B.책번호, B.책명
   FROM 도서 A FULL JOIN 도서 B
     ON A.선수과목_책번호 = B.책번호;</code></pre>
<table>
<thead>
<tr>
<th align="center">책번호</th>
<th align="center">책명</th>
<th align="center">책번호</th>
<th align="center">책명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">111</td>
<td align="center">운영체제</td>
<td align="center">222</td>
<td align="center">자료구조</td>
</tr>
<tr>
<td align="center">222</td>
<td align="center">자료구조</td>
<td align="center">555</td>
<td align="center">컴퓨터구조</td>
</tr>
</tbody></table>
<ol start="3">
<li><p>서브쿼리(Sub-query)</p>
<ul>
<li>SQL 문 안에 포함된 또 다른 SQL 문</li>
<li>용도는 알려지지 않은 기준을 위한 검색을 위해 사용</li>
<li>메인쿼리와 서브쿼리는 <strong>주종 관계</strong>로서, 서브쿼리에 사용되는 컬럼 정보는 메인 쿼리의 컬럼 정보를 사용할 수 있으나, 역으로는 성립 X</li>
</ul>
<p>ⓐ FROM 절 서브쿼리</p>
<ul>
<li>서브쿼리가 FROM 절 안에 들어있는 형태</li>
<li><strong>인라인 뷰</strong>라고 불림</li>
<li>뷰처럼 결과가 동적으로 생성된 테이블 형태로 사용 가능</li>
</ul>
<pre><code class="language-sql">SELECT MAX(가격) AS 가격
FROM 도서가격 A, 
       (SELECT 책번호
          FROM 도서
         WHERE 책명=&#39;자료구조&#39;) B
WHERE A.책번호 = B.책번호;</code></pre>
<table>
<thead>
<tr>
<th align="center">가격</th>
</tr>
</thead>
<tbody><tr>
<td align="center">25000</td>
</tr>
</tbody></table>
<p>ⓑ WHERE 절 서브쿼리</p>
<ul>
<li>서브쿼리가 WHERE 절 안에 들어있는 형태</li>
<li>중첩 서브쿼리(Nested Sub-Query)라도고 불림</li>
</ul>
<pre><code class="language-sql">SELECT MAX(가격) AS 가격
FROM 도서가격 A, 
WHERE 책번호 IN (SELECT 책번호
                 FROM 도서
                WHERE 책명=&#39;자료구조&#39;);</code></pre>
<table>
<thead>
<tr>
<th align="center">가격</th>
</tr>
</thead>
<tbody><tr>
<td align="center">25000</td>
</tr>
</tbody></table>
</li>
</ol>
<h4 id="④-insert데이터-삽입">④ INSERT(데이터 삽입)</h4>
<ul>
<li>속성과 데이터 개수, 데이터 타입이 <strong>일치</strong>해야 함</li>
<li><strong>속성명</strong>은 생략 가능</li>
<li>속성의 타입이 <strong>숫자</strong>인 경우 <strong>따옴표</strong>를 붙이지 않아도 되며, <strong>문자열</strong>인 경우 붙여야 함</li>
</ul>
<pre><code class="language-sql">  INSERT INTO 테이블명(속성명1, ...)
  VALUES (데이터1, ...);</code></pre>
<ul>
<li>예시<pre><code class="language-sql">INSERT INTO 학생(학번, 성명, 학년, 수강과목)
VALUES (6677, &#39;장길산&#39;, 3, &#39;수학&#39;);</code></pre>
</li>
</ul>
<h4 id="⑤-update데이터-갱신">⑤ UPDATE(데이터 갱신)</h4>
<ul>
<li><code>WHERE</code> 절을 통해 어떤 조건이 만족할 경우에만 <strong>특정</strong> 컬럼의 값을 수정하는 용도로 자주 사용됨</li>
</ul>
<pre><code class="language-sql">  UPDATE 테이블명
     SET 속성명 = 데이터, ...
   WHERE 조건;</code></pre>
<ul>
<li>예시<pre><code class="language-sql">UPDATE 학생
   SET 주소=&#39;인천&#39;
 WHERE 이름=&#39;장길산&#39;;</code></pre>
</li>
</ul>
<h4 id="⑥-delete데이터-삭제">⑥ DELETE(데이터 삭제)</h4>
<ul>
<li>모든 레코드를 삭제할 때는 WHERE 절 없이 DELETE만 사용</li>
<li>⭐ 레코드를 삭제해도 테이블 구조는 남아 있어서 디스크에서 테이블을 <strong>완전히</strong> 삭제하는 <code>DROP</code> 명령과는 다름</li>
</ul>
<pre><code class="language-sql">  DELETE FROM 테이블명
   WHERE 조건;</code></pre>
<ul>
<li>예시<pre><code class="language-sql">DELETE FROM 학생
 WHERE 이름=&#39;장길산&#39;;</code></pre>
</li>
</ul>
<h3 id="4-dcl">4) DCL</h3>
<h4 id="①-데이터-제어어dcl-data-control-language">① 데이터 제어어(DCL; Data Control Language)</h4>
<ul>
<li>데이터베이스 관리자가 데이터 보안, 무결성 유지, 병행 제어, 회복을 위해 관리자(DBA)가 사용하는 제어용 언어</li>
</ul>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th align="center">동작</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>GRANT</code></td>
<td align="center">사용 권한 부여</td>
<td>관리자(DBA)가 사용자에게 데이터베이스에 대한 권한을 부여하는 명령어</td>
</tr>
<tr>
<td align="center"><code>REVOKE</code></td>
<td align="center">사용 권한 취소</td>
<td>관리자(DBA)가 사용자에게 부여했던 권한을 회수하기 위한 명령어</td>
</tr>
</tbody></table>
<ol>
<li><p>GRANT(권한 부여) 명령어</p>
<ul>
<li>데이터베이스 관리자(DBA; Database Administrator)가 사용자에게 데이터베이스에 대한 권한을 부여하는 명령어</li>
</ul>
<pre><code class="language-sql"> GRANT 권한 ON 테이블 TO 사용자;</code></pre>
<ul>
<li>예시<pre><code class="language-sql">GRANT UPDATE ON 학생 TO 장길산;</code></pre>
→ 관리자가 사용자 장길산에게 &#39;학생&#39; 테이블에 대해 UPDATE 할 수 있는 권한 부여</li>
</ul>
</li>
</ol>
<ol start="2">
<li><p>REVOKE(권한 회수) 명령어</p>
<ul>
<li>데이터베이스 관리자(DBA)가 사용자에게 부여했던 권한을 회수하기 위한 명령어</li>
</ul>
<pre><code class="language-sql"> REVOKE 권한 ON 테이블 FROM 사용자;</code></pre>
<ul>
<li>예시<pre><code class="language-sql">REVOKE UPDATE ON 학생 FROM 장길산;</code></pre>
→ 관리자가 사용자 장길산에게 &#39;학생&#39; 테이블에 대해 UPDATE 할 수 있는 권한 회수</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[정보처리기사 실기] 10. 프로그래밍 언어 활용 - 파이썬]]></title>
            <link>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-10.-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4-%ED%99%9C%EC%9A%A9-%ED%8C%8C%EC%9D%B4%EC%8D%AC</link>
            <guid>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-10.-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4-%ED%99%9C%EC%9A%A9-%ED%8C%8C%EC%9D%B4%EC%8D%AC</guid>
            <pubDate>Wed, 24 Jul 2024 16:33:22 GMT</pubDate>
            <description><![CDATA[<h1 id="4-파이썬">4. 파이썬</h1>
<h2 id="01-파이썬-기본-구조">01. 파이썬 기본 구조</h2>
<ul>
<li>파이썬은 사용자 정의 함수, 클래스가 먼저 정의되고, 그 다음에 실행 코드</li>
<li>가독성을 위해 들여쓰기를 함</li>
</ul>
<pre><code class="language-python">def fn(num):
  if num % 2 == 0:
    return &#39;Y&#39;

class A:
  def fn(self):
    print(&#39;A&#39;)

print(&#39;Hello&#39;) # Hello</code></pre>
<h2 id="span-stylebackground-colorfff5b102-자료형-⭐⭐⭐span"><span style="background-color:#fff5b1">02. 자료형 ⭐⭐⭐</span></h2>
<h3 id="1-자료형-유형">1) 자료형 유형</h3>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th align="center">설명</th>
<th align="center">세부 유형</th>
</tr>
</thead>
<tbody><tr>
<td align="center">기본 자료형 <br>(Primitive Data Type)</td>
<td align="center">직접 자료를 표현하는 자료형</td>
<td align="center">숫자형(Number) <br>논리형(Logical)</td>
</tr>
<tr>
<td align="center">컬렉션 자료형 <br>(Collection Data Type)</td>
<td align="center">다수의 데이터를 효과적으로 처리</td>
<td align="center">문자열형(String) <br>리스트형(List) <br>튜플형(Tuple) <br>딕셔너리형(Dictionary) <br>세트형(Set)</td>
</tr>
</tbody></table>
<h3 id="2-컬렉션-자료형collection-data-type">2) 컬렉션 자료형(Collection Data Type)</h3>
<ul>
<li>시퀀스 자료형(순서 O)</li>
</ul>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td align="center">문자열형(String)</td>
<td>- 문자 한 개 또는 여러 개 저장하고자 할 때 사용</td>
<td><code>s = &quot;Test&quot;</code></td>
</tr>
<tr>
<td align="center">리스트형(List)</td>
<td>- 크기가 가변적으로 변하는 선형리스트의 성질을 가짐 <br>- 읽기, 쓰기 모두 가능</td>
<td><code>I=[1, 2, 3]</code></td>
</tr>
<tr>
<td align="center">튜플형(Tuple)</td>
<td>- 초기에 선언된 값에서 값을 생성, 삭제, 수정할 수 없는 형태 <br>- 읽기 전용으로 속도가 빠름</td>
<td><code>t=(1, 2, 3)</code></td>
</tr>
</tbody></table>
<ul>
<li>비시퀀스 자료형(순서 X)</li>
</ul>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td align="center">세트형(Set)</td>
<td>- 중복된 원소를 허용하지 않는 집합의 성질을 가짐</td>
<td><code>s={1, 2, 3}</code></td>
</tr>
<tr>
<td align="center">딕셔너리형(Dictionary)</td>
<td>- 키, 값으로 구성된 객체를 저장하는 구조</td>
<td><code>d={&#39;s&#39;:1, &#39;j&#39;:2, &#39;b&#39;:3}</code></td>
</tr>
<tr>
<td align="center">→ 파이썬의 <strong>세트형</strong>은 자바의 Set 클래스(<strong>HashSet</strong>)과, 파이썬의 <strong>리스트형</strong>은 자바의 List 클래스(<strong>ArrayList, LinkedList</strong>)와, 파이썬의 <strong>딕셔너리형</strong>은 자바의 Map 클래스(<strong>HashMap</strong>)와 비슷</td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h4 id="①-시퀀스-자료형-구조">① 시퀀스 자료형 구조</h4>
<ol>
<li><p>시퀀스 자료형 종류</p>
<p>ⓐ 문자열형(String) ⭐</p>
<pre><code class="language-python">print(&quot;Hello&quot;)
print(&quot;Hello&quot;, &quot;World&quot;) # Hello World ← (,)로 구분되면 띄어쓰기
print(&quot;\&quot;Hello\&quot;&quot;) # &quot;Hello&quot;
print(&quot;Hello&quot;*3) # HelloHelloHello</code></pre>
<ul>
<li><p>파이썬 문자열은 포맷스트링을 이용하여 문자열을 출력할 수 있음</p>
<pre><code class="language-python">a = &quot;Hello&quot;
print(&quot;%s&quot; % a) # Hello
b = &quot;%s&quot; % &quot; world&quot;
print(a+b) # Hello world
c = 123
print(&quot;%s %d&quot; % (a, c)) # Hello 123 </code></pre>
<p>→ 컬렉션 자료형 변수를 그냥 출력했을 때는 괄호 표시 O, 문자열 변수를 출력했을 때는 괄호 표시 X</p>
</li>
<li><p>문자열에서 <code>in</code> 연산자를 이용하여 찾고자 하는 문자열이 존재하면 <code>True</code>, 없으면 <code>False</code></p>
</li>
<li><p>문자열 관련 함수</p>
<table>
<thead>
<tr>
<th align="center">함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>upper()</code></td>
<td>문자열을 대문자로 변환</td>
</tr>
<tr>
<td align="center"><code>lower()</code></td>
<td>문자열을 소문자로 변환</td>
</tr>
<tr>
<td align="center"><code>isalnum()</code></td>
<td>문자열이 알파벳 또는 숫자로만 구성되어 있는지</td>
</tr>
<tr>
<td align="center"><code>isalpha()</code></td>
<td>문자열이 알파벳으로만 구성되어 있는지</td>
</tr>
<tr>
<td align="center"><code>isdecimal()</code></td>
<td>문자열이 정수인지</td>
</tr>
<tr>
<td align="center"><code>isdigit()</code></td>
<td>문자열이 숫자인지</td>
</tr>
<tr>
<td align="center"><code>isspace()</code></td>
<td>문자열이 공백으로만 구성되어 있는지</td>
</tr>
<tr>
<td align="center"><code>split()</code></td>
<td>문자열을 매개변수로 전달된 문자(구분자)로 나누어 리스트로 변환</td>
</tr>
</tbody></table>
<pre><code class="language-python">str = &quot;1,2,3&quot;.split(&quot;,&quot;)
print(str) # [&#39;1&#39;, &#39;2&#39;, &#39;3&#39;]</code></pre>
</li>
</ul>
<p>ⓑ 리스트형(list) ⭐⭐</p>
<ul>
<li><p>[,] 를 이용하여 리스트형 선언</p>
<ul>
<li><code>리스트명=[요소1, 요소2, ···]</code></li>
</ul>
</li>
<li><p>리스트형 메서드</p>
<table>
<thead>
<tr>
<th align="center">메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>append(x)</code></td>
<td>리스트 마지막 요소 뒤에 값 x를 추가</td>
</tr>
<tr>
<td align="center"><code>clear()</code></td>
<td>리스트의 모든 항목을 삭제</td>
</tr>
<tr>
<td align="center"><code>copy()</code></td>
<td>리스트를 복사</td>
</tr>
<tr>
<td align="center"><code>count(x)</code></td>
<td>리스트에서 x 항목의 개수를 알려줌</td>
</tr>
<tr>
<td align="center"><code>extend(i)</code></td>
<td>리스트 마지막에 컬렉션 자료형 i를 추가</td>
</tr>
<tr>
<td align="center"><code>index(x)</code></td>
<td>값 x와 같은 값을 가지고 있는 인덱스 번호를 알려줌</td>
</tr>
<tr>
<td align="center"><code>insert(i, x)</code></td>
<td>리스트의 i 번지 위치에 값 x를 삽입</td>
</tr>
<tr>
<td align="center"><code>pop()</code></td>
<td>마지막 항목을 삭제하고 값을 꺼내옴</td>
</tr>
<tr>
<td align="center"><code>remove(x)</code></td>
<td>리스트에서 해당하는 값(중복이면 가장 앞) x를 제거</td>
</tr>
<tr>
<td align="center"><code>reverse()</code></td>
<td>리스트의 위치를 전부 역순으로 바꿔줌</td>
</tr>
<tr>
<td align="center"><code>sort()</code></td>
<td>리스트의 항목들을 정렬</td>
</tr>
</tbody></table>
</li>
<li><p>리스트를 2차원으로 만들 수 있음</p>
<pre><code class="language-python">a = [[1, 2], [3, 4], [5, 6]]
print(a) # [[1, 2], [3, 4], [5, 6]]
print(a[0]) # [1, 2]
print(a[1][0]) # 3
b = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
print(b[0]) # [1, 2, 3]</code></pre>
</li>
</ul>
<p>ⓒ 튜플형</p>
<ul>
<li><p>(,) 를 이용하여 리스트형 선언</p>
<ul>
<li><code>튜플명=(요소1, 요소2, ···)</code></li>
</ul>
<pre><code class="language-python">t = (&#39;s&#39;, &#39;j&#39;, &#39;b&#39;)
print(t) # (&#39;s&#39;, &#39;j&#39;, &#39;b&#39;)</code></pre>
</li>
</ul>
</li>
<li><p>시퀀스 자료형 요소 접근 방벙 - 인덱싱(Indexing)</p>
<ul>
<li><p>시퀀스 자료형은 여러 값으로 이루어져 있는데 인덱스를 이용해서 중간값에 접근할 수 있음</p>
<table>
<thead>
<tr>
<th align="center">첫 번째 요소</th>
<th align="center">두 번째 요소</th>
<th align="center">···</th>
<th align="center">뒤에서 두 번째 요소</th>
<th align="center">뒤에서 첫 번째 요소</th>
</tr>
</thead>
<tbody><tr>
<td align="center">0</td>
<td align="center">1</td>
<td align="center">···</td>
<td align="center">(n-2)</td>
<td align="center">(n-1)</td>
</tr>
<tr>
<td align="center">-n</td>
<td align="center">-(n-1)</td>
<td align="center">···</td>
<td align="center">-2</td>
<td align="center">-1</td>
</tr>
</tbody></table>
<ul>
<li>인덱싱은 문자열, 리스트 같은 자료구조에서 사용</li>
<li>문자열 인덱싱은 문자열에 부여된 번호로 원하는 문자를 가리킬 때 사용</li>
<li>문자열 앞에서부터 시작하면 인덱스는 0부터 시작하고, 뒤에서부터 시작하면 -1 부터 시작</li>
<li>인덱싱으로 접근하면 출력 결과에 괄호가 없음</li>
</ul>
</li>
</ul>
</li>
<li><p>시퀀스 자료형 요소 접근 방벙 - 슬라이싱(Slicing)</p>
<ul>
<li><p>슬라이싱은 시퀀스 자료형에서 여러 개의 데이터에 동시에 접근하는 기법</p>
</li>
<li><p><code>시퀀스변수명[시작 : 종료 : 스텝]</code></p>
<table>
<thead>
<tr>
<th align="center">형태</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">시작</td>
<td>- 슬라이싱을 <strong>시작</strong>할 인덱스 <br>- 생략할 경우 &#39;시퀀스변수명[ : 종료]&#39; 또는 &#39;시퀀스변수명[ : 종료 : 스텝]&#39; 형태가 됨 <br>- 생략할 경우 처음부터 슬라이싱</td>
</tr>
<tr>
<td align="center">종료</td>
<td>- 슬라이싱을 <strong>종료</strong>할 인덱스 <br>- 종료 인덱스에 있는 인덱스 전까지만 슬라이싱 <br>- 생략할 경우 &#39;시퀀스변수명[ 시작 : ]&#39; 또는 &#39;시퀀스변수명[ 시작 : : 스텝]&#39; 형태가 됨 <br>- 생략할 경우 마지막까지 슬라이싱</td>
</tr>
<tr>
<td align="center">스텝</td>
<td>- 몇 개씩 끊어서 슬라이싱을 할지 결정하는 값 <br>- 생략할 경우 &#39;시퀀스변수명[ 시작 : 종료 ]&#39; 또는 &#39;시퀀스변수명[ 시작 : 종료 : ]&#39; 형태가 됨 <br>- 생략할 경우 1이 기본값</td>
</tr>
</tbody></table>
</li>
</ul>
<p>ⓐ 문자열 슬라이싱</p>
<pre><code class="language-python"> print(&quot;Information&quot;[1:]) # nformation
 print(&quot;Information&quot;[2:4]) # fo
 print(&quot;Information&quot;[:3]) # inf</code></pre>
<p> → 문자열 슬라이싱을 제외한 다은 시퀀스 자료형은 출력 결과에 괄호가 표시됨</p>
<p>ⓑ 리스트 슬라이싱</p>
<pre><code class="language-python"> a = [4, 2, 7, 3, 5]
 print(a[0 : 4 : 2] # [4, 7]</code></pre>
<p>ⓒ 튜플 슬라이싱</p>
<pre><code class="language-python"> t = (&#39;s&#39;, &#39;j&#39;, &#39;b&#39;)
 print(t[1:]) # (&#39;j&#39;, &#39;b&#39;)</code></pre>
</li>
</ol>
<h4 id="②-비시퀀스-자료형-구조">② 비시퀀스 자료형 구조</h4>
<ol>
<li><p>세트형
ⓐ 세트(Set)형 개념</p>
<ul>
<li>중복된 원소를 허용하지 않는 자료형으로 순서가 중요하지 않음</li>
<li>set라는 키워드로 세트형을 초기화하거나 {, }를 이용하여 선언<pre><code>세트명 = set([요소1, 요소2, ···])
세트명 = {요소1, 요소2, ···}</code></pre></li>
</ul>
<p>ⓑ 세트형 메서드</p>
<table>
<thead>
<tr>
<th align="center">메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>add(값)</code></td>
<td>값을 1개 추가</td>
</tr>
<tr>
<td align="center"><code>update([값1, 값2, ···])</code></td>
<td>여러 개의 값을 한꺼번에 추가</td>
</tr>
<tr>
<td align="center"><code>remove(값)</code></td>
<td>특정 값을 제거하는 메서드</td>
</tr>
</tbody></table>
</li>
</ol>
<ol start="2">
<li><p>딕셔너리(Dictionary)
ⓐ 딕셔너리형 개념</p>
<ul>
<li>키와 값으로 구성된 객체를 저장하는 구조</li>
</ul>
<p>ⓑ 딕셔너리형 요소 생성</p>
<ul>
<li><code>딕셔너리명={키1:값1, 키2:값2, ···}</code></li>
<li>{, } 안에 콜론(:)을 이용하여 키와 값을 구분하여 선언</li>
</ul>
<p>ⓒ 딕셔너리형 요소 변경</p>
<ul>
<li><code>딕셔너리명[키]=값</code></li>
<li>기존 변수에 키와 값을 추가</li>
<li>기존 변수에 해당 키에 해당하는 값이 있었으면 값을 변경</li>
</ul>
<p>ⓓ 딕셔너리형 요소 삭제</p>
<ul>
<li>기존 변수에서 해당 키와 키에 해당하는 값을 삭제</li>
<li><code>del 딕셔너리명[키]</code></li>
</ul>
</li>
</ol>
<h4 id="③">③</h4>
<h3 id="3-자료형-함수">3) 자료형 함수</h3>
<h4 id="①-type-함수">① type 함수</h4>
<ul>
<li><p>자료형을 확인하는 함수</p>
</li>
<li><p>기본 자료형(Primitive Data Type)</p>
<table>
<thead>
<tr>
<th align="center">세부 유형</th>
<th align="center">출력</th>
</tr>
</thead>
<tbody><tr>
<td align="center">정수형(Integer)</td>
<td align="center">&lt;class &#39;int&#39;&gt;</td>
</tr>
<tr>
<td align="center">실수형(Floating Point)</td>
<td align="center">&lt;class &#39;float&#39;&gt;</td>
</tr>
<tr>
<td align="center">논리형(Logical)</td>
<td align="center">&lt;class &#39;bool&#39;&gt;</td>
</tr>
</tbody></table>
</li>
<li><p>컬렉션 자료형(Collction Data Type)</p>
<table>
<thead>
<tr>
<th align="center">세부 유형</th>
<th align="center">출력</th>
</tr>
</thead>
<tbody><tr>
<td align="center">문자열형(String)</td>
<td align="center">&lt;class &#39;str&#39;&gt;</td>
</tr>
<tr>
<td align="center">리스트형(List)</td>
<td align="center">&lt;class &#39;list&#39;&gt;</td>
</tr>
<tr>
<td align="center">튜플형(Tuple)</td>
<td align="center">&lt;class &#39;tuple&#39;&gt;</td>
</tr>
<tr>
<td align="center">딕셔너리형(Dictionary)</td>
<td align="center">&lt;class &#39;dict&#39;&gt;</td>
</tr>
<tr>
<td align="center">세트형(Set)</td>
<td align="center">&lt;class &#39;set&#39;&gt;</td>
</tr>
</tbody></table>
</li>
</ul>
<h4 id="②-len-함수">② len 함수</h4>
<ul>
<li>컬렉션 자료형의 크기를 계산하는 함수</li>
</ul>
<h2 id="03-입출력-⭐">03. 입출력 ⭐</h2>
<h3 id="1-표준-출력-함수print">1) 표준 출력 함수(print)</h3>
<h4 id="①-단순-출력-및-개행">① 단순 출력 및 개행</h4>
<ul>
<li><code>print(문자열)</code> : 출력 후에 개행</li>
<li><code>print(문자열, end=&#39;&#39;)</code> : 출력 후에 개행을 하지 않음</li>
</ul>
<h4 id="②-변수-출력">② 변수 출력</h4>
<ul>
<li><code>print(변수명)</code></li>
</ul>
<h3 id="2-표준-입력-함수input">2) 표준 입력 함수(input)</h3>
<ul>
<li>파이썬에서는 정수형이나 실수형과 같은 숫자를 입력받을 때는 문자열로 저장한 후에 <code>eval</code> 함수를 써서 숫자를 변환해 주어야 함<ul>
<li>문자열 입력 : <code>변수명 = input()</code></li>
<li>숫자 입력 : <code>변수명 = eval(변수명)</code></li>
</ul>
</li>
</ul>
<pre><code class="language-python">  s = input() # 1
  s = eval(s)
  print(s) # 1</code></pre>
<h2 id="04-연산자-⭐⭐">04. 연산자 ⭐⭐</h2>
<ul>
<li>프로그램 실행을 위해 연산을 표현하는 기호</li>
</ul>
<h3 id="1-연산자-종류">1) 연산자 종류</h3>
<h4 id="①-swap-연산자">① Swap 연산자</h4>
<ul>
<li>두 변수의 값을 교환하는 연산자</li>
<li>콤마를 기준으로 두 값을 교환</li>
</ul>
<pre><code class="language-python">a, b = 10, 20
print(a) # 10
print(b) # 20
a, b = b, a
print(a) # 20
print(b) # 10</code></pre>
<p>→ 파이썬 연산자는 C언어와 거의 동일하지만 ++, --는 지원하지 않음</p>
<h4 id="②-산술-연산자">② 산술 연산자</h4>
<ul>
<li>두 수의 수치 계산을 위한 연산자</li>
<li>사칙 연산(+, -, <em>, /, //), 지수 연산(*</em>), 나머지 연산(%)</li>
</ul>
<pre><code class="language-python">print(3 / 2) # 1.5
print(3 // 2) # 1 ← 몫 계산
print(3 ** 2) # 9
print(3 % 2) # 1</code></pre>
<h4 id="③-대입-연산자">③ 대입 연산자</h4>
<ul>
<li>변수에 값을 할당하는 연산자</li>
<li>&#39;+=&#39;, &#39;-=&#39;, &#39;<em>=&#39;, &#39;/=&#39; 은 C나 Java와 동일하며, 파이썬에는 추가적으로 &#39;*</em>=&#39;, &#39;//=&#39; 연산자 제공</li>
</ul>
<h2 id="05-조건문과-반복문">05. 조건문과 반복문</h2>
<ul>
<li>파이썬에서는 switch 문이 없음</li>
<li>파이썬에서는 do-while 문이 없음</li>
</ul>
<h3 id="1-for-문">1) for 문</h3>
<ul>
<li>in 연산다 뒤에 range 함수를 사용하여 반복의 범위를 지정하거나 리스트 개수만큼 반복을 수행</li>
</ul>
<p>① 일반 for 문</p>
<ul>
<li>range 함수는 범위를 지정하는 함수</li>
<li>range 함수에서 시작을 생략하면 0, 스텝 값을 생략하면 1이 자동으로 들어감</li>
</ul>
<pre><code class="language-python">for 변수 in range(시작, 종료, 스텝) : 
  명령문</code></pre>
<p>② for each 문</p>
<ul>
<li>시퀀스 자료형의 요소들을 차례대로 변수에 대입하면서 반복하는 명령어</li>
</ul>
<pre><code class="language-python">for 변수 in 시퀀스자료형 : 
  명령문</code></pre>
<ul>
<li><p>파이썬 for each 문</p>
<pre><code class="language-python">li = [1, 2, 3, 4, 5]
for a in li : 
print(a) # 1\n2\n3\n4\n5\n</code></pre>
</li>
<li><p>파이썬 이중 for each 문</p>
<pre><code class="language-python">li = [[1, 2], [3, 4, 5]]
for a in li : 
for b in a :
  print(b, end=&#39;&#39;) # 12345</code></pre>
</li>
</ul>
<h2 id="06-함수-⭐⭐">06. 함수 ⭐⭐</h2>
<h3 id="1-사용자-정의-함수">1) 사용자 정의 함수</h3>
<p>① 사용자 정의 함수(User-Defined Function)</p>
<ul>
<li>사용자가 직접 새로운 함수를 정의하여 사용하는 방법</li>
<li>사용자 정의 함수에서 매개변수나 생성된 변수는 사용자 정의 함수가 종료되면 없어짐</li>
</ul>
<pre><code class="language-python">def 함수명(변수명, ···) :
  명령어
  return 반환값</code></pre>
<p>② 디폴트 매개변수</p>
<ul>
<li>기본값이 정의된 매개변수</li>
<li>함수를 호출할 때, 매개변수가 명시외더 있지 않으면 디폴트 매개변수 값이 전달</li>
</ul>
<pre><code class="language-python">def 함수명(매개변수=디폴트값) :
  명령문</code></pre>
<h3 id="2-람다-함수">2) 람다 함수</h3>
<p>① 람다 함수</p>
<ul>
<li>함수 이름 없이 동작하는 함수</li>
<li>매개변수에 값을 전달하면 표현식에서 연순을 수행</li>
</ul>
<p>② 람다 함수 문법</p>
<ol>
<li>일반 람다 함수<pre><code class="language-python">lambda 매개변수 : 표현식</code></pre>
</li>
</ol>
<ul>
<li>일반 사용자 정의 함수는 def 키워드와 return 키워드를 사용하여 함수를 구현</li>
</ul>
<pre><code class="language-python">(lambda n, m : n + m)(2, 3) # 5 (왜 출력이 되는거지?)</code></pre>
<ol start="2">
<li>변수를 이용한 람다 함수</li>
</ol>
<ul>
<li>람다 함수를 변수에 할당하여 재사용할 수 있음</li>
</ul>
<pre><code class="language-python">sum = lambda n, m : n + m
print(sum(2, 3)) # 5</code></pre>
<ol start="3">
<li>사용자 정의 함수를 이용한 람다 함수</li>
</ol>
<ul>
<li>람다 함수는 사용자 정의 함수로 구현할 수 있음</li>
</ul>
<pre><code class="language-python">def f(n) :
  return lambda a:a*m
k = f(3)
print(k(10)) # 30</code></pre>
<ol start="4">
<li>내장 함수를 이용한 람다 함수 ⭐</li>
</ol>
<ul>
<li><p>람다 함수는 파이썬 map 함수, filter 함수와 같이 사용 가능</p>
<table>
<thead>
<tr>
<th align="center">함수</th>
<th align="center">형태</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>map</code></td>
<td align="center">map(함수, 리스트)</td>
<td>- 첫 번째 매개변수에는 함수, 두 번째 매개변수에는 리스트를 전달 <br>- 리스트 요소를 함수에 전달하여 반복을 수행하는 함수</td>
</tr>
<tr>
<td align="center"><code>filter</code></td>
<td align="center">filter(함수, 리스트)</td>
<td>- 첫 번째 매개변수에는 함수, 두 번째 매개변수에는 리스트를 전달 <br>- 리스트 요소를 함수에 전달하여 조건이 참인 값을 리턴하는 함수</td>
</tr>
</tbody></table>
</li>
<li><p>파이썬 map을 이용한 람다 함수</p>
</li>
</ul>
<pre><code class="language-python">a = [1, 2, 3, 4, 5]
m = list(map(lambda num : num + 100, a))
print(m) # [101, 102, 103, 104, 105]</code></pre>
<ul>
<li>파이썬 filter를 이용한 람다 함수</li>
</ul>
<pre><code class="language-python">a = [1, 2, 3, 4, 5]
m = list(filter(lambda num : num &gt; 2, a))
print(m) # [3, 4, 5]</code></pre>
<h2 id="07-예외-처리-⭐">07. 예외 처리 ⭐</h2>
<h3 id="1-예외-처리">1) 예외 처리</h3>
<p>① 예외 처리</p>
<ul>
<li>작성한 코드가 실행하는 도중에 발생되는 에러를 처리하는 구문</li>
<li>try, except, finally를 이용하여 예외 처리</li>
</ul>
<pre><code class="language-python">try :
  명령문
except :
  예외 발생시 동작할 명령문</code></pre>
<p>→ except 다음에 예외가 발생하는 경우 동작할 코드 작성</p>
<pre><code class="language-python">try :
  명령문
except 발생예외명:
  예외 발생시 동작할 명령문
finally : 
  명령문</code></pre>
<p>→ except에서 특정 예외만 처리하기 위함
→ finally는 try가 실행되고 마지막에 반드시 실행될 명령문</p>
<pre><code class="language-python">try :
  명령문
except 발생예외명1:
  예외 발생시 동작할 명령문1
except 발생예외명2:
  예외 발생시 동작할 명령문2
else : 
  명령문</code></pre>
<p>→ else는 예외가 발생되지 않았을 경우에 실행될 명령문</p>
<pre><code class="language-python">a, b = 2, 0
try :
  print(a/b)
except IndexError as e :
  print(&#39;[exception]&#39;, e)
except ZeroDivisionError as e :
  print(&#39;[exception]&#39;, e) # [exception] division by zero</code></pre>
<p>② raise</p>
<ul>
<li>프로그램이 의도하지 안헤 동작하는 것을 방지하기 위해 의도적으로 예외를 발생시키는 명령</li>
<li>try except 구분 안에서도 사용 가능</li>
</ul>
<pre><code class="language-python">명령문
raise</code></pre>
<pre><code class="language-python">명령문
raise 예외처리명</code></pre>
<pre><code class="language-python">명령문
raise 예외처리명(&quot;메시지&quot;)</code></pre>
<pre><code class="language-python">a, b = 2, 0
try :
  print(a/b)
  raise
except ZeroDivisionError as e :
  print(&#39;에러&#39;) # 에러</code></pre>
<h2 id="08-클래스">08. 클래스</h2>
<h3 id="1-클래스">1) 클래스</h3>
<ul>
<li>객체 지향 프로그래밍(OOP; Object-Oriented Programming)에서 특정 객체를 생성하기 위해 변수와 메서드를 정의하는 틀</li>
</ul>
<h3 id="2-클래스-정의">2) 클래스 정의</h3>
<ul>
<li>클래스에서 변수는 변수 선언과 동일, 메서드는 사용자 정의 함수와 문법 동일</li>
</ul>
<pre><code class="language-python">class 클래스명:
  def 메서드명(self, 변수명, ···):
    명령어
    return 반환값</code></pre>
<ul>
<li>파이썬에서는 함수명에 입력받을 값(매개변수) 앞에 self라는 키워드를 적어야 함</li>
</ul>
<pre><code class="language-python">class Test:
  def fn(self):
    print(5)</code></pre>
<h3 id="3-self">3) self</h3>
<ul>
<li>self는 현재 객체를 가리키는 키워드</li>
<li>클래스 내부의 변수와 함수를 가리킬 수 있음</li>
</ul>
<pre><code class="language-python">self.변수명
self.함수명(매개변수)</code></pre>
<pre><code class="language-python">class Test:
  def setS(self, a):
    self.a = a
  def getS(self):
    return self.a 
a = Test()
a.setS(5)
print(a.getS()) # 5</code></pre>
<h3 id="4-생성자constructor-⭐">4) 생성자(Constructor) ⭐</h3>
<ul>
<li><p>해당 클래스의 객체가 생성될 때 자동으로 호출되는 특수한 종류의 메서드</p>
</li>
<li><p>생성자는 <code>__init__</code>이라는 메서드 명을 사용하고, 첫 번째 매개변수로 <code>self</code>를 작성하며, 반환 값이 없음</p>
</li>
<li><p>생성자 정의</p>
<pre><code class="language-python">class 클래스명:
def __init__(self, 매개변수): 
  명령어</code></pre>
</li>
<li><p>생성자 호출 : <code>클래스변수=클래스(매개변수)</code></p>
</li>
</ul>
<h3 id="5-소멸자destructor">5) 소멸자(Destructor)</h3>
<ul>
<li><p>객체의 수명이 끝났을 때 객체를 제거하기 위한 목적으로 사용되는 메서드</p>
</li>
<li><p>소멸자는 <code>__del__</code>이라는 메서드명을 사용하고, 첫 번째 매개변수에 <code>self</code>를 작성하며, 반환 값이 없음</p>
</li>
<li><p>소멸자 정의</p>
<pre><code class="language-python">class 클래스명:
def __del__(self): 
  명령어</code></pre>
</li>
<li><p>소멸자 호출 : <code>del 클래스변수</code></p>
</li>
</ul>
<pre><code class="language-python">class Test:
  def __init__(self):
    print(&quot;생성자&quot;)
  def __del__(self):
    print(&quot;소멸자&quot;)
  def fn(self):
    print(&quot;일반함수&quot;)

t = Test() # 생성자
t.fn() # 일반함수
del t # 소멸자</code></pre>
<h3 id="6-클래스-접근-제어자">6) 클래스 접근 제어자</h3>
<ul>
<li>파이썬은 <code>private</code>, <code>public</code> 등의 접근 제어자 키워드가 존재하지 않고 작명법(Naming)으로 접근 제어를 해야 함</li>
</ul>
<table>
<thead>
<tr>
<th align="center">종류</th>
<th>규칙</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">public</td>
<td>- 밑줄이 접두사에 없어야 함</td>
<td>- 외부의 모든 클래스에서 접근이 가능한 접근 제어자</td>
</tr>
<tr>
<td align="center">protected</td>
<td>- 한 개즤 밑줄 _이 접두사여야 함</td>
<td>- 같은 패키지 내부에 있는 클래스, 하위 클래스(상속받은 경우)에서 접근이 가능한 접근 제어자 <br>- 자기 자신과 상속받은 하위 클래스 둘 다 접근이 가능한 접근 제어자</td>
</tr>
<tr>
<td align="center">private</td>
<td>- 두 개의 밑줄 __이 접두사여야 함</td>
<td>- 같은클래스 내에서만 접근이 가능한 접근 제어자</td>
</tr>
</tbody></table>
<h2 id="09-클래스-상속">09. 클래스 상속</h2>
<h3 id="1-클래스-상속inheritance">1) 클래스 상속(Inheritance)</h3>
<ul>
<li>상속은 어떤 객체가 있을 때 그 객체의 변수와 메서드를 다른 객체가 물려받는 기능</li>
</ul>
<pre><code class="language-python">class 부모_클래스명:
···
class 자식_클래스명(부모_클래스명):
···</code></pre>
<h3 id="2-메서드-오버라이딩overriding">2) 메서드 오버라이딩(Overriding)</h3>
<ul>
<li>오버라이딩은 하위 클래스에서 상위 클래스 메서드를 재정의할 수 있는 기능<ul>
<li>오버라이드하고자 하는 메서드가 상위 클래스에 존재하여야 함</li>
<li>메서드 이름은 같아야 함</li>
<li>메서드 매개변수 개수, 데이터 타입이 같아야 함</li>
</ul>
</li>
</ul>
<pre><code class="language-python">class 부모_클래스명:
  def 메서드명(self, 변수명) :
    명령어
class 자식_클래스명(부모_클래스명):
  def 메서드명(self, 변수명) : # 부모 클래스와 메서드명, 매개변수가 같아야 함
    명령어</code></pre>
<pre><code class="language-python">class A:
  def fn(self) :
    print(&#39;A&#39;)
class B(A):
  def fn(self) :
    print(&#39;B&#39;)
a = B()
a.fn() # B</code></pre>
<h3 id="3-부모-클래스-접근">3) 부모 클래스 접근</h3>
<ul>
<li>파이썬은 super 키워드를 이용하여 상위 클래스의 변수나 메서드에 접근할 수 있음<pre><code class="language-python">super().메서드명()</code></pre>
</li>
</ul>
<pre><code class="language-python">class A:
  def fn(self) :
    print(&#39;A&#39;)
class B(A):
  def fn(self) :
    super().fn()
    print(&#39;B&#39;)
a = B()
a.fn() # A\nB\n</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[정보처리기사 실기] 10. 프로그래밍 언어 활용 - 자바]]></title>
            <link>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-10.-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4-%ED%99%9C%EC%9A%A9-%EC%9E%90%EB%B0%94</link>
            <guid>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-10.-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4-%ED%99%9C%EC%9A%A9-%EC%9E%90%EB%B0%94</guid>
            <pubDate>Sun, 14 Jul 2024 14:02:00 GMT</pubDate>
            <description><![CDATA[<p>C언어에 이어 JAVA 부분입니다.</p>
<hr>
<h1 id="3-자바">3. 자바</h1>
<h2 id="01-자바-기본-구조">01. 자바 기본 구조</h2>
<ul>
<li>Java에서 모든 소스 코드는 <strong>클래스</strong> 단위로 구성</li>
<li>프로그램은 public static void main부터 시작</li>
</ul>
<blockquote>
<p><strong>클래스(Class)</strong>
객체 지향 관점에서 <strong>객체(Object)</strong>를 정의하는 틀로서 많은 객체 지향 프로그래밍 언어의 기본 구조로, <strong>변수(Variable)</strong>와 <strong>메서드(Method)</strong>로 구성</p>
</blockquote>
<pre><code class="language-java">public class Test {
  public static void main(String[] args){
    System.out.println(&quot;Hello&quot;); // Hello
  }
}</code></pre>
<h2 id="02-자료형">02. 자료형</h2>
<h3 id="1-자료형의-유형">1) 자료형의 유형</h3>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th align="center">설명</th>
<th align="center">선언 형식</th>
<th align="center">크기</th>
</tr>
</thead>
<tbody><tr>
<td align="center">문자형(Character)</td>
<td align="center">- 문자 하나를 저장 <br>- 메모리에 저장은 숫자로</td>
<td align="center">char</td>
<td align="center">1</td>
</tr>
<tr>
<td align="center">문자열형(String)</td>
<td align="center">- 문자 여러 개를 저장</td>
<td align="center">String</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">정수형(Integer)</td>
<td align="center">- 정숫값을 저장</td>
<td align="center">int</td>
<td align="center">4</td>
</tr>
<tr>
<td align="center">부동 소수점<br>(Floating Point)</td>
<td align="center">- 소수점을 포함하는 실숫값 저장</td>
<td align="center">float, double</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">논리형(Logical; Boolean)</td>
<td align="center">- 변수의 참(true), 거짓(false)을 나타냄</td>
<td align="center">boolean</td>
<td align="center"></td>
</tr>
</tbody></table>
<h2 id="03-변수-⭐⭐">03. 변수 ⭐⭐</h2>
<h3 id="1-변수-유효범위variable-scope">1) 변수 유효범위(Variable Scope)</h3>
<p>① 클래스 변수(Class Variable)</p>
<ul>
<li>클래스 <strong>블록</strong>에 선언하는 변수</li>
<li>클래스가 시작되면 변수가 생성되고, 클래스가 종료되면 변수 소멸</li>
<li>클래스 변수는 <strong>클래스 내</strong>에서 사용할 수 있음</li>
</ul>
<pre><code class="language-java">public class Test {
  int a = 5;
  void fn(){
    a = a + 3;
  }
  public static void main(String[] args){
    Test s = new Test();
    s.a = s.a + 5;
    s.fn();
    System.out.println(s.a); // 13
  }
}</code></pre>
<p>② 지역 변수(Local Variable)</p>
<ul>
<li>블록 내에서 선언하는 변수</li>
<li>블록이 시작되는 부분에 바로 선언해주어야 하고, 중괄호가 닫히는 시점에 소멸</li>
<li>지역 변수는 해당 <strong>블록</strong> 안에서만 사용할 수 있음</li>
</ul>
<pre><code class="language-java">public class Test {
  public static void main(String[] args){
    int a = 3;
    System.out.println(a); // 3
  }
}</code></pre>
<p>③ static 변수</p>
<ul>
<li>프로그램이 시작되면 변수가 생성되고, 프로그램이 종료되면 변수가 소멸</li>
<li>static 변수는 프로그램 전체에서 사용할 수 있음</li>
</ul>
<pre><code class="language-java">public class Test {
  static int count = 0;
  }
  public static void main(String[] args){
    Test s = new Test();
    s.count++;
    System.out.println(s.count); // 1
    s.count++;
    System.out.println(s.count); // 2
  }
}</code></pre>
<h2 id="span-stylebackground-colorfff5b104-배열-⭐⭐⭐span"><span style="background-color:#fff5b1">04. 배열 ⭐⭐⭐</span></h2>
<h3 id="1-배열-선언">1) 배열 선언</h3>
<p>① 1차원 배열 선언</p>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th>선언</th>
</tr>
</thead>
<tbody><tr>
<td align="center">초깃값이 없는 경우</td>
<td>자료형 []배열명 = new 자료형[배열_요소_개수]; <br>자료형 배열명[] = new 자료형[배열_요소_개수];</td>
</tr>
<tr>
<td align="center">초깃값이 있는 경우</td>
<td>자료형 []배열명 = {초깃값};</td>
</tr>
</tbody></table>
<ul>
<li>배열 요수 개수에 정의된 숫자만큼 같은 타입의 데이터 공간이 선언</li>
<li>배열 요소 개수를 명시하지 않고 초깃값이 정의되어 있을 경우 초깃값 개수만큼 공간이 선언</li>
<li>자바에서 배열의 크기를 구할 때는 length 속성을 사용</li>
</ul>
<pre><code class="language-java">public class Test {
  public static void main(String[] args){
    int []a = new int[3];
    System.out.println(a.length); // 3
  }
}</code></pre>
<p>② 2차원 배열 선언</p>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th>선언</th>
</tr>
</thead>
<tbody><tr>
<td align="center">초깃값이 없는 경우</td>
<td>자료형 [][]배열명 = new 자료형[행의 개수][열의 개수]; <br>자료형 배열명[][] = new 자료형[행의 개수][열의 개수];</td>
</tr>
<tr>
<td align="center">초깃값이 있는 경우</td>
<td>자료형 [][]배열명 = {{초깃값}, {초깃값}, ··· };</td>
</tr>
</tbody></table>
<pre><code class="language-java">public class Test {
  public static void main(String[] args){
    int[][] a = new int[3][2];
    System.out.println(a.length); // 3
    System.out.println(a[0].length); // 3
  }
}</code></pre>
<pre><code class="language-java">public class Test {
  public static void main(String[] args){
    int[][] a = {{1, 2}, {3}, {4, 5, 6}};
    System.out.println(a.length); // 3
    System.out.println(a[0].length); // 2
    System.out.println(a[1].length); // 1
    System.out.println(a[2].length); // 3 
  }
}</code></pre>
<h2 id="05-표준-입출력-함수-⭐⭐">05. 표준 입출력 함수 ⭐⭐</h2>
<h3 id="1-표준-출력-함수">1) 표준 출력 함수</h3>
<table>
<thead>
<tr>
<th align="center">함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>System.out.print()</code></td>
<td>개행을 하지 않는 출력함수</td>
</tr>
<tr>
<td align="center"><code>System.out.println()</code></td>
<td>개행을 하는 출력함수</td>
</tr>
<tr>
<td align="center"><code>System.out.printf()</code></td>
<td>C 언어처럼 변수를 출력할 수 있는 출력 함수</td>
</tr>
</tbody></table>
<h3 id="2-표준-입력-함수">2) 표준 입력 함수</h3>
<ul>
<li>readLine은 입력장치(키보드)로부터 라인 전체를 읽는 표준 입력 함수</li>
</ul>
<pre><code>System.in.readLine()</code></pre><pre><code class="language-java">import java.io.BufferedReader; // BufferedReader 사용 
import java.io.InputStreamReader; // InputStreamReader 사용
import java.io.IOException; // IOException 사용

public class Test {
  public static void main(String[] args) throws IOException{ // 입력 시 예외처리
    String a = null;
    BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
    a = r.readLine(); // Hello

    System.out.println(a); // Hello
  }
}</code></pre>
<h2 id="06-반복문---for-each-문-⭐">06. 반복문 - for each 문 ⭐</h2>
<h3 id="1-for-each-문">1) for each 문</h3>
<ul>
<li>배열이나 리스트의 크기만큼 반복하는데, 반복할 때마다 배열이나 리스트의 항목을 순차적으로 변수에 대입하는 반복문</li>
</ul>
<pre><code class="language-java">for(제어변수 : 배열) {
  문장;
}</code></pre>
<pre><code class="language-java">public class Test {
  public static void main(String[] args){
    String[] name = {&quot;MINSU&quot;, &quot;DANBI&quot;, &quot;YUJIN&quot;};
    for( String nm : name ){
      System.out.println(nm); // MINSU\nDANBI\nYUJIN
  }
}</code></pre>
<h2 id="07-메서드-⭐⭐">07. 메서드 ⭐⭐</h2>
<h3 id="1-사용자-정의-함수메서드">1) 사용자 정의 함수(메서드)</h3>
<p>① 사용자 정의 함수(User-Defined Function)</p>
<ul>
<li>사용자가 직접 새로운 함수를 정의하여 사용하는 방법</li>
<li>사용자 정의 함수에서 매개변수나 생성된 변수는 <strong>사용자 정의 함수가 종료되면 없어짐</strong></li>
</ul>
<pre><code class="language-java">자료형 함수명(자료형 변수명, ···){
  명령어;
  return 반환값;
}</code></pre>
<pre><code class="language-java">public class Test {
  static char fn(int num){
    if(num % 2 == 0)
      return &#39;Y&#39;;
    else 
      return &#39;N&#39;;
  }
  public static void main(String[] args){
    char a = fn(5);
    System.out.print(a); // N
  }
}</code></pre>
<h3 id="2-static-메서드">2) static 메서드</h3>
<ul>
<li>클래스가 메모리에 올라갈 때 자동적으로 생성되는 메서드</li>
<li>⭐ <strong>인스턴스</strong>를 생성하지 않아도 호출이 가능<blockquote>
<p><strong>인스턴스</strong>란 클래스로부터 만들어진 객체</p>
</blockquote>
</li>
</ul>
<pre><code class="language-java">class Test {
  static void print(){
    System.out.println(&quot;static method&quot;);
  }
}
public class TestMain {
  public static void main(String[] args){
    Test.print(); // static method
  }
}</code></pre>
<p>→ ⭐ 자바는 <strong>클래스 이름과 파일 이름이 같아야 함</strong>. <strong>main 메서드가 포함된 클래스</strong>를 기준으로 하는데, 위 예제는 TestMain 클래스에 main 메서드가 포함되어 있으므로 <strong>TestMain.java</strong> 파일에 코드를 넣어서 실행해야 함</p>
<h2 id="span-stylebackground-colorfff5b108-클래스-⭐⭐⭐span"><span style="background-color:#fff5b1">08. 클래스 ⭐⭐⭐</span></h2>
<h3 id="1-클래스class">1) 클래스(class)</h3>
<ul>
<li>객체 지향 프로그래밍(OOP; Object-Oriented Origrannubg)에서 특정 객체를 생성하기 위해 변수와 메서드를 정의하는 틀</li>
</ul>
<h3 id="2-클래스-접근-제어자">2) 클래스 접근 제어자</h3>
<p>① 클래스 접근 제어자(Access Modifier)</p>
<ul>
<li>지정된 클래스, 변수, 메서드를 외부(같은 패키지이거나 다른 패키지)에서 접근할 수 있도록 권한을 설정하는 기능</li>
</ul>
<p>② 클래스 접근 제어자 종류</p>
<table>
<thead>
<tr>
<th align="center">종류</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>public</code></td>
<td>- 외부의 모든 클래스에서 접근이 가능한 접근 제어자</td>
</tr>
<tr>
<td align="center"><code>protected</code></td>
<td>- 같은 패키지 내부에 있는 클래스, 하위 클래스(상속받은 경우)에서 접근이 가능한 접근 제어자 <br>- 자기 자신과 상속받은 하위 클래스 둘 다 접근이 가능한 접근 제어자</td>
</tr>
<tr>
<td align="center"><code>default</code></td>
<td>- 접근 제어자를 명시하지 않은 경우로 같은 패키지 내부에 있는 클래스에서 접근이 가능한 접근 제어자(java에만 존재)</td>
</tr>
<tr>
<td align="center"><code>private</code></td>
<td>- 같은 클래스 내에서만 접근이 가능한 접근 제어자</td>
</tr>
</tbody></table>
<h3 id="⭐-3-클래스-정의">⭐ 3) 클래스 정의</h3>
<ul>
<li>클래스에서 변수는 변수 선언과 동일하고, 메서드는 사용자 정의 함수와 문법이 동일</li>
<li>일반적으로 <strong>변수는 <code>private</code></strong> 접근 제어자를 사용하여 외부에서 접근하지 못하게 하며, 메서드는 <strong>외부에 공개할 것만 <code>public</code></strong> 접근 제어자를, 그렇지 않으면 <code>protected</code>나 <code>private</code> 접근 제어자를 사용하여 <strong>정보은닉</strong>을 함</li>
</ul>
<pre><code class="language-java">public class 클래스명{
  private 자료형 변수명;
  public 반환_자료형 메서드명(자료형 변수명, ···){
    명령어;
    return 반환값;
  }
}</code></pre>
<h3 id="⭐-4-클래스의-변수-생성">⭐ 4) 클래스의 변수 생성</h3>
<ul>
<li>클래스는 객체를 생성하기 위해 변수와 메서드를 정의하는 틀이므로 실제 변수에 들어갈 <strong>인스턴스를 <code>new</code> 키워드</strong>로 생성해주어야 함</li>
<li>변수를 이용해 <strong>클래스의 메서드</strong>에 접근</li>
</ul>
<pre><code class="language-java">클래스명 변수명 = new 클래스명(파라미터);
변수명.메서드명();</code></pre>
<h3 id="5-클래스-this">5) 클래스 this</h3>
<ul>
<li>this는 현재 객체를 가리키는 키워드</li>
<li>클래스 내부의 변수와 메서드를 가리킬 수 있음</li>
</ul>
<pre><code class="language-java">this.변수;
this.함수(매개변수);</code></pre>
<pre><code class="language-java">class Test {
  private int a;
  public void setA(int a){
    this.a = a;
  }
  public int getA(){
    return a;
  }
  public static void main(String[] args){
    Test tes = new Test();
    tes.setA(5);
    System.out.print(tes.getA()); // 5
  }
}</code></pre>
<h3 id="6-생성자constructor-⭐">6) 생성자(Constructor) ⭐</h3>
<ul>
<li>해당 클래스의 객체가 생성될 때 자동으로 호출되는 특수한 종류의 메서드</li>
<li>생성자는 일반적으로 클래스의 <strong>멤버 변수를 초기화</strong>하거나 클래스를 사용하는 데 필요한 <strong>설정이 필요한 경우</strong> 사용</li>
<li>생성자는 클래스 명과 동일한 메서드명을 가지고, 반환 값이 없음</li>
<li>생성자가 없을 경우 <code>public 클래스명(){}</code> 이라는 아무 일도 하지 않는 생성자가 있는 것처럼 동작</li>
</ul>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th>코드</th>
</tr>
</thead>
<tbody><tr>
<td align="center">생성자 정의</td>
<td><code>public class 클래스명{</code> <br> <code>public 클래스명(매개변수){</code> <br> <code>명령어; }  }</code></td>
</tr>
<tr>
<td align="center">생성자 호출</td>
<td><code>클래스명 클래스변수 = new 클래스명(매개변수);</code></td>
</tr>
</tbody></table>
<h3 id="7-소멸자destructor---finalize-메서드">7) 소멸자(Destructor) - finalize 메서드</h3>
<ul>
<li>finalize 메서드는 객체의 수명이 끝났을 때 <strong>객체를 제거</strong>하기 위한 목적으로 사용되는 메서드</li>
<li><strong>반환 값이 없음</strong></li>
</ul>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th>코드</th>
</tr>
</thead>
<tbody><tr>
<td align="center">소멸자 정의</td>
<td><code>public class 클래스명{</code> <br> <code>public void finalize(매개변수){</code> <br> <code>명령어; }  }</code></td>
</tr>
<tr>
<td align="center">생성자 호출</td>
<td><code>클래스변수.finalize(매개변수);</code></td>
</tr>
</tbody></table>
<pre><code class="language-java">class Test {
  public Test(){
    System.out.print(&quot;A&quot;);
  }
  public Test(int a){
    System.out.print(&quot;B: &quot;+a);
  }
  public void finalize(){
    System.out.print(&quot;C&quot;);
  }
  public void fn(){
    System.out.print(&quot;D&quot;);
  }
  public static void main(String[] args){
    Test tes1 = new Test(); // A
    Test tes2 = new Test(5); // B: 5
    tes1.fn(); // D
    tes1.finalize(); // C
  }
}</code></pre>
<h2 id="span-stylebackground-colorfff5b109-클래스-상속-⭐⭐⭐span"><span style="background-color:#fff5b1">09. 클래스 상속 ⭐⭐⭐</span></h2>
<h3 id="1-클래스-상속inheritance">1) 클래스 상속(Inheritance)</h3>
<ul>
<li>상속은 어떤 객체가 있을 때 그 객체의 변수와 메서드를 다른 객체가 물려받는 기능</li>
<li>자식 클래스를 생성하면 무조건 <strong>부모 클래스의 생성자를 실행한 후</strong>에 자식 클래스의 생성자를 실행</li>
</ul>
<h3 id="⭐-2-상속-문법">⭐ 2) 상속 문법</h3>
<pre><code class="language-java">class 부모_클래스명{ // 슈퍼 클래스
}
class 자식_클래스명 extends 부모_클래스명{ // 하위 클래스, 서브 클래스
}</code></pre>
<pre><code class="language-java">class A {
  public void fnA(){
    System.out.print(&quot;A&quot;);
  }
}
class B extends A{
  public void fnB(){
    System.out.print(&quot;B&quot;);
  }
}
public class Test {
  public static void main(String[] args){
    B b = new B();
    b.fnA(); // A
    b.fnB(); // B
  }
}</code></pre>
<p>→ ⭐ <strong>자바</strong>는 자식 클래스를 생성하면 <strong>부모 클래스 생성자를 먼저 방문</strong>하지만, <strong>파이썬</strong>은 <strong>자식 클래스의 생성자</strong>만 방문</p>
<h3 id="3-오버로딩overloading">3) 오버로딩(Overloading)</h3>
<ul>
<li>동일 이름의 메서드를 매개변수만 다르게 하여 여러 개 정의할 수 있는 기능<ul>
<li>메서드 이름이 같아야 함</li>
<li>매개변수 개수가 달라야 함</li>
<li>매개변수 개수가 같을 경우 데이터 타입이 달라야 함</li>
<li>반환형은 같거나 달라도 됨</li>
</ul>
</li>
</ul>
<pre><code class="language-java">class A {
  public void fn(){
    System.out.println(&quot;A&quot;);
  }
  public void fn(int i){
    System.out.println(i);
  }
  public void fn(double d){
    System.out.println(d);
  }
  public int fn(int a, int b){
    return a+b;
  }
}
public class Test {
  public static void main(String[] args){
    A a = new A();
    a.fn(); // A
    a.fn(7); // 7
    a.fn(10.0); // 10.0
    System.out.print(a.fn(2, 3)); // 5
  }
}</code></pre>
<h3 id="4-오버라이딩overriding">4) 오버라이딩(Overriding)</h3>
<ul>
<li>하위 클래스에서 상위 클래스 메서드를 재정의할 수 있는 기능<ul>
<li>오버라이드하고자 하는 메서드가 상위 클래스에 존재하여 함</li>
<li>메서드 이름은 같아야 함</li>
<li>메서드 매개변수 개수, 데이터 타입이 같아야 함</li>
<li>메서드 반환형이 같아야 함</li>
</ul>
</li>
</ul>
<pre><code class="language-java">class 부모_클래스명{
  public 반환_자료형 메서드명(자료형 변수명){ }
}
class 자식_클래스명 extends 부모_클래스명{
  public 반환_자료형 메서드명(자료형 변수명){ 
    // 부모 클래스의 메서드명, 매개변수가 동일해야 함
  }
}</code></pre>
<pre><code class="language-java">class A {
  public void fn(){
    System.out.println(&quot;A&quot;);
  }
}
class B extends A {
  public void fn(){
    System.out.println(&quot;B&quot;);
  }
}
public class Test {
  public static void main(String[] args){
    A a = new B(); // B의 생성자 B()와 A의 생성자 A()를 호출해야 하지만 둘 다 없으므로 아무 일 X
    a.fn(); // B
  }
}</code></pre>
<p>→  <code>A a = new B();</code> 는 <strong>다형성</strong>(polymorphism)의 예로, 부모 클래스 A의 참조 변수가 자식 클래스 B의 인스턴스를 참조할 수 있음을 보여줌</p>
<ul>
<li><strong>생성자 vs 오버라이딩</strong> : 생성자는 클래스명과 동일한 이름의 메서드, 오버라이딩은 부모, 자식 간 동일한 이름의 메서드</li>
</ul>
<pre><code class="language-java">class Parent {
  public Parent(){
    System.out.println(&quot;A&quot;);
  }
  public void fn(){
    System.out.println(&quot;B&quot;);
  }
}
class Child extends Parent {
  public Child(){
    System.out.println(&quot;C&quot;);
  }
  public void fn(){
    System.out.println(&quot;D&quot;);
  }
}
public class Test {
  public static void main(String[] args){
    Child c = new Child(); // A\nC\n
    c.fn(); // D
}</code></pre>
<h3 id="5-부모-클래스-접근">5) 부모 클래스 접근</h3>
<ul>
<li>자바는 <code>super</code> 키워드를 이용하여 상위 클래스의 변수나 메서드에 접근할 수 있음</li>
</ul>
<pre><code class="language-java">super.메서드명();</code></pre>
<pre><code class="language-java">class A {
  public void fn(){
    System.out.println(&quot;A&quot;);
  }
}
class B extends A {
  public void fn(){
    super.fn();
    System.out.println(&quot;B&quot;);
  }
}
public class Test {
  public static void main(String[] args){
    A a = new B(); 
    a.fn(); // A\nB\n
  }
}</code></pre>
<h2 id="10-추상-클래스-⭐⭐">10. 추상 클래스 ⭐⭐</h2>
<h3 id="1-추상-클래스">1) 추상 클래스</h3>
<ul>
<li>미구현 추상 메서드를 한 개 이상 가지며, 자식 클래스에서 해당 추상 메서드를 반드시 구현하도록 강제하는 기능</li>
</ul>
<pre><code class="language-java">abstract class 추상_클래스명 { 
  abstract 자료형 메서드명(); // 메서드 내부는 정의하지 않음
}
class 자식_클래스명 extends 추상_클래스명{
  자료형 메서드명(){
    명령어; // 메서드를 상속받아 메서드 내부를 정의
  }
}</code></pre>
<h2 id="11-인터페이스-⭐">11. 인터페이스 ⭐</h2>
<h3 id="1-인터페이스interface">1) 인터페이스(Interface)</h3>
<ul>
<li>자바의 다형성을 극대화하여 개발코드 수정을 줄이고 프로그램 유지보수성을 높이기 위한 문법(인터페이스는 일종의 추상 클래스)</li>
<li>오직 <strong>추상 메서드</strong>와 <strong>상수</strong>만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 <strong>허용하지 않음</strong></li>
<li>인터페이스는 구현된 것은 아무것도 없고 밑그림만 그려져 있는 &#39;기본 설계도&#39;</li>
</ul>
<pre><code class="language-java">interface 인터페이스_클래스명 {
  자료형 메서드명(); // 메서드 내부는 정의하지 않음
}
class 자식_클래스명 implements 인터페이스_클래스명{
  자료형 메서드명(){
    // interface의 메서드를 상속받아 내부를 정의
  }
}</code></pre>
<pre><code class="language-java">interface A{
  void fn();
}
class B implements A {
  public void fn(){
    System.out.println(&quot;B&quot;);
  }
}
class C implements A {
  public void fn(){
    System.out.println(&quot;C&quot;);
  }
}
public class Test {
  public static void main(String[] args){
    A b = new B(); 
    A c = new C(); 
    b.fn(); // B
    c.fn(); // C
  }
}</code></pre>
<h2 id="12-스레드-⭐">12. 스레드 ⭐</h2>
<h3 id="1-스레드">1) 스레드</h3>
<ul>
<li>프로세스보다 가벼운, 독립적으로 수행되는 순차적인 제어의 흐름이며, 실행 단위</li>
</ul>
<h3 id="2-스레드-구현">2) 스레드 구현</h3>
<p>① Thread 클래스 상속 </p>
<ol>
<li>Thread 클래스 상속 부분</li>
</ol>
<ul>
<li>스레드를 만들기 위해서는 <code>Thread</code> 클래스를 상속받고, <code>run()</code> 메서드에 스레드 동작 시 수행할 코드를 작성(run 메서드 오버라이딩)</li>
</ul>
<pre><code class="language-java">class T_Test extends Thread{
  public void run(){
    // 스레드 동작 시 수행할 코드
  }
}</code></pre>
<p>→ Thread 클래스의 run() 메서드를 상속받아 재정의</p>
<ol start="2">
<li>Thread 클래스 호출 부분</li>
</ol>
<ul>
<li>스레드 클래스를 생성하여 스레드 변수에 저장
1) <code>Thread 스레드변수 = new 상속받은스레드클래스();</code>
2) <code>Thread 스레드변수 = new Thread(new 상속받은스레드클래스());</code></li>
<li><code>스레드변수.start()</code>를 통해 스레드의 <code>run()</code> 메서드를 실행</li>
</ul>
<pre><code class="language-java">class T_Test extends Thread{
  public void run(){
    System.out.println(&quot;Run&quot;);
  }
}

public class Test {
  public static void main(String[] args){
    Thread t1 = new T_Test(); 
    Thread t2 = new Thread(new T_Test());

    t1.start();
    t2.start();
    System.out.println(&quot;Main&quot;);
  }
}</code></pre>
<p>→ main 함수에서 <code>t1.start();</code> 이후, <code>t2.start();</code>를 하면 main 함수와 t1 스레드, t2 스레드가 동시에 동작하게 되므로 출력 결과는 달라질 수 있음</p>
<p>② Runnable 인터페이스 상속</p>
<ol>
<li>Runnable 인터페이스 상속 부분</li>
</ol>
<ul>
<li>스레드를 만들기 위해서는 Runnable 인터페이스 상속받고, <code>run()</code> 메서드에 스레드 동작 시 수행할 코드를 작성(run 메서드 오버라이딩) <pre><code class="language-java">class T_Test implements Runnable{
public void run(){
  // 스레드 동작 시 수행할 코드
}
}</code></pre>
→ Runnable 클래스의 run() 메서드를 상속받아 재정의</li>
</ul>
<ol start="2">
<li>Runnable 클래스 호출 부분</li>
</ol>
<ul>
<li>스레드 클래스를 생성하여 스레드 변수에 저장
1) <code>Thread 스레드변수 = new Thread(new 상속받은스레드클래스());</code></li>
<li>위 Thread와 마찬가지로 <code>스레드변수.start()</code>를 통해 스레드의 <code>run()</code> 메서드를 실행</li>
</ul>
<h2 id="13-컬렉션-⭐">13. 컬렉션 ⭐</h2>
<h3 id="1-컬렉션-프레임워크collection-framework의-개념">1) 컬렉션 프레임워크(Collection Framework)의 개념</h3>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/7a3598f8-d41f-4952-8a13-82b676334bf8/image.png" alt="">
<a href="https://backendcode.tistory.com/163" target="_blank" style="color: gray">출처 : [IT 기술 면접] Java의 Collection Framework 이란? </a></p>
<ul>
<li>다수의 데이터를 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합</li>
<li>자바에서는 컬렉션 프레임워크를 통해 모든 컬렉션 클래스와 인터페이스를 제공</li>
<li>⭐ map은 Collection 인터페이스를 상속받고 있지 않지만 Collection으로 분류</li>
</ul>
<h3 id="2-컬렉션-프레임워크-특징">2) 컬렉션 프레임워크 특징</h3>
<ul>
<li><strong>배열의 단점을 보완</strong> : 배열(Array)의 단점을 보완하여 만들어진 클래스로, 메모리 낭비를 방지하고 동적인 크기 변경 가능</li>
<li><strong>자료구조의 구현</strong> : 자료구조 형태인 List, Set, Map 등이 클래스로 구현</li>
<li><strong>일관된 인터페이스</strong> : 대량의 데이터를 일관된 인터페이스로 제공하여 쉽고 효율적으로 프로그램 작성 가능</li>
</ul>
<h3 id="3-컬렉션-프레임워크의-구조">3) 컬렉션 프레임워크의 구조</h3>
<ul>
<li>자바에서 컬렉션 프레임워크는 인터페이스로 List, Set, Map 등을 제공</li>
<li>⭐ Vector와 Hashtable의 경우 컬렉션 프레임워크의 명명법을 따르지 않음 → 가능하면 Vector 대신 ArrayList를, Hashtable 대신 Hashmap 사용을 권장</li>
</ul>
<table>
<thead>
<tr>
<th align="center">인터페이스</th>
<th align="center">구현 클래스</th>
<th align="center">특징</th>
</tr>
</thead>
<tbody><tr>
<td align="center">List</td>
<td align="center">LinkedList <br>ArrayList</td>
<td align="center">중복이 가능하고, 순서가 있는 데이터의 집합</td>
</tr>
<tr>
<td align="center">Set</td>
<td align="center">HashSet <br>TreeSet</td>
<td align="center">중복이 불가능하고, 순서가 없는 데이터의 집합</td>
</tr>
<tr>
<td align="center">Map</td>
<td align="center">Hashtable <br>HashMap <br>TreeMap</td>
<td align="center">&lt;키, 값&gt;의 구조로 키는 중복이 불가능하고 값은 중복이 가능한 데이터의 집합</td>
</tr>
</tbody></table>
<h2 id="14-예외-처리-⭐">14. 예외 처리 ⭐</h2>
<h3 id="1-예외-처리exception-handling">1) 예외 처리(Exception Handling)</h3>
<ul>
<li>프로그램이 동작 중에 의도하지 않은 비정상적인 동작을 처리</li>
</ul>
<table>
<thead>
<tr>
<th>구문</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td><code>try {</code> <br> <code>명령문;</code> <br> <code>}</code> <br> <code>catch ( 예외처리명 ) {</code> <br> <code>예외처리_명령문;</code> <br> <code>}</code> <br> <code>finally {</code> <br> <code>명령문;</code> <br> <code>}</code></td>
<td>- try 다음에 수행할 명령문에서 예외가 발생하면 catch에서 예외를 처리 <br> - catch는 하나 이상 작성하며, 상황에 맞는 예외처리가 수행됨 <br> - finally 문장은 예외처리가 끝나고 받드시 실행되어야 하는 명령문을 수행함</td>
</tr>
</tbody></table>
<pre><code class="language-java">public class Test {
  public static void main(String[] args){
    try {
      int a = 4/0;
    }
    catch (Exception e) {
      System.out.println(e.getMessage()); // /by zero(0으로 나눌 수 없어 예외 발생)
    }
    finally {
      System.out.println(&quot;Finally&quot;);
    }
  }
}</code></pre>
<h3 id="2-throw">2) throw</h3>
<ul>
<li>의도적으로 예외를 던지는 예약어</li>
<li>컴파일에는 문제가 없지만 런타임에 발생된 에러를 처리하기 위해 사용</li>
</ul>
<pre><code class="language-java">public class Test {
  public static void main(String[] args){
    try {
      throw new Exception();
    }
    catch (Exception e) {
      System.out.println(&quot;강제 예외 발생&quot;); 
    }
  }
}</code></pre>
<h3 id="⭐-3-throws">⭐ 3) throws</h3>
<ul>
<li>메서드에서 발생하는 예외를 던지는 예약어</li>
</ul>
<pre><code class="language-java">접근제어자 자료형 메서드명(매개변수) throws 예외처리명{
  명령문;</code></pre>
<pre><code class="language-java">public class Test {
  public void divide(int a, int b) throws Eception{
    System.out.println(a/b); 
  }
  public static void main(String[] args){
    try {
      a.divide(4, 0);
    }
    catch (Exception e) {
      System.out.println(e.getMessage()); // /by zero
    }
  }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[정보처리기사 실기] 10. 프로그래밍 언어 활용 - 진법 변환, C언어]]></title>
            <link>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-10.-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@cey_adda/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-10.-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Mon, 08 Jul 2024 13:05:56 GMT</pubDate>
            <description><![CDATA[<p>정보처리기사 공부를 다시 시작했습니다. </p>
<hr>
<h1 id="1-프로그래밍을-위한-기본-사항">1. 프로그래밍을 위한 기본 사항</h1>
<h2 id="01-진수">01. 진수</h2>
<h3 id="1-진수antilogarithm">1) 진수(Antilogarithm)</h3>
<ul>
<li>특정 개수의 숫자만을 이용하여 수를 나타내는 수 체계<h3 id="2-진수-변환">2) 진수 변환</h3>
① 10진수를 n진수로 변환</li>
<li>10진수 값을 몫이 작은 n보다 작을 때까지 n으로 나누고 나머지 값들을 표시한 후에 나머지 값들을 읽음</li>
</ul>
<p>② n진수를 10진수로 변환</p>
<ul>
<li>n진수에서 마지막 자리는 자리 숫자에 자릿값인 $\text n^0$을 곱하고, 마지막에서 두 번째 자리는 자리 숫자에 자릿값인 $\text n^1$을 곱하고, 마지막에서 세 번째 자리는 자리 숫자에 자릿값인 $\text n^2$을 곱하고, ··· 자리 숫자와 자릿값을 더해 10진수를 계산</li>
</ul>
<h3 id="3-아스키-코드">3) 아스키 코드</h3>
<p>① 아스키 코드</p>
<ul>
<li>미국 ANSI에서 표준화한 정보교환용 부호체계</li>
<li>영문 키보드로 입력할 수 있는 모든 기호가 할당된 기본적인 부호체계</li>
</ul>
<p>② 주요 아스키 코드</p>
<table>
<thead>
<tr>
<th align="center">10진수</th>
<th align="center">부호</th>
<th align="center">10진수</th>
<th align="center">부호</th>
<th align="center">10진수</th>
<th align="center">부호</th>
</tr>
</thead>
<tbody><tr>
<td align="center">0</td>
<td align="center">NULL</td>
<td align="center">65</td>
<td align="center">A</td>
<td align="center">97</td>
<td align="center">a</td>
</tr>
<tr>
<td align="center">32</td>
<td align="center">&#39; &#39;(Space)</td>
<td align="center">66</td>
<td align="center">B</td>
<td align="center">98</td>
<td align="center">b</td>
</tr>
<tr>
<td align="center">48</td>
<td align="center">0</td>
<td align="center">67</td>
<td align="center">C</td>
<td align="center">99</td>
<td align="center">c</td>
</tr>
<tr>
<td align="center">49</td>
<td align="center">1</td>
<td align="center">68</td>
<td align="center">D</td>
<td align="center">100</td>
<td align="center">d</td>
</tr>
</tbody></table>
<h1 id="2-c언어">2. C언어</h1>
<h2 id="01-c언어-기본">01. C언어 기본</h2>
<h3 id="1-c언어-기본-구조">1) C언어 기본 구조</h3>
<ul>
<li>C언어는 본문 전에 처리하는 전처리 부분과 본문으로 구성되어 있음</li>
<li>헤더는 xxx.h 파일로, 헤더 안에는 프로그래밍에 필요한 함수가 포함<h3 id="2-전처리기">2) 전처리기</h3>
① 전처리기(Preprocessor)</li>
<li>실행 파일을 생성하는 과정에서 소스 파일 내에 존재하는 전처리 지시문을 처리하는 작업</li>
</ul>
<p>② 전처리기 종류</p>
<ul>
<li><code>#include</code> : C언어 프로그램에 <strong>헤더 파일</strong>을 포함할 때 사용하는 전처리기</li>
<li><code>#define</code> : <strong>매크로</strong>를 정의할 때 사용하며, <strong>상숫값</strong>을 지정하기 위한 예약어로 구문의 상수로 치환할 때 사용하는 전처리기</li>
</ul>
<h2 id="02-자료형-⭐">02. 자료형 ⭐</h2>
<h3 id="1-자료형">1) 자료형</h3>
<ul>
<li>프로그래밍 언어에서 실숫값, 정숫값과 같은 여러 종류의 데이터를 식별하는 형태</li>
<li><strong>메모리 공간</strong>을 효율적으로 사용하고 <strong>2진수 데이터</strong>를 다양한 형태로 사용하기 위해 존재</li>
</ul>
<h3 id="2-자료형-유형">2) 자료형 유형</h3>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th align="center">설명</th>
<th align="center">선언 형식</th>
</tr>
</thead>
<tbody><tr>
<td align="center">문자(Character)</td>
<td align="center">- 문자 하나를 저장 <br>- 메모리에 저장은 숫자로</td>
<td align="center">char</td>
</tr>
<tr>
<td align="center">정수(Integer)</td>
<td align="center">- 정숫값을 저장</td>
<td align="center">int</td>
</tr>
<tr>
<td align="center">부동 소수점<br>(Floating Point)</td>
<td align="center">- 소수점을 포함하는 실숫값 저장</td>
<td align="center">float, double</td>
</tr>
</tbody></table>
<h2 id="03-식별자-⭐">03. 식별자 ⭐</h2>
<h3 id="1-식별자">1) 식별자</h3>
<ul>
<li>변수, 상수, 함수 등 서로 구분하기 위해 사용되는 이름</li>
<li>프로그램의 구성요소를 구별하기 위해 사용</li>
</ul>
<h3 id="2-식별자-명명-규칙">2) 식별자 명명 규칙</h3>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th align="center">규칙</th>
<th align="center">사용 가능 예시</th>
<th align="center">사용 불가능 예시</th>
</tr>
</thead>
<tbody><tr>
<td align="center">사용 가능 문자</td>
<td align="center">- 영문 대문자/소문자, 숫자, 밑줄 사용 가능</td>
<td align="center">a, A, a1, _, _hello</td>
<td align="center">?a, &lt;a</td>
</tr>
<tr>
<td align="center">변수 사용 규칙</td>
<td align="center">- 첫 자리에는 숫자 사용 불가 <br>- 변수 이름 중간에 공백 사용 불가</td>
<td align="center">_1, a1, a100 <br>my_student</td>
<td align="center">1, 1a, 1A, 1234 <br>my student</td>
</tr>
<tr>
<td align="center">변수 의미 부여</td>
<td align="center">- 이미 사용되고 있는 예약어의 경우 변수 사용 불가</td>
<td align="center">For, If, While</td>
<td align="center">int, shor, long, ···</td>
</tr>
</tbody></table>
<blockquote>
<p><strong>에약어</strong>
이미 문법적인 용도로 사용되고 있는 단어</p>
</blockquote>
<h3 id="3-식별자-표기법">3) 식별자 표기법</h3>
<table>
<thead>
<tr>
<th align="center">표기법</th>
<th align="center">설명</th>
<th align="center">예시</th>
</tr>
</thead>
<tbody><tr>
<td align="center">카멜 표기법 <br>(Camel Case)</td>
<td align="center">- 여러 단어가 이어지면 첫 단어 시작만 <strong>소문자</strong>로,<br> 각 단어의 첫 글자는 <strong>대문자</strong>로 지정</td>
<td align="center">inputFunction</td>
</tr>
<tr>
<td align="center">파스칼 표기법<br>(Pascal Case)</td>
<td align="center">- 여러 단어가 이어지면 각 단어의 <br>첫 글자는 <strong>대문자</strong>로 지정하는 표기법</td>
<td align="center">InputFunction</td>
</tr>
<tr>
<td align="center">스네이크 표기법<br>(Snake Case)</td>
<td align="center">- 여러 단어가 이어지면 단어 사이에<br><strong>언더바</strong>를 넣는 표기법</td>
<td align="center">input_function</td>
</tr>
<tr>
<td align="center">헝가리안 표기법<br>(Hungarian Case)</td>
<td align="center">- <strong>두어</strong>에 자료형을 붙이는 표기법 <br>- int 형일 경우 n, char 형일 경우 c, <br>문자열일 경우 sz를 붙임</td>
<td align="center">nScore</td>
</tr>
</tbody></table>
<h2 id="span-stylebackground-colorfff5b104-변수-⭐⭐span"><span style="background-color:#fff5b1">04. 변수 ⭐⭐</span></h2>
<h3 id="1-변수variable">1) 변수(Variable)</h3>
<ul>
<li>저장하고자 하는 어떠한 값이 있을 때, 그 값을 주기억장치에 기억하기 위한 공간</li>
</ul>
<h3 id="2-변수-선언variable-declaration">2) 변수 선언(Variable Declaration)</h3>
<ul>
<li>변수나 함수가 있음을 알려주는 행위</li>
<li>변수가 어떤 자료형을 사용할지 알려주기 위해 사용<ul>
<li>초기화하지 않는 경우 : <code>자료형 변수명;</code></li>
<li>초기화하는 경우 : <code>자료형 변수명=초깃값;</code></li>
</ul>
</li>
</ul>
<h3 id="3-변수-유효범위variable-scope">3) 변수 유효범위(Variable Scope)</h3>
<p>① 전역 변수(Global Variable)</p>
<ul>
<li>어떤 블록에도 속하지 않은 변수<blockquote>
<p>블록(Block) : C언어에서 중괄호로 묶는 부분</p>
</blockquote>
</li>
<li>프로그램이 시작되면 변수가 생성되고, 프로그램이 종료되면 변수가 소멸</li>
<li>초기화하지 않으면 정수형은 0, 실수형은 0.0, 문자형은 NULL로 초기화</li>
<li>아무 곳에서나 사용 가능</li>
</ul>
<p>② 지역 변수(Local Variable)</p>
<ul>
<li>블록 내에서 선언하는 변수</li>
<li>블록이 시작되는 부분에 바로 선언해주어야 하고, 중괄호가 닫히는 시점에 소멸</li>
<li>해당 블록 안에서만 사용 가능</li>
</ul>
<p>③ static 변수(초기화용)</p>
<ul>
<li>블록 내외부 상관없이 선언할  수 있는 변수</li>
<li>변수 선언할 때 static이라는 키워드를 붙임</li>
<li>블록 내외부 상관없이 프로그램이 시작되면 변수가 생성되고, 프로그램이 종료되면 변수 소멸</li>
<li>전역 변수로 선언할 경우 프로그램 전체에서, 블록 내에 선언할 경우 블록 내에서만 사용 가능</li>
</ul>
<h2 id="span-stylebackground-colorfff5b105-표준-입출력-함수-⭐⭐span"><span style="background-color:#fff5b1">05. 표준 입출력 함수 ⭐⭐</span></h2>
<h3 id="1-표준-출력-함수printf">1) 표준 출력 함수(printf)</h3>
<ul>
<li>printf는 지정된 지정된 포맷 스트링으로 데이터를 출력하는 함수</li>
</ul>
<p>① 단순 출력</p>
<pre><code>printf(문자열);</code></pre><p>② 이스케이프 문자를 이용한 출력</p>
<ul>
<li><strong>이스케이프 문자</strong>는 문자열 내에서 특수한 기능을 수행하는 문자</li>
<li>특수한 기능을 수행하기 위해서 이스케이프 문자를 printf 함수의 큰 따옴표 안에 넣음<ul>
<li><code>\n</code> (New Line) : 커서를 다음 줄 앞으로 이동(개행)</li>
<li><code>\t</code> (Tab) : 커서를 일정 간격만큼 수평 이동</li>
</ul>
</li>
</ul>
<p>③ 포맷 스트링을 이용한 변수 출력</p>
<ul>
<li>일반적으로  scanf를 통해 사용자로투버 입력을 받아들이거나 printf를 통해 결과를 출력하기 위해 사용하는 형식</li>
<li>인자에는 변수명, 값, 수식이 올 수 있음<pre><code>printf(포맷_스트링이_포함된_문자열, 인자, ···);</code></pre></li>
</ul>
<table>
<thead>
<tr>
<th align="center">유형</th>
<th align="center">표현</th>
<th align="center">의미</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">문자 <br>(Character)</td>
<td align="center">%c</td>
<td align="center">Character</td>
<td align="center">- 문자 1글자에 대한 형식</td>
</tr>
<tr>
<td align="center">문자열<br>(String)</td>
<td align="center">%s</td>
<td align="center">String</td>
<td align="center">- 문자가 여러 개인 문자열에 대한 형식</td>
</tr>
<tr>
<td align="center">정수<br>(Integer)</td>
<td align="center">%u<br>%d<br>%o<br>%x, %X</td>
<td align="center">Unsigned Decimal<br>Decimal <br>Octal<br>Hexa Decimal</td>
<td align="center">- 부호 없는 10진수 정수 <br>- 10진수 정수 <br>-8진수 정수 <br>-16진수 정수(%x일땐 영어가 소문자로, %X일땐  대문자로 표시)</td>
</tr>
<tr>
<td align="center">부동 소수점 <br>(Floating Point)</td>
<td align="center">%e, %E <br>%f <br>%lf</td>
<td align="center">Exponent <br>Floating Point <br>Long Floating Point</td>
<td align="center">- 지수 표기(%e는 지수표현을 e로, %E는 E로 표시) <br>- 부동 소수점 표기 <br>- 부동 소수점 표기</td>
</tr>
</tbody></table>
<p>④ 포맷 스트링을 이용한 변수 상세 출력</p>
<ul>
<li>포맷 스트링을 이용해 정렬, 0 채우기, 출력할 공간 확보, 소수점 자릿수 표기를 지정 가능<pre><code>%[-][0][전체자리수].[소수점자리수]스트링</code></pre></li>
</ul>
<table>
<thead>
<tr>
<th align="center">포맷 스트링</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">[$-$]</td>
<td align="center">- [$-$]를 붙이면 왼쪽 정렬 <br>- [$-$]를 붙이지 않고, $[전체자리수]$가 정해져 있을 경우 오른쪽 정렬</td>
</tr>
<tr>
<td align="center">[0]</td>
<td align="center">- 0을 붙이면 전체 자릿수에서 앞에 빈공간 만큼 0으로 채움</td>
</tr>
<tr>
<td align="center">[전체자리수]</td>
<td align="center">- [전체자리수]만큼 공간이 확보됨 <br>- 소수점(.)도 한 자릿수로 포함됨</td>
</tr>
<tr>
<td align="center">.[소수점자리수]</td>
<td align="center">- [소수점자리수]만큼 소수점이 출력됨 <br>- 실수형일 때만 적용됨</td>
</tr>
</tbody></table>
<h3 id="2-표준-입력-함수scanf">2) 표준 입력 함수(scanf)</h3>
<ul>
<li>키보드로 입력받은 문자열에서 지정된 포맷 스트링으로 데이터를 읽는 함수</li>
<li>scanf의 포맷 스트링은 printf의 포맷 스트링과 동일<pre><code>scanf(포맷_스트링이_포함된_문자열, 변수의_주솟값, ···);</code></pre><blockquote>
<p>scanf를 사용하기 위해서는 <code>stdio.h</code> 헤더를 선언해야함</p>
</blockquote>
</li>
</ul>
<h2 id="span-stylebackground-colorfff5b106-연산자-⭐⭐⭐span"><span style="background-color:#fff5b1">06. 연산자 ⭐⭐⭐</span></h2>
<h3 id="1-연산자operator">1) 연산자(Operator)</h3>
<ul>
<li>프로그램 실행을 위해 연산을 표현하는 기호</li>
</ul>
<h3 id="2-연산자-종류">2) 연산자 종류</h3>
<ul>
<li>증감 연산자(++,$--$) : 피연산자를 1씩 증가 혹은 1식 감소시킬 때 사용</li>
<li>산술 연산자(+, $-$, *, /, %) : 산술식을 구성</li>
<li>시프트 연산자(&lt;&lt;, &gt;&gt;) : 비트를 이동</li>
<li>관계 연산자(&gt;, &lt;, &gt;=, &lt;=, ==, !=) : 두 피연산자 사이의 크기를 비교</li>
<li>비트 연산자(&amp;, |, ^, ~) : 비트 단위로 논리 연산할 때 사용</li>
<li>논리 연산자(&amp;&amp;, ||, !) : 두 피연산자 사이의 논리적인 관계 정의</li>
<li>삼항 연산자((조건식)? (참):(거짓)) : 조건이 참일 경우 (참) 값을, 거짓일 경우 (거짓) 값을 반환</li>
<li>대입 연산자(=, +=, -=, *=, /=, %=) : 변수(왼쪽)에 값(오른쪽)을 대입할 때 사용</li>
</ul>
<h3 id="3-연산자-우선순위">3) 연산자 우선순위</h3>
<ul>
<li>증산시 관비논삼대</li>
</ul>
<table>
<thead>
<tr>
<th align="center">우선순위</th>
<th align="center">연산자</th>
<th align="center">유형</th>
</tr>
</thead>
<tbody><tr>
<td align="center">1</td>
<td align="center">x++, x--</td>
<td align="center">증감</td>
</tr>
<tr>
<td align="center">2</td>
<td align="center">++x, --x <br>! <br>~</td>
<td align="center">증감 <br>*논리 <br>*비트</td>
</tr>
<tr>
<td align="center">3</td>
<td align="center">*, /, %</td>
<td align="center">산술</td>
</tr>
<tr>
<td align="center">4</td>
<td align="center">+, -</td>
<td align="center">산술</td>
</tr>
<tr>
<td align="center">5</td>
<td align="center">&lt;&lt;, &gt;&gt;</td>
<td align="center">시프트</td>
</tr>
<tr>
<td align="center">6</td>
<td align="center">&lt;, &lt;=, &gt;, &gt;=</td>
<td align="center">관계</td>
</tr>
<tr>
<td align="center">7</td>
<td align="center">==, !=</td>
<td align="center">관계</td>
</tr>
<tr>
<td align="center">8, 9, 10</td>
<td align="center">&amp;, ^, |</td>
<td align="center">비트</td>
</tr>
<tr>
<td align="center">11, 12</td>
<td align="center">&amp;&amp;, ||</td>
<td align="center">논리</td>
</tr>
<tr>
<td align="center">13</td>
<td align="center">(조건식)? a:b</td>
<td align="center">삼항</td>
</tr>
<tr>
<td align="center">14</td>
<td align="center">=, +=, -=, *=, /=, %=</td>
<td align="center">대입</td>
</tr>
</tbody></table>
<h3 id="4-연산자-상세">4) 연산자 상세</h3>
<p>① 증감 연산자(Increment &amp; Decrement Operator)</p>
<table>
<thead>
<tr>
<th align="center">종류</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">$++$x</td>
<td>변수의 값을 1 증가시킨 후에 해당 변수를 사용</td>
</tr>
<tr>
<td align="center">x$++$</td>
<td>변수를 사용한 후에 변수의 값을 1 증가</td>
</tr>
<tr>
<td align="center">$--$x</td>
<td>변수의 값을 1 감소시킨 후에 해당 변수를 사용</td>
</tr>
<tr>
<td align="center">x$--$</td>
<td>변수를 사용한 후에 변수의 값을 1 감소</td>
</tr>
</tbody></table>
<p>② 산술 연산자</p>
<table>
<thead>
<tr>
<th align="center">종류</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">$+$</td>
<td>양쪽의 값을 더하는 연산자</td>
</tr>
<tr>
<td align="center">$-$</td>
<td>왼쪽 값에서 오른쪽 값을 빼는 연산자</td>
</tr>
<tr>
<td align="center">*</td>
<td>두 개의 값을 곱</td>
</tr>
<tr>
<td align="center">/</td>
<td>왼쪽 값을 오른쪽 값으로 나눔</td>
</tr>
<tr>
<td align="center">%</td>
<td>왼쪽 값을 오른쪽 값으로 나눈 나머지를 계산(정수만 가능)</td>
</tr>
</tbody></table>
<p>③ 시프트 연산자(Shift Operator) ⭐</p>
<ul>
<li>&lt;&lt;로 1비트 이동시킬 때마다 2배씩 증가하게 되고, &gt;&gt;로 1비트 이동시킬 때마다 2배씩 감소</li>
</ul>
<table>
<thead>
<tr>
<th align="center">종류</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">&lt;&lt;</td>
<td>양쪽의 값을 더하는 연산자</td>
</tr>
<tr>
<td align="center">&gt;&gt;</td>
<td>왼쪽 값에서 오른쪽 값을 빼는 연산자</td>
</tr>
</tbody></table>
<p>④ 관계 연산자(Relation Operator)</p>
<ul>
<li>참이면 1을, 거짓이면 0을 반환</li>
</ul>
<p>⑤ 비트 연산자(Bit Operator)</p>
<table>
<thead>
<tr>
<th align="center">종류</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">&amp;</td>
<td>두 값을 비트로  연산하여 같은 비트의 값이 <strong>모두 1</strong>이면 <strong>해당 비트 값이 1</strong>이 되고, <strong>그렇지 않으면 0</strong>이 되는 연산자(AND 연산자)</td>
</tr>
<tr>
<td align="center">|</td>
<td>두 값을 비트로 연산하여 같은 비트의 값이 <strong>하나라도 1</strong>이면 <strong>해당 비트 값이 1</strong>이 되고, <strong>그렇지 않으면 0</strong>이 되는 연산자(OR 연산자)</td>
</tr>
<tr>
<td align="center">^</td>
<td>두 값을 비트로 연산하여 같은 비트의 값이 <strong>서로 다르면 해당 비트 값이 1</strong>이 되고, <strong>그렇지 않으면 0</strong>이 되는 연산자(XOR 연산자)</td>
</tr>
<tr>
<td align="center">~</td>
<td>모든 비트의 값을 <strong>반대로</strong> 바꾸는 반전 기능을 하는 연산자(NOT 연산자) <br> ⭐ 부호를 반대로 바꾼 값에 1을 뺀 값</td>
</tr>
<tr>
<td align="center">- AND 연산자는 피연산자가 모두 True인 경우에만 결과가 True, 그외에는 모두 False인 연산자</td>
<td></td>
</tr>
<tr>
<td align="center">- OR 연산자는 피연산자가 모두 True인 경우에만 결과가 True, 그외에는 모두 False인 연산자</td>
<td></td>
</tr>
</tbody></table>
<p>⑥ 논리 연산자(Logig Operator)</p>
<ul>
<li>참이면 1, 거짓이면 0 반환</li>
</ul>
<p>⑦ 삼항 연산자(Ternary Operator)</p>
<pre><code>조건식 ? 참일때값 : 거짓일때값;</code></pre><p>⑧ 대입 연산자(Assignment Operator)</p>
<ul>
<li>변수(왼쪽)에 값(오른쪽)을 대입할 때 사용</li>
</ul>
<h2 id="07-조건문">07. 조건문</h2>
<ul>
<li>조건의 참, 거짓 여부에 따라 실행 경로를 달리하는 if 문과 여러 경로 중에 하나를 선택하는 switch 문으로 구분</li>
</ul>
<h3 id="1-if-문">1) if 문</h3>
<pre><code class="language-c">if(조건문){
  명령문;
}</code></pre>
<h3 id="2-switch-문">2) switch 문</h3>
<pre><code class="language-c">switch (식){
  case 값:
    명령문;
    break;
  default:
    명령문;</code></pre>
<ul>
<li>식을 계산해서 일치하는 값을 가진 case 문을 실행</li>
<li>식이 어떠한 값도 만족하지 않으면 default로 진입</li>
<li>⭐ <strong>break가 존재하지 않을 경우</strong> break를 만날 때까지 switch 문에 있는 다른 문장 실행</li>
</ul>
<h2 id="08-반복문">08. 반복문</h2>
<ul>
<li>특정 부분을 조건이 만족할 때가지 실행하도록 하는 명령문</li>
<li>반복문을 사용할 때 특별한 조건이 없으면 무한 처리를 반복(무한 루프)함</li>
</ul>
<h3 id="1-while-문">1) while 문</h3>
<pre><code class="language-c">while(조건문){
  명령문;
}</code></pre>
<h3 id="2-do-while-문">2) do while 문</h3>
<pre><code class="language-c">do{
  명령문;
}while(조건문);</code></pre>
<ul>
<li>참, 거짓과 관련 없이 무조건 한 번은 실행하고, 그 다음부터는 조건이 참인 동안에 해당 분기를 반복해서 실행하는 명령문</li>
</ul>
<h3 id="3-for-문">3) for 문</h3>
<pre><code class="language-c">for (초기식; 조건식; 증감식){
  명령문;
}

명령문;</code></pre>
<ul>
<li>초기식, 조건식, 증감식을 지정하여 반복</li>
</ul>
<h3 id="4-루프-제어-명령문">4) 루프 제어 명령문</h3>
<p>① break 문</p>
<ul>
<li>반복문이나 switch 문을 중간에 탈출하기 위해 사용하는 명령어</li>
</ul>
<p>② continue 문</p>
<ul>
<li>반복문에서 다음 반복으로 넘어갈 수 있도록 하는 명령어</li>
</ul>
<h2 id="span-stylebackground-colorfff5b109-배열-⭐⭐⭐span"><span style="background-color:#fff5b1">09. 배열 ⭐⭐⭐</span></h2>
<h3 id="1-배열array">1) 배열(Array)</h3>
<ul>
<li>같은 자료형의 변수들로 이루어진 집합</li>
</ul>
<h3 id="2-배열-종류">2) 배열 종류</h3>
<p>① 1차원 배열</p>
<ul>
<li>초기값이 없는 경우 : 자료형 배열명[배열_요소_개수];</li>
<li>초기값이 있는 경우 : 자료형 배열명[배열_요소_개수] = {초깃값};</li>
</ul>
<pre><code class="language-c">int a[3] = {1, 2};
int 데이터가 들어갈 공간 = 배열값;</code></pre>
<ul>
<li>배열 요소 개수에 정의된 숫자만큼 같은 자료형의 데이터 공간 할당</li>
<li>초깃값을 선언하지 않으면 쓰레깃값이 저장</li>
<li>배열 요소 개수보다 <strong>적은 개수만큼 초기화</strong>하면 정수형일 경우 0으로, 실수형일 경우 0.0으로, 문자형일 경우 NULL로 초기화<ul>
<li>NULL의 아스키코드는 0</li>
</ul>
</li>
</ul>
<p>② 2차원 배열</p>
<ul>
<li>초기값이 없는 경우 : 자료형 배열명[행의_개수][열의_개수];</li>
<li>초기값이 있는 경우 : 자료형 배열명[행의_개수][열의_개수] = {초깃값};</li>
</ul>
<pre><code class="language-c">int a[2][3] = {1, 2, 3, 4};</code></pre>
<ul>
<li>(행의 개수)$\times$(열의 개수)에 정의된 숫자만큼 같은 자료형의 데이터 공간 할당</li>
<li>초깃값을 선언하지 않으면 쓰레깃값 저장</li>
</ul>
<h2 id="span-stylebackground-colorfff5b110-문자열-⭐⭐⭐span"><span style="background-color:#fff5b1">10. 문자열 ⭐⭐⭐</span></h2>
<h3 id="1-1차원-배열과-문자열">1) 1차원 배열과 문자열</h3>
<ul>
<li>C언어에서는 문자열은 char 형 배열로 표현</li>
<li>문자열을 초기화할 때 <strong>마지막 NULL 문자가 삽입</strong>되므로 초기화하는 글자 수보다 1 이상 큰 값으로 배열을 선언(초기화할 때 배열의 크기를 명시하지 않으면 문자열의 문자 수+1만큼 자동 생성)</li>
<li>printf 함수에서 %s를 이용하여 문자열을 읽고 출력하는데, printf 파라미터로 문자를 읽기 시작할 시작 주소를 알려주면 시작 주소부터** NULL 직전 값까지 읽어서 출력**</li>
</ul>
<pre><code class="language-c">#include &lt;stdio.h&gt;
void main(){
  char a[8] = &quot;Hello&quot;; 
  printf(&quot;%s\n&quot;, a); // Hello
  printf(&quot;%s\n&quot;, a+1); // ello
  a[3] = NULL;
  printf(&quot;%s\n&quot;, a+1); // el
  printf(&quot;%s\n&quot;, a+4); // o
}</code></pre>
<p><code>char a[8] = &quot;Hello&quot;;</code></p>
<table>
<thead>
<tr>
<th align="center">a[0]</th>
<th align="center">a[1]</th>
<th align="center">a[2]</th>
<th align="center">a[3]</th>
<th align="center">a[4]</th>
<th align="center">a[5]</th>
<th align="center">a[6]</th>
<th align="center">a[7]</th>
</tr>
</thead>
<tbody><tr>
<td align="center">H</td>
<td align="center">e</td>
<td align="center">l</td>
<td align="center">l</td>
<td align="center">o</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
</tr>
</tbody></table>
<p><code>a[3] = NULL;</code></p>
<table>
<thead>
<tr>
<th align="center">a[0]</th>
<th align="center">a[1]</th>
<th align="center">a[2]</th>
<th align="center">a[3]</th>
<th align="center">a[4]</th>
<th align="center">a[5]</th>
<th align="center">a[6]</th>
<th align="center">a[7]</th>
</tr>
</thead>
<tbody><tr>
<td align="center">H</td>
<td align="center">e</td>
<td align="center">l</td>
<td align="center">NULL</td>
<td align="center">o</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
</tr>
<tr>
<td align="center">→ ⭐ printf는 NULL 직전 값까지 읽어서 출력</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td align="center">→ ⭐ <code>printf(&quot;%s\n&quot;, a);</code> 에서 <code>a</code> 대신에 <code>&amp;a[0]</code>으로, <code>printf(&quot;%s\n&quot;, a+1);</code> 에서 <code>a+1</code> 대신에 <code>&amp;a[1]</code>로 <code>printf(&quot;%s\n&quot;, a+4);</code> 에서 <code>a+4</code> 대신에 <code>&amp;a[4]</code>로 바꿔도 결과는 같음</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
</tbody></table>
<h3 id="2-2차원-배열과-문자열">2) 2차원 배열과 문자열</h3>
<ul>
<li>여러 개 정의할 때 char 형 2차원 배열을 사용<pre><code class="language-c">#include &lt;stdio.h&gt;
void main(){
char a[2][8] = {&quot;Hello&quot;, &quot;Stranger&quot;};
printf(&quot;%s\n&quot;, a[0]) // Hello
printf(&quot;%s\n&quot;, a[1]) // Stranger
printf(&quot;%s\n&quot;, a[1]+3) // anger
a[1][4] = NULL; 
printf(&quot;%s\n&quot;, a[1]+2) // ra</code></pre>
</li>
</ul>
<p><code>char a[2][8] = {&quot;Hello&quot;, &quot;Stranger&quot;};</code></p>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">a[0]</th>
<th align="center">a[1]</th>
<th align="center">a[2]</th>
<th align="center">a[3]</th>
<th align="center">a[4]</th>
<th align="center">a[5]</th>
<th align="center">a[6]</th>
<th align="center">a[7]</th>
</tr>
</thead>
<tbody><tr>
<td align="center">a[0]</td>
<td align="center">H</td>
<td align="center">e</td>
<td align="center">l</td>
<td align="center">l</td>
<td align="center">o</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
</tr>
<tr>
<td align="center">a[1]</td>
<td align="center">S</td>
<td align="center">t</td>
<td align="center">r</td>
<td align="center">a</td>
<td align="center">n</td>
<td align="center">g</td>
<td align="center">e</td>
<td align="center">r</td>
</tr>
</tbody></table>
<p><code>a[1][4] = NULL;</code></p>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">a[0]</th>
<th align="center">a[1]</th>
<th align="center">a[2]</th>
<th align="center">a[3]</th>
<th align="center">a[4]</th>
<th align="center">a[5]</th>
<th align="center">a[6]</th>
<th align="center">a[7]</th>
</tr>
</thead>
<tbody><tr>
<td align="center">a[0]</td>
<td align="center">H</td>
<td align="center">e</td>
<td align="center">l</td>
<td align="center">l</td>
<td align="center">o</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
<td align="center">NULL</td>
</tr>
<tr>
<td align="center">a[1]</td>
<td align="center">S</td>
<td align="center">t</td>
<td align="center">r</td>
<td align="center">a</td>
<td align="center">NULL</td>
<td align="center">g</td>
<td align="center">e</td>
<td align="center">r</td>
</tr>
<tr>
<td align="center">→ ⭐ <code>printf(&quot;%s\n&quot;, a[0]);</code> 에서 <code>a[0]</code> 대신에 <code>&amp;a[0][0]</code>으로, <code>printf(&quot;%s\n&quot;, a[1]);</code> 에서 <code>a[1]</code> 대신에 <code>&amp;a[1][0]</code>로 <code>printf(&quot;%s\n&quot;, a[1]+2);</code> 에서 <code>a[1]+2</code> 대신에 <code>&amp;a[1][2]</code>로 바꿔도 결과는 같음</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
</tbody></table>
<h2 id="11-구조체-⭐⭐">11. 구조체 ⭐⭐</h2>
<h3 id="1-구조체">1) 구조체</h3>
<ul>
<li>사용자가 기본 자료형을 가지고 새롭게 정의할 수 있는 사용자 정의 자료형</li>
</ul>
<h3 id="2-구조체-선언">2) 구조체 선언</h3>
<pre><code class="language-c">struct 구조체명{
  자료형 변수명1;
  자료형 변수명2;
  ···
};</code></pre>
<ul>
<li>구초체는 <code>구조체변수.변수명</code> 형태로 값을 가리킴<pre><code class="language-c">#include &lt;stdio.h&gt;
struct Student {
char gender;
int age;
};
</code></pre>
</li>
</ul>
<p>void main(){
  struct Student s = {&#39;F&#39;, 21};
  s.gender = &#39;M&#39;;
  printf(&quot;%c&quot;, s.gender); // M
  printf(&quot;%d&quot;, s.age); // 21</p>
<pre><code>
## &lt;span style=&quot;background-color:#fff5b1&quot;&gt;12. 함수 ⭐⭐⭐&lt;/span&gt;
### 1) main 함수
① main 함수
- main 함수는 프로그램이 실행하는 모든 프로그램의 시작점
- main 함수에 있는 명령어를 실행

② main 함수 형태
```c
자료형 main(파라미터){
  명령어;
}</code></pre><ul>
<li>*<em><code>void main()</code> *</em>일 경우 반환할 값이 없으므로 <code>return;</code> 을 사용하거나 return 자체를 사용하지 않고, *<em><code>int main()</code> *</em>일 경우 <code>return 반환값;</code> 을 명시해주어야 함</li>
<li>main 함수나 사용자 정의 함수는 <code>return</code> 을 만나면 그 즉시 함수를 종료<pre><code class="language-c">void main(){
return;
}</code></pre>
<pre><code class="language-c">int main(){
return 반환값;
}</code></pre>
</li>
</ul>
<blockquote>
<p><strong>void</strong></p>
</blockquote>
<ul>
<li>함수를 호출한 호출자에게 결괏값을 제공하지 않는다는 의미의 자료형</li>
<li>void는 &#39;존재하지 않음&#39;이라는 뜻으로 반환 값이 없다는 의미로 사용</li>
</ul>
<h3 id="2-사용자-정의-함수">2) 사용자 정의 함수</h3>
<p>① 사용자 정의 함수(User-Defined Function)</p>
<ul>
<li>사용자가 직접 새로운 함수를 정의하여 사용하는 방법</li>
<li><strong>매개변수</strong>나 생성된 변수는 사용자 정의 함수가 종료되면 없어짐</li>
</ul>
<p>② 사용자 정의 함수 선언</p>
<pre><code class="language-c">자료형 함수명(자료형 변수명, ···){
  명령어;
  return 반환값;
}</code></pre>
<p>③ 매개변수 전달 방법</p>
<ul>
<li>매개변수 전달 방법은 함수가 필요로 하는 값을 매개변수로 만들면 함수를 호출하는 쪽에서 매개변수를 사용하여 해당 함수에게 변수의 값, 변수의 주솟값을 전달하는 방식</li>
<li>매개변수 전달 방법 구성 요소</li>
</ul>
<table>
<thead>
<tr>
<th align="center">구성요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">전달인자 <br>(Argument)</td>
<td>- 실 매개변수(Actual Parameters)로도 불림<br>- 함수를 호출하는 쪽에서 전달하는 변수의 값 또는 변수의 주솟값</td>
</tr>
<tr>
<td align="center">매개변수 <br>(Parameter)</td>
<td>- 형식 매개변수(Formal Parameters)로도 불림 <br>- 함수를 호출하는 쪽에서 전달하는 변수의 값 또는 변수의 주솟값</td>
</tr>
</tbody></table>
<pre><code class="language-c">#include &lt;stdio.h&gt;

int fn(int x, int y){ // → 매개변수 
  ···
}

void main(){
  int i, j;
  ···
  fn(i, j); // → 전달인자
}</code></pre>
<ul>
<li>⭐ 매개변수 전달 방법 종류</li>
</ul>
<table>
<thead>
<tr>
<th align="center">구성요소</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td align="center">Call by Value</td>
<td>- 변수의 값을 넘겨주고, 이 값은 새로운 공간에 할당되어 사용하는 방식<br>- 형식 매개변수의 어떠한 변화도 실 매개변수에 아무런 영향을 미치지 않음</td>
<td><code>#include &lt;stdio.h&gt;</code><br><code>int fn(int x, int y){</code><br><code>···</code><br><code>}</code> <br><code>void main(){</code><br><code>int i, j;</code><br><code>···</code><br><code>fn(i, j);</code><br><code>}</code></td>
</tr>
<tr>
<td align="center">Call by Reference</td>
<td>- 변수의 값이 아닌 변수가 사용 중인 메모리 공간의 주소를 넘겨주는 방식 <br>- 실 매개변수의 주소를 형식 매개변수로 보냄</td>
<td><code>#include &lt;stdio.h&gt;</code><br><code>int fn(int* x, int* y){</code><br><code>···</code><br><code>}</code> <br><code>void main(){</code><br><code>int i, j;</code><br><code>···</code><br><code>fn(&amp;i, &amp;j);</code><br><code>}</code></td>
</tr>
</tbody></table>
<p>④ 재귀 함수</p>
<ul>
<li>재귀 함수는 함수 자신이 자신을 부르는 함수</li>
<li>재귀 함수 선언<pre><code class="language-c">자료형 함수명(자료형 변수명, ···){
···
함수명(변수명, ···)
···
return 반환값;</code></pre>
</li>
</ul>
<h3 id="3-표준-함수">3) 표준 함수</h3>
<p>① 문자열 함수 #include&lt;string.h&gt;</p>
<p>*<em>1. strcat(String Concatenate) *</em></p>
<ul>
<li>문자열끼리 연결하는 함수<ul>
<li><code>strcat(dest, src);</code> : <code>src</code> 의 문자열을 <code>dest</code> 문자열 뒤에 붙임</li>
<li><code>strncat(dest, src, maxlen);</code> : <code>src</code> 의 문자열에서 <code>maxlent</code>의 개수만큼 <code>dest</code> 문자열 뒤에 붙임</li>
</ul>
</li>
</ul>
<p><strong>2. strcpy(String Copy)</strong></p>
<ul>
<li>문자열을 복사하는 함수<ul>
<li><code>strcpy(dest, src);</code> : <code>src</code>의 문자열을 <code>dest</code> 문자열에 복사</li>
<li><code>strncpy(dest, src, maxlen);</code> : <code>src</code>의 무자열에서 <code>maxlent</code>의 개수만큼 <code>dest</code> 문자열에 복사 </li>
</ul>
</li>
</ul>
<p><strong>3. strcmp(String Compare)</strong></p>
<ul>
<li>문자열을 비교하는 함수<ul>
<li><code>strcmp(s1, s2);</code> : <code>s1</code>, <code>s2</code>의 대소를 비교</li>
<li><code>strncmp(s1, s2, maxlent);</code> : <code>maxlen</code> 길이만큼만 <code>s1</code>, <code>s2</code>의 대소를 비교</li>
</ul>
</li>
<li>문자열에 대해서 ASCII 코드를 비교하여 <code>s1</code>이 <code>s2</code>보다 크면 1을, <code>s1</code>과 <code>s2</code>가 같으면 0을, <code>s1</code>이 <code>s2</code>보다 작으면 -1을 반환</li>
</ul>
<p><strong>4. strlen(String Length)</strong></p>
<ul>
<li>문자열의 길이를 알려주는 함수<ul>
<li><code>strlen(s);</code> : s의 길이를 알려줌</li>
</ul>
</li>
</ul>
<p><strong>5. strrev(String Reverse)</strong></p>
<ul>
<li>문자열을 거꾸로 뒤집는 함수<ul>
<li><code>strrev(str);</code> : str 내에 문자열을 거꾸로 뒤집음</li>
</ul>
</li>
</ul>
<p><strong>6. strchr</strong></p>
<ul>
<li>문자열 내에 일치하는 문자가 있는지 검사하는 함수<ul>
<li><code>strchr(str, c);</code> : str 내에 c가 존재하면 첫번째 c의 위치를 반환</li>
</ul>
</li>
</ul>
<p>② 수학 함수 #include&lt;math.h&gt;</p>
<p><strong>1. sqrt</strong></p>
<ul>
<li>양의 제곱근을 계산하는 함수<ul>
<li><code>sqrt(n)</code>; : $\sqrt n$ 의 값을 계산</li>
</ul>
</li>
</ul>
<blockquote>
<p>양의 제곱근은 소수를 확인할 때도 사용한다. a라는 값의 소수를 확인할 때는 2 ~ (a-1)의 모든 정수들로 나눴을 때 나누어 떨어지지 않는지 확인하는 것이 정석이지만, sqrt를 이용하면 2 ~  $\sqrt a$의 정수들만 나누어 떨어지지 않는지 확인하면 소수를 구할 수 있기 때문이다. </p>
</blockquote>
<p><strong>⭐ 2. ceil</strong></p>
<ul>
<li>소수점 올림 함수<ul>
<li><code>ceil(n);</code> : 소수점 올림</li>
</ul>
</li>
</ul>
<p><strong>⭐ 3. floor</strong></p>
<ul>
<li>소수점 내림 함수<ul>
<li><code>floor(n);</code> : 소수점 내림</li>
</ul>
</li>
</ul>
<p>③ 유틸리티 함수</p>
<p><strong>1. rand(Random)</strong> #include&lt;stdlib.h&gt;</p>
<ul>
<li>임의의 값을 생성하는 함수<ul>
<li><code>rand();</code> : 임의의 정숫값 1개를 생성</li>
</ul>
</li>
</ul>
<p><strong>2. srand(Seed Random)</strong> #include&lt;stdlib.h&gt;</p>
<ul>
<li>난수 생성 알고리즘에 사용하는 seed를 정해주는 함수</li>
<li><code>srand</code>를 사용하면 <code>rand</code> 함수를 사용할 때 해당 seed 값에 해당하는 난수 패턴으로 생성<ul>
<li><code>srand(seed);</code> : seed 값에 따라 난수 발생기를 초기화</li>
</ul>
</li>
</ul>
<p><strong>3. time</strong> #include&lt;time.h&gt;</p>
<ul>
<li>현재 시간을 가져오는 함수</li>
<li>1970년 1월 1일 이후로 몇 초가 경과했는지를 나타냄
<code>time(NULL);</code> : time 함수에 파라미터를 NULL로 하면 현재 시간을 리턴<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;time.h&gt;
void main() {
int a;
int i;
srand(time(NULL));
for(i=0; i&lt;6; i++){
  a = rand()%45+1;
  printf(&quot;%d &quot;, a); // 29 2 43 25 4
}
}</code></pre>
<blockquote>
<p><code>rand()</code> 함수는 임의로 난수만 생성하기 때문에 여러 번 실행하면 동일한 숫자가 나올 수 있음</p>
</blockquote>
</li>
</ul>
<p><strong>4. atoi(ASCII to Integer)</strong> #include&lt;stdlib.h&gt;</p>
<ul>
<li>문자열을 정수형으로 변환하는 함수<ul>
<li><code>atoi(str)</code> : 문자열(str)을 정수(int)형으로 변환<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
void main() {
char *a = &quot;1&quot;;
int num = atoi(a);
printf(&quot;%d &quot;, num); // 1
}</code></pre>
<blockquote>
<p>문자열을 저장하기 위해서 일반적으로 배열을 사용하지만, <strong>문자형 포인터</strong>를 생성하면서 문자열을 대입할 수 있음</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<p><strong>5. atof(ASCII to Floating Point)</strong> #include&lt;stdlib.h&gt;</p>
<ul>
<li>문자열을 실수형으로 변환하는 함수<ul>
<li><code>atof(str)</code> : 문자열(str)을 실수형(float, double)형으로 변환</li>
</ul>
</li>
</ul>
<p><strong>⭐ 6. itoa(integer to ASCII)</strong></p>
<ul>
<li>정수형을 문자열로 변환하는 함수<ul>
<li><code>itoa(value, str, radix)</code> : value를 변환하여 str에 radix 진수로 저장</li>
</ul>
</li>
</ul>
<h2 id="span-stylebackground-colorfff5b113-포인터-⭐⭐⭐span"><span style="background-color:#fff5b1">13. 포인터 ⭐⭐⭐</span></h2>
<h3 id="1-포인터">1) 포인터</h3>
<ul>
<li>변수의 주솟값을 저장하는 공간</li>
</ul>
<h3 id="2-포인터-선언">2) 포인터 선언</h3>
<pre><code>자료형* 포인터_변수명 = &amp;변수명;</code></pre><ul>
<li>자료형 뒤에 *를 붙이면 주소를 저장하는 포인터 변수, 일반 변수명에 &amp;를 붙이면 해당 변수명의 주솟값</li>
<li>주소에 해당하는 값을 가리키는 * 연산과 변수에 주솟값을 나타내는 &amp; 연산은 반대 기능 → *(&amp;) 는 상쇄</li>
</ul>
<pre><code class="language-c">#include &lt;stdio.h&gt;
void main() {
  int a = 10;
  int* b = &amp;a;
  printf(&quot;%d %d %d&quot;, a, *b, *(&amp;a))); // 10 10 10
}</code></pre>
<h3 id="⭐-3-배열과-포인터">⭐ 3) 배열과 포인터</h3>
<ul>
<li><code>자료형 배열명[요소];</code> 일 때 다음 코드는 동일<ul>
<li>배열의 i번지 주소 : 배열+i == &amp;배열[i];</li>
<li>배열의 i번지 값 : *(배열+i) == 배열[i];</li>
</ul>
</li>
</ul>
<p>① 1차원 배열과 1차원 포인터</p>
<ul>
<li>1차원 배열에서 배열명만 단독으로 사용할 경우 1차원 포인터와 동일</li>
<li>1차원 배열일 때는 배열명[요소] 형태, *(배열명+요소)일 경우 값을 가리키고, 1차원 포인터일 때는 포인터[요소] 형태, *(포인터+요소)일 경우 값을 가리킴<pre><code class="language-c">#include &lt;stdio.h&gt;
void main() {
int a[3] = {1, 2};
int *p = a;  
printf(&quot;%d %d %d\n&quot;, a[0], *b, *(&amp;a))); // 10 10 10
}</code></pre>
</li>
</ul>
<p>② 2차원 배열과 1차원 포인터</p>
<ul>
<li>2차원 배열에서 배열명만 단독으로 사용할 경우 2차원 포인터와 동일</li>
<li>2차원 배열일 때는 배열명[요소] 형태, *(배열명+요소)는 1차원 포인터와 동일하고, 1차원 포인터에 대해 *과 []을 이용해야 값을 가리킬 수 있음<pre><code class="language-c">#include &lt;stdio.h&gt;
void main() {
int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};
int *p = a[1];  
printf(&quot;%d %d %d\n&quot;, *a[0], *a[1], *a[2]); // 1 3 5
printf(&quot;%d %d %d\n&quot;, **a, **(a+1), **(a+2)); // 1 3 5
printf(&quot;%d %d\n&quot;, *p, *(p+1)); // 3 4
printf(&quot;%d %d\n&quot;, p[0], p[1]); // 3 4
}</code></pre>
</li>
</ul>
<p>③ 2차원 배열과 포인터 배열</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
void main() {
  int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};
  int *p[3] = {a[2], a[0], a[1]};  
  printf(&quot;%d %d %d\n&quot;, a[0][0], a[1][0], a[2][0]); // 1 3 5
  printf(&quot;%d %d %d\n&quot;, *a[0], *a[1], *a[2]); // 1 3 5
  printf(&quot;%d %d %d\n&quot;, p[0][0], p[1][0], p[2][0]); // 1 3 5
  printf(&quot;%d %d %d\n&quot;, *p[1], *p[2], *p[0]); // 1 3 5
}</code></pre>
<p>④ 2차원 배열과 2차원 포인터</p>
<ul>
<li>2차원 배열에서 배열명만 단독으로 사용할 경우 2차원 포인터와 동일</li>
<li>2차원 배열일 때 배열명[요소][요소], *배열명[요소], **(배열명+요소)일 경우 값을 가리킴</li>
<li>⭐ 2차원 포인터는 <code>int **p, **q;</code> 형태로 선언할 수 있으나 2차원 포인터 p, q는 2차원 배열에서 한 덩어리의 크기를 알 수 없기 때문에 열의 개수를 명시하는 형태로 포인터 변수를 선언</li>
<li>⭐ 포인터 변수 선언할 때 괄호가 없으면 2차원 배열에 대한 포인터가 아닌 포인터 배열이 됨<ul>
<li><code>자료형 (*포인터 변수)[열의 크기];</code><pre><code class="language-c">#include &lt;stdio.h&gt;
void main() {
int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};
int (*p)[2] = a;
int (*q)[2] = a+1;
printf(&quot;%d %d %d\n&quot;, a[0][0], a[0][1], a[1][0]); // 1 2 3
printf(&quot;%d %d %d\n&quot;, p[0][0], p[0][1], p[1][0]); // 1 2 3
printf(&quot;%d %d %d\n&quot;, q[0][0], q[0][1], q[1][0]); // 3 4 5
}</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="⭐-4-구조체와-포인터">⭐ 4) 구조체와 포인터</h3>
<p>① 구조체 변수와 구조체 포인터</p>
<ul>
<li>구조체는 <strong>일반 구조체 변수</strong>로 접근할 때는 <strong><code>.</code> *<em>으로 접근하고, *</em>구조체 포인터</strong>로 접근할 때는 <strong><code>-&gt;</code></strong> 로 접근</li>
</ul>
<pre><code class="language-c">#include &lt;stdio.h&gt;
Struct Student{
  char gender;
  int age;
}
void main() {
  struct Student s = {&#39;F&#39;, 21};
  struct Student *p = &amp;s;
  printf(&quot;%c %d\n&quot;, s.gender, s.age); // F 21
  printf(&quot;%c %d\n&quot;, (&amp;s)-&gt;gender, (&amp;s)-&gt;age); // F 21
  printf(&quot;%c %d\n&quot;, p-&gt;gender, p-&gt;age); // F 21
  printf(&quot;%c %d\n&quot;, (*p).gender, (*p).age); // F 21
  printf(&quot;%c %d\n&quot;, p[0].gender, p[0].age); // F 21
}</code></pre>
<p>② <span style="background-color:#fff5b1">1차원 구조체 배열과 1차원 구조체 포인터 ⭐ </span></p>
<ul>
<li>1차원 구조체 배열에서 배열명만 단독으로 사용할 경우 1차원 구조체 포인터와 동일</li>
<li>1차원 구조체 배열일 때 배열명[요소].변수명 형태, (*(배열명+요소)).변수명, 배열명-&gt;변수명 형태, (배열명+요소)-&gt;변수명 형태로 값을 가리킴</li>
<li>1차원 포인터일 때 포인터[요소].변수명 형태, (*(포인터+요소)).변수명, 포인터-&gt;변수명 형태, (포인터+요소)-&gt;변수명 형태로 값을 가리킴</li>
</ul>
<pre><code class="language-c">#include &lt;stdio.h&gt;
Struct Student{
  char gender;
  int age;
}
void main() {
  struct Student s[3] = {&#39;F&#39;, 21, &#39;M&#39;, 20, &#39;M&#39;, 24};
  struct Student *p = &amp;s;
  printf(&quot;%c %d\n&quot;, s[0].gender, s[0].age); // F 21
  printf(&quot;%c %d\n&quot;, (*s)-&gt;gender, (*s)-&gt;age); // F 21
  printf(&quot;%c %d\n&quot;, s-&gt;gender, s-&gt;age); // F 21
  printf(&quot;%c %d\n&quot;, (s+1)-&gt;gender, (s+1)-&gt;age); // M 20
  printf(&quot;%c %d\n&quot;, p[0].gender, p[0].age); // F 21
  printf(&quot;%c %d\n&quot;, (*p).gender, (*p).age); // F 21
  printf(&quot;%c %d\n&quot;, p-&gt;gender, p-&gt;age); // F 21
  printf(&quot;%c %d\n&quot;, (p+1)-&gt;gender, (p+1)-&gt;age); // M 20
}</code></pre>
<h3 id="⭐-5-함수-포인터">⭐ 5) 함수 포인터</h3>
<ul>
<li>함수의 주소를 저장하고, 해당 주소의 함수를 호출하는 데 사용하는 포인터<pre><code>리턴타입 (*함수_포인터)(함수 파라미터);</code></pre></li>
</ul>
<pre><code class="language-c">#include &lt;stdio.h&gt;
void fn1(){
  printf(&quot;fn1 함수\n&quot;);
}
int fn2(int a){
  printf(&quot;fn2 함수: %d\n&quot;, a);
  return 0;
}
void main(){
  void (*pf1)();
  int (*pf2)(int);
  fn1(); // fn1 함수
  fn2(5); //fn2 함수: 5
  pf1 = fn1; 
  pf2 = fn2;
  pf1(); // fn1 함수
  pf2(2); //fn2 함수: 2</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Unreal Engine] 언리얼엔진5에서 협업하기(+Github 추가 예정)]]></title>
            <link>https://velog.io/@cey_adda/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC%EC%97%94%EC%A7%845%EC%97%90%EC%84%9C-%ED%98%91%EC%97%85%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@cey_adda/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC%EC%97%94%EC%A7%845%EC%97%90%EC%84%9C-%ED%98%91%EC%97%85%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 02 Apr 2024 17:42:18 GMT</pubDate>
            <description><![CDATA[<p>언리얼 엔진의 <a href="https://dev.epicgames.com/documentation/ko-kr/unreal-engine/multi-user-editing-in-unreal-engine" target="_blank">Multi-User Editing</a> 관련 Unreal Engine Documentation을 참고하여 작성되었습니다. 여러 컴퓨터의 다중 사용자가 공유 언리얼 에디터 세션에 접속해서 라이브로 협업하며 같이 콘텐츠를 만드는 기능을 서술합니다.</p>
<p>언리얼 엔진에서는 협업을 위한 아주 강력한 도구를 제공합니다. 바로 &#39;Multi-User Editing&#39; 이라는 플러그인으로, 공유 편집 세션에서 무려 실시간 협업이 가능합니다. </p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/1c02e264-2297-41cf-a74f-3b4587a5f66d/image.png" alt=""></p>
<p>이 Multi-User Editing 워크플로우는 하나의 서버가 여러 세션을 <strong>호스팅</strong>하는 클라이언트-서버 모델을 기반으로 구축되어 있어, 협업을 하기 위해서는 먼저 몇가지 조건을 만족해야합니다. </p>
<ul>
<li>각 컴퓨터에 동일한 버전의 언리얼 엔진을 설치해야 합니다.</li>
<li>모든 컴퓨터가 동일한 LAN 또는 VPN 에 연결되어 있어야합니다. </li>
<li>모든 컴퓨터가 하나의 프로젝트(주로 Server)의 복사본을 가지고 있어야 합니다.</li>
</ul>
<h1 id="1-multi-user-editing-플러그인-활성화">1. Multi-User Editing 플러그인 활성화</h1>
<p>해당 기능을 사용하기 위해 [Edit] - [Plugins] 에서 &#39;Multi-User Editing&#39; 플러그인을 활성화시켜줍니다. </p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/f3bfa980-24c2-4ee5-bf08-8f7285af7b7f/image.png" alt=""></p>
<p>플러그인을 활성화하면, 각 컴퓨터 마다 고유 색상을 커스터마이징하여 서로 구별하기 쉬운 아이덴티티를 가질 수 있습니다. </p>
<ul>
<li>[Edit] - [Project Settings] - [Multi-User Editing] <ul>
<li>&#39;Enable Multi-User Toolbar Button&#39;을 활성화</li>
<li>&#39;Display Name&#39;과 &#39;Avatar Color&#39;를 변경</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/f6ccd158-c61f-4cd0-84c7-c85847c4b2fd/image.png" alt=""></p>
<h1 id="2-서버server">2. 서버(Server)</h1>
<h2 id="서버-시작">서버 시작</h2>
<p>먼저 공유 편집 세션을 구축하기 위해서 서버를 열어야합니다. [Window] - &#39;Mullti-User Browser&#39;를 선택하여 열린 블라우저 창에서 왼쪽 위에 있는 Launch 아이콘을 클릭하여 서버를 시작할 수 있습니다. </p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/71605bf8-8cea-4cd3-aab5-1a30a752660e/image.png" alt=""></p>
<p>혹은 이전 단계에서 &#39;Enable Multi-User Toolbar Button&#39;을 활성화했다면 툴바에 있는 Multi-User Editing 아이콘을 눌러 &#39;Mullti-User Browser&#39;를 표시할 수도 있습니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/e4e5552d-b8e7-4e82-9235-afa1de1e4f0a/image.png" alt=""></p>
<p>서버가 제대로 시작했다면 아래와 같이 서버 관리 창이 실행됩니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/4e516a61-3d8f-4aac-8bb1-d9f46a688a9f/image.png" alt=""></p>
<h2 id="세션-시작">세션 시작</h2>
<p>서버를 시작했다면, 이제 협업을 위한 방을 만들 차례입니다. 즉, 아직 해당 서버에 연결된 언리얼 에디터 인스턴스가 없다는 뜻이며, 인스턴스를 연결하기 위해서는 새로운 <strong>세션</strong>을 구축할 필요가 있습니다. </p>
<p>&#39;Mullti-User Browser&#39;에서 왼쪽 위에 Launch 오른쪽에 있는 Create 아이콘을 클릭하여 세션을 구성할 수 있습니다. 
<img src="https://velog.velcdn.com/images/cey_adda/post/97156c61-09ad-4aeb-9d8f-2684f470b2f5/image.png" alt=""></p>
<p>새롭게 생성할 세션의 이름을 입력하고 서버를 선택하여 세션을 생성합니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/06f6a1ce-51a3-4b02-ba2a-6a6af5666559/image.png" alt=""></p>
<p>별다른 행동없이도 자동으로 세션에 참가됩니다. 아래와 같이 세션에 참가되었다면 성공적으로 세션을 시작한 것입니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/436f1786-a953-4bfb-b06b-09ead2e6111a/image.png" alt=""></p>
<h1 id="3-클라이언트client">3. 클라이언트(Client)</h1>
<p>이제 생성된 세션에 <strong>다른</strong> 컴퓨터가 들어갈 준비가 되었습니다. 세션에 들어가려는 클라이언트도 서버와 마찬가지로 &#39;Mullti-User Browser&#39;를 열어 세션 목록을 확인하면, 서버에서 만든 세션이 보입니다.</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/21af68d8-5ce1-4228-9654-65dbb72629f8/image.png" alt=""></p>
<p>이 세션에 참가하면 모든 참가자가 수행한 변경 사항 히스토리가 표시되며 자동으로 변경 사항을 공유합니다. 
<img src="https://velog.velcdn.com/images/cey_adda/post/8ca2175c-eacd-4e7e-9caa-8f4a900571fb/image.png" alt=""></p>
<h1 id="4-트랜잭션-동기화">4. 트랜잭션 동기화</h1>
<p>작업 중인 에셋 타입과 적용된 변경 사항의 특성에 따라 연결된 클라이언트 사이에 변경 사항을 동기화합니다.</p>
<h3 id="레벨-즉시-동기화">레벨: 즉시 동기화</h3>
<p>레벨 콘텐츠에 적용된 모든 변경 사항은 해당 세션의 다른 모든 컴퓨터에 즉시 동기화됩니다.</p>
<h3 id="시퀀서-재생-동기화-및-선택적-ui-동기화">시퀀서: 재생 동기화 및 선택적 UI 동기화</h3>
<p>이 협업 시스템은 레벨 시퀀스와 마스터 시퀀스를 레벨과 같이 취급하기때문에, 사용자가 &#39;트랙 추가나 제거, 새 키프레임 추가&#39;와 같이 <strong>시퀀스</strong>를 변경하면 이러한 변경사항을 세션의 다른 모든 사용자에게 즉시 동기화합니다. </p>
<p>또한 한 사용자가 시퀀스를 열면 모든 클라이언트에서 <strong>시퀀서 UI</strong>를 자동으로 열도록 선택할 수 있으며, 시퀀스를 재생하면 <strong>동일한 시퀀스</strong>가 열려 있는 모든 사용자에 대해 동일한 시퀀스가 즉시 재생됩니다.</p>
<blockquote>
<p>시퀀서 UI 동기화를 활성화하려면 <code>Concert.EnableOpenRemoteSequencer</code> 콘솔 명령을 사용하면 됩니다. </p>
</blockquote>
<h3 id="기타-에셋-저장-시-동기화">기타 에셋: 저장 시 동기화</h3>
<p>프로젝트에 포함되어 있는 대부분의 에셋 타입(머티리얼, 머티리얼 인스턴스, 스태틱 메시 에셋, 블루프린트 클래스)은 수정될 때마다 즉시 동기화되지 않습니다. 누군가가 편집 중인 에셋에는 자물쇠 모양의 더티 상태의 아이콘이 표시됩니다. 이 경우 다른 사용자는 해당 에셋을 수정하지 못하도록 &#39;<strong>잠금</strong>&#39; 상태가 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/61ccac11-150e-4af6-b835-3a97c42defbf/image.png" alt=""></p>
<p>이후 변경한 에셋을 저장하면 세션의 다른 모든 사용자에게 트랜젝션을 전송하며, 잠금 상태였던 에셋의 잠금이 해제됩니다. 수정하지 않은 에셋을 잠그거나 해제하고자 한다면, 에셋을 우클릭하여 [Multi-User] - &#39;Lock Asset(s)&#39;을 선택하면 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/b9e4aaa2-7759-456d-b083-17e406fb68bc/image.png" alt=""></p>
<h1 id="5-세션-변경사항-지속">5. 세션 변경사항 지속</h1>
<p>여러 컴퓨터에서 세션의 레벨과 에셋을 변경하면, 이 트랜잭션이 본인이 사용하고 있는 컴퓨터의 프로젝트를 구성하는 실제 로컬 파일에는 아직 반영되어 있지 않습니다. 이 라이브 세션의 에디터는 일종의 가상 샌드박스 방식으로 로컬 프로젝트 콘텐츠 위에 트랜잭션을 적용하기 때문입니다. </p>
<p>따라서 다른 사람이 라이브 세션 도중에 수행한 작업을 본인의 로컬 프로젝트 파일에 유지하려면 해당 변경 사항을 동기화해야 합니다. 이를 위해서는 에디터 오른쪽 아래에 있는 &#39;Source Control&#39; 아이콘을 눌러 &#39;<strong>Persist Session Change...</strong>&#39;를 선택합니다. 세션 참가자가 이를 선택하면, 현재 세션에서 이루어진 모든 수정 사항을 디스크의 로컬 파일에 적용합니다. </p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/2e32483e-9ec6-4adc-80b9-4d4a8e999689/image.png" alt=""></p>
<p>이후 라이브 세션 도중 수정된 파일에서 로컬 컴퓨터의 프로젝트에 적용할 파일을 선택할 수 있습니다. 
<img src="https://velog.velcdn.com/images/cey_adda/post/88d09188-912c-4cde-bbee-3501399605c1/image.png" alt=""></p>
<p>만약 변경 사항을 지속시키지 않고 세션을 나가버린다면 에디터는 세션 시작 또는 참가 이전 상태로 프로젝트를 자동으로 되돌립니다. 하지만 이는 이전 트랜잭션이 완전히 사라진 것이 아니고, 이후에 같은 세션에 다시 참가하면 멀티 유저 편집 시스템이 모든 해당 트랜잭션을 그대로 에디터에 다시 적용합니다.</p>
<h2 id=""></h2>
<hr>
<h1 id="reference">Reference</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[[C++] STL 이란 - Container]]></title>
            <link>https://velog.io/@cey_adda/C-STL-%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@cey_adda/C-STL-%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 24 Mar 2024 17:46:23 GMT</pubDate>
            <description><![CDATA[<h1 id="stlstandard-template-library">STL(Standard Template Library)</h1>
<p>STL은 &#39;표준 템플릿 라이브러리&#39;의 약자로, C++ 프로그래밍 능률을 한껏 올리는 데 큰 기여를 한 라이브러리입니다. STL이라 함은 주로 세 개의 라이브러리를 사용합니다. </p>
<ul>
<li>container : 임의 타입의 객체를 보관</li>
<li>iterator : container에 보관된 원소에 접근</li>
<li>algorithm : iterator들을 이용하여 일련의 작업을 수행</li>
</ul>
<h2 id="container">Container</h2>
<ul>
<li>sequence container : vector, list, deque</li>
<li>associative container</li>
</ul>
<h3 id="sequence-containerunsorted">sequence container(unsorted)</h3>
<h4 id="1-vectorstdvector">1. Vector(std::vector)</h4>
<p><strong>선언</strong></p>
<pre><code class="language-cpp">#include &lt;vector&gt;
std::vector&lt;int&gt; vec;</code></pre>
<p><strong>초기화</strong></p>
<pre><code class="language-cpp">std::vector&lt; int &gt; vec = {1,2,3,4,5}; 
std::vector&lt; int &gt; vec(10); 
std::vector&lt; int &gt; vec(10,5); </code></pre>
<p><strong>멤버 함수</strong></p>
<pre><code class="language-cpp">vec.push_back( value ); // 맨 뒤에 원소 value 추가
vec.insert( vec.begin(), value ); //원하는 위치에 원하는 값 삽입
vec.pop_back(); // 맨 마지막 원소 제거
vec.erase( vec.begin() ); // 원하는 위치, 범위의 원소 제거
vec.clear();// 벡터 초기화 (길이 = 0)
vec.resize( n ); // 크기를 n으로 바꿈 ( 늘어난 위치의 원소들은 0으로 초기화 )
vec.size(), vec.empty(), vec.front(), vec.back(), vec.begin(), vec.end()</code></pre>
<h4 id="2-liststdlist">2. List(std::list)</h4>
<p><strong>선언</strong></p>
<pre><code class="language-cpp">#include &lt;deque&gt;
</code></pre>
<p><strong>초기화</strong></p>
<pre><code class="language-cpp"></code></pre>
<p><strong>멤버 함수</strong></p>
<pre><code class="language-cpp"></code></pre>
<h3 id="associative-containersorted">associative container(sorted)</h3>
<h4 id="1-setstdset">1. Set(std::set)</h4>
<p><strong>선언</strong></p>
<pre><code class="language-cpp">#include &lt;deque&gt;
</code></pre>
<p><strong>초기화</strong></p>
<pre><code class="language-cpp"></code></pre>
<p><strong>멤버 함수</strong></p>
<pre><code class="language-cpp"></code></pre>
<h3 id="container-adaptor">container adaptor</h3>
<h4 id="1-stackstdstack">1. Stack(std::stack)</h4>
<p><strong>선언</strong></p>
<pre><code class="language-cpp">#include &lt;deque&gt;
</code></pre>
<p><strong>초기화</strong></p>
<pre><code class="language-cpp"></code></pre>
<p><strong>멤버 함수</strong></p>
<pre><code class="language-cpp"></code></pre>
<hr>
<h1 id="reference">Reference</h1>
<ul>
<li><a href="https://modoocode.com/223" target="_blank">[모두의 코드] 씹어먹는 C++ - &lt;10 - 1. C++ STL - 벡터(std::vector), 리스트(list), 데크(deque)&gt;</a></li>
<li><a href="https://esangbaek.github.io/c/c++/CPlusPlusSTL/#vector" target="_blank">[Lee&#39;s blog] C++ STL 사용방법 모음집</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] programmers 깊이/너비 우선 탐색(DFS/BFS) - 단어 변환 C++]]></title>
            <link>https://velog.io/@cey_adda/Algorithm-programmers-%EA%B9%8A%EC%9D%B4%EB%84%88%EB%B9%84-%EC%9A%B0%EC%84%A0-%ED%83%90%EC%83%89DFSBFS-%EB%8B%A8%EC%96%B4-%EB%B3%80%ED%99%98</link>
            <guid>https://velog.io/@cey_adda/Algorithm-programmers-%EA%B9%8A%EC%9D%B4%EB%84%88%EB%B9%84-%EC%9A%B0%EC%84%A0-%ED%83%90%EC%83%89DFSBFS-%EB%8B%A8%EC%96%B4-%EB%B3%80%ED%99%98</guid>
            <pubDate>Fri, 22 Mar 2024 16:10:50 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/43163" target="_blank" >[programmers] Lv.3 단어 변환</a></p>
<blockquote>
</blockquote>
<p><code>문제</code> 두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.</p>
<pre><code>1. 한 번에 한 개의 알파벳만 바꿀 수 있습니다.
2. words에 있는 단어로만 변환할 수 있습니다.</code></pre><p>예를 들어 begin이 &quot;hit&quot;, target가 &quot;cog&quot;, words가 [&quot;hot&quot;,&quot;dot&quot;,&quot;dog&quot;,&quot;lot&quot;,&quot;log&quot;,&quot;cog&quot;]라면 &quot;hit&quot; -&gt; &quot;hot&quot; -&gt; &quot;dot&quot; -&gt; &quot;dog&quot; -&gt; &quot;cog&quot;와 같이 4단계를 거쳐 변환할 수 있습니다.</p>
<blockquote>
</blockquote>
<p>두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.</p>
<blockquote>
</blockquote>
<p><code>제한사항</code> </p>
<pre><code>- 각 단어는 알파벳 소문자로만 이루어져 있습니다.
- 각 단어의 길이는 3 이상 10 이하이며 모든 단어의 길이는 같습니다. 
- words에는 3개 이상 50개 이하의 단어가 있으며 중복되는 단어는 없습니다.
- begin과 target은 같지 않습니다.
- 변환할 수 없는 경우에는 0를 return 합니다.</code></pre><p><code>Input</code></p>
<table>
<thead>
<tr>
<th align="left"><center>begin</center></th>
<th><center>target</center></th>
<th align="right"><center>words</center></th>
</tr>
</thead>
<tbody><tr>
<td align="left"><center>&quot;hit&quot;</center></td>
<td><center>&quot;cog&quot;</center></td>
<td align="right"><center>[&quot;hit&quot;,&quot;dot&quot;,&quot;dog&quot;,&quot;lot&quot;,&quot;log&quot;,&quot;cog&quot;]</center></td>
</tr>
</tbody></table>
<p><code>Output</code></p>
<pre><code>4</code></pre><p><code>Code</code></p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] BAEKJOON 12789 - 도키도키 간식드리미 C++]]></title>
            <link>https://velog.io/@cey_adda/Algorithm-BAEKJOON-12789-%EB%8F%84%ED%82%A4%EB%8F%84%ED%82%A4-%EA%B0%84%EC%8B%9D%EB%93%9C%EB%A6%AC%EB%AF%B8</link>
            <guid>https://velog.io/@cey_adda/Algorithm-BAEKJOON-12789-%EB%8F%84%ED%82%A4%EB%8F%84%ED%82%A4-%EA%B0%84%EC%8B%9D%EB%93%9C%EB%A6%AC%EB%AF%B8</guid>
            <pubDate>Fri, 22 Mar 2024 08:49:36 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/12789" target="_blank" >[BAEKJOON] 12789번 도키도키 간식드리미</a></p>
<blockquote>
</blockquote>
<p><code>문제</code> ...(생략) 사람들은 현재 1열로 줄을 서있고, 맨 앞의 사람만 이동이 가능하다. 인규는 번호표 순서대로만 통과할 수 있는 라인을 만들어 두었다. 이 라인과 대기열의 맨 앞 사람 사이에는 한 사람씩 1열이 들어갈 수 있는 공간이 있다. 현재 대기열의 사람들은 이 공간으로 올 수 있지만 반대는 불가능하다. 승환이를 도와 프로그램을 완성하라.</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/52d2ded3-e340-4322-8086-72a9a90a67a3/image.png" alt=""></p>
</blockquote>
<p><code>입력</code> 입력의 첫째 줄에는 현재 승환이의 앞에 서 있는 학생들의 수 N(1 ≤ N ≤ 1,000,자연수)이 주어진다.
다음 줄에는 승환이 앞에 서있는 모든 학생들의 번호표(1,2,...,N) 순서가 앞에서부터 뒤 순서로 주어진다.</p>
<blockquote>
</blockquote>
<p><code>출력</code> 승환이가 무사히 간식을 받을 수 있으면 &quot;Nice&quot;(따옴표는 제외)를 출력하고 그렇지 않다면 &quot;Sad&quot;(따옴표는 제외)를 출력한다.</p>
<p><code>Input</code></p>
<pre><code>5
5 4 1 3 2</code></pre><p><code>Output</code></p>
<pre><code>Nice</code></pre><p><code>Code</code></p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;stack&gt;

using namespace std;

int main(){
    ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);

    int N, temp, cnt=1;
    cin&gt;&gt;N;

    stack&lt;int&gt; bottom;

    while(N--){
        cin&gt;&gt;temp;

        if(cnt==temp) cnt++;
        else bottom.push(temp);
        while (!bottom.empty() &amp;&amp; bottom.top()==cnt)
        {
            bottom.pop();
            cnt++;
        }
    }

    if(bottom.empty()) cout&lt;&lt;&quot;Nice&quot;;
    else cout&lt;&lt;&quot;Sad&quot;;

    return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] BAEKJOON 17103 - 골드바흐 파티션 C++]]></title>
            <link>https://velog.io/@cey_adda/Algorithm-BAEKJOON-17103-%EC%86%8C%EA%B3%A8%EB%93%9C%EB%B0%94%ED%9D%90-%ED%8C%8C%ED%8B%B0%EC%85%98-C-dd1i4hma</link>
            <guid>https://velog.io/@cey_adda/Algorithm-BAEKJOON-17103-%EC%86%8C%EA%B3%A8%EB%93%9C%EB%B0%94%ED%9D%90-%ED%8C%8C%ED%8B%B0%EC%85%98-C-dd1i4hma</guid>
            <pubDate>Thu, 21 Mar 2024 15:51:52 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/17103" target="_blank" >[BAEKJOON] 17103번 골드바흐 파티션</a></p>
<blockquote>
</blockquote>
<p><code>문제</code> 골드바흐의 추측: 2보다 큰 짝수는 두 소수의 합으로 나타낼 수 있다.
짝수 N을 두 소수의 합으로 나타내는 표현을 골드바흐 파티션이라고 한다. 짝수 N이 주어졌을 때, 골드바흐 파티션의 개수를 구해보자. 두 소수의 순서만 다른 것은 같은 파티션이다.</p>
<blockquote>
</blockquote>
<p><code>입력</code> 첫째 줄에 테스트 케이스의 개수 T (1 ≤ T ≤ 100)가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 N은 짝수이고, 2 &lt; N ≤ 1,000,000을 만족한다.</p>
<blockquote>
</blockquote>
<p><code>출력</code> 각각의 테스트 케이스마다 골드바흐 파티션의 수를 출력한다.</p>
<p><code>Input</code></p>
<pre><code>5 6 8 10 12 100</code></pre><p><code>Output</code></p>
<pre><code>1 1 2 1 6</code></pre><p><code>Code</code></p>
<pre><code class="language-cpp">#include &lt;iostream&gt;

using namespace std;


int main(){
    ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);

    int num, N;
    cin &gt;&gt; num;

    bool arr[1000001] = {false, };
    arr[0]=arr[1]=true;

    for(int i=2; i*i&lt;1000001; i++){
        if(arr[i]) continue;
        for(int j=2*i; j&lt;1000001; j+=i) arr[j] = true;
    }

    while(num--){
        cin &gt;&gt; N;
        int count=0;

        for(int i=2; i&lt;=N/2; i++) if(!arr[i] &amp;&amp; !arr[N-i]) count++;
        cout &lt;&lt; count &lt;&lt; &#39;\n&#39;;
    }

    return 0;
}</code></pre>
<hr>
<img width="55" alt="star1" src="https://github.com/nokcharathae/nokcharathae/assets/64080938/afbff74d-ac61-4e24-aaa0-a29888606c98">

<h3 id="풀이">풀이</h3>
<p>골트바흐의 추측에 따르면, 2보다 큰 모든 짝수는 두개의 소수(Prime nember)의 합으로 표시할 수 있다. 하나의 소수를 두 번 사용하는 것 또한 허용된다. 이를 기반으로 2보다 큰 짝수에 대한 소수를 중복을 허용하고 쭉 나열해 본다면 아래와 같다.</p>
<table>
<thead>
<tr>
<th align="left"><center>짝수</center></th>
<th align="right"><center>골트바흐 파티션</center></th>
</tr>
</thead>
<tbody><tr>
<td align="left"><center>4</center></td>
<td align="right"><center>2+2</center></td>
</tr>
<tr>
<td align="left"><center>6</center></td>
<td align="right"><center> 3+3</center></td>
</tr>
<tr>
<td align="left"><center>8</center></td>
<td align="right"><center> 3+5 = 5+3</center></td>
</tr>
<tr>
<td align="left"><center>10</center></td>
<td align="right"><center> 3+7 = 5+5 = 7+3</center></td>
</tr>
<tr>
<td align="left"><center>...</center></td>
<td align="right"><center> ...</center></td>
</tr>
<tr>
<td align="left"><center>22</center></td>
<td align="right"><center> 3+19 = 5+17 = 11+11 = 17+5 = 19+3</center></td>
</tr>
</tbody></table>
<p>표를 들여다보면 숫자들 사이에서 어떤 규칙을 발견할 수 있다. 바로 <code>하나의 소수의 합으로 이루지거나 중간을 기점으로 대칭하다는 것</code> 이다. </p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/b950767f-59ea-4a0f-93f0-b128531c8958/image.png" alt=""></p>
<h5 id="a-hrefhttpskowikipediaorgwikieab3a8ed8ab8ebb094ed9d90ec9d98_ecb694ecb8a1-stylefont-size70-target_blank-출처--wikipedia-골트바흐의-추측a"><a href="https://ko.wikipedia.org/wiki/%EA%B3%A8%ED%8A%B8%EB%B0%94%ED%9D%90%EC%9D%98_%EC%B6%94%EC%B8%A1" style="font-size:70%" target="_blank" >출처 : [wikipedia] 골트바흐의 추측</a></h5>
<p>이 이미지는 골트바흐의 숫자를 짝수 50까지 시각화한 것이며, 대칭한 규칙을 쉽게 확인할 수 있다. 이 대칭성을 토대로 임의의 짝수 N의 골트바흐 파티션은 임의의 소수 a가 있을 때 N-a가 소수면 그 <code>조건</code>이 성립된다. 이 <code>조건</code>을 만족하는 소수 a의 개수를 구하면 골트바흐 파티션의 개수를 구할 수 있다. </p>
<p>이때, 소수 a는 골트바흐 숫자의 대칭성에 따라 N의 절반 이하의 범위에서 찾을 수 있다. 코드로는 2부터 주어진 임의의 짝수/2 까지의 반복 내에서 위 <code>조건</code>을 만족하는 소수 쌍의 개수를 구하는 방향으로 작성할 수 있다.</p>
<hr>
<img width="55" alt="star1" src="https://github.com/nokcharathae/nokcharathae/assets/64080938/bc678855-5579-42d7-b0cd-1cd5069b22d5">

<h3 id="시행착오">시행착오</h3>
<p>처음에 호기롭게 작성한 식에서 N/2까지 유추를 했지만 시간복잡도가 O(N)이어서 시간 초과를 맛봤다. 이번 기회에 시간복잡도를 고려하면서 더 좋은 코드를 구현할 수 있도록 고민하는 과정의 필요성을 몸소 느꼈다.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;

using namespace std;


int main(){
    ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);

    int num, N;
    cin &gt;&gt; num;

    bool arr[1000001] = {false, };
    arr[0]=arr[1]=true;

    for(int i=2; i*i&lt;1000001; i++){
        if(arr[i]) continue;
        for(int j=2*i; j&lt;1000001; j+=i) arr[j] = true;
    }

    while(num--){
        cin &gt;&gt; N;
        int count=0;

        for(int i=2; i&lt;=N/2; i++){
            for(int j=N-1; j&gt;=N/2; j--){
                if(!arr[i] &amp;&amp; !arr[j]){
                    if(i+j&lt;N) break;
                    else if(i+j == N)
                        count++;
                }
                else continue;
            }
        }

        cout &lt;&lt; count &lt;&lt; &#39;\n&#39;;
    }

    return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] BAEKJOON 1929 - 소수 구하기 C++(시간 초과 해결)]]></title>
            <link>https://velog.io/@cey_adda/Algorithm-BAEKJOON-1929-%EC%86%8C%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0-C</link>
            <guid>https://velog.io/@cey_adda/Algorithm-BAEKJOON-1929-%EC%86%8C%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0-C</guid>
            <pubDate>Thu, 21 Mar 2024 05:35:31 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/1929" target="_blank" >[BAEKJOON] 1929번 소수 구하기</a></p>
<blockquote>
</blockquote>
<p><code>문제</code> M이상 N이하의 소수를 모두 출력하는 프로그램을 작성하시오.</p>
<blockquote>
</blockquote>
<p><code>입력</code> 첫째 줄에 자연수 M과 N이 빈 칸을 사이에 두고 주어진다. (1 ≤ M ≤ N ≤ 1,000,000) M이상 N이하의 소수가 하나 이상 있는 입력만 주어진다. </p>
<blockquote>
</blockquote>
<p><code>출력</code> 한 줄에 하나씩, 증가하는 순서대로 소수를 출력한다.</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/b1d357c5-b7b9-4041-a5c7-758888772ca2/image.gif" alt=""></p>
<h5 id="a-hrefhttpskowikipediaorgwikiec9790eb9dbced86a0ec8aa4ed858ceb84a4ec8aa4ec9d98_ecb2b4-stylefont-size70-colorgray-target_blank-출처--wikipedia-에라토스테네스의-체a"><a href="https://ko.wikipedia.org/wiki/%EC%97%90%EB%9D%BC%ED%86%A0%EC%8A%A4%ED%85%8C%EB%84%A4%EC%8A%A4%EC%9D%98_%EC%B2%B4" style="font-size:70%; color:gray" target="_blank" >출처 : [wikipedia] 에라토스테네스의 체</a></h5>
<p>2부터 차례대로 소수를 구하게 되면 시간 초과 결과와 마주하게된다. 이를 해결하기 위해서는 에라토스테네스의 체를 이용해야한다. 에라토스테네스의 체는 특정 범위가 주어졌을 때 그 범위 내의 소수를 찾는 빠르고 쉬운 방법이다.</p>
<p><code>Input</code></p>
<pre><code>3 6</code></pre><p><code>Output</code></p>
<pre><code>3 5 7 11 13</code></pre><p><code>Code</code></p>
<pre><code class="language-cpp">using namespace std;

int main(){
    ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);

    int min, max;
    cin &gt;&gt; min&gt;&gt;max;


    bool arr[max];
    arr[0] = arr[1] = false;

    for(int i=2; i&lt;=max; i++)
        arr[i] = true;


    for(int i=2; i*i &lt;= max; i++){
        if(!arr[i]) continue;
        for(int j = i*2; j &lt;= max; j += i) arr[j]=false;
    }

    for(int i=min; i&lt;=max; i++)
        if(arr[i]) cout&lt;&lt;i&lt;&lt;&#39;\n&#39;;

    return 0;
}</code></pre>
<hr>
<img width="55" alt="star1" src="https://github.com/nokcharathae/nokcharathae/assets/64080938/bc678855-5579-42d7-b0cd-1cd5069b22d5">


<h3 id="시행착오">시행착오</h3>
<p>처음에는 <code>1434</code> 문제와 비슷한 맥락으로 무작정 소수를 구하는 코드를 작성했다. 그 결과는 어김없이 <span style="color:red">시간 초과</span>  라는 결과를 마주했다.</p>
<h5 id="1첫번째-시도">$^1$첫번째 시도</h5>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;cmath&gt;

using namespace std;

bool isPrime(long long n)
{
    for(int i=2; i&lt;=sqrt(n); i++)
            if(n%i == 0) return false;

    return true;
}

int main(){
    ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);

    long long min, max;
    cin &gt;&gt; min&gt;&gt;max;

    for(int i=min; i&lt;=max; i++){
        while(isPrime(i)){
            cout &lt;&lt; i &lt;&lt; endl;
            i++;
        }  
    }

    return 0;
}</code></pre>
<h5 id="2두번째-시도">$^2$두번째 시도</h5>
<p>wikipedia에서 제공해주는 C++ 코드 기반으로 소수 구하기 코드를 작성했더니 어김없이 마주친 <span style="color:red">시간 초과</span> OTL..
<img src="https://velog.velcdn.com/images/cey_adda/post/c17a8610-014b-4ae9-adef-84224411785f/image.png" alt=""></p>
<pre><code class="language-cpp">using namespace std;

int main(){
    ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);

    int min, max;
    cin &gt;&gt; min&gt;&gt;max;

    bool arr[max];
    arr[0] = arr[1] = false;

    for(int i=2; i&lt;=max; i++)
        arr[i] = true;

    for(int i=2; i*i &lt;= max; i++){
        if(!arr[i]) continue;
        for(int j = i*i; j &lt;= max; j += i) arr[j]=false;
    }

    for(int i=min; i&lt;=max; i++) if(arr[i]) cout&lt;&lt;i&lt;&lt;endl;

    return 0;
}</code></pre>
<h5 id="3세번째-시도">$^3$세번째 시도</h5>
<p>사실 스스로의 힘으로 풀어보고 싶어서 여러번 도전 끝에 10번의 시간 초과 결과를 받고 다른 사람들의 코드를 찾아보기 시작했다. 그러다 ★<a href="https://www.acmicpc.net/board/view/39203" target="_blank" >한 줄기 빛</a>☆ 같은 글을 발견하였다. </p>
<pre><code>5. 에라토스테네스의 체를 구현할 때 흔히 안쪽 루프를 int j = i * i로 시작하는데, 
이렇게 하면 i가 46341이 되는 순간부터 
i * i가 int의 범위를 초과하기 때문에 오버플로우가 발생합니다. 
long long을 사용하거나, i * i 대신 i * 2부터 시작하는 등의 방법을 사용하세요.</code></pre><p>이 글을 믿고 <code>i*i</code> 대신 <code>i*2</code> 로 시작하는 코드로 수정했더니 마법처럼 시간 초과의 저주가 풀렸다!</p>
<pre><code class="language-cpp">...생략

    for(int i=2; i*i &lt;= max; i++){
        if(!arr[i]) continue;
        for(int j = i*2; j &lt;= max; j += i) arr[j]=false;
    }

...</code></pre>
<p>그리고 같은 글에서 앞으로의 코드 스타일에 변화를 주는 문장을 만났다. &quot;추가로 endl은 버퍼를 flush하기 때문에 너무 느립니다. <code>\n</code>을 대신 사용하세요.&quot; 지금부터 <code>endl</code>을 내주고 <code>&#39;\n&#39;</code>를 취한다! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Code Test] Instant NGP with Intel realsense via Python OpenCV]]></title>
            <link>https://velog.io/@cey_adda/Code-Test-Instant-NGP-with-Intel-realsense-via-Python-OpenCV</link>
            <guid>https://velog.io/@cey_adda/Code-Test-Instant-NGP-with-Intel-realsense-via-Python-OpenCV</guid>
            <pubDate>Sun, 17 Mar 2024 06:49:58 GMT</pubDate>
            <description><![CDATA[<p>Intel RealSense 카메라로 찍은 Custom Data를 활용하여 <a href="https://github.com/NVlabs/instant-ngp" target="_blank"><br>Instant NGP</a>를 통해 3D reconstruction하는 방법을 서술합니다. 저는 &#39;Intel RealSense D435&#39; 모델을 랩탑에 연결하여 영상을 찍는 실험을 진행하였습니다. </p>
<h1 id="1-외부-카메라를-통해-영상-촬영하기">1. 외부 카메라를 통해 영상 촬영하기</h1>
<h3 id="textbf1uses-intel-realsense-d435">$^\textbf{1}$Uses Intel RealSense D435</h3>
<p>먼저 &#39;Intel RealSense D435&#39;를 사용하기 위한 코드를 준비합니다.  </p>
<pre><code class="language-python">import pyrealsense2 as rs
import numpy as np
import cv2

# Configure depth and color streams
pipeline = rs.pipeline()
config = rs.config()

# Get device product line for setting a supporting resolution
pipeline_wrapper = rs.pipeline_wrapper(pipeline)
pipeline_profile = config.resolve(pipeline_wrapper)
device = pipeline_profile.get_device()
device_product_line = str(device.get_info(rs.camera_info.product_line))

found_rgb = False
for s in device.sensors:
    if s.get_info(rs.camera_info.name) == &#39;RGB Camera&#39;:
        found_rgb = True
        break
if not found_rgb:
    print(&quot;The demo requires Depth camera with Color sensor&quot;)
    exit(0)

config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)

if device_product_line == &#39;L500&#39;:
    config.enable_stream(rs.stream.color, 960, 540, rs.format.bgr8, 30)
else:
    config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)

# Start streaming
pipeline.start(config)

try:
    while True:

        # Wait for a coherent pair of frames: depth and color
        frames = pipeline.wait_for_frames()
        depth_frame = frames.get_depth_frame()
        color_frame = frames.get_color_frame()
        if not depth_frame or not color_frame:
            continue

        # Convert images to numpy arrays
        depth_image = np.asanyarray(depth_frame.get_data())
        color_image = np.asanyarray(color_frame.get_data())

        # Apply colormap on depth image (image must be converted to 8-bit per pixel first)
        depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.03), cv2.COLORMAP_JET)

        depth_colormap_dim = depth_colormap.shape
        color_colormap_dim = color_image.shape

        # If depth and color resolutions are different, resize color image to match depth image for display
        if depth_colormap_dim != color_colormap_dim:
            resized_color_image = cv2.resize(color_image, dsize=(depth_colormap_dim[1], depth_colormap_dim[0]), interpolation=cv2.INTER_AREA)
            images = np.hstack((resized_color_image, depth_colormap))
        else:
            images = np.hstack((color_image, depth_colormap))

        # Show images
        cv2.namedWindow(&#39;RealSense&#39;, cv2.WINDOW_AUTOSIZE)
        cv2.imshow(&#39;RealSense&#39;, images)
        cv2.waitKey(1)

finally:

    # Stop streaming
    pipeline.stop()</code></pre>
<h3 id="textbf2-record-video-with-webcam">$^\textbf{2}$ Record video with webcam</h3>
<p>촬영한 영상 혹은 사진을 Instant NGP가 사용할 수 있는 데이터로 정제하기 위해서 저장하는 과정을 거칩니다. 파일명은 이미 저장된 파일과 겹치지 않게 시간을 기준으로 생성되도록 작성하였습니다. </p>
<pre><code class="language-python">import cv2
import time
import pyrealsense2 as rs
import numpy as np

# intel realsense initial

# Configure depth and color streams
pipeline = rs.pipeline()
config = rs.config()

# Get device product line for setting a supporting resolution
pipeline_wrapper = rs.pipeline_wrapper(pipeline)
pipeline_profile = config.resolve(pipeline_wrapper)
device = pipeline_profile.get_device()
device_product_line = str(device.get_info(rs.camera_info.product_line))

# Get device product line for setting a supporting resolution
pipeline_wrapper = rs.pipeline_wrapper(pipeline)
pipeline_profile = config.resolve(pipeline_wrapper)
device = pipeline_profile.get_device()
device_product_line = str(device.get_info(rs.camera_info.product_line))

found_rgb = False
for s in device.sensors:
    if s.get_info(rs.camera_info.name) == &#39;RGB Camera&#39;:
        found_rgb = True
        break
if not found_rgb:
    print(&quot;The demo requires Depth camera with Color sensor&quot;)
    exit(0)

# config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)

if device_product_line == &#39;L500&#39;:
    config.enable_stream(rs.stream.color, 960, 540, rs.format.bgr8, 30)
else:
    config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)

# Start streaming
pipeline.start(config)

# ------------------------------------------------------

fc = 20.0
codec = cv2.VideoWriter_fourcc(&#39;D&#39;, &#39;I&#39;, &#39;V&#39;, &#39;X&#39;)
count = 99

while(True):

    frames = pipeline.wait_for_frames()
    color_frame = frames.get_color_frame()
    color_image = np.asanyarray(color_frame.get_data())
    color_colormap_dim = color_image.shape
    images = color_image

    if count != time.strftime(&#39;%H&#39;,time.localtime(time.time())): # 시간이 바뀌면 영상파일을 새로 만든다. (시간으로 감지)

        count = time.strftime(&#39;%H&#39;,time.localtime(time.time()))
        print(&#39;시간 변경 감지&#39;)

        out = cv2.VideoWriter(time.strftime(&#39;%Y-%m-%d %H시 %M분&#39;,time.localtime(time.time()))+&#39;.avi&#39;, codec, fc, (720,1084))
        print(&#39;파일 생성:&#39;,time.strftime(&#39;%Y-%m-%d %H시 %M분&#39;,time.localtime(time.time()))+&#39;.avi&#39;)

    # Show images
    # cv2.namedWindow(&#39;RealSense&#39;, cv2.WINDOW_AUTOSIZE)
    cv2.imshow(&#39;Record&amp;Save&#39;, images)
    out.write(images)
    if cv2.waitKey(1) &amp; 0xFF == ord(&#39;q&#39;):
        break

cv2.destroyAllWindows()</code></pre>
<h1 id="2-instant-ngp-실행-프로그램-다운로드">2. Instant NGP 실행 프로그램 다운로드</h1>
<a href="https://github.com/NVlabs/instant-ngp?tab=readme-ov-file#installation" target="_blank">    
Instant NGP Github</a> 페이지에서 'Installation' 파트에 있는 `instant-ngp.exe` 파일을 자신의 그래픽 카드 사양에 맞춰 다운로드합니다. 단, 해당 프로그램은 Windows 기반입니다. Linux를 사용하신다면 <a href="https://github.com/NVlabs/instant-ngp#python-bindings" target="_blank">다른 방식</a> 통해서 Instant NGP를 사용하실 수 있습니다. 

<p>저는 그래픽카드로 RTX 3060을 사용하고 있으므로 &#39;RTX 3000 &amp; 4000 series, RTX A4000–A6000, and other Ampere &amp; Ada cards&#39; 응용 프로그램을 다운받아서 실험을 진행하였습니다. </p>
<h1 id="3-인풋-데이터-얻기">3. 인풋 데이터 얻기</h1>
<p>저는 COLMAP이 추정한 intrinsic parameters과 고정된 intrinsic parameters에 따라 reconstruction 결과가 달라지는지 비교하고자 두 단계를 거쳐 실험하였습니다. 단순히 추정치만으로 실험하실 분은 3.1 번의 과정을 진행하시면 됩니다. </p>
<h2 id="31-colmap-추정-instrinsic-parameters-사용---instant-ngp에서-제공하는-코드-사용">3.1. COLMAP 추정 instrinsic parameters 사용 - Instant NGP에서 제공하는 코드 사용</h2>
<p>NVIDIA에서는 친절하게 custom data를 활용한 Instant NGP 사용 <a href="https://www.youtube.com/watch?v=3TWxO1PftMc" target="_blank">tutorial video</a>를 제공하고 있습니다. 아래 코드를 통해 본인의 데이터를 통해 모델에 필요한 파일 transform.json 을 얻으실 수 있습니다. </p>
<h3 id="textbf1-go-to-data-path">$^\textbf{1}$ Go to data path</h3>
<p>제 경우에는 촬영한 영상을 설치한 프로그램 폴더의 <code>data</code> 폴더 내의 <code>test</code> 폴더에 위치시켰습니다. 
<code>cd C:\(your path here)\Instant-NGP-for-RTX-3000-and-4000\data\test</code></p>
<h3 id="textbf2-primary-data-cleaning">$^\textbf{2}$ Primary data cleaning</h3>
<p>먼저 학습 데이터로 사용할 이미지를 추출하기 위한 작업을 거칩니다. 이때, 실험적으로 <code>--video_in</code> 에 사용될 영상은 <code>.mov</code> 파일 형식일 때 잘되는 것을 확인하였습니다. 
<code>python ..\scripts\colmap2nerf.py --video_in test.MOV --video_fps 2 --run_colmap --overwrite</code></p>
<p>비디오로부터 이미지를 추출하고 그 사이에서 양질의 이미지만을 고르는 과정을 거칠 것이기 때문에 &quot;Feature extract&quot;가 시작된다면 이미 이미지 추출은 끝났기때문에 <code>ctrl+C</code>를 눌러 작업을 취소합니다. (계속 진행해도 상관없습니다만 작업 속도가 오래걸릴 수 있습니다.)
<img src="https://velog.velcdn.com/images/cey_adda/post/98d8b6ff-4a72-4e42-a0ff-9582fe3c970c/image.png" alt=""></p>
<p>이후, <code>C:\(your path here)\Instant-NGP-for-RTX-3000-and-4000\data\test</code> 경로에 이미지와 여러 파일이 생성되는 것을 확인할 수 있습니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/b1571e8a-f883-46da-a6ef-8a74918fd869/image.png" alt=""></p>
<p>이후 <code>images</code> 폴더 내의 이미지 파일을 열어 흐릿하거나 쓸모 없는 프레임을 삭제합니다. 저는 <a href="https://www.irfanview.com/64bit.htm" target="_blank">IrfanView 64</a>라는 프로그램을 이용하여 이미지 사이즈를 조절하거나, 흐린 사진을 간편하게 삭제하였습니다. 
<img src="https://velog.velcdn.com/images/cey_adda/post/d02aa036-d936-4e2c-a417-de3d9dc8b741/image.jpg" alt=""></p>
<p>$\scriptsize{\textcolor{gray}{\textrm{이런 이미지를 삭제하면 됩니다.}}}$</p>
<h3 id="textbf3-secondary-data-cleaning">$^\textbf{3}$ Secondary data cleaning</h3>
<p>양질의 이미지세트를 얻었다면 이 이미지들을 기반으로 camera parameters를 추정합니다. 
<code>python C:\Users\(your path here)\instant-ngp\scripts\colmap2nerf.py --colmap_matcher exhaustive --run_colmap --aabb_scale 16 --overwrite</code></p>
<p>비디오 또는 밀접하게 관련된 샷 세트의 경우 이미지가 순서대로 있으므로 &quot;--colmap_matcher&quot;를 제거할 수 있습니다. 이렇게 하면 몇 분이 절약됩니다. 더 자세한 사항은 <a href="https://github.com/NVlabs/instant-ngp/blob/master/docs/nerf_dataset_tips.md" target="_blank">nerf_dataset_tips.md</a>를 참조하세요.</p>
<p>코드 실행이 끝나면 폴더에 다음과 같이 파일들이 생성되는 것을 확인하실 수 있습니다. 최종적으로 transforms.json 파일을 얻어 Instant NGP의 인풋데이터인 카메라 데이터를 얻을 수 있습니다. 
<img src="https://velog.velcdn.com/images/cey_adda/post/59a661e3-8bb2-4127-ae9e-b43d20b69e96/image.png" alt=""></p>
<h2 id="32-고정된-intrinsic-parameters-사용----colmap을-통해-intrinsic-parameters-얻기">3.2. 고정된 intrinsic parameters 사용 -  Colmap을 통해 intrinsic parameters 얻기</h2>
<h3 id="textbf1-get-intrinsic--parameters">$^\textbf{1}$ Get intrinsic  parameters</h3>
<p>카메라가 기본적으로 가지고 있는 intrinsic parameters를 출력하였습니다. </p>
<pre><code class="language-python">import pyrealsense2 as rs
pipeline = rs.pipeline()
config = rs.config()

pipeline_wrapper = rs.pipeline_wrapper(pipeline)
pipeline_profile = config.resolve(pipeline_wrapper)
device = pipeline_profile.get_device()
device_product_line = str(device.get_info(rs.camera_info.product_line))

config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)

pipeline.start(config)


frames = pipeline.wait_for_frames()
color_frame = frames.get_color_frame()

intrinsics = color_frame.profile.as_video_stream_profile().intrinsics
fx, fy = intrinsics.fx, intrinsics.fy  # Focal length
cx, cy = intrinsics.ppx, intrinsics.ppy  # Principal point
coeffs = intrinsics.coeffs  # Distortion coefficients

print(&quot;Intrinsic parameters:&quot;)
print(&quot;Focal Length (fx, fy):&quot;, fx, fy)
print(&quot;Principal Point (cx, cy):&quot;, cx, cy)
print(&quot;Distortion Coefficients:&quot;, coeffs)   

pipeline.stop()</code></pre>
<h3 id="textbf2-find-parameters-through-colmap">$^\textbf{2}$ Find parameters through colmap</h3>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/60cdb64d-fd90-4eff-bc84-5cf57486f9ab/image.png" alt=""></p>
<p>Colmap이란 간단히 말해 SfM(Structure from Motion)과 MVS(Multi-View Stereo) 기술을 사용하여, 여러 장의 2D 이미지로부터 3D 모델을 자동으로 생성하는 오픈소스 소프트웨어입니다. 정렬된 이미지 컬렉션과 정렬되지 않은 이미지 컬렉션을 재구성하기 위한 다양한 기능을 제공합니다:</p>
<ul>
<li>Automatic Camera Calibration: 이미지 집합에서 카메라의 위치와 방향을 추정합니다.</li>
<li>Point Cloud Generation: 이미지 집합에서 3D 포인트 클라우드를 생성합니다.</li>
<li>Dense 3D Reconstruction: 생성된 포인트 클라우드를 바탕으로 더 밀도 있는 3D 모델을 생성합니다.</li>
<li>Texture Mapping for 3D Models: 3D 모델에 이미지 텍스처를 매핑하여 사실적인 외관을 생성합니다.</li>
</ul>
<h4 id="①-create-project">① Create project</h4>
<ol>
<li>[File] - [New Project] 클릭</li>
<li>[New] - Database를 저장할 원하는 경로에 Database 파일을 생성</li>
<li>[Select] - Image들이 저장된 폴더를 지정</li>
<li>[Save] 버튼 클릭
<img src="https://velog.velcdn.com/images/cey_adda/post/09c89926-13af-46df-aefd-67457b33d597/image.png" alt=""></li>
</ol>
<h4 id="②-feature-extraction-for-each-image">② Feature extraction for each image</h4>
<ol>
<li>[Processing] - [Feature Extraction]</li>
</ol>
<ul>
<li>custom parameters를 앞에서 구한 intel realsense의 intrinsic parameter로 설정 + Camera model은 <code>OPENCV</code> 로 설정
<img src="https://velog.velcdn.com/images/cey_adda/post/aad7c538-a5e0-4cda-9c67-5b2d7a2aff3d/image.png" alt=""></li>
</ul>
<ol start="2">
<li>[Database management] - [Cameras]
<img src="https://velog.velcdn.com/images/cey_adda/post/74a2c2f6-c4c7-4019-bf88-ed6ce0272927/image.png" alt=""></li>
</ol>
<ul>
<li>카메라 데이터 테이블을 통해 이미지에 대한 카메라 intrinsic parameters가 잘 매칭되어 있는지 확인합니다. 
<img src="https://velog.velcdn.com/images/cey_adda/post/639f758a-1193-4c36-9e23-008e24c490c8/image.png" alt=""></li>
</ul>
<h4 id="③-feature-matching-for-each-image">③ Feature matching for each image</h4>
<p>[Processing] - [Feature Matching]</p>
<ul>
<li>특징 매칭을 위한 단계입니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/6c6b72df-2d2f-4640-893b-2c0cc1c0c308/image.png" alt=""></li>
</ul>
<h4 id="④-reconstruction">④ Reconstruction</h4>
<p>[Reconstruction] - [Start Reconstruction]</p>
<ul>
<li>reconstruction 시작 전, reconstruction  options - Bundle 에서 &#39;Camera parameters&#39; 파트의 카메라 파라미터 refine 항목들을 uncheck합니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/ea1b91c3-97c3-488c-99ec-12f70401e2fc/image.png" alt=""></li>
</ul>
<h4 id="⑤-save-model">⑤ Save model</h4>
<p>[File] - [Export model as text]</p>
<ul>
<li>앞서 구한 카메라 파라미터를 Instant NGP에서 사용할 수 있는 데이터 형식으로 사용할 수 있도록, <code>images</code> 폴더가 있는 데이터 root 폴더에 <code>colmap_text</code> 폴더를 생성합니다. 그리고 이 경로(제 경우에는 <code>C:\(your path here)\Instant-NGP-for-RTX-3000-and-4000\data\test\colmap_text</code>)에 text로 된 model를 export합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/896e4ac5-66ce-48a8-ab38-34ae3921cc52/image.png" alt=""></p>
<h3 id="textbf3-get-transformsjson-file">$^\textbf{3}$ Get transforms.json file</h3>
<p>애써 구한 파라미터들이 덮어 씌워지면 안되므로 기존 코드에 있던 <code>--run_colmap</code> 는 지우고 코드를 실행합니다.
<code>python C:\Users\(your path here)\instant-ngp\scripts\colmap2nerf.py  --aabb_scale 16 --overwrite</code></p>
<p>그러면 최종적으로 아래와 같이 tranforms.json 파일이 생성됩니다.</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/67cd7082-6a5a-418c-b4b2-409b8ea9f989/image.png" alt=""></p>
<h1 id="4-instant-ngpexe-실행하기">4. instant-ngp.exe 실행하기</h1>
<p>앞서 설치한 instant-ngp.exe 응용 파일을 실행하시면 아래와 같이 처음에는 검은 화면으로 시작합니다. 이제 이 프로그램에 우리가 구한 인풋 데이터 images와 tranforms.json이 들어있는 폴더 채로 drag&amp;drop 하여 넣어주면 됩니다. </p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/4902ee7f-ef92-425e-8f42-d81b3beadc28/image.png" alt=""></p>
<h1 id="results">Results</h1>
<hr>
<h1 id="reference">Reference</h1>
<ul>
<li><a href="https://colmap.github.io" target="_blank">COLMAP Official Documentation</a></li>
<li><a href="https://blog.naver.com/PostView.nhn?blogId=heennavi1004&logNo=222011908566" target="_blank">    
[Realsense2] 파이썬으로 realsense 프로그래밍 | 작성자 초초</a></li>
<li><a href="https://github.com/kmss1258/Colmap-setup" target="_blank">    
kmss1258/Colmap-setup</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Computer Graphics] Swap chain]]></title>
            <link>https://velog.io/@cey_adda/Computer-Graphics-Swap-chain</link>
            <guid>https://velog.io/@cey_adda/Computer-Graphics-Swap-chain</guid>
            <pubDate>Sun, 21 Jan 2024 09:07:39 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/cey_adda/post/c68d098b-9d66-455d-9b86-a37d1520bdf0/image.png" alt=""></p>
<p>Swap chain은 두 개의 버퍼 <span style="color: green"><strong>front buffer</strong></span>와 <span style="color: blue"><strong>back buffer</strong></span>를 사용하여 화면에 자연스럽게 이어지는 이미지를 표시하는 방법입니다. 이때, <span style="color: green"><strong>front buffer</strong></span>는 현재 화면에 표시되고 있는 이미지를 담고 있는 버퍼로, 사용자가 보고 있는 화면의 내용을 담고 있습니다. <span style="color: blue"><strong>back buffer</strong></span>는 새로운 이미지가 렌더링되는 버퍼로, 화면에 보이지 않는 버퍼 메로리가 두세개로 이루어져 있으며 다음 렌더링할 새로운 프레임이 여기에 렌더링됩니다. 렌더링이 완료되면, <span style="color: blue"><strong>back buffer</strong></span>의 내용이 <span style="color: green"><strong>front buffer</strong></span>로 교체됩니다. 이 과정을 &#39;swap&#39;이라고 합니다. swap 후, 새로운 이미지가 <span style="color: green"><strong>front buffer</strong></span>에 표시되어 사용자가 볼 수 있게 됩니다.</p>
<p>이 swap chain이 필요한 이유는 화면 갱신율과 렌더링 속도가 다를 때 발생하는 Screen Tearing 현상을 방지하기 위함입니다. 또한 사용자에게 부드러운 이미지 전환 경험을 제공합니다. 이미지가 렌더링되는 동안 사용자는 오래된 프레임을 보게 되므로, 렌더링 과정에서 발생할 수 있는 끊김이나 지연 현상을 줄일 수 있습니다. DirectX에서의 swap chain은 DXGI에 포함되어 있습니다. </p>
<hr>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Swap_chain" target="_blank">
[WIKIPEDIA] Swap chain</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Code Review] Barbershop: GAN-based Image Compositing using Segmentation Masks]]></title>
            <link>https://velog.io/@cey_adda/Code-Review-Barbershop-GAN-based-Image-Compositing-using-Segmentation-Masks</link>
            <guid>https://velog.io/@cey_adda/Code-Review-Barbershop-GAN-based-Image-Compositing-using-Segmentation-Masks</guid>
            <pubDate>Sun, 17 Dec 2023 15:51:09 GMT</pubDate>
            <description><![CDATA[<p>Paper : <a href="https://arxiv.org/pdf/2106.01505.pdf" target="_blank">Barbershop: GAN-based Image Compositing using Segmentation Maskss
</a></p>
<h1 id="data-preprocessing">Data preprocessing</h1>
<p><em>align_face.py</em>
: 이미지를 다운로드하고, 얼굴을 정렬한 후, 정렬된 얼굴 이미지를 저장</p>
<pre><code class="language-python">cache_dir = Path(args.cache_dir)
cache_dir.mkdir(parents=True, exist_ok=True)

output_dir = Path(args.output_dir)
output_dir.mkdir(parents=True,exist_ok=True)

print(&quot;Downloading Shape Predictor&quot;)
f=open_url(&quot;https://drive.google.com/uc?id=1huhv8PYpNNKbGCLOaYUjOgR1pY5pmbJx&quot;, cache_dir=cache_dir, return_path=True)
predictor = dlib.shape_predictor(f)

for im in Path(args.unprocessed_dir).glob(&quot;*.*&quot;):
    faces = align_face(str(im),predictor)

    for i,face in enumerate(faces):
        if(args.output_size):
            factor = 1024//args.output_size
            assert args.output_size*factor == 1024
            face_tensor = torchvision.transforms.ToTensor()(face).unsqueeze(0).cuda()
            face_tensor_lr = face_tensor[0].cpu().detach().clamp(0, 1)
            face = torchvision.transforms.ToPILImage()(face_tensor_lr)
            if factor != 1:
                face = face.resize((args.output_size, args.output_size), PIL.Image.LANCZOS)
        if len(faces) &gt; 1:
            face.save(Path(args.output_dir) / (im.stem+f&quot;_{i}.png&quot;))
        else:
            face.save(Path(args.output_dir) / (im.stem + f&quot;.png&quot;))</code></pre>
<ul>
<li><code>align_face</code> :  얼굴 정렬을 수행하는 함수로, 얼굴의 특징점(landmarks)을 찾아서 얼굴이 중심에 오도록 이미지를 재조정. 이 함수는 입력으로 이미지 파일 경로(filepath)와 얼굴의 랜드마크를 찾는데 사용되는 모델(predictor)을 통해 정렬된 얼굴 이미지를 반환.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/7cebc9cc-3c9a-49d8-9f01-344845e69314/image.png" alt=""></p>
<h1 id="main">Main</h1>
<p><em>main.py</em>
: ① Embedding ② Alignment ③ Blending</p>
<pre><code class="language-python">from models.Embedding import Embedding
from models.Alignment import Alignment
from models.Blending import Blending

def main(args):
    # ① Embedding
    ii2s = Embedding(args)

    im_path1 = os.path.join(args.input_dir, args.im_path1)
    im_path2 = os.path.join(args.input_dir, args.im_path2)
    im_path3 = os.path.join(args.input_dir, args.im_path3)

    im_set = {im_path1, im_path2, im_path3}
    ii2s.invert_images_in_W([*im_set])
    ii2s.invert_images_in_FS([*im_set])

    # ② Alignment
    align = Alignment(args)
    align.align_images(im_path1, im_path2, sign=args.sign, align_more_region=False, smooth=args.smooth)
    if im_path2 != im_path3:
        align.align_images(im_path1, im_path3, sign=args.sign, align_more_region=False, smooth=args.smooth, save_intermediate=False)

    # ③ Blending
    blend = Blending(args)
    blend.blend_images(im_path1, im_path2, im_path3, sign=args.sign)</code></pre>
<h3 id="①-embedding">① Embedding</h3>
<p><em>Embedding.py</em>
<code>ii2s = Embedding(args)</code></p>
<pre><code class="language-python">class Embedding(nn.Module):

    def __init__(self, opts):
        super(Embedding, self).__init__()
        self.opts = opts
        self.net = Net(self.opts)
        self.load_downsampling()
        self.setup_embedding_loss_builder()


    def load_downsampling(self):
        factor = self.opts.size // 256
        self.downsample = BicubicDownSample(factor=factor)

    def setup_embedding_loss_builder(self):
        self.loss_builder = EmbeddingLossBuilder(self.opts)</code></pre>
<p><code>ii2s.invert_images_in_W([*im_set])</code></p>
<pre><code class="language-python">    def invert_images_in_W(self, image_path=None):
        self.setup_dataloader(image_path=image_path)
        device = self.opts.device
        ibar = tqdm(self.dataloader, desc=&#39;Images&#39;)
        for ref_im_H, ref_im_L, ref_name in ibar:
            optimizer_W, latent = self.setup_W_optimizer()
            pbar = tqdm(range(self.opts.W_steps), desc=&#39;Embedding&#39;, leave=False)
            for step in pbar:
                optimizer_W.zero_grad()
                latent_in = torch.stack(latent).unsqueeze(0)

                gen_im, _ = self.net.generator([latent_in], input_is_latent=True, return_latents=False)
                im_dict = {
                    &#39;ref_im_H&#39;: ref_im_H.to(device),
                    &#39;ref_im_L&#39;: ref_im_L.to(device),
                    &#39;gen_im_H&#39;: gen_im,
                    &#39;gen_im_L&#39;: self.downsample(gen_im)
                }

                loss, loss_dic = self.cal_loss(im_dict, latent_in)
                loss.backward()
                optimizer_W.step()

                if self.opts.verbose:
                    pbar.set_description(&#39;Embedding: Loss: {:.3f}, L2 loss: {:.3f}, Perceptual loss: {:.3f}, P-norm loss: {:.3f}&#39;
                                         .format(loss, loss_dic[&#39;l2&#39;], loss_dic[&#39;percep&#39;], loss_dic[&#39;p-norm&#39;]))

                if self.opts.save_intermediate and step % self.opts.save_interval== 0:
                    self.save_W_intermediate_results(ref_name, gen_im, latent_in, step)

            self.save_W_results(ref_name, gen_im, latent_in)</code></pre>
<p><code>ii2s.invert_images_in_FS([*im_set])</code></p>
<pre><code class="language-python">    def invert_images_in_FS(self, image_path=None):
        self.setup_dataloader(image_path=image_path)
        output_dir = self.opts.output_dir
        device = self.opts.device
        ibar = tqdm(self.dataloader, desc=&#39;Images&#39;)
        for ref_im_H, ref_im_L, ref_name in ibar:

            latent_W_path = os.path.join(output_dir, &#39;W+&#39;, f&#39;{ref_name[0]}.npy&#39;)
            latent_W = torch.from_numpy(convert_npy_code(np.load(latent_W_path))).to(device)
            F_init, _ = self.net.generator([latent_W], input_is_latent=True, return_latents=False, start_layer=0, end_layer=3)
            optimizer_FS, latent_F, latent_S = self.setup_FS_optimizer(latent_W, F_init)


            pbar = tqdm(range(self.opts.FS_steps), desc=&#39;Embedding&#39;, leave=False)
            for step in pbar:

                optimizer_FS.zero_grad()
                latent_in = torch.stack(latent_S).unsqueeze(0)
                gen_im, _ = self.net.generator([latent_in], input_is_latent=True, return_latents=False,
                                               start_layer=4, end_layer=8, layer_in=latent_F)
                im_dict = {
                    &#39;ref_im_H&#39;: ref_im_H.to(device),
                    &#39;ref_im_L&#39;: ref_im_L.to(device),
                    &#39;gen_im_H&#39;: gen_im,
                    &#39;gen_im_L&#39;: self.downsample(gen_im)
                }

                loss, loss_dic = self.cal_loss(im_dict, latent_in)
                loss.backward()
                optimizer_FS.step()

                if self.opts.verbose:
                    pbar.set_description(
                        &#39;Embedding: Loss: {:.3f}, L2 loss: {:.3f}, Perceptual loss: {:.3f}, P-norm loss: {:.3f}, L_F loss: {:.3f}&#39;
                        .format(loss, loss_dic[&#39;l2&#39;], loss_dic[&#39;percep&#39;], loss_dic[&#39;p-norm&#39;], loss_dic[&#39;l_F&#39;]))

            self.save_FS_results(ref_name, gen_im, latent_in, latent_F)</code></pre>
<h3 id="②-alignment">② Alignment</h3>
<p><em>Alignment.py</em>
<code>align = Alignment(args)</code></p>
<pre><code class="language-python">class Alignment(nn.Module):

    def __init__(self, opts, net=None):
        super(Alignment, self).__init__()
        self.opts = opts
        if not net:
            self.net = Net(self.opts)
        else:
            self.net = net

        self.load_segmentation_network()
        self.load_downsampling()
        self.setup_align_loss_builder()

    def load_segmentation_network(self):
        self.seg = BiSeNet(n_classes=16)
        self.seg.to(self.opts.device)

        if not os.path.exists(self.opts.seg_ckpt):
            download_weight(self.opts.seg_ckpt)
        self.seg.load_state_dict(torch.load(self.opts.seg_ckpt))
        for param in self.seg.parameters():
            param.requires_grad = False
        self.seg.eval()

    def load_downsampling(self):

        self.downsample = BicubicDownSample(factor=self.opts.size // 512)
        self.downsample_256 = BicubicDownSample(factor=self.opts.size // 256)

    def setup_align_loss_builder(self):
        self.loss_builder = AlignLossBuilder(self.opts)</code></pre>
<p><code>align.align_images(im_path1, im_path2, sign=args.sign, align_more_region=False, smooth=args.smooth)</code>
: 두 이미지의 특성을 반영하여 최적의 정렬을 수행</p>
<pre><code class="language-python">    def align_images(self, img_path1, img_path2, sign=&#39;realistic&#39;, align_more_region=False, smooth=5,
                     save_intermediate=True):

        ################## img_path1: Identity Image
        ################## img_path2: Structure Image

        device = self.opts.device
        output_dir = self.opts.output_dir
        target_mask, hair_mask_target, hair_mask1, hair_mask2 = \
            self.create_target_segmentation_mask(img_path1=img_path1, img_path2=img_path2, sign=sign,
                                                 save_intermediate=save_intermediate)

        im_name_1 = os.path.splitext(os.path.basename(img_path1))[0]
        im_name_2 = os.path.splitext(os.path.basename(img_path2))[0]

        latent_FS_path_1 = os.path.join(output_dir, &#39;FS&#39;, f&#39;{im_name_1}.npz&#39;)
        latent_FS_path_2 = os.path.join(output_dir, &#39;FS&#39;, f&#39;{im_name_2}.npz&#39;)

        latent_1, latent_F_1 = load_FS_latent(latent_FS_path_1, device)
        latent_2, latent_F_2 = load_FS_latent(latent_FS_path_2, device)

        latent_W_path_1 = os.path.join(output_dir, &#39;W+&#39;, f&#39;{im_name_1}.npy&#39;)
        latent_W_path_2 = os.path.join(output_dir, &#39;W+&#39;, f&#39;{im_name_2}.npy&#39;)</code></pre>
<ul>
<li><code>save_intermediate</code> : 중간 결과를 저장할 것인지를 결정</li>
<li><code>create_target_segmentation_mask</code> : 이미지의 특정 영역을 추출하는 데 사용되는 대상 세그멘테이션 마스크를 생성</li>
<li><code>load_FS_latent</code> : 이미지의 특성을 불러옴</li>
</ul>
<h4 id="첫-번째-정렬-단계">첫 번째 정렬 단계</h4>
<pre><code class="language-python">        optimizer_align, latent_align_1 = self.setup_align_optimizer(latent_W_path_1)

        pbar = tqdm(range(self.opts.align_steps1), desc=&#39;Align Step 1&#39;, leave=False)
        for step in pbar:
            optimizer_align.zero_grad()
            latent_in = torch.cat([latent_align_1[:, :6, :], latent_1[:, 6:, :]], dim=1)
            down_seg, _ = self.create_down_seg(latent_in)

            loss_dict = {}
            ##### Cross Entropy Loss
            ce_loss = self.loss_builder.cross_entropy_loss(down_seg, target_mask)
            loss_dict[&quot;ce_loss&quot;] = ce_loss.item()
            loss = ce_loss

            loss.backward()
            optimizer_align.step()

        intermediate_align, _ = self.net.generator([latent_in], input_is_latent=True, return_latents=False,
                                                   start_layer=0, end_layer=3)
        intermediate_align = intermediate_align.clone().detach()</code></pre>
<ul>
<li><code>setup_align_optimizer</code> : 이미지 정렬을 위한 최적화기와 정렬 대상 이미지의 특성을 설정</li>
<li><code>create_down_seg</code> : 주어진 latent code를 이용하여 이미지를 생성하고, 생성된 이미지의 세그멘테이션을 생성하는 과정을 수행</li>
</ul>
<h4 id="두-번째-정렬-단계">두 번째 정렬 단계</h4>
<pre><code class="language-python">        optimizer_align, latent_align_2 = self.setup_align_optimizer(latent_W_path_2)

        with torch.no_grad():
            tmp_latent_in = torch.cat([latent_align_2[:, :6, :], latent_2[:, 6:, :]], dim=1)
            down_seg_tmp, I_Structure_Style_changed = self.create_down_seg(tmp_latent_in)

            current_mask_tmp = torch.argmax(down_seg_tmp, dim=1).long()
            HM_Structure = torch.where(current_mask_tmp == 10, torch.ones_like(current_mask_tmp),
                                       torch.zeros_like(current_mask_tmp))
            HM_Structure = F.interpolate(HM_Structure.float().unsqueeze(0), size=(256, 256), mode=&#39;nearest&#39;)

        pbar = tqdm(range(self.opts.align_steps2), desc=&#39;Align Step 2&#39;, leave=False)
        for step in pbar:
            optimizer_align.zero_grad()
            latent_in = torch.cat([latent_align_2[:, :6, :], latent_2[:, 6:, :]], dim=1)
            down_seg, gen_im = self.create_down_seg(latent_in)

            Current_Mask = torch.argmax(down_seg, dim=1).long()
            HM_G_512 = torch.where(Current_Mask == 10, torch.ones_like(Current_Mask),
                                   torch.zeros_like(Current_Mask)).float().unsqueeze(0)
            HM_G = F.interpolate(HM_G_512, size=(256, 256), mode=&#39;nearest&#39;)

            loss_dict = {}

            ########## Segmentation Loss
            ce_loss = self.loss_builder.cross_entropy_loss(down_seg, target_mask)
            loss_dict[&quot;ce_loss&quot;] = ce_loss.item()
            loss = ce_loss

            #### Style Loss
            H1_region = self.downsample_256(I_Structure_Style_changed) * HM_Structure
            H2_region = self.downsample_256(gen_im) * HM_G
            style_loss = self.loss_builder.style_loss(H1_region, H2_region, mask1=HM_Structure, mask2=HM_G)

            loss_dict[&quot;style_loss&quot;] = style_loss.item()
            loss += style_loss

            loss.backward()
            optimizer_align.step()

        latent_F_out_new, _ = self.net.generator([latent_in], input_is_latent=True, return_latents=False,
                                                 start_layer=0, end_layer=3)
        latent_F_out_new = latent_F_out_new.clone().detach()</code></pre>
<h4 id="마지막-정렬-단계">마지막 정렬 단계</h4>
<p>: 특정 영역에 대한 마스크(원래 이미지와 목표 이미지의 특정 영역)를 생성하고, 두 이미지의 latent code를 섞음. 이 과정을 두번 반복하여 최종적으로 두 이미지가 섞인 latent code로 결합하여 최종 이미지를 생성하고 이를 저장.</p>
<pre><code class="language-python">        free_mask = 1 - (1 - hair_mask1.unsqueeze(0)) * (1 - hair_mask_target)

        ##############################
        free_mask, _ = self.dilate_erosion(free_mask, device, dilate_erosion=smooth)
        ##############################

        free_mask_down_32 = F.interpolate(free_mask.float(), size=(32, 32), mode=&#39;bicubic&#39;)[0]
        interpolation_low = 1 - free_mask_down_32


        latent_F_mixed = intermediate_align + interpolation_low.unsqueeze(0) * (
                latent_F_1 - intermediate_align)

        if not align_more_region:
            free_mask = hair_mask_target
            ##########################
            _, free_mask = self.dilate_erosion(free_mask, device, dilate_erosion=smooth)
            ##########################
            free_mask_down_32 = F.interpolate(free_mask.float(), size=(32, 32), mode=&#39;bicubic&#39;)[0]
            interpolation_low = 1 - free_mask_down_32


        latent_F_mixed = latent_F_out_new + interpolation_low.unsqueeze(0) * (
                latent_F_mixed - latent_F_out_new)

        free_mask = F.interpolate((hair_mask2.unsqueeze(0) * hair_mask_target).float(), size=(256, 256), mode=&#39;nearest&#39;).cuda()
        ##########################
        _, free_mask = self.dilate_erosion(free_mask, device, dilate_erosion=smooth)
        ##########################
        free_mask_down_32 = F.interpolate(free_mask.float(), size=(32, 32), mode=&#39;bicubic&#39;)[0]
        interpolation_low = 1 - free_mask_down_32

        latent_F_mixed = latent_F_2 + interpolation_low.unsqueeze(0) * (
                latent_F_mixed - latent_F_2)

        gen_im, _ = self.net.generator([latent_1], input_is_latent=True, return_latents=False, start_layer=4,
                                       end_layer=8, layer_in=latent_F_mixed)
        self.save_align_results(im_name_1, im_name_2, sign, gen_im, latent_1, latent_F_mixed,
                                save_intermediate=save_intermediate)</code></pre>
<ul>
<li><code>dilate_erosion</code> : 마스크의 크기를 조절하고 마스크를 부드럽게 만드는 함수</li>
<li><code>save_align_results</code> : 생성된 특성을 이용하여 최종 이미지를 생성하고, 이를 저장</li>
</ul>
<h3 id="③-blending">③ Blending</h3>
<p><em>Blending.py</em>
<code>blend = Blending(args)</code></p>
<pre><code class="language-python">class Blending(nn.Module):

    def __init__(self, opts, net=None):
        super(Blending, self).__init__()
        self.opts = opts
        if not net:
            self.net = Net(self.opts)
        else:
            self.net = net

        self.load_segmentation_network()
        self.load_downsampling()
        self.setup_blend_loss_builder()


    def load_segmentation_network(self):
        self.seg = BiSeNet(n_classes=16)
        self.seg.to(self.opts.device)

        if not os.path.exists(self.opts.seg_ckpt):
            download_weight(self.opts.seg_ckpt)
        self.seg.load_state_dict(torch.load(self.opts.seg_ckpt))
        for param in self.seg.parameters():
            param.requires_grad = False
        self.seg.eval()

    def load_downsampling(self):
        self.downsample = BicubicDownSample(factor=self.opts.size // 512)
        self.downsample_256 = BicubicDownSample(factor=self.opts.size // 256)

    def setup_blend_loss_builder(self):
        self.loss_builder = BlendLossBuilder(self.opts)</code></pre>
<p><code>blend.blend_images(im_path1, im_path2, im_path3, sign=args.sign)</code>
: 두 이미지의 특성을 합성하고, 세 번째 이미지의 특성을 더하는 블렌딩 함수</p>
<pre><code class="language-python">    def blend_images(self, img_path1, img_path2, img_path3, sign=&#39;realistic&#39;):

        device = self.opts.device
        output_dir = self.opts.output_dir

        im_name_1 = os.path.splitext(os.path.basename(img_path1))[0]
        im_name_2 = os.path.splitext(os.path.basename(img_path2))[0]
        im_name_3 = os.path.splitext(os.path.basename(img_path3))[0]

        I_1 = load_image(img_path1, downsample=True).to(device).unsqueeze(0)
        I_3 = load_image(img_path3, downsample=True).to(device).unsqueeze(0)

        HM_1D, _ = cuda_unsqueeze(dilate_erosion_mask_path(img_path1, self.seg), device)
        HM_3D, HM_3E = cuda_unsqueeze(dilate_erosion_mask_path(img_path3, self.seg), device)

        opt_blend, interpolation_latent = self.setup_blend_optimizer()
        latent_1, latent_F_mixed = load_FS_latent(os.path.join(output_dir, &#39;Align_{}&#39;.format(sign),
                                            &#39;{}_{}.npz&#39;.format(im_name_1, im_name_3)),device)
        latent_3, _ = load_FS_latent(os.path.join(output_dir, &#39;FS&#39;,
                                            &#39;{}.npz&#39;.format(im_name_3)), device)

        with torch.no_grad():
            I_X, _ = self.net.generator([latent_1], input_is_latent=True, return_latents=False, start_layer=4,
                               end_layer=8, layer_in=latent_F_mixed)
            I_X_0_1 = (I_X + 1) / 2
            IM = (self.downsample(I_X_0_1) - seg_mean) / seg_std
            down_seg, _, _ = self.seg(IM)
            current_mask = torch.argmax(down_seg, dim=1).long().cpu().float()
            HM_X = torch.where(current_mask == 10, torch.ones_like(current_mask), torch.zeros_like(current_mask))
            HM_X = F.interpolate(HM_X.unsqueeze(0), size=(256, 256), mode=&#39;nearest&#39;).squeeze()
            HM_XD, _ = cuda_unsqueeze(dilate_erosion_mask_tensor(HM_X), device)
            target_mask = (1 - HM_1D) * (1 - HM_3D) * (1 - HM_XD)


        pbar = tqdm(range(self.opts.blend_steps), desc=&#39;Blend&#39;, leave=False)
        for step in pbar:

            opt_blend.zero_grad()

            latent_mixed = latent_1 + interpolation_latent.unsqueeze(0) * (latent_3 - latent_1)

            I_G, _ = self.net.generator([latent_mixed], input_is_latent=True, return_latents=False, start_layer=4,
                               end_layer=8, layer_in=latent_F_mixed)
            I_G_0_1 = (I_G + 1) / 2

            im_dict = {
                &#39;gen_im&#39;: self.downsample_256(I_G),
                &#39;im_1&#39;: I_1,
                &#39;im_3&#39;: I_3,
                &#39;mask_face&#39;: target_mask,
                &#39;mask_hair&#39;: HM_3E
            }
            loss, loss_dic = self.loss_builder(**im_dict)

            loss.backward()
            opt_blend.step()

        ############## Load F code from  &#39;{}_{}.npz&#39;.format(im_name_1, im_name_2)
        _, latent_F_mixed = load_FS_latent(os.path.join(output_dir, &#39;Align_{}&#39;.format(sign),
                                                        &#39;{}_{}.npz&#39;.format(im_name_1, im_name_2)), device)
        I_G, _ = self.net.generator([latent_mixed], input_is_latent=True, return_latents=False, start_layer=4,
                           end_layer=8, layer_in=latent_F_mixed)

        self.save_blend_results(im_name_1, im_name_2, im_name_3, sign, I_G, latent_mixed, latent_F_mixed)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Unreal Engine] C++ Solution build가 되지 않을 때]]></title>
            <link>https://velog.io/@cey_adda/Unreal-Engine-C-%EC%86%94%EB%A3%A8%EC%85%98-%EB%B9%8C%EB%93%9C%EA%B0%80-%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%84-%EB%95%8C</link>
            <guid>https://velog.io/@cey_adda/Unreal-Engine-C-%EC%86%94%EB%A3%A8%EC%85%98-%EB%B9%8C%EB%93%9C%EA%B0%80-%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%84-%EB%95%8C</guid>
            <pubDate>Sun, 10 Dec 2023 11:04:18 GMT</pubDate>
            <description><![CDATA[<p>언리얼 엔진을 사용하다 보면 필수불가결하게 마주치는 녀석이 있습니다. 바로 C++ 솔루션 빌드를 할 때 생기는 오류입니다. </p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/8d24aec2-642b-4705-be2f-a1cba0f4ecc2/image.png" alt=""></p>
<p>처음에 빌드 에러를 마주하면 당혹스럽기 그지없습니다. 엎친 데 덮친 격으로 잘만 열리던 프로젝트도 열리지 않습니다..!! 이때 당황하지 마시고 하나하나 해결해봅시다. 언젠가 프로젝트는 열릴 것입니다.</p>
<h1 id="error-1">Error 1</h1>
<p>Unable to build while is active. Exit the editor and game, or press Ctrl+Alt+F11 if iterating on code in the editor or game</p>
<h3 id="solution">Solution</h3>
<p>*<em>1) *</em>언리얼 엔진 에디터를 끄고 Visual studio 만 켠 채로 솔루션 빌드를 하거나 *<em>2) *</em>live coding을 끄는 방법이 있습니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/d1119929-e2f3-4154-9232-a7c88437fe9b/image.png" alt=""></p>
<blockquote>
<p><strong>live coding</strong>
Ctrl + Alt + F11은 언리얼 엔진5 에디터에서 컴파일 역할을 하는 기능입니다. </p>
</blockquote>
<h1 id="참고">참고</h1>
<ul>
<li><a href="https://docs.unrealengine.com/5.3/ko/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine/">https://docs.unrealengine.com/5.3/ko/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine/</a></li>
<li><a href="https://daekyoulibrary.tistory.com/entry/UE5-Unable-to-build-while-Live-Coding-is-active-Exit-the-editor-and-game-or-press-CtrlAltF11-if-iterating-on-code-in-the-editor-or-game-%EC%98%A4%EB%A5%98">https://daekyoulibrary.tistory.com/entry/UE5-Unable-to-build-while-Live-Coding-is-active-Exit-the-editor-and-game-or-press-CtrlAltF11-if-iterating-on-code-in-the-editor-or-game-%EC%98%A4%EB%A5%98</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Unreal Engine] Window packaging이 되지 않을 때]]></title>
            <link>https://velog.io/@cey_adda/Unreal-Engine-Window-packaging%EC%9D%B4-%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%84-%EB%95%8C</link>
            <guid>https://velog.io/@cey_adda/Unreal-Engine-Window-packaging%EC%9D%B4-%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%84-%EB%95%8C</guid>
            <pubDate>Sun, 10 Dec 2023 10:50:08 GMT</pubDate>
            <description><![CDATA[<h1 id="error-1">Error 1</h1>
<p><code>Packaging (Windows): Platform Win64 is not a valid platform to build. Check that the SDK is installed properly.</code></p>
<pre><code>UATHelper: Packaging (Windows): Platform Win64 is not a valid platform to build. Check that the SDK is installed properly.
UATHelper: Packaging (Windows): Took 0.8534231999999999s to run dotnet.exe, ExitCode=6
UATHelper: Packaging (Windows): UnrealBuildTool failed. See log for more details. (C:\Users\figster\AppData\Roaming\Unreal Engine\AutomationTool\Logs\C+Program+Files+Epic+Games+UE_5.1\UBT-MyProject2-Win64-Development.txt)
UATHelper: Packaging (Windows): AutomationTool executed for 0h 0m 3s
UATHelper: Packaging (Windows): AutomationTool exiting with ExitCode=6 (6)
UATHelper: Packaging (Windows): BUILD FAILED
PackagingResults: Error: Unknown Error</code></pre><p>Visual stdio에서 Workloads가 제대로 설치되지 않았을 때 발생하는 에러입니다.</p>
<h3 id="solution">Solution</h3>
<p>언리얼 엔진은 Visual Studio와 통합되어 설계되었기에 visual studio의 환경이 적절히 구성되어야 합니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/7e2a3c19-cd48-42ad-a63b-88ea369a70ab/image.png" alt="">
VS를 사용한 언리얼 엔진 개발 시 다음의 Visual Studio Workloads 옵션을 설치해야 합니다.</p>
<ul>
<li>.NET desktop development</li>
<li>Desktop development with C++</li>
<li>Universal Windows Platform development</li>
<li>Game development with C++
<img src="https://velog.velcdn.com/images/cey_adda/post/ca4188f4-ec73-463d-aa4f-3a0dabab3ec8/image.png" alt=""><ul>
<li>추가로 우측의 Unreal Engine 관련 요소를 설치해주어야 원활한 개발 환경을 구성할 수 있습니다.</li>
</ul>
</li>
</ul>
<h1 id="참고">참고</h1>
<ul>
<li><a href="https://docs.unrealengine.com/5.3/ko/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine/">https://docs.unrealengine.com/5.3/ko/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Unreal Engine] Distance Field]]></title>
            <link>https://velog.io/@cey_adda/Unreal-Engine-Distance-Field-da1wat0i</link>
            <guid>https://velog.io/@cey_adda/Unreal-Engine-Distance-Field-da1wat0i</guid>
            <pubDate>Thu, 07 Dec 2023 09:35:45 GMT</pubDate>
            <description><![CDATA[<p><a href="https://docs.unrealengine.com/4.27/en-US/BuildingWorlds/LightingAndShadows/MeshDistanceFields/" target="_blank">Mesh Distance Fields</a> 관련 Unreal Engine Documentation을 참고하여 작성되었습니다. Unreal Engine를 개발할 때 사용할 수 있는 Distance Field의 사용에 대한 개요를 서술합니다.</p>
<h1 id="distance-field">Distance Field</h1>
<p>언리얼 엔진은 Distance Field를 활용하여 Static Mesh Actor를 위한 dynamic ambient occlusion 및 그림자 기능을 제공합니다. 이 외에도, Actor의 Mesh Distance Field representation은 GPU particle collision이나 동적 흐름 맵을 만드는 Material Editor와 함께 사용될 수 있습니다.</p>
<h2 id="signed-distance-field">Signed Distance Field</h2>
<p>Static Mesh의 표면을 나타내기 위해서 <strong>Signed Distance Field (SDF)</strong>가 사용됩니다. Signed Distance Field란 위치를 입력으로 받아 해당 위치에서 object의 가장 가까운 부분까지의 거리를 출력하는 함수를 이용해 object를 나타내는 방식입니다. UE에서 이는 volume texture에 가장 가까운 표면까지의 거리를 저장하여 작동합니다. Mesh 외부의 모든 점은 양의 거리로 간주되고 메쉬 내부의 모든 점은 음의 거리로 저장합니다.<br><img src="https://velog.velcdn.com/images/cey_adda/post/9cc5d16a-1643-4960-81a6-e769e92caf46/image.png" alt=""></p>
<p><a style='color:#adadad' href="http://bytewrangler.blogspot.com/2011/10/signed-distance-fields.html" target="_blank" align="center">Signed Distance Field가 픽셀에서 어떻게 보이는지에 대한 예</a></p>
<h2 id="mesh-distance-field">Mesh Distance Field</h2>
<p>Level에 배치된 Actor는 모두 Mesh Distance Field로 구성됩니다. Mesh Distance Field가 생성될 때 결과를 volume texture에 저장하는 triangle raytracing을 사용하여 <strong>&quot;오프라인&quot;</strong>으로 생성됩니다. 이 때문에 Mesh Distance Field 생성은 런타임에 수행할 수 없습니다. 이 방법은 모든 방향에서 Signed Distance Field 광선을 계산하여 가장 가까운 표면을 찾고 해당 정보를 저장합니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/9d3212fb-f55b-476e-acb7-fc9ea842d9e8/image.png" alt=""></p>
<p>회색보다 흰색에 가까운 영역이 표시되면 메쉬 표면의 교차점을 찾는 데 많은 단계가 필요했음을 의미합니다. 표면에 대한 grazing angle(스침각: 입사 광선과 반사 표면 사이의 각도)의 광선은 단순한 메시보다 교차하는 데 훨씬 더 많은 단계를 거칩니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/4459eee6-0d4d-4d2e-b0cf-e5a4ed616cbf/image.png" alt=""></p>
<p><a href="https://www.mathworks.com/help/radar/ref/grazingang.html" target="_blank" align="center">Grazing Angle</a></p>
<h3 id="enabling-mesh-distance-field">Enabling Mesh Distance Field</h3>
<p>Mesh Distance Field를 활성화하기 위해서는 [Edit] - [Project Settings] - [Rendering] - [Lighting] - [Generate Mesh Distance Fields]를 체크합니다.</p>
<p align="center"><img src="https://velog.velcdn.com/images/cey_adda/post/a7abc6b0-ddb2-4fe7-9f58-de54fca2b7f2/image.png" width="300" height="300" /> </p>

<h3 id="visualize-mesh-distance-field">Visualize Mesh Distance Field</h3>
<p>뷰포트에서 전역 거리 필드를 시각화기 위해서는 [Show] - [Visualize] - [Mesh Distance Field]를 체크합니다.</p>
<p align="center"><img src="https://velog.velcdn.com/images/cey_adda/post/7181af8c-e206-4573-9810-4cbb8a914c98/image.png" width="300" height="300" /> </p>

<p>단일 메시가 가질 수 있는 최대 볼륨 텍스처 크기는 128x128x128 해상도에서 8MB입니다.</p>
<h2 id="global-distance-field">Global Distance Field</h2>
<p>Global Distance Field는 해당 Level에서 카메라를 따라 Signed Distance Field occlusion을 사용하는 low-resolution Distance Field입니다. 이는 object 별 Mesh Distance Field의 캐시를 생성하고 카메라를 중심으로한 몇 개의 볼륨 텍스처인 clipmap으로 합성합니다. 새로 보이는 영역이나 장면 수정의 영향을 받는 영역만 업데이트하면 되기 때문에 구성 비용이 많이 들지 않습니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/4eb525f4-7185-462d-bc5b-1014d899d8bb/image.png" alt=""></p>
<h3 id="visualize-global-distance-field">Visualize Global Distance Field</h3>
<p>뷰포트에서 전역 거리 필드를 시각화기 위해서는 [Show] - [Visualize] - [Global Distance Field]를 체크합니다.</p>
<p align="center"><img src="https://velog.velcdn.com/images/cey_adda/post/47798030-88d9-446d-ba4e-f17da611198c/image.png" width="300" height="300" /> </p>


<h1 id="참고">참고</h1>
<ul>
<li><a href="https://docs.unrealengine.com/4.27/en-US/BuildingWorlds/LightingAndShadows/MeshDistanceFields/">https://docs.unrealengine.com/4.27/en-US/BuildingWorlds/LightingAndShadows/MeshDistanceFields/</a></li>
<li><a href="http://bytewrangler.blogspot.com/2011/10/signed-distance-fields.html">http://bytewrangler.blogspot.com/2011/10/signed-distance-fields.html</a></li>
<li><a href="https://www.mathworks.com/help/radar/ref/grazingang.html">https://www.mathworks.com/help/radar/ref/grazingang.html</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Unreal Engine] UpperBody plugin]]></title>
            <link>https://velog.io/@cey_adda/Unreal-Engine-UpperBody-plugin</link>
            <guid>https://velog.io/@cey_adda/Unreal-Engine-UpperBody-plugin</guid>
            <pubDate>Thu, 07 Dec 2023 09:23:56 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/JonasMolgaard/UBIKSolver" target="_blank">UpperBody IK (UBIK)</a> 플러그인을 언리얼 엔진에서 사용하는 방법을 서술합니다.</p>
<p>Upper Body Ik Plugin이 현재 5.3에서 오류가 발생합니다. 깃허브의 풀리퀘스트를 참고하여 수정한 코드는 아래 링크에서 다운받을 수 있습니다. </p>
<ul>
<li><a href="https://github.com/nokcharathae/UpperBody-IK-Plugin" target="_blank">UpperBody-IK-Plugin</a></li>
</ul>
<h1 id="using-upperbody-ik-plugin">Using UpperBody IK plugin</h1>
<h2 id="플러그인-import">플러그인 import</h2>
<ol>
<li>[프로젝트 폴더]에 [Plugins]라고 하는 폴더를 생성</li>
<li>플러그인 폴더 [UBIKSolver-main] 드래그 &amp; 드랍</li>
<li>프로젝트 실행하고 rebuild
<img src="https://velog.velcdn.com/images/cey_adda/post/44d2d6ac-d8d0-44a7-8785-34d519112048/image.png" alt=""><ul>
<li>플러그인이 잘 임포트되면 위처럼 플러그인 창에 나타남</li>
</ul>
</li>
</ol>
<h2 id="blueprint">Blueprint</h2>
<h3 id="animation-blueprint-생성">Animation Blueprint 생성</h3>
<ol>
<li>Animation blueprint를 &#39;SK_Mannequin_Skeleton&#39;로 생성</li>
<li>[AnimationBlueprint] - [AnimGraph]
<img src="https://velog.velcdn.com/images/cey_adda/post/a45f78f5-727a-427c-b2cc-f8f72577d4b4/image.png" alt=""></li>
<li>[AnimationBlueprint] - [Event Graph]
<img src="https://velog.velcdn.com/images/cey_adda/post/11cd4c99-c2fd-4d12-a156-1a547d18da9e/image.png" alt=""></li>
</ol>
<h3 id="vrpwan-수정">VRPwan 수정</h3>
<ol>
<li>스켈레탈 메시 추가하고 Animation blueprint로 지정했던 스켈레톤을 가진 스켈레탈 메시로 변경</li>
<li>[skeletal mesh] - [Animation] - [Animation Mode] 는 &#39;Use AnimationBlueprint&#39;로, [Anim Class] 는 위에서 생성한 Animation blueprint로 설정
<img src="https://velog.velcdn.com/images/cey_adda/post/8fdd7c4f-8d35-4fda-bcc9-d85e747a9d83/image.png" alt=""></li>
<li>[Event Graph] 에 &#39;Event Tick&#39; 이벤트 추가하여 아래 이미지 노드를 추가
<img src="https://velog.velcdn.com/images/cey_adda/post/2be46c8c-ed50-4f08-862f-52716d4ddf53/image.png" alt=""></li>
</ol>
<h2 id="results">Results</h2>
<p>기존 언리얼 엔진 5의 VR pawn에 매핑되어 있는 애니메이션을 리타겟팅하여 upper body 스켈레탈 메시의 손가락 애니메이션을 제어하였습니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/e49e4ea7-fa2d-4121-b045-0f10cf575c98/image.png" alt=""></p>
<h1 id="참고">참고</h1>
<ul>
<li><a href="https://www.youtube.com/watch?v=6Xiq6w9mJaI">https://www.youtube.com/watch?v=6Xiq6w9mJaI</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Unreal Engine] Animation Retargeting]]></title>
            <link>https://velog.io/@cey_adda/Unreal-Engine-Animation-Retargeting</link>
            <guid>https://velog.io/@cey_adda/Unreal-Engine-Animation-Retargeting</guid>
            <pubDate>Thu, 07 Dec 2023 08:46:32 GMT</pubDate>
            <description><![CDATA[<a href="https://docs.unrealengine.com/5.3/en-US/animation-retargeting-in-unreal-engine/" target="_blank">
Animation Retargeting</a> 관련 Unreal Engine Documentation을 참고하여 작성되었습니다. Unreal Engine에서 스켈레탈 메시에 Animation Retargeting을 사용하는 방법을 서술합니다. 

<h1 id="animation-retargeting">Animation Retargeting</h1>
<p>가상 3d world에서 손을 뻗는 자세를 취하고 있는 캐릭터와 같은 동작을 옆 캐릭터에게 시키려면 어떻게 해야할까요? 단순히 같은 애니메이션을 적용시키면 되지 않을까 하고 생각할 수 있습니다. </p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/a0915616-d658-462c-be3e-fb9b7558ccec/image.png" alt=""></p>
<p>애니메이션을 적용한다는 것은 joint 를 제어한다는 것과 같습니다. 실제 사람의 뼈처럼 캐릭터에는 가상 뼈가 존재합니다. 이 가상 뼈 즉, bone의 사이사이는 회전을 제어할 수 있는 joint가 존재하며, 이 joint의 회전을 통해 뼈의 움직임을 조작할 수 있습니다. 
<img src="https://velog.velcdn.com/images/cey_adda/post/ab47b570-69e2-4c52-b67a-d6a6a0a2b0c0/image.png" alt=""></p>
<p>이미지에서 볼 수 있듯 어깨로부터 팔꿈치, 팔꿈치로부터 손목처럼 가상 뼈는 parent-child 관계로 계층적으로 이루어져 있습니다. 이를 통해 우측 이미지와 같이 어깨를 회전하면 아래 자식 뼈들도 함께 회전하게 됩니다. 이런 식으로 joint의 변형을 통해 애니메이션을 동작할 수 있습니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/139d7523-82c3-48fc-a8c9-32c67c55f271/image.png" alt=""></p>
<h3 id="리타겟팅이-필요한-이유">리타겟팅이 필요한 이유</h3>
<p>그러면 이 가상 뼈를 통한 애니메이션 적용을 상상해봅시다. 아래와 같이 애니메이션을 공유고자 하는 캐릭터가 표준 캐릭터, 작고 다부진 캐릭터, 크고 홀쭉한 캐릭터로 세 버전이 있다고 가정해 봅시다. 세 캐릭터가 총을 들고 전진하고 있는 모습을 취한다고 하면 대충 어떤 식으로 자세를 잡을지 상상할 수 있습니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/89b9c83f-d317-4895-b4db-ea7edb43dd3b/image.png" alt=""></p>
<h4 id="리타겟팅을-적용하지-않은-스켈레톤-에셋을-사용할-경우">리타겟팅을 적용하지 않은 스켈레톤 에셋을 사용할 경우</h4>
<p>만약 표준 캐릭터의 애니메이션을 그대로 다른 두 캐릭터에 적용한다면 다음과 같은 모습으로 적용됩니다.
머릿 속으로 상상했던 모습과 달리 원치않은 변형이 일어난 것처럼 보입니다.</p>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/6324d65a-896d-42f1-a247-ad5df72c36c6/image.png" alt=""></p>
<p>애니메이션 리타겟팅은 이런 기존의 어떤 캐릭터로부터 다른 캐릭터에 동일한 애니메이션을 재생하려는 시도로부터 시작합니다. 이런 불필요한 변형을 방지하기 위해 리타겟팅을 사용하는 것입니다. 애니메이션 리타겟팅은 스켈레톤, 즉 가상 뼈대를 사용하는 캐릭터 간에 애니메이션을 공유할 수 있도록 해주는 기능입니다.</p>
<h4 id="리타겟팅을-적용한-스켈레톤-에셋을-사용할-경우">리타겟팅을 적용한 스켈레톤 에셋을 사용할 경우</h4>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/bfd4ce1f-76d9-47f4-8dc3-0c386a6d6452/image.png" alt=""></p>
<p>캐릭터에 리타기팅을 적용한 결과, 방정식을 통해 비율 차이를 계산하여 캐릭터에 애니메이션이 제대로 적용된 것을 확인할 수 있습니다. 살색 표시는 원래 스켈레톤을, 흰색은 현재 스켈레톤으로 두 리타겟팅 전 스켈레톤과의 차이를 확인할 수 있습니다. 표준 캐릭터는 리타기팅되지 않은 bone과 스켈레톤에 완벽히 일치하는 것으로 보입니다. 이렇게 리타겟팅을 사용하면, 캐릭터 사이에 애니메이션 애셋을 공유하여 애니메이션을 완전히 새로 만들 필요가 없어져 메모리를 효율적으로 사용할 수 있습니다.</p>
<h1 id="animation-retargeing-in-unreal-engine">Animation retargeing in Unreal Engine</h1>
<p>캐릭터들은 크기, 비율, 모양이 제각각이기 때문에 캐릭터마다 본 개수, 본 이름, 오리엔테이션 등의 다양한 유형의 뼈를 가집니다. 따라서 언리얼 엔진에서는 하나의 캐릭터에서 다른 캐릭터로 애니메이션을 리타기팅하는 유연한 툴을 제공합니다. 이러한 방법 중 하나가 바로 <strong>IK Rig</strong> 및 <strong>IK Retargeter</strong>를 함께 사용하는 것입니다. 이를 사용하면 스켈레톤 계층구조 및 비율이 현저히 차이나는 캐릭터들을 리타기팅할 수 있습니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/4279f4d8-e137-4b16-b106-174e5d7d1672/image.png" alt=""></p>
<p>IK Rig를 사용하여 다양한 스켈레탈 메시 간에 애니메이션을 공유하는 IK Retargeter를 구성할 수 있습니다. 서로 다른 스켈레톤은 각기 다른 bone 개수, bone 이름, orientation 등으로 정의되어 있는데 이는 IK rig을 통해 제어할 수 있습니다. 예를 들어 서로 다른 캐릭터의 팔을 구성하고 있는 bone이 각각 3개, 5개로 구성되어 있는 상황을 가정해봅시다. 조인트와 본의 개수가 달라 1대 1로 바로 매핑시킬 수 없는 상황에 IK Rig은 이를 리타겟 체인을 통해 매핑합니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/19efbe45-dff1-40dd-8ac5-bf79f62adb61/image.png" alt=""></p>
<p>팔을 조인트와 본으로 구성된 스켈레톤이 아닌 조인트 체인으로 정의하여 매우 차이가 큰 본 구조체를 가진 캐릭터들을 한층 유연하게 리타기팅할 수 있습니다. 리타기팅할 모든 주요 팔다리에 대해 체인을 생성해야 합니다.
<img src="https://velog.velcdn.com/images/cey_adda/post/26534689-a13c-4750-b0f9-34632479c344/image.png" alt=""></p>
<h2 id="start-retargeting">Start Retargeting</h2>
<h3 id="same-skeleton-asset">Same skeleton asset</h3>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/cc1c9c46-743c-4a25-aa1c-5c0d8a3f2860/image.png" alt=""></p>
<h3 id="different-skeleton-asset">Different skeleton asset</h3>
<h4 id="import-another-skeletal-mesh">Import another skeletal mesh</h4>
<ol>
<li><p>Using Unreal engine market place
<img src="https://velog.velcdn.com/images/cey_adda/post/3b63c193-9256-456e-883f-d345461385f2/image.png" alt=""></p>
</li>
<li><p>Using Mixamo</p>
</li>
</ol>
<ul>
<li><a href="https://www.mixamo.com/#/">https://www.mixamo.com/#/</a>
<img src="https://velog.velcdn.com/images/cey_adda/post/ad186e0c-a1f7-4edd-920e-3fee3ede3e37/image.png" alt=""></li>
</ul>
<h4 id="initializing-ik-rig">Initializing IK Rig</h4>
<ol>
<li>[Content] - [Animation] 폴더 생성</li>
<li>우클릭 - [Animation] - [Retargeting] - [IK Rig] 선택하고 ‘IK_UECharater’ IK Rig 생성</li>
<li>‘IK_UECharater’ IK Rig 선택하고 [Preview Skeletal Mesh]를 ‘SKM_Quinn_Simple’로 설정
<img src="https://velog.velcdn.com/images/cey_adda/post/9588988c-1ac6-4857-9efa-41b334842891/image.png" alt=""></li>
<li>위와 똑같은 과정을 리타겟팅할 스켈레탈 메쉬에도 적용
<img src="https://velog.velcdn.com/images/cey_adda/post/ff87d6db-a61f-4ed7-ac87-d9cc5e4b4a4d/image.png" alt=""></li>
</ol>
<h3 id="initializing-ik-retargeter">Initializing IK Retargeter</h3>
<ol>
<li>우클릭 - [Animation] - [Retargeting] - [IK Retargeter] 선택하고 ‘RT_UE2Shinbi’ IK Retargeter 생성</li>
<li>‘RT_UE2Shinbi’ IK Retargeter 선택하고 [Source IKRig Asset]을 기존 애니메이션이 있는 ‘IK_UECharacter’로, [Target IKRig Asset]을 애니메이션을 적용할 ‘IK_Shinbi’로 설정
<img src="https://velog.velcdn.com/images/cey_adda/post/5b8379cc-caf8-4002-9a84-8a5da336b834/image.png" alt=""></li>
</ol>
<h3 id="setting-ik-rig">Setting IK Rig</h3>
<p><img src="https://velog.velcdn.com/images/cey_adda/post/8db69951-2219-4492-9f3c-1cb253af73da/image.png" alt=""></p>
<h3 id="setting-ik-retargeter">Setting IK Retargeter</h3>
<ol>
<li>우측 Chain Mappings의 Source Chain을 설정한 solver로 각각 매핑
<img src="https://velog.velcdn.com/images/cey_adda/post/8b67eedd-c657-47cf-9f18-badc7ce54ffd/image.png" alt=""></li>
<li>Asset Browser의 애니메이션을 실행하면 똑같이 동작하는 것을 확인
<img src="https://velog.velcdn.com/images/cey_adda/post/e20b4dbc-8bc0-4c12-95dc-a0f4a289ffc3/image.png" alt=""></li>
</ol>
<h3 id="export-retargeted-animaion">Export retargeted animaion</h3>
<p>리타겟팅된 애니메이션을 내보낼 수 있습니다.</p>
<h2 id="runtime-ik-retargeting">Runtime IK Retargeting</h2>
<ol>
<li>애니메이션 블루프린트를 만들고, 타겟 스켈레톤을 선택</li>
<li>‘Retarget Pose From Mesh’ 노드를 추가하여 IK Retargeter 선택</li>
<li>소스 캐릭터가 숨겨진 상황에서는 <strong>비저빌리티 기반 애님 틱 옵션(Visibility Based Anim Tick Option)</strong> 을 <strong>최적화(Optimizations)</strong> 카테고리의 <strong>항상 포즈 틱 및 본 새로고침(Always Tick Pose and Refresh Bones)</strong> 으로 설정해야 합니다.</li>
</ol>
<h1 id="참고">참고</h1>
<ul>
<li><a href="https://medium.com/@nvidiaomniverse/what-is-animation-retargeting-4aadab383032">https://medium.com/@nvidiaomniverse/what-is-animation-retargeting-4aadab383032</a></li>
<li><a href="https://docs.unrealengine.com/5.3/ko/animation-retargeting-in-unreal-engine/">https://docs.unrealengine.com/5.3/ko/animation-retargeting-in-unreal-engine/</a></li>
<li><a href="https://devjino.tistory.com/276">https://devjino.tistory.com/276</a></li>
<li><a href="https://www.youtube.com/watch?v=xvHOamXuZDI">https://www.youtube.com/watch?v=xvHOamXuZDI</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>